0001
0002
0003
0004
0005
0006
0007
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
0021
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
0033 #define SPEAR1340_PCIE_SATA_CFG 0x424
0034
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
0081 enum spear1340_miphy_mode mode;
0082
0083 struct regmap *misc;
0084
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
0097 regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG,
0098 SPEAR1340_PCM_CFG_SATA_POWER_EN,
0099 SPEAR1340_PCM_CFG_SATA_POWER_EN);
0100
0101 msleep(20);
0102
0103
0104 regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST,
0105 SPEAR1340_PERIP1_SW_RSATA, 0);
0106
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
0120 regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST,
0121 SPEAR1340_PERIP1_SW_RSATA,
0122 SPEAR1340_PERIP1_SW_RSATA);
0123
0124 msleep(20);
0125
0126 regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG,
0127 SPEAR1340_PCM_CFG_SATA_POWER_EN, 0);
0128
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");