Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2018 Marvell
0004  *
0005  * Authors:
0006  *   Igal Liberman <igall@marvell.com>
0007  *   Miquèl Raynal <miquel.raynal@bootlin.com>
0008  *
0009  * Marvell A3700 UTMI PHY driver
0010  */
0011 
0012 #include <linux/io.h>
0013 #include <linux/iopoll.h>
0014 #include <linux/mfd/syscon.h>
0015 #include <linux/module.h>
0016 #include <linux/of_device.h>
0017 #include <linux/phy/phy.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/regmap.h>
0020 
0021 /* Armada 3700 UTMI PHY registers */
0022 #define USB2_PHY_PLL_CTRL_REG0          0x0
0023 #define   PLL_REF_DIV_OFF           0
0024 #define   PLL_REF_DIV_MASK          GENMASK(6, 0)
0025 #define   PLL_REF_DIV_5             5
0026 #define   PLL_FB_DIV_OFF            16
0027 #define   PLL_FB_DIV_MASK           GENMASK(24, 16)
0028 #define   PLL_FB_DIV_96             96
0029 #define   PLL_SEL_LPFR_OFF          28
0030 #define   PLL_SEL_LPFR_MASK         GENMASK(29, 28)
0031 #define   PLL_READY             BIT(31)
0032 #define USB2_PHY_CAL_CTRL           0x8
0033 #define   PHY_PLLCAL_DONE           BIT(31)
0034 #define   PHY_IMPCAL_DONE           BIT(23)
0035 #define USB2_RX_CHAN_CTRL1          0x18
0036 #define   USB2PHY_SQCAL_DONE            BIT(31)
0037 #define USB2_PHY_OTG_CTRL           0x34
0038 #define   PHY_PU_OTG                BIT(4)
0039 #define USB2_PHY_CHRGR_DETECT           0x38
0040 #define   PHY_CDP_EN                BIT(2)
0041 #define   PHY_DCP_EN                BIT(3)
0042 #define   PHY_PD_EN             BIT(4)
0043 #define   PHY_PU_CHRG_DTC           BIT(5)
0044 #define   PHY_CDP_DM_AUTO           BIT(7)
0045 #define   PHY_ENSWITCH_DP           BIT(12)
0046 #define   PHY_ENSWITCH_DM           BIT(13)
0047 
0048 /* Armada 3700 USB miscellaneous registers */
0049 #define USB2_PHY_CTRL(usb32)            (usb32 ? 0x20 : 0x4)
0050 #define   RB_USB2PHY_PU             BIT(0)
0051 #define   USB2_DP_PULLDN_DEV_MODE       BIT(5)
0052 #define   USB2_DM_PULLDN_DEV_MODE       BIT(6)
0053 #define   RB_USB2PHY_SUSPM(usb32)       (usb32 ? BIT(14) : BIT(7))
0054 
0055 #define PLL_LOCK_DELAY_US           10000
0056 #define PLL_LOCK_TIMEOUT_US         1000000
0057 
0058 /**
0059  * struct mvebu_a3700_utmi_caps - PHY capabilities
0060  *
0061  * @usb32: Flag indicating which PHY is in use (impacts the register map):
0062  *           - The UTMI PHY wired to the USB3/USB2 controller (otg)
0063  *           - The UTMI PHY wired to the USB2 controller (host only)
0064  * @ops: PHY operations
0065  */
0066 struct mvebu_a3700_utmi_caps {
0067     int usb32;
0068     const struct phy_ops *ops;
0069 };
0070 
0071 /**
0072  * struct mvebu_a3700_utmi - PHY driver data
0073  *
0074  * @regs: PHY registers
0075  * @usb_misc: Regmap with USB miscellaneous registers including PHY ones
0076  * @caps: PHY capabilities
0077  * @phy: PHY handle
0078  */
0079 struct mvebu_a3700_utmi {
0080     void __iomem *regs;
0081     struct regmap *usb_misc;
0082     const struct mvebu_a3700_utmi_caps *caps;
0083     struct phy *phy;
0084 };
0085 
0086 static int mvebu_a3700_utmi_phy_power_on(struct phy *phy)
0087 {
0088     struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy);
0089     struct device *dev = &phy->dev;
0090     int usb32 = utmi->caps->usb32;
0091     int ret = 0;
0092     u32 reg;
0093 
0094     /*
0095      * Setup PLL. 40MHz clock used to be the default, being 25MHz now.
0096      * See "PLL Settings for Typical REFCLK" table.
0097      */
0098     reg = readl(utmi->regs + USB2_PHY_PLL_CTRL_REG0);
0099     reg &= ~(PLL_REF_DIV_MASK | PLL_FB_DIV_MASK | PLL_SEL_LPFR_MASK);
0100     reg |= (PLL_REF_DIV_5 << PLL_REF_DIV_OFF) |
0101            (PLL_FB_DIV_96 << PLL_FB_DIV_OFF);
0102     writel(reg, utmi->regs + USB2_PHY_PLL_CTRL_REG0);
0103 
0104     /* Enable PHY pull up and disable USB2 suspend */
0105     regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32),
0106                RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU,
0107                RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU);
0108 
0109     if (usb32) {
0110         /* Power up OTG module */
0111         reg = readl(utmi->regs + USB2_PHY_OTG_CTRL);
0112         reg |= PHY_PU_OTG;
0113         writel(reg, utmi->regs + USB2_PHY_OTG_CTRL);
0114 
0115         /* Disable PHY charger detection */
0116         reg = readl(utmi->regs + USB2_PHY_CHRGR_DETECT);
0117         reg &= ~(PHY_CDP_EN | PHY_DCP_EN | PHY_PD_EN | PHY_PU_CHRG_DTC |
0118              PHY_CDP_DM_AUTO | PHY_ENSWITCH_DP | PHY_ENSWITCH_DM);
0119         writel(reg, utmi->regs + USB2_PHY_CHRGR_DETECT);
0120 
0121         /* Disable PHY DP/DM pull-down (used for device mode) */
0122         regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32),
0123                    USB2_DP_PULLDN_DEV_MODE |
0124                    USB2_DM_PULLDN_DEV_MODE, 0);
0125     }
0126 
0127     /* Wait for PLL calibration */
0128     ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg,
0129                  reg & PHY_PLLCAL_DONE,
0130                  PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
0131     if (ret) {
0132         dev_err(dev, "Failed to end USB2 PLL calibration\n");
0133         return ret;
0134     }
0135 
0136     /* Wait for impedance calibration */
0137     ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg,
0138                  reg & PHY_IMPCAL_DONE,
0139                  PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
0140     if (ret) {
0141         dev_err(dev, "Failed to end USB2 impedance calibration\n");
0142         return ret;
0143     }
0144 
0145     /* Wait for squelch calibration */
0146     ret = readl_poll_timeout(utmi->regs + USB2_RX_CHAN_CTRL1, reg,
0147                  reg & USB2PHY_SQCAL_DONE,
0148                  PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
0149     if (ret) {
0150         dev_err(dev, "Failed to end USB2 unknown calibration\n");
0151         return ret;
0152     }
0153 
0154     /* Wait for PLL to be locked */
0155     ret = readl_poll_timeout(utmi->regs + USB2_PHY_PLL_CTRL_REG0, reg,
0156                  reg & PLL_READY,
0157                  PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
0158     if (ret)
0159         dev_err(dev, "Failed to lock USB2 PLL\n");
0160 
0161     return ret;
0162 }
0163 
0164 static int mvebu_a3700_utmi_phy_power_off(struct phy *phy)
0165 {
0166     struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy);
0167     int usb32 = utmi->caps->usb32;
0168     u32 reg;
0169 
0170     /* Disable PHY pull-up and enable USB2 suspend */
0171     reg = readl(utmi->regs + USB2_PHY_CTRL(usb32));
0172     reg &= ~(RB_USB2PHY_PU | RB_USB2PHY_SUSPM(usb32));
0173     writel(reg, utmi->regs + USB2_PHY_CTRL(usb32));
0174 
0175     /* Power down OTG module */
0176     if (usb32) {
0177         reg = readl(utmi->regs + USB2_PHY_OTG_CTRL);
0178         reg &= ~PHY_PU_OTG;
0179         writel(reg, utmi->regs + USB2_PHY_OTG_CTRL);
0180     }
0181 
0182     return 0;
0183 }
0184 
0185 static const struct phy_ops mvebu_a3700_utmi_phy_ops = {
0186     .power_on = mvebu_a3700_utmi_phy_power_on,
0187     .power_off = mvebu_a3700_utmi_phy_power_off,
0188     .owner = THIS_MODULE,
0189 };
0190 
0191 static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_otg_phy_caps = {
0192     .usb32 = true,
0193     .ops = &mvebu_a3700_utmi_phy_ops,
0194 };
0195 
0196 static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_host_phy_caps = {
0197     .usb32 = false,
0198     .ops = &mvebu_a3700_utmi_phy_ops,
0199 };
0200 
0201 static const struct of_device_id mvebu_a3700_utmi_of_match[] = {
0202     {
0203         .compatible = "marvell,a3700-utmi-otg-phy",
0204         .data = &mvebu_a3700_utmi_otg_phy_caps,
0205     },
0206     {
0207         .compatible = "marvell,a3700-utmi-host-phy",
0208         .data = &mvebu_a3700_utmi_host_phy_caps,
0209     },
0210     {},
0211 };
0212 MODULE_DEVICE_TABLE(of, mvebu_a3700_utmi_of_match);
0213 
0214 static int mvebu_a3700_utmi_phy_probe(struct platform_device *pdev)
0215 {
0216     struct device *dev = &pdev->dev;
0217     struct mvebu_a3700_utmi *utmi;
0218     struct phy_provider *provider;
0219 
0220     utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL);
0221     if (!utmi)
0222         return -ENOMEM;
0223 
0224     /* Get UTMI memory region */
0225     utmi->regs = devm_platform_ioremap_resource(pdev, 0);
0226     if (IS_ERR(utmi->regs))
0227         return PTR_ERR(utmi->regs);
0228 
0229     /* Get miscellaneous Host/PHY region */
0230     utmi->usb_misc = syscon_regmap_lookup_by_phandle(dev->of_node,
0231                              "marvell,usb-misc-reg");
0232     if (IS_ERR(utmi->usb_misc)) {
0233         dev_err(dev,
0234             "Missing USB misc purpose system controller\n");
0235         return PTR_ERR(utmi->usb_misc);
0236     }
0237 
0238     /* Retrieve PHY capabilities */
0239     utmi->caps = of_device_get_match_data(dev);
0240 
0241     /* Instantiate the PHY */
0242     utmi->phy = devm_phy_create(dev, NULL, utmi->caps->ops);
0243     if (IS_ERR(utmi->phy)) {
0244         dev_err(dev, "Failed to create the UTMI PHY\n");
0245         return PTR_ERR(utmi->phy);
0246     }
0247 
0248     phy_set_drvdata(utmi->phy, utmi);
0249 
0250     /* Ensure the PHY is powered off */
0251     utmi->caps->ops->power_off(utmi->phy);
0252 
0253     provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
0254 
0255     return PTR_ERR_OR_ZERO(provider);
0256 }
0257 
0258 static struct platform_driver mvebu_a3700_utmi_driver = {
0259     .probe  = mvebu_a3700_utmi_phy_probe,
0260     .driver = {
0261         .name       = "mvebu-a3700-utmi-phy",
0262         .of_match_table = mvebu_a3700_utmi_of_match,
0263      },
0264 };
0265 module_platform_driver(mvebu_a3700_utmi_driver);
0266 
0267 MODULE_AUTHOR("Igal Liberman <igall@marvell.com>");
0268 MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
0269 MODULE_DESCRIPTION("Marvell EBU A3700 UTMI PHY driver");
0270 MODULE_LICENSE("GPL v2");