1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2338a1281SOctavian Purdila /*
3338a1281SOctavian Purdila * Driver for the Diolan DLN-2 USB adapter
4338a1281SOctavian Purdila *
5338a1281SOctavian Purdila * Copyright (c) 2014 Intel Corporation
6338a1281SOctavian Purdila *
7338a1281SOctavian Purdila * Derived from:
8338a1281SOctavian Purdila * i2c-diolan-u2c.c
9338a1281SOctavian Purdila * Copyright (c) 2010-2011 Ericsson AB
10338a1281SOctavian Purdila */
11338a1281SOctavian Purdila
12338a1281SOctavian Purdila #include <linux/kernel.h>
13338a1281SOctavian Purdila #include <linux/module.h>
14338a1281SOctavian Purdila #include <linux/types.h>
15338a1281SOctavian Purdila #include <linux/slab.h>
16338a1281SOctavian Purdila #include <linux/usb.h>
17338a1281SOctavian Purdila #include <linux/mutex.h>
18338a1281SOctavian Purdila #include <linux/platform_device.h>
19338a1281SOctavian Purdila #include <linux/mfd/core.h>
20338a1281SOctavian Purdila #include <linux/mfd/dln2.h>
21338a1281SOctavian Purdila #include <linux/rculist.h>
22338a1281SOctavian Purdila
23338a1281SOctavian Purdila struct dln2_header {
24338a1281SOctavian Purdila __le16 size;
25338a1281SOctavian Purdila __le16 id;
26338a1281SOctavian Purdila __le16 echo;
27338a1281SOctavian Purdila __le16 handle;
28338a1281SOctavian Purdila };
29338a1281SOctavian Purdila
30338a1281SOctavian Purdila struct dln2_response {
31338a1281SOctavian Purdila struct dln2_header hdr;
32338a1281SOctavian Purdila __le16 result;
33338a1281SOctavian Purdila };
34338a1281SOctavian Purdila
35338a1281SOctavian Purdila #define DLN2_GENERIC_MODULE_ID 0x00
36338a1281SOctavian Purdila #define DLN2_GENERIC_CMD(cmd) DLN2_CMD(cmd, DLN2_GENERIC_MODULE_ID)
37338a1281SOctavian Purdila #define CMD_GET_DEVICE_VER DLN2_GENERIC_CMD(0x30)
38338a1281SOctavian Purdila #define CMD_GET_DEVICE_SN DLN2_GENERIC_CMD(0x31)
39338a1281SOctavian Purdila
40338a1281SOctavian Purdila #define DLN2_HW_ID 0x200
41338a1281SOctavian Purdila #define DLN2_USB_TIMEOUT 200 /* in ms */
42338a1281SOctavian Purdila #define DLN2_MAX_RX_SLOTS 16
43338a1281SOctavian Purdila #define DLN2_MAX_URBS 16
44338a1281SOctavian Purdila #define DLN2_RX_BUF_SIZE 512
45338a1281SOctavian Purdila
46338a1281SOctavian Purdila enum dln2_handle {
47338a1281SOctavian Purdila DLN2_HANDLE_EVENT = 0, /* don't change, hardware defined */
48338a1281SOctavian Purdila DLN2_HANDLE_CTRL,
49338a1281SOctavian Purdila DLN2_HANDLE_GPIO,
50338a1281SOctavian Purdila DLN2_HANDLE_I2C,
5121cf3318SLaurentiu Palcu DLN2_HANDLE_SPI,
52313c84b5SJack Andersen DLN2_HANDLE_ADC,
53338a1281SOctavian Purdila DLN2_HANDLES
54338a1281SOctavian Purdila };
55338a1281SOctavian Purdila
56338a1281SOctavian Purdila /*
57338a1281SOctavian Purdila * Receive context used between the receive demultiplexer and the transfer
58338a1281SOctavian Purdila * routine. While sending a request the transfer routine will look for a free
59338a1281SOctavian Purdila * receive context and use it to wait for a response and to receive the URB and
60338a1281SOctavian Purdila * thus the response data.
61338a1281SOctavian Purdila */
62338a1281SOctavian Purdila struct dln2_rx_context {
63338a1281SOctavian Purdila /* completion used to wait for a response */
64338a1281SOctavian Purdila struct completion done;
65338a1281SOctavian Purdila
66338a1281SOctavian Purdila /* if non-NULL the URB contains the response */
67338a1281SOctavian Purdila struct urb *urb;
68338a1281SOctavian Purdila
69338a1281SOctavian Purdila /* if true then this context is used to wait for a response */
70338a1281SOctavian Purdila bool in_use;
71338a1281SOctavian Purdila };
72338a1281SOctavian Purdila
73338a1281SOctavian Purdila /*
74338a1281SOctavian Purdila * Receive contexts for a particular DLN2 module (i2c, gpio, etc.). We use the
75338a1281SOctavian Purdila * handle header field to identify the module in dln2_dev.mod_rx_slots and then
76338a1281SOctavian Purdila * the echo header field to index the slots field and find the receive context
77338a1281SOctavian Purdila * for a particular request.
78338a1281SOctavian Purdila */
79338a1281SOctavian Purdila struct dln2_mod_rx_slots {
80338a1281SOctavian Purdila /* RX slots bitmap */
81338a1281SOctavian Purdila DECLARE_BITMAP(bmap, DLN2_MAX_RX_SLOTS);
82338a1281SOctavian Purdila
83338a1281SOctavian Purdila /* used to wait for a free RX slot */
84338a1281SOctavian Purdila wait_queue_head_t wq;
85338a1281SOctavian Purdila
86338a1281SOctavian Purdila /* used to wait for an RX operation to complete */
87338a1281SOctavian Purdila struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
88338a1281SOctavian Purdila
89338a1281SOctavian Purdila /* avoid races between alloc/free_rx_slot and dln2_rx_transfer */
90338a1281SOctavian Purdila spinlock_t lock;
91338a1281SOctavian Purdila };
92338a1281SOctavian Purdila
93338a1281SOctavian Purdila struct dln2_dev {
94338a1281SOctavian Purdila struct usb_device *usb_dev;
95338a1281SOctavian Purdila struct usb_interface *interface;
96338a1281SOctavian Purdila u8 ep_in;
97338a1281SOctavian Purdila u8 ep_out;
98338a1281SOctavian Purdila
99338a1281SOctavian Purdila struct urb *rx_urb[DLN2_MAX_URBS];
100338a1281SOctavian Purdila void *rx_buf[DLN2_MAX_URBS];
101338a1281SOctavian Purdila
102338a1281SOctavian Purdila struct dln2_mod_rx_slots mod_rx_slots[DLN2_HANDLES];
103338a1281SOctavian Purdila
104338a1281SOctavian Purdila struct list_head event_cb_list;
105338a1281SOctavian Purdila spinlock_t event_cb_lock;
106338a1281SOctavian Purdila
107338a1281SOctavian Purdila bool disconnect;
108338a1281SOctavian Purdila int active_transfers;
109338a1281SOctavian Purdila wait_queue_head_t disconnect_wq;
110338a1281SOctavian Purdila spinlock_t disconnect_lock;
111338a1281SOctavian Purdila };
112338a1281SOctavian Purdila
113338a1281SOctavian Purdila struct dln2_event_cb_entry {
114338a1281SOctavian Purdila struct list_head list;
115338a1281SOctavian Purdila u16 id;
116338a1281SOctavian Purdila struct platform_device *pdev;
117338a1281SOctavian Purdila dln2_event_cb_t callback;
118338a1281SOctavian Purdila };
119338a1281SOctavian Purdila
dln2_register_event_cb(struct platform_device * pdev,u16 id,dln2_event_cb_t event_cb)120338a1281SOctavian Purdila int dln2_register_event_cb(struct platform_device *pdev, u16 id,
121338a1281SOctavian Purdila dln2_event_cb_t event_cb)
122338a1281SOctavian Purdila {
123338a1281SOctavian Purdila struct dln2_dev *dln2 = dev_get_drvdata(pdev->dev.parent);
124338a1281SOctavian Purdila struct dln2_event_cb_entry *i, *entry;
125338a1281SOctavian Purdila unsigned long flags;
126338a1281SOctavian Purdila int ret = 0;
127338a1281SOctavian Purdila
128338a1281SOctavian Purdila entry = kzalloc(sizeof(*entry), GFP_KERNEL);
129338a1281SOctavian Purdila if (!entry)
130338a1281SOctavian Purdila return -ENOMEM;
131338a1281SOctavian Purdila
132338a1281SOctavian Purdila entry->id = id;
133338a1281SOctavian Purdila entry->callback = event_cb;
134338a1281SOctavian Purdila entry->pdev = pdev;
135338a1281SOctavian Purdila
136338a1281SOctavian Purdila spin_lock_irqsave(&dln2->event_cb_lock, flags);
137338a1281SOctavian Purdila
138338a1281SOctavian Purdila list_for_each_entry(i, &dln2->event_cb_list, list) {
139338a1281SOctavian Purdila if (i->id == id) {
140338a1281SOctavian Purdila ret = -EBUSY;
141338a1281SOctavian Purdila break;
142338a1281SOctavian Purdila }
143338a1281SOctavian Purdila }
144338a1281SOctavian Purdila
145338a1281SOctavian Purdila if (!ret)
146338a1281SOctavian Purdila list_add_rcu(&entry->list, &dln2->event_cb_list);
147338a1281SOctavian Purdila
148338a1281SOctavian Purdila spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
149338a1281SOctavian Purdila
150338a1281SOctavian Purdila if (ret)
151338a1281SOctavian Purdila kfree(entry);
152338a1281SOctavian Purdila
153338a1281SOctavian Purdila return ret;
154338a1281SOctavian Purdila }
155338a1281SOctavian Purdila EXPORT_SYMBOL(dln2_register_event_cb);
156338a1281SOctavian Purdila
dln2_unregister_event_cb(struct platform_device * pdev,u16 id)157338a1281SOctavian Purdila void dln2_unregister_event_cb(struct platform_device *pdev, u16 id)
158338a1281SOctavian Purdila {
159338a1281SOctavian Purdila struct dln2_dev *dln2 = dev_get_drvdata(pdev->dev.parent);
160338a1281SOctavian Purdila struct dln2_event_cb_entry *i;
161338a1281SOctavian Purdila unsigned long flags;
162338a1281SOctavian Purdila bool found = false;
163338a1281SOctavian Purdila
164338a1281SOctavian Purdila spin_lock_irqsave(&dln2->event_cb_lock, flags);
165338a1281SOctavian Purdila
166338a1281SOctavian Purdila list_for_each_entry(i, &dln2->event_cb_list, list) {
167338a1281SOctavian Purdila if (i->id == id) {
168338a1281SOctavian Purdila list_del_rcu(&i->list);
169338a1281SOctavian Purdila found = true;
170338a1281SOctavian Purdila break;
171338a1281SOctavian Purdila }
172338a1281SOctavian Purdila }
173338a1281SOctavian Purdila
174338a1281SOctavian Purdila spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
175338a1281SOctavian Purdila
176338a1281SOctavian Purdila if (found) {
177338a1281SOctavian Purdila synchronize_rcu();
178338a1281SOctavian Purdila kfree(i);
179338a1281SOctavian Purdila }
180338a1281SOctavian Purdila }
181338a1281SOctavian Purdila EXPORT_SYMBOL(dln2_unregister_event_cb);
182338a1281SOctavian Purdila
183338a1281SOctavian Purdila /*
184338a1281SOctavian Purdila * Returns true if a valid transfer slot is found. In this case the URB must not
185338a1281SOctavian Purdila * be resubmitted immediately in dln2_rx as we need the data when dln2_transfer
186338a1281SOctavian Purdila * is woke up. It will be resubmitted there.
187338a1281SOctavian Purdila */
dln2_transfer_complete(struct dln2_dev * dln2,struct urb * urb,u16 handle,u16 rx_slot)188338a1281SOctavian Purdila static bool dln2_transfer_complete(struct dln2_dev *dln2, struct urb *urb,
189338a1281SOctavian Purdila u16 handle, u16 rx_slot)
190338a1281SOctavian Purdila {
191338a1281SOctavian Purdila struct device *dev = &dln2->interface->dev;
192338a1281SOctavian Purdila struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle];
193338a1281SOctavian Purdila struct dln2_rx_context *rxc;
19450d44f82SSebastian Andrzej Siewior unsigned long flags;
195338a1281SOctavian Purdila bool valid_slot = false;
196338a1281SOctavian Purdila
19700ee7a37SOctavian Purdila if (rx_slot >= DLN2_MAX_RX_SLOTS)
19800ee7a37SOctavian Purdila goto out;
19900ee7a37SOctavian Purdila
200338a1281SOctavian Purdila rxc = &rxs->slots[rx_slot];
201338a1281SOctavian Purdila
20250d44f82SSebastian Andrzej Siewior spin_lock_irqsave(&rxs->lock, flags);
203338a1281SOctavian Purdila if (rxc->in_use && !rxc->urb) {
204338a1281SOctavian Purdila rxc->urb = urb;
205338a1281SOctavian Purdila complete(&rxc->done);
206338a1281SOctavian Purdila valid_slot = true;
207338a1281SOctavian Purdila }
20850d44f82SSebastian Andrzej Siewior spin_unlock_irqrestore(&rxs->lock, flags);
209338a1281SOctavian Purdila
21000ee7a37SOctavian Purdila out:
211338a1281SOctavian Purdila if (!valid_slot)
212338a1281SOctavian Purdila dev_warn(dev, "bad/late response %d/%d\n", handle, rx_slot);
213338a1281SOctavian Purdila
214338a1281SOctavian Purdila return valid_slot;
215338a1281SOctavian Purdila }
216338a1281SOctavian Purdila
dln2_run_event_callbacks(struct dln2_dev * dln2,u16 id,u16 echo,void * data,int len)217338a1281SOctavian Purdila static void dln2_run_event_callbacks(struct dln2_dev *dln2, u16 id, u16 echo,
218338a1281SOctavian Purdila void *data, int len)
219338a1281SOctavian Purdila {
220338a1281SOctavian Purdila struct dln2_event_cb_entry *i;
221338a1281SOctavian Purdila
222338a1281SOctavian Purdila rcu_read_lock();
223338a1281SOctavian Purdila
224338a1281SOctavian Purdila list_for_each_entry_rcu(i, &dln2->event_cb_list, list) {
225338a1281SOctavian Purdila if (i->id == id) {
226338a1281SOctavian Purdila i->callback(i->pdev, echo, data, len);
227338a1281SOctavian Purdila break;
228338a1281SOctavian Purdila }
229338a1281SOctavian Purdila }
230338a1281SOctavian Purdila
231338a1281SOctavian Purdila rcu_read_unlock();
232338a1281SOctavian Purdila }
233338a1281SOctavian Purdila
dln2_rx(struct urb * urb)234338a1281SOctavian Purdila static void dln2_rx(struct urb *urb)
235338a1281SOctavian Purdila {
236338a1281SOctavian Purdila struct dln2_dev *dln2 = urb->context;
237338a1281SOctavian Purdila struct dln2_header *hdr = urb->transfer_buffer;
238338a1281SOctavian Purdila struct device *dev = &dln2->interface->dev;
239338a1281SOctavian Purdila u16 id, echo, handle, size;
240338a1281SOctavian Purdila u8 *data;
241338a1281SOctavian Purdila int len;
242338a1281SOctavian Purdila int err;
243338a1281SOctavian Purdila
244338a1281SOctavian Purdila switch (urb->status) {
245338a1281SOctavian Purdila case 0:
246338a1281SOctavian Purdila /* success */
247338a1281SOctavian Purdila break;
248338a1281SOctavian Purdila case -ECONNRESET:
249338a1281SOctavian Purdila case -ENOENT:
250338a1281SOctavian Purdila case -ESHUTDOWN:
251338a1281SOctavian Purdila case -EPIPE:
252338a1281SOctavian Purdila /* this urb is terminated, clean up */
253338a1281SOctavian Purdila dev_dbg(dev, "urb shutting down with status %d\n", urb->status);
254338a1281SOctavian Purdila return;
255338a1281SOctavian Purdila default:
256338a1281SOctavian Purdila dev_dbg(dev, "nonzero urb status received %d\n", urb->status);
257338a1281SOctavian Purdila goto out;
258338a1281SOctavian Purdila }
259338a1281SOctavian Purdila
260338a1281SOctavian Purdila if (urb->actual_length < sizeof(struct dln2_header)) {
261338a1281SOctavian Purdila dev_err(dev, "short response: %d\n", urb->actual_length);
262338a1281SOctavian Purdila goto out;
263338a1281SOctavian Purdila }
264338a1281SOctavian Purdila
265338a1281SOctavian Purdila handle = le16_to_cpu(hdr->handle);
266338a1281SOctavian Purdila id = le16_to_cpu(hdr->id);
267338a1281SOctavian Purdila echo = le16_to_cpu(hdr->echo);
268338a1281SOctavian Purdila size = le16_to_cpu(hdr->size);
269338a1281SOctavian Purdila
270338a1281SOctavian Purdila if (size != urb->actual_length) {
271338a1281SOctavian Purdila dev_err(dev, "size mismatch: handle %x cmd %x echo %x size %d actual %d\n",
272338a1281SOctavian Purdila handle, id, echo, size, urb->actual_length);
273338a1281SOctavian Purdila goto out;
274338a1281SOctavian Purdila }
275338a1281SOctavian Purdila
276338a1281SOctavian Purdila if (handle >= DLN2_HANDLES) {
277338a1281SOctavian Purdila dev_warn(dev, "invalid handle %d\n", handle);
278338a1281SOctavian Purdila goto out;
279338a1281SOctavian Purdila }
280338a1281SOctavian Purdila
281338a1281SOctavian Purdila data = urb->transfer_buffer + sizeof(struct dln2_header);
282338a1281SOctavian Purdila len = urb->actual_length - sizeof(struct dln2_header);
283338a1281SOctavian Purdila
284338a1281SOctavian Purdila if (handle == DLN2_HANDLE_EVENT) {
2853d858942SAndy Shevchenko unsigned long flags;
2863d858942SAndy Shevchenko
2873d858942SAndy Shevchenko spin_lock_irqsave(&dln2->event_cb_lock, flags);
288338a1281SOctavian Purdila dln2_run_event_callbacks(dln2, id, echo, data, len);
2893d858942SAndy Shevchenko spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
290338a1281SOctavian Purdila } else {
291338a1281SOctavian Purdila /* URB will be re-submitted in _dln2_transfer (free_rx_slot) */
292338a1281SOctavian Purdila if (dln2_transfer_complete(dln2, urb, handle, echo))
293338a1281SOctavian Purdila return;
294338a1281SOctavian Purdila }
295338a1281SOctavian Purdila
296338a1281SOctavian Purdila out:
297338a1281SOctavian Purdila err = usb_submit_urb(urb, GFP_ATOMIC);
298338a1281SOctavian Purdila if (err < 0)
299338a1281SOctavian Purdila dev_err(dev, "failed to resubmit RX URB: %d\n", err);
300338a1281SOctavian Purdila }
301338a1281SOctavian Purdila
dln2_prep_buf(u16 handle,u16 cmd,u16 echo,const void * obuf,int * obuf_len,gfp_t gfp)302338a1281SOctavian Purdila static void *dln2_prep_buf(u16 handle, u16 cmd, u16 echo, const void *obuf,
303338a1281SOctavian Purdila int *obuf_len, gfp_t gfp)
304338a1281SOctavian Purdila {
305338a1281SOctavian Purdila int len;
306338a1281SOctavian Purdila void *buf;
307338a1281SOctavian Purdila struct dln2_header *hdr;
308338a1281SOctavian Purdila
309338a1281SOctavian Purdila len = *obuf_len + sizeof(*hdr);
310338a1281SOctavian Purdila buf = kmalloc(len, gfp);
311338a1281SOctavian Purdila if (!buf)
312338a1281SOctavian Purdila return NULL;
313338a1281SOctavian Purdila
314338a1281SOctavian Purdila hdr = (struct dln2_header *)buf;
315338a1281SOctavian Purdila hdr->id = cpu_to_le16(cmd);
316338a1281SOctavian Purdila hdr->size = cpu_to_le16(len);
317338a1281SOctavian Purdila hdr->echo = cpu_to_le16(echo);
318338a1281SOctavian Purdila hdr->handle = cpu_to_le16(handle);
319338a1281SOctavian Purdila
320338a1281SOctavian Purdila memcpy(buf + sizeof(*hdr), obuf, *obuf_len);
321338a1281SOctavian Purdila
322338a1281SOctavian Purdila *obuf_len = len;
323338a1281SOctavian Purdila
324338a1281SOctavian Purdila return buf;
325338a1281SOctavian Purdila }
326338a1281SOctavian Purdila
dln2_send_wait(struct dln2_dev * dln2,u16 handle,u16 cmd,u16 echo,const void * obuf,int obuf_len)327338a1281SOctavian Purdila static int dln2_send_wait(struct dln2_dev *dln2, u16 handle, u16 cmd, u16 echo,
328338a1281SOctavian Purdila const void *obuf, int obuf_len)
329338a1281SOctavian Purdila {
330338a1281SOctavian Purdila int ret = 0;
331338a1281SOctavian Purdila int len = obuf_len;
332338a1281SOctavian Purdila void *buf;
333338a1281SOctavian Purdila int actual;
334338a1281SOctavian Purdila
335338a1281SOctavian Purdila buf = dln2_prep_buf(handle, cmd, echo, obuf, &len, GFP_KERNEL);
336338a1281SOctavian Purdila if (!buf)
337338a1281SOctavian Purdila return -ENOMEM;
338338a1281SOctavian Purdila
339338a1281SOctavian Purdila ret = usb_bulk_msg(dln2->usb_dev,
340338a1281SOctavian Purdila usb_sndbulkpipe(dln2->usb_dev, dln2->ep_out),
341338a1281SOctavian Purdila buf, len, &actual, DLN2_USB_TIMEOUT);
342338a1281SOctavian Purdila
343338a1281SOctavian Purdila kfree(buf);
344338a1281SOctavian Purdila
345338a1281SOctavian Purdila return ret;
346338a1281SOctavian Purdila }
347338a1281SOctavian Purdila
find_free_slot(struct dln2_dev * dln2,u16 handle,int * slot)348338a1281SOctavian Purdila static bool find_free_slot(struct dln2_dev *dln2, u16 handle, int *slot)
349338a1281SOctavian Purdila {
350338a1281SOctavian Purdila struct dln2_mod_rx_slots *rxs;
351338a1281SOctavian Purdila unsigned long flags;
352338a1281SOctavian Purdila
353338a1281SOctavian Purdila if (dln2->disconnect) {
354338a1281SOctavian Purdila *slot = -ENODEV;
355338a1281SOctavian Purdila return true;
356338a1281SOctavian Purdila }
357338a1281SOctavian Purdila
358338a1281SOctavian Purdila rxs = &dln2->mod_rx_slots[handle];
359338a1281SOctavian Purdila
360338a1281SOctavian Purdila spin_lock_irqsave(&rxs->lock, flags);
361338a1281SOctavian Purdila
362338a1281SOctavian Purdila *slot = find_first_zero_bit(rxs->bmap, DLN2_MAX_RX_SLOTS);
363338a1281SOctavian Purdila
364338a1281SOctavian Purdila if (*slot < DLN2_MAX_RX_SLOTS) {
365338a1281SOctavian Purdila struct dln2_rx_context *rxc = &rxs->slots[*slot];
366338a1281SOctavian Purdila
367338a1281SOctavian Purdila set_bit(*slot, rxs->bmap);
368338a1281SOctavian Purdila rxc->in_use = true;
369338a1281SOctavian Purdila }
370338a1281SOctavian Purdila
371338a1281SOctavian Purdila spin_unlock_irqrestore(&rxs->lock, flags);
372338a1281SOctavian Purdila
373338a1281SOctavian Purdila return *slot < DLN2_MAX_RX_SLOTS;
374338a1281SOctavian Purdila }
375338a1281SOctavian Purdila
alloc_rx_slot(struct dln2_dev * dln2,u16 handle)376338a1281SOctavian Purdila static int alloc_rx_slot(struct dln2_dev *dln2, u16 handle)
377338a1281SOctavian Purdila {
378338a1281SOctavian Purdila int ret;
379338a1281SOctavian Purdila int slot;
380338a1281SOctavian Purdila
381338a1281SOctavian Purdila /*
382338a1281SOctavian Purdila * No need to timeout here, the wait is bounded by the timeout in
383338a1281SOctavian Purdila * _dln2_transfer.
384338a1281SOctavian Purdila */
385338a1281SOctavian Purdila ret = wait_event_interruptible(dln2->mod_rx_slots[handle].wq,
386338a1281SOctavian Purdila find_free_slot(dln2, handle, &slot));
387338a1281SOctavian Purdila if (ret < 0)
388338a1281SOctavian Purdila return ret;
389338a1281SOctavian Purdila
390338a1281SOctavian Purdila return slot;
391338a1281SOctavian Purdila }
392338a1281SOctavian Purdila
free_rx_slot(struct dln2_dev * dln2,u16 handle,int slot)393338a1281SOctavian Purdila static void free_rx_slot(struct dln2_dev *dln2, u16 handle, int slot)
394338a1281SOctavian Purdila {
395338a1281SOctavian Purdila struct dln2_mod_rx_slots *rxs;
396338a1281SOctavian Purdila struct urb *urb = NULL;
397338a1281SOctavian Purdila unsigned long flags;
398338a1281SOctavian Purdila struct dln2_rx_context *rxc;
399338a1281SOctavian Purdila
400338a1281SOctavian Purdila rxs = &dln2->mod_rx_slots[handle];
401338a1281SOctavian Purdila
402338a1281SOctavian Purdila spin_lock_irqsave(&rxs->lock, flags);
403338a1281SOctavian Purdila
404338a1281SOctavian Purdila clear_bit(slot, rxs->bmap);
405338a1281SOctavian Purdila
406338a1281SOctavian Purdila rxc = &rxs->slots[slot];
407338a1281SOctavian Purdila rxc->in_use = false;
408338a1281SOctavian Purdila urb = rxc->urb;
409338a1281SOctavian Purdila rxc->urb = NULL;
410338a1281SOctavian Purdila reinit_completion(&rxc->done);
411338a1281SOctavian Purdila
412338a1281SOctavian Purdila spin_unlock_irqrestore(&rxs->lock, flags);
413338a1281SOctavian Purdila
414338a1281SOctavian Purdila if (urb) {
415338a1281SOctavian Purdila int err;
416338a1281SOctavian Purdila struct device *dev = &dln2->interface->dev;
417338a1281SOctavian Purdila
418338a1281SOctavian Purdila err = usb_submit_urb(urb, GFP_KERNEL);
419338a1281SOctavian Purdila if (err < 0)
420338a1281SOctavian Purdila dev_err(dev, "failed to resubmit RX URB: %d\n", err);
421338a1281SOctavian Purdila }
422338a1281SOctavian Purdila
423338a1281SOctavian Purdila wake_up_interruptible(&rxs->wq);
424338a1281SOctavian Purdila }
425338a1281SOctavian Purdila
_dln2_transfer(struct dln2_dev * dln2,u16 handle,u16 cmd,const void * obuf,unsigned obuf_len,void * ibuf,unsigned * ibuf_len)426338a1281SOctavian Purdila static int _dln2_transfer(struct dln2_dev *dln2, u16 handle, u16 cmd,
427338a1281SOctavian Purdila const void *obuf, unsigned obuf_len,
428338a1281SOctavian Purdila void *ibuf, unsigned *ibuf_len)
429338a1281SOctavian Purdila {
430338a1281SOctavian Purdila int ret = 0;
431338a1281SOctavian Purdila int rx_slot;
432338a1281SOctavian Purdila struct dln2_response *rsp;
433338a1281SOctavian Purdila struct dln2_rx_context *rxc;
434338a1281SOctavian Purdila struct device *dev = &dln2->interface->dev;
43548579a9aSNicholas Mc Guire const unsigned long timeout = msecs_to_jiffies(DLN2_USB_TIMEOUT);
436338a1281SOctavian Purdila struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle];
4372fc2b484SDan Carpenter int size;
438338a1281SOctavian Purdila
439338a1281SOctavian Purdila spin_lock(&dln2->disconnect_lock);
440338a1281SOctavian Purdila if (!dln2->disconnect)
441338a1281SOctavian Purdila dln2->active_transfers++;
442338a1281SOctavian Purdila else
443338a1281SOctavian Purdila ret = -ENODEV;
444338a1281SOctavian Purdila spin_unlock(&dln2->disconnect_lock);
445338a1281SOctavian Purdila
446338a1281SOctavian Purdila if (ret)
447338a1281SOctavian Purdila return ret;
448338a1281SOctavian Purdila
449338a1281SOctavian Purdila rx_slot = alloc_rx_slot(dln2, handle);
450338a1281SOctavian Purdila if (rx_slot < 0) {
451338a1281SOctavian Purdila ret = rx_slot;
452338a1281SOctavian Purdila goto out_decr;
453338a1281SOctavian Purdila }
454338a1281SOctavian Purdila
455338a1281SOctavian Purdila ret = dln2_send_wait(dln2, handle, cmd, rx_slot, obuf, obuf_len);
456338a1281SOctavian Purdila if (ret < 0) {
457338a1281SOctavian Purdila dev_err(dev, "USB write failed: %d\n", ret);
458338a1281SOctavian Purdila goto out_free_rx_slot;
459338a1281SOctavian Purdila }
460338a1281SOctavian Purdila
461338a1281SOctavian Purdila rxc = &rxs->slots[rx_slot];
462338a1281SOctavian Purdila
463338a1281SOctavian Purdila ret = wait_for_completion_interruptible_timeout(&rxc->done, timeout);
464338a1281SOctavian Purdila if (ret <= 0) {
465338a1281SOctavian Purdila if (!ret)
466338a1281SOctavian Purdila ret = -ETIMEDOUT;
467338a1281SOctavian Purdila goto out_free_rx_slot;
4687ca2b1c6SOctavian Purdila } else {
4697ca2b1c6SOctavian Purdila ret = 0;
470338a1281SOctavian Purdila }
471338a1281SOctavian Purdila
472338a1281SOctavian Purdila if (dln2->disconnect) {
473338a1281SOctavian Purdila ret = -ENODEV;
474338a1281SOctavian Purdila goto out_free_rx_slot;
475338a1281SOctavian Purdila }
476338a1281SOctavian Purdila
477338a1281SOctavian Purdila /* if we got here we know that the response header has been checked */
478338a1281SOctavian Purdila rsp = rxc->urb->transfer_buffer;
4792fc2b484SDan Carpenter size = le16_to_cpu(rsp->hdr.size);
480338a1281SOctavian Purdila
4812fc2b484SDan Carpenter if (size < sizeof(*rsp)) {
482338a1281SOctavian Purdila ret = -EPROTO;
483338a1281SOctavian Purdila goto out_free_rx_slot;
484338a1281SOctavian Purdila }
485338a1281SOctavian Purdila
486338a1281SOctavian Purdila if (le16_to_cpu(rsp->result) > 0x80) {
487338a1281SOctavian Purdila dev_dbg(dev, "%d received response with error %d\n",
488338a1281SOctavian Purdila handle, le16_to_cpu(rsp->result));
489338a1281SOctavian Purdila ret = -EREMOTEIO;
490338a1281SOctavian Purdila goto out_free_rx_slot;
491338a1281SOctavian Purdila }
492338a1281SOctavian Purdila
4937ca2b1c6SOctavian Purdila if (!ibuf)
494338a1281SOctavian Purdila goto out_free_rx_slot;
495338a1281SOctavian Purdila
4962fc2b484SDan Carpenter if (*ibuf_len > size - sizeof(*rsp))
4972fc2b484SDan Carpenter *ibuf_len = size - sizeof(*rsp);
498338a1281SOctavian Purdila
499338a1281SOctavian Purdila memcpy(ibuf, rsp + 1, *ibuf_len);
500338a1281SOctavian Purdila
501338a1281SOctavian Purdila out_free_rx_slot:
502338a1281SOctavian Purdila free_rx_slot(dln2, handle, rx_slot);
503338a1281SOctavian Purdila out_decr:
504338a1281SOctavian Purdila spin_lock(&dln2->disconnect_lock);
505338a1281SOctavian Purdila dln2->active_transfers--;
506338a1281SOctavian Purdila spin_unlock(&dln2->disconnect_lock);
507338a1281SOctavian Purdila if (dln2->disconnect)
508338a1281SOctavian Purdila wake_up(&dln2->disconnect_wq);
509338a1281SOctavian Purdila
510338a1281SOctavian Purdila return ret;
511338a1281SOctavian Purdila }
512338a1281SOctavian Purdila
dln2_transfer(struct platform_device * pdev,u16 cmd,const void * obuf,unsigned obuf_len,void * ibuf,unsigned * ibuf_len)513338a1281SOctavian Purdila int dln2_transfer(struct platform_device *pdev, u16 cmd,
514338a1281SOctavian Purdila const void *obuf, unsigned obuf_len,
515338a1281SOctavian Purdila void *ibuf, unsigned *ibuf_len)
516338a1281SOctavian Purdila {
517338a1281SOctavian Purdila struct dln2_platform_data *dln2_pdata;
518338a1281SOctavian Purdila struct dln2_dev *dln2;
519338a1281SOctavian Purdila u16 handle;
520338a1281SOctavian Purdila
521338a1281SOctavian Purdila dln2 = dev_get_drvdata(pdev->dev.parent);
522338a1281SOctavian Purdila dln2_pdata = dev_get_platdata(&pdev->dev);
523338a1281SOctavian Purdila handle = dln2_pdata->handle;
524338a1281SOctavian Purdila
525338a1281SOctavian Purdila return _dln2_transfer(dln2, handle, cmd, obuf, obuf_len, ibuf,
526338a1281SOctavian Purdila ibuf_len);
527338a1281SOctavian Purdila }
528338a1281SOctavian Purdila EXPORT_SYMBOL(dln2_transfer);
529338a1281SOctavian Purdila
dln2_check_hw(struct dln2_dev * dln2)530338a1281SOctavian Purdila static int dln2_check_hw(struct dln2_dev *dln2)
531338a1281SOctavian Purdila {
532338a1281SOctavian Purdila int ret;
533338a1281SOctavian Purdila __le32 hw_type;
534338a1281SOctavian Purdila int len = sizeof(hw_type);
535338a1281SOctavian Purdila
536338a1281SOctavian Purdila ret = _dln2_transfer(dln2, DLN2_HANDLE_CTRL, CMD_GET_DEVICE_VER,
537338a1281SOctavian Purdila NULL, 0, &hw_type, &len);
538338a1281SOctavian Purdila if (ret < 0)
539338a1281SOctavian Purdila return ret;
540338a1281SOctavian Purdila if (len < sizeof(hw_type))
541338a1281SOctavian Purdila return -EREMOTEIO;
542338a1281SOctavian Purdila
543338a1281SOctavian Purdila if (le32_to_cpu(hw_type) != DLN2_HW_ID) {
544338a1281SOctavian Purdila dev_err(&dln2->interface->dev, "Device ID 0x%x not supported\n",
545338a1281SOctavian Purdila le32_to_cpu(hw_type));
546338a1281SOctavian Purdila return -ENODEV;
547338a1281SOctavian Purdila }
548338a1281SOctavian Purdila
549338a1281SOctavian Purdila return 0;
550338a1281SOctavian Purdila }
551338a1281SOctavian Purdila
dln2_print_serialno(struct dln2_dev * dln2)552338a1281SOctavian Purdila static int dln2_print_serialno(struct dln2_dev *dln2)
553338a1281SOctavian Purdila {
554338a1281SOctavian Purdila int ret;
555338a1281SOctavian Purdila __le32 serial_no;
556338a1281SOctavian Purdila int len = sizeof(serial_no);
557338a1281SOctavian Purdila struct device *dev = &dln2->interface->dev;
558338a1281SOctavian Purdila
559338a1281SOctavian Purdila ret = _dln2_transfer(dln2, DLN2_HANDLE_CTRL, CMD_GET_DEVICE_SN, NULL, 0,
560338a1281SOctavian Purdila &serial_no, &len);
561338a1281SOctavian Purdila if (ret < 0)
562338a1281SOctavian Purdila return ret;
563338a1281SOctavian Purdila if (len < sizeof(serial_no))
564338a1281SOctavian Purdila return -EREMOTEIO;
565338a1281SOctavian Purdila
566338a1281SOctavian Purdila dev_info(dev, "Diolan DLN2 serial %u\n", le32_to_cpu(serial_no));
567338a1281SOctavian Purdila
568338a1281SOctavian Purdila return 0;
569338a1281SOctavian Purdila }
570338a1281SOctavian Purdila
dln2_hw_init(struct dln2_dev * dln2)571338a1281SOctavian Purdila static int dln2_hw_init(struct dln2_dev *dln2)
572338a1281SOctavian Purdila {
573338a1281SOctavian Purdila int ret;
574338a1281SOctavian Purdila
575338a1281SOctavian Purdila ret = dln2_check_hw(dln2);
576338a1281SOctavian Purdila if (ret < 0)
577338a1281SOctavian Purdila return ret;
578338a1281SOctavian Purdila
579338a1281SOctavian Purdila return dln2_print_serialno(dln2);
580338a1281SOctavian Purdila }
581338a1281SOctavian Purdila
dln2_free_rx_urbs(struct dln2_dev * dln2)582338a1281SOctavian Purdila static void dln2_free_rx_urbs(struct dln2_dev *dln2)
583338a1281SOctavian Purdila {
584338a1281SOctavian Purdila int i;
585338a1281SOctavian Purdila
586338a1281SOctavian Purdila for (i = 0; i < DLN2_MAX_URBS; i++) {
587338a1281SOctavian Purdila usb_free_urb(dln2->rx_urb[i]);
588338a1281SOctavian Purdila kfree(dln2->rx_buf[i]);
589338a1281SOctavian Purdila }
590338a1281SOctavian Purdila }
591338a1281SOctavian Purdila
dln2_stop_rx_urbs(struct dln2_dev * dln2)592ee231aeeSOctavian Purdila static void dln2_stop_rx_urbs(struct dln2_dev *dln2)
593ee231aeeSOctavian Purdila {
594ee231aeeSOctavian Purdila int i;
595ee231aeeSOctavian Purdila
596ee231aeeSOctavian Purdila for (i = 0; i < DLN2_MAX_URBS; i++)
597ee231aeeSOctavian Purdila usb_kill_urb(dln2->rx_urb[i]);
598ee231aeeSOctavian Purdila }
599ee231aeeSOctavian Purdila
dln2_free(struct dln2_dev * dln2)600338a1281SOctavian Purdila static void dln2_free(struct dln2_dev *dln2)
601338a1281SOctavian Purdila {
602338a1281SOctavian Purdila dln2_free_rx_urbs(dln2);
603338a1281SOctavian Purdila usb_put_dev(dln2->usb_dev);
604338a1281SOctavian Purdila kfree(dln2);
605338a1281SOctavian Purdila }
606338a1281SOctavian Purdila
dln2_setup_rx_urbs(struct dln2_dev * dln2,struct usb_host_interface * hostif)607338a1281SOctavian Purdila static int dln2_setup_rx_urbs(struct dln2_dev *dln2,
608338a1281SOctavian Purdila struct usb_host_interface *hostif)
609338a1281SOctavian Purdila {
610338a1281SOctavian Purdila int i;
611338a1281SOctavian Purdila const int rx_max_size = DLN2_RX_BUF_SIZE;
612338a1281SOctavian Purdila
613338a1281SOctavian Purdila for (i = 0; i < DLN2_MAX_URBS; i++) {
614338a1281SOctavian Purdila dln2->rx_buf[i] = kmalloc(rx_max_size, GFP_KERNEL);
615338a1281SOctavian Purdila if (!dln2->rx_buf[i])
616338a1281SOctavian Purdila return -ENOMEM;
617338a1281SOctavian Purdila
618338a1281SOctavian Purdila dln2->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
619338a1281SOctavian Purdila if (!dln2->rx_urb[i])
620338a1281SOctavian Purdila return -ENOMEM;
621338a1281SOctavian Purdila
622338a1281SOctavian Purdila usb_fill_bulk_urb(dln2->rx_urb[i], dln2->usb_dev,
623338a1281SOctavian Purdila usb_rcvbulkpipe(dln2->usb_dev, dln2->ep_in),
624338a1281SOctavian Purdila dln2->rx_buf[i], rx_max_size, dln2_rx, dln2);
625ee231aeeSOctavian Purdila }
626338a1281SOctavian Purdila
627ee231aeeSOctavian Purdila return 0;
628ee231aeeSOctavian Purdila }
629ee231aeeSOctavian Purdila
dln2_start_rx_urbs(struct dln2_dev * dln2,gfp_t gfp)630ee231aeeSOctavian Purdila static int dln2_start_rx_urbs(struct dln2_dev *dln2, gfp_t gfp)
631ee231aeeSOctavian Purdila {
632ee231aeeSOctavian Purdila struct device *dev = &dln2->interface->dev;
633ee231aeeSOctavian Purdila int ret;
634ee231aeeSOctavian Purdila int i;
635ee231aeeSOctavian Purdila
636ee231aeeSOctavian Purdila for (i = 0; i < DLN2_MAX_URBS; i++) {
637ee231aeeSOctavian Purdila ret = usb_submit_urb(dln2->rx_urb[i], gfp);
638338a1281SOctavian Purdila if (ret < 0) {
639338a1281SOctavian Purdila dev_err(dev, "failed to submit RX URB: %d\n", ret);
640338a1281SOctavian Purdila return ret;
641338a1281SOctavian Purdila }
642338a1281SOctavian Purdila }
643338a1281SOctavian Purdila
644338a1281SOctavian Purdila return 0;
645338a1281SOctavian Purdila }
646338a1281SOctavian Purdila
647e3fadb35SAndy Shevchenko enum {
648e3fadb35SAndy Shevchenko DLN2_ACPI_MATCH_GPIO = 0,
649e3fadb35SAndy Shevchenko DLN2_ACPI_MATCH_I2C = 1,
650e3fadb35SAndy Shevchenko DLN2_ACPI_MATCH_SPI = 2,
651313c84b5SJack Andersen DLN2_ACPI_MATCH_ADC = 3,
652e3fadb35SAndy Shevchenko };
653e3fadb35SAndy Shevchenko
654338a1281SOctavian Purdila static struct dln2_platform_data dln2_pdata_gpio = {
655338a1281SOctavian Purdila .handle = DLN2_HANDLE_GPIO,
656338a1281SOctavian Purdila };
657338a1281SOctavian Purdila
658e3fadb35SAndy Shevchenko static struct mfd_cell_acpi_match dln2_acpi_match_gpio = {
659e3fadb35SAndy Shevchenko .adr = DLN2_ACPI_MATCH_GPIO,
660e3fadb35SAndy Shevchenko };
661e3fadb35SAndy Shevchenko
662338a1281SOctavian Purdila /* Only one I2C port seems to be supported on current hardware */
663338a1281SOctavian Purdila static struct dln2_platform_data dln2_pdata_i2c = {
664338a1281SOctavian Purdila .handle = DLN2_HANDLE_I2C,
665338a1281SOctavian Purdila .port = 0,
666338a1281SOctavian Purdila };
667338a1281SOctavian Purdila
668e3fadb35SAndy Shevchenko static struct mfd_cell_acpi_match dln2_acpi_match_i2c = {
669e3fadb35SAndy Shevchenko .adr = DLN2_ACPI_MATCH_I2C,
670e3fadb35SAndy Shevchenko };
671e3fadb35SAndy Shevchenko
67221cf3318SLaurentiu Palcu /* Only one SPI port supported */
67321cf3318SLaurentiu Palcu static struct dln2_platform_data dln2_pdata_spi = {
67421cf3318SLaurentiu Palcu .handle = DLN2_HANDLE_SPI,
67521cf3318SLaurentiu Palcu .port = 0,
67621cf3318SLaurentiu Palcu };
67721cf3318SLaurentiu Palcu
678e3fadb35SAndy Shevchenko static struct mfd_cell_acpi_match dln2_acpi_match_spi = {
679e3fadb35SAndy Shevchenko .adr = DLN2_ACPI_MATCH_SPI,
680e3fadb35SAndy Shevchenko };
681e3fadb35SAndy Shevchenko
682313c84b5SJack Andersen /* Only one ADC port supported */
683313c84b5SJack Andersen static struct dln2_platform_data dln2_pdata_adc = {
684313c84b5SJack Andersen .handle = DLN2_HANDLE_ADC,
685313c84b5SJack Andersen .port = 0,
686313c84b5SJack Andersen };
687313c84b5SJack Andersen
688313c84b5SJack Andersen static struct mfd_cell_acpi_match dln2_acpi_match_adc = {
689313c84b5SJack Andersen .adr = DLN2_ACPI_MATCH_ADC,
690313c84b5SJack Andersen };
691313c84b5SJack Andersen
692338a1281SOctavian Purdila static const struct mfd_cell dln2_devs[] = {
693338a1281SOctavian Purdila {
694338a1281SOctavian Purdila .name = "dln2-gpio",
695e3fadb35SAndy Shevchenko .acpi_match = &dln2_acpi_match_gpio,
696338a1281SOctavian Purdila .platform_data = &dln2_pdata_gpio,
697338a1281SOctavian Purdila .pdata_size = sizeof(struct dln2_platform_data),
698338a1281SOctavian Purdila },
699338a1281SOctavian Purdila {
700338a1281SOctavian Purdila .name = "dln2-i2c",
701e3fadb35SAndy Shevchenko .acpi_match = &dln2_acpi_match_i2c,
702338a1281SOctavian Purdila .platform_data = &dln2_pdata_i2c,
703338a1281SOctavian Purdila .pdata_size = sizeof(struct dln2_platform_data),
704338a1281SOctavian Purdila },
70521cf3318SLaurentiu Palcu {
70621cf3318SLaurentiu Palcu .name = "dln2-spi",
707e3fadb35SAndy Shevchenko .acpi_match = &dln2_acpi_match_spi,
70821cf3318SLaurentiu Palcu .platform_data = &dln2_pdata_spi,
70921cf3318SLaurentiu Palcu .pdata_size = sizeof(struct dln2_platform_data),
71021cf3318SLaurentiu Palcu },
711313c84b5SJack Andersen {
712313c84b5SJack Andersen .name = "dln2-adc",
713313c84b5SJack Andersen .acpi_match = &dln2_acpi_match_adc,
714313c84b5SJack Andersen .platform_data = &dln2_pdata_adc,
715313c84b5SJack Andersen .pdata_size = sizeof(struct dln2_platform_data),
716313c84b5SJack Andersen },
717338a1281SOctavian Purdila };
718338a1281SOctavian Purdila
dln2_stop(struct dln2_dev * dln2)719ee231aeeSOctavian Purdila static void dln2_stop(struct dln2_dev *dln2)
720338a1281SOctavian Purdila {
721338a1281SOctavian Purdila int i, j;
722338a1281SOctavian Purdila
723338a1281SOctavian Purdila /* don't allow starting new transfers */
724338a1281SOctavian Purdila spin_lock(&dln2->disconnect_lock);
725338a1281SOctavian Purdila dln2->disconnect = true;
726338a1281SOctavian Purdila spin_unlock(&dln2->disconnect_lock);
727338a1281SOctavian Purdila
728338a1281SOctavian Purdila /* cancel in progress transfers */
729338a1281SOctavian Purdila for (i = 0; i < DLN2_HANDLES; i++) {
730338a1281SOctavian Purdila struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[i];
731338a1281SOctavian Purdila unsigned long flags;
732338a1281SOctavian Purdila
733338a1281SOctavian Purdila spin_lock_irqsave(&rxs->lock, flags);
734338a1281SOctavian Purdila
735338a1281SOctavian Purdila /* cancel all response waiters */
736338a1281SOctavian Purdila for (j = 0; j < DLN2_MAX_RX_SLOTS; j++) {
737338a1281SOctavian Purdila struct dln2_rx_context *rxc = &rxs->slots[j];
738338a1281SOctavian Purdila
739338a1281SOctavian Purdila if (rxc->in_use)
740338a1281SOctavian Purdila complete(&rxc->done);
741338a1281SOctavian Purdila }
742338a1281SOctavian Purdila
743338a1281SOctavian Purdila spin_unlock_irqrestore(&rxs->lock, flags);
744338a1281SOctavian Purdila }
745338a1281SOctavian Purdila
746338a1281SOctavian Purdila /* wait for transfers to end */
747338a1281SOctavian Purdila wait_event(dln2->disconnect_wq, !dln2->active_transfers);
748338a1281SOctavian Purdila
749ee231aeeSOctavian Purdila dln2_stop_rx_urbs(dln2);
750ee231aeeSOctavian Purdila }
751ee231aeeSOctavian Purdila
dln2_disconnect(struct usb_interface * interface)752ee231aeeSOctavian Purdila static void dln2_disconnect(struct usb_interface *interface)
753ee231aeeSOctavian Purdila {
754ee231aeeSOctavian Purdila struct dln2_dev *dln2 = usb_get_intfdata(interface);
755ee231aeeSOctavian Purdila
756ee231aeeSOctavian Purdila dln2_stop(dln2);
757ee231aeeSOctavian Purdila
758338a1281SOctavian Purdila mfd_remove_devices(&interface->dev);
759338a1281SOctavian Purdila
760338a1281SOctavian Purdila dln2_free(dln2);
761338a1281SOctavian Purdila }
762338a1281SOctavian Purdila
dln2_probe(struct usb_interface * interface,const struct usb_device_id * usb_id)763338a1281SOctavian Purdila static int dln2_probe(struct usb_interface *interface,
764338a1281SOctavian Purdila const struct usb_device_id *usb_id)
765338a1281SOctavian Purdila {
766338a1281SOctavian Purdila struct usb_host_interface *hostif = interface->cur_altsetting;
7672b8bd606SOliver Neukum struct usb_endpoint_descriptor *epin;
7682b8bd606SOliver Neukum struct usb_endpoint_descriptor *epout;
769338a1281SOctavian Purdila struct device *dev = &interface->dev;
770338a1281SOctavian Purdila struct dln2_dev *dln2;
771338a1281SOctavian Purdila int ret;
772338a1281SOctavian Purdila int i, j;
773338a1281SOctavian Purdila
774*99a7ec2fSAndy Shevchenko if (hostif->desc.bInterfaceNumber != 0)
775338a1281SOctavian Purdila return -ENODEV;
776338a1281SOctavian Purdila
777*99a7ec2fSAndy Shevchenko ret = usb_find_common_endpoints(hostif, &epin, &epout, NULL, NULL);
778*99a7ec2fSAndy Shevchenko if (ret)
779*99a7ec2fSAndy Shevchenko return ret;
7802b8bd606SOliver Neukum
781338a1281SOctavian Purdila dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL);
782338a1281SOctavian Purdila if (!dln2)
783338a1281SOctavian Purdila return -ENOMEM;
784338a1281SOctavian Purdila
7852b8bd606SOliver Neukum dln2->ep_out = epout->bEndpointAddress;
7862b8bd606SOliver Neukum dln2->ep_in = epin->bEndpointAddress;
787338a1281SOctavian Purdila dln2->usb_dev = usb_get_dev(interface_to_usbdev(interface));
788338a1281SOctavian Purdila dln2->interface = interface;
789338a1281SOctavian Purdila usb_set_intfdata(interface, dln2);
790338a1281SOctavian Purdila init_waitqueue_head(&dln2->disconnect_wq);
791338a1281SOctavian Purdila
792338a1281SOctavian Purdila for (i = 0; i < DLN2_HANDLES; i++) {
793338a1281SOctavian Purdila init_waitqueue_head(&dln2->mod_rx_slots[i].wq);
794338a1281SOctavian Purdila spin_lock_init(&dln2->mod_rx_slots[i].lock);
795338a1281SOctavian Purdila for (j = 0; j < DLN2_MAX_RX_SLOTS; j++)
796338a1281SOctavian Purdila init_completion(&dln2->mod_rx_slots[i].slots[j].done);
797338a1281SOctavian Purdila }
798338a1281SOctavian Purdila
799338a1281SOctavian Purdila spin_lock_init(&dln2->event_cb_lock);
800338a1281SOctavian Purdila spin_lock_init(&dln2->disconnect_lock);
801338a1281SOctavian Purdila INIT_LIST_HEAD(&dln2->event_cb_list);
802338a1281SOctavian Purdila
803338a1281SOctavian Purdila ret = dln2_setup_rx_urbs(dln2, hostif);
804338a1281SOctavian Purdila if (ret)
805ee231aeeSOctavian Purdila goto out_free;
806ee231aeeSOctavian Purdila
807ee231aeeSOctavian Purdila ret = dln2_start_rx_urbs(dln2, GFP_KERNEL);
808ee231aeeSOctavian Purdila if (ret)
809ee231aeeSOctavian Purdila goto out_stop_rx;
810338a1281SOctavian Purdila
811338a1281SOctavian Purdila ret = dln2_hw_init(dln2);
812338a1281SOctavian Purdila if (ret < 0) {
813338a1281SOctavian Purdila dev_err(dev, "failed to initialize hardware\n");
814ee231aeeSOctavian Purdila goto out_stop_rx;
815338a1281SOctavian Purdila }
816338a1281SOctavian Purdila
817338a1281SOctavian Purdila ret = mfd_add_hotplug_devices(dev, dln2_devs, ARRAY_SIZE(dln2_devs));
818338a1281SOctavian Purdila if (ret != 0) {
819338a1281SOctavian Purdila dev_err(dev, "failed to add mfd devices to core\n");
820ee231aeeSOctavian Purdila goto out_stop_rx;
821338a1281SOctavian Purdila }
822338a1281SOctavian Purdila
823338a1281SOctavian Purdila return 0;
824338a1281SOctavian Purdila
825ee231aeeSOctavian Purdila out_stop_rx:
826ee231aeeSOctavian Purdila dln2_stop_rx_urbs(dln2);
827ee231aeeSOctavian Purdila
828ee231aeeSOctavian Purdila out_free:
829338a1281SOctavian Purdila dln2_free(dln2);
830338a1281SOctavian Purdila
831338a1281SOctavian Purdila return ret;
832338a1281SOctavian Purdila }
833338a1281SOctavian Purdila
dln2_suspend(struct usb_interface * iface,pm_message_t message)8343daa122dSOctavian Purdila static int dln2_suspend(struct usb_interface *iface, pm_message_t message)
8353daa122dSOctavian Purdila {
8363daa122dSOctavian Purdila struct dln2_dev *dln2 = usb_get_intfdata(iface);
8373daa122dSOctavian Purdila
8383daa122dSOctavian Purdila dln2_stop(dln2);
8393daa122dSOctavian Purdila
8403daa122dSOctavian Purdila return 0;
8413daa122dSOctavian Purdila }
8423daa122dSOctavian Purdila
dln2_resume(struct usb_interface * iface)8433daa122dSOctavian Purdila static int dln2_resume(struct usb_interface *iface)
8443daa122dSOctavian Purdila {
8453daa122dSOctavian Purdila struct dln2_dev *dln2 = usb_get_intfdata(iface);
8463daa122dSOctavian Purdila
8473daa122dSOctavian Purdila dln2->disconnect = false;
8483daa122dSOctavian Purdila
8493daa122dSOctavian Purdila return dln2_start_rx_urbs(dln2, GFP_NOIO);
8503daa122dSOctavian Purdila }
8513daa122dSOctavian Purdila
852338a1281SOctavian Purdila static const struct usb_device_id dln2_table[] = {
853338a1281SOctavian Purdila { USB_DEVICE(0xa257, 0x2013) },
854338a1281SOctavian Purdila { }
855338a1281SOctavian Purdila };
856338a1281SOctavian Purdila
857338a1281SOctavian Purdila MODULE_DEVICE_TABLE(usb, dln2_table);
858338a1281SOctavian Purdila
859338a1281SOctavian Purdila static struct usb_driver dln2_driver = {
860338a1281SOctavian Purdila .name = "dln2",
861338a1281SOctavian Purdila .probe = dln2_probe,
862338a1281SOctavian Purdila .disconnect = dln2_disconnect,
863338a1281SOctavian Purdila .id_table = dln2_table,
8643daa122dSOctavian Purdila .suspend = dln2_suspend,
8653daa122dSOctavian Purdila .resume = dln2_resume,
866338a1281SOctavian Purdila };
867338a1281SOctavian Purdila
868338a1281SOctavian Purdila module_usb_driver(dln2_driver);
869338a1281SOctavian Purdila
870338a1281SOctavian Purdila MODULE_AUTHOR("Octavian Purdila <octavian.purdila@intel.com>");
871338a1281SOctavian Purdila MODULE_DESCRIPTION("Core driver for the Diolan DLN2 interface adapter");
872338a1281SOctavian Purdila MODULE_LICENSE("GPL v2");
873