Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge patch series "Add SpacemiT K1 USB3.0 host controller support"

Ze Huang <huang.ze@linux.dev> says:

The USB 3.0 controller found in the SpacemiT K1 SoC[1] supports both
USB3.0 Host and USB2.0 Dual-Role Device (DRD).

This controller is compatible with DesignWare Core USB 3 (DWC3) driver.
However, constraints in the `snps,dwc3` bindings limit the ability to
describe hardware-specific features in a clean and maintainable way.
While `dwc3-of-simple` still serves as a glue layer for many platforms,
it requires a split device tree node structure, which is less desirable
in newer platforms.

To promote a transition toward a flattened `dwc` node structure, this
series introduces `dwc3-generic-plat`, building upon prior efforts that
exposed the DWC3 core driver [2].

The device tree support for SpacemiT K1 will be submitted separately
when the associated PHY driver is ready.

Link: https://developer.spacemit.com/documentation?token=AjHDwrW78igAAEkiHracBI9HnTb [1]
Link: https://lore.kernel.org/all/20250414-dwc3-refactor-v7-3-f015b358722d@oss.qualcomm.com [2]
Link: https://lore.kernel.org/r/20250913-dwc3_generic-v8-0-b50f81f05f95@linux.dev
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

+299
+121
Documentation/devicetree/bindings/usb/spacemit,k1-dwc3.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/usb/spacemit,k1-dwc3.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: SpacemiT K1 SuperSpeed DWC3 USB SoC Controller 8 + 9 + maintainers: 10 + - Ze Huang <huang.ze@linux.dev> 11 + 12 + description: | 13 + The SpacemiT K1 embeds a DWC3 USB IP Core which supports Host functions 14 + for USB 3.0 and DRD for USB 2.0. 15 + 16 + Key features: 17 + - USB3.0 SuperSpeed and USB2.0 High/Full/Low-Speed support 18 + - Supports low-power modes (USB2.0 suspend, USB3.0 U1/U2/U3) 19 + - Internal DMA controller and flexible endpoint FIFO sizing 20 + 21 + Communication Interface: 22 + - Use of PIPE3 (125MHz) interface for USB3.0 PHY 23 + - Use of UTMI+ (30/60MHz) interface for USB2.0 PHY 24 + 25 + allOf: 26 + - $ref: snps,dwc3-common.yaml# 27 + 28 + properties: 29 + compatible: 30 + const: spacemit,k1-dwc3 31 + 32 + reg: 33 + maxItems: 1 34 + 35 + clocks: 36 + maxItems: 1 37 + 38 + clock-names: 39 + const: usbdrd30 40 + 41 + interrupts: 42 + maxItems: 1 43 + 44 + phys: 45 + items: 46 + - description: phandle to USB2/HS PHY 47 + - description: phandle to USB3/SS PHY 48 + 49 + phy-names: 50 + items: 51 + - const: usb2-phy 52 + - const: usb3-phy 53 + 54 + resets: 55 + items: 56 + - description: USB3.0 AHB reset 57 + - description: USB3.0 VCC reset 58 + - description: USB3.0 PHY reset 59 + 60 + reset-names: 61 + items: 62 + - const: ahb 63 + - const: vcc 64 + - const: phy 65 + 66 + reset-delay: 67 + $ref: /schemas/types.yaml#/definitions/uint32 68 + default: 2 69 + description: delay after reset sequence [us] 70 + 71 + vbus-supply: 72 + description: A phandle to the regulator supplying the VBUS voltage. 73 + 74 + required: 75 + - compatible 76 + - reg 77 + - clocks 78 + - clock-names 79 + - interrupts 80 + - phys 81 + - phy-names 82 + - resets 83 + - reset-names 84 + 85 + unevaluatedProperties: false 86 + 87 + examples: 88 + - | 89 + usb@c0a00000 { 90 + compatible = "spacemit,k1-dwc3"; 91 + reg = <0xc0a00000 0x10000>; 92 + clocks = <&syscon_apmu 16>; 93 + clock-names = "usbdrd30"; 94 + interrupts = <125>; 95 + phys = <&usb2phy>, <&usb3phy>; 96 + phy-names = "usb2-phy", "usb3-phy"; 97 + resets = <&syscon_apmu 8>, 98 + <&syscon_apmu 9>, 99 + <&syscon_apmu 10>; 100 + reset-names = "ahb", "vcc", "phy"; 101 + reset-delay = <2>; 102 + vbus-supply = <&usb3_vbus>; 103 + #address-cells = <1>; 104 + #size-cells = <0>; 105 + 106 + hub_2_0: hub@1 { 107 + compatible = "usb2109,2817"; 108 + reg = <1>; 109 + vdd-supply = <&usb3_vhub>; 110 + peer-hub = <&hub_3_0>; 111 + reset-gpios = <&gpio 3 28 1>; 112 + }; 113 + 114 + hub_3_0: hub@2 { 115 + compatible = "usb2109,817"; 116 + reg = <2>; 117 + vdd-supply = <&usb3_vhub>; 118 + peer-hub = <&hub_2_0>; 119 + reset-gpios = <&gpio 3 28 1>; 120 + }; 121 + };
+11
drivers/usb/dwc3/Kconfig
··· 189 189 or dual-role mode. 190 190 Say 'Y' or 'M' if you have such device. 191 191 192 + config USB_DWC3_GENERIC_PLAT 193 + tristate "DWC3 Generic Platform Driver" 194 + depends on OF && COMMON_CLK 195 + default USB_DWC3 196 + help 197 + Support USB3 functionality in simple SoC integrations. 198 + Currently supports SpacemiT DWC USB3. Platforms using 199 + dwc3-of-simple can easily switch to dwc3-generic by flattening 200 + the dwc3 child node in the device tree. 201 + Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way. 202 + 192 203 endif
+1
drivers/usb/dwc3/Makefile
··· 57 57 obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o 58 58 obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o 59 59 obj-$(CONFIG_USB_DWC3_RTK) += dwc3-rtk.o 60 + obj-$(CONFIG_USB_DWC3_GENERIC_PLAT) += dwc3-generic-plat.o
+166
drivers/usb/dwc3/dwc3-generic-plat.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * dwc3-generic-plat.c - DesignWare USB3 generic platform driver 4 + * 5 + * Copyright (C) 2025 Ze Huang <huang.ze@linux.dev> 6 + * 7 + * Inspired by dwc3-qcom.c and dwc3-of-simple.c 8 + */ 9 + 10 + #include <linux/clk.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/reset.h> 13 + #include "glue.h" 14 + 15 + struct dwc3_generic { 16 + struct device *dev; 17 + struct dwc3 dwc; 18 + struct clk_bulk_data *clks; 19 + int num_clocks; 20 + struct reset_control *resets; 21 + }; 22 + 23 + #define to_dwc3_generic(d) container_of((d), struct dwc3_generic, dwc) 24 + 25 + static void dwc3_generic_reset_control_assert(void *data) 26 + { 27 + reset_control_assert(data); 28 + } 29 + 30 + static int dwc3_generic_probe(struct platform_device *pdev) 31 + { 32 + struct dwc3_probe_data probe_data = {}; 33 + struct device *dev = &pdev->dev; 34 + struct dwc3_generic *dwc3g; 35 + struct resource *res; 36 + int ret; 37 + 38 + dwc3g = devm_kzalloc(dev, sizeof(*dwc3g), GFP_KERNEL); 39 + if (!dwc3g) 40 + return -ENOMEM; 41 + 42 + dwc3g->dev = dev; 43 + 44 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 45 + if (!res) { 46 + dev_err(&pdev->dev, "missing memory resource\n"); 47 + return -ENODEV; 48 + } 49 + 50 + dwc3g->resets = devm_reset_control_array_get_optional_exclusive(dev); 51 + if (IS_ERR(dwc3g->resets)) 52 + return dev_err_probe(dev, PTR_ERR(dwc3g->resets), "failed to get resets\n"); 53 + 54 + ret = reset_control_assert(dwc3g->resets); 55 + if (ret) 56 + return dev_err_probe(dev, ret, "failed to assert resets\n"); 57 + 58 + /* Not strict timing, just for safety */ 59 + udelay(2); 60 + 61 + ret = reset_control_deassert(dwc3g->resets); 62 + if (ret) 63 + return dev_err_probe(dev, ret, "failed to deassert resets\n"); 64 + 65 + ret = devm_add_action_or_reset(dev, dwc3_generic_reset_control_assert, dwc3g->resets); 66 + if (ret) 67 + return ret; 68 + 69 + ret = devm_clk_bulk_get_all_enabled(dwc3g->dev, &dwc3g->clks); 70 + if (ret < 0) 71 + return dev_err_probe(dev, ret, "failed to get clocks\n"); 72 + 73 + dwc3g->num_clocks = ret; 74 + dwc3g->dwc.dev = dev; 75 + probe_data.dwc = &dwc3g->dwc; 76 + probe_data.res = res; 77 + probe_data.ignore_clocks_and_resets = true; 78 + ret = dwc3_core_probe(&probe_data); 79 + if (ret) 80 + return dev_err_probe(dev, ret, "failed to register DWC3 Core\n"); 81 + 82 + return 0; 83 + } 84 + 85 + static void dwc3_generic_remove(struct platform_device *pdev) 86 + { 87 + struct dwc3 *dwc = platform_get_drvdata(pdev); 88 + struct dwc3_generic *dwc3g = to_dwc3_generic(dwc); 89 + 90 + dwc3_core_remove(dwc); 91 + 92 + clk_bulk_disable_unprepare(dwc3g->num_clocks, dwc3g->clks); 93 + } 94 + 95 + static int dwc3_generic_suspend(struct device *dev) 96 + { 97 + struct dwc3 *dwc = dev_get_drvdata(dev); 98 + struct dwc3_generic *dwc3g = to_dwc3_generic(dwc); 99 + int ret; 100 + 101 + ret = dwc3_pm_suspend(dwc); 102 + if (ret) 103 + return ret; 104 + 105 + clk_bulk_disable_unprepare(dwc3g->num_clocks, dwc3g->clks); 106 + 107 + return 0; 108 + } 109 + 110 + static int dwc3_generic_resume(struct device *dev) 111 + { 112 + struct dwc3 *dwc = dev_get_drvdata(dev); 113 + struct dwc3_generic *dwc3g = to_dwc3_generic(dwc); 114 + int ret; 115 + 116 + ret = clk_bulk_prepare_enable(dwc3g->num_clocks, dwc3g->clks); 117 + if (ret) 118 + return ret; 119 + 120 + ret = dwc3_pm_resume(dwc); 121 + if (ret) 122 + return ret; 123 + 124 + return 0; 125 + } 126 + 127 + static int dwc3_generic_runtime_suspend(struct device *dev) 128 + { 129 + return dwc3_runtime_suspend(dev_get_drvdata(dev)); 130 + } 131 + 132 + static int dwc3_generic_runtime_resume(struct device *dev) 133 + { 134 + return dwc3_runtime_resume(dev_get_drvdata(dev)); 135 + } 136 + 137 + static int dwc3_generic_runtime_idle(struct device *dev) 138 + { 139 + return dwc3_runtime_idle(dev_get_drvdata(dev)); 140 + } 141 + 142 + static const struct dev_pm_ops dwc3_generic_dev_pm_ops = { 143 + SYSTEM_SLEEP_PM_OPS(dwc3_generic_suspend, dwc3_generic_resume) 144 + RUNTIME_PM_OPS(dwc3_generic_runtime_suspend, dwc3_generic_runtime_resume, 145 + dwc3_generic_runtime_idle) 146 + }; 147 + 148 + static const struct of_device_id dwc3_generic_of_match[] = { 149 + { .compatible = "spacemit,k1-dwc3", }, 150 + { /* sentinel */ } 151 + }; 152 + MODULE_DEVICE_TABLE(of, dwc3_generic_of_match); 153 + 154 + static struct platform_driver dwc3_generic_driver = { 155 + .probe = dwc3_generic_probe, 156 + .remove = dwc3_generic_remove, 157 + .driver = { 158 + .name = "dwc3-generic-plat", 159 + .of_match_table = dwc3_generic_of_match, 160 + .pm = pm_ptr(&dwc3_generic_dev_pm_ops), 161 + }, 162 + }; 163 + module_platform_driver(dwc3_generic_driver); 164 + 165 + MODULE_LICENSE("GPL"); 166 + MODULE_DESCRIPTION("DesignWare USB3 generic platform driver");