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

usb: cdns3: Add StarFive JH7110 USB driver

Adds Specific Glue layer to support USB peripherals on
StarFive JH7110 SoC.
There is a Cadence USB3 core for JH7110 SoCs, the cdns
core is the child of this USB wrapper module device.

Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
Acked-by: Peter Chen <peter.chen@kernel.org>
Reviewed-by: Roger Quadros <rogerq@kernel.org>
Link: https://lore.kernel.org/r/20230518112750.57924-7-minda.chen@starfivetech.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Minda Chen and committed by
Greg Kroah-Hartman
bfb46b42 8486eb80

+264
+6
MAINTAINERS
··· 20137 20137 F: drivers/reset/starfive/reset-starfive-jh71* 20138 20138 F: include/dt-bindings/reset/starfive?jh71*.h 20139 20139 20140 + STARFIVE JH71X0 USB DRIVERS 20141 + M: Minda Chen <minda.chen@starfivetech.com> 20142 + S: Maintained 20143 + F: Documentation/devicetree/bindings/usb/starfive,jh7110-usb.yaml 20144 + F: drivers/usb/cdns3/cdns3-starfive.c 20145 + 20140 20146 STARFIVE JH71XX PMU CONTROLLER DRIVER 20141 20147 M: Walker Chen <walker.chen@starfivetech.com> 20142 20148 S: Supported
+11
drivers/usb/cdns3/Kconfig
··· 78 78 79 79 For example, imx8qm and imx8qxp. 80 80 81 + config USB_CDNS3_STARFIVE 82 + tristate "Cadence USB3 support on StarFive SoC platforms" 83 + depends on ARCH_STARFIVE || COMPILE_TEST 84 + help 85 + Say 'Y' or 'M' here if you are building for StarFive SoCs 86 + platforms that contain Cadence USB3 controller core. 87 + 88 + e.g. JH7110. 89 + 90 + If you choose to build this driver as module it will 91 + be dynamically linked and module will be called cdns3-starfive.ko 81 92 endif 82 93 83 94 if USB_CDNS_SUPPORT
+1
drivers/usb/cdns3/Makefile
··· 24 24 obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o 25 25 obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o 26 26 obj-$(CONFIG_USB_CDNS3_IMX) += cdns3-imx.o 27 + obj-$(CONFIG_USB_CDNS3_STARFIVE) += cdns3-starfive.o 27 28 28 29 cdnsp-udc-pci-y := cdnsp-pci.o 29 30
+246
drivers/usb/cdns3/cdns3-starfive.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /** 3 + * cdns3-starfive.c - StarFive specific Glue layer for Cadence USB Controller 4 + * 5 + * Copyright (C) 2023 StarFive Technology Co., Ltd. 6 + * 7 + * Author: Minda Chen <minda.chen@starfivetech.com> 8 + */ 9 + 10 + #include <linux/bits.h> 11 + #include <linux/clk.h> 12 + #include <linux/module.h> 13 + #include <linux/mfd/syscon.h> 14 + #include <linux/kernel.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/io.h> 17 + #include <linux/of_platform.h> 18 + #include <linux/reset.h> 19 + #include <linux/regmap.h> 20 + #include <linux/usb/otg.h> 21 + #include "core.h" 22 + 23 + #define USB_STRAP_HOST BIT(17) 24 + #define USB_STRAP_DEVICE BIT(18) 25 + #define USB_STRAP_MASK GENMASK(18, 16) 26 + 27 + #define USB_SUSPENDM_HOST BIT(19) 28 + #define USB_SUSPENDM_MASK BIT(19) 29 + 30 + #define USB_MISC_CFG_MASK GENMASK(23, 20) 31 + #define USB_SUSPENDM_BYPS BIT(20) 32 + #define USB_PLL_EN BIT(22) 33 + #define USB_REFCLK_MODE BIT(23) 34 + 35 + struct cdns_starfive { 36 + struct device *dev; 37 + struct regmap *stg_syscon; 38 + struct reset_control *resets; 39 + struct clk_bulk_data *clks; 40 + int num_clks; 41 + u32 stg_usb_mode; 42 + }; 43 + 44 + static void cdns_mode_init(struct platform_device *pdev, 45 + struct cdns_starfive *data) 46 + { 47 + enum usb_dr_mode mode; 48 + 49 + regmap_update_bits(data->stg_syscon, data->stg_usb_mode, 50 + USB_MISC_CFG_MASK, 51 + USB_SUSPENDM_BYPS | USB_PLL_EN | USB_REFCLK_MODE); 52 + 53 + /* dr mode setting */ 54 + mode = usb_get_dr_mode(&pdev->dev); 55 + 56 + switch (mode) { 57 + case USB_DR_MODE_HOST: 58 + regmap_update_bits(data->stg_syscon, 59 + data->stg_usb_mode, 60 + USB_STRAP_MASK, 61 + USB_STRAP_HOST); 62 + regmap_update_bits(data->stg_syscon, 63 + data->stg_usb_mode, 64 + USB_SUSPENDM_MASK, 65 + USB_SUSPENDM_HOST); 66 + break; 67 + 68 + case USB_DR_MODE_PERIPHERAL: 69 + regmap_update_bits(data->stg_syscon, data->stg_usb_mode, 70 + USB_STRAP_MASK, USB_STRAP_DEVICE); 71 + regmap_update_bits(data->stg_syscon, data->stg_usb_mode, 72 + USB_SUSPENDM_MASK, 0); 73 + break; 74 + default: 75 + break; 76 + } 77 + } 78 + 79 + static int cdns_clk_rst_init(struct cdns_starfive *data) 80 + { 81 + int ret; 82 + 83 + ret = clk_bulk_prepare_enable(data->num_clks, data->clks); 84 + if (ret) 85 + return dev_err_probe(data->dev, ret, 86 + "failed to enable clocks\n"); 87 + 88 + ret = reset_control_deassert(data->resets); 89 + if (ret) { 90 + dev_err(data->dev, "failed to reset clocks\n"); 91 + goto err_clk_init; 92 + } 93 + 94 + return ret; 95 + 96 + err_clk_init: 97 + clk_bulk_disable_unprepare(data->num_clks, data->clks); 98 + return ret; 99 + } 100 + 101 + static void cdns_clk_rst_deinit(struct cdns_starfive *data) 102 + { 103 + reset_control_assert(data->resets); 104 + clk_bulk_disable_unprepare(data->num_clks, data->clks); 105 + } 106 + 107 + static int cdns_starfive_probe(struct platform_device *pdev) 108 + { 109 + struct device *dev = &pdev->dev; 110 + struct cdns_starfive *data; 111 + unsigned int args; 112 + int ret; 113 + 114 + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 115 + if (!data) 116 + return -ENOMEM; 117 + 118 + data->dev = dev; 119 + 120 + data->stg_syscon = 121 + syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node, 122 + "starfive,stg-syscon", 1, &args); 123 + 124 + if (IS_ERR(data->stg_syscon)) 125 + return dev_err_probe(dev, PTR_ERR(data->stg_syscon), 126 + "Failed to parse starfive,stg-syscon\n"); 127 + 128 + data->stg_usb_mode = args; 129 + 130 + data->num_clks = devm_clk_bulk_get_all(data->dev, &data->clks); 131 + if (data->num_clks < 0) 132 + return dev_err_probe(data->dev, -ENODEV, 133 + "Failed to get clocks\n"); 134 + 135 + data->resets = devm_reset_control_array_get_exclusive(data->dev); 136 + if (IS_ERR(data->resets)) 137 + return dev_err_probe(data->dev, PTR_ERR(data->resets), 138 + "Failed to get resets"); 139 + 140 + cdns_mode_init(pdev, data); 141 + ret = cdns_clk_rst_init(data); 142 + if (ret) 143 + return ret; 144 + 145 + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 146 + if (ret) { 147 + dev_err(dev, "Failed to create children\n"); 148 + cdns_clk_rst_deinit(data); 149 + return ret; 150 + } 151 + 152 + device_set_wakeup_capable(dev, true); 153 + pm_runtime_set_active(dev); 154 + pm_runtime_enable(dev); 155 + platform_set_drvdata(pdev, data); 156 + 157 + return 0; 158 + } 159 + 160 + static int cdns_starfive_remove_core(struct device *dev, void *c) 161 + { 162 + struct platform_device *pdev = to_platform_device(dev); 163 + 164 + platform_device_unregister(pdev); 165 + 166 + return 0; 167 + } 168 + 169 + static int cdns_starfive_remove(struct platform_device *pdev) 170 + { 171 + struct device *dev = &pdev->dev; 172 + struct cdns_starfive *data = dev_get_drvdata(dev); 173 + 174 + pm_runtime_get_sync(dev); 175 + device_for_each_child(dev, NULL, cdns_starfive_remove_core); 176 + 177 + pm_runtime_disable(dev); 178 + pm_runtime_put_noidle(dev); 179 + cdns_clk_rst_deinit(data); 180 + platform_set_drvdata(pdev, NULL); 181 + 182 + return 0; 183 + } 184 + 185 + #ifdef CONFIG_PM 186 + static int cdns_starfive_runtime_resume(struct device *dev) 187 + { 188 + struct cdns_starfive *data = dev_get_drvdata(dev); 189 + 190 + return clk_bulk_prepare_enable(data->num_clks, data->clks); 191 + } 192 + 193 + static int cdns_starfive_runtime_suspend(struct device *dev) 194 + { 195 + struct cdns_starfive *data = dev_get_drvdata(dev); 196 + 197 + clk_bulk_disable_unprepare(data->num_clks, data->clks); 198 + 199 + return 0; 200 + } 201 + 202 + #ifdef CONFIG_PM_SLEEP 203 + static int cdns_starfive_resume(struct device *dev) 204 + { 205 + struct cdns_starfive *data = dev_get_drvdata(dev); 206 + 207 + return cdns_clk_rst_init(data); 208 + } 209 + 210 + static int cdns_starfive_suspend(struct device *dev) 211 + { 212 + struct cdns_starfive *data = dev_get_drvdata(dev); 213 + 214 + cdns_clk_rst_deinit(data); 215 + 216 + return 0; 217 + } 218 + #endif 219 + #endif 220 + 221 + static const struct dev_pm_ops cdns_starfive_pm_ops = { 222 + SET_RUNTIME_PM_OPS(cdns_starfive_runtime_suspend, 223 + cdns_starfive_runtime_resume, NULL) 224 + SET_SYSTEM_SLEEP_PM_OPS(cdns_starfive_suspend, cdns_starfive_resume) 225 + }; 226 + 227 + static const struct of_device_id cdns_starfive_of_match[] = { 228 + { .compatible = "starfive,jh7110-usb", }, 229 + { /* sentinel */ } 230 + }; 231 + MODULE_DEVICE_TABLE(of, cdns_starfive_of_match); 232 + 233 + static struct platform_driver cdns_starfive_driver = { 234 + .probe = cdns_starfive_probe, 235 + .remove = cdns_starfive_remove, 236 + .driver = { 237 + .name = "cdns3-starfive", 238 + .of_match_table = cdns_starfive_of_match, 239 + .pm = &cdns_starfive_pm_ops, 240 + }, 241 + }; 242 + module_platform_driver(cdns_starfive_driver); 243 + 244 + MODULE_ALIAS("platform:cdns3-starfive"); 245 + MODULE_LICENSE("GPL v2"); 246 + MODULE_DESCRIPTION("Cadence USB3 StarFive Glue Layer");