Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include <linux/clk.h>
0004 #include <linux/err.h>
0005 #include <linux/io.h>
0006 #include <linux/module.h>
0007 #include <linux/of_device.h>
0008 #include <linux/phy/phy.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/delay.h>
0011 #include <linux/regmap.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/bitfield.h>
0014 
0015 /* USB QSCRATCH Hardware registers */
0016 #define QSCRATCH_GENERAL_CFG        (0x08)
0017 #define HSUSB_PHY_CTRL_REG      (0x10)
0018 
0019 /* PHY_CTRL_REG */
0020 #define HSUSB_CTRL_DMSEHV_CLAMP     BIT(24)
0021 #define HSUSB_CTRL_USB2_SUSPEND     BIT(23)
0022 #define HSUSB_CTRL_UTMI_CLK_EN      BIT(21)
0023 #define HSUSB_CTRL_UTMI_OTG_VBUS_VALID  BIT(20)
0024 #define HSUSB_CTRL_USE_CLKCORE      BIT(18)
0025 #define HSUSB_CTRL_DPSEHV_CLAMP     BIT(17)
0026 #define HSUSB_CTRL_COMMONONN        BIT(11)
0027 #define HSUSB_CTRL_ID_HV_CLAMP      BIT(9)
0028 #define HSUSB_CTRL_OTGSESSVLD_CLAMP BIT(8)
0029 #define HSUSB_CTRL_CLAMP_EN     BIT(7)
0030 #define HSUSB_CTRL_RETENABLEN       BIT(1)
0031 #define HSUSB_CTRL_POR          BIT(0)
0032 
0033 /* QSCRATCH_GENERAL_CFG */
0034 #define HSUSB_GCFG_XHCI_REV     BIT(2)
0035 
0036 /* USB QSCRATCH Hardware registers */
0037 #define SSUSB_PHY_CTRL_REG      (0x00)
0038 #define SSUSB_PHY_PARAM_CTRL_1      (0x04)
0039 #define SSUSB_PHY_PARAM_CTRL_2      (0x08)
0040 #define CR_PROTOCOL_DATA_IN_REG     (0x0c)
0041 #define CR_PROTOCOL_DATA_OUT_REG    (0x10)
0042 #define CR_PROTOCOL_CAP_ADDR_REG    (0x14)
0043 #define CR_PROTOCOL_CAP_DATA_REG    (0x18)
0044 #define CR_PROTOCOL_READ_REG        (0x1c)
0045 #define CR_PROTOCOL_WRITE_REG       (0x20)
0046 
0047 /* PHY_CTRL_REG */
0048 #define SSUSB_CTRL_REF_USE_PAD      BIT(28)
0049 #define SSUSB_CTRL_TEST_POWERDOWN   BIT(27)
0050 #define SSUSB_CTRL_LANE0_PWR_PRESENT    BIT(24)
0051 #define SSUSB_CTRL_SS_PHY_EN        BIT(8)
0052 #define SSUSB_CTRL_SS_PHY_RESET     BIT(7)
0053 
0054 /* SSPHY control registers - Does this need 0x30? */
0055 #define SSPHY_CTRL_RX_OVRD_IN_HI(lane)  (0x1006 + 0x100 * (lane))
0056 #define SSPHY_CTRL_TX_OVRD_DRV_LO(lane) (0x1002 + 0x100 * (lane))
0057 
0058 /* SSPHY SoC version specific values */
0059 #define SSPHY_RX_EQ_VALUE       4 /* Override value for rx_eq */
0060 /* Override value for transmit preemphasis */
0061 #define SSPHY_TX_DEEMPH_3_5DB       23
0062 /* Override value for mpll */
0063 #define SSPHY_MPLL_VALUE        0
0064 
0065 /* QSCRATCH PHY_PARAM_CTRL1 fields */
0066 #define PHY_PARAM_CTRL1_TX_FULL_SWING_MASK  GENMASK(26, 19)
0067 #define PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK  GENMASK(19, 13)
0068 #define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK    GENMASK(13, 7)
0069 #define PHY_PARAM_CTRL1_LOS_BIAS_MASK       GENMASK(7, 2)
0070 
0071 #define PHY_PARAM_CTRL1_MASK                \
0072         (PHY_PARAM_CTRL1_TX_FULL_SWING_MASK |   \
0073          PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK |   \
0074          PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK | \
0075          PHY_PARAM_CTRL1_LOS_BIAS_MASK)
0076 
0077 #define PHY_PARAM_CTRL1_TX_FULL_SWING(x)    \
0078         FIELD_PREP(PHY_PARAM_CTRL1_TX_FULL_SWING_MASK, (x))
0079 #define PHY_PARAM_CTRL1_TX_DEEMPH_6DB(x)    \
0080         FIELD_PREP(PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK, (x))
0081 #define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(x)  \
0082         FIELD_PREP(PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK, x)
0083 #define PHY_PARAM_CTRL1_LOS_BIAS(x) \
0084         FIELD_PREP(PHY_PARAM_CTRL1_LOS_BIAS_MASK, (x))
0085 
0086 /* RX OVRD IN HI bits */
0087 #define RX_OVRD_IN_HI_RX_RESET_OVRD     BIT(13)
0088 #define RX_OVRD_IN_HI_RX_RX_RESET       BIT(12)
0089 #define RX_OVRD_IN_HI_RX_EQ_OVRD        BIT(11)
0090 #define RX_OVRD_IN_HI_RX_EQ_MASK        GENMASK(10, 7)
0091 #define RX_OVRD_IN_HI_RX_EQ(x)          FIELD_PREP(RX_OVRD_IN_HI_RX_EQ_MASK, (x))
0092 #define RX_OVRD_IN_HI_RX_EQ_EN_OVRD     BIT(7)
0093 #define RX_OVRD_IN_HI_RX_EQ_EN          BIT(6)
0094 #define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD    BIT(5)
0095 #define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK    GENMASK(4, 2)
0096 #define RX_OVRD_IN_HI_RX_RATE_OVRD      BIT(2)
0097 #define RX_OVRD_IN_HI_RX_RATE_MASK      GENMASK(2, 0)
0098 
0099 /* TX OVRD DRV LO register bits */
0100 #define TX_OVRD_DRV_LO_AMPLITUDE_MASK       GENMASK(6, 0)
0101 #define TX_OVRD_DRV_LO_PREEMPH_MASK     GENMASK(13, 6)
0102 #define TX_OVRD_DRV_LO_PREEMPH(x)       ((x) << 7)
0103 #define TX_OVRD_DRV_LO_EN           BIT(14)
0104 
0105 /* MPLL bits */
0106 #define SSPHY_MPLL_MASK             GENMASK(8, 5)
0107 #define SSPHY_MPLL(x)               ((x) << 5)
0108 
0109 /* SS CAP register bits */
0110 #define SS_CR_CAP_ADDR_REG          BIT(0)
0111 #define SS_CR_CAP_DATA_REG          BIT(0)
0112 #define SS_CR_READ_REG              BIT(0)
0113 #define SS_CR_WRITE_REG             BIT(0)
0114 
0115 #define LATCH_SLEEP             40
0116 #define LATCH_TIMEOUT               100
0117 
0118 struct usb_phy {
0119     void __iomem        *base;
0120     struct device       *dev;
0121     struct clk      *xo_clk;
0122     struct clk      *ref_clk;
0123     u32         rx_eq;
0124     u32         tx_deamp_3_5db;
0125     u32         mpll;
0126 };
0127 
0128 struct phy_drvdata {
0129     struct phy_ops  ops;
0130     u32     clk_rate;
0131 };
0132 
0133 /**
0134  * usb_phy_write_readback() - Write register and read back masked value to
0135  * confirm it is written
0136  *
0137  * @phy_dwc3: QCOM DWC3 phy context
0138  * @offset: register offset.
0139  * @mask: register bitmask specifying what should be updated
0140  * @val: value to write.
0141  */
0142 static inline void usb_phy_write_readback(struct usb_phy *phy_dwc3,
0143                       u32 offset,
0144                       const u32 mask, u32 val)
0145 {
0146     u32 write_val, tmp = readl(phy_dwc3->base + offset);
0147 
0148     tmp &= ~mask;       /* retain other bits */
0149     write_val = tmp | val;
0150 
0151     writel(write_val, phy_dwc3->base + offset);
0152 
0153     /* Read back to see if val was written */
0154     tmp = readl(phy_dwc3->base + offset);
0155     tmp &= mask;        /* clear other bits */
0156 
0157     if (tmp != val)
0158         dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n", val, offset);
0159 }
0160 
0161 static int wait_for_latch(void __iomem *addr)
0162 {
0163     u32 val;
0164 
0165     return readl_poll_timeout(addr, val, !val, LATCH_SLEEP, LATCH_TIMEOUT);
0166 }
0167 
0168 /**
0169  * usb_ss_write_phycreg() - Write SSPHY register
0170  *
0171  * @phy_dwc3: QCOM DWC3 phy context
0172  * @addr: SSPHY address to write.
0173  * @val: value to write.
0174  */
0175 static int usb_ss_write_phycreg(struct usb_phy *phy_dwc3,
0176                 u32 addr, u32 val)
0177 {
0178     int ret;
0179 
0180     writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
0181     writel(SS_CR_CAP_ADDR_REG,
0182            phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
0183 
0184     ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
0185     if (ret)
0186         goto err_wait;
0187 
0188     writel(val, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
0189     writel(SS_CR_CAP_DATA_REG,
0190            phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
0191 
0192     ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
0193     if (ret)
0194         goto err_wait;
0195 
0196     writel(SS_CR_WRITE_REG, phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
0197 
0198     ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
0199 
0200 err_wait:
0201     if (ret)
0202         dev_err(phy_dwc3->dev, "timeout waiting for latch\n");
0203     return ret;
0204 }
0205 
0206 /**
0207  * usb_ss_read_phycreg() - Read SSPHY register.
0208  *
0209  * @phy_dwc3: QCOM DWC3 phy context
0210  * @addr: SSPHY address to read.
0211  * @val: pointer in which read is store.
0212  */
0213 static int usb_ss_read_phycreg(struct usb_phy *phy_dwc3,
0214                    u32 addr, u32 *val)
0215 {
0216     int ret;
0217 
0218     writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
0219     writel(SS_CR_CAP_ADDR_REG,
0220            phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
0221 
0222     ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
0223     if (ret)
0224         goto err_wait;
0225 
0226     /*
0227      * Due to hardware bug, first read of SSPHY register might be
0228      * incorrect. Hence as workaround, SW should perform SSPHY register
0229      * read twice, but use only second read and ignore first read.
0230      */
0231     writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG);
0232 
0233     ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG);
0234     if (ret)
0235         goto err_wait;
0236 
0237     /* throwaway read */
0238     readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG);
0239 
0240     writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG);
0241 
0242     ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG);
0243     if (ret)
0244         goto err_wait;
0245 
0246     *val = readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG);
0247 
0248 err_wait:
0249     return ret;
0250 }
0251 
0252 static int qcom_ipq806x_usb_hs_phy_init(struct phy *phy)
0253 {
0254     struct usb_phy *phy_dwc3 = phy_get_drvdata(phy);
0255     int ret;
0256     u32 val;
0257 
0258     ret = clk_prepare_enable(phy_dwc3->xo_clk);
0259     if (ret)
0260         return ret;
0261 
0262     ret = clk_prepare_enable(phy_dwc3->ref_clk);
0263     if (ret) {
0264         clk_disable_unprepare(phy_dwc3->xo_clk);
0265         return ret;
0266     }
0267 
0268     /*
0269      * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel
0270      * enable clamping, and disable RETENTION (power-on default is ENABLED)
0271      */
0272     val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP |
0273         HSUSB_CTRL_RETENABLEN  | HSUSB_CTRL_COMMONONN |
0274         HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP |
0275         HSUSB_CTRL_UTMI_OTG_VBUS_VALID | HSUSB_CTRL_UTMI_CLK_EN |
0276         HSUSB_CTRL_CLAMP_EN | 0x70;
0277 
0278     /* use core clock if external reference is not present */
0279     if (!phy_dwc3->xo_clk)
0280         val |= HSUSB_CTRL_USE_CLKCORE;
0281 
0282     writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG);
0283     usleep_range(2000, 2200);
0284 
0285     /* Disable (bypass) VBUS and ID filters */
0286     writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG);
0287 
0288     return 0;
0289 }
0290 
0291 static int qcom_ipq806x_usb_hs_phy_exit(struct phy *phy)
0292 {
0293     struct usb_phy *phy_dwc3 = phy_get_drvdata(phy);
0294 
0295     clk_disable_unprepare(phy_dwc3->ref_clk);
0296     clk_disable_unprepare(phy_dwc3->xo_clk);
0297 
0298     return 0;
0299 }
0300 
0301 static int qcom_ipq806x_usb_ss_phy_init(struct phy *phy)
0302 {
0303     struct usb_phy *phy_dwc3 = phy_get_drvdata(phy);
0304     int ret;
0305     u32 data;
0306 
0307     ret = clk_prepare_enable(phy_dwc3->xo_clk);
0308     if (ret)
0309         return ret;
0310 
0311     ret = clk_prepare_enable(phy_dwc3->ref_clk);
0312     if (ret) {
0313         clk_disable_unprepare(phy_dwc3->xo_clk);
0314         return ret;
0315     }
0316 
0317     /* reset phy */
0318     data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG);
0319     writel(data | SSUSB_CTRL_SS_PHY_RESET,
0320            phy_dwc3->base + SSUSB_PHY_CTRL_REG);
0321     usleep_range(2000, 2200);
0322     writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
0323 
0324     /* clear REF_PAD if we don't have XO clk */
0325     if (!phy_dwc3->xo_clk)
0326         data &= ~SSUSB_CTRL_REF_USE_PAD;
0327     else
0328         data |= SSUSB_CTRL_REF_USE_PAD;
0329 
0330     writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
0331 
0332     /* wait for ref clk to become stable, this can take up to 30ms */
0333     msleep(30);
0334 
0335     data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT;
0336     writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
0337 
0338     /*
0339      * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
0340      * in HS mode instead of SS mode. Workaround it by asserting
0341      * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
0342      */
0343     ret = usb_ss_read_phycreg(phy_dwc3, 0x102D, &data);
0344     if (ret)
0345         goto err_phy_trans;
0346 
0347     data |= (1 << 7);
0348     ret = usb_ss_write_phycreg(phy_dwc3, 0x102D, data);
0349     if (ret)
0350         goto err_phy_trans;
0351 
0352     ret = usb_ss_read_phycreg(phy_dwc3, 0x1010, &data);
0353     if (ret)
0354         goto err_phy_trans;
0355 
0356     data &= ~0xff0;
0357     data |= 0x20;
0358     ret = usb_ss_write_phycreg(phy_dwc3, 0x1010, data);
0359     if (ret)
0360         goto err_phy_trans;
0361 
0362     /*
0363      * Fix RX Equalization setting as follows
0364      * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
0365      * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
0366      * LANE0.RX_OVRD_IN_HI.RX_EQ set based on SoC version
0367      * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
0368      */
0369     ret = usb_ss_read_phycreg(phy_dwc3, SSPHY_CTRL_RX_OVRD_IN_HI(0), &data);
0370     if (ret)
0371         goto err_phy_trans;
0372 
0373     data &= ~RX_OVRD_IN_HI_RX_EQ_EN;
0374     data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD;
0375     data &= ~RX_OVRD_IN_HI_RX_EQ_MASK;
0376     data |= RX_OVRD_IN_HI_RX_EQ(phy_dwc3->rx_eq);
0377     data |= RX_OVRD_IN_HI_RX_EQ_OVRD;
0378     ret = usb_ss_write_phycreg(phy_dwc3,
0379                    SSPHY_CTRL_RX_OVRD_IN_HI(0), data);
0380     if (ret)
0381         goto err_phy_trans;
0382 
0383     /*
0384      * Set EQ and TX launch amplitudes as follows
0385      * LANE0.TX_OVRD_DRV_LO.PREEMPH set based on SoC version
0386      * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 110
0387      * LANE0.TX_OVRD_DRV_LO.EN set to 1.
0388      */
0389     ret = usb_ss_read_phycreg(phy_dwc3,
0390                   SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data);
0391     if (ret)
0392         goto err_phy_trans;
0393 
0394     data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK;
0395     data |= TX_OVRD_DRV_LO_PREEMPH(phy_dwc3->tx_deamp_3_5db);
0396     data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK;
0397     data |= 0x6E;
0398     data |= TX_OVRD_DRV_LO_EN;
0399     ret = usb_ss_write_phycreg(phy_dwc3,
0400                    SSPHY_CTRL_TX_OVRD_DRV_LO(0), data);
0401     if (ret)
0402         goto err_phy_trans;
0403 
0404     data = 0;
0405     data &= ~SSPHY_MPLL_MASK;
0406     data |= SSPHY_MPLL(phy_dwc3->mpll);
0407     usb_ss_write_phycreg(phy_dwc3, 0x30, data);
0408 
0409     /*
0410      * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows
0411      * TX_FULL_SWING [26:20] amplitude to 110
0412      * TX_DEEMPH_6DB [19:14] to 32
0413      * TX_DEEMPH_3_5DB [13:8] set based on SoC version
0414      * LOS_BIAS [7:3] to 9
0415      */
0416     data = readl(phy_dwc3->base + SSUSB_PHY_PARAM_CTRL_1);
0417 
0418     data &= ~PHY_PARAM_CTRL1_MASK;
0419 
0420     data |= PHY_PARAM_CTRL1_TX_FULL_SWING(0x6e) |
0421         PHY_PARAM_CTRL1_TX_DEEMPH_6DB(0x20) |
0422         PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(phy_dwc3->tx_deamp_3_5db) |
0423         PHY_PARAM_CTRL1_LOS_BIAS(0x9);
0424 
0425     usb_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1,
0426                    PHY_PARAM_CTRL1_MASK, data);
0427 
0428 err_phy_trans:
0429     return ret;
0430 }
0431 
0432 static int qcom_ipq806x_usb_ss_phy_exit(struct phy *phy)
0433 {
0434     struct usb_phy *phy_dwc3 = phy_get_drvdata(phy);
0435 
0436     /* Sequence to put SSPHY in low power state:
0437      * 1. Clear REF_PHY_EN in PHY_CTRL_REG
0438      * 2. Clear REF_USE_PAD in PHY_CTRL_REG
0439      * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention
0440      */
0441     usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
0442                    SSUSB_CTRL_SS_PHY_EN, 0x0);
0443     usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
0444                    SSUSB_CTRL_REF_USE_PAD, 0x0);
0445     usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
0446                    SSUSB_CTRL_TEST_POWERDOWN, 0x0);
0447 
0448     clk_disable_unprepare(phy_dwc3->ref_clk);
0449     clk_disable_unprepare(phy_dwc3->xo_clk);
0450 
0451     return 0;
0452 }
0453 
0454 static const struct phy_drvdata qcom_ipq806x_usb_hs_drvdata = {
0455     .ops = {
0456         .init       = qcom_ipq806x_usb_hs_phy_init,
0457         .exit       = qcom_ipq806x_usb_hs_phy_exit,
0458         .owner      = THIS_MODULE,
0459     },
0460     .clk_rate = 60000000,
0461 };
0462 
0463 static const struct phy_drvdata qcom_ipq806x_usb_ss_drvdata = {
0464     .ops = {
0465         .init       = qcom_ipq806x_usb_ss_phy_init,
0466         .exit       = qcom_ipq806x_usb_ss_phy_exit,
0467         .owner      = THIS_MODULE,
0468     },
0469     .clk_rate = 125000000,
0470 };
0471 
0472 static const struct of_device_id qcom_ipq806x_usb_phy_table[] = {
0473     { .compatible = "qcom,ipq806x-usb-phy-hs",
0474       .data = &qcom_ipq806x_usb_hs_drvdata },
0475     { .compatible = "qcom,ipq806x-usb-phy-ss",
0476       .data = &qcom_ipq806x_usb_ss_drvdata },
0477     { /* Sentinel */ }
0478 };
0479 MODULE_DEVICE_TABLE(of, qcom_ipq806x_usb_phy_table);
0480 
0481 static int qcom_ipq806x_usb_phy_probe(struct platform_device *pdev)
0482 {
0483     struct resource *res;
0484     resource_size_t size;
0485     struct phy *generic_phy;
0486     struct usb_phy *phy_dwc3;
0487     const struct phy_drvdata *data;
0488     struct phy_provider *phy_provider;
0489 
0490     phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL);
0491     if (!phy_dwc3)
0492         return -ENOMEM;
0493 
0494     data = of_device_get_match_data(&pdev->dev);
0495 
0496     phy_dwc3->dev = &pdev->dev;
0497 
0498     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0499     if (!res)
0500         return -EINVAL;
0501     size = resource_size(res);
0502     phy_dwc3->base = devm_ioremap(phy_dwc3->dev, res->start, size);
0503 
0504     if (!phy_dwc3->base) {
0505         dev_err(phy_dwc3->dev, "failed to map reg\n");
0506         return -ENOMEM;
0507     }
0508 
0509     phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref");
0510     if (IS_ERR(phy_dwc3->ref_clk)) {
0511         dev_dbg(phy_dwc3->dev, "cannot get reference clock\n");
0512         return PTR_ERR(phy_dwc3->ref_clk);
0513     }
0514 
0515     clk_set_rate(phy_dwc3->ref_clk, data->clk_rate);
0516 
0517     phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo");
0518     if (IS_ERR(phy_dwc3->xo_clk)) {
0519         dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n");
0520         phy_dwc3->xo_clk = NULL;
0521     }
0522 
0523     /* Parse device node to probe HSIO settings */
0524     if (device_property_read_u32(&pdev->dev, "qcom,rx-eq",
0525                      &phy_dwc3->rx_eq))
0526         phy_dwc3->rx_eq = SSPHY_RX_EQ_VALUE;
0527 
0528     if (device_property_read_u32(&pdev->dev, "qcom,tx-deamp_3_5db",
0529                      &phy_dwc3->tx_deamp_3_5db))
0530         phy_dwc3->tx_deamp_3_5db = SSPHY_TX_DEEMPH_3_5DB;
0531 
0532     if (device_property_read_u32(&pdev->dev, "qcom,mpll", &phy_dwc3->mpll))
0533         phy_dwc3->mpll = SSPHY_MPLL_VALUE;
0534 
0535     generic_phy = devm_phy_create(phy_dwc3->dev, pdev->dev.of_node, &data->ops);
0536 
0537     if (IS_ERR(generic_phy))
0538         return PTR_ERR(generic_phy);
0539 
0540     phy_set_drvdata(generic_phy, phy_dwc3);
0541     platform_set_drvdata(pdev, phy_dwc3);
0542 
0543     phy_provider = devm_of_phy_provider_register(phy_dwc3->dev,
0544                              of_phy_simple_xlate);
0545 
0546     if (IS_ERR(phy_provider))
0547         return PTR_ERR(phy_provider);
0548 
0549     return 0;
0550 }
0551 
0552 static struct platform_driver qcom_ipq806x_usb_phy_driver = {
0553     .probe      = qcom_ipq806x_usb_phy_probe,
0554     .driver     = {
0555         .name   = "qcom-ipq806x-usb-phy",
0556         .of_match_table = qcom_ipq806x_usb_phy_table,
0557     },
0558 };
0559 
0560 module_platform_driver(qcom_ipq806x_usb_phy_driver);
0561 
0562 MODULE_ALIAS("platform:phy-qcom-ipq806x-usb");
0563 MODULE_LICENSE("GPL v2");
0564 MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
0565 MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
0566 MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver");