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