Add driver model support by using the uclass UCLASS_USB_GADGET_GENERIC. Disable local usb_gadget_register_driver()/usb_gadget_unregister_driver() implementation which is implemented in udc-core.c when DM_USB_GADGET is enabled.
Replace dm_usb_gadget_handle_interrupts() with handle_interrupts ops when DM_USB_GADGET is enabled. Disable legacy usba_udc_probe() to avoid conflict with DM when it's enabled. Compared to Linux driver only supported devices' DT bindings are included (sorted as Linux driver) Signed-off-by: Zixun LI <z...@ogga.fr> --- drivers/usb/gadget/atmel_usba_udc.c | 123 ++++++++++++++++++++++++++++ include/linux/usb/atmel_usba_udc.h | 2 + 2 files changed, 125 insertions(+) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 46f7ae9a0c..95abb86840 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -8,10 +8,13 @@ */ #include <clk.h> +#include <dm.h> #include <log.h> #include <malloc.h> #include <asm/gpio.h> #include <asm/hardware.h> +#include <dm/device_compat.h> +#include <dm/devres.h> #include <linux/bitops.h> #include <linux/errno.h> #include <linux/list.h> @@ -19,6 +22,10 @@ #include <linux/usb/gadget.h> #include <linux/usb/atmel_usba_udc.h> +#if CONFIG_IS_ENABLED(DM_USB_GADGET) +#include <mach/atmel_usba_udc.h> +#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */ + #include "atmel_usba_udc.h" static struct usba_udc *controller; @@ -1193,6 +1200,7 @@ static int usba_udc_pullup(struct usb_gadget *g, int is_on) return 0; } +#if !CONFIG_IS_ENABLED(DM_USB_GADGET) int dm_usb_gadget_handle_interrupts(struct udevice *dev) { struct usba_udc *udc = controller; @@ -1246,11 +1254,40 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } +#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */ +static int usba_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = controller; + + usba_udc_enable(udc); + + udc->driver = driver; + + return 0; +} + +static int usba_udc_stop(struct usb_gadget *g) +{ + struct usba_udc *udc = controller; + + udc->driver = NULL; + + usba_udc_disable(udc); + + return 0; +} +#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */ + static const struct usb_gadget_ops usba_udc_ops = { .get_frame = usba_udc_get_frame, .wakeup = usba_udc_wakeup, .set_selfpowered = usba_udc_set_selfpowered, .pullup = usba_udc_pullup, +#if CONFIG_IS_ENABLED(DM_USB_GADGET) + .udc_start = usba_udc_start, + .udc_stop = usba_udc_stop, +#endif }; static struct usba_udc udc_controller = { @@ -1305,6 +1342,7 @@ static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata, return eps; } +#if !CONFIG_IS_ENABLED(DM_USB_GADGET) int usba_udc_probe(struct usba_platform_data *pdata) { controller = &udc_controller; @@ -1313,3 +1351,88 @@ int usba_udc_probe(struct usba_platform_data *pdata) return 0; } + +#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */ +struct usba_priv_data { + struct clk_bulk clks; +}; + +static int usba_udc_clk_init(struct udevice *dev, struct clk_bulk *clks) +{ + int ret; + + ret = clk_get_bulk(dev, clks); + if (ret == -ENOSYS) + return 0; + + if (ret) + return ret; + + ret = clk_enable_bulk(clks); + if (ret) { + clk_release_bulk(clks); + return ret; + } + + return 0; +} + +static int usba_udc_probe(struct udevice *dev) +{ + struct usba_priv_data *priv = dev_get_priv(dev); + int ret; + + ret = usba_udc_clk_init(dev, &priv->clks); + if (ret) + return ret; + + controller = &udc_controller; + + controller->usba_ep = usba_udc_pdata(&pdata, controller); + + controller->driver = 0; + + ret = usb_add_gadget_udc((struct device *)dev, &controller->gadget); + + return ret; +} + +static int usba_udc_remove(struct udevice *dev) +{ + struct usba_priv_data *priv = dev_get_priv(dev); + + usb_del_gadget_udc(&controller->gadget); + + clk_release_bulk(&priv->clks); + + return dm_scan_fdt_dev(dev); +} + +static int usba_udc_handle_interrupts(struct udevice *dev) +{ + struct usba_udc *udc = controller; + + return usba_udc_irq(udc); +} + +static const struct usb_gadget_generic_ops usba_udc_gadget_ops = { + .handle_interrupts = usba_udc_handle_interrupts, +}; + +static const struct udevice_id usba_udc_ids[] = { + { .compatible = "atmel,at91sam9rl-udc" }, + { .compatible = "atmel,at91sam9g45-udc" }, + { .compatible = "atmel,sama5d3-udc" }, + {} +}; + +U_BOOT_DRIVER(ateml_usba_udc) = { + .name = "ateml_usba_udc", + .id = UCLASS_USB_GADGET_GENERIC, + .of_match = usba_udc_ids, + .ops = &usba_udc_gadget_ops, + .probe = usba_udc_probe, + .remove = usba_udc_remove, + .priv_auto = sizeof(struct usba_priv_data), +}; +#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */ diff --git a/include/linux/usb/atmel_usba_udc.h b/include/linux/usb/atmel_usba_udc.h index c1c810759c..37c4f21849 100644 --- a/include/linux/usb/atmel_usba_udc.h +++ b/include/linux/usb/atmel_usba_udc.h @@ -20,6 +20,8 @@ struct usba_platform_data { struct usba_ep_data *ep; }; +#if !CONFIG_IS_ENABLED(DM_USB_GADGET) extern int usba_udc_probe(struct usba_platform_data *pdata); +#endif #endif /* __LINUX_USB_USBA_H */ -- 2.45.2