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

phy: rcar-gen3-usb3: add support for R-Car Gen3 USB 3.0 PHY

The USB 3.0 PHY modules of R-Car Gen3 SoCs have:
- Spread spectrum clock (ssc).
- Using USB 2.0 EXTAL clock instead of USB 3.0 clock.
- Enabling VBUS detection for usb3.0 peripheral.

So, this driver supports these features.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Yoshihiro Shimoda and committed by
Kishon Vijay Abraham I
7c7356ba b59b1d39

+282 -2
+46
Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt
··· 1 + * Renesas R-Car generation 3 USB 3.0 PHY 2 + 3 + This file provides information on what the device node for the R-Car generation 4 + 3 USB 3.0 PHY contains. 5 + If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL 6 + instead of USB3_CLK. However, if you don't want to these features, you don't 7 + need this driver. 8 + 9 + Required properties: 10 + - compatible: "renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795 11 + SoC. 12 + "renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796 13 + SoC. 14 + "renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible 15 + device. 16 + 17 + When compatible with the generic version, nodes must list the 18 + SoC-specific version corresponding to the platform first 19 + followed by the generic version. 20 + 21 + - reg: offset and length of the USB 3.0 PHY register block. 22 + - clocks: A list of phandles and clock-specifier pairs. 23 + - clock-names: Name of the clocks. 24 + - The funcional clock must be "usb3-if". 25 + - The usb3's external clock must be "usb3s_clk". 26 + - The usb2's external clock must be "usb_extal". If you want to use the ssc, 27 + the clock-frequency must not be 0. 28 + - #phy-cells: see phy-bindings.txt in the same directory, must be <0>. 29 + 30 + Optional properties: 31 + - renesas,ssc-range: Enable/disable spread spectrum clock (ssc) by using 32 + the following values as u32: 33 + - 0 (or the property doesn't exist): disable the ssc 34 + - 4980: enable the ssc as -4980 ppm 35 + - 4492: enable the ssc as -4492 ppm 36 + - 4003: enable the ssc as -4003 ppm 37 + 38 + Example (R-Car H3): 39 + 40 + usb-phy@e65ee000 { 41 + compatible = "renesas,r8a7795-usb3-phy", 42 + "renesas,rcar-gen3-usb3-phy"; 43 + reg = <0 0xe65ee000 0 0x90>; 44 + clocks = <&cpg CPG_MOD 328>, <&usb3s0_clk>, <&usb_extal>; 45 + clock-names = "usb3-if", "usb3s_clk", "usb_extal"; 46 + };
+2 -2
MAINTAINERS
··· 10829 10829 S: Supported 10830 10830 F: drivers/iio/adc/rcar_gyro_adc.c 10831 10831 10832 - RENESAS USB2 PHY DRIVER 10832 + RENESAS USB PHY DRIVER 10833 10833 M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> 10834 10834 L: linux-renesas-soc@vger.kernel.org 10835 10835 S: Maintained 10836 - F: drivers/phy/renesas/phy-rcar-gen3-usb2.c 10836 + F: drivers/phy/renesas/phy-rcar-gen3-usb*.c 10837 10837 10838 10838 RESET CONTROLLER FRAMEWORK 10839 10839 M: Philipp Zabel <p.zabel@pengutronix.de>
+7
drivers/phy/renesas/Kconfig
··· 15 15 select GENERIC_PHY 16 16 help 17 17 Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. 18 + 19 + config PHY_RCAR_GEN3_USB3 20 + tristate "Renesas R-Car generation 3 USB 3.0 PHY driver" 21 + depends on ARCH_RENESAS || COMPILE_TEST 22 + select GENERIC_PHY 23 + help 24 + Support for USB 3.0 PHY found on Renesas R-Car generation 3 SoCs.
+1
drivers/phy/renesas/Makefile
··· 1 1 obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o 2 2 obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o 3 + obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o
+226
drivers/phy/renesas/phy-rcar-gen3-usb3.c
··· 1 + /* 2 + * Renesas R-Car Gen3 for USB3.0 PHY driver 3 + * 4 + * Copyright (C) 2017 Renesas Electronics Corporation 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/clk.h> 12 + #include <linux/delay.h> 13 + #include <linux/io.h> 14 + #include <linux/module.h> 15 + #include <linux/of.h> 16 + #include <linux/phy/phy.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/pm_runtime.h> 19 + 20 + #define USB30_CLKSET0 0x034 21 + #define USB30_CLKSET1 0x036 22 + #define USB30_SSC_SET 0x038 23 + #define USB30_PHY_ENABLE 0x060 24 + #define USB30_VBUS_EN 0x064 25 + 26 + /* USB30_CLKSET0 */ 27 + #define CLKSET0_PRIVATE 0x05c0 28 + #define CLKSET0_USB30_FSEL_USB_EXTAL 0x0002 29 + 30 + /* USB30_CLKSET1 */ 31 + #define CLKSET1_USB30_PLL_MULTI_SHIFT 6 32 + #define CLKSET1_USB30_PLL_MULTI_USB_EXTAL (0x64 << \ 33 + CLKSET1_USB30_PLL_MULTI_SHIFT) 34 + #define CLKSET1_PHYRESET BIT(4) /* 1: reset */ 35 + #define CLKSET1_REF_CLKDIV BIT(3) /* 1: USB_EXTAL */ 36 + #define CLKSET1_PRIVATE_2_1 BIT(1) /* Write B'01 */ 37 + #define CLKSET1_REF_CLK_SEL BIT(0) /* 1: USB3S0_CLK_P */ 38 + 39 + /* USB30_SSC_SET */ 40 + #define SSC_SET_SSC_EN BIT(12) 41 + #define SSC_SET_RANGE_SHIFT 9 42 + #define SSC_SET_RANGE_4980 (0x0 << SSC_SET_RANGE_SHIFT) 43 + #define SSC_SET_RANGE_4492 (0x1 << SSC_SET_RANGE_SHIFT) 44 + #define SSC_SET_RANGE_4003 (0x2 << SSC_SET_RANGE_SHIFT) 45 + 46 + /* USB30_PHY_ENABLE */ 47 + #define PHY_ENABLE_RESET_EN BIT(4) 48 + 49 + /* USB30_VBUS_EN */ 50 + #define VBUS_EN_VBUS_EN BIT(1) 51 + 52 + struct rcar_gen3_usb3 { 53 + void __iomem *base; 54 + struct phy *phy; 55 + u32 ssc_range; 56 + bool usb3s_clk; 57 + bool usb_extal; 58 + }; 59 + 60 + static void write_clkset1_for_usb_extal(struct rcar_gen3_usb3 *r, bool reset) 61 + { 62 + u16 val = CLKSET1_USB30_PLL_MULTI_USB_EXTAL | 63 + CLKSET1_REF_CLKDIV | CLKSET1_PRIVATE_2_1; 64 + 65 + if (reset) 66 + val |= CLKSET1_PHYRESET; 67 + 68 + writew(val, r->base + USB30_CLKSET1); 69 + } 70 + 71 + static void rcar_gen3_phy_usb3_enable_ssc(struct rcar_gen3_usb3 *r) 72 + { 73 + u16 val = SSC_SET_SSC_EN; 74 + 75 + switch (r->ssc_range) { 76 + case 4980: 77 + val |= SSC_SET_RANGE_4980; 78 + break; 79 + case 4492: 80 + val |= SSC_SET_RANGE_4492; 81 + break; 82 + case 4003: 83 + val |= SSC_SET_RANGE_4003; 84 + break; 85 + default: 86 + dev_err(&r->phy->dev, "%s: unsupported range (%x)\n", __func__, 87 + r->ssc_range); 88 + return; 89 + } 90 + 91 + writew(val, r->base + USB30_SSC_SET); 92 + } 93 + 94 + static void rcar_gen3_phy_usb3_select_usb_extal(struct rcar_gen3_usb3 *r) 95 + { 96 + write_clkset1_for_usb_extal(r, false); 97 + if (r->ssc_range) 98 + rcar_gen3_phy_usb3_enable_ssc(r); 99 + writew(CLKSET0_PRIVATE | CLKSET0_USB30_FSEL_USB_EXTAL, 100 + r->base + USB30_CLKSET0); 101 + writew(PHY_ENABLE_RESET_EN, r->base + USB30_PHY_ENABLE); 102 + write_clkset1_for_usb_extal(r, true); 103 + usleep_range(10, 20); 104 + write_clkset1_for_usb_extal(r, false); 105 + } 106 + 107 + static int rcar_gen3_phy_usb3_init(struct phy *p) 108 + { 109 + struct rcar_gen3_usb3 *r = phy_get_drvdata(p); 110 + 111 + dev_vdbg(&r->phy->dev, "%s: enter (%d, %d, %d)\n", __func__, 112 + r->usb3s_clk, r->usb_extal, r->ssc_range); 113 + 114 + if (!r->usb3s_clk && r->usb_extal) 115 + rcar_gen3_phy_usb3_select_usb_extal(r); 116 + 117 + /* Enables VBUS detection anyway */ 118 + writew(VBUS_EN_VBUS_EN, r->base + USB30_VBUS_EN); 119 + 120 + return 0; 121 + } 122 + 123 + static const struct phy_ops rcar_gen3_phy_usb3_ops = { 124 + .init = rcar_gen3_phy_usb3_init, 125 + .owner = THIS_MODULE, 126 + }; 127 + 128 + static const struct of_device_id rcar_gen3_phy_usb3_match_table[] = { 129 + { .compatible = "renesas,rcar-gen3-usb3-phy" }, 130 + { } 131 + }; 132 + MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb3_match_table); 133 + 134 + static int rcar_gen3_phy_usb3_probe(struct platform_device *pdev) 135 + { 136 + struct device *dev = &pdev->dev; 137 + struct rcar_gen3_usb3 *r; 138 + struct phy_provider *provider; 139 + struct resource *res; 140 + int ret = 0; 141 + struct clk *clk; 142 + 143 + if (!dev->of_node) { 144 + dev_err(dev, "This driver needs device tree\n"); 145 + return -EINVAL; 146 + } 147 + 148 + r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); 149 + if (!r) 150 + return -ENOMEM; 151 + 152 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 153 + r->base = devm_ioremap_resource(dev, res); 154 + if (IS_ERR(r->base)) 155 + return PTR_ERR(r->base); 156 + 157 + clk = devm_clk_get(dev, "usb3s_clk"); 158 + if (!IS_ERR(clk) && !clk_prepare_enable(clk)) { 159 + r->usb3s_clk = !!clk_get_rate(clk); 160 + clk_disable_unprepare(clk); 161 + } 162 + clk = devm_clk_get(dev, "usb_extal"); 163 + if (!IS_ERR(clk) && !clk_prepare_enable(clk)) { 164 + r->usb_extal = !!clk_get_rate(clk); 165 + clk_disable_unprepare(clk); 166 + } 167 + 168 + if (!r->usb3s_clk && !r->usb_extal) { 169 + dev_err(dev, "This driver needs usb3s_clk and/or usb_extal\n"); 170 + ret = -EINVAL; 171 + goto error; 172 + } 173 + 174 + /* 175 + * devm_phy_create() will call pm_runtime_enable(&phy->dev); 176 + * And then, phy-core will manage runtime pm for this device. 177 + */ 178 + pm_runtime_enable(dev); 179 + 180 + r->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb3_ops); 181 + if (IS_ERR(r->phy)) { 182 + dev_err(dev, "Failed to create USB3 PHY\n"); 183 + ret = PTR_ERR(r->phy); 184 + goto error; 185 + } 186 + 187 + of_property_read_u32(dev->of_node, "renesas,ssc-range", &r->ssc_range); 188 + 189 + platform_set_drvdata(pdev, r); 190 + phy_set_drvdata(r->phy, r); 191 + 192 + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 193 + if (IS_ERR(provider)) { 194 + dev_err(dev, "Failed to register PHY provider\n"); 195 + ret = PTR_ERR(provider); 196 + goto error; 197 + } 198 + 199 + return 0; 200 + 201 + error: 202 + pm_runtime_disable(dev); 203 + 204 + return ret; 205 + } 206 + 207 + static int rcar_gen3_phy_usb3_remove(struct platform_device *pdev) 208 + { 209 + pm_runtime_disable(&pdev->dev); 210 + 211 + return 0; 212 + }; 213 + 214 + static struct platform_driver rcar_gen3_phy_usb3_driver = { 215 + .driver = { 216 + .name = "phy_rcar_gen3_usb3", 217 + .of_match_table = rcar_gen3_phy_usb3_match_table, 218 + }, 219 + .probe = rcar_gen3_phy_usb3_probe, 220 + .remove = rcar_gen3_phy_usb3_remove, 221 + }; 222 + module_platform_driver(rcar_gen3_phy_usb3_driver); 223 + 224 + MODULE_LICENSE("GPL v2"); 225 + MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 3.0 PHY"); 226 + MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");