linux/drivers/phy/qualcomm/phy-qcom-qusb2.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 and
   6 * only version 2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/delay.h>
  16#include <linux/err.h>
  17#include <linux/io.h>
  18#include <linux/kernel.h>
  19#include <linux/mfd/syscon.h>
  20#include <linux/module.h>
  21#include <linux/nvmem-consumer.h>
  22#include <linux/of.h>
  23#include <linux/of_device.h>
  24#include <linux/phy/phy.h>
  25#include <linux/platform_device.h>
  26#include <linux/regmap.h>
  27#include <linux/regulator/consumer.h>
  28#include <linux/reset.h>
  29#include <linux/slab.h>
  30
  31#define QUSB2PHY_PLL_TEST               0x04
  32#define CLK_REF_SEL                     BIT(7)
  33
  34#define QUSB2PHY_PLL_TUNE               0x08
  35#define QUSB2PHY_PLL_USER_CTL1          0x0c
  36#define QUSB2PHY_PLL_USER_CTL2          0x10
  37#define QUSB2PHY_PLL_AUTOPGM_CTL1       0x1c
  38#define QUSB2PHY_PLL_PWR_CTRL           0x18
  39
  40#define QUSB2PHY_PLL_STATUS             0x38
  41#define PLL_LOCKED                      BIT(5)
  42
  43#define QUSB2PHY_PORT_TUNE1             0x80
  44#define QUSB2PHY_PORT_TUNE2             0x84
  45#define QUSB2PHY_PORT_TUNE3             0x88
  46#define QUSB2PHY_PORT_TUNE4             0x8c
  47#define QUSB2PHY_PORT_TUNE5             0x90
  48#define QUSB2PHY_PORT_TEST2             0x9c
  49
  50#define QUSB2PHY_PORT_POWERDOWN         0xb4
  51#define CLAMP_N_EN                      BIT(5)
  52#define FREEZIO_N                       BIT(1)
  53#define POWER_DOWN                      BIT(0)
  54
  55#define QUSB2PHY_REFCLK_ENABLE          BIT(0)
  56
  57#define PHY_CLK_SCHEME_SEL              BIT(0)
  58
  59struct qusb2_phy_init_tbl {
  60        unsigned int offset;
  61        unsigned int val;
  62};
  63
  64#define QUSB2_PHY_INIT_CFG(o, v) \
  65        {                       \
  66                .offset = o,    \
  67                .val = v,       \
  68        }
  69
  70static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
  71        QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xf8),
  72        QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xb3),
  73        QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
  74        QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xc0),
  75        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
  76        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
  77        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
  78        QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
  79        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
  80        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
  81};
  82
  83struct qusb2_phy_cfg {
  84        const struct qusb2_phy_init_tbl *tbl;
  85        /* number of entries in the table */
  86        unsigned int tbl_num;
  87        /* offset to PHY_CLK_SCHEME register in TCSR map */
  88        unsigned int clk_scheme_offset;
  89};
  90
  91static const struct qusb2_phy_cfg msm8996_phy_cfg = {
  92        .tbl = msm8996_init_tbl,
  93        .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
  94};
  95
  96static const char * const qusb2_phy_vreg_names[] = {
  97        "vdda-pll", "vdda-phy-dpdm",
  98};
  99
 100#define QUSB2_NUM_VREGS         ARRAY_SIZE(qusb2_phy_vreg_names)
 101
 102/**
 103 * struct qusb2_phy - structure holding qusb2 phy attributes
 104 *
 105 * @phy: generic phy
 106 * @base: iomapped memory space for qubs2 phy
 107 *
 108 * @cfg_ahb_clk: AHB2PHY interface clock
 109 * @ref_clk: phy reference clock
 110 * @iface_clk: phy interface clock
 111 * @phy_reset: phy reset control
 112 * @vregs: regulator supplies bulk data
 113 *
 114 * @tcsr: TCSR syscon register map
 115 * @cell: nvmem cell containing phy tuning value
 116 *
 117 * @cfg: phy config data
 118 * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
 119 */
 120struct qusb2_phy {
 121        struct phy *phy;
 122        void __iomem *base;
 123
 124        struct clk *cfg_ahb_clk;
 125        struct clk *ref_clk;
 126        struct clk *iface_clk;
 127        struct reset_control *phy_reset;
 128        struct regulator_bulk_data vregs[QUSB2_NUM_VREGS];
 129
 130        struct regmap *tcsr;
 131        struct nvmem_cell *cell;
 132
 133        const struct qusb2_phy_cfg *cfg;
 134        bool has_se_clk_scheme;
 135};
 136
 137static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)
 138{
 139        u32 reg;
 140
 141        reg = readl(base + offset);
 142        reg |= val;
 143        writel(reg, base + offset);
 144
 145        /* Ensure above write is completed */
 146        readl(base + offset);
 147}
 148
 149static inline void qusb2_clrbits(void __iomem *base, u32 offset, u32 val)
 150{
 151        u32 reg;
 152
 153        reg = readl(base + offset);
 154        reg &= ~val;
 155        writel(reg, base + offset);
 156
 157        /* Ensure above write is completed */
 158        readl(base + offset);
 159}
 160
 161static inline
 162void qcom_qusb2_phy_configure(void __iomem *base,
 163                              const struct qusb2_phy_init_tbl tbl[], int num)
 164{
 165        int i;
 166
 167        for (i = 0; i < num; i++)
 168                writel(tbl[i].val, base + tbl[i].offset);
 169}
 170
 171/*
 172 * Fetches HS Tx tuning value from nvmem and sets the
 173 * QUSB2PHY_PORT_TUNE2 register.
 174 * For error case, skip setting the value and use the default value.
 175 */
 176static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
 177{
 178        struct device *dev = &qphy->phy->dev;
 179        u8 *val;
 180
 181        /*
 182         * Read efuse register having TUNE2 parameter's high nibble.
 183         * If efuse register shows value as 0x0, or if we fail to find
 184         * a valid efuse register settings, then use default value
 185         * as 0xB for high nibble that we have already set while
 186         * configuring phy.
 187         */
 188        val = nvmem_cell_read(qphy->cell, NULL);
 189        if (IS_ERR(val) || !val[0]) {
 190                dev_dbg(dev, "failed to read a valid hs-tx trim value\n");
 191                return;
 192        }
 193
 194        /* Fused TUNE2 value is the higher nibble only */
 195        qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
 196}
 197
 198static int qusb2_phy_poweron(struct phy *phy)
 199{
 200        struct qusb2_phy *qphy = phy_get_drvdata(phy);
 201        int num = ARRAY_SIZE(qphy->vregs);
 202        int ret;
 203
 204        dev_vdbg(&phy->dev, "%s(): Powering-on QUSB2 phy\n", __func__);
 205
 206        /* turn on regulator supplies */
 207        ret = regulator_bulk_enable(num, qphy->vregs);
 208        if (ret)
 209                return ret;
 210
 211        ret = clk_prepare_enable(qphy->iface_clk);
 212        if (ret) {
 213                dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
 214                regulator_bulk_disable(num, qphy->vregs);
 215                return ret;
 216        }
 217
 218        return 0;
 219}
 220
 221static int qusb2_phy_poweroff(struct phy *phy)
 222{
 223        struct qusb2_phy *qphy = phy_get_drvdata(phy);
 224
 225        clk_disable_unprepare(qphy->iface_clk);
 226
 227        regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
 228
 229        return 0;
 230}
 231
 232static int qusb2_phy_init(struct phy *phy)
 233{
 234        struct qusb2_phy *qphy = phy_get_drvdata(phy);
 235        unsigned int val;
 236        unsigned int clk_scheme;
 237        int ret;
 238
 239        dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
 240
 241        /* enable ahb interface clock to program phy */
 242        ret = clk_prepare_enable(qphy->cfg_ahb_clk);
 243        if (ret) {
 244                dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
 245                return ret;
 246        }
 247
 248        /* Perform phy reset */
 249        ret = reset_control_assert(qphy->phy_reset);
 250        if (ret) {
 251                dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
 252                goto disable_ahb_clk;
 253        }
 254
 255        /* 100 us delay to keep PHY in reset mode */
 256        usleep_range(100, 150);
 257
 258        ret = reset_control_deassert(qphy->phy_reset);
 259        if (ret) {
 260                dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
 261                goto disable_ahb_clk;
 262        }
 263
 264        /* Disable the PHY */
 265        qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
 266                      CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
 267
 268        /* save reset value to override reference clock scheme later */
 269        val = readl(qphy->base + QUSB2PHY_PLL_TEST);
 270
 271        qcom_qusb2_phy_configure(qphy->base, qphy->cfg->tbl,
 272                                 qphy->cfg->tbl_num);
 273
 274        /* Set efuse value for tuning the PHY */
 275        qusb2_phy_set_tune2_param(qphy);
 276
 277        /* Enable the PHY */
 278        qusb2_clrbits(qphy->base, QUSB2PHY_PORT_POWERDOWN, POWER_DOWN);
 279
 280        /* Required to get phy pll lock successfully */
 281        usleep_range(150, 160);
 282
 283        /* Default is single-ended clock on msm8996 */
 284        qphy->has_se_clk_scheme = true;
 285        /*
 286         * read TCSR_PHY_CLK_SCHEME register to check if single-ended
 287         * clock scheme is selected. If yes, then disable differential
 288         * ref_clk and use single-ended clock, otherwise use differential
 289         * ref_clk only.
 290         */
 291        if (qphy->tcsr) {
 292                ret = regmap_read(qphy->tcsr, qphy->cfg->clk_scheme_offset,
 293                                  &clk_scheme);
 294                if (ret) {
 295                        dev_err(&phy->dev, "failed to read clk scheme reg\n");
 296                        goto assert_phy_reset;
 297                }
 298
 299                /* is it a differential clock scheme ? */
 300                if (!(clk_scheme & PHY_CLK_SCHEME_SEL)) {
 301                        dev_vdbg(&phy->dev, "%s(): select differential clk\n",
 302                                 __func__);
 303                        qphy->has_se_clk_scheme = false;
 304                } else {
 305                        dev_vdbg(&phy->dev, "%s(): select single-ended clk\n",
 306                                 __func__);
 307                }
 308        }
 309
 310        if (!qphy->has_se_clk_scheme) {
 311                val &= ~CLK_REF_SEL;
 312                ret = clk_prepare_enable(qphy->ref_clk);
 313                if (ret) {
 314                        dev_err(&phy->dev, "failed to enable ref clk, %d\n",
 315                                ret);
 316                        goto assert_phy_reset;
 317                }
 318        } else {
 319                val |= CLK_REF_SEL;
 320        }
 321
 322        writel(val, qphy->base + QUSB2PHY_PLL_TEST);
 323
 324        /* ensure above write is through */
 325        readl(qphy->base + QUSB2PHY_PLL_TEST);
 326
 327        /* Required to get phy pll lock successfully */
 328        usleep_range(100, 110);
 329
 330        val = readb(qphy->base + QUSB2PHY_PLL_STATUS);
 331        if (!(val & PLL_LOCKED)) {
 332                dev_err(&phy->dev,
 333                        "QUSB2PHY pll lock failed: status reg = %x\n", val);
 334                ret = -EBUSY;
 335                goto disable_ref_clk;
 336        }
 337
 338        return 0;
 339
 340disable_ref_clk:
 341        if (!qphy->has_se_clk_scheme)
 342                clk_disable_unprepare(qphy->ref_clk);
 343assert_phy_reset:
 344        reset_control_assert(qphy->phy_reset);
 345disable_ahb_clk:
 346        clk_disable_unprepare(qphy->cfg_ahb_clk);
 347        return ret;
 348}
 349
 350static int qusb2_phy_exit(struct phy *phy)
 351{
 352        struct qusb2_phy *qphy = phy_get_drvdata(phy);
 353
 354        /* Disable the PHY */
 355        qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
 356                      CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
 357
 358        if (!qphy->has_se_clk_scheme)
 359                clk_disable_unprepare(qphy->ref_clk);
 360
 361        reset_control_assert(qphy->phy_reset);
 362
 363        clk_disable_unprepare(qphy->cfg_ahb_clk);
 364
 365        return 0;
 366}
 367
 368static const struct phy_ops qusb2_phy_gen_ops = {
 369        .init           = qusb2_phy_init,
 370        .exit           = qusb2_phy_exit,
 371        .power_on       = qusb2_phy_poweron,
 372        .power_off      = qusb2_phy_poweroff,
 373        .owner          = THIS_MODULE,
 374};
 375
 376static const struct of_device_id qusb2_phy_of_match_table[] = {
 377        {
 378                .compatible     = "qcom,msm8996-qusb2-phy",
 379                .data           = &msm8996_phy_cfg,
 380        },
 381        { },
 382};
 383MODULE_DEVICE_TABLE(of, qusb2_phy_of_match_table);
 384
 385static int qusb2_phy_probe(struct platform_device *pdev)
 386{
 387        struct device *dev = &pdev->dev;
 388        struct qusb2_phy *qphy;
 389        struct phy_provider *phy_provider;
 390        struct phy *generic_phy;
 391        struct resource *res;
 392        int ret, i;
 393        int num;
 394
 395        qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
 396        if (!qphy)
 397                return -ENOMEM;
 398
 399        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 400        qphy->base = devm_ioremap_resource(dev, res);
 401        if (IS_ERR(qphy->base))
 402                return PTR_ERR(qphy->base);
 403
 404        qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb");
 405        if (IS_ERR(qphy->cfg_ahb_clk)) {
 406                ret = PTR_ERR(qphy->cfg_ahb_clk);
 407                if (ret != -EPROBE_DEFER)
 408                        dev_err(dev, "failed to get cfg ahb clk, %d\n", ret);
 409                return ret;
 410        }
 411
 412        qphy->ref_clk = devm_clk_get(dev, "ref");
 413        if (IS_ERR(qphy->ref_clk)) {
 414                ret = PTR_ERR(qphy->ref_clk);
 415                if (ret != -EPROBE_DEFER)
 416                        dev_err(dev, "failed to get ref clk, %d\n", ret);
 417                return ret;
 418        }
 419
 420        qphy->iface_clk = devm_clk_get(dev, "iface");
 421        if (IS_ERR(qphy->iface_clk)) {
 422                ret = PTR_ERR(qphy->iface_clk);
 423                if (ret == -EPROBE_DEFER)
 424                        return ret;
 425                qphy->iface_clk = NULL;
 426                dev_dbg(dev, "failed to get iface clk, %d\n", ret);
 427        }
 428
 429        qphy->phy_reset = devm_reset_control_get_by_index(&pdev->dev, 0);
 430        if (IS_ERR(qphy->phy_reset)) {
 431                dev_err(dev, "failed to get phy core reset\n");
 432                return PTR_ERR(qphy->phy_reset);
 433        }
 434
 435        num = ARRAY_SIZE(qphy->vregs);
 436        for (i = 0; i < num; i++)
 437                qphy->vregs[i].supply = qusb2_phy_vreg_names[i];
 438
 439        ret = devm_regulator_bulk_get(dev, num, qphy->vregs);
 440        if (ret) {
 441                dev_err(dev, "failed to get regulator supplies\n");
 442                return ret;
 443        }
 444
 445        /* Get the specific init parameters of QMP phy */
 446        qphy->cfg = of_device_get_match_data(dev);
 447
 448        qphy->tcsr = syscon_regmap_lookup_by_phandle(dev->of_node,
 449                                                        "qcom,tcsr-syscon");
 450        if (IS_ERR(qphy->tcsr)) {
 451                dev_dbg(dev, "failed to lookup TCSR regmap\n");
 452                qphy->tcsr = NULL;
 453        }
 454
 455        qphy->cell = devm_nvmem_cell_get(dev, NULL);
 456        if (IS_ERR(qphy->cell)) {
 457                if (PTR_ERR(qphy->cell) == -EPROBE_DEFER)
 458                        return -EPROBE_DEFER;
 459                qphy->cell = NULL;
 460                dev_dbg(dev, "failed to lookup tune2 hstx trim value\n");
 461        }
 462
 463        generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops);
 464        if (IS_ERR(generic_phy)) {
 465                ret = PTR_ERR(generic_phy);
 466                dev_err(dev, "failed to create phy, %d\n", ret);
 467                return ret;
 468        }
 469        qphy->phy = generic_phy;
 470
 471        dev_set_drvdata(dev, qphy);
 472        phy_set_drvdata(generic_phy, qphy);
 473
 474        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 475        if (!IS_ERR(phy_provider))
 476                dev_info(dev, "Registered Qcom-QUSB2 phy\n");
 477
 478        return PTR_ERR_OR_ZERO(phy_provider);
 479}
 480
 481static struct platform_driver qusb2_phy_driver = {
 482        .probe          = qusb2_phy_probe,
 483        .driver = {
 484                .name   = "qcom-qusb2-phy",
 485                .of_match_table = qusb2_phy_of_match_table,
 486        },
 487};
 488
 489module_platform_driver(qusb2_phy_driver);
 490
 491MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
 492MODULE_DESCRIPTION("Qualcomm QUSB2 PHY driver");
 493MODULE_LICENSE("GPL v2");
 494