Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Rockchip usb PHY driver
0004  *
0005  * Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com>
0006  * Copyright (C) 2014 ROCKCHIP, Inc.
0007  */
0008 
0009 #include <linux/clk.h>
0010 #include <linux/clk-provider.h>
0011 #include <linux/io.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/mutex.h>
0015 #include <linux/of.h>
0016 #include <linux/of_address.h>
0017 #include <linux/of_platform.h>
0018 #include <linux/phy/phy.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regulator/consumer.h>
0021 #include <linux/reset.h>
0022 #include <linux/regmap.h>
0023 #include <linux/mfd/syscon.h>
0024 #include <linux/delay.h>
0025 
0026 static int enable_usb_uart;
0027 
0028 #define HIWORD_UPDATE(val, mask) \
0029         ((val) | (mask) << 16)
0030 
0031 #define UOC_CON0                    0x00
0032 #define UOC_CON0_SIDDQ                  BIT(13)
0033 #define UOC_CON0_DISABLE                BIT(4)
0034 #define UOC_CON0_COMMON_ON_N                BIT(0)
0035 
0036 #define UOC_CON2                    0x08
0037 #define UOC_CON2_SOFT_CON_SEL               BIT(2)
0038 
0039 #define UOC_CON3                    0x0c
0040 /* bits present on rk3188 and rk3288 phys */
0041 #define UOC_CON3_UTMI_TERMSEL_FULLSPEED         BIT(5)
0042 #define UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC       (1 << 3)
0043 #define UOC_CON3_UTMI_XCVRSEELCT_MASK           (3 << 3)
0044 #define UOC_CON3_UTMI_OPMODE_NODRIVING          (1 << 1)
0045 #define UOC_CON3_UTMI_OPMODE_MASK           (3 << 1)
0046 #define UOC_CON3_UTMI_SUSPENDN              BIT(0)
0047 
0048 struct rockchip_usb_phys {
0049     int reg;
0050     const char *pll_name;
0051 };
0052 
0053 struct rockchip_usb_phy_base;
0054 struct rockchip_usb_phy_pdata {
0055     struct rockchip_usb_phys *phys;
0056     int (*init_usb_uart)(struct regmap *grf,
0057                  const struct rockchip_usb_phy_pdata *pdata);
0058     int usb_uart_phy;
0059 };
0060 
0061 struct rockchip_usb_phy_base {
0062     struct device *dev;
0063     struct regmap *reg_base;
0064     const struct rockchip_usb_phy_pdata *pdata;
0065 };
0066 
0067 struct rockchip_usb_phy {
0068     struct rockchip_usb_phy_base *base;
0069     struct device_node *np;
0070     unsigned int    reg_offset;
0071     struct clk  *clk;
0072     struct clk      *clk480m;
0073     struct clk_hw   clk480m_hw;
0074     struct phy  *phy;
0075     bool        uart_enabled;
0076     struct reset_control *reset;
0077     struct regulator *vbus;
0078 };
0079 
0080 static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
0081                        bool siddq)
0082 {
0083     u32 val = HIWORD_UPDATE(siddq ? UOC_CON0_SIDDQ : 0, UOC_CON0_SIDDQ);
0084 
0085     return regmap_write(phy->base->reg_base, phy->reg_offset, val);
0086 }
0087 
0088 static unsigned long rockchip_usb_phy480m_recalc_rate(struct clk_hw *hw,
0089                         unsigned long parent_rate)
0090 {
0091     return 480000000;
0092 }
0093 
0094 static void rockchip_usb_phy480m_disable(struct clk_hw *hw)
0095 {
0096     struct rockchip_usb_phy *phy = container_of(hw,
0097                             struct rockchip_usb_phy,
0098                             clk480m_hw);
0099 
0100     if (phy->vbus)
0101         regulator_disable(phy->vbus);
0102 
0103     /* Power down usb phy analog blocks by set siddq 1 */
0104     rockchip_usb_phy_power(phy, 1);
0105 }
0106 
0107 static int rockchip_usb_phy480m_enable(struct clk_hw *hw)
0108 {
0109     struct rockchip_usb_phy *phy = container_of(hw,
0110                             struct rockchip_usb_phy,
0111                             clk480m_hw);
0112 
0113     /* Power up usb phy analog blocks by set siddq 0 */
0114     return rockchip_usb_phy_power(phy, 0);
0115 }
0116 
0117 static int rockchip_usb_phy480m_is_enabled(struct clk_hw *hw)
0118 {
0119     struct rockchip_usb_phy *phy = container_of(hw,
0120                             struct rockchip_usb_phy,
0121                             clk480m_hw);
0122     int ret;
0123     u32 val;
0124 
0125     ret = regmap_read(phy->base->reg_base, phy->reg_offset, &val);
0126     if (ret < 0)
0127         return ret;
0128 
0129     return (val & UOC_CON0_SIDDQ) ? 0 : 1;
0130 }
0131 
0132 static const struct clk_ops rockchip_usb_phy480m_ops = {
0133     .enable = rockchip_usb_phy480m_enable,
0134     .disable = rockchip_usb_phy480m_disable,
0135     .is_enabled = rockchip_usb_phy480m_is_enabled,
0136     .recalc_rate = rockchip_usb_phy480m_recalc_rate,
0137 };
0138 
0139 static int rockchip_usb_phy_power_off(struct phy *_phy)
0140 {
0141     struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
0142 
0143     if (phy->uart_enabled)
0144         return -EBUSY;
0145 
0146     clk_disable_unprepare(phy->clk480m);
0147 
0148     return 0;
0149 }
0150 
0151 static int rockchip_usb_phy_power_on(struct phy *_phy)
0152 {
0153     struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
0154 
0155     if (phy->uart_enabled)
0156         return -EBUSY;
0157 
0158     if (phy->vbus) {
0159         int ret;
0160 
0161         ret = regulator_enable(phy->vbus);
0162         if (ret)
0163             return ret;
0164     }
0165 
0166     return clk_prepare_enable(phy->clk480m);
0167 }
0168 
0169 static int rockchip_usb_phy_reset(struct phy *_phy)
0170 {
0171     struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
0172 
0173     if (phy->reset) {
0174         reset_control_assert(phy->reset);
0175         udelay(10);
0176         reset_control_deassert(phy->reset);
0177     }
0178 
0179     return 0;
0180 }
0181 
0182 static const struct phy_ops ops = {
0183     .power_on   = rockchip_usb_phy_power_on,
0184     .power_off  = rockchip_usb_phy_power_off,
0185     .reset      = rockchip_usb_phy_reset,
0186     .owner      = THIS_MODULE,
0187 };
0188 
0189 static void rockchip_usb_phy_action(void *data)
0190 {
0191     struct rockchip_usb_phy *rk_phy = data;
0192 
0193     if (!rk_phy->uart_enabled) {
0194         of_clk_del_provider(rk_phy->np);
0195         clk_unregister(rk_phy->clk480m);
0196     }
0197 
0198     if (rk_phy->clk)
0199         clk_put(rk_phy->clk);
0200 }
0201 
0202 static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
0203                  struct device_node *child)
0204 {
0205     struct rockchip_usb_phy *rk_phy;
0206     unsigned int reg_offset;
0207     const char *clk_name;
0208     struct clk_init_data init;
0209     int err, i;
0210 
0211     rk_phy = devm_kzalloc(base->dev, sizeof(*rk_phy), GFP_KERNEL);
0212     if (!rk_phy)
0213         return -ENOMEM;
0214 
0215     rk_phy->base = base;
0216     rk_phy->np = child;
0217 
0218     if (of_property_read_u32(child, "reg", &reg_offset)) {
0219         dev_err(base->dev, "missing reg property in node %pOFn\n",
0220             child);
0221         return -EINVAL;
0222     }
0223 
0224     rk_phy->reset = of_reset_control_get(child, "phy-reset");
0225     if (IS_ERR(rk_phy->reset))
0226         rk_phy->reset = NULL;
0227 
0228     rk_phy->reg_offset = reg_offset;
0229 
0230     rk_phy->clk = of_clk_get_by_name(child, "phyclk");
0231     if (IS_ERR(rk_phy->clk))
0232         rk_phy->clk = NULL;
0233 
0234     i = 0;
0235     init.name = NULL;
0236     while (base->pdata->phys[i].reg) {
0237         if (base->pdata->phys[i].reg == reg_offset) {
0238             init.name = base->pdata->phys[i].pll_name;
0239             break;
0240         }
0241         i++;
0242     }
0243 
0244     if (!init.name) {
0245         dev_err(base->dev, "phy data not found\n");
0246         return -EINVAL;
0247     }
0248 
0249     if (enable_usb_uart && base->pdata->usb_uart_phy == i) {
0250         dev_dbg(base->dev, "phy%d used as uart output\n", i);
0251         rk_phy->uart_enabled = true;
0252     } else {
0253         if (rk_phy->clk) {
0254             clk_name = __clk_get_name(rk_phy->clk);
0255             init.flags = 0;
0256             init.parent_names = &clk_name;
0257             init.num_parents = 1;
0258         } else {
0259             init.flags = 0;
0260             init.parent_names = NULL;
0261             init.num_parents = 0;
0262         }
0263 
0264         init.ops = &rockchip_usb_phy480m_ops;
0265         rk_phy->clk480m_hw.init = &init;
0266 
0267         rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw);
0268         if (IS_ERR(rk_phy->clk480m)) {
0269             err = PTR_ERR(rk_phy->clk480m);
0270             goto err_clk;
0271         }
0272 
0273         err = of_clk_add_provider(child, of_clk_src_simple_get,
0274                     rk_phy->clk480m);
0275         if (err < 0)
0276             goto err_clk_prov;
0277     }
0278 
0279     err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action,
0280                        rk_phy);
0281     if (err)
0282         return err;
0283 
0284     rk_phy->phy = devm_phy_create(base->dev, child, &ops);
0285     if (IS_ERR(rk_phy->phy)) {
0286         dev_err(base->dev, "failed to create PHY\n");
0287         return PTR_ERR(rk_phy->phy);
0288     }
0289     phy_set_drvdata(rk_phy->phy, rk_phy);
0290 
0291     rk_phy->vbus = devm_regulator_get_optional(&rk_phy->phy->dev, "vbus");
0292     if (IS_ERR(rk_phy->vbus)) {
0293         if (PTR_ERR(rk_phy->vbus) == -EPROBE_DEFER)
0294             return PTR_ERR(rk_phy->vbus);
0295         rk_phy->vbus = NULL;
0296     }
0297 
0298     /*
0299      * When acting as uart-pipe, just keep clock on otherwise
0300      * only power up usb phy when it use, so disable it when init
0301      */
0302     if (rk_phy->uart_enabled)
0303         return clk_prepare_enable(rk_phy->clk);
0304     else
0305         return rockchip_usb_phy_power(rk_phy, 1);
0306 
0307 err_clk_prov:
0308     if (!rk_phy->uart_enabled)
0309         clk_unregister(rk_phy->clk480m);
0310 err_clk:
0311     if (rk_phy->clk)
0312         clk_put(rk_phy->clk);
0313     return err;
0314 }
0315 
0316 static const struct rockchip_usb_phy_pdata rk3066a_pdata = {
0317     .phys = (struct rockchip_usb_phys[]){
0318         { .reg = 0x17c, .pll_name = "sclk_otgphy0_480m" },
0319         { .reg = 0x188, .pll_name = "sclk_otgphy1_480m" },
0320         { /* sentinel */ }
0321     },
0322 };
0323 
0324 static int __init rockchip_init_usb_uart_common(struct regmap *grf,
0325                 const struct rockchip_usb_phy_pdata *pdata)
0326 {
0327     int regoffs = pdata->phys[pdata->usb_uart_phy].reg;
0328     int ret;
0329     u32 val;
0330 
0331     /*
0332      * COMMON_ON and DISABLE settings are described in the TRM,
0333      * but were not present in the original code.
0334      * Also disable the analog phy components to save power.
0335      */
0336     val = HIWORD_UPDATE(UOC_CON0_COMMON_ON_N
0337                 | UOC_CON0_DISABLE
0338                 | UOC_CON0_SIDDQ,
0339                 UOC_CON0_COMMON_ON_N
0340                 | UOC_CON0_DISABLE
0341                 | UOC_CON0_SIDDQ);
0342     ret = regmap_write(grf, regoffs + UOC_CON0, val);
0343     if (ret)
0344         return ret;
0345 
0346     val = HIWORD_UPDATE(UOC_CON2_SOFT_CON_SEL,
0347                 UOC_CON2_SOFT_CON_SEL);
0348     ret = regmap_write(grf, regoffs + UOC_CON2, val);
0349     if (ret)
0350         return ret;
0351 
0352     val = HIWORD_UPDATE(UOC_CON3_UTMI_OPMODE_NODRIVING
0353                 | UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC
0354                 | UOC_CON3_UTMI_TERMSEL_FULLSPEED,
0355                 UOC_CON3_UTMI_SUSPENDN
0356                 | UOC_CON3_UTMI_OPMODE_MASK
0357                 | UOC_CON3_UTMI_XCVRSEELCT_MASK
0358                 | UOC_CON3_UTMI_TERMSEL_FULLSPEED);
0359     ret = regmap_write(grf, UOC_CON3, val);
0360     if (ret)
0361         return ret;
0362 
0363     return 0;
0364 }
0365 
0366 #define RK3188_UOC0_CON0                0x10c
0367 #define RK3188_UOC0_CON0_BYPASSSEL          BIT(9)
0368 #define RK3188_UOC0_CON0_BYPASSDMEN         BIT(8)
0369 
0370 /*
0371  * Enable the bypass of uart2 data through the otg usb phy.
0372  * See description of rk3288-variant for details.
0373  */
0374 static int __init rk3188_init_usb_uart(struct regmap *grf,
0375                 const struct rockchip_usb_phy_pdata *pdata)
0376 {
0377     u32 val;
0378     int ret;
0379 
0380     ret = rockchip_init_usb_uart_common(grf, pdata);
0381     if (ret)
0382         return ret;
0383 
0384     val = HIWORD_UPDATE(RK3188_UOC0_CON0_BYPASSSEL
0385                 | RK3188_UOC0_CON0_BYPASSDMEN,
0386                 RK3188_UOC0_CON0_BYPASSSEL
0387                 | RK3188_UOC0_CON0_BYPASSDMEN);
0388     ret = regmap_write(grf, RK3188_UOC0_CON0, val);
0389     if (ret)
0390         return ret;
0391 
0392     return 0;
0393 }
0394 
0395 static const struct rockchip_usb_phy_pdata rk3188_pdata = {
0396     .phys = (struct rockchip_usb_phys[]){
0397         { .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" },
0398         { .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" },
0399         { /* sentinel */ }
0400     },
0401     .init_usb_uart = rk3188_init_usb_uart,
0402     .usb_uart_phy = 0,
0403 };
0404 
0405 #define RK3288_UOC0_CON3                0x32c
0406 #define RK3288_UOC0_CON3_BYPASSDMEN         BIT(6)
0407 #define RK3288_UOC0_CON3_BYPASSSEL          BIT(7)
0408 
0409 /*
0410  * Enable the bypass of uart2 data through the otg usb phy.
0411  * Original description in the TRM.
0412  * 1. Disable the OTG block by setting OTGDISABLE0 to 1’b1.
0413  * 2. Disable the pull-up resistance on the D+ line by setting
0414  *    OPMODE0[1:0] to 2’b01.
0415  * 3. To ensure that the XO, Bias, and PLL blocks are powered down in Suspend
0416  *    mode, set COMMONONN to 1’b1.
0417  * 4. Place the USB PHY in Suspend mode by setting SUSPENDM0 to 1’b0.
0418  * 5. Set BYPASSSEL0 to 1’b1.
0419  * 6. To transmit data, controls BYPASSDMEN0, and BYPASSDMDATA0.
0420  * To receive data, monitor FSVPLUS0.
0421  *
0422  * The actual code in the vendor kernel does some things differently.
0423  */
0424 static int __init rk3288_init_usb_uart(struct regmap *grf,
0425                 const struct rockchip_usb_phy_pdata *pdata)
0426 {
0427     u32 val;
0428     int ret;
0429 
0430     ret = rockchip_init_usb_uart_common(grf, pdata);
0431     if (ret)
0432         return ret;
0433 
0434     val = HIWORD_UPDATE(RK3288_UOC0_CON3_BYPASSSEL
0435                 | RK3288_UOC0_CON3_BYPASSDMEN,
0436                 RK3288_UOC0_CON3_BYPASSSEL
0437                 | RK3288_UOC0_CON3_BYPASSDMEN);
0438     ret = regmap_write(grf, RK3288_UOC0_CON3, val);
0439     if (ret)
0440         return ret;
0441 
0442     return 0;
0443 }
0444 
0445 static const struct rockchip_usb_phy_pdata rk3288_pdata = {
0446     .phys = (struct rockchip_usb_phys[]){
0447         { .reg = 0x320, .pll_name = "sclk_otgphy0_480m" },
0448         { .reg = 0x334, .pll_name = "sclk_otgphy1_480m" },
0449         { .reg = 0x348, .pll_name = "sclk_otgphy2_480m" },
0450         { /* sentinel */ }
0451     },
0452     .init_usb_uart = rk3288_init_usb_uart,
0453     .usb_uart_phy = 0,
0454 };
0455 
0456 static int rockchip_usb_phy_probe(struct platform_device *pdev)
0457 {
0458     struct device *dev = &pdev->dev;
0459     struct rockchip_usb_phy_base *phy_base;
0460     struct phy_provider *phy_provider;
0461     const struct of_device_id *match;
0462     struct device_node *child;
0463     int err;
0464 
0465     phy_base = devm_kzalloc(dev, sizeof(*phy_base), GFP_KERNEL);
0466     if (!phy_base)
0467         return -ENOMEM;
0468 
0469     match = of_match_device(dev->driver->of_match_table, dev);
0470     if (!match || !match->data) {
0471         dev_err(dev, "missing phy data\n");
0472         return -EINVAL;
0473     }
0474 
0475     phy_base->pdata = match->data;
0476 
0477     phy_base->dev = dev;
0478     phy_base->reg_base = ERR_PTR(-ENODEV);
0479     if (dev->parent && dev->parent->of_node)
0480         phy_base->reg_base = syscon_node_to_regmap(
0481                         dev->parent->of_node);
0482     if (IS_ERR(phy_base->reg_base))
0483         phy_base->reg_base = syscon_regmap_lookup_by_phandle(
0484                         dev->of_node, "rockchip,grf");
0485     if (IS_ERR(phy_base->reg_base)) {
0486         dev_err(&pdev->dev, "Missing rockchip,grf property\n");
0487         return PTR_ERR(phy_base->reg_base);
0488     }
0489 
0490     for_each_available_child_of_node(dev->of_node, child) {
0491         err = rockchip_usb_phy_init(phy_base, child);
0492         if (err) {
0493             of_node_put(child);
0494             return err;
0495         }
0496     }
0497 
0498     phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
0499     return PTR_ERR_OR_ZERO(phy_provider);
0500 }
0501 
0502 static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
0503     { .compatible = "rockchip,rk3066a-usb-phy", .data = &rk3066a_pdata },
0504     { .compatible = "rockchip,rk3188-usb-phy", .data = &rk3188_pdata },
0505     { .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata },
0506     {}
0507 };
0508 
0509 MODULE_DEVICE_TABLE(of, rockchip_usb_phy_dt_ids);
0510 
0511 static struct platform_driver rockchip_usb_driver = {
0512     .probe      = rockchip_usb_phy_probe,
0513     .driver     = {
0514         .name   = "rockchip-usb-phy",
0515         .of_match_table = rockchip_usb_phy_dt_ids,
0516     },
0517 };
0518 
0519 module_platform_driver(rockchip_usb_driver);
0520 
0521 #ifndef MODULE
0522 static int __init rockchip_init_usb_uart(void)
0523 {
0524     const struct of_device_id *match;
0525     const struct rockchip_usb_phy_pdata *data;
0526     struct device_node *np;
0527     struct regmap *grf;
0528     int ret;
0529 
0530     if (!enable_usb_uart)
0531         return 0;
0532 
0533     np = of_find_matching_node_and_match(NULL, rockchip_usb_phy_dt_ids,
0534                          &match);
0535     if (!np) {
0536         pr_err("%s: failed to find usbphy node\n", __func__);
0537         return -ENOTSUPP;
0538     }
0539 
0540     pr_debug("%s: using settings for %s\n", __func__, match->compatible);
0541     data = match->data;
0542 
0543     if (!data->init_usb_uart) {
0544         pr_err("%s: usb-uart not available on %s\n",
0545                __func__, match->compatible);
0546         return -ENOTSUPP;
0547     }
0548 
0549     grf = ERR_PTR(-ENODEV);
0550     if (np->parent)
0551         grf = syscon_node_to_regmap(np->parent);
0552     if (IS_ERR(grf))
0553         grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
0554     if (IS_ERR(grf)) {
0555         pr_err("%s: Missing rockchip,grf property, %lu\n",
0556                __func__, PTR_ERR(grf));
0557         return PTR_ERR(grf);
0558     }
0559 
0560     ret = data->init_usb_uart(grf, data);
0561     if (ret) {
0562         pr_err("%s: could not init usb_uart, %d\n", __func__, ret);
0563         enable_usb_uart = 0;
0564         return ret;
0565     }
0566 
0567     return 0;
0568 }
0569 early_initcall(rockchip_init_usb_uart);
0570 
0571 static int __init rockchip_usb_uart(char *buf)
0572 {
0573     enable_usb_uart = true;
0574     return 0;
0575 }
0576 early_param("rockchip.usb_uart", rockchip_usb_uart);
0577 #endif
0578 
0579 MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
0580 MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");
0581 MODULE_LICENSE("GPL v2");