Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2009-2018, Linux Foundation. All rights reserved.
0004  * Copyright (c) 2018-2020, Linaro Limited
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 /* PHY register and bit definitions */
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     /* Clear any existing interrupts before enabling the interrupts */
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     /* Make sure the interrupts are cleared */
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         /* No device connected */
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     /* Clear any pending interrupts */
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     /* Device match data is optional. */
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      * The Femto PHY is POR reset in the following scenarios.
0229      *
0230      * 1. After overriding the parameter registers.
0231      * 2. Low power mode exit from PHY retention.
0232      *
0233      * Ensure that SIDDQ is cleared before bringing the PHY
0234      * out of reset.
0235      */
0236     qcom_snps_hsphy_exit_retention(priv);
0237 
0238     /*
0239      * As per databook, 10 usec delay is required between
0240      * PHY POR assert and de-assert.
0241      */
0242     usleep_range(10, 20);
0243     ret = reset_control_deassert(priv->por_reset);
0244     if (ret)
0245         return ret;
0246 
0247     /*
0248      * As per databook, it takes 75 usec for PHY to stabilize
0249      * after the reset.
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     /* Get device match data */
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  * The macro is used to define an initialization sequence.  Each tuple
0383  * is meant to program 'value' into phy register at 'offset' with 'delay'
0384  * in us followed.
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");