xref: /linux/drivers/phy/st/phy-spear1340-miphy.c (revision bfd5bb6f90af092aa345b15cd78143956a13c2a8)
1 /*
2  * ST spear1340-miphy driver
3  *
4  * Copyright (C) 2014 ST Microelectronics
5  * Pratyush Anand <pratyush.anand@gmail.com>
6  * Mohit Kumar <mohit.kumar.dhaka@gmail.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 
78 enum spear1340_miphy_mode {
79 	SATA,
80 	PCIE,
81 };
82 
83 struct 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 
92 static 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 
116 static 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 
138 static 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 
150 static 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 
160 static 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 
173 static 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 
186 static const struct of_device_id spear1340_miphy_of_match[] = {
187 	{ .compatible = "st,spear1340-miphy" },
188 	{ },
189 };
190 MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match);
191 
192 static const 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
199 static 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 
210 static 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 
222 static SIMPLE_DEV_PM_OPS(spear1340_miphy_pm_ops, spear1340_miphy_suspend,
223 			 spear1340_miphy_resume);
224 
225 static 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 
245 static 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 
281 static 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 
290 module_platform_driver(spear1340_miphy_driver);
291 
292 MODULE_DESCRIPTION("ST SPEAR1340-MIPHY driver");
293 MODULE_AUTHOR("Pratyush Anand <pratyush.anand@gmail.com>");
294 MODULE_LICENSE("GPL v2");
295