Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * phy-uniphier-usb3hs.c - HS-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/nvmem-consumer.h>
0018 #include <linux/of.h>
0019 #include <linux/of_platform.h>
0020 #include <linux/phy/phy.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/regulator/consumer.h>
0023 #include <linux/reset.h>
0024 #include <linux/slab.h>
0025 
0026 #define HSPHY_CFG0      0x0
0027 #define HSPHY_CFG0_HS_I_MASK    GENMASK(31, 28)
0028 #define HSPHY_CFG0_HSDISC_MASK  GENMASK(27, 26)
0029 #define HSPHY_CFG0_SWING_MASK   GENMASK(17, 16)
0030 #define HSPHY_CFG0_SEL_T_MASK   GENMASK(15, 12)
0031 #define HSPHY_CFG0_RTERM_MASK   GENMASK(7, 6)
0032 #define HSPHY_CFG0_TRIMMASK (HSPHY_CFG0_HS_I_MASK \
0033                  | HSPHY_CFG0_SEL_T_MASK \
0034                  | HSPHY_CFG0_RTERM_MASK)
0035 
0036 #define HSPHY_CFG1      0x4
0037 #define HSPHY_CFG1_DAT_EN   BIT(29)
0038 #define HSPHY_CFG1_ADR_EN   BIT(28)
0039 #define HSPHY_CFG1_ADR_MASK GENMASK(27, 16)
0040 #define HSPHY_CFG1_DAT_MASK GENMASK(23, 16)
0041 
0042 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
0043 
0044 #define RX_CHK_SYNC PHY_F(0, 5, 5)  /* RX sync mode */
0045 #define RX_SYNC_SEL PHY_F(1, 1, 0)  /* RX sync length */
0046 #define LS_SLEW     PHY_F(10, 6, 6) /* LS mode slew rate */
0047 #define FS_LS_DRV   PHY_F(10, 5, 5) /* FS/LS slew rate */
0048 
0049 #define MAX_PHY_PARAMS  4
0050 
0051 struct uniphier_u3hsphy_param {
0052     struct {
0053         int reg_no;
0054         int msb;
0055         int lsb;
0056     } field;
0057     u8 value;
0058 };
0059 
0060 struct uniphier_u3hsphy_trim_param {
0061     unsigned int rterm;
0062     unsigned int sel_t;
0063     unsigned int hs_i;
0064 };
0065 
0066 #define trim_param_is_valid(p)  ((p)->rterm || (p)->sel_t || (p)->hs_i)
0067 
0068 struct uniphier_u3hsphy_priv {
0069     struct device *dev;
0070     void __iomem *base;
0071     struct clk *clk, *clk_parent, *clk_ext, *clk_parent_gio;
0072     struct reset_control *rst, *rst_parent, *rst_parent_gio;
0073     struct regulator *vbus;
0074     const struct uniphier_u3hsphy_soc_data *data;
0075 };
0076 
0077 struct uniphier_u3hsphy_soc_data {
0078     bool is_legacy;
0079     int nparams;
0080     const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
0081     u32 config0;
0082     u32 config1;
0083     void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig,
0084               struct uniphier_u3hsphy_trim_param *pt);
0085 };
0086 
0087 static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv,
0088                        u32 *pconfig,
0089                        struct uniphier_u3hsphy_trim_param *pt)
0090 {
0091     *pconfig &= ~HSPHY_CFG0_RTERM_MASK;
0092     *pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm);
0093 
0094     *pconfig &= ~HSPHY_CFG0_SEL_T_MASK;
0095     *pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t);
0096 
0097     *pconfig &= ~HSPHY_CFG0_HS_I_MASK;
0098     *pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK,  pt->hs_i);
0099 }
0100 
0101 static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv,
0102                     const char *name, unsigned int *val)
0103 {
0104     struct nvmem_cell *cell;
0105     u8 *buf;
0106 
0107     cell = devm_nvmem_cell_get(priv->dev, name);
0108     if (IS_ERR(cell))
0109         return PTR_ERR(cell);
0110 
0111     buf = nvmem_cell_read(cell, NULL);
0112     if (IS_ERR(buf))
0113         return PTR_ERR(buf);
0114 
0115     *val = *buf;
0116 
0117     kfree(buf);
0118 
0119     return 0;
0120 }
0121 
0122 static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv,
0123                      struct uniphier_u3hsphy_trim_param *pt)
0124 {
0125     int ret;
0126 
0127     ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm);
0128     if (ret)
0129         return ret;
0130 
0131     ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t);
0132     if (ret)
0133         return ret;
0134 
0135     ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i);
0136     if (ret)
0137         return ret;
0138 
0139     return 0;
0140 }
0141 
0142 static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv,
0143                       u32 *pconfig)
0144 {
0145     struct uniphier_u3hsphy_trim_param trim;
0146     int ret, trimmed = 0;
0147 
0148     if (priv->data->trim_func) {
0149         ret = uniphier_u3hsphy_get_nvparams(priv, &trim);
0150         if (ret == -EPROBE_DEFER)
0151             return ret;
0152 
0153         /*
0154          * call trim_func only when trimming parameters that aren't
0155          * all-zero can be acquired. All-zero parameters mean nothing
0156          * has been written to nvmem.
0157          */
0158         if (!ret && trim_param_is_valid(&trim)) {
0159             priv->data->trim_func(priv, pconfig, &trim);
0160             trimmed = 1;
0161         } else {
0162             dev_dbg(priv->dev, "can't get parameter from nvmem\n");
0163         }
0164     }
0165 
0166     /* use default parameters without trimming values */
0167     if (!trimmed) {
0168         *pconfig &= ~HSPHY_CFG0_HSDISC_MASK;
0169         *pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3);
0170     }
0171 
0172     return 0;
0173 }
0174 
0175 static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv,
0176                        const struct uniphier_u3hsphy_param *p)
0177 {
0178     u32 val;
0179     u32 field_mask = GENMASK(p->field.msb, p->field.lsb);
0180     u8 data;
0181 
0182     val = readl(priv->base + HSPHY_CFG1);
0183     val &= ~HSPHY_CFG1_ADR_MASK;
0184     val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no)
0185         | HSPHY_CFG1_ADR_EN;
0186     writel(val, priv->base + HSPHY_CFG1);
0187 
0188     val = readl(priv->base + HSPHY_CFG1);
0189     val &= ~HSPHY_CFG1_ADR_EN;
0190     writel(val, priv->base + HSPHY_CFG1);
0191 
0192     val = readl(priv->base + HSPHY_CFG1);
0193     val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask);
0194     data = field_mask & (p->value << p->field.lsb);
0195     val |=  FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN;
0196     writel(val, priv->base + HSPHY_CFG1);
0197 
0198     val = readl(priv->base + HSPHY_CFG1);
0199     val &= ~HSPHY_CFG1_DAT_EN;
0200     writel(val, priv->base + HSPHY_CFG1);
0201 }
0202 
0203 static int uniphier_u3hsphy_power_on(struct phy *phy)
0204 {
0205     struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
0206     int ret;
0207 
0208     ret = clk_prepare_enable(priv->clk_ext);
0209     if (ret)
0210         return ret;
0211 
0212     ret = clk_prepare_enable(priv->clk);
0213     if (ret)
0214         goto out_clk_ext_disable;
0215 
0216     ret = reset_control_deassert(priv->rst);
0217     if (ret)
0218         goto out_clk_disable;
0219 
0220     if (priv->vbus) {
0221         ret = regulator_enable(priv->vbus);
0222         if (ret)
0223             goto out_rst_assert;
0224     }
0225 
0226     return 0;
0227 
0228 out_rst_assert:
0229     reset_control_assert(priv->rst);
0230 out_clk_disable:
0231     clk_disable_unprepare(priv->clk);
0232 out_clk_ext_disable:
0233     clk_disable_unprepare(priv->clk_ext);
0234 
0235     return ret;
0236 }
0237 
0238 static int uniphier_u3hsphy_power_off(struct phy *phy)
0239 {
0240     struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
0241 
0242     if (priv->vbus)
0243         regulator_disable(priv->vbus);
0244 
0245     reset_control_assert(priv->rst);
0246     clk_disable_unprepare(priv->clk);
0247     clk_disable_unprepare(priv->clk_ext);
0248 
0249     return 0;
0250 }
0251 
0252 static int uniphier_u3hsphy_init(struct phy *phy)
0253 {
0254     struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
0255     u32 config0, config1;
0256     int i, ret;
0257 
0258     ret = clk_prepare_enable(priv->clk_parent);
0259     if (ret)
0260         return ret;
0261 
0262     ret = clk_prepare_enable(priv->clk_parent_gio);
0263     if (ret)
0264         goto out_clk_disable;
0265 
0266     ret = reset_control_deassert(priv->rst_parent);
0267     if (ret)
0268         goto out_clk_gio_disable;
0269 
0270     ret = reset_control_deassert(priv->rst_parent_gio);
0271     if (ret)
0272         goto out_rst_assert;
0273 
0274     if ((priv->data->is_legacy)
0275         || (!priv->data->config0 && !priv->data->config1))
0276         return 0;
0277 
0278     config0 = priv->data->config0;
0279     config1 = priv->data->config1;
0280 
0281     ret = uniphier_u3hsphy_update_config(priv, &config0);
0282     if (ret)
0283         goto out_rst_assert;
0284 
0285     writel(config0, priv->base + HSPHY_CFG0);
0286     writel(config1, priv->base + HSPHY_CFG1);
0287 
0288     for (i = 0; i < priv->data->nparams; i++)
0289         uniphier_u3hsphy_set_param(priv, &priv->data->param[i]);
0290 
0291     return 0;
0292 
0293 out_rst_assert:
0294     reset_control_assert(priv->rst_parent);
0295 out_clk_gio_disable:
0296     clk_disable_unprepare(priv->clk_parent_gio);
0297 out_clk_disable:
0298     clk_disable_unprepare(priv->clk_parent);
0299 
0300     return ret;
0301 }
0302 
0303 static int uniphier_u3hsphy_exit(struct phy *phy)
0304 {
0305     struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
0306 
0307     reset_control_assert(priv->rst_parent_gio);
0308     reset_control_assert(priv->rst_parent);
0309     clk_disable_unprepare(priv->clk_parent_gio);
0310     clk_disable_unprepare(priv->clk_parent);
0311 
0312     return 0;
0313 }
0314 
0315 static const struct phy_ops uniphier_u3hsphy_ops = {
0316     .init           = uniphier_u3hsphy_init,
0317     .exit           = uniphier_u3hsphy_exit,
0318     .power_on       = uniphier_u3hsphy_power_on,
0319     .power_off      = uniphier_u3hsphy_power_off,
0320     .owner          = THIS_MODULE,
0321 };
0322 
0323 static int uniphier_u3hsphy_probe(struct platform_device *pdev)
0324 {
0325     struct device *dev = &pdev->dev;
0326     struct uniphier_u3hsphy_priv *priv;
0327     struct phy_provider *phy_provider;
0328     struct phy *phy;
0329 
0330     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0331     if (!priv)
0332         return -ENOMEM;
0333 
0334     priv->dev = dev;
0335     priv->data = of_device_get_match_data(dev);
0336     if (WARN_ON(!priv->data ||
0337             priv->data->nparams > MAX_PHY_PARAMS))
0338         return -EINVAL;
0339 
0340     priv->base = devm_platform_ioremap_resource(pdev, 0);
0341     if (IS_ERR(priv->base))
0342         return PTR_ERR(priv->base);
0343 
0344     if (!priv->data->is_legacy) {
0345         priv->clk = devm_clk_get(dev, "phy");
0346         if (IS_ERR(priv->clk))
0347             return PTR_ERR(priv->clk);
0348 
0349         priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
0350         if (IS_ERR(priv->clk_ext))
0351             return PTR_ERR(priv->clk_ext);
0352 
0353         priv->rst = devm_reset_control_get_shared(dev, "phy");
0354         if (IS_ERR(priv->rst))
0355             return PTR_ERR(priv->rst);
0356 
0357     } else {
0358         priv->clk_parent_gio = devm_clk_get(dev, "gio");
0359         if (IS_ERR(priv->clk_parent_gio))
0360             return PTR_ERR(priv->clk_parent_gio);
0361 
0362         priv->rst_parent_gio =
0363             devm_reset_control_get_shared(dev, "gio");
0364         if (IS_ERR(priv->rst_parent_gio))
0365             return PTR_ERR(priv->rst_parent_gio);
0366     }
0367 
0368     priv->clk_parent = devm_clk_get(dev, "link");
0369     if (IS_ERR(priv->clk_parent))
0370         return PTR_ERR(priv->clk_parent);
0371 
0372     priv->rst_parent = devm_reset_control_get_shared(dev, "link");
0373     if (IS_ERR(priv->rst_parent))
0374         return PTR_ERR(priv->rst_parent);
0375 
0376     priv->vbus = devm_regulator_get_optional(dev, "vbus");
0377     if (IS_ERR(priv->vbus)) {
0378         if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
0379             return PTR_ERR(priv->vbus);
0380         priv->vbus = NULL;
0381     }
0382 
0383     phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops);
0384     if (IS_ERR(phy))
0385         return PTR_ERR(phy);
0386 
0387     phy_set_drvdata(phy, priv);
0388     phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
0389 
0390     return PTR_ERR_OR_ZERO(phy_provider);
0391 }
0392 
0393 static const struct uniphier_u3hsphy_soc_data uniphier_pro5_data = {
0394     .is_legacy = true,
0395     .nparams = 0,
0396 };
0397 
0398 static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
0399     .is_legacy = false,
0400     .nparams = 2,
0401     .param = {
0402         { RX_CHK_SYNC, 1 },
0403         { RX_SYNC_SEL, 1 },
0404     },
0405 };
0406 
0407 static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
0408     .is_legacy = false,
0409     .nparams = 4,
0410     .param = {
0411         { RX_CHK_SYNC, 1 },
0412         { RX_SYNC_SEL, 1 },
0413         { LS_SLEW, 1 },
0414         { FS_LS_DRV, 1 },
0415     },
0416     .trim_func = uniphier_u3hsphy_trim_ld20,
0417     .config0 = 0x92316680,
0418     .config1 = 0x00000106,
0419 };
0420 
0421 static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
0422     .is_legacy = false,
0423     .nparams = 2,
0424     .param = {
0425         { RX_CHK_SYNC, 1 },
0426         { RX_SYNC_SEL, 1 },
0427     },
0428     .trim_func = uniphier_u3hsphy_trim_ld20,
0429     .config0 = 0x92316680,
0430     .config1 = 0x00000106,
0431 };
0432 
0433 static const struct of_device_id uniphier_u3hsphy_match[] = {
0434     {
0435         .compatible = "socionext,uniphier-pro5-usb3-hsphy",
0436         .data = &uniphier_pro5_data,
0437     },
0438     {
0439         .compatible = "socionext,uniphier-pxs2-usb3-hsphy",
0440         .data = &uniphier_pxs2_data,
0441     },
0442     {
0443         .compatible = "socionext,uniphier-ld20-usb3-hsphy",
0444         .data = &uniphier_ld20_data,
0445     },
0446     {
0447         .compatible = "socionext,uniphier-pxs3-usb3-hsphy",
0448         .data = &uniphier_pxs3_data,
0449     },
0450     {
0451         .compatible = "socionext,uniphier-nx1-usb3-hsphy",
0452         .data = &uniphier_pxs3_data,
0453     },
0454     { /* sentinel */ }
0455 };
0456 MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match);
0457 
0458 static struct platform_driver uniphier_u3hsphy_driver = {
0459     .probe = uniphier_u3hsphy_probe,
0460     .driver = {
0461         .name = "uniphier-usb3-hsphy",
0462         .of_match_table = uniphier_u3hsphy_match,
0463     },
0464 };
0465 
0466 module_platform_driver(uniphier_u3hsphy_driver);
0467 
0468 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
0469 MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
0470 MODULE_LICENSE("GPL v2");