1 /* 2 * ST SPEAr1310-miphy driver 3 * 4 * Copyright (C) 2014 ST Microelectronics 5 * Pratyush Anand <pratyush.anand@gmail.com> 6 * Mohit Kumar <mohit.kumar.dhaka@gmail.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 */ 13 14 #include <linux/bitops.h> 15 #include <linux/delay.h> 16 #include <linux/dma-mapping.h> 17 #include <linux/kernel.h> 18 #include <linux/mfd/syscon.h> 19 #include <linux/module.h> 20 #include <linux/of_device.h> 21 #include <linux/phy/phy.h> 22 #include <linux/regmap.h> 23 24 /* SPEAr1310 Registers */ 25 #define SPEAR1310_PCIE_SATA_CFG 0x3A4 26 #define SPEAR1310_PCIE_SATA2_SEL_PCIE (0 << 31) 27 #define SPEAR1310_PCIE_SATA1_SEL_PCIE (0 << 30) 28 #define SPEAR1310_PCIE_SATA0_SEL_PCIE (0 << 29) 29 #define SPEAR1310_PCIE_SATA2_SEL_SATA BIT(31) 30 #define SPEAR1310_PCIE_SATA1_SEL_SATA BIT(30) 31 #define SPEAR1310_PCIE_SATA0_SEL_SATA BIT(29) 32 #define SPEAR1310_SATA2_CFG_TX_CLK_EN BIT(27) 33 #define SPEAR1310_SATA2_CFG_RX_CLK_EN BIT(26) 34 #define SPEAR1310_SATA2_CFG_POWERUP_RESET BIT(25) 35 #define SPEAR1310_SATA2_CFG_PM_CLK_EN BIT(24) 36 #define SPEAR1310_SATA1_CFG_TX_CLK_EN BIT(23) 37 #define SPEAR1310_SATA1_CFG_RX_CLK_EN BIT(22) 38 #define SPEAR1310_SATA1_CFG_POWERUP_RESET BIT(21) 39 #define SPEAR1310_SATA1_CFG_PM_CLK_EN BIT(20) 40 #define SPEAR1310_SATA0_CFG_TX_CLK_EN BIT(19) 41 #define SPEAR1310_SATA0_CFG_RX_CLK_EN BIT(18) 42 #define SPEAR1310_SATA0_CFG_POWERUP_RESET BIT(17) 43 #define SPEAR1310_SATA0_CFG_PM_CLK_EN BIT(16) 44 #define SPEAR1310_PCIE2_CFG_DEVICE_PRESENT BIT(11) 45 #define SPEAR1310_PCIE2_CFG_POWERUP_RESET BIT(10) 46 #define SPEAR1310_PCIE2_CFG_CORE_CLK_EN BIT(9) 47 #define SPEAR1310_PCIE2_CFG_AUX_CLK_EN BIT(8) 48 #define SPEAR1310_PCIE1_CFG_DEVICE_PRESENT BIT(7) 49 #define SPEAR1310_PCIE1_CFG_POWERUP_RESET BIT(6) 50 #define SPEAR1310_PCIE1_CFG_CORE_CLK_EN BIT(5) 51 #define SPEAR1310_PCIE1_CFG_AUX_CLK_EN BIT(4) 52 #define SPEAR1310_PCIE0_CFG_DEVICE_PRESENT BIT(3) 53 #define SPEAR1310_PCIE0_CFG_POWERUP_RESET BIT(2) 54 #define SPEAR1310_PCIE0_CFG_CORE_CLK_EN BIT(1) 55 #define SPEAR1310_PCIE0_CFG_AUX_CLK_EN BIT(0) 56 57 #define SPEAR1310_PCIE_CFG_MASK(x) ((0xF << (x * 4)) | BIT((x + 29))) 58 #define SPEAR1310_SATA_CFG_MASK(x) ((0xF << (x * 4 + 16)) | \ 59 BIT((x + 29))) 60 #define SPEAR1310_PCIE_CFG_VAL(x) \ 61 (SPEAR1310_PCIE_SATA##x##_SEL_PCIE | \ 62 SPEAR1310_PCIE##x##_CFG_AUX_CLK_EN | \ 63 SPEAR1310_PCIE##x##_CFG_CORE_CLK_EN | \ 64 SPEAR1310_PCIE##x##_CFG_POWERUP_RESET | \ 65 SPEAR1310_PCIE##x##_CFG_DEVICE_PRESENT) 66 #define SPEAR1310_SATA_CFG_VAL(x) \ 67 (SPEAR1310_PCIE_SATA##x##_SEL_SATA | \ 68 SPEAR1310_SATA##x##_CFG_PM_CLK_EN | \ 69 SPEAR1310_SATA##x##_CFG_POWERUP_RESET | \ 70 SPEAR1310_SATA##x##_CFG_RX_CLK_EN | \ 71 SPEAR1310_SATA##x##_CFG_TX_CLK_EN) 72 73 #define SPEAR1310_PCIE_MIPHY_CFG_1 0x3A8 74 #define SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT BIT(31) 75 #define SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2 BIT(28) 76 #define SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(x) (x << 16) 77 #define SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT BIT(15) 78 #define SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2 BIT(12) 79 #define SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(x) (x << 0) 80 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_MASK (0xFFFF) 81 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK (0xFFFF << 16) 82 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA \ 83 (SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \ 84 SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2 | \ 85 SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(60) | \ 86 SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \ 87 SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2 | \ 88 SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(60)) 89 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \ 90 (SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(120)) 91 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE \ 92 (SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \ 93 SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(25) | \ 94 SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \ 95 SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(25)) 96 97 #define SPEAR1310_PCIE_MIPHY_CFG_2 0x3AC 98 99 enum spear1310_miphy_mode { 100 SATA, 101 PCIE, 102 }; 103 104 struct spear1310_miphy_priv { 105 /* instance id of this phy */ 106 u32 id; 107 /* phy mode: 0 for SATA 1 for PCIe */ 108 enum spear1310_miphy_mode mode; 109 /* regmap for any soc specific misc registers */ 110 struct regmap *misc; 111 /* phy struct pointer */ 112 struct phy *phy; 113 }; 114 115 static int spear1310_miphy_pcie_init(struct spear1310_miphy_priv *priv) 116 { 117 u32 val; 118 119 regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1, 120 SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK, 121 SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE); 122 123 switch (priv->id) { 124 case 0: 125 val = SPEAR1310_PCIE_CFG_VAL(0); 126 break; 127 case 1: 128 val = SPEAR1310_PCIE_CFG_VAL(1); 129 break; 130 case 2: 131 val = SPEAR1310_PCIE_CFG_VAL(2); 132 break; 133 default: 134 return -EINVAL; 135 } 136 137 regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG, 138 SPEAR1310_PCIE_CFG_MASK(priv->id), val); 139 140 return 0; 141 } 142 143 static int spear1310_miphy_pcie_exit(struct spear1310_miphy_priv *priv) 144 { 145 regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG, 146 SPEAR1310_PCIE_CFG_MASK(priv->id), 0); 147 148 regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1, 149 SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK, 0); 150 151 return 0; 152 } 153 154 static int spear1310_miphy_init(struct phy *phy) 155 { 156 struct spear1310_miphy_priv *priv = phy_get_drvdata(phy); 157 int ret = 0; 158 159 if (priv->mode == PCIE) 160 ret = spear1310_miphy_pcie_init(priv); 161 162 return ret; 163 } 164 165 static int spear1310_miphy_exit(struct phy *phy) 166 { 167 struct spear1310_miphy_priv *priv = phy_get_drvdata(phy); 168 int ret = 0; 169 170 if (priv->mode == PCIE) 171 ret = spear1310_miphy_pcie_exit(priv); 172 173 return ret; 174 } 175 176 static const struct of_device_id spear1310_miphy_of_match[] = { 177 { .compatible = "st,spear1310-miphy" }, 178 { }, 179 }; 180 MODULE_DEVICE_TABLE(of, spear1310_miphy_of_match); 181 182 static const struct phy_ops spear1310_miphy_ops = { 183 .init = spear1310_miphy_init, 184 .exit = spear1310_miphy_exit, 185 .owner = THIS_MODULE, 186 }; 187 188 static struct phy *spear1310_miphy_xlate(struct device *dev, 189 struct of_phandle_args *args) 190 { 191 struct spear1310_miphy_priv *priv = dev_get_drvdata(dev); 192 193 if (args->args_count < 1) { 194 dev_err(dev, "DT did not pass correct no of args\n"); 195 return ERR_PTR(-ENODEV); 196 } 197 198 priv->mode = args->args[0]; 199 200 if (priv->mode != SATA && priv->mode != PCIE) { 201 dev_err(dev, "DT did not pass correct phy mode\n"); 202 return ERR_PTR(-ENODEV); 203 } 204 205 return priv->phy; 206 } 207 208 static int spear1310_miphy_probe(struct platform_device *pdev) 209 { 210 struct device *dev = &pdev->dev; 211 struct spear1310_miphy_priv *priv; 212 struct phy_provider *phy_provider; 213 214 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 215 if (!priv) 216 return -ENOMEM; 217 218 priv->misc = 219 syscon_regmap_lookup_by_phandle(dev->of_node, "misc"); 220 if (IS_ERR(priv->misc)) { 221 dev_err(dev, "failed to find misc regmap\n"); 222 return PTR_ERR(priv->misc); 223 } 224 225 if (of_property_read_u32(dev->of_node, "phy-id", &priv->id)) { 226 dev_err(dev, "failed to find phy id\n"); 227 return -EINVAL; 228 } 229 230 priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops); 231 if (IS_ERR(priv->phy)) { 232 dev_err(dev, "failed to create SATA PCIe PHY\n"); 233 return PTR_ERR(priv->phy); 234 } 235 236 dev_set_drvdata(dev, priv); 237 phy_set_drvdata(priv->phy, priv); 238 239 phy_provider = 240 devm_of_phy_provider_register(dev, spear1310_miphy_xlate); 241 if (IS_ERR(phy_provider)) { 242 dev_err(dev, "failed to register phy provider\n"); 243 return PTR_ERR(phy_provider); 244 } 245 246 return 0; 247 } 248 249 static struct platform_driver spear1310_miphy_driver = { 250 .probe = spear1310_miphy_probe, 251 .driver = { 252 .name = "spear1310-miphy", 253 .of_match_table = of_match_ptr(spear1310_miphy_of_match), 254 }, 255 }; 256 257 module_platform_driver(spear1310_miphy_driver); 258 259 MODULE_DESCRIPTION("ST SPEAR1310-MIPHY driver"); 260 MODULE_AUTHOR("Pratyush Anand <pratyush.anand@gmail.com>"); 261 MODULE_LICENSE("GPL v2"); 262