1/* 2 * ST spear1340-miphy driver 3 * 4 * Copyright (C) 2014 ST Microelectronics 5 * Pratyush Anand <pratyush.anand@st.com> 6 * Mohit Kumar <mohit.kumar@st.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/* SPEAr1340 Registers */ 25/* Power Management Registers */ 26#define SPEAR1340_PCM_CFG 0x100 27 #define SPEAR1340_PCM_CFG_SATA_POWER_EN BIT(11) 28#define SPEAR1340_PCM_WKUP_CFG 0x104 29#define SPEAR1340_SWITCH_CTR 0x108 30 31#define SPEAR1340_PERIP1_SW_RST 0x318 32 #define SPEAR1340_PERIP1_SW_RSATA BIT(12) 33#define SPEAR1340_PERIP2_SW_RST 0x31C 34#define SPEAR1340_PERIP3_SW_RST 0x320 35 36/* PCIE - SATA configuration registers */ 37#define SPEAR1340_PCIE_SATA_CFG 0x424 38 /* PCIE CFG MASks */ 39 #define SPEAR1340_PCIE_CFG_DEVICE_PRESENT BIT(11) 40 #define SPEAR1340_PCIE_CFG_POWERUP_RESET BIT(10) 41 #define SPEAR1340_PCIE_CFG_CORE_CLK_EN BIT(9) 42 #define SPEAR1340_PCIE_CFG_AUX_CLK_EN BIT(8) 43 #define SPEAR1340_SATA_CFG_TX_CLK_EN BIT(4) 44 #define SPEAR1340_SATA_CFG_RX_CLK_EN BIT(3) 45 #define SPEAR1340_SATA_CFG_POWERUP_RESET BIT(2) 46 #define SPEAR1340_SATA_CFG_PM_CLK_EN BIT(1) 47 #define SPEAR1340_PCIE_SATA_SEL_PCIE (0) 48 #define SPEAR1340_PCIE_SATA_SEL_SATA (1) 49 #define SPEAR1340_PCIE_SATA_CFG_MASK 0xF1F 50 #define SPEAR1340_PCIE_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_PCIE | \ 51 SPEAR1340_PCIE_CFG_AUX_CLK_EN | \ 52 SPEAR1340_PCIE_CFG_CORE_CLK_EN | \ 53 SPEAR1340_PCIE_CFG_POWERUP_RESET | \ 54 SPEAR1340_PCIE_CFG_DEVICE_PRESENT) 55 #define SPEAR1340_SATA_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_SATA | \ 56 SPEAR1340_SATA_CFG_PM_CLK_EN | \ 57 SPEAR1340_SATA_CFG_POWERUP_RESET | \ 58 SPEAR1340_SATA_CFG_RX_CLK_EN | \ 59 SPEAR1340_SATA_CFG_TX_CLK_EN) 60 61#define SPEAR1340_PCIE_MIPHY_CFG 0x428 62 #define SPEAR1340_MIPHY_OSC_BYPASS_EXT BIT(31) 63 #define SPEAR1340_MIPHY_CLK_REF_DIV2 BIT(27) 64 #define SPEAR1340_MIPHY_CLK_REF_DIV4 (2 << 27) 65 #define SPEAR1340_MIPHY_CLK_REF_DIV8 (3 << 27) 66 #define SPEAR1340_MIPHY_PLL_RATIO_TOP(x) (x << 0) 67 #define SPEAR1340_PCIE_MIPHY_CFG_MASK 0xF80000FF 68 #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA \ 69 (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \ 70 SPEAR1340_MIPHY_CLK_REF_DIV2 | \ 71 SPEAR1340_MIPHY_PLL_RATIO_TOP(60)) 72 #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \ 73 (SPEAR1340_MIPHY_PLL_RATIO_TOP(120)) 74 #define SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE \ 75 (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \ 76 SPEAR1340_MIPHY_PLL_RATIO_TOP(25)) 77 78enum spear1340_miphy_mode { 79 SATA, 80 PCIE, 81}; 82 83struct spear1340_miphy_priv { 84 /* phy mode: 0 for SATA 1 for PCIe */ 85 enum spear1340_miphy_mode mode; 86 /* regmap for any soc specific misc registers */ 87 struct regmap *misc; 88 /* phy struct pointer */ 89 struct phy *phy; 90}; 91 92static int spear1340_miphy_sata_init(struct spear1340_miphy_priv *priv) 93{ 94 regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG, 95 SPEAR1340_PCIE_SATA_CFG_MASK, 96 SPEAR1340_SATA_CFG_VAL); 97 regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG, 98 SPEAR1340_PCIE_MIPHY_CFG_MASK, 99 SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK); 100 /* Switch on sata power domain */ 101 regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG, 102 SPEAR1340_PCM_CFG_SATA_POWER_EN, 103 SPEAR1340_PCM_CFG_SATA_POWER_EN); 104 /* Wait for SATA power domain on */ 105 msleep(20); 106 107 /* Disable PCIE SATA Controller reset */ 108 regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST, 109 SPEAR1340_PERIP1_SW_RSATA, 0); 110 /* Wait for SATA reset de-assert completion */ 111 msleep(20); 112 113 return 0; 114} 115 116static int spear1340_miphy_sata_exit(struct spear1340_miphy_priv *priv) 117{ 118 regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG, 119 SPEAR1340_PCIE_SATA_CFG_MASK, 0); 120 regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG, 121 SPEAR1340_PCIE_MIPHY_CFG_MASK, 0); 122 123 /* Enable PCIE SATA Controller reset */ 124 regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST, 125 SPEAR1340_PERIP1_SW_RSATA, 126 SPEAR1340_PERIP1_SW_RSATA); 127 /* Wait for SATA power domain off */ 128 msleep(20); 129 /* Switch off sata power domain */ 130 regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG, 131 SPEAR1340_PCM_CFG_SATA_POWER_EN, 0); 132 /* Wait for SATA reset assert completion */ 133 msleep(20); 134 135 return 0; 136} 137 138static int spear1340_miphy_pcie_init(struct spear1340_miphy_priv *priv) 139{ 140 regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG, 141 SPEAR1340_PCIE_MIPHY_CFG_MASK, 142 SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE); 143 regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG, 144 SPEAR1340_PCIE_SATA_CFG_MASK, 145 SPEAR1340_PCIE_CFG_VAL); 146 147 return 0; 148} 149 150static int spear1340_miphy_pcie_exit(struct spear1340_miphy_priv *priv) 151{ 152 regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG, 153 SPEAR1340_PCIE_MIPHY_CFG_MASK, 0); 154 regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG, 155 SPEAR1340_PCIE_SATA_CFG_MASK, 0); 156 157 return 0; 158} 159 160static int spear1340_miphy_init(struct phy *phy) 161{ 162 struct spear1340_miphy_priv *priv = phy_get_drvdata(phy); 163 int ret = 0; 164 165 if (priv->mode == SATA) 166 ret = spear1340_miphy_sata_init(priv); 167 else if (priv->mode == PCIE) 168 ret = spear1340_miphy_pcie_init(priv); 169 170 return ret; 171} 172 173static int spear1340_miphy_exit(struct phy *phy) 174{ 175 struct spear1340_miphy_priv *priv = phy_get_drvdata(phy); 176 int ret = 0; 177 178 if (priv->mode == SATA) 179 ret = spear1340_miphy_sata_exit(priv); 180 else if (priv->mode == PCIE) 181 ret = spear1340_miphy_pcie_exit(priv); 182 183 return ret; 184} 185 186static const struct of_device_id spear1340_miphy_of_match[] = { 187 { .compatible = "st,spear1340-miphy" }, 188 { }, 189}; 190MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match); 191 192static struct phy_ops spear1340_miphy_ops = { 193 .init = spear1340_miphy_init, 194 .exit = spear1340_miphy_exit, 195 .owner = THIS_MODULE, 196}; 197 198#ifdef CONFIG_PM_SLEEP 199static int spear1340_miphy_suspend(struct device *dev) 200{ 201 struct spear1340_miphy_priv *priv = dev_get_drvdata(dev); 202 int ret = 0; 203 204 if (priv->mode == SATA) 205 ret = spear1340_miphy_sata_exit(priv); 206 207 return ret; 208} 209 210static int spear1340_miphy_resume(struct device *dev) 211{ 212 struct spear1340_miphy_priv *priv = dev_get_drvdata(dev); 213 int ret = 0; 214 215 if (priv->mode == SATA) 216 ret = spear1340_miphy_sata_init(priv); 217 218 return ret; 219} 220#endif 221 222static SIMPLE_DEV_PM_OPS(spear1340_miphy_pm_ops, spear1340_miphy_suspend, 223 spear1340_miphy_resume); 224 225static struct phy *spear1340_miphy_xlate(struct device *dev, 226 struct of_phandle_args *args) 227{ 228 struct spear1340_miphy_priv *priv = dev_get_drvdata(dev); 229 230 if (args->args_count < 1) { 231 dev_err(dev, "DT did not pass correct no of args\n"); 232 return ERR_PTR(-ENODEV); 233 } 234 235 priv->mode = args->args[0]; 236 237 if (priv->mode != SATA && priv->mode != PCIE) { 238 dev_err(dev, "DT did not pass correct phy mode\n"); 239 return ERR_PTR(-ENODEV); 240 } 241 242 return priv->phy; 243} 244 245static int spear1340_miphy_probe(struct platform_device *pdev) 246{ 247 struct device *dev = &pdev->dev; 248 struct spear1340_miphy_priv *priv; 249 struct phy_provider *phy_provider; 250 251 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 252 if (!priv) 253 return -ENOMEM; 254 255 priv->misc = 256 syscon_regmap_lookup_by_phandle(dev->of_node, "misc"); 257 if (IS_ERR(priv->misc)) { 258 dev_err(dev, "failed to find misc regmap\n"); 259 return PTR_ERR(priv->misc); 260 } 261 262 priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops); 263 if (IS_ERR(priv->phy)) { 264 dev_err(dev, "failed to create SATA PCIe PHY\n"); 265 return PTR_ERR(priv->phy); 266 } 267 268 dev_set_drvdata(dev, priv); 269 phy_set_drvdata(priv->phy, priv); 270 271 phy_provider = 272 devm_of_phy_provider_register(dev, spear1340_miphy_xlate); 273 if (IS_ERR(phy_provider)) { 274 dev_err(dev, "failed to register phy provider\n"); 275 return PTR_ERR(phy_provider); 276 } 277 278 return 0; 279} 280 281static struct platform_driver spear1340_miphy_driver = { 282 .probe = spear1340_miphy_probe, 283 .driver = { 284 .name = "spear1340-miphy", 285 .pm = &spear1340_miphy_pm_ops, 286 .of_match_table = of_match_ptr(spear1340_miphy_of_match), 287 }, 288}; 289 290module_platform_driver(spear1340_miphy_driver); 291 292MODULE_DESCRIPTION("ST SPEAR1340-MIPHY driver"); 293MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>"); 294MODULE_LICENSE("GPL v2"); 295