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