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