xref: /openbmc/linux/drivers/mfd/dln2.c (revision e7a7ffeb)
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