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.

phy: Add Renesas RZ/G3E USB3.0 PHY driver

Biju <biju.das.au@gmail.com> says:

This patch series aims to add Renesas RZ/G3E USB3.0 PHY driver support.
This module is connected between USB3 Host and PHY module. The main
functions of this module are:
1) Reset control
2) Control of PHY input pins
3) Monitoring of PHY output pins

Biju Das (2):
dt-bindings: phy: renesas: Document Renesas RZ/G3E USB3.0 PHY
phy: renesas: Add Renesas RZ/G3E USB3.0 PHY driver

Link: https://patch.msgid.link/20251029084037.108610-1-biju.das.jz@bp.renesas.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

+330
+63
Documentation/devicetree/bindings/phy/renesas,rzg3e-usb3-phy.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/phy/renesas,rzg3e-usb3-phy.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Renesas RZ/G3E USB 3.0 PHY 8 + 9 + maintainers: 10 + - Biju Das <biju.das.jz@bp.renesas.com> 11 + 12 + properties: 13 + compatible: 14 + const: renesas,r9a09g047-usb3-phy 15 + 16 + reg: 17 + maxItems: 1 18 + 19 + clocks: 20 + items: 21 + - description: APB bus clock 22 + - description: USB 2.0 PHY reference clock 23 + - description: USB 3.0 PHY reference clock 24 + 25 + clock-names: 26 + items: 27 + - const: pclk 28 + - const: core 29 + - const: ref_alt_clk_p 30 + 31 + power-domains: 32 + maxItems: 1 33 + 34 + resets: 35 + maxItems: 1 36 + 37 + '#phy-cells': 38 + const: 0 39 + 40 + required: 41 + - compatible 42 + - reg 43 + - clocks 44 + - clock-names 45 + - power-domains 46 + - resets 47 + - '#phy-cells' 48 + 49 + additionalProperties: false 50 + 51 + examples: 52 + - | 53 + #include <dt-bindings/clock/renesas,r9a09g047-cpg.h> 54 + 55 + usb-phy@15870000 { 56 + compatible = "renesas,r9a09g047-usb3-phy"; 57 + reg = <0x15870000 0x10000>; 58 + clocks = <&cpg CPG_MOD 0xb0>, <&cpg CPG_CORE 13>, <&cpg CPG_CORE 12>; 59 + clock-names = "pclk", "core", "ref_alt_clk_p"; 60 + power-domains = <&cpg>; 61 + resets = <&cpg 0xaa>; 62 + #phy-cells = <0>; 63 + };
+7
drivers/phy/renesas/Kconfig
··· 40 40 select GENERIC_PHY 41 41 help 42 42 Support for USB 3.0 PHY found on Renesas R-Car generation 3 SoCs. 43 + 44 + config PHY_RZ_G3E_USB3 45 + tristate "Renesas RZ/G3E USB 3.0 PHY driver" 46 + depends on ARCH_RENESAS || COMPILE_TEST 47 + select GENERIC_PHY 48 + help 49 + Support for USB 3.0 PHY found on Renesas RZ/G3E SoCs.
+1
drivers/phy/renesas/Makefile
··· 4 4 obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o 5 5 obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o 6 6 obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o 7 + obj-$(CONFIG_PHY_RZ_G3E_USB3) += phy-rzg3e-usb3.o
+259
drivers/phy/renesas/phy-rzg3e-usb3.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Renesas RZ/G3E USB3.0 PHY driver 4 + * 5 + * Copyright (C) 2025 Renesas Electronics Corporation 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/delay.h> 10 + #include <linux/io.h> 11 + #include <linux/iopoll.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/phy/phy.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/pm_runtime.h> 17 + #include <linux/reset.h> 18 + 19 + #define USB3_TEST_RESET 0x0000 20 + #define USB3_TEST_UTMICTRL2 0x0b04 21 + #define USB3_TEST_PRMCTRL5_R 0x0c10 22 + #define USB3_TEST_PRMCTRL6_R 0x0c14 23 + 24 + #define USB3_TEST_RSTCTRL 0x1000 25 + #define USB3_TEST_CLKCTRL 0x1004 26 + #define USB3_TEST_RAMCTRL 0x100c 27 + #define USB3_TEST_CREGCTRL 0x1010 28 + #define USB3_TEST_LANECONFIG0 0x1030 29 + 30 + #define USB3_TEST_RESET_PORTRESET0_CTRL BIT(9) 31 + #define USB3_TEST_RESET_SIDDQ BIT(3) 32 + #define USB3_TEST_RESET_PHY_RESET BIT(2) 33 + #define USB3_TEST_RESET_PORTRESET0 BIT(1) 34 + #define USB3_TEST_RESET_RELEASE_OVERRIDE (0) 35 + 36 + #define USB3_TEST_UTMICTRL2_CTRL_MASK GENMASK(9, 8) 37 + #define USB3_TEST_UTMICTRL2_MODE_MASK GENMASK(1, 0) 38 + 39 + #define USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK GENMASK(2, 1) 40 + 41 + #define USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK GENMASK(2, 0) 42 + 43 + #define USB3_TEST_RSTCTRL_HARDRESET_ODEN BIT(9) 44 + #define USB3_TEST_RSTCTRL_PIPERESET_ODEN BIT(8) 45 + #define USB3_TEST_RSTCTRL_HARDRESET BIT(1) 46 + #define USB3_TEST_RSTCTRL_PIPERESET BIT(0) 47 + #define USB3_TEST_RSTCTRL_ASSERT \ 48 + (USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN | \ 49 + USB3_TEST_RSTCTRL_HARDRESET | USB3_TEST_RSTCTRL_PIPERESET) 50 + #define USB3_TEST_RSTCTRL_RELEASE_HARDRESET \ 51 + (USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN | \ 52 + USB3_TEST_RSTCTRL_PIPERESET) 53 + #define USB3_TEST_RSTCTRL_DEASSERT \ 54 + (USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN) 55 + #define USB3_TEST_RSTCTRL_RELEASE_OVERRIDE (0) 56 + 57 + #define USB3_TEST_CLKCTRL_MPLLA_SSC_EN BIT(2) 58 + 59 + #define USB3_TEST_RAMCTRL_SRAM_INIT_DONE BIT(2) 60 + #define USB3_TEST_RAMCTRL_SRAM_EXT_LD_DONE BIT(0) 61 + 62 + #define USB3_TEST_CREGCTRL_PARA_SEL BIT(8) 63 + 64 + #define USB3_TEST_LANECONFIG0_DEFAULT (0xd) 65 + 66 + struct rz_usb3 { 67 + void __iomem *base; 68 + struct reset_control *rstc; 69 + bool skip_reinit; 70 + }; 71 + 72 + static void rzg3e_phy_usb2test_phy_init(void __iomem *base) 73 + { 74 + u32 val; 75 + 76 + val = readl(base + USB3_TEST_UTMICTRL2); 77 + val |= USB3_TEST_UTMICTRL2_CTRL_MASK | USB3_TEST_UTMICTRL2_MODE_MASK; 78 + writel(val, base + USB3_TEST_UTMICTRL2); 79 + 80 + val = readl(base + USB3_TEST_PRMCTRL5_R); 81 + val &= ~USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK; 82 + val |= FIELD_PREP(USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK, 2); 83 + writel(val, base + USB3_TEST_PRMCTRL5_R); 84 + 85 + val = readl(base + USB3_TEST_PRMCTRL6_R); 86 + val &= ~USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK; 87 + val |= FIELD_PREP(USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK, 7); 88 + writel(val, base + USB3_TEST_PRMCTRL6_R); 89 + 90 + val = readl(base + USB3_TEST_RESET); 91 + val &= ~USB3_TEST_RESET_SIDDQ; 92 + val |= USB3_TEST_RESET_PORTRESET0_CTRL | USB3_TEST_RESET_PHY_RESET | 93 + USB3_TEST_RESET_PORTRESET0; 94 + writel(val, base + USB3_TEST_RESET); 95 + fsleep(10); 96 + 97 + val &= ~(USB3_TEST_RESET_PHY_RESET | USB3_TEST_RESET_PORTRESET0); 98 + writel(val, base + USB3_TEST_RESET); 99 + fsleep(10); 100 + 101 + val = readl(base + USB3_TEST_UTMICTRL2); 102 + val &= ~USB3_TEST_UTMICTRL2_CTRL_MASK; 103 + writel(val, base + USB3_TEST_UTMICTRL2); 104 + 105 + writel(USB3_TEST_RESET_RELEASE_OVERRIDE, base + USB3_TEST_RESET); 106 + } 107 + 108 + static int rzg3e_phy_usb3test_phy_init(void __iomem *base) 109 + { 110 + int ret; 111 + u32 val; 112 + 113 + writel(USB3_TEST_CREGCTRL_PARA_SEL, base + USB3_TEST_CREGCTRL); 114 + writel(USB3_TEST_RSTCTRL_ASSERT, base + USB3_TEST_RSTCTRL); 115 + fsleep(20); 116 + 117 + writel(USB3_TEST_CLKCTRL_MPLLA_SSC_EN, base + USB3_TEST_CLKCTRL); 118 + writel(USB3_TEST_LANECONFIG0_DEFAULT, base + USB3_TEST_LANECONFIG0); 119 + writel(USB3_TEST_RSTCTRL_RELEASE_HARDRESET, base + USB3_TEST_RSTCTRL); 120 + 121 + ret = readl_poll_timeout_atomic(base + USB3_TEST_RAMCTRL, val, 122 + val & USB3_TEST_RAMCTRL_SRAM_INIT_DONE, 1, 10000); 123 + if (ret) 124 + return ret; 125 + 126 + writel(USB3_TEST_RSTCTRL_DEASSERT, base + USB3_TEST_RSTCTRL); 127 + writel(USB3_TEST_RAMCTRL_SRAM_EXT_LD_DONE, base + USB3_TEST_RAMCTRL); 128 + writel(USB3_TEST_RSTCTRL_RELEASE_OVERRIDE, base + USB3_TEST_RSTCTRL); 129 + 130 + return 0; 131 + } 132 + 133 + static int rzg3e_phy_usb3_init_helper(void __iomem *base) 134 + { 135 + rzg3e_phy_usb2test_phy_init(base); 136 + 137 + return rzg3e_phy_usb3test_phy_init(base); 138 + } 139 + 140 + static int rzg3e_phy_usb3_init(struct phy *p) 141 + { 142 + struct rz_usb3 *r = phy_get_drvdata(p); 143 + int ret = 0; 144 + 145 + if (!r->skip_reinit) 146 + ret = rzg3e_phy_usb3_init_helper(r->base); 147 + 148 + return ret; 149 + } 150 + 151 + static const struct phy_ops rzg3e_phy_usb3_ops = { 152 + .init = rzg3e_phy_usb3_init, 153 + .owner = THIS_MODULE, 154 + }; 155 + 156 + static int rzg3e_phy_usb3_probe(struct platform_device *pdev) 157 + { 158 + struct device *dev = &pdev->dev; 159 + struct phy_provider *provider; 160 + struct rz_usb3 *r; 161 + struct phy *phy; 162 + int ret; 163 + 164 + r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); 165 + if (!r) 166 + return -ENOMEM; 167 + 168 + r->base = devm_platform_ioremap_resource(pdev, 0); 169 + if (IS_ERR(r->base)) 170 + return PTR_ERR(r->base); 171 + 172 + r->rstc = devm_reset_control_get_shared_deasserted(dev, NULL); 173 + if (IS_ERR(r->rstc)) 174 + return dev_err_probe(dev, PTR_ERR(r->rstc), "failed to get deasserted reset\n"); 175 + 176 + /* 177 + * devm_phy_create() will call pm_runtime_enable(&phy->dev); 178 + * And then, phy-core will manage runtime pm for this device. 179 + */ 180 + ret = devm_pm_runtime_enable(dev); 181 + if (ret < 0) 182 + return ret; 183 + 184 + phy = devm_phy_create(dev, NULL, &rzg3e_phy_usb3_ops); 185 + if (IS_ERR(phy)) 186 + return dev_err_probe(dev, PTR_ERR(phy), "failed to create USB3 PHY\n"); 187 + 188 + platform_set_drvdata(pdev, r); 189 + phy_set_drvdata(phy, r); 190 + 191 + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 192 + if (IS_ERR(provider)) 193 + return dev_err_probe(dev, PTR_ERR(provider), "failed to register PHY provider\n"); 194 + 195 + return 0; 196 + } 197 + 198 + static int rzg3e_phy_usb3_suspend(struct device *dev) 199 + { 200 + struct rz_usb3 *r = dev_get_drvdata(dev); 201 + 202 + pm_runtime_put(dev); 203 + reset_control_assert(r->rstc); 204 + r->skip_reinit = false; 205 + 206 + return 0; 207 + } 208 + 209 + static int rzg3e_phy_usb3_resume(struct device *dev) 210 + { 211 + struct rz_usb3 *r = dev_get_drvdata(dev); 212 + int ret; 213 + 214 + ret = reset_control_deassert(r->rstc); 215 + if (ret) 216 + return ret; 217 + 218 + ret = pm_runtime_resume_and_get(dev); 219 + if (ret) 220 + goto reset_assert; 221 + 222 + ret = rzg3e_phy_usb3_init_helper(r->base); 223 + if (ret) 224 + goto pm_put; 225 + 226 + r->skip_reinit = true; 227 + 228 + return 0; 229 + 230 + pm_put: 231 + pm_runtime_put(dev); 232 + reset_assert: 233 + reset_control_assert(r->rstc); 234 + return ret; 235 + } 236 + 237 + static const struct dev_pm_ops rzg3e_phy_usb3_pm = { 238 + NOIRQ_SYSTEM_SLEEP_PM_OPS(rzg3e_phy_usb3_suspend, rzg3e_phy_usb3_resume) 239 + }; 240 + 241 + static const struct of_device_id rzg3e_phy_usb3_match_table[] = { 242 + { .compatible = "renesas,r9a09g047-usb3-phy" }, 243 + { /* Sentinel */ } 244 + }; 245 + 246 + MODULE_DEVICE_TABLE(of, rzg3e_phy_usb3_match_table); 247 + static struct platform_driver rzg3e_phy_usb3_driver = { 248 + .driver = { 249 + .name = "phy_rzg3e_usb3", 250 + .of_match_table = rzg3e_phy_usb3_match_table, 251 + .pm = pm_sleep_ptr(&rzg3e_phy_usb3_pm), 252 + }, 253 + .probe = rzg3e_phy_usb3_probe, 254 + }; 255 + module_platform_driver(rzg3e_phy_usb3_driver); 256 + 257 + MODULE_LICENSE("GPL"); 258 + MODULE_DESCRIPTION("Renesas RZ/G3E USB3.0 PHY Driver"); 259 + MODULE_AUTHOR("biju.das.jz@bp.renesas.com>");