1*7c7356baSYoshihiro Shimoda /* 2*7c7356baSYoshihiro Shimoda * Renesas R-Car Gen3 for USB3.0 PHY driver 3*7c7356baSYoshihiro Shimoda * 4*7c7356baSYoshihiro Shimoda * Copyright (C) 2017 Renesas Electronics Corporation 5*7c7356baSYoshihiro Shimoda * 6*7c7356baSYoshihiro Shimoda * This program is free software; you can redistribute it and/or modify 7*7c7356baSYoshihiro Shimoda * it under the terms of the GNU General Public License version 2 as 8*7c7356baSYoshihiro Shimoda * published by the Free Software Foundation. 9*7c7356baSYoshihiro Shimoda */ 10*7c7356baSYoshihiro Shimoda 11*7c7356baSYoshihiro Shimoda #include <linux/clk.h> 12*7c7356baSYoshihiro Shimoda #include <linux/delay.h> 13*7c7356baSYoshihiro Shimoda #include <linux/io.h> 14*7c7356baSYoshihiro Shimoda #include <linux/module.h> 15*7c7356baSYoshihiro Shimoda #include <linux/of.h> 16*7c7356baSYoshihiro Shimoda #include <linux/phy/phy.h> 17*7c7356baSYoshihiro Shimoda #include <linux/platform_device.h> 18*7c7356baSYoshihiro Shimoda #include <linux/pm_runtime.h> 19*7c7356baSYoshihiro Shimoda 20*7c7356baSYoshihiro Shimoda #define USB30_CLKSET0 0x034 21*7c7356baSYoshihiro Shimoda #define USB30_CLKSET1 0x036 22*7c7356baSYoshihiro Shimoda #define USB30_SSC_SET 0x038 23*7c7356baSYoshihiro Shimoda #define USB30_PHY_ENABLE 0x060 24*7c7356baSYoshihiro Shimoda #define USB30_VBUS_EN 0x064 25*7c7356baSYoshihiro Shimoda 26*7c7356baSYoshihiro Shimoda /* USB30_CLKSET0 */ 27*7c7356baSYoshihiro Shimoda #define CLKSET0_PRIVATE 0x05c0 28*7c7356baSYoshihiro Shimoda #define CLKSET0_USB30_FSEL_USB_EXTAL 0x0002 29*7c7356baSYoshihiro Shimoda 30*7c7356baSYoshihiro Shimoda /* USB30_CLKSET1 */ 31*7c7356baSYoshihiro Shimoda #define CLKSET1_USB30_PLL_MULTI_SHIFT 6 32*7c7356baSYoshihiro Shimoda #define CLKSET1_USB30_PLL_MULTI_USB_EXTAL (0x64 << \ 33*7c7356baSYoshihiro Shimoda CLKSET1_USB30_PLL_MULTI_SHIFT) 34*7c7356baSYoshihiro Shimoda #define CLKSET1_PHYRESET BIT(4) /* 1: reset */ 35*7c7356baSYoshihiro Shimoda #define CLKSET1_REF_CLKDIV BIT(3) /* 1: USB_EXTAL */ 36*7c7356baSYoshihiro Shimoda #define CLKSET1_PRIVATE_2_1 BIT(1) /* Write B'01 */ 37*7c7356baSYoshihiro Shimoda #define CLKSET1_REF_CLK_SEL BIT(0) /* 1: USB3S0_CLK_P */ 38*7c7356baSYoshihiro Shimoda 39*7c7356baSYoshihiro Shimoda /* USB30_SSC_SET */ 40*7c7356baSYoshihiro Shimoda #define SSC_SET_SSC_EN BIT(12) 41*7c7356baSYoshihiro Shimoda #define SSC_SET_RANGE_SHIFT 9 42*7c7356baSYoshihiro Shimoda #define SSC_SET_RANGE_4980 (0x0 << SSC_SET_RANGE_SHIFT) 43*7c7356baSYoshihiro Shimoda #define SSC_SET_RANGE_4492 (0x1 << SSC_SET_RANGE_SHIFT) 44*7c7356baSYoshihiro Shimoda #define SSC_SET_RANGE_4003 (0x2 << SSC_SET_RANGE_SHIFT) 45*7c7356baSYoshihiro Shimoda 46*7c7356baSYoshihiro Shimoda /* USB30_PHY_ENABLE */ 47*7c7356baSYoshihiro Shimoda #define PHY_ENABLE_RESET_EN BIT(4) 48*7c7356baSYoshihiro Shimoda 49*7c7356baSYoshihiro Shimoda /* USB30_VBUS_EN */ 50*7c7356baSYoshihiro Shimoda #define VBUS_EN_VBUS_EN BIT(1) 51*7c7356baSYoshihiro Shimoda 52*7c7356baSYoshihiro Shimoda struct rcar_gen3_usb3 { 53*7c7356baSYoshihiro Shimoda void __iomem *base; 54*7c7356baSYoshihiro Shimoda struct phy *phy; 55*7c7356baSYoshihiro Shimoda u32 ssc_range; 56*7c7356baSYoshihiro Shimoda bool usb3s_clk; 57*7c7356baSYoshihiro Shimoda bool usb_extal; 58*7c7356baSYoshihiro Shimoda }; 59*7c7356baSYoshihiro Shimoda 60*7c7356baSYoshihiro Shimoda static void write_clkset1_for_usb_extal(struct rcar_gen3_usb3 *r, bool reset) 61*7c7356baSYoshihiro Shimoda { 62*7c7356baSYoshihiro Shimoda u16 val = CLKSET1_USB30_PLL_MULTI_USB_EXTAL | 63*7c7356baSYoshihiro Shimoda CLKSET1_REF_CLKDIV | CLKSET1_PRIVATE_2_1; 64*7c7356baSYoshihiro Shimoda 65*7c7356baSYoshihiro Shimoda if (reset) 66*7c7356baSYoshihiro Shimoda val |= CLKSET1_PHYRESET; 67*7c7356baSYoshihiro Shimoda 68*7c7356baSYoshihiro Shimoda writew(val, r->base + USB30_CLKSET1); 69*7c7356baSYoshihiro Shimoda } 70*7c7356baSYoshihiro Shimoda 71*7c7356baSYoshihiro Shimoda static void rcar_gen3_phy_usb3_enable_ssc(struct rcar_gen3_usb3 *r) 72*7c7356baSYoshihiro Shimoda { 73*7c7356baSYoshihiro Shimoda u16 val = SSC_SET_SSC_EN; 74*7c7356baSYoshihiro Shimoda 75*7c7356baSYoshihiro Shimoda switch (r->ssc_range) { 76*7c7356baSYoshihiro Shimoda case 4980: 77*7c7356baSYoshihiro Shimoda val |= SSC_SET_RANGE_4980; 78*7c7356baSYoshihiro Shimoda break; 79*7c7356baSYoshihiro Shimoda case 4492: 80*7c7356baSYoshihiro Shimoda val |= SSC_SET_RANGE_4492; 81*7c7356baSYoshihiro Shimoda break; 82*7c7356baSYoshihiro Shimoda case 4003: 83*7c7356baSYoshihiro Shimoda val |= SSC_SET_RANGE_4003; 84*7c7356baSYoshihiro Shimoda break; 85*7c7356baSYoshihiro Shimoda default: 86*7c7356baSYoshihiro Shimoda dev_err(&r->phy->dev, "%s: unsupported range (%x)\n", __func__, 87*7c7356baSYoshihiro Shimoda r->ssc_range); 88*7c7356baSYoshihiro Shimoda return; 89*7c7356baSYoshihiro Shimoda } 90*7c7356baSYoshihiro Shimoda 91*7c7356baSYoshihiro Shimoda writew(val, r->base + USB30_SSC_SET); 92*7c7356baSYoshihiro Shimoda } 93*7c7356baSYoshihiro Shimoda 94*7c7356baSYoshihiro Shimoda static void rcar_gen3_phy_usb3_select_usb_extal(struct rcar_gen3_usb3 *r) 95*7c7356baSYoshihiro Shimoda { 96*7c7356baSYoshihiro Shimoda write_clkset1_for_usb_extal(r, false); 97*7c7356baSYoshihiro Shimoda if (r->ssc_range) 98*7c7356baSYoshihiro Shimoda rcar_gen3_phy_usb3_enable_ssc(r); 99*7c7356baSYoshihiro Shimoda writew(CLKSET0_PRIVATE | CLKSET0_USB30_FSEL_USB_EXTAL, 100*7c7356baSYoshihiro Shimoda r->base + USB30_CLKSET0); 101*7c7356baSYoshihiro Shimoda writew(PHY_ENABLE_RESET_EN, r->base + USB30_PHY_ENABLE); 102*7c7356baSYoshihiro Shimoda write_clkset1_for_usb_extal(r, true); 103*7c7356baSYoshihiro Shimoda usleep_range(10, 20); 104*7c7356baSYoshihiro Shimoda write_clkset1_for_usb_extal(r, false); 105*7c7356baSYoshihiro Shimoda } 106*7c7356baSYoshihiro Shimoda 107*7c7356baSYoshihiro Shimoda static int rcar_gen3_phy_usb3_init(struct phy *p) 108*7c7356baSYoshihiro Shimoda { 109*7c7356baSYoshihiro Shimoda struct rcar_gen3_usb3 *r = phy_get_drvdata(p); 110*7c7356baSYoshihiro Shimoda 111*7c7356baSYoshihiro Shimoda dev_vdbg(&r->phy->dev, "%s: enter (%d, %d, %d)\n", __func__, 112*7c7356baSYoshihiro Shimoda r->usb3s_clk, r->usb_extal, r->ssc_range); 113*7c7356baSYoshihiro Shimoda 114*7c7356baSYoshihiro Shimoda if (!r->usb3s_clk && r->usb_extal) 115*7c7356baSYoshihiro Shimoda rcar_gen3_phy_usb3_select_usb_extal(r); 116*7c7356baSYoshihiro Shimoda 117*7c7356baSYoshihiro Shimoda /* Enables VBUS detection anyway */ 118*7c7356baSYoshihiro Shimoda writew(VBUS_EN_VBUS_EN, r->base + USB30_VBUS_EN); 119*7c7356baSYoshihiro Shimoda 120*7c7356baSYoshihiro Shimoda return 0; 121*7c7356baSYoshihiro Shimoda } 122*7c7356baSYoshihiro Shimoda 123*7c7356baSYoshihiro Shimoda static const struct phy_ops rcar_gen3_phy_usb3_ops = { 124*7c7356baSYoshihiro Shimoda .init = rcar_gen3_phy_usb3_init, 125*7c7356baSYoshihiro Shimoda .owner = THIS_MODULE, 126*7c7356baSYoshihiro Shimoda }; 127*7c7356baSYoshihiro Shimoda 128*7c7356baSYoshihiro Shimoda static const struct of_device_id rcar_gen3_phy_usb3_match_table[] = { 129*7c7356baSYoshihiro Shimoda { .compatible = "renesas,rcar-gen3-usb3-phy" }, 130*7c7356baSYoshihiro Shimoda { } 131*7c7356baSYoshihiro Shimoda }; 132*7c7356baSYoshihiro Shimoda MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb3_match_table); 133*7c7356baSYoshihiro Shimoda 134*7c7356baSYoshihiro Shimoda static int rcar_gen3_phy_usb3_probe(struct platform_device *pdev) 135*7c7356baSYoshihiro Shimoda { 136*7c7356baSYoshihiro Shimoda struct device *dev = &pdev->dev; 137*7c7356baSYoshihiro Shimoda struct rcar_gen3_usb3 *r; 138*7c7356baSYoshihiro Shimoda struct phy_provider *provider; 139*7c7356baSYoshihiro Shimoda struct resource *res; 140*7c7356baSYoshihiro Shimoda int ret = 0; 141*7c7356baSYoshihiro Shimoda struct clk *clk; 142*7c7356baSYoshihiro Shimoda 143*7c7356baSYoshihiro Shimoda if (!dev->of_node) { 144*7c7356baSYoshihiro Shimoda dev_err(dev, "This driver needs device tree\n"); 145*7c7356baSYoshihiro Shimoda return -EINVAL; 146*7c7356baSYoshihiro Shimoda } 147*7c7356baSYoshihiro Shimoda 148*7c7356baSYoshihiro Shimoda r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); 149*7c7356baSYoshihiro Shimoda if (!r) 150*7c7356baSYoshihiro Shimoda return -ENOMEM; 151*7c7356baSYoshihiro Shimoda 152*7c7356baSYoshihiro Shimoda res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 153*7c7356baSYoshihiro Shimoda r->base = devm_ioremap_resource(dev, res); 154*7c7356baSYoshihiro Shimoda if (IS_ERR(r->base)) 155*7c7356baSYoshihiro Shimoda return PTR_ERR(r->base); 156*7c7356baSYoshihiro Shimoda 157*7c7356baSYoshihiro Shimoda clk = devm_clk_get(dev, "usb3s_clk"); 158*7c7356baSYoshihiro Shimoda if (!IS_ERR(clk) && !clk_prepare_enable(clk)) { 159*7c7356baSYoshihiro Shimoda r->usb3s_clk = !!clk_get_rate(clk); 160*7c7356baSYoshihiro Shimoda clk_disable_unprepare(clk); 161*7c7356baSYoshihiro Shimoda } 162*7c7356baSYoshihiro Shimoda clk = devm_clk_get(dev, "usb_extal"); 163*7c7356baSYoshihiro Shimoda if (!IS_ERR(clk) && !clk_prepare_enable(clk)) { 164*7c7356baSYoshihiro Shimoda r->usb_extal = !!clk_get_rate(clk); 165*7c7356baSYoshihiro Shimoda clk_disable_unprepare(clk); 166*7c7356baSYoshihiro Shimoda } 167*7c7356baSYoshihiro Shimoda 168*7c7356baSYoshihiro Shimoda if (!r->usb3s_clk && !r->usb_extal) { 169*7c7356baSYoshihiro Shimoda dev_err(dev, "This driver needs usb3s_clk and/or usb_extal\n"); 170*7c7356baSYoshihiro Shimoda ret = -EINVAL; 171*7c7356baSYoshihiro Shimoda goto error; 172*7c7356baSYoshihiro Shimoda } 173*7c7356baSYoshihiro Shimoda 174*7c7356baSYoshihiro Shimoda /* 175*7c7356baSYoshihiro Shimoda * devm_phy_create() will call pm_runtime_enable(&phy->dev); 176*7c7356baSYoshihiro Shimoda * And then, phy-core will manage runtime pm for this device. 177*7c7356baSYoshihiro Shimoda */ 178*7c7356baSYoshihiro Shimoda pm_runtime_enable(dev); 179*7c7356baSYoshihiro Shimoda 180*7c7356baSYoshihiro Shimoda r->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb3_ops); 181*7c7356baSYoshihiro Shimoda if (IS_ERR(r->phy)) { 182*7c7356baSYoshihiro Shimoda dev_err(dev, "Failed to create USB3 PHY\n"); 183*7c7356baSYoshihiro Shimoda ret = PTR_ERR(r->phy); 184*7c7356baSYoshihiro Shimoda goto error; 185*7c7356baSYoshihiro Shimoda } 186*7c7356baSYoshihiro Shimoda 187*7c7356baSYoshihiro Shimoda of_property_read_u32(dev->of_node, "renesas,ssc-range", &r->ssc_range); 188*7c7356baSYoshihiro Shimoda 189*7c7356baSYoshihiro Shimoda platform_set_drvdata(pdev, r); 190*7c7356baSYoshihiro Shimoda phy_set_drvdata(r->phy, r); 191*7c7356baSYoshihiro Shimoda 192*7c7356baSYoshihiro Shimoda provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 193*7c7356baSYoshihiro Shimoda if (IS_ERR(provider)) { 194*7c7356baSYoshihiro Shimoda dev_err(dev, "Failed to register PHY provider\n"); 195*7c7356baSYoshihiro Shimoda ret = PTR_ERR(provider); 196*7c7356baSYoshihiro Shimoda goto error; 197*7c7356baSYoshihiro Shimoda } 198*7c7356baSYoshihiro Shimoda 199*7c7356baSYoshihiro Shimoda return 0; 200*7c7356baSYoshihiro Shimoda 201*7c7356baSYoshihiro Shimoda error: 202*7c7356baSYoshihiro Shimoda pm_runtime_disable(dev); 203*7c7356baSYoshihiro Shimoda 204*7c7356baSYoshihiro Shimoda return ret; 205*7c7356baSYoshihiro Shimoda } 206*7c7356baSYoshihiro Shimoda 207*7c7356baSYoshihiro Shimoda static int rcar_gen3_phy_usb3_remove(struct platform_device *pdev) 208*7c7356baSYoshihiro Shimoda { 209*7c7356baSYoshihiro Shimoda pm_runtime_disable(&pdev->dev); 210*7c7356baSYoshihiro Shimoda 211*7c7356baSYoshihiro Shimoda return 0; 212*7c7356baSYoshihiro Shimoda }; 213*7c7356baSYoshihiro Shimoda 214*7c7356baSYoshihiro Shimoda static struct platform_driver rcar_gen3_phy_usb3_driver = { 215*7c7356baSYoshihiro Shimoda .driver = { 216*7c7356baSYoshihiro Shimoda .name = "phy_rcar_gen3_usb3", 217*7c7356baSYoshihiro Shimoda .of_match_table = rcar_gen3_phy_usb3_match_table, 218*7c7356baSYoshihiro Shimoda }, 219*7c7356baSYoshihiro Shimoda .probe = rcar_gen3_phy_usb3_probe, 220*7c7356baSYoshihiro Shimoda .remove = rcar_gen3_phy_usb3_remove, 221*7c7356baSYoshihiro Shimoda }; 222*7c7356baSYoshihiro Shimoda module_platform_driver(rcar_gen3_phy_usb3_driver); 223*7c7356baSYoshihiro Shimoda 224*7c7356baSYoshihiro Shimoda MODULE_LICENSE("GPL v2"); 225*7c7356baSYoshihiro Shimoda MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 3.0 PHY"); 226*7c7356baSYoshihiro Shimoda MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>"); 227