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