0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/of_graph.h>
0014 #include <linux/phy/phy.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regulator/consumer.h>
0017 #include <linux/reset.h>
0018 #include <linux/slab.h>
0019
0020
0021 #define PHY_CTRL_COMMON0 0x078
0022 #define SIDDQ BIT(2)
0023 #define PHY_IRQ_CMD 0x0d0
0024 #define PHY_INTR_MASK0 0x0d4
0025 #define PHY_INTR_CLEAR0 0x0dc
0026 #define DPDM_MASK 0x1e
0027 #define DP_1_0 BIT(4)
0028 #define DP_0_1 BIT(3)
0029 #define DM_1_0 BIT(2)
0030 #define DM_0_1 BIT(1)
0031
0032 enum hsphy_voltage {
0033 VOL_NONE,
0034 VOL_MIN,
0035 VOL_MAX,
0036 VOL_NUM,
0037 };
0038
0039 enum hsphy_vreg {
0040 VDD,
0041 VDDA_1P8,
0042 VDDA_3P3,
0043 VREG_NUM,
0044 };
0045
0046 struct hsphy_init_seq {
0047 int offset;
0048 int val;
0049 int delay;
0050 };
0051
0052 struct hsphy_data {
0053 const struct hsphy_init_seq *init_seq;
0054 unsigned int init_seq_num;
0055 };
0056
0057 struct hsphy_priv {
0058 void __iomem *base;
0059 struct clk_bulk_data *clks;
0060 int num_clks;
0061 struct reset_control *phy_reset;
0062 struct reset_control *por_reset;
0063 struct regulator_bulk_data vregs[VREG_NUM];
0064 const struct hsphy_data *data;
0065 enum phy_mode mode;
0066 };
0067
0068 static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
0069 int submode)
0070 {
0071 struct hsphy_priv *priv = phy_get_drvdata(phy);
0072
0073 priv->mode = PHY_MODE_INVALID;
0074
0075 if (mode > 0)
0076 priv->mode = mode;
0077
0078 return 0;
0079 }
0080
0081 static void qcom_snps_hsphy_enable_hv_interrupts(struct hsphy_priv *priv)
0082 {
0083 u32 val;
0084
0085
0086 val = readb(priv->base + PHY_INTR_CLEAR0);
0087 val |= DPDM_MASK;
0088 writeb(val, priv->base + PHY_INTR_CLEAR0);
0089
0090 writeb(0x0, priv->base + PHY_IRQ_CMD);
0091 usleep_range(200, 220);
0092 writeb(0x1, priv->base + PHY_IRQ_CMD);
0093
0094
0095 usleep_range(200, 220);
0096
0097 val = readb(priv->base + PHY_INTR_MASK0);
0098 switch (priv->mode) {
0099 case PHY_MODE_USB_HOST_HS:
0100 case PHY_MODE_USB_HOST_FS:
0101 case PHY_MODE_USB_DEVICE_HS:
0102 case PHY_MODE_USB_DEVICE_FS:
0103 val |= DP_1_0 | DM_0_1;
0104 break;
0105 case PHY_MODE_USB_HOST_LS:
0106 case PHY_MODE_USB_DEVICE_LS:
0107 val |= DP_0_1 | DM_1_0;
0108 break;
0109 default:
0110
0111 val |= DP_0_1 | DM_0_1;
0112 break;
0113 }
0114 writeb(val, priv->base + PHY_INTR_MASK0);
0115 }
0116
0117 static void qcom_snps_hsphy_disable_hv_interrupts(struct hsphy_priv *priv)
0118 {
0119 u32 val;
0120
0121 val = readb(priv->base + PHY_INTR_MASK0);
0122 val &= ~DPDM_MASK;
0123 writeb(val, priv->base + PHY_INTR_MASK0);
0124
0125
0126 val = readb(priv->base + PHY_INTR_CLEAR0);
0127 val |= DPDM_MASK;
0128 writeb(val, priv->base + PHY_INTR_CLEAR0);
0129
0130 writeb(0x0, priv->base + PHY_IRQ_CMD);
0131 usleep_range(200, 220);
0132
0133 writeb(0x1, priv->base + PHY_IRQ_CMD);
0134 usleep_range(200, 220);
0135 }
0136
0137 static void qcom_snps_hsphy_enter_retention(struct hsphy_priv *priv)
0138 {
0139 u32 val;
0140
0141 val = readb(priv->base + PHY_CTRL_COMMON0);
0142 val |= SIDDQ;
0143 writeb(val, priv->base + PHY_CTRL_COMMON0);
0144 }
0145
0146 static void qcom_snps_hsphy_exit_retention(struct hsphy_priv *priv)
0147 {
0148 u32 val;
0149
0150 val = readb(priv->base + PHY_CTRL_COMMON0);
0151 val &= ~SIDDQ;
0152 writeb(val, priv->base + PHY_CTRL_COMMON0);
0153 }
0154
0155 static int qcom_snps_hsphy_power_on(struct phy *phy)
0156 {
0157 struct hsphy_priv *priv = phy_get_drvdata(phy);
0158 int ret;
0159
0160 ret = regulator_bulk_enable(VREG_NUM, priv->vregs);
0161 if (ret)
0162 return ret;
0163
0164 qcom_snps_hsphy_disable_hv_interrupts(priv);
0165 qcom_snps_hsphy_exit_retention(priv);
0166
0167 return 0;
0168 }
0169
0170 static int qcom_snps_hsphy_power_off(struct phy *phy)
0171 {
0172 struct hsphy_priv *priv = phy_get_drvdata(phy);
0173
0174 qcom_snps_hsphy_enter_retention(priv);
0175 qcom_snps_hsphy_enable_hv_interrupts(priv);
0176 regulator_bulk_disable(VREG_NUM, priv->vregs);
0177
0178 return 0;
0179 }
0180
0181 static int qcom_snps_hsphy_reset(struct hsphy_priv *priv)
0182 {
0183 int ret;
0184
0185 ret = reset_control_assert(priv->phy_reset);
0186 if (ret)
0187 return ret;
0188
0189 usleep_range(10, 15);
0190
0191 ret = reset_control_deassert(priv->phy_reset);
0192 if (ret)
0193 return ret;
0194
0195 usleep_range(80, 100);
0196
0197 return 0;
0198 }
0199
0200 static void qcom_snps_hsphy_init_sequence(struct hsphy_priv *priv)
0201 {
0202 const struct hsphy_data *data = priv->data;
0203 const struct hsphy_init_seq *seq;
0204 int i;
0205
0206
0207 if (!data)
0208 return;
0209
0210 seq = data->init_seq;
0211
0212 for (i = 0; i < data->init_seq_num; i++, seq++) {
0213 writeb(seq->val, priv->base + seq->offset);
0214 if (seq->delay)
0215 usleep_range(seq->delay, seq->delay + 10);
0216 }
0217 }
0218
0219 static int qcom_snps_hsphy_por_reset(struct hsphy_priv *priv)
0220 {
0221 int ret;
0222
0223 ret = reset_control_assert(priv->por_reset);
0224 if (ret)
0225 return ret;
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 qcom_snps_hsphy_exit_retention(priv);
0237
0238
0239
0240
0241
0242 usleep_range(10, 20);
0243 ret = reset_control_deassert(priv->por_reset);
0244 if (ret)
0245 return ret;
0246
0247
0248
0249
0250
0251 usleep_range(80, 100);
0252
0253 return 0;
0254 }
0255
0256 static int qcom_snps_hsphy_init(struct phy *phy)
0257 {
0258 struct hsphy_priv *priv = phy_get_drvdata(phy);
0259 int ret;
0260
0261 ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks);
0262 if (ret)
0263 return ret;
0264
0265 ret = qcom_snps_hsphy_reset(priv);
0266 if (ret)
0267 goto disable_clocks;
0268
0269 qcom_snps_hsphy_init_sequence(priv);
0270
0271 ret = qcom_snps_hsphy_por_reset(priv);
0272 if (ret)
0273 goto disable_clocks;
0274
0275 return 0;
0276
0277 disable_clocks:
0278 clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
0279 return ret;
0280 }
0281
0282 static int qcom_snps_hsphy_exit(struct phy *phy)
0283 {
0284 struct hsphy_priv *priv = phy_get_drvdata(phy);
0285
0286 clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
0287
0288 return 0;
0289 }
0290
0291 static const struct phy_ops qcom_snps_hsphy_ops = {
0292 .init = qcom_snps_hsphy_init,
0293 .exit = qcom_snps_hsphy_exit,
0294 .power_on = qcom_snps_hsphy_power_on,
0295 .power_off = qcom_snps_hsphy_power_off,
0296 .set_mode = qcom_snps_hsphy_set_mode,
0297 .owner = THIS_MODULE,
0298 };
0299
0300 static const char * const qcom_snps_hsphy_clks[] = {
0301 "ref",
0302 "ahb",
0303 "sleep",
0304 };
0305
0306 static int qcom_snps_hsphy_probe(struct platform_device *pdev)
0307 {
0308 struct device *dev = &pdev->dev;
0309 struct phy_provider *provider;
0310 struct hsphy_priv *priv;
0311 struct phy *phy;
0312 int ret;
0313 int i;
0314
0315 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0316 if (!priv)
0317 return -ENOMEM;
0318
0319 priv->base = devm_platform_ioremap_resource(pdev, 0);
0320 if (IS_ERR(priv->base))
0321 return PTR_ERR(priv->base);
0322
0323 priv->num_clks = ARRAY_SIZE(qcom_snps_hsphy_clks);
0324 priv->clks = devm_kcalloc(dev, priv->num_clks, sizeof(*priv->clks),
0325 GFP_KERNEL);
0326 if (!priv->clks)
0327 return -ENOMEM;
0328
0329 for (i = 0; i < priv->num_clks; i++)
0330 priv->clks[i].id = qcom_snps_hsphy_clks[i];
0331
0332 ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks);
0333 if (ret)
0334 return ret;
0335
0336 priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
0337 if (IS_ERR(priv->phy_reset))
0338 return PTR_ERR(priv->phy_reset);
0339
0340 priv->por_reset = devm_reset_control_get_exclusive(dev, "por");
0341 if (IS_ERR(priv->por_reset))
0342 return PTR_ERR(priv->por_reset);
0343
0344 priv->vregs[VDD].supply = "vdd";
0345 priv->vregs[VDDA_1P8].supply = "vdda1p8";
0346 priv->vregs[VDDA_3P3].supply = "vdda3p3";
0347
0348 ret = devm_regulator_bulk_get(dev, VREG_NUM, priv->vregs);
0349 if (ret)
0350 return ret;
0351
0352
0353 priv->data = device_get_match_data(dev);
0354
0355 phy = devm_phy_create(dev, dev->of_node, &qcom_snps_hsphy_ops);
0356 if (IS_ERR(phy))
0357 return PTR_ERR(phy);
0358
0359 phy_set_drvdata(phy, priv);
0360
0361 provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
0362 if (IS_ERR(provider))
0363 return PTR_ERR(provider);
0364
0365 ret = regulator_set_load(priv->vregs[VDDA_1P8].consumer, 19000);
0366 if (ret < 0)
0367 return ret;
0368
0369 ret = regulator_set_load(priv->vregs[VDDA_3P3].consumer, 16000);
0370 if (ret < 0)
0371 goto unset_1p8_load;
0372
0373 return 0;
0374
0375 unset_1p8_load:
0376 regulator_set_load(priv->vregs[VDDA_1P8].consumer, 0);
0377
0378 return ret;
0379 }
0380
0381
0382
0383
0384
0385
0386 #define HSPHY_INIT_CFG(o, v, d) { .offset = o, .val = v, .delay = d, }
0387
0388 static const struct hsphy_init_seq init_seq_femtophy[] = {
0389 HSPHY_INIT_CFG(0xc0, 0x01, 0),
0390 HSPHY_INIT_CFG(0xe8, 0x0d, 0),
0391 HSPHY_INIT_CFG(0x74, 0x12, 0),
0392 HSPHY_INIT_CFG(0x98, 0x63, 0),
0393 HSPHY_INIT_CFG(0x9c, 0x03, 0),
0394 HSPHY_INIT_CFG(0xa0, 0x1d, 0),
0395 HSPHY_INIT_CFG(0xa4, 0x03, 0),
0396 HSPHY_INIT_CFG(0x8c, 0x23, 0),
0397 HSPHY_INIT_CFG(0x78, 0x08, 0),
0398 HSPHY_INIT_CFG(0x7c, 0xdc, 0),
0399 HSPHY_INIT_CFG(0x90, 0xe0, 20),
0400 HSPHY_INIT_CFG(0x74, 0x10, 0),
0401 HSPHY_INIT_CFG(0x90, 0x60, 0),
0402 };
0403
0404 static const struct hsphy_init_seq init_seq_mdm9607[] = {
0405 HSPHY_INIT_CFG(0x80, 0x44, 0),
0406 HSPHY_INIT_CFG(0x81, 0x38, 0),
0407 HSPHY_INIT_CFG(0x82, 0x24, 0),
0408 HSPHY_INIT_CFG(0x83, 0x13, 0),
0409 };
0410
0411 static const struct hsphy_data hsphy_data_femtophy = {
0412 .init_seq = init_seq_femtophy,
0413 .init_seq_num = ARRAY_SIZE(init_seq_femtophy),
0414 };
0415
0416 static const struct hsphy_data hsphy_data_mdm9607 = {
0417 .init_seq = init_seq_mdm9607,
0418 .init_seq_num = ARRAY_SIZE(init_seq_mdm9607),
0419 };
0420
0421 static const struct of_device_id qcom_snps_hsphy_match[] = {
0422 { .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, },
0423 { .compatible = "qcom,usb-hs-28nm-mdm9607", .data = &hsphy_data_mdm9607, },
0424 { },
0425 };
0426 MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match);
0427
0428 static struct platform_driver qcom_snps_hsphy_driver = {
0429 .probe = qcom_snps_hsphy_probe,
0430 .driver = {
0431 .name = "qcom,usb-hs-28nm-phy",
0432 .of_match_table = qcom_snps_hsphy_match,
0433 },
0434 };
0435 module_platform_driver(qcom_snps_hsphy_driver);
0436
0437 MODULE_DESCRIPTION("Qualcomm 28nm Hi-Speed USB PHY driver");
0438 MODULE_LICENSE("GPL v2");