Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ST spear1340-miphy driver
0004  *
0005  * Copyright (C) 2014 ST Microelectronics
0006  * Pratyush Anand <pratyush.anand@gmail.com>
0007  * Mohit Kumar <mohit.kumar.dhaka@gmail.com>
0008  */
0009 
0010 #include <linux/bitops.h>
0011 #include <linux/delay.h>
0012 #include <linux/dma-mapping.h>
0013 #include <linux/kernel.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/regmap.h>
0019 
0020 /* SPEAr1340 Registers */
0021 /* Power Management Registers */
0022 #define SPEAR1340_PCM_CFG           0x100
0023     #define SPEAR1340_PCM_CFG_SATA_POWER_EN     BIT(11)
0024 #define SPEAR1340_PCM_WKUP_CFG          0x104
0025 #define SPEAR1340_SWITCH_CTR            0x108
0026 
0027 #define SPEAR1340_PERIP1_SW_RST         0x318
0028     #define SPEAR1340_PERIP1_SW_RSATA       BIT(12)
0029 #define SPEAR1340_PERIP2_SW_RST         0x31C
0030 #define SPEAR1340_PERIP3_SW_RST         0x320
0031 
0032 /* PCIE - SATA configuration registers */
0033 #define SPEAR1340_PCIE_SATA_CFG         0x424
0034     /* PCIE CFG MASks */
0035     #define SPEAR1340_PCIE_CFG_DEVICE_PRESENT   BIT(11)
0036     #define SPEAR1340_PCIE_CFG_POWERUP_RESET    BIT(10)
0037     #define SPEAR1340_PCIE_CFG_CORE_CLK_EN      BIT(9)
0038     #define SPEAR1340_PCIE_CFG_AUX_CLK_EN       BIT(8)
0039     #define SPEAR1340_SATA_CFG_TX_CLK_EN        BIT(4)
0040     #define SPEAR1340_SATA_CFG_RX_CLK_EN        BIT(3)
0041     #define SPEAR1340_SATA_CFG_POWERUP_RESET    BIT(2)
0042     #define SPEAR1340_SATA_CFG_PM_CLK_EN        BIT(1)
0043     #define SPEAR1340_PCIE_SATA_SEL_PCIE        (0)
0044     #define SPEAR1340_PCIE_SATA_SEL_SATA        (1)
0045     #define SPEAR1340_PCIE_SATA_CFG_MASK        0xF1F
0046     #define SPEAR1340_PCIE_CFG_VAL  (SPEAR1340_PCIE_SATA_SEL_PCIE | \
0047             SPEAR1340_PCIE_CFG_AUX_CLK_EN | \
0048             SPEAR1340_PCIE_CFG_CORE_CLK_EN | \
0049             SPEAR1340_PCIE_CFG_POWERUP_RESET | \
0050             SPEAR1340_PCIE_CFG_DEVICE_PRESENT)
0051     #define SPEAR1340_SATA_CFG_VAL  (SPEAR1340_PCIE_SATA_SEL_SATA | \
0052             SPEAR1340_SATA_CFG_PM_CLK_EN | \
0053             SPEAR1340_SATA_CFG_POWERUP_RESET | \
0054             SPEAR1340_SATA_CFG_RX_CLK_EN | \
0055             SPEAR1340_SATA_CFG_TX_CLK_EN)
0056 
0057 #define SPEAR1340_PCIE_MIPHY_CFG        0x428
0058     #define SPEAR1340_MIPHY_OSC_BYPASS_EXT      BIT(31)
0059     #define SPEAR1340_MIPHY_CLK_REF_DIV2        BIT(27)
0060     #define SPEAR1340_MIPHY_CLK_REF_DIV4        (2 << 27)
0061     #define SPEAR1340_MIPHY_CLK_REF_DIV8        (3 << 27)
0062     #define SPEAR1340_MIPHY_PLL_RATIO_TOP(x)    (x << 0)
0063     #define SPEAR1340_PCIE_MIPHY_CFG_MASK       0xF80000FF
0064     #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA \
0065             (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \
0066             SPEAR1340_MIPHY_CLK_REF_DIV2 | \
0067             SPEAR1340_MIPHY_PLL_RATIO_TOP(60))
0068     #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \
0069             (SPEAR1340_MIPHY_PLL_RATIO_TOP(120))
0070     #define SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE \
0071             (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \
0072             SPEAR1340_MIPHY_PLL_RATIO_TOP(25))
0073 
0074 enum spear1340_miphy_mode {
0075     SATA,
0076     PCIE,
0077 };
0078 
0079 struct spear1340_miphy_priv {
0080     /* phy mode: 0 for SATA 1 for PCIe */
0081     enum spear1340_miphy_mode   mode;
0082     /* regmap for any soc specific misc registers */
0083     struct regmap           *misc;
0084     /* phy struct pointer */
0085     struct phy          *phy;
0086 };
0087 
0088 static int spear1340_miphy_sata_init(struct spear1340_miphy_priv *priv)
0089 {
0090     regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
0091                SPEAR1340_PCIE_SATA_CFG_MASK,
0092                SPEAR1340_SATA_CFG_VAL);
0093     regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
0094                SPEAR1340_PCIE_MIPHY_CFG_MASK,
0095                SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK);
0096     /* Switch on sata power domain */
0097     regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG,
0098                SPEAR1340_PCM_CFG_SATA_POWER_EN,
0099                SPEAR1340_PCM_CFG_SATA_POWER_EN);
0100     /* Wait for SATA power domain on */
0101     msleep(20);
0102 
0103     /* Disable PCIE SATA Controller reset */
0104     regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST,
0105                SPEAR1340_PERIP1_SW_RSATA, 0);
0106     /* Wait for SATA reset de-assert completion */
0107     msleep(20);
0108 
0109     return 0;
0110 }
0111 
0112 static int spear1340_miphy_sata_exit(struct spear1340_miphy_priv *priv)
0113 {
0114     regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
0115                SPEAR1340_PCIE_SATA_CFG_MASK, 0);
0116     regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
0117                SPEAR1340_PCIE_MIPHY_CFG_MASK, 0);
0118 
0119     /* Enable PCIE SATA Controller reset */
0120     regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST,
0121                SPEAR1340_PERIP1_SW_RSATA,
0122                SPEAR1340_PERIP1_SW_RSATA);
0123     /* Wait for SATA power domain off */
0124     msleep(20);
0125     /* Switch off sata power domain */
0126     regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG,
0127                SPEAR1340_PCM_CFG_SATA_POWER_EN, 0);
0128     /* Wait for SATA reset assert completion */
0129     msleep(20);
0130 
0131     return 0;
0132 }
0133 
0134 static int spear1340_miphy_pcie_init(struct spear1340_miphy_priv *priv)
0135 {
0136     regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
0137                SPEAR1340_PCIE_MIPHY_CFG_MASK,
0138                SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE);
0139     regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
0140                SPEAR1340_PCIE_SATA_CFG_MASK,
0141                SPEAR1340_PCIE_CFG_VAL);
0142 
0143     return 0;
0144 }
0145 
0146 static int spear1340_miphy_pcie_exit(struct spear1340_miphy_priv *priv)
0147 {
0148     regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
0149                SPEAR1340_PCIE_MIPHY_CFG_MASK, 0);
0150     regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
0151                SPEAR1340_PCIE_SATA_CFG_MASK, 0);
0152 
0153     return 0;
0154 }
0155 
0156 static int spear1340_miphy_init(struct phy *phy)
0157 {
0158     struct spear1340_miphy_priv *priv = phy_get_drvdata(phy);
0159     int ret = 0;
0160 
0161     if (priv->mode == SATA)
0162         ret = spear1340_miphy_sata_init(priv);
0163     else if (priv->mode == PCIE)
0164         ret = spear1340_miphy_pcie_init(priv);
0165 
0166     return ret;
0167 }
0168 
0169 static int spear1340_miphy_exit(struct phy *phy)
0170 {
0171     struct spear1340_miphy_priv *priv = phy_get_drvdata(phy);
0172     int ret = 0;
0173 
0174     if (priv->mode == SATA)
0175         ret = spear1340_miphy_sata_exit(priv);
0176     else if (priv->mode == PCIE)
0177         ret = spear1340_miphy_pcie_exit(priv);
0178 
0179     return ret;
0180 }
0181 
0182 static const struct of_device_id spear1340_miphy_of_match[] = {
0183     { .compatible = "st,spear1340-miphy" },
0184     { },
0185 };
0186 MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match);
0187 
0188 static const struct phy_ops spear1340_miphy_ops = {
0189     .init = spear1340_miphy_init,
0190     .exit = spear1340_miphy_exit,
0191     .owner = THIS_MODULE,
0192 };
0193 
0194 #ifdef CONFIG_PM_SLEEP
0195 static int spear1340_miphy_suspend(struct device *dev)
0196 {
0197     struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
0198     int ret = 0;
0199 
0200     if (priv->mode == SATA)
0201         ret = spear1340_miphy_sata_exit(priv);
0202 
0203     return ret;
0204 }
0205 
0206 static int spear1340_miphy_resume(struct device *dev)
0207 {
0208     struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
0209     int ret = 0;
0210 
0211     if (priv->mode == SATA)
0212         ret = spear1340_miphy_sata_init(priv);
0213 
0214     return ret;
0215 }
0216 #endif
0217 
0218 static SIMPLE_DEV_PM_OPS(spear1340_miphy_pm_ops, spear1340_miphy_suspend,
0219              spear1340_miphy_resume);
0220 
0221 static struct phy *spear1340_miphy_xlate(struct device *dev,
0222                      struct of_phandle_args *args)
0223 {
0224     struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
0225 
0226     if (args->args_count < 1) {
0227         dev_err(dev, "DT did not pass correct no of args\n");
0228         return ERR_PTR(-ENODEV);
0229     }
0230 
0231     priv->mode = args->args[0];
0232 
0233     if (priv->mode != SATA && priv->mode != PCIE) {
0234         dev_err(dev, "DT did not pass correct phy mode\n");
0235         return ERR_PTR(-ENODEV);
0236     }
0237 
0238     return priv->phy;
0239 }
0240 
0241 static int spear1340_miphy_probe(struct platform_device *pdev)
0242 {
0243     struct device *dev = &pdev->dev;
0244     struct spear1340_miphy_priv *priv;
0245     struct phy_provider *phy_provider;
0246 
0247     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0248     if (!priv)
0249         return -ENOMEM;
0250 
0251     priv->misc =
0252         syscon_regmap_lookup_by_phandle(dev->of_node, "misc");
0253     if (IS_ERR(priv->misc)) {
0254         dev_err(dev, "failed to find misc regmap\n");
0255         return PTR_ERR(priv->misc);
0256     }
0257 
0258     priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops);
0259     if (IS_ERR(priv->phy)) {
0260         dev_err(dev, "failed to create SATA PCIe PHY\n");
0261         return PTR_ERR(priv->phy);
0262     }
0263 
0264     dev_set_drvdata(dev, priv);
0265     phy_set_drvdata(priv->phy, priv);
0266 
0267     phy_provider =
0268         devm_of_phy_provider_register(dev, spear1340_miphy_xlate);
0269     if (IS_ERR(phy_provider)) {
0270         dev_err(dev, "failed to register phy provider\n");
0271         return PTR_ERR(phy_provider);
0272     }
0273 
0274     return 0;
0275 }
0276 
0277 static struct platform_driver spear1340_miphy_driver = {
0278     .probe      = spear1340_miphy_probe,
0279     .driver = {
0280         .name = "spear1340-miphy",
0281         .pm = &spear1340_miphy_pm_ops,
0282         .of_match_table = of_match_ptr(spear1340_miphy_of_match),
0283     },
0284 };
0285 
0286 module_platform_driver(spear1340_miphy_driver);
0287 
0288 MODULE_DESCRIPTION("ST SPEAR1340-MIPHY driver");
0289 MODULE_AUTHOR("Pratyush Anand <pratyush.anand@gmail.com>");
0290 MODULE_LICENSE("GPL v2");