xref: /openbmc/u-boot/drivers/usb/gadget/udc/udc-core.c (revision d94604d5)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
2a139b96aSKishon Vijay Abraham I /**
3103fa06cSKishon Vijay Abraham I  * udc-core.c - Core UDC Framework
4a139b96aSKishon Vijay Abraham I  *
5103fa06cSKishon Vijay Abraham I  * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
6103fa06cSKishon Vijay Abraham I  *
7a139b96aSKishon Vijay Abraham I  * Author: Felipe Balbi <balbi@ti.com>
8a139b96aSKishon Vijay Abraham I  *
9103fa06cSKishon Vijay Abraham I  * Taken from Linux Kernel v3.19-rc1 (drivers/usb/gadget/udc-core.c) and ported
10103fa06cSKishon Vijay Abraham I  * to uboot.
11a139b96aSKishon Vijay Abraham I  *
12103fa06cSKishon Vijay Abraham I  * commit 02e8c96627 : usb: gadget: udc: core: prepend udc_attach_driver with
13103fa06cSKishon Vijay Abraham I  *		       usb_
14a139b96aSKishon Vijay Abraham I  */
15a139b96aSKishon Vijay Abraham I 
16103fa06cSKishon Vijay Abraham I #include <linux/compat.h>
17103fa06cSKishon Vijay Abraham I #include <malloc.h>
18103fa06cSKishon Vijay Abraham I #include <asm/cache.h>
19103fa06cSKishon Vijay Abraham I #include <asm/dma-mapping.h>
20103fa06cSKishon Vijay Abraham I #include <common.h>
21*ff8d7558SJean-Jacques Hiblot #include <dm.h>
22*ff8d7558SJean-Jacques Hiblot #include <dm/device-internal.h>
23a139b96aSKishon Vijay Abraham I #include <linux/usb/ch9.h>
24a139b96aSKishon Vijay Abraham I #include <linux/usb/gadget.h>
25a139b96aSKishon Vijay Abraham I 
26a139b96aSKishon Vijay Abraham I /**
27a139b96aSKishon Vijay Abraham I  * struct usb_udc - describes one usb device controller
28a139b96aSKishon Vijay Abraham I  * @driver - the gadget driver pointer. For use by the class code
29a139b96aSKishon Vijay Abraham I  * @dev - the child device to the actual controller
30a139b96aSKishon Vijay Abraham I  * @gadget - the gadget. For use by the class code
31a139b96aSKishon Vijay Abraham I  * @list - for use by the udc class driver
32a139b96aSKishon Vijay Abraham I  *
33a139b96aSKishon Vijay Abraham I  * This represents the internal data structure which is used by the UDC-class
34a139b96aSKishon Vijay Abraham I  * to hold information about udc driver and gadget together.
35a139b96aSKishon Vijay Abraham I  */
36a139b96aSKishon Vijay Abraham I struct usb_udc {
37a139b96aSKishon Vijay Abraham I 	struct usb_gadget_driver	*driver;
38a139b96aSKishon Vijay Abraham I 	struct usb_gadget		*gadget;
39a139b96aSKishon Vijay Abraham I 	struct device			dev;
40a139b96aSKishon Vijay Abraham I 	struct list_head		list;
41a139b96aSKishon Vijay Abraham I };
42a139b96aSKishon Vijay Abraham I 
43a139b96aSKishon Vijay Abraham I static struct class *udc_class;
44a139b96aSKishon Vijay Abraham I static LIST_HEAD(udc_list);
45103fa06cSKishon Vijay Abraham I DEFINE_MUTEX(udc_lock);
46a139b96aSKishon Vijay Abraham I 
47a139b96aSKishon Vijay Abraham I /* ------------------------------------------------------------------------- */
48a139b96aSKishon Vijay Abraham I 
usb_gadget_map_request(struct usb_gadget * gadget,struct usb_request * req,int is_in)49a139b96aSKishon Vijay Abraham I int usb_gadget_map_request(struct usb_gadget *gadget,
50a139b96aSKishon Vijay Abraham I 		struct usb_request *req, int is_in)
51a139b96aSKishon Vijay Abraham I {
52a139b96aSKishon Vijay Abraham I 	if (req->length == 0)
53a139b96aSKishon Vijay Abraham I 		return 0;
54a139b96aSKishon Vijay Abraham I 
55103fa06cSKishon Vijay Abraham I 	req->dma = dma_map_single(req->buf, req->length,
56a139b96aSKishon Vijay Abraham I 				  is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
57a139b96aSKishon Vijay Abraham I 
58a139b96aSKishon Vijay Abraham I 	return 0;
59a139b96aSKishon Vijay Abraham I }
60a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_gadget_map_request);
61a139b96aSKishon Vijay Abraham I 
usb_gadget_unmap_request(struct usb_gadget * gadget,struct usb_request * req,int is_in)62a139b96aSKishon Vijay Abraham I void usb_gadget_unmap_request(struct usb_gadget *gadget,
63a139b96aSKishon Vijay Abraham I 		struct usb_request *req, int is_in)
64a139b96aSKishon Vijay Abraham I {
65a139b96aSKishon Vijay Abraham I 	if (req->length == 0)
66a139b96aSKishon Vijay Abraham I 		return;
67a139b96aSKishon Vijay Abraham I 
68f6fcebf5SMichal Simek 	dma_unmap_single((void *)(uintptr_t)req->dma, req->length,
69a139b96aSKishon Vijay Abraham I 			 is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
70a139b96aSKishon Vijay Abraham I }
71a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
72a139b96aSKishon Vijay Abraham I 
73a139b96aSKishon Vijay Abraham I /* ------------------------------------------------------------------------- */
74a139b96aSKishon Vijay Abraham I 
75a139b96aSKishon Vijay Abraham I /**
76a139b96aSKishon Vijay Abraham I  * usb_gadget_giveback_request - give the request back to the gadget layer
77a139b96aSKishon Vijay Abraham I  * Context: in_interrupt()
78a139b96aSKishon Vijay Abraham I  *
79a139b96aSKishon Vijay Abraham I  * This is called by device controller drivers in order to return the
80a139b96aSKishon Vijay Abraham I  * completed request back to the gadget layer.
81a139b96aSKishon Vijay Abraham I  */
usb_gadget_giveback_request(struct usb_ep * ep,struct usb_request * req)82a139b96aSKishon Vijay Abraham I void usb_gadget_giveback_request(struct usb_ep *ep,
83a139b96aSKishon Vijay Abraham I 		struct usb_request *req)
84a139b96aSKishon Vijay Abraham I {
85a139b96aSKishon Vijay Abraham I 	req->complete(ep, req);
86a139b96aSKishon Vijay Abraham I }
87a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
88a139b96aSKishon Vijay Abraham I 
89a139b96aSKishon Vijay Abraham I /* ------------------------------------------------------------------------- */
90a139b96aSKishon Vijay Abraham I 
usb_gadget_set_state(struct usb_gadget * gadget,enum usb_device_state state)91a139b96aSKishon Vijay Abraham I void usb_gadget_set_state(struct usb_gadget *gadget,
92a139b96aSKishon Vijay Abraham I 		enum usb_device_state state)
93a139b96aSKishon Vijay Abraham I {
94a139b96aSKishon Vijay Abraham I 	gadget->state = state;
95a139b96aSKishon Vijay Abraham I }
96a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_gadget_set_state);
97a139b96aSKishon Vijay Abraham I 
98a139b96aSKishon Vijay Abraham I /* ------------------------------------------------------------------------- */
99a139b96aSKishon Vijay Abraham I 
100a139b96aSKishon Vijay Abraham I /**
101a139b96aSKishon Vijay Abraham I  * usb_gadget_udc_reset - notifies the udc core that bus reset occurs
102a139b96aSKishon Vijay Abraham I  * @gadget: The gadget which bus reset occurs
103a139b96aSKishon Vijay Abraham I  * @driver: The gadget driver we want to notify
104a139b96aSKishon Vijay Abraham I  *
105a139b96aSKishon Vijay Abraham I  * If the udc driver has bus reset handler, it needs to call this when the bus
106a139b96aSKishon Vijay Abraham I  * reset occurs, it notifies the gadget driver that the bus reset occurs as
107a139b96aSKishon Vijay Abraham I  * well as updates gadget state.
108a139b96aSKishon Vijay Abraham I  */
usb_gadget_udc_reset(struct usb_gadget * gadget,struct usb_gadget_driver * driver)109a139b96aSKishon Vijay Abraham I void usb_gadget_udc_reset(struct usb_gadget *gadget,
110a139b96aSKishon Vijay Abraham I 		struct usb_gadget_driver *driver)
111a139b96aSKishon Vijay Abraham I {
112a139b96aSKishon Vijay Abraham I 	driver->reset(gadget);
113a139b96aSKishon Vijay Abraham I 	usb_gadget_set_state(gadget, USB_STATE_DEFAULT);
114a139b96aSKishon Vijay Abraham I }
115a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
116a139b96aSKishon Vijay Abraham I 
117a139b96aSKishon Vijay Abraham I /**
118a139b96aSKishon Vijay Abraham I  * usb_gadget_udc_start - tells usb device controller to start up
119a139b96aSKishon Vijay Abraham I  * @udc: The UDC to be started
120a139b96aSKishon Vijay Abraham I  *
121a139b96aSKishon Vijay Abraham I  * This call is issued by the UDC Class driver when it's about
122a139b96aSKishon Vijay Abraham I  * to register a gadget driver to the device controller, before
123a139b96aSKishon Vijay Abraham I  * calling gadget driver's bind() method.
124a139b96aSKishon Vijay Abraham I  *
125a139b96aSKishon Vijay Abraham I  * It allows the controller to be powered off until strictly
126a139b96aSKishon Vijay Abraham I  * necessary to have it powered on.
127a139b96aSKishon Vijay Abraham I  *
128a139b96aSKishon Vijay Abraham I  * Returns zero on success, else negative errno.
129a139b96aSKishon Vijay Abraham I  */
usb_gadget_udc_start(struct usb_udc * udc)130a139b96aSKishon Vijay Abraham I static inline int usb_gadget_udc_start(struct usb_udc *udc)
131a139b96aSKishon Vijay Abraham I {
132a139b96aSKishon Vijay Abraham I 	return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
133a139b96aSKishon Vijay Abraham I }
134a139b96aSKishon Vijay Abraham I 
135a139b96aSKishon Vijay Abraham I /**
136a139b96aSKishon Vijay Abraham I  * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
137a139b96aSKishon Vijay Abraham I  * @gadget: The device we want to stop activity
138a139b96aSKishon Vijay Abraham I  * @driver: The driver to unbind from @gadget
139a139b96aSKishon Vijay Abraham I  *
140a139b96aSKishon Vijay Abraham I  * This call is issued by the UDC Class driver after calling
141a139b96aSKishon Vijay Abraham I  * gadget driver's unbind() method.
142a139b96aSKishon Vijay Abraham I  *
143a139b96aSKishon Vijay Abraham I  * The details are implementation specific, but it can go as
144a139b96aSKishon Vijay Abraham I  * far as powering off UDC completely and disable its data
145a139b96aSKishon Vijay Abraham I  * line pullups.
146a139b96aSKishon Vijay Abraham I  */
usb_gadget_udc_stop(struct usb_udc * udc)147a139b96aSKishon Vijay Abraham I static inline void usb_gadget_udc_stop(struct usb_udc *udc)
148a139b96aSKishon Vijay Abraham I {
149a139b96aSKishon Vijay Abraham I 	udc->gadget->ops->udc_stop(udc->gadget);
150a139b96aSKishon Vijay Abraham I }
151a139b96aSKishon Vijay Abraham I 
152a139b96aSKishon Vijay Abraham I /**
153a139b96aSKishon Vijay Abraham I  * usb_udc_release - release the usb_udc struct
154a139b96aSKishon Vijay Abraham I  * @dev: the dev member within usb_udc
155a139b96aSKishon Vijay Abraham I  *
156a139b96aSKishon Vijay Abraham I  * This is called by driver's core in order to free memory once the last
157a139b96aSKishon Vijay Abraham I  * reference is released.
158a139b96aSKishon Vijay Abraham I  */
usb_udc_release(struct device * dev)159a139b96aSKishon Vijay Abraham I static void usb_udc_release(struct device *dev)
160a139b96aSKishon Vijay Abraham I {
161a139b96aSKishon Vijay Abraham I 	struct usb_udc *udc;
162a139b96aSKishon Vijay Abraham I 
163a139b96aSKishon Vijay Abraham I 	udc = container_of(dev, struct usb_udc, dev);
164a139b96aSKishon Vijay Abraham I 	kfree(udc);
165a139b96aSKishon Vijay Abraham I }
166a139b96aSKishon Vijay Abraham I 
167a139b96aSKishon Vijay Abraham I /**
168a139b96aSKishon Vijay Abraham I  * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
169a139b96aSKishon Vijay Abraham I  * @parent: the parent device to this udc. Usually the controller driver's
170a139b96aSKishon Vijay Abraham I  * device.
171a139b96aSKishon Vijay Abraham I  * @gadget: the gadget to be added to the list.
172a139b96aSKishon Vijay Abraham I  * @release: a gadget release function.
173a139b96aSKishon Vijay Abraham I  *
174a139b96aSKishon Vijay Abraham I  * Returns zero on success, negative errno otherwise.
175a139b96aSKishon Vijay Abraham I  */
usb_add_gadget_udc_release(struct device * parent,struct usb_gadget * gadget,void (* release)(struct device * dev))176a139b96aSKishon Vijay Abraham I int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
177a139b96aSKishon Vijay Abraham I 		void (*release)(struct device *dev))
178a139b96aSKishon Vijay Abraham I {
179a139b96aSKishon Vijay Abraham I 	struct usb_udc		*udc;
180a139b96aSKishon Vijay Abraham I 	int			ret = -ENOMEM;
181a139b96aSKishon Vijay Abraham I 
182a139b96aSKishon Vijay Abraham I 	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
183a139b96aSKishon Vijay Abraham I 	if (!udc)
184a139b96aSKishon Vijay Abraham I 		goto err1;
185a139b96aSKishon Vijay Abraham I 
186a139b96aSKishon Vijay Abraham I 	dev_set_name(&gadget->dev, "gadget");
187a139b96aSKishon Vijay Abraham I 	gadget->dev.parent = parent;
188a139b96aSKishon Vijay Abraham I 
189a139b96aSKishon Vijay Abraham I 	udc->dev.release = usb_udc_release;
190a139b96aSKishon Vijay Abraham I 	udc->dev.class = udc_class;
191a139b96aSKishon Vijay Abraham I 	udc->dev.parent = parent;
192a139b96aSKishon Vijay Abraham I 
193a139b96aSKishon Vijay Abraham I 	udc->gadget = gadget;
194a139b96aSKishon Vijay Abraham I 
195a139b96aSKishon Vijay Abraham I 	mutex_lock(&udc_lock);
196a139b96aSKishon Vijay Abraham I 	list_add_tail(&udc->list, &udc_list);
197a139b96aSKishon Vijay Abraham I 
198a139b96aSKishon Vijay Abraham I 	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
199a139b96aSKishon Vijay Abraham I 
200a139b96aSKishon Vijay Abraham I 	mutex_unlock(&udc_lock);
201a139b96aSKishon Vijay Abraham I 
202a139b96aSKishon Vijay Abraham I 	return 0;
203a139b96aSKishon Vijay Abraham I 
204a139b96aSKishon Vijay Abraham I err1:
205a139b96aSKishon Vijay Abraham I 	return ret;
206a139b96aSKishon Vijay Abraham I }
207a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
208a139b96aSKishon Vijay Abraham I 
209a139b96aSKishon Vijay Abraham I /**
210a139b96aSKishon Vijay Abraham I  * usb_add_gadget_udc - adds a new gadget to the udc class driver list
211a139b96aSKishon Vijay Abraham I  * @parent: the parent device to this udc. Usually the controller
212a139b96aSKishon Vijay Abraham I  * driver's device.
213a139b96aSKishon Vijay Abraham I  * @gadget: the gadget to be added to the list
214a139b96aSKishon Vijay Abraham I  *
215a139b96aSKishon Vijay Abraham I  * Returns zero on success, negative errno otherwise.
216a139b96aSKishon Vijay Abraham I  */
usb_add_gadget_udc(struct device * parent,struct usb_gadget * gadget)217a139b96aSKishon Vijay Abraham I int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
218a139b96aSKishon Vijay Abraham I {
219a139b96aSKishon Vijay Abraham I 	return usb_add_gadget_udc_release(parent, gadget, NULL);
220a139b96aSKishon Vijay Abraham I }
221a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
222a139b96aSKishon Vijay Abraham I 
usb_gadget_remove_driver(struct usb_udc * udc)223a139b96aSKishon Vijay Abraham I static void usb_gadget_remove_driver(struct usb_udc *udc)
224a139b96aSKishon Vijay Abraham I {
225a139b96aSKishon Vijay Abraham I 	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
226a139b96aSKishon Vijay Abraham I 			udc->driver->function);
227a139b96aSKishon Vijay Abraham I 
228a139b96aSKishon Vijay Abraham I 	usb_gadget_disconnect(udc->gadget);
229a139b96aSKishon Vijay Abraham I 	udc->driver->disconnect(udc->gadget);
230a139b96aSKishon Vijay Abraham I 	udc->driver->unbind(udc->gadget);
231a139b96aSKishon Vijay Abraham I 	usb_gadget_udc_stop(udc);
232a139b96aSKishon Vijay Abraham I 
233a139b96aSKishon Vijay Abraham I 	udc->driver = NULL;
234a139b96aSKishon Vijay Abraham I }
235a139b96aSKishon Vijay Abraham I 
236a139b96aSKishon Vijay Abraham I /**
237a139b96aSKishon Vijay Abraham I  * usb_del_gadget_udc - deletes @udc from udc_list
238a139b96aSKishon Vijay Abraham I  * @gadget: the gadget to be removed.
239a139b96aSKishon Vijay Abraham I  *
240a139b96aSKishon Vijay Abraham I  * This, will call usb_gadget_unregister_driver() if
241a139b96aSKishon Vijay Abraham I  * the @udc is still busy.
242a139b96aSKishon Vijay Abraham I  */
usb_del_gadget_udc(struct usb_gadget * gadget)243a139b96aSKishon Vijay Abraham I void usb_del_gadget_udc(struct usb_gadget *gadget)
244a139b96aSKishon Vijay Abraham I {
245a139b96aSKishon Vijay Abraham I 	struct usb_udc		*udc = NULL;
246a139b96aSKishon Vijay Abraham I 
247a139b96aSKishon Vijay Abraham I 	mutex_lock(&udc_lock);
248a139b96aSKishon Vijay Abraham I 	list_for_each_entry(udc, &udc_list, list)
249a139b96aSKishon Vijay Abraham I 		if (udc->gadget == gadget)
250a139b96aSKishon Vijay Abraham I 			goto found;
251a139b96aSKishon Vijay Abraham I 
252a139b96aSKishon Vijay Abraham I 	dev_err(gadget->dev.parent, "gadget not registered.\n");
253a139b96aSKishon Vijay Abraham I 	mutex_unlock(&udc_lock);
254a139b96aSKishon Vijay Abraham I 
255a139b96aSKishon Vijay Abraham I 	return;
256a139b96aSKishon Vijay Abraham I 
257a139b96aSKishon Vijay Abraham I found:
258a139b96aSKishon Vijay Abraham I 	dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
259a139b96aSKishon Vijay Abraham I 
260a139b96aSKishon Vijay Abraham I 	list_del(&udc->list);
261a139b96aSKishon Vijay Abraham I 	mutex_unlock(&udc_lock);
262a139b96aSKishon Vijay Abraham I 
263a139b96aSKishon Vijay Abraham I 	if (udc->driver)
264a139b96aSKishon Vijay Abraham I 		usb_gadget_remove_driver(udc);
265a139b96aSKishon Vijay Abraham I }
266a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
267a139b96aSKishon Vijay Abraham I 
268a139b96aSKishon Vijay Abraham I /* ------------------------------------------------------------------------- */
269a139b96aSKishon Vijay Abraham I 
udc_bind_to_driver(struct usb_udc * udc,struct usb_gadget_driver * driver)270a139b96aSKishon Vijay Abraham I static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
271a139b96aSKishon Vijay Abraham I {
272a139b96aSKishon Vijay Abraham I 	int ret;
273a139b96aSKishon Vijay Abraham I 
274a139b96aSKishon Vijay Abraham I 	dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
275a139b96aSKishon Vijay Abraham I 			driver->function);
276a139b96aSKishon Vijay Abraham I 
277a139b96aSKishon Vijay Abraham I 	udc->driver = driver;
278a139b96aSKishon Vijay Abraham I 
279103fa06cSKishon Vijay Abraham I 	ret = driver->bind(udc->gadget);
280a139b96aSKishon Vijay Abraham I 	if (ret)
281a139b96aSKishon Vijay Abraham I 		goto err1;
282a139b96aSKishon Vijay Abraham I 	ret = usb_gadget_udc_start(udc);
283a139b96aSKishon Vijay Abraham I 	if (ret) {
284a139b96aSKishon Vijay Abraham I 		driver->unbind(udc->gadget);
285a139b96aSKishon Vijay Abraham I 		goto err1;
286a139b96aSKishon Vijay Abraham I 	}
287a139b96aSKishon Vijay Abraham I 	usb_gadget_connect(udc->gadget);
288a139b96aSKishon Vijay Abraham I 
289a139b96aSKishon Vijay Abraham I 	return 0;
290a139b96aSKishon Vijay Abraham I err1:
291a139b96aSKishon Vijay Abraham I 	if (ret != -EISNAM)
292a139b96aSKishon Vijay Abraham I 		dev_err(&udc->dev, "failed to start %s: %d\n",
293a139b96aSKishon Vijay Abraham I 			udc->driver->function, ret);
294a139b96aSKishon Vijay Abraham I 	udc->driver = NULL;
295a139b96aSKishon Vijay Abraham I 	return ret;
296a139b96aSKishon Vijay Abraham I }
297a139b96aSKishon Vijay Abraham I 
usb_gadget_probe_driver(struct usb_gadget_driver * driver)298a139b96aSKishon Vijay Abraham I int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
299a139b96aSKishon Vijay Abraham I {
300a139b96aSKishon Vijay Abraham I 	struct usb_udc		*udc = NULL;
301a139b96aSKishon Vijay Abraham I 	int			ret;
302a139b96aSKishon Vijay Abraham I 
303a139b96aSKishon Vijay Abraham I 	if (!driver || !driver->bind || !driver->setup)
304a139b96aSKishon Vijay Abraham I 		return -EINVAL;
305a139b96aSKishon Vijay Abraham I 
306a139b96aSKishon Vijay Abraham I 	mutex_lock(&udc_lock);
307a139b96aSKishon Vijay Abraham I 	list_for_each_entry(udc, &udc_list, list) {
308a139b96aSKishon Vijay Abraham I 		/* For now we take the first one */
309a139b96aSKishon Vijay Abraham I 		if (!udc->driver)
310a139b96aSKishon Vijay Abraham I 			goto found;
311a139b96aSKishon Vijay Abraham I 	}
312a139b96aSKishon Vijay Abraham I 
313103fa06cSKishon Vijay Abraham I 	printf("couldn't find an available UDC\n");
314a139b96aSKishon Vijay Abraham I 	mutex_unlock(&udc_lock);
315a139b96aSKishon Vijay Abraham I 	return -ENODEV;
316a139b96aSKishon Vijay Abraham I found:
317a139b96aSKishon Vijay Abraham I 	ret = udc_bind_to_driver(udc, driver);
318a139b96aSKishon Vijay Abraham I 	mutex_unlock(&udc_lock);
319a139b96aSKishon Vijay Abraham I 	return ret;
320a139b96aSKishon Vijay Abraham I }
321a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
322a139b96aSKishon Vijay Abraham I 
usb_gadget_register_driver(struct usb_gadget_driver * driver)323103fa06cSKishon Vijay Abraham I int usb_gadget_register_driver(struct usb_gadget_driver *driver)
324103fa06cSKishon Vijay Abraham I {
325103fa06cSKishon Vijay Abraham I 	return usb_gadget_probe_driver(driver);
326103fa06cSKishon Vijay Abraham I }
327103fa06cSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_gadget_register_driver);
328103fa06cSKishon Vijay Abraham I 
usb_gadget_unregister_driver(struct usb_gadget_driver * driver)329a139b96aSKishon Vijay Abraham I int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
330a139b96aSKishon Vijay Abraham I {
331a139b96aSKishon Vijay Abraham I 	struct usb_udc		*udc = NULL;
332a139b96aSKishon Vijay Abraham I 	int			ret = -ENODEV;
333a139b96aSKishon Vijay Abraham I 
334a139b96aSKishon Vijay Abraham I 	if (!driver || !driver->unbind)
335a139b96aSKishon Vijay Abraham I 		return -EINVAL;
336a139b96aSKishon Vijay Abraham I 
337a139b96aSKishon Vijay Abraham I 	mutex_lock(&udc_lock);
338a139b96aSKishon Vijay Abraham I 	list_for_each_entry(udc, &udc_list, list)
339a139b96aSKishon Vijay Abraham I 		if (udc->driver == driver) {
340a139b96aSKishon Vijay Abraham I 			usb_gadget_remove_driver(udc);
341a139b96aSKishon Vijay Abraham I 			usb_gadget_set_state(udc->gadget,
342a139b96aSKishon Vijay Abraham I 					USB_STATE_NOTATTACHED);
343a139b96aSKishon Vijay Abraham I 			ret = 0;
344a139b96aSKishon Vijay Abraham I 			break;
345a139b96aSKishon Vijay Abraham I 		}
346a139b96aSKishon Vijay Abraham I 
347a139b96aSKishon Vijay Abraham I 	mutex_unlock(&udc_lock);
348a139b96aSKishon Vijay Abraham I 	return ret;
349a139b96aSKishon Vijay Abraham I }
350a139b96aSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
351a139b96aSKishon Vijay Abraham I 
352a139b96aSKishon Vijay Abraham I MODULE_DESCRIPTION("UDC Framework");
353a139b96aSKishon Vijay Abraham I MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
354a139b96aSKishon Vijay Abraham I MODULE_LICENSE("GPL v2");
355