Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /* Copyright (c) 2017 NXP. */
0003 
0004 #include <linux/bitfield.h>
0005 #include <linux/clk.h>
0006 #include <linux/delay.h>
0007 #include <linux/io.h>
0008 #include <linux/module.h>
0009 #include <linux/of_platform.h>
0010 #include <linux/phy/phy.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/regulator/consumer.h>
0013 
0014 #define PHY_CTRL0           0x0
0015 #define PHY_CTRL0_REF_SSP_EN        BIT(2)
0016 #define PHY_CTRL0_FSEL_MASK     GENMASK(10, 5)
0017 #define PHY_CTRL0_FSEL_24M      0x2a
0018 
0019 #define PHY_CTRL1           0x4
0020 #define PHY_CTRL1_RESET         BIT(0)
0021 #define PHY_CTRL1_COMMONONN     BIT(1)
0022 #define PHY_CTRL1_ATERESET      BIT(3)
0023 #define PHY_CTRL1_VDATSRCENB0       BIT(19)
0024 #define PHY_CTRL1_VDATDETENB0       BIT(20)
0025 
0026 #define PHY_CTRL2           0x8
0027 #define PHY_CTRL2_TXENABLEN0        BIT(8)
0028 #define PHY_CTRL2_OTG_DISABLE       BIT(9)
0029 
0030 #define PHY_CTRL6           0x18
0031 #define PHY_CTRL6_ALT_CLK_EN        BIT(1)
0032 #define PHY_CTRL6_ALT_CLK_SEL       BIT(0)
0033 
0034 struct imx8mq_usb_phy {
0035     struct phy *phy;
0036     struct clk *clk;
0037     void __iomem *base;
0038     struct regulator *vbus;
0039 };
0040 
0041 static int imx8mq_usb_phy_init(struct phy *phy)
0042 {
0043     struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
0044     u32 value;
0045 
0046     value = readl(imx_phy->base + PHY_CTRL1);
0047     value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
0048            PHY_CTRL1_COMMONONN);
0049     value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
0050     writel(value, imx_phy->base + PHY_CTRL1);
0051 
0052     value = readl(imx_phy->base + PHY_CTRL0);
0053     value |= PHY_CTRL0_REF_SSP_EN;
0054     writel(value, imx_phy->base + PHY_CTRL0);
0055 
0056     value = readl(imx_phy->base + PHY_CTRL2);
0057     value |= PHY_CTRL2_TXENABLEN0;
0058     writel(value, imx_phy->base + PHY_CTRL2);
0059 
0060     value = readl(imx_phy->base + PHY_CTRL1);
0061     value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
0062     writel(value, imx_phy->base + PHY_CTRL1);
0063 
0064     return 0;
0065 }
0066 
0067 static int imx8mp_usb_phy_init(struct phy *phy)
0068 {
0069     struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
0070     u32 value;
0071 
0072     /* USB3.0 PHY signal fsel for 24M ref */
0073     value = readl(imx_phy->base + PHY_CTRL0);
0074     value &= ~PHY_CTRL0_FSEL_MASK;
0075     value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M);
0076     writel(value, imx_phy->base + PHY_CTRL0);
0077 
0078     /* Disable alt_clk_en and use internal MPLL clocks */
0079     value = readl(imx_phy->base + PHY_CTRL6);
0080     value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN);
0081     writel(value, imx_phy->base + PHY_CTRL6);
0082 
0083     value = readl(imx_phy->base + PHY_CTRL1);
0084     value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0);
0085     value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
0086     writel(value, imx_phy->base + PHY_CTRL1);
0087 
0088     value = readl(imx_phy->base + PHY_CTRL0);
0089     value |= PHY_CTRL0_REF_SSP_EN;
0090     writel(value, imx_phy->base + PHY_CTRL0);
0091 
0092     value = readl(imx_phy->base + PHY_CTRL2);
0093     value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE;
0094     writel(value, imx_phy->base + PHY_CTRL2);
0095 
0096     udelay(10);
0097 
0098     value = readl(imx_phy->base + PHY_CTRL1);
0099     value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
0100     writel(value, imx_phy->base + PHY_CTRL1);
0101 
0102     return 0;
0103 }
0104 
0105 static int imx8mq_phy_power_on(struct phy *phy)
0106 {
0107     struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
0108     int ret;
0109 
0110     ret = regulator_enable(imx_phy->vbus);
0111     if (ret)
0112         return ret;
0113 
0114     return clk_prepare_enable(imx_phy->clk);
0115 }
0116 
0117 static int imx8mq_phy_power_off(struct phy *phy)
0118 {
0119     struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
0120 
0121     clk_disable_unprepare(imx_phy->clk);
0122     regulator_disable(imx_phy->vbus);
0123 
0124     return 0;
0125 }
0126 
0127 static const struct phy_ops imx8mq_usb_phy_ops = {
0128     .init       = imx8mq_usb_phy_init,
0129     .power_on   = imx8mq_phy_power_on,
0130     .power_off  = imx8mq_phy_power_off,
0131     .owner      = THIS_MODULE,
0132 };
0133 
0134 static const struct phy_ops imx8mp_usb_phy_ops = {
0135     .init       = imx8mp_usb_phy_init,
0136     .power_on   = imx8mq_phy_power_on,
0137     .power_off  = imx8mq_phy_power_off,
0138     .owner      = THIS_MODULE,
0139 };
0140 
0141 static const struct of_device_id imx8mq_usb_phy_of_match[] = {
0142     {.compatible = "fsl,imx8mq-usb-phy",
0143      .data = &imx8mq_usb_phy_ops,},
0144     {.compatible = "fsl,imx8mp-usb-phy",
0145      .data = &imx8mp_usb_phy_ops,},
0146     { }
0147 };
0148 MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
0149 
0150 static int imx8mq_usb_phy_probe(struct platform_device *pdev)
0151 {
0152     struct phy_provider *phy_provider;
0153     struct device *dev = &pdev->dev;
0154     struct imx8mq_usb_phy *imx_phy;
0155     const struct phy_ops *phy_ops;
0156 
0157     imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL);
0158     if (!imx_phy)
0159         return -ENOMEM;
0160 
0161     imx_phy->clk = devm_clk_get(dev, "phy");
0162     if (IS_ERR(imx_phy->clk)) {
0163         dev_err(dev, "failed to get imx8mq usb phy clock\n");
0164         return PTR_ERR(imx_phy->clk);
0165     }
0166 
0167     imx_phy->base = devm_platform_ioremap_resource(pdev, 0);
0168     if (IS_ERR(imx_phy->base))
0169         return PTR_ERR(imx_phy->base);
0170 
0171     phy_ops = of_device_get_match_data(dev);
0172     if (!phy_ops)
0173         return -EINVAL;
0174 
0175     imx_phy->phy = devm_phy_create(dev, NULL, phy_ops);
0176     if (IS_ERR(imx_phy->phy))
0177         return PTR_ERR(imx_phy->phy);
0178 
0179     imx_phy->vbus = devm_regulator_get(dev, "vbus");
0180     if (IS_ERR(imx_phy->vbus))
0181         return PTR_ERR(imx_phy->vbus);
0182 
0183     phy_set_drvdata(imx_phy->phy, imx_phy);
0184 
0185     phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
0186 
0187     return PTR_ERR_OR_ZERO(phy_provider);
0188 }
0189 
0190 static struct platform_driver imx8mq_usb_phy_driver = {
0191     .probe  = imx8mq_usb_phy_probe,
0192     .driver = {
0193         .name   = "imx8mq-usb-phy",
0194         .of_match_table = imx8mq_usb_phy_of_match,
0195     }
0196 };
0197 module_platform_driver(imx8mq_usb_phy_driver);
0198 
0199 MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver");
0200 MODULE_LICENSE("GPL");