1 /* 2 * Samsung SATA SerDes(PHY) driver 3 * 4 * Copyright (C) 2013 Samsung Electronics Co., Ltd. 5 * Authors: Girish K S <ks.giri@samsung.com> 6 * Yuvaraj Kumar C D <yuvaraj.cd@samsung.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 #include <linux/clk.h> 14 #include <linux/delay.h> 15 #include <linux/io.h> 16 #include <linux/i2c.h> 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/of.h> 20 #include <linux/of_address.h> 21 #include <linux/phy/phy.h> 22 #include <linux/platform_device.h> 23 #include <linux/regmap.h> 24 #include <linux/spinlock.h> 25 #include <linux/mfd/syscon.h> 26 27 #define SATAPHY_CONTROL_OFFSET 0x0724 28 #define EXYNOS5_SATAPHY_PMU_ENABLE BIT(0) 29 #define EXYNOS5_SATA_RESET 0x4 30 #define RESET_GLOBAL_RST_N BIT(0) 31 #define RESET_CMN_RST_N BIT(1) 32 #define RESET_CMN_BLOCK_RST_N BIT(2) 33 #define RESET_CMN_I2C_RST_N BIT(3) 34 #define RESET_TX_RX_PIPE_RST_N BIT(4) 35 #define RESET_TX_RX_BLOCK_RST_N BIT(5) 36 #define RESET_TX_RX_I2C_RST_N (BIT(6) | BIT(7)) 37 #define LINK_RESET 0xf0000 38 #define EXYNOS5_SATA_MODE0 0x10 39 #define SATA_SPD_GEN3 BIT(1) 40 #define EXYNOS5_SATA_CTRL0 0x14 41 #define CTRL0_P0_PHY_CALIBRATED_SEL BIT(9) 42 #define CTRL0_P0_PHY_CALIBRATED BIT(8) 43 #define EXYNOS5_SATA_PHSATA_CTRLM 0xe0 44 #define PHCTRLM_REF_RATE BIT(1) 45 #define PHCTRLM_HIGH_SPEED BIT(0) 46 #define EXYNOS5_SATA_PHSATA_STATM 0xf0 47 #define PHSTATM_PLL_LOCKED BIT(0) 48 49 #define PHY_PLL_TIMEOUT (usecs_to_jiffies(1000)) 50 51 struct exynos_sata_phy { 52 struct phy *phy; 53 struct clk *phyclk; 54 void __iomem *regs; 55 struct regmap *pmureg; 56 struct i2c_client *client; 57 }; 58 59 static int wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit, 60 u32 status) 61 { 62 unsigned long timeout = jiffies + PHY_PLL_TIMEOUT; 63 64 while (time_before(jiffies, timeout)) { 65 if ((readl(base + reg) & checkbit) == status) 66 return 0; 67 } 68 69 return -EFAULT; 70 } 71 72 static int exynos_sata_phy_power_on(struct phy *phy) 73 { 74 struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy); 75 76 return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET, 77 EXYNOS5_SATAPHY_PMU_ENABLE, true); 78 79 } 80 81 static int exynos_sata_phy_power_off(struct phy *phy) 82 { 83 struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy); 84 85 return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET, 86 EXYNOS5_SATAPHY_PMU_ENABLE, false); 87 88 } 89 90 static int exynos_sata_phy_init(struct phy *phy) 91 { 92 u32 val = 0; 93 int ret = 0; 94 u8 buf[] = { 0x3a, 0x0b }; 95 struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy); 96 97 ret = regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET, 98 EXYNOS5_SATAPHY_PMU_ENABLE, true); 99 if (ret != 0) 100 dev_err(&sata_phy->phy->dev, "phy init failed\n"); 101 102 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET); 103 104 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET); 105 val |= RESET_GLOBAL_RST_N | RESET_CMN_RST_N | RESET_CMN_BLOCK_RST_N 106 | RESET_CMN_I2C_RST_N | RESET_TX_RX_PIPE_RST_N 107 | RESET_TX_RX_BLOCK_RST_N | RESET_TX_RX_I2C_RST_N; 108 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET); 109 110 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET); 111 val |= LINK_RESET; 112 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET); 113 114 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET); 115 val |= RESET_CMN_RST_N; 116 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET); 117 118 val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM); 119 val &= ~PHCTRLM_REF_RATE; 120 writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM); 121 122 /* High speed enable for Gen3 */ 123 val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM); 124 val |= PHCTRLM_HIGH_SPEED; 125 writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM); 126 127 val = readl(sata_phy->regs + EXYNOS5_SATA_CTRL0); 128 val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED; 129 writel(val, sata_phy->regs + EXYNOS5_SATA_CTRL0); 130 131 val = readl(sata_phy->regs + EXYNOS5_SATA_MODE0); 132 val |= SATA_SPD_GEN3; 133 writel(val, sata_phy->regs + EXYNOS5_SATA_MODE0); 134 135 ret = i2c_master_send(sata_phy->client, buf, sizeof(buf)); 136 if (ret < 0) 137 return ret; 138 139 /* release cmu reset */ 140 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET); 141 val &= ~RESET_CMN_RST_N; 142 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET); 143 144 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET); 145 val |= RESET_CMN_RST_N; 146 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET); 147 148 ret = wait_for_reg_status(sata_phy->regs, 149 EXYNOS5_SATA_PHSATA_STATM, 150 PHSTATM_PLL_LOCKED, 1); 151 if (ret < 0) 152 dev_err(&sata_phy->phy->dev, 153 "PHY PLL locking failed\n"); 154 return ret; 155 } 156 157 static const struct phy_ops exynos_sata_phy_ops = { 158 .init = exynos_sata_phy_init, 159 .power_on = exynos_sata_phy_power_on, 160 .power_off = exynos_sata_phy_power_off, 161 .owner = THIS_MODULE, 162 }; 163 164 static int exynos_sata_phy_probe(struct platform_device *pdev) 165 { 166 struct exynos_sata_phy *sata_phy; 167 struct device *dev = &pdev->dev; 168 struct resource *res; 169 struct phy_provider *phy_provider; 170 struct device_node *node; 171 int ret = 0; 172 173 sata_phy = devm_kzalloc(dev, sizeof(*sata_phy), GFP_KERNEL); 174 if (!sata_phy) 175 return -ENOMEM; 176 177 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 178 179 sata_phy->regs = devm_ioremap_resource(dev, res); 180 if (IS_ERR(sata_phy->regs)) 181 return PTR_ERR(sata_phy->regs); 182 183 sata_phy->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, 184 "samsung,syscon-phandle"); 185 if (IS_ERR(sata_phy->pmureg)) { 186 dev_err(dev, "syscon regmap lookup failed.\n"); 187 return PTR_ERR(sata_phy->pmureg); 188 } 189 190 node = of_parse_phandle(dev->of_node, 191 "samsung,exynos-sataphy-i2c-phandle", 0); 192 if (!node) 193 return -EINVAL; 194 195 sata_phy->client = of_find_i2c_device_by_node(node); 196 if (!sata_phy->client) 197 return -EPROBE_DEFER; 198 199 dev_set_drvdata(dev, sata_phy); 200 201 sata_phy->phyclk = devm_clk_get(dev, "sata_phyctrl"); 202 if (IS_ERR(sata_phy->phyclk)) { 203 dev_err(dev, "failed to get clk for PHY\n"); 204 return PTR_ERR(sata_phy->phyclk); 205 } 206 207 ret = clk_prepare_enable(sata_phy->phyclk); 208 if (ret < 0) { 209 dev_err(dev, "failed to enable source clk\n"); 210 return ret; 211 } 212 213 sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops); 214 if (IS_ERR(sata_phy->phy)) { 215 clk_disable_unprepare(sata_phy->phyclk); 216 dev_err(dev, "failed to create PHY\n"); 217 return PTR_ERR(sata_phy->phy); 218 } 219 220 phy_set_drvdata(sata_phy->phy, sata_phy); 221 222 phy_provider = devm_of_phy_provider_register(dev, 223 of_phy_simple_xlate); 224 if (IS_ERR(phy_provider)) { 225 clk_disable_unprepare(sata_phy->phyclk); 226 return PTR_ERR(phy_provider); 227 } 228 229 return 0; 230 } 231 232 static const struct of_device_id exynos_sata_phy_of_match[] = { 233 { .compatible = "samsung,exynos5250-sata-phy" }, 234 { }, 235 }; 236 MODULE_DEVICE_TABLE(of, exynos_sata_phy_of_match); 237 238 static struct platform_driver exynos_sata_phy_driver = { 239 .probe = exynos_sata_phy_probe, 240 .driver = { 241 .of_match_table = exynos_sata_phy_of_match, 242 .name = "samsung,sata-phy", 243 } 244 }; 245 module_platform_driver(exynos_sata_phy_driver); 246 247 MODULE_DESCRIPTION("Samsung SerDes PHY driver"); 248 MODULE_LICENSE("GPL v2"); 249 MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>"); 250 MODULE_AUTHOR("Yuvaraj C D <yuvaraj.cd@samsung.com>"); 251