Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * phy-uniphier-usb3ss.c - SS-PHY driver for Socionext UniPhier USB3 controller
0004  * Copyright 2015-2018 Socionext Inc.
0005  * Author:
0006  *      Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
0007  * Contributors:
0008  *      Motoya Tanigawa <tanigawa.motoya@socionext.com>
0009  *      Masami Hiramatsu <masami.hiramatsu@linaro.org>
0010  */
0011 
0012 #include <linux/bitfield.h>
0013 #include <linux/bitops.h>
0014 #include <linux/clk.h>
0015 #include <linux/io.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/of_platform.h>
0019 #include <linux/phy/phy.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/regulator/consumer.h>
0022 #include <linux/reset.h>
0023 
0024 #define SSPHY_TESTI     0x0
0025 #define TESTI_DAT_MASK      GENMASK(13, 6)
0026 #define TESTI_ADR_MASK      GENMASK(5, 1)
0027 #define TESTI_WR_EN     BIT(0)
0028 
0029 #define SSPHY_TESTO     0x4
0030 #define TESTO_DAT_MASK      GENMASK(7, 0)
0031 
0032 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
0033 
0034 #define CDR_CPD_TRIM    PHY_F(7, 3, 0)  /* RxPLL charge pump current */
0035 #define CDR_CPF_TRIM    PHY_F(8, 3, 0)  /* RxPLL charge pump current 2 */
0036 #define TX_PLL_TRIM PHY_F(9, 3, 0)  /* TxPLL charge pump current */
0037 #define BGAP_TRIM   PHY_F(11, 3, 0) /* Bandgap voltage */
0038 #define CDR_TRIM    PHY_F(13, 6, 5) /* Clock Data Recovery setting */
0039 #define VCO_CTRL    PHY_F(26, 7, 4) /* VCO control */
0040 #define VCOPLL_CTRL PHY_F(27, 2, 0) /* TxPLL VCO tuning */
0041 #define VCOPLL_CM   PHY_F(28, 1, 0) /* TxPLL voltage */
0042 
0043 #define MAX_PHY_PARAMS  7
0044 
0045 struct uniphier_u3ssphy_param {
0046     struct {
0047         int reg_no;
0048         int msb;
0049         int lsb;
0050     } field;
0051     u8 value;
0052 };
0053 
0054 struct uniphier_u3ssphy_priv {
0055     struct device *dev;
0056     void __iomem *base;
0057     struct clk *clk, *clk_ext, *clk_parent, *clk_parent_gio;
0058     struct reset_control *rst, *rst_parent, *rst_parent_gio;
0059     struct regulator *vbus;
0060     const struct uniphier_u3ssphy_soc_data *data;
0061 };
0062 
0063 struct uniphier_u3ssphy_soc_data {
0064     bool is_legacy;
0065     int nparams;
0066     const struct uniphier_u3ssphy_param param[MAX_PHY_PARAMS];
0067 };
0068 
0069 static void uniphier_u3ssphy_testio_write(struct uniphier_u3ssphy_priv *priv,
0070                       u32 data)
0071 {
0072     /* need to read TESTO twice after accessing TESTI */
0073     writel(data, priv->base + SSPHY_TESTI);
0074     readl(priv->base + SSPHY_TESTO);
0075     readl(priv->base + SSPHY_TESTO);
0076 }
0077 
0078 static void uniphier_u3ssphy_set_param(struct uniphier_u3ssphy_priv *priv,
0079                        const struct uniphier_u3ssphy_param *p)
0080 {
0081     u32 val;
0082     u8 field_mask = GENMASK(p->field.msb, p->field.lsb);
0083     u8 data;
0084 
0085     /* read previous data */
0086     val  = FIELD_PREP(TESTI_DAT_MASK, 1);
0087     val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
0088     uniphier_u3ssphy_testio_write(priv, val);
0089     val = readl(priv->base + SSPHY_TESTO) & TESTO_DAT_MASK;
0090 
0091     /* update value */
0092     val &= ~field_mask;
0093     data = field_mask & (p->value << p->field.lsb);
0094     val  = FIELD_PREP(TESTI_DAT_MASK, data | val);
0095     val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
0096     uniphier_u3ssphy_testio_write(priv, val);
0097     uniphier_u3ssphy_testio_write(priv, val | TESTI_WR_EN);
0098     uniphier_u3ssphy_testio_write(priv, val);
0099 
0100     /* read current data as dummy */
0101     val  = FIELD_PREP(TESTI_DAT_MASK, 1);
0102     val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
0103     uniphier_u3ssphy_testio_write(priv, val);
0104     readl(priv->base + SSPHY_TESTO);
0105 }
0106 
0107 static int uniphier_u3ssphy_power_on(struct phy *phy)
0108 {
0109     struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
0110     int ret;
0111 
0112     ret = clk_prepare_enable(priv->clk_ext);
0113     if (ret)
0114         return ret;
0115 
0116     ret = clk_prepare_enable(priv->clk);
0117     if (ret)
0118         goto out_clk_ext_disable;
0119 
0120     ret = reset_control_deassert(priv->rst);
0121     if (ret)
0122         goto out_clk_disable;
0123 
0124     if (priv->vbus) {
0125         ret = regulator_enable(priv->vbus);
0126         if (ret)
0127             goto out_rst_assert;
0128     }
0129 
0130     return 0;
0131 
0132 out_rst_assert:
0133     reset_control_assert(priv->rst);
0134 out_clk_disable:
0135     clk_disable_unprepare(priv->clk);
0136 out_clk_ext_disable:
0137     clk_disable_unprepare(priv->clk_ext);
0138 
0139     return ret;
0140 }
0141 
0142 static int uniphier_u3ssphy_power_off(struct phy *phy)
0143 {
0144     struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
0145 
0146     if (priv->vbus)
0147         regulator_disable(priv->vbus);
0148 
0149     reset_control_assert(priv->rst);
0150     clk_disable_unprepare(priv->clk);
0151     clk_disable_unprepare(priv->clk_ext);
0152 
0153     return 0;
0154 }
0155 
0156 static int uniphier_u3ssphy_init(struct phy *phy)
0157 {
0158     struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
0159     int i, ret;
0160 
0161     ret = clk_prepare_enable(priv->clk_parent);
0162     if (ret)
0163         return ret;
0164 
0165     ret = clk_prepare_enable(priv->clk_parent_gio);
0166     if (ret)
0167         goto out_clk_disable;
0168 
0169     ret = reset_control_deassert(priv->rst_parent);
0170     if (ret)
0171         goto out_clk_gio_disable;
0172 
0173     ret = reset_control_deassert(priv->rst_parent_gio);
0174     if (ret)
0175         goto out_rst_assert;
0176 
0177     if (priv->data->is_legacy)
0178         return 0;
0179 
0180     for (i = 0; i < priv->data->nparams; i++)
0181         uniphier_u3ssphy_set_param(priv, &priv->data->param[i]);
0182 
0183     return 0;
0184 
0185 out_rst_assert:
0186     reset_control_assert(priv->rst_parent);
0187 out_clk_gio_disable:
0188     clk_disable_unprepare(priv->clk_parent_gio);
0189 out_clk_disable:
0190     clk_disable_unprepare(priv->clk_parent);
0191 
0192     return ret;
0193 }
0194 
0195 static int uniphier_u3ssphy_exit(struct phy *phy)
0196 {
0197     struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
0198 
0199     reset_control_assert(priv->rst_parent_gio);
0200     reset_control_assert(priv->rst_parent);
0201     clk_disable_unprepare(priv->clk_parent_gio);
0202     clk_disable_unprepare(priv->clk_parent);
0203 
0204     return 0;
0205 }
0206 
0207 static const struct phy_ops uniphier_u3ssphy_ops = {
0208     .init           = uniphier_u3ssphy_init,
0209     .exit           = uniphier_u3ssphy_exit,
0210     .power_on       = uniphier_u3ssphy_power_on,
0211     .power_off      = uniphier_u3ssphy_power_off,
0212     .owner          = THIS_MODULE,
0213 };
0214 
0215 static int uniphier_u3ssphy_probe(struct platform_device *pdev)
0216 {
0217     struct device *dev = &pdev->dev;
0218     struct uniphier_u3ssphy_priv *priv;
0219     struct phy_provider *phy_provider;
0220     struct phy *phy;
0221 
0222     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0223     if (!priv)
0224         return -ENOMEM;
0225 
0226     priv->dev = dev;
0227     priv->data = of_device_get_match_data(dev);
0228     if (WARN_ON(!priv->data ||
0229             priv->data->nparams > MAX_PHY_PARAMS))
0230         return -EINVAL;
0231 
0232     priv->base = devm_platform_ioremap_resource(pdev, 0);
0233     if (IS_ERR(priv->base))
0234         return PTR_ERR(priv->base);
0235 
0236     if (!priv->data->is_legacy) {
0237         priv->clk = devm_clk_get(dev, "phy");
0238         if (IS_ERR(priv->clk))
0239             return PTR_ERR(priv->clk);
0240 
0241         priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
0242         if (IS_ERR(priv->clk_ext))
0243             return PTR_ERR(priv->clk_ext);
0244 
0245         priv->rst = devm_reset_control_get_shared(dev, "phy");
0246         if (IS_ERR(priv->rst))
0247             return PTR_ERR(priv->rst);
0248     } else {
0249         priv->clk_parent_gio = devm_clk_get(dev, "gio");
0250         if (IS_ERR(priv->clk_parent_gio))
0251             return PTR_ERR(priv->clk_parent_gio);
0252 
0253         priv->rst_parent_gio =
0254             devm_reset_control_get_shared(dev, "gio");
0255         if (IS_ERR(priv->rst_parent_gio))
0256             return PTR_ERR(priv->rst_parent_gio);
0257     }
0258 
0259     priv->clk_parent = devm_clk_get(dev, "link");
0260     if (IS_ERR(priv->clk_parent))
0261         return PTR_ERR(priv->clk_parent);
0262 
0263     priv->rst_parent = devm_reset_control_get_shared(dev, "link");
0264     if (IS_ERR(priv->rst_parent))
0265         return PTR_ERR(priv->rst_parent);
0266 
0267     priv->vbus = devm_regulator_get_optional(dev, "vbus");
0268     if (IS_ERR(priv->vbus)) {
0269         if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
0270             return PTR_ERR(priv->vbus);
0271         priv->vbus = NULL;
0272     }
0273 
0274     phy = devm_phy_create(dev, dev->of_node, &uniphier_u3ssphy_ops);
0275     if (IS_ERR(phy))
0276         return PTR_ERR(phy);
0277 
0278     phy_set_drvdata(phy, priv);
0279     phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
0280 
0281     return PTR_ERR_OR_ZERO(phy_provider);
0282 }
0283 
0284 static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data = {
0285     .is_legacy = true,
0286 };
0287 
0288 static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data = {
0289     .is_legacy = false,
0290     .nparams = 7,
0291     .param = {
0292         { CDR_CPD_TRIM, 10 },
0293         { CDR_CPF_TRIM, 3 },
0294         { TX_PLL_TRIM, 5 },
0295         { BGAP_TRIM, 9 },
0296         { CDR_TRIM, 2 },
0297         { VCOPLL_CTRL, 7 },
0298         { VCOPLL_CM, 1 },
0299     },
0300 };
0301 
0302 static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data = {
0303     .is_legacy = false,
0304     .nparams = 3,
0305     .param = {
0306         { CDR_CPD_TRIM, 6 },
0307         { CDR_TRIM, 2 },
0308         { VCO_CTRL, 5 },
0309     },
0310 };
0311 
0312 static const struct of_device_id uniphier_u3ssphy_match[] = {
0313     {
0314         .compatible = "socionext,uniphier-pro4-usb3-ssphy",
0315         .data = &uniphier_pro4_data,
0316     },
0317     {
0318         .compatible = "socionext,uniphier-pro5-usb3-ssphy",
0319         .data = &uniphier_pro4_data,
0320     },
0321     {
0322         .compatible = "socionext,uniphier-pxs2-usb3-ssphy",
0323         .data = &uniphier_pxs2_data,
0324     },
0325     {
0326         .compatible = "socionext,uniphier-ld20-usb3-ssphy",
0327         .data = &uniphier_ld20_data,
0328     },
0329     {
0330         .compatible = "socionext,uniphier-pxs3-usb3-ssphy",
0331         .data = &uniphier_ld20_data,
0332     },
0333     {
0334         .compatible = "socionext,uniphier-nx1-usb3-ssphy",
0335         .data = &uniphier_ld20_data,
0336     },
0337     { /* sentinel */ }
0338 };
0339 MODULE_DEVICE_TABLE(of, uniphier_u3ssphy_match);
0340 
0341 static struct platform_driver uniphier_u3ssphy_driver = {
0342     .probe = uniphier_u3ssphy_probe,
0343     .driver = {
0344         .name = "uniphier-usb3-ssphy",
0345         .of_match_table = uniphier_u3ssphy_match,
0346     },
0347 };
0348 
0349 module_platform_driver(uniphier_u3ssphy_driver);
0350 
0351 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
0352 MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller");
0353 MODULE_LICENSE("GPL v2");