All of lore.kernel.org
 help / color / mirror / Atom feed
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


  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.