From: Ze Huang <huang.ze@linux.dev>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Yixun Lan <dlan@gentoo.org>,
Thinh Nguyen <Thinh.Nguyen@synopsys.com>,
Philipp Zabel <p.zabel@pengutronix.de>
Cc: linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
linux-riscv@lists.infradead.org, spacemit@lists.linux.dev,
linux-kernel@vger.kernel.org, Ze Huang <huang.ze@linux.dev>
Subject: [PATCH v6 2/2] usb: dwc3: add generic driver to support flattened
Date: Sat, 12 Jul 2025 15:49:01 +0800 [thread overview]
Message-ID: <20250712-dwc3_generic-v6-2-cc87737cc936@linux.dev> (raw)
In-Reply-To: <20250712-dwc3_generic-v6-0-cc87737cc936@linux.dev>
To support flattened dwc3 dt model and drop the glue layer, introduce the
`dwc3-generic` driver. This enables direct binding of the DWC3 core driver
and offers an alternative to the existing glue driver `dwc3-of-simple`.
Signed-off-by: Ze Huang <huang.ze@linux.dev>
---
drivers/usb/dwc3/Kconfig | 11 +++
drivers/usb/dwc3/Makefile | 1 +
drivers/usb/dwc3/dwc3-generic-plat.c | 182 +++++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+)
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 310d182e10b50b253d7e5a51674806e6ec442a2a..4925d15084f816d3ff92059b476ebcc799b56b51 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -189,4 +189,15 @@ config USB_DWC3_RTK
or dual-role mode.
Say 'Y' or 'M' if you have such device.
+config USB_DWC3_GENERIC_PLAT
+ tristate "DWC3 Generic Platform Driver"
+ depends on OF && COMMON_CLK
+ default USB_DWC3
+ help
+ Support USB3 functionality in simple SoC integrations.
+ Currently supports SpacemiT DWC USB3. Platforms using
+ dwc3-of-simple can easily switch to dwc3-generic by flattening
+ the dwc3 child node in the device tree.
+ Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way.
+
endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 830e6c9e5fe073c1f662ce34b6a4a2da34c407a2..96469e48ff9d189cc8d0b65e65424eae2158bcfe 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o
obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o
obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o
obj-$(CONFIG_USB_DWC3_RTK) += dwc3-rtk.o
+obj-$(CONFIG_USB_DWC3_GENERIC_PLAT) += dwc3-generic-plat.o
diff --git a/drivers/usb/dwc3/dwc3-generic-plat.c b/drivers/usb/dwc3/dwc3-generic-plat.c
new file mode 100644
index 0000000000000000000000000000000000000000..766f4cf17b6909793956f44660d3b3febad50a23
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-generic-plat.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * dwc3-generic-plat.c - DesignWare USB3 generic platform driver
+ *
+ * Copyright (C) 2025 Ze Huang <huang.ze@linux.dev>
+ *
+ * Inspired by dwc3-qcom.c and dwc3-of-simple.c
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include "glue.h"
+
+struct dwc3_generic {
+ struct device *dev;
+ struct dwc3 dwc;
+ struct clk_bulk_data *clks;
+ int num_clocks;
+ struct reset_control *resets;
+};
+
+static void dwc3_generic_reset_control_assert(void *data)
+{
+ reset_control_assert(data);
+}
+
+static void dwc3_generic_clk_bulk_disable_unprepare(void *data)
+{
+ struct dwc3_generic *dwc3 = data;
+
+ clk_bulk_disable_unprepare(dwc3->num_clocks, dwc3->clks);
+}
+
+static int dwc3_generic_probe(struct platform_device *pdev)
+{
+ struct dwc3_probe_data probe_data = {};
+ struct device *dev = &pdev->dev;
+ struct dwc3_generic *dwc3;
+ struct resource *res;
+ int ret;
+
+ dwc3 = devm_kzalloc(dev, sizeof(*dwc3), GFP_KERNEL);
+ if (!dwc3)
+ return -ENOMEM;
+
+ dwc3->dev = dev;
+
+ platform_set_drvdata(pdev, dwc3);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing memory resource\n");
+ return -ENODEV;
+ }
+
+ dwc3->resets = devm_reset_control_array_get_optional_exclusive(dev);
+ if (IS_ERR(dwc3->resets))
+ return dev_err_probe(dev, PTR_ERR(dwc3->resets), "failed to get resets\n");
+
+ ret = reset_control_assert(dwc3->resets);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to assert resets\n");
+
+ ret = devm_add_action_or_reset(dev, dwc3_generic_reset_control_assert, dwc3->resets);
+ if (ret)
+ return ret;
+
+ usleep_range(10, 1000);
+
+ ret = reset_control_deassert(dwc3->resets);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to deassert resets\n");
+
+ ret = devm_clk_bulk_get_all(dwc3->dev, &dwc3->clks);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get clocks\n");
+
+ dwc3->num_clocks = ret;
+
+ ret = clk_bulk_prepare_enable(dwc3->num_clocks, dwc3->clks);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable clocks\n");
+
+ ret = devm_add_action_or_reset(dev, dwc3_generic_clk_bulk_disable_unprepare, dwc3);
+ if (ret)
+ return ret;
+
+ dwc3->dwc.dev = dev;
+ probe_data.dwc = &dwc3->dwc;
+ probe_data.res = res;
+ probe_data.ignore_clocks_and_resets = true;
+ ret = dwc3_core_probe(&probe_data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register DWC3 Core\n");
+
+ return 0;
+}
+
+static void dwc3_generic_remove(struct platform_device *pdev)
+{
+ struct dwc3_generic *dwc3 = platform_get_drvdata(pdev);
+
+ dwc3_core_remove(&dwc3->dwc);
+}
+
+static int dwc3_generic_suspend(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = dwc3_pm_suspend(&dwc3->dwc);
+ if (ret)
+ return ret;
+
+ clk_bulk_disable_unprepare(dwc3->num_clocks, dwc3->clks);
+
+ return 0;
+}
+
+static int dwc3_generic_resume(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(dwc3->num_clocks, dwc3->clks);
+ if (ret)
+ return ret;
+
+ ret = dwc3_pm_resume(&dwc3->dwc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int dwc3_generic_runtime_suspend(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+
+ return dwc3_runtime_suspend(&dwc3->dwc);
+}
+
+static int dwc3_generic_runtime_resume(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+
+ return dwc3_runtime_resume(&dwc3->dwc);
+}
+
+static int dwc3_generic_runtime_idle(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+
+ return dwc3_runtime_idle(&dwc3->dwc);
+}
+
+static const struct dev_pm_ops dwc3_generic_dev_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(dwc3_generic_suspend, dwc3_generic_resume)
+ RUNTIME_PM_OPS(dwc3_generic_runtime_suspend, dwc3_generic_runtime_resume,
+ dwc3_generic_runtime_idle)
+};
+
+static const struct of_device_id dwc3_generic_of_match[] = {
+ { .compatible = "spacemit,k1-dwc3", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dwc3_generic_of_match);
+
+static struct platform_driver dwc3_generic_driver = {
+ .probe = dwc3_generic_probe,
+ .remove = dwc3_generic_remove,
+ .driver = {
+ .name = "dwc3-generic-plat",
+ .of_match_table = dwc3_generic_of_match,
+ .pm = pm_ptr(&dwc3_generic_dev_pm_ops),
+ },
+};
+module_platform_driver(dwc3_generic_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare USB3 generic platform driver");
--
2.50.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
WARNING: multiple messages have this Message-ID (diff)
From: Ze Huang <huang.ze@linux.dev>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Yixun Lan <dlan@gentoo.org>,
Thinh Nguyen <Thinh.Nguyen@synopsys.com>,
Philipp Zabel <p.zabel@pengutronix.de>
Cc: linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
linux-riscv@lists.infradead.org, spacemit@lists.linux.dev,
linux-kernel@vger.kernel.org, Ze Huang <huang.ze@linux.dev>
Subject: [PATCH v6 2/2] usb: dwc3: add generic driver to support flattened
Date: Sat, 12 Jul 2025 15:49:01 +0800 [thread overview]
Message-ID: <20250712-dwc3_generic-v6-2-cc87737cc936@linux.dev> (raw)
In-Reply-To: <20250712-dwc3_generic-v6-0-cc87737cc936@linux.dev>
To support flattened dwc3 dt model and drop the glue layer, introduce the
`dwc3-generic` driver. This enables direct binding of the DWC3 core driver
and offers an alternative to the existing glue driver `dwc3-of-simple`.
Signed-off-by: Ze Huang <huang.ze@linux.dev>
---
drivers/usb/dwc3/Kconfig | 11 +++
drivers/usb/dwc3/Makefile | 1 +
drivers/usb/dwc3/dwc3-generic-plat.c | 182 +++++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+)
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 310d182e10b50b253d7e5a51674806e6ec442a2a..4925d15084f816d3ff92059b476ebcc799b56b51 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -189,4 +189,15 @@ config USB_DWC3_RTK
or dual-role mode.
Say 'Y' or 'M' if you have such device.
+config USB_DWC3_GENERIC_PLAT
+ tristate "DWC3 Generic Platform Driver"
+ depends on OF && COMMON_CLK
+ default USB_DWC3
+ help
+ Support USB3 functionality in simple SoC integrations.
+ Currently supports SpacemiT DWC USB3. Platforms using
+ dwc3-of-simple can easily switch to dwc3-generic by flattening
+ the dwc3 child node in the device tree.
+ Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way.
+
endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 830e6c9e5fe073c1f662ce34b6a4a2da34c407a2..96469e48ff9d189cc8d0b65e65424eae2158bcfe 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o
obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o
obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o
obj-$(CONFIG_USB_DWC3_RTK) += dwc3-rtk.o
+obj-$(CONFIG_USB_DWC3_GENERIC_PLAT) += dwc3-generic-plat.o
diff --git a/drivers/usb/dwc3/dwc3-generic-plat.c b/drivers/usb/dwc3/dwc3-generic-plat.c
new file mode 100644
index 0000000000000000000000000000000000000000..766f4cf17b6909793956f44660d3b3febad50a23
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-generic-plat.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * dwc3-generic-plat.c - DesignWare USB3 generic platform driver
+ *
+ * Copyright (C) 2025 Ze Huang <huang.ze@linux.dev>
+ *
+ * Inspired by dwc3-qcom.c and dwc3-of-simple.c
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include "glue.h"
+
+struct dwc3_generic {
+ struct device *dev;
+ struct dwc3 dwc;
+ struct clk_bulk_data *clks;
+ int num_clocks;
+ struct reset_control *resets;
+};
+
+static void dwc3_generic_reset_control_assert(void *data)
+{
+ reset_control_assert(data);
+}
+
+static void dwc3_generic_clk_bulk_disable_unprepare(void *data)
+{
+ struct dwc3_generic *dwc3 = data;
+
+ clk_bulk_disable_unprepare(dwc3->num_clocks, dwc3->clks);
+}
+
+static int dwc3_generic_probe(struct platform_device *pdev)
+{
+ struct dwc3_probe_data probe_data = {};
+ struct device *dev = &pdev->dev;
+ struct dwc3_generic *dwc3;
+ struct resource *res;
+ int ret;
+
+ dwc3 = devm_kzalloc(dev, sizeof(*dwc3), GFP_KERNEL);
+ if (!dwc3)
+ return -ENOMEM;
+
+ dwc3->dev = dev;
+
+ platform_set_drvdata(pdev, dwc3);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing memory resource\n");
+ return -ENODEV;
+ }
+
+ dwc3->resets = devm_reset_control_array_get_optional_exclusive(dev);
+ if (IS_ERR(dwc3->resets))
+ return dev_err_probe(dev, PTR_ERR(dwc3->resets), "failed to get resets\n");
+
+ ret = reset_control_assert(dwc3->resets);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to assert resets\n");
+
+ ret = devm_add_action_or_reset(dev, dwc3_generic_reset_control_assert, dwc3->resets);
+ if (ret)
+ return ret;
+
+ usleep_range(10, 1000);
+
+ ret = reset_control_deassert(dwc3->resets);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to deassert resets\n");
+
+ ret = devm_clk_bulk_get_all(dwc3->dev, &dwc3->clks);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get clocks\n");
+
+ dwc3->num_clocks = ret;
+
+ ret = clk_bulk_prepare_enable(dwc3->num_clocks, dwc3->clks);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable clocks\n");
+
+ ret = devm_add_action_or_reset(dev, dwc3_generic_clk_bulk_disable_unprepare, dwc3);
+ if (ret)
+ return ret;
+
+ dwc3->dwc.dev = dev;
+ probe_data.dwc = &dwc3->dwc;
+ probe_data.res = res;
+ probe_data.ignore_clocks_and_resets = true;
+ ret = dwc3_core_probe(&probe_data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register DWC3 Core\n");
+
+ return 0;
+}
+
+static void dwc3_generic_remove(struct platform_device *pdev)
+{
+ struct dwc3_generic *dwc3 = platform_get_drvdata(pdev);
+
+ dwc3_core_remove(&dwc3->dwc);
+}
+
+static int dwc3_generic_suspend(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = dwc3_pm_suspend(&dwc3->dwc);
+ if (ret)
+ return ret;
+
+ clk_bulk_disable_unprepare(dwc3->num_clocks, dwc3->clks);
+
+ return 0;
+}
+
+static int dwc3_generic_resume(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(dwc3->num_clocks, dwc3->clks);
+ if (ret)
+ return ret;
+
+ ret = dwc3_pm_resume(&dwc3->dwc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int dwc3_generic_runtime_suspend(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+
+ return dwc3_runtime_suspend(&dwc3->dwc);
+}
+
+static int dwc3_generic_runtime_resume(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+
+ return dwc3_runtime_resume(&dwc3->dwc);
+}
+
+static int dwc3_generic_runtime_idle(struct device *dev)
+{
+ struct dwc3_generic *dwc3 = dev_get_drvdata(dev);
+
+ return dwc3_runtime_idle(&dwc3->dwc);
+}
+
+static const struct dev_pm_ops dwc3_generic_dev_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(dwc3_generic_suspend, dwc3_generic_resume)
+ RUNTIME_PM_OPS(dwc3_generic_runtime_suspend, dwc3_generic_runtime_resume,
+ dwc3_generic_runtime_idle)
+};
+
+static const struct of_device_id dwc3_generic_of_match[] = {
+ { .compatible = "spacemit,k1-dwc3", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dwc3_generic_of_match);
+
+static struct platform_driver dwc3_generic_driver = {
+ .probe = dwc3_generic_probe,
+ .remove = dwc3_generic_remove,
+ .driver = {
+ .name = "dwc3-generic-plat",
+ .of_match_table = dwc3_generic_of_match,
+ .pm = pm_ptr(&dwc3_generic_dev_pm_ops),
+ },
+};
+module_platform_driver(dwc3_generic_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare USB3 generic platform driver");
--
2.50.1
next prev parent reply other threads:[~2025-07-12 7:55 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-12 7:48 [PATCH v6 0/2] Add SpacemiT K1 USB3.0 host controller support Ze Huang
2025-07-12 7:48 ` Ze Huang
2025-07-12 7:49 ` [PATCH v6 1/2] dt-bindings: usb: dwc3: add support for SpacemiT K1 Ze Huang
2025-07-12 7:49 ` Ze Huang
2025-07-21 11:02 ` Philipp Zabel
2025-07-21 11:02 ` Philipp Zabel
2025-07-21 11:57 ` Ze Huang
2025-07-21 11:57 ` Ze Huang
2025-07-12 7:49 ` Ze Huang [this message]
2025-07-12 7:49 ` [PATCH v6 2/2] usb: dwc3: add generic driver to support flattened Ze Huang
2025-07-15 20:50 ` Alex Elder
2025-07-15 20:50 ` Alex Elder
2025-07-20 6:34 ` Ze Huang
2025-07-20 6:34 ` Ze Huang
2025-07-21 12:08 ` Ze Huang
2025-07-21 12:08 ` Ze Huang
2025-07-22 0:34 ` Yao Zi
2025-07-22 0:34 ` Yao Zi
2025-07-22 15:55 ` Ze Huang
2025-07-22 15:55 ` Ze Huang
2025-07-21 11:01 ` Philipp Zabel
2025-07-21 11:01 ` Philipp Zabel
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=20250712-dwc3_generic-v6-2-cc87737cc936@linux.dev \
--to=huang.ze@linux.dev \
--cc=Thinh.Nguyen@synopsys.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dlan@gentoo.org \
--cc=gregkh@linuxfoundation.org \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=linux-usb@vger.kernel.org \
--cc=p.zabel@pengutronix.de \
--cc=robh@kernel.org \
--cc=spacemit@lists.linux.dev \
/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.