linux/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2009-2018, Linux Foundation. All rights reserved.
   4 * Copyright (c) 2018-2020, Linaro Limited
   5 */
   6
   7#include <linux/clk.h>
   8#include <linux/delay.h>
   9#include <linux/io.h>
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/of.h>
  13#include <linux/of_graph.h>
  14#include <linux/phy/phy.h>
  15#include <linux/platform_device.h>
  16#include <linux/regulator/consumer.h>
  17#include <linux/reset.h>
  18#include <linux/slab.h>
  19
  20/* PHY register and bit definitions */
  21#define PHY_CTRL_COMMON0                0x078
  22#define SIDDQ                           BIT(2)
  23#define PHY_IRQ_CMD                     0x0d0
  24#define PHY_INTR_MASK0                  0x0d4
  25#define PHY_INTR_CLEAR0                 0x0dc
  26#define DPDM_MASK                       0x1e
  27#define DP_1_0                          BIT(4)
  28#define DP_0_1                          BIT(3)
  29#define DM_1_0                          BIT(2)
  30#define DM_0_1                          BIT(1)
  31
  32enum hsphy_voltage {
  33        VOL_NONE,
  34        VOL_MIN,
  35        VOL_MAX,
  36        VOL_NUM,
  37};
  38
  39enum hsphy_vreg {
  40        VDD,
  41        VDDA_1P8,
  42        VDDA_3P3,
  43        VREG_NUM,
  44};
  45
  46struct hsphy_init_seq {
  47        int offset;
  48        int val;
  49        int delay;
  50};
  51
  52struct hsphy_data {
  53        const struct hsphy_init_seq *init_seq;
  54        unsigned int init_seq_num;
  55};
  56
  57struct hsphy_priv {
  58        void __iomem *base;
  59        struct clk_bulk_data *clks;
  60        int num_clks;
  61        struct reset_control *phy_reset;
  62        struct reset_control *por_reset;
  63        struct regulator_bulk_data vregs[VREG_NUM];
  64        const struct hsphy_data *data;
  65        enum phy_mode mode;
  66};
  67
  68static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
  69                                    int submode)
  70{
  71        struct hsphy_priv *priv = phy_get_drvdata(phy);
  72
  73        priv->mode = PHY_MODE_INVALID;
  74
  75        if (mode > 0)
  76                priv->mode = mode;
  77
  78        return 0;
  79}
  80
  81static void qcom_snps_hsphy_enable_hv_interrupts(struct hsphy_priv *priv)
  82{
  83        u32 val;
  84
  85        /* Clear any existing interrupts before enabling the interrupts */
  86        val = readb(priv->base + PHY_INTR_CLEAR0);
  87        val |= DPDM_MASK;
  88        writeb(val, priv->base + PHY_INTR_CLEAR0);
  89
  90        writeb(0x0, priv->base + PHY_IRQ_CMD);
  91        usleep_range(200, 220);
  92        writeb(0x1, priv->base + PHY_IRQ_CMD);
  93
  94        /* Make sure the interrupts are cleared */
  95        usleep_range(200, 220);
  96
  97        val = readb(priv->base + PHY_INTR_MASK0);
  98        switch (priv->mode) {
  99        case PHY_MODE_USB_HOST_HS:
 100        case PHY_MODE_USB_HOST_FS:
 101        case PHY_MODE_USB_DEVICE_HS:
 102        case PHY_MODE_USB_DEVICE_FS:
 103                val |= DP_1_0 | DM_0_1;
 104                break;
 105        case PHY_MODE_USB_HOST_LS:
 106        case PHY_MODE_USB_DEVICE_LS:
 107                val |= DP_0_1 | DM_1_0;
 108                break;
 109        default:
 110                /* No device connected */
 111                val |= DP_0_1 | DM_0_1;
 112                break;
 113        }
 114        writeb(val, priv->base + PHY_INTR_MASK0);
 115}
 116
 117static void qcom_snps_hsphy_disable_hv_interrupts(struct hsphy_priv *priv)
 118{
 119        u32 val;
 120
 121        val = readb(priv->base + PHY_INTR_MASK0);
 122        val &= ~DPDM_MASK;
 123        writeb(val, priv->base + PHY_INTR_MASK0);
 124
 125        /* Clear any pending interrupts */
 126        val = readb(priv->base + PHY_INTR_CLEAR0);
 127        val |= DPDM_MASK;
 128        writeb(val, priv->base + PHY_INTR_CLEAR0);
 129
 130        writeb(0x0, priv->base + PHY_IRQ_CMD);
 131        usleep_range(200, 220);
 132
 133        writeb(0x1, priv->base + PHY_IRQ_CMD);
 134        usleep_range(200, 220);
 135}
 136
 137static void qcom_snps_hsphy_enter_retention(struct hsphy_priv *priv)
 138{
 139        u32 val;
 140
 141        val = readb(priv->base + PHY_CTRL_COMMON0);
 142        val |= SIDDQ;
 143        writeb(val, priv->base + PHY_CTRL_COMMON0);
 144}
 145
 146static void qcom_snps_hsphy_exit_retention(struct hsphy_priv *priv)
 147{
 148        u32 val;
 149
 150        val = readb(priv->base + PHY_CTRL_COMMON0);
 151        val &= ~SIDDQ;
 152        writeb(val, priv->base + PHY_CTRL_COMMON0);
 153}
 154
 155static int qcom_snps_hsphy_power_on(struct phy *phy)
 156{
 157        struct hsphy_priv *priv = phy_get_drvdata(phy);
 158        int ret;
 159
 160        ret = regulator_bulk_enable(VREG_NUM, priv->vregs);
 161        if (ret)
 162                return ret;
 163
 164        qcom_snps_hsphy_disable_hv_interrupts(priv);
 165        qcom_snps_hsphy_exit_retention(priv);
 166
 167        return 0;
 168}
 169
 170static int qcom_snps_hsphy_power_off(struct phy *phy)
 171{
 172        struct hsphy_priv *priv = phy_get_drvdata(phy);
 173
 174        qcom_snps_hsphy_enter_retention(priv);
 175        qcom_snps_hsphy_enable_hv_interrupts(priv);
 176        regulator_bulk_disable(VREG_NUM, priv->vregs);
 177
 178        return 0;
 179}
 180
 181static int qcom_snps_hsphy_reset(struct hsphy_priv *priv)
 182{
 183        int ret;
 184
 185        ret = reset_control_assert(priv->phy_reset);
 186        if (ret)
 187                return ret;
 188
 189        usleep_range(10, 15);
 190
 191        ret = reset_control_deassert(priv->phy_reset);
 192        if (ret)
 193                return ret;
 194
 195        usleep_range(80, 100);
 196
 197        return 0;
 198}
 199
 200static void qcom_snps_hsphy_init_sequence(struct hsphy_priv *priv)
 201{
 202        const struct hsphy_data *data = priv->data;
 203        const struct hsphy_init_seq *seq;
 204        int i;
 205
 206        /* Device match data is optional. */
 207        if (!data)
 208                return;
 209
 210        seq = data->init_seq;
 211
 212        for (i = 0; i < data->init_seq_num; i++, seq++) {
 213                writeb(seq->val, priv->base + seq->offset);
 214                if (seq->delay)
 215                        usleep_range(seq->delay, seq->delay + 10);
 216        }
 217}
 218
 219static int qcom_snps_hsphy_por_reset(struct hsphy_priv *priv)
 220{
 221        int ret;
 222
 223        ret = reset_control_assert(priv->por_reset);
 224        if (ret)
 225                return ret;
 226
 227        /*
 228         * The Femto PHY is POR reset in the following scenarios.
 229         *
 230         * 1. After overriding the parameter registers.
 231         * 2. Low power mode exit from PHY retention.
 232         *
 233         * Ensure that SIDDQ is cleared before bringing the PHY
 234         * out of reset.
 235         */
 236        qcom_snps_hsphy_exit_retention(priv);
 237
 238        /*
 239         * As per databook, 10 usec delay is required between
 240         * PHY POR assert and de-assert.
 241         */
 242        usleep_range(10, 20);
 243        ret = reset_control_deassert(priv->por_reset);
 244        if (ret)
 245                return ret;
 246
 247        /*
 248         * As per databook, it takes 75 usec for PHY to stabilize
 249         * after the reset.
 250         */
 251        usleep_range(80, 100);
 252
 253        return 0;
 254}
 255
 256static int qcom_snps_hsphy_init(struct phy *phy)
 257{
 258        struct hsphy_priv *priv = phy_get_drvdata(phy);
 259        int ret;
 260
 261        ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks);
 262        if (ret)
 263                return ret;
 264
 265        ret = qcom_snps_hsphy_reset(priv);
 266        if (ret)
 267                goto disable_clocks;
 268
 269        qcom_snps_hsphy_init_sequence(priv);
 270
 271        ret = qcom_snps_hsphy_por_reset(priv);
 272        if (ret)
 273                goto disable_clocks;
 274
 275        return 0;
 276
 277disable_clocks:
 278        clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
 279        return ret;
 280}
 281
 282static int qcom_snps_hsphy_exit(struct phy *phy)
 283{
 284        struct hsphy_priv *priv = phy_get_drvdata(phy);
 285
 286        clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
 287
 288        return 0;
 289}
 290
 291static const struct phy_ops qcom_snps_hsphy_ops = {
 292        .init = qcom_snps_hsphy_init,
 293        .exit = qcom_snps_hsphy_exit,
 294        .power_on = qcom_snps_hsphy_power_on,
 295        .power_off = qcom_snps_hsphy_power_off,
 296        .set_mode = qcom_snps_hsphy_set_mode,
 297        .owner = THIS_MODULE,
 298};
 299
 300static const char * const qcom_snps_hsphy_clks[] = {
 301        "ref",
 302        "ahb",
 303        "sleep",
 304};
 305
 306static int qcom_snps_hsphy_probe(struct platform_device *pdev)
 307{
 308        struct device *dev = &pdev->dev;
 309        struct phy_provider *provider;
 310        struct hsphy_priv *priv;
 311        struct phy *phy;
 312        int ret;
 313        int i;
 314
 315        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 316        if (!priv)
 317                return -ENOMEM;
 318
 319        priv->base = devm_platform_ioremap_resource(pdev, 0);
 320        if (IS_ERR(priv->base))
 321                return PTR_ERR(priv->base);
 322
 323        priv->num_clks = ARRAY_SIZE(qcom_snps_hsphy_clks);
 324        priv->clks = devm_kcalloc(dev, priv->num_clks, sizeof(*priv->clks),
 325                                  GFP_KERNEL);
 326        if (!priv->clks)
 327                return -ENOMEM;
 328
 329        for (i = 0; i < priv->num_clks; i++)
 330                priv->clks[i].id = qcom_snps_hsphy_clks[i];
 331
 332        ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks);
 333        if (ret)
 334                return ret;
 335
 336        priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
 337        if (IS_ERR(priv->phy_reset))
 338                return PTR_ERR(priv->phy_reset);
 339
 340        priv->por_reset = devm_reset_control_get_exclusive(dev, "por");
 341        if (IS_ERR(priv->por_reset))
 342                return PTR_ERR(priv->por_reset);
 343
 344        priv->vregs[VDD].supply = "vdd";
 345        priv->vregs[VDDA_1P8].supply = "vdda1p8";
 346        priv->vregs[VDDA_3P3].supply = "vdda3p3";
 347
 348        ret = devm_regulator_bulk_get(dev, VREG_NUM, priv->vregs);
 349        if (ret)
 350                return ret;
 351
 352        /* Get device match data */
 353        priv->data = device_get_match_data(dev);
 354
 355        phy = devm_phy_create(dev, dev->of_node, &qcom_snps_hsphy_ops);
 356        if (IS_ERR(phy))
 357                return PTR_ERR(phy);
 358
 359        phy_set_drvdata(phy, priv);
 360
 361        provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 362        if (IS_ERR(provider))
 363                return PTR_ERR(provider);
 364
 365        ret = regulator_set_load(priv->vregs[VDDA_1P8].consumer, 19000);
 366        if (ret < 0)
 367                return ret;
 368
 369        ret = regulator_set_load(priv->vregs[VDDA_3P3].consumer, 16000);
 370        if (ret < 0)
 371                goto unset_1p8_load;
 372
 373        return 0;
 374
 375unset_1p8_load:
 376        regulator_set_load(priv->vregs[VDDA_1P8].consumer, 0);
 377
 378        return ret;
 379}
 380
 381/*
 382 * The macro is used to define an initialization sequence.  Each tuple
 383 * is meant to program 'value' into phy register at 'offset' with 'delay'
 384 * in us followed.
 385 */
 386#define HSPHY_INIT_CFG(o, v, d) { .offset = o, .val = v, .delay = d, }
 387
 388static const struct hsphy_init_seq init_seq_femtophy[] = {
 389        HSPHY_INIT_CFG(0xc0, 0x01, 0),
 390        HSPHY_INIT_CFG(0xe8, 0x0d, 0),
 391        HSPHY_INIT_CFG(0x74, 0x12, 0),
 392        HSPHY_INIT_CFG(0x98, 0x63, 0),
 393        HSPHY_INIT_CFG(0x9c, 0x03, 0),
 394        HSPHY_INIT_CFG(0xa0, 0x1d, 0),
 395        HSPHY_INIT_CFG(0xa4, 0x03, 0),
 396        HSPHY_INIT_CFG(0x8c, 0x23, 0),
 397        HSPHY_INIT_CFG(0x78, 0x08, 0),
 398        HSPHY_INIT_CFG(0x7c, 0xdc, 0),
 399        HSPHY_INIT_CFG(0x90, 0xe0, 20),
 400        HSPHY_INIT_CFG(0x74, 0x10, 0),
 401        HSPHY_INIT_CFG(0x90, 0x60, 0),
 402};
 403
 404static const struct hsphy_init_seq init_seq_mdm9607[] = {
 405        HSPHY_INIT_CFG(0x80, 0x44, 0),
 406        HSPHY_INIT_CFG(0x81, 0x38, 0),
 407        HSPHY_INIT_CFG(0x82, 0x24, 0),
 408        HSPHY_INIT_CFG(0x83, 0x13, 0),
 409};
 410
 411static const struct hsphy_data hsphy_data_femtophy = {
 412        .init_seq = init_seq_femtophy,
 413        .init_seq_num = ARRAY_SIZE(init_seq_femtophy),
 414};
 415
 416static const struct hsphy_data hsphy_data_mdm9607 = {
 417        .init_seq = init_seq_mdm9607,
 418        .init_seq_num = ARRAY_SIZE(init_seq_mdm9607),
 419};
 420
 421static const struct of_device_id qcom_snps_hsphy_match[] = {
 422        { .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, },
 423        { .compatible = "qcom,usb-hs-28nm-mdm9607", .data = &hsphy_data_mdm9607, },
 424        { },
 425};
 426MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match);
 427
 428static struct platform_driver qcom_snps_hsphy_driver = {
 429        .probe = qcom_snps_hsphy_probe,
 430        .driver = {
 431                .name = "qcom,usb-hs-28nm-phy",
 432                .of_match_table = qcom_snps_hsphy_match,
 433        },
 434};
 435module_platform_driver(qcom_snps_hsphy_driver);
 436
 437MODULE_DESCRIPTION("Qualcomm 28nm Hi-Speed USB PHY driver");
 438MODULE_LICENSE("GPL v2");
 439