From: Stefan Eichenberger <eichest@gmail.com>
To: francesco.dolcini@toradex.com, trini@konsulko.com,
ilias.apalodimas@linaro.org, sbabic@nabladev.com,
festevam@gmail.com, uboot-imx@nxp.com,
marek.vasut+usb@mailbox.org, lukma@denx.de,
mkorpershoek@kernel.org, antoine.gouby@toradex.com,
alice.guo@nxp.com, stefan.eichenberger@toradex.com,
sjg@chromium.org, emanuele.ghidoli@toradex.com,
franz.schnyder@toradex.com, pbrobinson@gmail.com,
quentin.schulz@cherry.de, jbx6244@gmail.com, ye.li@nxp.com,
xu.yang_2@nxp.com, bmeng.cn@gmail.com, xypron.glpk@gmx.de,
hayashi.kunihiko@socionext.com, sean.anderson@linux.dev
Cc: u-boot@lists.u-boot-project.org
Subject: [PATCH v2 1/7] usb: ci_udc: add driver model support
Date: Mon, 14 Sep 2026 09:42:43 +0200 [thread overview]
Message-ID: <20260914074314.12522-2-eichest@gmail.com> (raw)
In-Reply-To: <20260914074314.12522-1-eichest@gmail.com>
From: Stefan Eichenberger <stefan.eichenberger@toradex.com>
Register the ChipIdea gadget as a UCLASS_USB_GADGET_GENERIC driver so it
can be used on boards with DM_USB_GADGET enabled, which CI_UDC no longer
excludes. The driver enables the clocks and the PHY of its device tree
node and registers the gadget with usb_add_gadget_udc().
It has no of_match of its own. The controller node is shared with the
EHCI host driver, which owns it and binds this driver by name, so CI_UDC
depends on that driver once DM_USB_GADGET is enabled.
Boards without DM_USB_GADGET keep the existing behaviour.
Signed-off-by: Stefan Eichenberger <stefan.eichenberger@toradex.com>
---
drivers/usb/gadget/Kconfig | 8 +-
drivers/usb/gadget/ci_udc.c | 152 +++++++++++++++++++++++++++++++++++-
2 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index e42d5a43696..67826ee5150 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -153,12 +153,18 @@ config USB_GADGET_OS_DESCRIPTORS
config CI_UDC
bool "ChipIdea device controller"
- depends on !DM_USB_GADGET
+ depends on !DM_USB_GADGET || USB_EHCI_MX6 || USB_EHCI_MX7
select USB_GADGET_DUALSPEED
help
Say Y here to enable device controller functionality of the
ChipIdea driver.
+ With DM_USB_GADGET enabled this driver has no device tree match of
+ its own. The EHCI host driver owns the controller node and binds
+ this driver by name for the ports whose dr_mode is "peripheral" or
+ "otg", which is why it is required. Without DM_USB_GADGET the
+ controller is picked up through the EHCI host driver as before.
+
config USB_GADGET_VBUS_DRAW
int "Maximum VBUS Power usage (2-500 mA)"
range 2 500
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 53796887dac..f63cb17b58f 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -7,14 +7,18 @@
* Murray.Jensen@cmst.csiro.au, 27-Jan-01.
*/
+#include <clk.h>
#include <command.h>
#include <config.h>
#include <cpu_func.h>
+#include <dm.h>
+#include <generic-phy.h>
#include <net.h>
#include <malloc.h>
#include <wait_bit.h>
#include <asm/byteorder.h>
#include <asm/cache.h>
+#include <dm/device_compat.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <asm/io.h>
@@ -23,6 +27,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <usb/ci_udc.h>
+#include <usb/ehci-ci.h>
#include "../host/ehci.h"
#include "ci_udc.h"
@@ -93,9 +98,18 @@ static int ci_ep_dequeue(struct usb_ep *ep, struct usb_request *req);
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_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int ci_udc_stop(struct usb_gadget *gadget);
+#endif
static const struct usb_gadget_ops ci_udc_ops = {
.pullup = ci_pullup,
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+ .udc_start = ci_udc_start,
+ .udc_stop = ci_udc_stop,
+#endif
};
static const struct usb_ep_ops ci_ep_ops = {
@@ -994,7 +1008,7 @@ void udc_irq(void)
}
}
-int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+static int ci_udc_gadget_handle_interrupts(struct udevice *dev)
{
struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
u32 value;
@@ -1139,6 +1153,12 @@ static int ci_udc_probe(void)
return 0;
}
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+ return ci_udc_gadget_handle_interrupts(dev);
+}
+
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
int ret;
@@ -1192,6 +1212,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
return 0;
}
+#endif /* !DM_USB_GADGET */
bool dfu_usb_get_reset(void)
{
@@ -1199,3 +1220,132 @@ bool dfu_usb_get_reset(void)
return !!(readl(&udc->usbsts) & STS_URI);
}
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+struct ci_udc_priv {
+ /* Only hccr and hcor are used, the gadget does not drive EHCI. */
+ struct ehci_ctrl ctrl;
+ struct clk_bulk clks;
+ struct phy phy;
+};
+
+static int ci_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ if (!driver || !driver->bind || !driver->setup || !driver->disconnect)
+ return -EINVAL;
+
+ controller.driver = driver;
+
+ return 0;
+}
+
+static int ci_udc_stop(struct usb_gadget *gadget)
+{
+ controller.driver = NULL;
+
+ return 0;
+}
+
+static int ci_udc_clk_init(struct udevice *dev, struct clk_bulk *clks)
+{
+ int ret;
+
+ ret = clk_get_bulk(dev, clks);
+ if (ret == -ENOSYS || ret == -ENOENT)
+ return 0;
+ if (ret)
+ return ret;
+
+ ret = clk_enable_bulk(clks);
+ if (ret) {
+ clk_release_bulk(clks);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ci_udc_dm_probe(struct udevice *dev)
+{
+ struct ci_udc_priv *priv = dev_get_priv(dev);
+ struct usb_ehci *ehci;
+ int ret;
+
+ ehci = dev_read_addr_ptr(dev);
+ if (!ehci)
+ return -EINVAL;
+
+ ret = ci_udc_clk_init(dev, &priv->clks);
+ if (ret)
+ return ret;
+
+ ret = generic_setup_phy(dev, &priv->phy, 0, PHY_MODE_USB_DEVICE, 0);
+ if (ret)
+ goto err_clk;
+
+ /* Same register layout the EHCI host driver derives its regs from. */
+ priv->ctrl.hccr = (struct ehci_hccr *)&ehci->caplength;
+ priv->ctrl.hcor = (struct ehci_hcor *)((uintptr_t)priv->ctrl.hccr +
+ HC_LENGTH(ehci_readl(&priv->ctrl.hccr->cr_capbase)));
+ controller.ctrl = &priv->ctrl;
+
+ ret = ci_udc_probe();
+ if (ret) {
+ dev_err(dev, "udc probe failed, returned %d\n", ret);
+ goto err_phy;
+ }
+
+ ret = usb_add_gadget_udc((struct device *)dev, &controller.gadget);
+ if (ret)
+ goto err_udc;
+
+ return 0;
+
+err_udc:
+ ci_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req);
+ free(controller.items_mem);
+ free(controller.epts);
+err_phy:
+ generic_shutdown_phy(&priv->phy);
+err_clk:
+ clk_release_bulk(&priv->clks);
+ return ret;
+}
+
+static int ci_udc_dm_remove(struct udevice *dev)
+{
+ struct ci_udc_priv *priv = dev_get_priv(dev);
+
+ usb_del_gadget_udc(&controller.gadget);
+
+ ci_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req);
+ free(controller.items_mem);
+ free(controller.epts);
+ controller.ctrl = NULL;
+
+ generic_shutdown_phy(&priv->phy);
+ clk_release_bulk(&priv->clks);
+
+ return 0;
+}
+
+static const struct usb_gadget_generic_ops ci_udc_gadget_ops = {
+ .handle_interrupts = ci_udc_gadget_handle_interrupts,
+};
+
+/*
+ * No of_match: the ChipIdea controller shares its device tree node with the
+ * EHCI host driver, which owns the node and binds this driver by name for
+ * the ports that are usable in device mode.
+ */
+U_BOOT_DRIVER(ci_udc) = {
+ .name = "ci_udc",
+ .id = UCLASS_USB_GADGET_GENERIC,
+ .ops = &ci_udc_gadget_ops,
+ .probe = ci_udc_dm_probe,
+ .remove = ci_udc_dm_remove,
+ .priv_auto = sizeof(struct ci_udc_priv),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* DM_USB_GADGET */
--
2.55.0
next prev parent reply other threads:[~2026-09-14 14:17 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-14 7:42 [PATCH v2 0/7] usb: fix DWC3/gadget issues and enable USB on Toradex i.MX95 boards Stefan Eichenberger
2026-09-14 7:42 ` Stefan Eichenberger [this message]
2026-09-14 7:42 ` [PATCH v2 2/7] usb: ehci-mx6: bind the ChipIdea gadget driver Stefan Eichenberger
2026-09-14 7:42 ` [PATCH v2 3/7] usb: dwc3-generic: fix ref clock lookup indexing wrong clk_bulk array Stefan Eichenberger
2026-09-14 19:26 ` Marek Vasut
2026-09-15 7:44 ` Stefan Eichenberger
2026-09-15 14:22 ` Marek Vasut
2026-09-14 7:42 ` [PATCH v2 4/7] usb: skip host-only devices when picking the ehci gadget controller Stefan Eichenberger
2026-09-14 19:31 ` Marek Vasut
2026-09-15 7:57 ` Stefan Eichenberger
2026-09-15 14:24 ` Marek Vasut
2026-09-16 12:47 ` Stefan Eichenberger
2026-09-16 14:29 ` Marek Vasut
2026-09-14 7:42 ` [PATCH v2 5/7] configs: verdin-imx95: enable CI_UDC usb gadget driver Stefan Eichenberger
2026-09-14 7:42 ` [PATCH v2 6/7] toradex: verdin-imx95: enable DWC3 USB controller support Stefan Eichenberger
2026-09-14 7:42 ` [PATCH v2 7/7] toradex: smarc-imx95: " Stefan Eichenberger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260914074314.12522-2-eichest@gmail.com \
--to=eichest@gmail.com \
--cc=alice.guo@nxp.com \
--cc=antoine.gouby@toradex.com \
--cc=bmeng.cn@gmail.com \
--cc=emanuele.ghidoli@toradex.com \
--cc=festevam@gmail.com \
--cc=francesco.dolcini@toradex.com \
--cc=franz.schnyder@toradex.com \
--cc=hayashi.kunihiko@socionext.com \
--cc=ilias.apalodimas@linaro.org \
--cc=jbx6244@gmail.com \
--cc=lukma@denx.de \
--cc=marek.vasut+usb@mailbox.org \
--cc=mkorpershoek@kernel.org \
--cc=pbrobinson@gmail.com \
--cc=quentin.schulz@cherry.de \
--cc=sbabic@nabladev.com \
--cc=sean.anderson@linux.dev \
--cc=sjg@chromium.org \
--cc=stefan.eichenberger@toradex.com \
--cc=trini@konsulko.com \
--cc=u-boot@lists.u-boot-project.org \
--cc=uboot-imx@nxp.com \
--cc=xu.yang_2@nxp.com \
--cc=xypron.glpk@gmx.de \
--cc=ye.li@nxp.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox