root/drivers/phy/socionext/phy-uniphier-usb3hs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uniphier_u3hsphy_trim_ld20
  2. uniphier_u3hsphy_get_nvparam
  3. uniphier_u3hsphy_get_nvparams
  4. uniphier_u3hsphy_update_config
  5. uniphier_u3hsphy_set_param
  6. uniphier_u3hsphy_power_on
  7. uniphier_u3hsphy_power_off
  8. uniphier_u3hsphy_init
  9. uniphier_u3hsphy_exit
  10. uniphier_u3hsphy_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller
   4  * Copyright 2015-2018 Socionext Inc.
   5  * Author:
   6  *      Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
   7  * Contributors:
   8  *      Motoya Tanigawa <tanigawa.motoya@socionext.com>
   9  *      Masami Hiramatsu <masami.hiramatsu@linaro.org>
  10  */
  11 
  12 #include <linux/bitfield.h>
  13 #include <linux/bitops.h>
  14 #include <linux/clk.h>
  15 #include <linux/io.h>
  16 #include <linux/module.h>
  17 #include <linux/nvmem-consumer.h>
  18 #include <linux/of.h>
  19 #include <linux/of_platform.h>
  20 #include <linux/phy/phy.h>
  21 #include <linux/platform_device.h>
  22 #include <linux/regulator/consumer.h>
  23 #include <linux/reset.h>
  24 #include <linux/slab.h>
  25 
  26 #define HSPHY_CFG0              0x0
  27 #define HSPHY_CFG0_HS_I_MASK    GENMASK(31, 28)
  28 #define HSPHY_CFG0_HSDISC_MASK  GENMASK(27, 26)
  29 #define HSPHY_CFG0_SWING_MASK   GENMASK(17, 16)
  30 #define HSPHY_CFG0_SEL_T_MASK   GENMASK(15, 12)
  31 #define HSPHY_CFG0_RTERM_MASK   GENMASK(7, 6)
  32 #define HSPHY_CFG0_TRIMMASK     (HSPHY_CFG0_HS_I_MASK \
  33                                  | HSPHY_CFG0_SEL_T_MASK \
  34                                  | HSPHY_CFG0_RTERM_MASK)
  35 
  36 #define HSPHY_CFG1              0x4
  37 #define HSPHY_CFG1_DAT_EN       BIT(29)
  38 #define HSPHY_CFG1_ADR_EN       BIT(28)
  39 #define HSPHY_CFG1_ADR_MASK     GENMASK(27, 16)
  40 #define HSPHY_CFG1_DAT_MASK     GENMASK(23, 16)
  41 
  42 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
  43 
  44 #define LS_SLEW         PHY_F(10, 6, 6) /* LS mode slew rate */
  45 #define FS_LS_DRV       PHY_F(10, 5, 5) /* FS/LS slew rate */
  46 
  47 #define MAX_PHY_PARAMS  2
  48 
  49 struct uniphier_u3hsphy_param {
  50         struct {
  51                 int reg_no;
  52                 int msb;
  53                 int lsb;
  54         } field;
  55         u8 value;
  56 };
  57 
  58 struct uniphier_u3hsphy_trim_param {
  59         unsigned int rterm;
  60         unsigned int sel_t;
  61         unsigned int hs_i;
  62 };
  63 
  64 #define trim_param_is_valid(p)  ((p)->rterm || (p)->sel_t || (p)->hs_i)
  65 
  66 struct uniphier_u3hsphy_priv {
  67         struct device *dev;
  68         void __iomem *base;
  69         struct clk *clk, *clk_parent, *clk_ext;
  70         struct reset_control *rst, *rst_parent;
  71         struct regulator *vbus;
  72         const struct uniphier_u3hsphy_soc_data *data;
  73 };
  74 
  75 struct uniphier_u3hsphy_soc_data {
  76         int nparams;
  77         const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
  78         u32 config0;
  79         u32 config1;
  80         void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig,
  81                           struct uniphier_u3hsphy_trim_param *pt);
  82 };
  83 
  84 static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv,
  85                                        u32 *pconfig,
  86                                        struct uniphier_u3hsphy_trim_param *pt)
  87 {
  88         *pconfig &= ~HSPHY_CFG0_RTERM_MASK;
  89         *pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm);
  90 
  91         *pconfig &= ~HSPHY_CFG0_SEL_T_MASK;
  92         *pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t);
  93 
  94         *pconfig &= ~HSPHY_CFG0_HS_I_MASK;
  95         *pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK,  pt->hs_i);
  96 }
  97 
  98 static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv,
  99                                         const char *name, unsigned int *val)
 100 {
 101         struct nvmem_cell *cell;
 102         u8 *buf;
 103 
 104         cell = devm_nvmem_cell_get(priv->dev, name);
 105         if (IS_ERR(cell))
 106                 return PTR_ERR(cell);
 107 
 108         buf = nvmem_cell_read(cell, NULL);
 109         if (IS_ERR(buf))
 110                 return PTR_ERR(buf);
 111 
 112         *val = *buf;
 113 
 114         kfree(buf);
 115 
 116         return 0;
 117 }
 118 
 119 static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv,
 120                                          struct uniphier_u3hsphy_trim_param *pt)
 121 {
 122         int ret;
 123 
 124         ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm);
 125         if (ret)
 126                 return ret;
 127 
 128         ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t);
 129         if (ret)
 130                 return ret;
 131 
 132         ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i);
 133         if (ret)
 134                 return ret;
 135 
 136         return 0;
 137 }
 138 
 139 static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv,
 140                                           u32 *pconfig)
 141 {
 142         struct uniphier_u3hsphy_trim_param trim;
 143         int ret, trimmed = 0;
 144 
 145         if (priv->data->trim_func) {
 146                 ret = uniphier_u3hsphy_get_nvparams(priv, &trim);
 147                 if (ret == -EPROBE_DEFER)
 148                         return ret;
 149 
 150                 /*
 151                  * call trim_func only when trimming parameters that aren't
 152                  * all-zero can be acquired. All-zero parameters mean nothing
 153                  * has been written to nvmem.
 154                  */
 155                 if (!ret && trim_param_is_valid(&trim)) {
 156                         priv->data->trim_func(priv, pconfig, &trim);
 157                         trimmed = 1;
 158                 } else {
 159                         dev_dbg(priv->dev, "can't get parameter from nvmem\n");
 160                 }
 161         }
 162 
 163         /* use default parameters without trimming values */
 164         if (!trimmed) {
 165                 *pconfig &= ~HSPHY_CFG0_HSDISC_MASK;
 166                 *pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3);
 167         }
 168 
 169         return 0;
 170 }
 171 
 172 static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv,
 173                                        const struct uniphier_u3hsphy_param *p)
 174 {
 175         u32 val;
 176         u32 field_mask = GENMASK(p->field.msb, p->field.lsb);
 177         u8 data;
 178 
 179         val = readl(priv->base + HSPHY_CFG1);
 180         val &= ~HSPHY_CFG1_ADR_MASK;
 181         val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no)
 182                 | HSPHY_CFG1_ADR_EN;
 183         writel(val, priv->base + HSPHY_CFG1);
 184 
 185         val = readl(priv->base + HSPHY_CFG1);
 186         val &= ~HSPHY_CFG1_ADR_EN;
 187         writel(val, priv->base + HSPHY_CFG1);
 188 
 189         val = readl(priv->base + HSPHY_CFG1);
 190         val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask);
 191         data = field_mask & (p->value << p->field.lsb);
 192         val |=  FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN;
 193         writel(val, priv->base + HSPHY_CFG1);
 194 
 195         val = readl(priv->base + HSPHY_CFG1);
 196         val &= ~HSPHY_CFG1_DAT_EN;
 197         writel(val, priv->base + HSPHY_CFG1);
 198 }
 199 
 200 static int uniphier_u3hsphy_power_on(struct phy *phy)
 201 {
 202         struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
 203         int ret;
 204 
 205         ret = clk_prepare_enable(priv->clk_ext);
 206         if (ret)
 207                 return ret;
 208 
 209         ret = clk_prepare_enable(priv->clk);
 210         if (ret)
 211                 goto out_clk_ext_disable;
 212 
 213         ret = reset_control_deassert(priv->rst);
 214         if (ret)
 215                 goto out_clk_disable;
 216 
 217         if (priv->vbus) {
 218                 ret = regulator_enable(priv->vbus);
 219                 if (ret)
 220                         goto out_rst_assert;
 221         }
 222 
 223         return 0;
 224 
 225 out_rst_assert:
 226         reset_control_assert(priv->rst);
 227 out_clk_disable:
 228         clk_disable_unprepare(priv->clk);
 229 out_clk_ext_disable:
 230         clk_disable_unprepare(priv->clk_ext);
 231 
 232         return ret;
 233 }
 234 
 235 static int uniphier_u3hsphy_power_off(struct phy *phy)
 236 {
 237         struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
 238 
 239         if (priv->vbus)
 240                 regulator_disable(priv->vbus);
 241 
 242         reset_control_assert(priv->rst);
 243         clk_disable_unprepare(priv->clk);
 244         clk_disable_unprepare(priv->clk_ext);
 245 
 246         return 0;
 247 }
 248 
 249 static int uniphier_u3hsphy_init(struct phy *phy)
 250 {
 251         struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
 252         u32 config0, config1;
 253         int i, ret;
 254 
 255         ret = clk_prepare_enable(priv->clk_parent);
 256         if (ret)
 257                 return ret;
 258 
 259         ret = reset_control_deassert(priv->rst_parent);
 260         if (ret)
 261                 goto out_clk_disable;
 262 
 263         if (!priv->data->config0 && !priv->data->config1)
 264                 return 0;
 265 
 266         config0 = priv->data->config0;
 267         config1 = priv->data->config1;
 268 
 269         ret = uniphier_u3hsphy_update_config(priv, &config0);
 270         if (ret)
 271                 goto out_rst_assert;
 272 
 273         writel(config0, priv->base + HSPHY_CFG0);
 274         writel(config1, priv->base + HSPHY_CFG1);
 275 
 276         for (i = 0; i < priv->data->nparams; i++)
 277                 uniphier_u3hsphy_set_param(priv, &priv->data->param[i]);
 278 
 279         return 0;
 280 
 281 out_rst_assert:
 282         reset_control_assert(priv->rst_parent);
 283 out_clk_disable:
 284         clk_disable_unprepare(priv->clk_parent);
 285 
 286         return ret;
 287 }
 288 
 289 static int uniphier_u3hsphy_exit(struct phy *phy)
 290 {
 291         struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
 292 
 293         reset_control_assert(priv->rst_parent);
 294         clk_disable_unprepare(priv->clk_parent);
 295 
 296         return 0;
 297 }
 298 
 299 static const struct phy_ops uniphier_u3hsphy_ops = {
 300         .init           = uniphier_u3hsphy_init,
 301         .exit           = uniphier_u3hsphy_exit,
 302         .power_on       = uniphier_u3hsphy_power_on,
 303         .power_off      = uniphier_u3hsphy_power_off,
 304         .owner          = THIS_MODULE,
 305 };
 306 
 307 static int uniphier_u3hsphy_probe(struct platform_device *pdev)
 308 {
 309         struct device *dev = &pdev->dev;
 310         struct uniphier_u3hsphy_priv *priv;
 311         struct phy_provider *phy_provider;
 312         struct resource *res;
 313         struct phy *phy;
 314 
 315         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 316         if (!priv)
 317                 return -ENOMEM;
 318 
 319         priv->dev = dev;
 320         priv->data = of_device_get_match_data(dev);
 321         if (WARN_ON(!priv->data ||
 322                     priv->data->nparams > MAX_PHY_PARAMS))
 323                 return -EINVAL;
 324 
 325         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 326         priv->base = devm_ioremap_resource(dev, res);
 327         if (IS_ERR(priv->base))
 328                 return PTR_ERR(priv->base);
 329 
 330         priv->clk = devm_clk_get(dev, "phy");
 331         if (IS_ERR(priv->clk))
 332                 return PTR_ERR(priv->clk);
 333 
 334         priv->clk_parent = devm_clk_get(dev, "link");
 335         if (IS_ERR(priv->clk_parent))
 336                 return PTR_ERR(priv->clk_parent);
 337 
 338         priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
 339         if (IS_ERR(priv->clk_ext))
 340                 return PTR_ERR(priv->clk_ext);
 341 
 342         priv->rst = devm_reset_control_get_shared(dev, "phy");
 343         if (IS_ERR(priv->rst))
 344                 return PTR_ERR(priv->rst);
 345 
 346         priv->rst_parent = devm_reset_control_get_shared(dev, "link");
 347         if (IS_ERR(priv->rst_parent))
 348                 return PTR_ERR(priv->rst_parent);
 349 
 350         priv->vbus = devm_regulator_get_optional(dev, "vbus");
 351         if (IS_ERR(priv->vbus)) {
 352                 if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
 353                         return PTR_ERR(priv->vbus);
 354                 priv->vbus = NULL;
 355         }
 356 
 357         phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops);
 358         if (IS_ERR(phy))
 359                 return PTR_ERR(phy);
 360 
 361         phy_set_drvdata(phy, priv);
 362         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 363 
 364         return PTR_ERR_OR_ZERO(phy_provider);
 365 }
 366 
 367 static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
 368         .nparams = 0,
 369 };
 370 
 371 static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
 372         .nparams = 2,
 373         .param = {
 374                 { LS_SLEW, 1 },
 375                 { FS_LS_DRV, 1 },
 376         },
 377         .trim_func = uniphier_u3hsphy_trim_ld20,
 378         .config0 = 0x92316680,
 379         .config1 = 0x00000106,
 380 };
 381 
 382 static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
 383         .nparams = 0,
 384         .trim_func = uniphier_u3hsphy_trim_ld20,
 385         .config0 = 0x92316680,
 386         .config1 = 0x00000106,
 387 };
 388 
 389 static const struct of_device_id uniphier_u3hsphy_match[] = {
 390         {
 391                 .compatible = "socionext,uniphier-pxs2-usb3-hsphy",
 392                 .data = &uniphier_pxs2_data,
 393         },
 394         {
 395                 .compatible = "socionext,uniphier-ld20-usb3-hsphy",
 396                 .data = &uniphier_ld20_data,
 397         },
 398         {
 399                 .compatible = "socionext,uniphier-pxs3-usb3-hsphy",
 400                 .data = &uniphier_pxs3_data,
 401         },
 402         { /* sentinel */ }
 403 };
 404 MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match);
 405 
 406 static struct platform_driver uniphier_u3hsphy_driver = {
 407         .probe = uniphier_u3hsphy_probe,
 408         .driver = {
 409                 .name = "uniphier-usb3-hsphy",
 410                 .of_match_table = uniphier_u3hsphy_match,
 411         },
 412 };
 413 
 414 module_platform_driver(uniphier_u3hsphy_driver);
 415 
 416 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
 417 MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
 418 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */