linux/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2
   3#include <linux/clk.h>
   4#include <linux/err.h>
   5#include <linux/io.h>
   6#include <linux/module.h>
   7#include <linux/of_device.h>
   8#include <linux/phy/phy.h>
   9#include <linux/platform_device.h>
  10#include <linux/delay.h>
  11#include <linux/regmap.h>
  12#include <linux/mfd/syscon.h>
  13
  14/* USB QSCRATCH Hardware registers */
  15#define QSCRATCH_GENERAL_CFG            (0x08)
  16#define HSUSB_PHY_CTRL_REG              (0x10)
  17
  18/* PHY_CTRL_REG */
  19#define HSUSB_CTRL_DMSEHV_CLAMP         BIT(24)
  20#define HSUSB_CTRL_USB2_SUSPEND         BIT(23)
  21#define HSUSB_CTRL_UTMI_CLK_EN          BIT(21)
  22#define HSUSB_CTRL_UTMI_OTG_VBUS_VALID  BIT(20)
  23#define HSUSB_CTRL_USE_CLKCORE          BIT(18)
  24#define HSUSB_CTRL_DPSEHV_CLAMP         BIT(17)
  25#define HSUSB_CTRL_COMMONONN            BIT(11)
  26#define HSUSB_CTRL_ID_HV_CLAMP          BIT(9)
  27#define HSUSB_CTRL_OTGSESSVLD_CLAMP     BIT(8)
  28#define HSUSB_CTRL_CLAMP_EN             BIT(7)
  29#define HSUSB_CTRL_RETENABLEN           BIT(1)
  30#define HSUSB_CTRL_POR                  BIT(0)
  31
  32/* QSCRATCH_GENERAL_CFG */
  33#define HSUSB_GCFG_XHCI_REV             BIT(2)
  34
  35/* USB QSCRATCH Hardware registers */
  36#define SSUSB_PHY_CTRL_REG              (0x00)
  37#define SSUSB_PHY_PARAM_CTRL_1          (0x04)
  38#define SSUSB_PHY_PARAM_CTRL_2          (0x08)
  39#define CR_PROTOCOL_DATA_IN_REG         (0x0c)
  40#define CR_PROTOCOL_DATA_OUT_REG        (0x10)
  41#define CR_PROTOCOL_CAP_ADDR_REG        (0x14)
  42#define CR_PROTOCOL_CAP_DATA_REG        (0x18)
  43#define CR_PROTOCOL_READ_REG            (0x1c)
  44#define CR_PROTOCOL_WRITE_REG           (0x20)
  45
  46/* PHY_CTRL_REG */
  47#define SSUSB_CTRL_REF_USE_PAD          BIT(28)
  48#define SSUSB_CTRL_TEST_POWERDOWN       BIT(27)
  49#define SSUSB_CTRL_LANE0_PWR_PRESENT    BIT(24)
  50#define SSUSB_CTRL_SS_PHY_EN            BIT(8)
  51#define SSUSB_CTRL_SS_PHY_RESET         BIT(7)
  52
  53/* SSPHY control registers - Does this need 0x30? */
  54#define SSPHY_CTRL_RX_OVRD_IN_HI(lane)  (0x1006 + 0x100 * (lane))
  55#define SSPHY_CTRL_TX_OVRD_DRV_LO(lane) (0x1002 + 0x100 * (lane))
  56
  57/* SSPHY SoC version specific values */
  58#define SSPHY_RX_EQ_VALUE               4 /* Override value for rx_eq */
  59/* Override value for transmit preemphasis */
  60#define SSPHY_TX_DEEMPH_3_5DB           23
  61/* Override value for mpll */
  62#define SSPHY_MPLL_VALUE                0
  63
  64/* QSCRATCH PHY_PARAM_CTRL1 fields */
  65#define PHY_PARAM_CTRL1_TX_FULL_SWING_MASK      GENMASK(26, 19)
  66#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK      GENMASK(19, 13)
  67#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK    GENMASK(13, 7)
  68#define PHY_PARAM_CTRL1_LOS_BIAS_MASK           GENMASK(7, 2)
  69
  70#define PHY_PARAM_CTRL1_MASK                            \
  71                (PHY_PARAM_CTRL1_TX_FULL_SWING_MASK |   \
  72                 PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK |   \
  73                 PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK | \
  74                 PHY_PARAM_CTRL1_LOS_BIAS_MASK)
  75
  76#define PHY_PARAM_CTRL1_TX_FULL_SWING(x)        \
  77                (((x) << 20) & PHY_PARAM_CTRL1_TX_FULL_SWING_MASK)
  78#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB(x)        \
  79                (((x) << 14) & PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK)
  80#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(x)      \
  81                (((x) <<  8) & PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK)
  82#define PHY_PARAM_CTRL1_LOS_BIAS(x)     \
  83                (((x) <<  3) & PHY_PARAM_CTRL1_LOS_BIAS_MASK)
  84
  85/* RX OVRD IN HI bits */
  86#define RX_OVRD_IN_HI_RX_RESET_OVRD             BIT(13)
  87#define RX_OVRD_IN_HI_RX_RX_RESET               BIT(12)
  88#define RX_OVRD_IN_HI_RX_EQ_OVRD                BIT(11)
  89#define RX_OVRD_IN_HI_RX_EQ_MASK                GENMASK(10, 7)
  90#define RX_OVRD_IN_HI_RX_EQ(x)                  ((x) << 8)
  91#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD             BIT(7)
  92#define RX_OVRD_IN_HI_RX_EQ_EN                  BIT(6)
  93#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD        BIT(5)
  94#define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK        GENMASK(4, 2)
  95#define RX_OVRD_IN_HI_RX_RATE_OVRD              BIT(2)
  96#define RX_OVRD_IN_HI_RX_RATE_MASK              GENMASK(2, 0)
  97
  98/* TX OVRD DRV LO register bits */
  99#define TX_OVRD_DRV_LO_AMPLITUDE_MASK           GENMASK(6, 0)
 100#define TX_OVRD_DRV_LO_PREEMPH_MASK             GENMASK(13, 6)
 101#define TX_OVRD_DRV_LO_PREEMPH(x)               ((x) << 7)
 102#define TX_OVRD_DRV_LO_EN                       BIT(14)
 103
 104/* MPLL bits */
 105#define SSPHY_MPLL_MASK                         GENMASK(8, 5)
 106#define SSPHY_MPLL(x)                           ((x) << 5)
 107
 108/* SS CAP register bits */
 109#define SS_CR_CAP_ADDR_REG                      BIT(0)
 110#define SS_CR_CAP_DATA_REG                      BIT(0)
 111#define SS_CR_READ_REG                          BIT(0)
 112#define SS_CR_WRITE_REG                         BIT(0)
 113
 114struct usb_phy {
 115        void __iomem            *base;
 116        struct device           *dev;
 117        struct clk              *xo_clk;
 118        struct clk              *ref_clk;
 119        u32                     rx_eq;
 120        u32                     tx_deamp_3_5db;
 121        u32                     mpll;
 122};
 123
 124struct phy_drvdata {
 125        struct phy_ops  ops;
 126        u32             clk_rate;
 127};
 128
 129/**
 130 * usb_phy_write_readback() - Write register and read back masked value to
 131 * confirm it is written
 132 *
 133 * @phy_dwc3: QCOM DWC3 phy context
 134 * @offset: register offset.
 135 * @mask: register bitmask specifying what should be updated
 136 * @val: value to write.
 137 */
 138static inline void usb_phy_write_readback(struct usb_phy *phy_dwc3,
 139                                          u32 offset,
 140                                          const u32 mask, u32 val)
 141{
 142        u32 write_val, tmp = readl(phy_dwc3->base + offset);
 143
 144        tmp &= ~mask;           /* retain other bits */
 145        write_val = tmp | val;
 146
 147        writel(write_val, phy_dwc3->base + offset);
 148
 149        /* Read back to see if val was written */
 150        tmp = readl(phy_dwc3->base + offset);
 151        tmp &= mask;            /* clear other bits */
 152
 153        if (tmp != val)
 154                dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n", val, offset);
 155}
 156
 157static int wait_for_latch(void __iomem *addr)
 158{
 159        u32 retry = 10;
 160
 161        while (true) {
 162                if (!readl(addr))
 163                        break;
 164
 165                if (--retry == 0)
 166                        return -ETIMEDOUT;
 167
 168                usleep_range(10, 20);
 169        }
 170
 171        return 0;
 172}
 173
 174/**
 175 * usb_ss_write_phycreg() - Write SSPHY register
 176 *
 177 * @phy_dwc3: QCOM DWC3 phy context
 178 * @addr: SSPHY address to write.
 179 * @val: value to write.
 180 */
 181static int usb_ss_write_phycreg(struct usb_phy *phy_dwc3,
 182                                u32 addr, u32 val)
 183{
 184        int ret;
 185
 186        writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
 187        writel(SS_CR_CAP_ADDR_REG,
 188               phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
 189
 190        ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
 191        if (ret)
 192                goto err_wait;
 193
 194        writel(val, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
 195        writel(SS_CR_CAP_DATA_REG,
 196               phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
 197
 198        ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
 199        if (ret)
 200                goto err_wait;
 201
 202        writel(SS_CR_WRITE_REG, phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
 203
 204        ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
 205
 206err_wait:
 207        if (ret)
 208                dev_err(phy_dwc3->dev, "timeout waiting for latch\n");
 209        return ret;
 210}
 211
 212/**
 213 * usb_ss_read_phycreg() - Read SSPHY register.
 214 *
 215 * @phy_dwc3: QCOM DWC3 phy context
 216 * @addr: SSPHY address to read.
 217 * @val: pointer in which read is store.
 218 */
 219static int usb_ss_read_phycreg(struct usb_phy *phy_dwc3,
 220                               u32 addr, u32 *val)
 221{
 222        int ret;
 223
 224        writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
 225        writel(SS_CR_CAP_ADDR_REG,
 226               phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
 227
 228        ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
 229        if (ret)
 230                goto err_wait;
 231
 232        /*
 233         * Due to hardware bug, first read of SSPHY register might be
 234         * incorrect. Hence as workaround, SW should perform SSPHY register
 235         * read twice, but use only second read and ignore first read.
 236         */
 237        writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG);
 238
 239        ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG);
 240        if (ret)
 241                goto err_wait;
 242
 243        /* throwaway read */
 244        readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG);
 245
 246        writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG);
 247
 248        ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG);
 249        if (ret)
 250                goto err_wait;
 251
 252        *val = readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG);
 253
 254err_wait:
 255        return ret;
 256}
 257
 258static int qcom_ipq806x_usb_hs_phy_init(struct phy *phy)
 259{
 260        struct usb_phy *phy_dwc3 = phy_get_drvdata(phy);
 261        int ret;
 262        u32 val;
 263
 264        ret = clk_prepare_enable(phy_dwc3->xo_clk);
 265        if (ret)
 266                return ret;
 267
 268        ret = clk_prepare_enable(phy_dwc3->ref_clk);
 269        if (ret) {
 270                clk_disable_unprepare(phy_dwc3->xo_clk);
 271                return ret;
 272        }
 273
 274        /*
 275         * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel
 276         * enable clamping, and disable RETENTION (power-on default is ENABLED)
 277         */
 278        val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP |
 279                HSUSB_CTRL_RETENABLEN  | HSUSB_CTRL_COMMONONN |
 280                HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP |
 281                HSUSB_CTRL_UTMI_OTG_VBUS_VALID | HSUSB_CTRL_UTMI_CLK_EN |
 282                HSUSB_CTRL_CLAMP_EN | 0x70;
 283
 284        /* use core clock if external reference is not present */
 285        if (!phy_dwc3->xo_clk)
 286                val |= HSUSB_CTRL_USE_CLKCORE;
 287
 288        writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG);
 289        usleep_range(2000, 2200);
 290
 291        /* Disable (bypass) VBUS and ID filters */
 292        writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG);
 293
 294        return 0;
 295}
 296
 297static int qcom_ipq806x_usb_hs_phy_exit(struct phy *phy)
 298{
 299        struct usb_phy *phy_dwc3 = phy_get_drvdata(phy);
 300
 301        clk_disable_unprepare(phy_dwc3->ref_clk);
 302        clk_disable_unprepare(phy_dwc3->xo_clk);
 303
 304        return 0;
 305}
 306
 307static int qcom_ipq806x_usb_ss_phy_init(struct phy *phy)
 308{
 309        struct usb_phy *phy_dwc3 = phy_get_drvdata(phy);
 310        int ret;
 311        u32 data;
 312
 313        ret = clk_prepare_enable(phy_dwc3->xo_clk);
 314        if (ret)
 315                return ret;
 316
 317        ret = clk_prepare_enable(phy_dwc3->ref_clk);
 318        if (ret) {
 319                clk_disable_unprepare(phy_dwc3->xo_clk);
 320                return ret;
 321        }
 322
 323        /* reset phy */
 324        data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG);
 325        writel(data | SSUSB_CTRL_SS_PHY_RESET,
 326               phy_dwc3->base + SSUSB_PHY_CTRL_REG);
 327        usleep_range(2000, 2200);
 328        writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
 329
 330        /* clear REF_PAD if we don't have XO clk */
 331        if (!phy_dwc3->xo_clk)
 332                data &= ~SSUSB_CTRL_REF_USE_PAD;
 333        else
 334                data |= SSUSB_CTRL_REF_USE_PAD;
 335
 336        writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
 337
 338        /* wait for ref clk to become stable, this can take up to 30ms */
 339        msleep(30);
 340
 341        data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT;
 342        writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
 343
 344        /*
 345         * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
 346         * in HS mode instead of SS mode. Workaround it by asserting
 347         * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
 348         */
 349        ret = usb_ss_read_phycreg(phy_dwc3, 0x102D, &data);
 350        if (ret)
 351                goto err_phy_trans;
 352
 353        data |= (1 << 7);
 354        ret = usb_ss_write_phycreg(phy_dwc3, 0x102D, data);
 355        if (ret)
 356                goto err_phy_trans;
 357
 358        ret = usb_ss_read_phycreg(phy_dwc3, 0x1010, &data);
 359        if (ret)
 360                goto err_phy_trans;
 361
 362        data &= ~0xff0;
 363        data |= 0x20;
 364        ret = usb_ss_write_phycreg(phy_dwc3, 0x1010, data);
 365        if (ret)
 366                goto err_phy_trans;
 367
 368        /*
 369         * Fix RX Equalization setting as follows
 370         * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
 371         * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
 372         * LANE0.RX_OVRD_IN_HI.RX_EQ set based on SoC version
 373         * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
 374         */
 375        ret = usb_ss_read_phycreg(phy_dwc3, SSPHY_CTRL_RX_OVRD_IN_HI(0), &data);
 376        if (ret)
 377                goto err_phy_trans;
 378
 379        data &= ~RX_OVRD_IN_HI_RX_EQ_EN;
 380        data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD;
 381        data &= ~RX_OVRD_IN_HI_RX_EQ_MASK;
 382        data |= RX_OVRD_IN_HI_RX_EQ(phy_dwc3->rx_eq);
 383        data |= RX_OVRD_IN_HI_RX_EQ_OVRD;
 384        ret = usb_ss_write_phycreg(phy_dwc3,
 385                                   SSPHY_CTRL_RX_OVRD_IN_HI(0), data);
 386        if (ret)
 387                goto err_phy_trans;
 388
 389        /*
 390         * Set EQ and TX launch amplitudes as follows
 391         * LANE0.TX_OVRD_DRV_LO.PREEMPH set based on SoC version
 392         * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 110
 393         * LANE0.TX_OVRD_DRV_LO.EN set to 1.
 394         */
 395        ret = usb_ss_read_phycreg(phy_dwc3,
 396                                  SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data);
 397        if (ret)
 398                goto err_phy_trans;
 399
 400        data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK;
 401        data |= TX_OVRD_DRV_LO_PREEMPH(phy_dwc3->tx_deamp_3_5db);
 402        data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK;
 403        data |= 0x6E;
 404        data |= TX_OVRD_DRV_LO_EN;
 405        ret = usb_ss_write_phycreg(phy_dwc3,
 406                                   SSPHY_CTRL_TX_OVRD_DRV_LO(0), data);
 407        if (ret)
 408                goto err_phy_trans;
 409
 410        data = 0;
 411        data &= ~SSPHY_MPLL_MASK;
 412        data |= SSPHY_MPLL(phy_dwc3->mpll);
 413        usb_ss_write_phycreg(phy_dwc3, 0x30, data);
 414
 415        /*
 416         * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows
 417         * TX_FULL_SWING [26:20] amplitude to 110
 418         * TX_DEEMPH_6DB [19:14] to 32
 419         * TX_DEEMPH_3_5DB [13:8] set based on SoC version
 420         * LOS_BIAS [7:3] to 9
 421         */
 422        data = readl(phy_dwc3->base + SSUSB_PHY_PARAM_CTRL_1);
 423
 424        data &= ~PHY_PARAM_CTRL1_MASK;
 425
 426        data |= PHY_PARAM_CTRL1_TX_FULL_SWING(0x6e) |
 427                PHY_PARAM_CTRL1_TX_DEEMPH_6DB(0x20) |
 428                PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(phy_dwc3->tx_deamp_3_5db) |
 429                PHY_PARAM_CTRL1_LOS_BIAS(0x9);
 430
 431        usb_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1,
 432                               PHY_PARAM_CTRL1_MASK, data);
 433
 434err_phy_trans:
 435        return ret;
 436}
 437
 438static int qcom_ipq806x_usb_ss_phy_exit(struct phy *phy)
 439{
 440        struct usb_phy *phy_dwc3 = phy_get_drvdata(phy);
 441
 442        /* Sequence to put SSPHY in low power state:
 443         * 1. Clear REF_PHY_EN in PHY_CTRL_REG
 444         * 2. Clear REF_USE_PAD in PHY_CTRL_REG
 445         * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention
 446         */
 447        usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
 448                               SSUSB_CTRL_SS_PHY_EN, 0x0);
 449        usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
 450                               SSUSB_CTRL_REF_USE_PAD, 0x0);
 451        usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
 452                               SSUSB_CTRL_TEST_POWERDOWN, 0x0);
 453
 454        clk_disable_unprepare(phy_dwc3->ref_clk);
 455        clk_disable_unprepare(phy_dwc3->xo_clk);
 456
 457        return 0;
 458}
 459
 460static const struct phy_drvdata qcom_ipq806x_usb_hs_drvdata = {
 461        .ops = {
 462                .init           = qcom_ipq806x_usb_hs_phy_init,
 463                .exit           = qcom_ipq806x_usb_hs_phy_exit,
 464                .owner          = THIS_MODULE,
 465        },
 466        .clk_rate = 60000000,
 467};
 468
 469static const struct phy_drvdata qcom_ipq806x_usb_ss_drvdata = {
 470        .ops = {
 471                .init           = qcom_ipq806x_usb_ss_phy_init,
 472                .exit           = qcom_ipq806x_usb_ss_phy_exit,
 473                .owner          = THIS_MODULE,
 474        },
 475        .clk_rate = 125000000,
 476};
 477
 478static const struct of_device_id qcom_ipq806x_usb_phy_table[] = {
 479        { .compatible = "qcom,ipq806x-usb-phy-hs",
 480          .data = &qcom_ipq806x_usb_hs_drvdata },
 481        { .compatible = "qcom,ipq806x-usb-phy-ss",
 482          .data = &qcom_ipq806x_usb_ss_drvdata },
 483        { /* Sentinel */ }
 484};
 485MODULE_DEVICE_TABLE(of, qcom_ipq806x_usb_phy_table);
 486
 487static int qcom_ipq806x_usb_phy_probe(struct platform_device *pdev)
 488{
 489        struct resource *res;
 490        resource_size_t size;
 491        struct phy *generic_phy;
 492        struct usb_phy *phy_dwc3;
 493        const struct phy_drvdata *data;
 494        struct phy_provider *phy_provider;
 495
 496        phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL);
 497        if (!phy_dwc3)
 498                return -ENOMEM;
 499
 500        data = of_device_get_match_data(&pdev->dev);
 501
 502        phy_dwc3->dev = &pdev->dev;
 503
 504        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 505        if (!res)
 506                return -EINVAL;
 507        size = resource_size(res);
 508        phy_dwc3->base = devm_ioremap(phy_dwc3->dev, res->start, size);
 509
 510        if (!phy_dwc3->base) {
 511                dev_err(phy_dwc3->dev, "failed to map reg\n");
 512                return -ENOMEM;
 513        }
 514
 515        phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref");
 516        if (IS_ERR(phy_dwc3->ref_clk)) {
 517                dev_dbg(phy_dwc3->dev, "cannot get reference clock\n");
 518                return PTR_ERR(phy_dwc3->ref_clk);
 519        }
 520
 521        clk_set_rate(phy_dwc3->ref_clk, data->clk_rate);
 522
 523        phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo");
 524        if (IS_ERR(phy_dwc3->xo_clk)) {
 525                dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n");
 526                phy_dwc3->xo_clk = NULL;
 527        }
 528
 529        /* Parse device node to probe HSIO settings */
 530        if (device_property_read_u32(&pdev->dev, "qcom,rx-eq",
 531                                     &phy_dwc3->rx_eq))
 532                phy_dwc3->rx_eq = SSPHY_RX_EQ_VALUE;
 533
 534        if (device_property_read_u32(&pdev->dev, "qcom,tx-deamp_3_5db",
 535                                     &phy_dwc3->tx_deamp_3_5db))
 536                phy_dwc3->tx_deamp_3_5db = SSPHY_TX_DEEMPH_3_5DB;
 537
 538        if (device_property_read_u32(&pdev->dev, "qcom,mpll", &phy_dwc3->mpll))
 539                phy_dwc3->mpll = SSPHY_MPLL_VALUE;
 540
 541        generic_phy = devm_phy_create(phy_dwc3->dev, pdev->dev.of_node, &data->ops);
 542
 543        if (IS_ERR(generic_phy))
 544                return PTR_ERR(generic_phy);
 545
 546        phy_set_drvdata(generic_phy, phy_dwc3);
 547        platform_set_drvdata(pdev, phy_dwc3);
 548
 549        phy_provider = devm_of_phy_provider_register(phy_dwc3->dev,
 550                                                     of_phy_simple_xlate);
 551
 552        if (IS_ERR(phy_provider))
 553                return PTR_ERR(phy_provider);
 554
 555        return 0;
 556}
 557
 558static struct platform_driver qcom_ipq806x_usb_phy_driver = {
 559        .probe          = qcom_ipq806x_usb_phy_probe,
 560        .driver         = {
 561                .name   = "qcom-ipq806x-usb-phy",
 562                .of_match_table = qcom_ipq806x_usb_phy_table,
 563        },
 564};
 565
 566module_platform_driver(qcom_ipq806x_usb_phy_driver);
 567
 568MODULE_ALIAS("platform:phy-qcom-ipq806x-usb");
 569MODULE_LICENSE("GPL v2");
 570MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
 571MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
 572MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver");
 573