xref: /linux/drivers/phy/socionext/phy-uniphier-usb3hs.c (revision e68c2a8a2f45cbe4a237b874f87ec14ae2dfa84c)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller
4  * Copyright 2015-2018 Socionext Inc.
5  * Author:
6  *      Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
7  * Contributors:
8  *      Motoya Tanigawa <tanigawa.motoya@socionext.com>
9  *      Masami Hiramatsu <masami.hiramatsu@linaro.org>
10  */
11 
12 #include <linux/bitfield.h>
13 #include <linux/bitops.h>
14 #include <linux/clk.h>
15 #include <linux/io.h>
16 #include <linux/module.h>
17 #include <linux/nvmem-consumer.h>
18 #include <linux/of.h>
19 #include <linux/of_platform.h>
20 #include <linux/phy/phy.h>
21 #include <linux/platform_device.h>
22 #include <linux/regulator/consumer.h>
23 #include <linux/reset.h>
24 #include <linux/slab.h>
25 
26 #define HSPHY_CFG0		0x0
27 #define HSPHY_CFG0_HS_I_MASK	GENMASK(31, 28)
28 #define HSPHY_CFG0_HSDISC_MASK	GENMASK(27, 26)
29 #define HSPHY_CFG0_SWING_MASK	GENMASK(17, 16)
30 #define HSPHY_CFG0_SEL_T_MASK	GENMASK(15, 12)
31 #define HSPHY_CFG0_RTERM_MASK	GENMASK(7, 6)
32 #define HSPHY_CFG0_TRIMMASK	(HSPHY_CFG0_HS_I_MASK \
33 				 | HSPHY_CFG0_SEL_T_MASK \
34 				 | HSPHY_CFG0_RTERM_MASK)
35 
36 #define HSPHY_CFG1		0x4
37 #define HSPHY_CFG1_DAT_EN	BIT(29)
38 #define HSPHY_CFG1_ADR_EN	BIT(28)
39 #define HSPHY_CFG1_ADR_MASK	GENMASK(27, 16)
40 #define HSPHY_CFG1_DAT_MASK	GENMASK(23, 16)
41 
42 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
43 
44 #define LS_SLEW		PHY_F(10, 6, 6)	/* LS mode slew rate */
45 #define FS_LS_DRV	PHY_F(10, 5, 5)	/* FS/LS slew rate */
46 
47 #define MAX_PHY_PARAMS	2
48 
49 struct uniphier_u3hsphy_param {
50 	struct {
51 		int reg_no;
52 		int msb;
53 		int lsb;
54 	} field;
55 	u8 value;
56 };
57 
58 struct uniphier_u3hsphy_trim_param {
59 	unsigned int rterm;
60 	unsigned int sel_t;
61 	unsigned int hs_i;
62 };
63 
64 #define trim_param_is_valid(p)	((p)->rterm || (p)->sel_t || (p)->hs_i)
65 
66 struct uniphier_u3hsphy_priv {
67 	struct device *dev;
68 	void __iomem *base;
69 	struct clk *clk, *clk_parent, *clk_ext, *clk_parent_gio;
70 	struct reset_control *rst, *rst_parent, *rst_parent_gio;
71 	struct regulator *vbus;
72 	const struct uniphier_u3hsphy_soc_data *data;
73 };
74 
75 struct uniphier_u3hsphy_soc_data {
76 	bool is_legacy;
77 	int nparams;
78 	const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
79 	u32 config0;
80 	u32 config1;
81 	void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig,
82 			  struct uniphier_u3hsphy_trim_param *pt);
83 };
84 
85 static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv,
86 				       u32 *pconfig,
87 				       struct uniphier_u3hsphy_trim_param *pt)
88 {
89 	*pconfig &= ~HSPHY_CFG0_RTERM_MASK;
90 	*pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm);
91 
92 	*pconfig &= ~HSPHY_CFG0_SEL_T_MASK;
93 	*pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t);
94 
95 	*pconfig &= ~HSPHY_CFG0_HS_I_MASK;
96 	*pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK,  pt->hs_i);
97 }
98 
99 static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv,
100 					const char *name, unsigned int *val)
101 {
102 	struct nvmem_cell *cell;
103 	u8 *buf;
104 
105 	cell = devm_nvmem_cell_get(priv->dev, name);
106 	if (IS_ERR(cell))
107 		return PTR_ERR(cell);
108 
109 	buf = nvmem_cell_read(cell, NULL);
110 	if (IS_ERR(buf))
111 		return PTR_ERR(buf);
112 
113 	*val = *buf;
114 
115 	kfree(buf);
116 
117 	return 0;
118 }
119 
120 static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv,
121 					 struct uniphier_u3hsphy_trim_param *pt)
122 {
123 	int ret;
124 
125 	ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm);
126 	if (ret)
127 		return ret;
128 
129 	ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t);
130 	if (ret)
131 		return ret;
132 
133 	ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i);
134 	if (ret)
135 		return ret;
136 
137 	return 0;
138 }
139 
140 static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv,
141 					  u32 *pconfig)
142 {
143 	struct uniphier_u3hsphy_trim_param trim;
144 	int ret, trimmed = 0;
145 
146 	if (priv->data->trim_func) {
147 		ret = uniphier_u3hsphy_get_nvparams(priv, &trim);
148 		if (ret == -EPROBE_DEFER)
149 			return ret;
150 
151 		/*
152 		 * call trim_func only when trimming parameters that aren't
153 		 * all-zero can be acquired. All-zero parameters mean nothing
154 		 * has been written to nvmem.
155 		 */
156 		if (!ret && trim_param_is_valid(&trim)) {
157 			priv->data->trim_func(priv, pconfig, &trim);
158 			trimmed = 1;
159 		} else {
160 			dev_dbg(priv->dev, "can't get parameter from nvmem\n");
161 		}
162 	}
163 
164 	/* use default parameters without trimming values */
165 	if (!trimmed) {
166 		*pconfig &= ~HSPHY_CFG0_HSDISC_MASK;
167 		*pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3);
168 	}
169 
170 	return 0;
171 }
172 
173 static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv,
174 				       const struct uniphier_u3hsphy_param *p)
175 {
176 	u32 val;
177 	u32 field_mask = GENMASK(p->field.msb, p->field.lsb);
178 	u8 data;
179 
180 	val = readl(priv->base + HSPHY_CFG1);
181 	val &= ~HSPHY_CFG1_ADR_MASK;
182 	val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no)
183 		| HSPHY_CFG1_ADR_EN;
184 	writel(val, priv->base + HSPHY_CFG1);
185 
186 	val = readl(priv->base + HSPHY_CFG1);
187 	val &= ~HSPHY_CFG1_ADR_EN;
188 	writel(val, priv->base + HSPHY_CFG1);
189 
190 	val = readl(priv->base + HSPHY_CFG1);
191 	val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask);
192 	data = field_mask & (p->value << p->field.lsb);
193 	val |=  FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN;
194 	writel(val, priv->base + HSPHY_CFG1);
195 
196 	val = readl(priv->base + HSPHY_CFG1);
197 	val &= ~HSPHY_CFG1_DAT_EN;
198 	writel(val, priv->base + HSPHY_CFG1);
199 }
200 
201 static int uniphier_u3hsphy_power_on(struct phy *phy)
202 {
203 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
204 	int ret;
205 
206 	ret = clk_prepare_enable(priv->clk_ext);
207 	if (ret)
208 		return ret;
209 
210 	ret = clk_prepare_enable(priv->clk);
211 	if (ret)
212 		goto out_clk_ext_disable;
213 
214 	ret = reset_control_deassert(priv->rst);
215 	if (ret)
216 		goto out_clk_disable;
217 
218 	if (priv->vbus) {
219 		ret = regulator_enable(priv->vbus);
220 		if (ret)
221 			goto out_rst_assert;
222 	}
223 
224 	return 0;
225 
226 out_rst_assert:
227 	reset_control_assert(priv->rst);
228 out_clk_disable:
229 	clk_disable_unprepare(priv->clk);
230 out_clk_ext_disable:
231 	clk_disable_unprepare(priv->clk_ext);
232 
233 	return ret;
234 }
235 
236 static int uniphier_u3hsphy_power_off(struct phy *phy)
237 {
238 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
239 
240 	if (priv->vbus)
241 		regulator_disable(priv->vbus);
242 
243 	reset_control_assert(priv->rst);
244 	clk_disable_unprepare(priv->clk);
245 	clk_disable_unprepare(priv->clk_ext);
246 
247 	return 0;
248 }
249 
250 static int uniphier_u3hsphy_init(struct phy *phy)
251 {
252 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
253 	u32 config0, config1;
254 	int i, ret;
255 
256 	ret = clk_prepare_enable(priv->clk_parent);
257 	if (ret)
258 		return ret;
259 
260 	ret = clk_prepare_enable(priv->clk_parent_gio);
261 	if (ret)
262 		goto out_clk_disable;
263 
264 	ret = reset_control_deassert(priv->rst_parent);
265 	if (ret)
266 		goto out_clk_gio_disable;
267 
268 	ret = reset_control_deassert(priv->rst_parent_gio);
269 	if (ret)
270 		goto out_rst_assert;
271 
272 	if ((priv->data->is_legacy)
273 	    || (!priv->data->config0 && !priv->data->config1))
274 		return 0;
275 
276 	config0 = priv->data->config0;
277 	config1 = priv->data->config1;
278 
279 	ret = uniphier_u3hsphy_update_config(priv, &config0);
280 	if (ret)
281 		goto out_rst_assert;
282 
283 	writel(config0, priv->base + HSPHY_CFG0);
284 	writel(config1, priv->base + HSPHY_CFG1);
285 
286 	for (i = 0; i < priv->data->nparams; i++)
287 		uniphier_u3hsphy_set_param(priv, &priv->data->param[i]);
288 
289 	return 0;
290 
291 out_rst_assert:
292 	reset_control_assert(priv->rst_parent);
293 out_clk_gio_disable:
294 	clk_disable_unprepare(priv->clk_parent_gio);
295 out_clk_disable:
296 	clk_disable_unprepare(priv->clk_parent);
297 
298 	return ret;
299 }
300 
301 static int uniphier_u3hsphy_exit(struct phy *phy)
302 {
303 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
304 
305 	reset_control_assert(priv->rst_parent_gio);
306 	reset_control_assert(priv->rst_parent);
307 	clk_disable_unprepare(priv->clk_parent_gio);
308 	clk_disable_unprepare(priv->clk_parent);
309 
310 	return 0;
311 }
312 
313 static const struct phy_ops uniphier_u3hsphy_ops = {
314 	.init           = uniphier_u3hsphy_init,
315 	.exit           = uniphier_u3hsphy_exit,
316 	.power_on       = uniphier_u3hsphy_power_on,
317 	.power_off      = uniphier_u3hsphy_power_off,
318 	.owner          = THIS_MODULE,
319 };
320 
321 static int uniphier_u3hsphy_probe(struct platform_device *pdev)
322 {
323 	struct device *dev = &pdev->dev;
324 	struct uniphier_u3hsphy_priv *priv;
325 	struct phy_provider *phy_provider;
326 	struct phy *phy;
327 
328 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
329 	if (!priv)
330 		return -ENOMEM;
331 
332 	priv->dev = dev;
333 	priv->data = of_device_get_match_data(dev);
334 	if (WARN_ON(!priv->data ||
335 		    priv->data->nparams > MAX_PHY_PARAMS))
336 		return -EINVAL;
337 
338 	priv->base = devm_platform_ioremap_resource(pdev, 0);
339 	if (IS_ERR(priv->base))
340 		return PTR_ERR(priv->base);
341 
342 	if (!priv->data->is_legacy) {
343 		priv->clk = devm_clk_get(dev, "phy");
344 		if (IS_ERR(priv->clk))
345 			return PTR_ERR(priv->clk);
346 
347 		priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
348 		if (IS_ERR(priv->clk_ext))
349 			return PTR_ERR(priv->clk_ext);
350 
351 		priv->rst = devm_reset_control_get_shared(dev, "phy");
352 		if (IS_ERR(priv->rst))
353 			return PTR_ERR(priv->rst);
354 
355 	} else {
356 		priv->clk_parent_gio = devm_clk_get(dev, "gio");
357 		if (IS_ERR(priv->clk_parent_gio))
358 			return PTR_ERR(priv->clk_parent_gio);
359 
360 		priv->rst_parent_gio =
361 			devm_reset_control_get_shared(dev, "gio");
362 		if (IS_ERR(priv->rst_parent_gio))
363 			return PTR_ERR(priv->rst_parent_gio);
364 	}
365 
366 	priv->clk_parent = devm_clk_get(dev, "link");
367 	if (IS_ERR(priv->clk_parent))
368 		return PTR_ERR(priv->clk_parent);
369 
370 	priv->rst_parent = devm_reset_control_get_shared(dev, "link");
371 	if (IS_ERR(priv->rst_parent))
372 		return PTR_ERR(priv->rst_parent);
373 
374 	priv->vbus = devm_regulator_get_optional(dev, "vbus");
375 	if (IS_ERR(priv->vbus)) {
376 		if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
377 			return PTR_ERR(priv->vbus);
378 		priv->vbus = NULL;
379 	}
380 
381 	phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops);
382 	if (IS_ERR(phy))
383 		return PTR_ERR(phy);
384 
385 	phy_set_drvdata(phy, priv);
386 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
387 
388 	return PTR_ERR_OR_ZERO(phy_provider);
389 }
390 
391 static const struct uniphier_u3hsphy_soc_data uniphier_pro5_data = {
392 	.is_legacy = true,
393 	.nparams = 0,
394 };
395 
396 static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
397 	.is_legacy = false,
398 	.nparams = 0,
399 };
400 
401 static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
402 	.is_legacy = false,
403 	.nparams = 2,
404 	.param = {
405 		{ LS_SLEW, 1 },
406 		{ FS_LS_DRV, 1 },
407 	},
408 	.trim_func = uniphier_u3hsphy_trim_ld20,
409 	.config0 = 0x92316680,
410 	.config1 = 0x00000106,
411 };
412 
413 static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
414 	.is_legacy = false,
415 	.nparams = 0,
416 	.trim_func = uniphier_u3hsphy_trim_ld20,
417 	.config0 = 0x92316680,
418 	.config1 = 0x00000106,
419 };
420 
421 static const struct of_device_id uniphier_u3hsphy_match[] = {
422 	{
423 		.compatible = "socionext,uniphier-pro5-usb3-hsphy",
424 		.data = &uniphier_pro5_data,
425 	},
426 	{
427 		.compatible = "socionext,uniphier-pxs2-usb3-hsphy",
428 		.data = &uniphier_pxs2_data,
429 	},
430 	{
431 		.compatible = "socionext,uniphier-ld20-usb3-hsphy",
432 		.data = &uniphier_ld20_data,
433 	},
434 	{
435 		.compatible = "socionext,uniphier-pxs3-usb3-hsphy",
436 		.data = &uniphier_pxs3_data,
437 	},
438 	{ /* sentinel */ }
439 };
440 MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match);
441 
442 static struct platform_driver uniphier_u3hsphy_driver = {
443 	.probe = uniphier_u3hsphy_probe,
444 	.driver	= {
445 		.name = "uniphier-usb3-hsphy",
446 		.of_match_table	= uniphier_u3hsphy_match,
447 	},
448 };
449 
450 module_platform_driver(uniphier_u3hsphy_driver);
451 
452 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
453 MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
454 MODULE_LICENSE("GPL v2");
455