When CONFIG_DM_USB_GADGET is enabled, a UCLASS_USB_GADGET_GENERIC driver
will be defined that wraps the ChipIdea UDC operations. The
(dm_)?usb_gadget_.* symbols will no longer be defined (as these are now
handled by the UDC uclass).

If CONFIG_DM_USB_GADGET is not enabled, this driver behaves as it
previously did.

This new driver does not declare any compatibles of its own. It requires
a glue driver to bind it. The ehci_msm driver will be updated in the
following commit to do exactly that.

Signed-off-by: Sam Day <[email protected]>
---
 drivers/usb/gadget/Kconfig  |   1 -
 drivers/usb/gadget/ci_udc.c | 118 ++++++++++++++++++++++++++++++++++++--------
 2 files changed, 97 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 5390878254a..6ba558cc292 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -153,7 +153,6 @@ config USB_GADGET_OS_DESCRIPTORS
 
 config CI_UDC
        bool "ChipIdea device controller"
-       depends on !DM_USB_GADGET
        select USB_GADGET_DUALSPEED
        help
          Say Y here to enable device controller functionality of the
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 4729570c525..42028e11d59 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -10,6 +10,7 @@
 #include <command.h>
 #include <config.h>
 #include <cpu_func.h>
+#include <dm.h>
 #include <net.h>
 #include <malloc.h>
 #include <wait_bit.h>
@@ -94,8 +95,17 @@ static struct usb_request *
 ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
 static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
 
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+static int ci_udc_gadget_start(struct usb_gadget *g, struct usb_gadget_driver 
*driver);
+static int ci_udc_gadget_stop(struct usb_gadget *g);
+#endif
+
 static const struct usb_gadget_ops ci_udc_ops = {
        .pullup = ci_pullup,
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+       .udc_start = ci_udc_gadget_start,
+       .udc_stop = ci_udc_gadget_stop,
+#endif
 };
 
 static const struct usb_ep_ops ci_ep_ops = {
@@ -978,7 +988,7 @@ void udc_irq(void)
        }
 }
 
-int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+static int ci_udc_handle_interrupts(struct udevice *dev)
 {
        struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
        u32 value;
@@ -1037,7 +1047,7 @@ static int ci_pullup(struct usb_gadget *gadget, int is_on)
 static int ci_udc_probe(void)
 {
        struct ept_queue_head *head;
-       int i;
+       int i, ret;
 
        const int num = 2 * NUM_ENDPOINTS;
 
@@ -1046,6 +1056,14 @@ static int ci_udc_probe(void)
        const int eplist_raw_sz = num * sizeof(struct ept_queue_head);
        const int eplist_sz = roundup(eplist_raw_sz, ARCH_DMA_MINALIGN);
 
+       if (IS_ENABLED(CONFIG_DM_USB))
+               ret = usb_setup_ehci_gadget(&controller.ctrl);
+       else
+               ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void 
**)&controller.ctrl);
+
+       if (ret)
+               return ret;
+
        /* The QH list must be aligned to 4096 bytes. */
        controller.epts = memalign(eplist_align, eplist_sz);
        if (!controller.epts)
@@ -1123,6 +1141,73 @@ static int ci_udc_probe(void)
        return 0;
 }
 
+static void ci_udc_remove(void)
+{
+       if (IS_ENABLED(CONFIG_DM_USB)) {
+               usb_remove_ehci_gadget(&controller.ctrl);
+       } else {
+               usb_lowlevel_stop(0);
+               controller.ctrl = NULL;
+       }
+}
+
+static void ci_udc_stop(void)
+{
+       ci_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req);
+       free(controller.items_mem);
+       free(controller.epts);
+}
+
+static int ci_udc_gadget_start(struct usb_gadget *g, struct usb_gadget_driver 
*driver)
+{
+       controller.driver = driver;
+       return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+static int ci_udc_generic_probe(struct udevice *dev)
+{
+       int ret = ci_udc_probe();
+
+       if (ret)
+               return ret;
+
+       return usb_add_gadget_udc((struct device *)dev, &controller.gadget);
+}
+
+static int ci_udc_generic_remove(struct udevice *dev)
+{
+       usb_del_gadget_udc(&controller.gadget);
+
+       ci_udc_remove();
+
+       return 0;
+}
+
+static const struct usb_gadget_generic_ops ci_udc_generic_ops = {
+       .handle_interrupts      = ci_udc_handle_interrupts,
+};
+
+U_BOOT_DRIVER(ci_udc_generic) = {
+       .name = "ci-udc",
+       .id = UCLASS_USB_GADGET_GENERIC,
+       .ops = &ci_udc_generic_ops,
+       .probe = ci_udc_generic_probe,
+       .remove = ci_udc_generic_remove,
+};
+
+static int ci_udc_gadget_stop(struct usb_gadget *g)
+{
+       /* Avoid calling disconnect() twice; the UDC uclass already did it. */
+       controller.driver = NULL;
+       udc_disconnect();
+
+       ci_udc_stop();
+
+       return 0;
+}
+
+#else
 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 {
        int ret;
@@ -1132,14 +1217,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
        if (!driver->bind || !driver->setup || !driver->disconnect)
                return -EINVAL;
 
-#if CONFIG_IS_ENABLED(DM_USB)
-       ret = usb_setup_ehci_gadget(&controller.ctrl);
-#else
-       ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl);
-#endif
-       if (ret)
-               return ret;
-
        ret = ci_udc_probe();
        if (ret) {
                DBG("udc probe failed, returned %d\n", ret);
@@ -1151,7 +1228,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
                DBG("driver->bind() returned %d\n", ret);
                return ret;
        }
-       controller.driver = driver;
+
+       ci_udc_gadget_start(&controller.gadget, driver);
 
        return 0;
 }
@@ -1163,20 +1241,18 @@ int usb_gadget_unregister_driver(struct 
usb_gadget_driver *driver)
        driver->unbind(&controller.gadget);
        controller.driver = NULL;
 
-       ci_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req);
-       free(controller.items_mem);
-       free(controller.epts);
-
-#if CONFIG_IS_ENABLED(DM_USB)
-       usb_remove_ehci_gadget(&controller.ctrl);
-#else
-       usb_lowlevel_stop(0);
-       controller.ctrl = NULL;
-#endif
+       ci_udc_stop();
+       ci_udc_remove();
 
        return 0;
 }
 
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+       return ci_udc_handle_interrupts(dev);
+}
+#endif
+
 bool dfu_usb_get_reset(void)
 {
        struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;

-- 
2.54.0


Reply via email to