xref: /linux/drivers/phy/rockchip/phy-rockchip-usb.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Rockchip usb PHY driver
4  *
5  * Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com>
6  * Copyright (C) 2014 ROCKCHIP, Inc.
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/clk-provider.h>
11 #include <linux/io.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/of.h>
16 #include <linux/phy/phy.h>
17 #include <linux/platform_device.h>
18 #include <linux/property.h>
19 #include <linux/regulator/consumer.h>
20 #include <linux/reset.h>
21 #include <linux/regmap.h>
22 #include <linux/mfd/syscon.h>
23 #include <linux/delay.h>
24 
25 static int enable_usb_uart;
26 
27 #define HIWORD_UPDATE(val, mask) \
28 		((val) | (mask) << 16)
29 
30 #define UOC_CON0					0x00
31 #define UOC_CON0_SIDDQ					BIT(13)
32 #define UOC_CON0_DISABLE				BIT(4)
33 #define UOC_CON0_COMMON_ON_N				BIT(0)
34 
35 #define UOC_CON2					0x08
36 #define UOC_CON2_SOFT_CON_SEL				BIT(2)
37 
38 #define UOC_CON3					0x0c
39 /* bits present on rk3188 and rk3288 phys */
40 #define UOC_CON3_UTMI_TERMSEL_FULLSPEED			BIT(5)
41 #define UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC		(1 << 3)
42 #define UOC_CON3_UTMI_XCVRSEELCT_MASK			(3 << 3)
43 #define UOC_CON3_UTMI_OPMODE_NODRIVING			(1 << 1)
44 #define UOC_CON3_UTMI_OPMODE_MASK			(3 << 1)
45 #define UOC_CON3_UTMI_SUSPENDN				BIT(0)
46 
47 struct rockchip_usb_phys {
48 	int reg;
49 	const char *pll_name;
50 };
51 
52 struct rockchip_usb_phy_base;
53 struct rockchip_usb_phy_pdata {
54 	struct rockchip_usb_phys *phys;
55 	int (*init_usb_uart)(struct regmap *grf,
56 			     const struct rockchip_usb_phy_pdata *pdata);
57 	int usb_uart_phy;
58 };
59 
60 struct rockchip_usb_phy_base {
61 	struct device *dev;
62 	struct regmap *reg_base;
63 	const struct rockchip_usb_phy_pdata *pdata;
64 };
65 
66 struct rockchip_usb_phy {
67 	struct rockchip_usb_phy_base *base;
68 	struct device_node *np;
69 	unsigned int	reg_offset;
70 	struct clk	*clk;
71 	struct clk      *clk480m;
72 	struct clk_hw	clk480m_hw;
73 	struct phy	*phy;
74 	bool		uart_enabled;
75 	struct reset_control *reset;
76 	struct regulator *vbus;
77 };
78 
rockchip_usb_phy_power(struct rockchip_usb_phy * phy,bool siddq)79 static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
80 					   bool siddq)
81 {
82 	u32 val = HIWORD_UPDATE(siddq ? UOC_CON0_SIDDQ : 0, UOC_CON0_SIDDQ);
83 
84 	return regmap_write(phy->base->reg_base, phy->reg_offset, val);
85 }
86 
rockchip_usb_phy480m_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)87 static unsigned long rockchip_usb_phy480m_recalc_rate(struct clk_hw *hw,
88 						unsigned long parent_rate)
89 {
90 	return 480000000;
91 }
92 
rockchip_usb_phy480m_disable(struct clk_hw * hw)93 static void rockchip_usb_phy480m_disable(struct clk_hw *hw)
94 {
95 	struct rockchip_usb_phy *phy = container_of(hw,
96 						    struct rockchip_usb_phy,
97 						    clk480m_hw);
98 
99 	if (phy->vbus)
100 		regulator_disable(phy->vbus);
101 
102 	/* Power down usb phy analog blocks by set siddq 1 */
103 	rockchip_usb_phy_power(phy, 1);
104 }
105 
rockchip_usb_phy480m_enable(struct clk_hw * hw)106 static int rockchip_usb_phy480m_enable(struct clk_hw *hw)
107 {
108 	struct rockchip_usb_phy *phy = container_of(hw,
109 						    struct rockchip_usb_phy,
110 						    clk480m_hw);
111 
112 	/* Power up usb phy analog blocks by set siddq 0 */
113 	return rockchip_usb_phy_power(phy, 0);
114 }
115 
rockchip_usb_phy480m_is_enabled(struct clk_hw * hw)116 static int rockchip_usb_phy480m_is_enabled(struct clk_hw *hw)
117 {
118 	struct rockchip_usb_phy *phy = container_of(hw,
119 						    struct rockchip_usb_phy,
120 						    clk480m_hw);
121 	int ret;
122 	u32 val;
123 
124 	ret = regmap_read(phy->base->reg_base, phy->reg_offset, &val);
125 	if (ret < 0)
126 		return ret;
127 
128 	return (val & UOC_CON0_SIDDQ) ? 0 : 1;
129 }
130 
131 static const struct clk_ops rockchip_usb_phy480m_ops = {
132 	.enable = rockchip_usb_phy480m_enable,
133 	.disable = rockchip_usb_phy480m_disable,
134 	.is_enabled = rockchip_usb_phy480m_is_enabled,
135 	.recalc_rate = rockchip_usb_phy480m_recalc_rate,
136 };
137 
rockchip_usb_phy_power_off(struct phy * _phy)138 static int rockchip_usb_phy_power_off(struct phy *_phy)
139 {
140 	struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
141 
142 	if (phy->uart_enabled)
143 		return -EBUSY;
144 
145 	clk_disable_unprepare(phy->clk480m);
146 
147 	return 0;
148 }
149 
rockchip_usb_phy_power_on(struct phy * _phy)150 static int rockchip_usb_phy_power_on(struct phy *_phy)
151 {
152 	struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
153 
154 	if (phy->uart_enabled)
155 		return -EBUSY;
156 
157 	if (phy->vbus) {
158 		int ret;
159 
160 		ret = regulator_enable(phy->vbus);
161 		if (ret)
162 			return ret;
163 	}
164 
165 	return clk_prepare_enable(phy->clk480m);
166 }
167 
rockchip_usb_phy_reset(struct phy * _phy)168 static int rockchip_usb_phy_reset(struct phy *_phy)
169 {
170 	struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
171 
172 	if (phy->reset) {
173 		reset_control_assert(phy->reset);
174 		udelay(10);
175 		reset_control_deassert(phy->reset);
176 	}
177 
178 	return 0;
179 }
180 
181 static const struct phy_ops ops = {
182 	.power_on	= rockchip_usb_phy_power_on,
183 	.power_off	= rockchip_usb_phy_power_off,
184 	.reset		= rockchip_usb_phy_reset,
185 	.owner		= THIS_MODULE,
186 };
187 
rockchip_usb_phy_action(void * data)188 static void rockchip_usb_phy_action(void *data)
189 {
190 	struct rockchip_usb_phy *rk_phy = data;
191 
192 	if (!rk_phy->uart_enabled) {
193 		of_clk_del_provider(rk_phy->np);
194 		clk_unregister(rk_phy->clk480m);
195 	}
196 
197 	if (rk_phy->clk)
198 		clk_put(rk_phy->clk);
199 }
200 
rockchip_usb_phy_init(struct rockchip_usb_phy_base * base,struct device_node * child)201 static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
202 				 struct device_node *child)
203 {
204 	struct rockchip_usb_phy *rk_phy;
205 	unsigned int reg_offset;
206 	const char *clk_name;
207 	struct clk_init_data init;
208 	int err, i;
209 
210 	rk_phy = devm_kzalloc(base->dev, sizeof(*rk_phy), GFP_KERNEL);
211 	if (!rk_phy)
212 		return -ENOMEM;
213 
214 	rk_phy->base = base;
215 	rk_phy->np = child;
216 
217 	if (of_property_read_u32(child, "reg", &reg_offset)) {
218 		dev_err(base->dev, "missing reg property in node %pOFn\n",
219 			child);
220 		return -EINVAL;
221 	}
222 
223 	rk_phy->reset = of_reset_control_get(child, "phy-reset");
224 	if (IS_ERR(rk_phy->reset))
225 		rk_phy->reset = NULL;
226 
227 	rk_phy->reg_offset = reg_offset;
228 
229 	rk_phy->clk = of_clk_get_by_name(child, "phyclk");
230 	if (IS_ERR(rk_phy->clk))
231 		rk_phy->clk = NULL;
232 
233 	i = 0;
234 	init.name = NULL;
235 	while (base->pdata->phys[i].reg) {
236 		if (base->pdata->phys[i].reg == reg_offset) {
237 			init.name = base->pdata->phys[i].pll_name;
238 			break;
239 		}
240 		i++;
241 	}
242 
243 	if (!init.name) {
244 		dev_err(base->dev, "phy data not found\n");
245 		return -EINVAL;
246 	}
247 
248 	if (enable_usb_uart && base->pdata->usb_uart_phy == i) {
249 		dev_dbg(base->dev, "phy%d used as uart output\n", i);
250 		rk_phy->uart_enabled = true;
251 	} else {
252 		if (rk_phy->clk) {
253 			clk_name = __clk_get_name(rk_phy->clk);
254 			init.flags = 0;
255 			init.parent_names = &clk_name;
256 			init.num_parents = 1;
257 		} else {
258 			init.flags = 0;
259 			init.parent_names = NULL;
260 			init.num_parents = 0;
261 		}
262 
263 		init.ops = &rockchip_usb_phy480m_ops;
264 		rk_phy->clk480m_hw.init = &init;
265 
266 		rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw);
267 		if (IS_ERR(rk_phy->clk480m)) {
268 			err = PTR_ERR(rk_phy->clk480m);
269 			goto err_clk;
270 		}
271 
272 		err = of_clk_add_provider(child, of_clk_src_simple_get,
273 					rk_phy->clk480m);
274 		if (err < 0)
275 			goto err_clk_prov;
276 	}
277 
278 	err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action,
279 				       rk_phy);
280 	if (err)
281 		return err;
282 
283 	rk_phy->phy = devm_phy_create(base->dev, child, &ops);
284 	if (IS_ERR(rk_phy->phy)) {
285 		dev_err(base->dev, "failed to create PHY\n");
286 		return PTR_ERR(rk_phy->phy);
287 	}
288 	phy_set_drvdata(rk_phy->phy, rk_phy);
289 
290 	rk_phy->vbus = devm_regulator_get_optional(&rk_phy->phy->dev, "vbus");
291 	if (IS_ERR(rk_phy->vbus)) {
292 		if (PTR_ERR(rk_phy->vbus) == -EPROBE_DEFER)
293 			return PTR_ERR(rk_phy->vbus);
294 		rk_phy->vbus = NULL;
295 	}
296 
297 	/*
298 	 * When acting as uart-pipe, just keep clock on otherwise
299 	 * only power up usb phy when it use, so disable it when init
300 	 */
301 	if (rk_phy->uart_enabled)
302 		return clk_prepare_enable(rk_phy->clk);
303 	else
304 		return rockchip_usb_phy_power(rk_phy, 1);
305 
306 err_clk_prov:
307 	if (!rk_phy->uart_enabled)
308 		clk_unregister(rk_phy->clk480m);
309 err_clk:
310 	if (rk_phy->clk)
311 		clk_put(rk_phy->clk);
312 	return err;
313 }
314 
315 static const struct rockchip_usb_phy_pdata rk3066a_pdata = {
316 	.phys = (struct rockchip_usb_phys[]){
317 		{ .reg = 0x17c, .pll_name = "sclk_otgphy0_480m" },
318 		{ .reg = 0x188, .pll_name = "sclk_otgphy1_480m" },
319 		{ /* sentinel */ }
320 	},
321 };
322 
rockchip_init_usb_uart_common(struct regmap * grf,const struct rockchip_usb_phy_pdata * pdata)323 static int __init rockchip_init_usb_uart_common(struct regmap *grf,
324 				const struct rockchip_usb_phy_pdata *pdata)
325 {
326 	int regoffs = pdata->phys[pdata->usb_uart_phy].reg;
327 	int ret;
328 	u32 val;
329 
330 	/*
331 	 * COMMON_ON and DISABLE settings are described in the TRM,
332 	 * but were not present in the original code.
333 	 * Also disable the analog phy components to save power.
334 	 */
335 	val = HIWORD_UPDATE(UOC_CON0_COMMON_ON_N
336 				| UOC_CON0_DISABLE
337 				| UOC_CON0_SIDDQ,
338 			    UOC_CON0_COMMON_ON_N
339 				| UOC_CON0_DISABLE
340 				| UOC_CON0_SIDDQ);
341 	ret = regmap_write(grf, regoffs + UOC_CON0, val);
342 	if (ret)
343 		return ret;
344 
345 	val = HIWORD_UPDATE(UOC_CON2_SOFT_CON_SEL,
346 			    UOC_CON2_SOFT_CON_SEL);
347 	ret = regmap_write(grf, regoffs + UOC_CON2, val);
348 	if (ret)
349 		return ret;
350 
351 	val = HIWORD_UPDATE(UOC_CON3_UTMI_OPMODE_NODRIVING
352 				| UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC
353 				| UOC_CON3_UTMI_TERMSEL_FULLSPEED,
354 			    UOC_CON3_UTMI_SUSPENDN
355 				| UOC_CON3_UTMI_OPMODE_MASK
356 				| UOC_CON3_UTMI_XCVRSEELCT_MASK
357 				| UOC_CON3_UTMI_TERMSEL_FULLSPEED);
358 	ret = regmap_write(grf, UOC_CON3, val);
359 	if (ret)
360 		return ret;
361 
362 	return 0;
363 }
364 
365 #define RK3188_UOC0_CON0				0x10c
366 #define RK3188_UOC0_CON0_BYPASSSEL			BIT(9)
367 #define RK3188_UOC0_CON0_BYPASSDMEN			BIT(8)
368 
369 /*
370  * Enable the bypass of uart2 data through the otg usb phy.
371  * See description of rk3288-variant for details.
372  */
rk3188_init_usb_uart(struct regmap * grf,const struct rockchip_usb_phy_pdata * pdata)373 static int __init rk3188_init_usb_uart(struct regmap *grf,
374 				const struct rockchip_usb_phy_pdata *pdata)
375 {
376 	u32 val;
377 	int ret;
378 
379 	ret = rockchip_init_usb_uart_common(grf, pdata);
380 	if (ret)
381 		return ret;
382 
383 	val = HIWORD_UPDATE(RK3188_UOC0_CON0_BYPASSSEL
384 				| RK3188_UOC0_CON0_BYPASSDMEN,
385 			    RK3188_UOC0_CON0_BYPASSSEL
386 				| RK3188_UOC0_CON0_BYPASSDMEN);
387 	ret = regmap_write(grf, RK3188_UOC0_CON0, val);
388 	if (ret)
389 		return ret;
390 
391 	return 0;
392 }
393 
394 static const struct rockchip_usb_phy_pdata rk3188_pdata = {
395 	.phys = (struct rockchip_usb_phys[]){
396 		{ .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" },
397 		{ .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" },
398 		{ /* sentinel */ }
399 	},
400 	.init_usb_uart = rk3188_init_usb_uart,
401 	.usb_uart_phy = 0,
402 };
403 
404 #define RK3288_UOC0_CON3				0x32c
405 #define RK3288_UOC0_CON3_BYPASSDMEN			BIT(6)
406 #define RK3288_UOC0_CON3_BYPASSSEL			BIT(7)
407 
408 /*
409  * Enable the bypass of uart2 data through the otg usb phy.
410  * Original description in the TRM.
411  * 1. Disable the OTG block by setting OTGDISABLE0 to 1’b1.
412  * 2. Disable the pull-up resistance on the D+ line by setting
413  *    OPMODE0[1:0] to 2’b01.
414  * 3. To ensure that the XO, Bias, and PLL blocks are powered down in Suspend
415  *    mode, set COMMONONN to 1’b1.
416  * 4. Place the USB PHY in Suspend mode by setting SUSPENDM0 to 1’b0.
417  * 5. Set BYPASSSEL0 to 1’b1.
418  * 6. To transmit data, controls BYPASSDMEN0, and BYPASSDMDATA0.
419  * To receive data, monitor FSVPLUS0.
420  *
421  * The actual code in the vendor kernel does some things differently.
422  */
rk3288_init_usb_uart(struct regmap * grf,const struct rockchip_usb_phy_pdata * pdata)423 static int __init rk3288_init_usb_uart(struct regmap *grf,
424 				const struct rockchip_usb_phy_pdata *pdata)
425 {
426 	u32 val;
427 	int ret;
428 
429 	ret = rockchip_init_usb_uart_common(grf, pdata);
430 	if (ret)
431 		return ret;
432 
433 	val = HIWORD_UPDATE(RK3288_UOC0_CON3_BYPASSSEL
434 				| RK3288_UOC0_CON3_BYPASSDMEN,
435 			    RK3288_UOC0_CON3_BYPASSSEL
436 				| RK3288_UOC0_CON3_BYPASSDMEN);
437 	ret = regmap_write(grf, RK3288_UOC0_CON3, val);
438 	if (ret)
439 		return ret;
440 
441 	return 0;
442 }
443 
444 static const struct rockchip_usb_phy_pdata rk3288_pdata = {
445 	.phys = (struct rockchip_usb_phys[]){
446 		{ .reg = 0x320, .pll_name = "sclk_otgphy0_480m" },
447 		{ .reg = 0x334, .pll_name = "sclk_otgphy1_480m" },
448 		{ .reg = 0x348, .pll_name = "sclk_otgphy2_480m" },
449 		{ /* sentinel */ }
450 	},
451 	.init_usb_uart = rk3288_init_usb_uart,
452 	.usb_uart_phy = 0,
453 };
454 
rockchip_usb_phy_probe(struct platform_device * pdev)455 static int rockchip_usb_phy_probe(struct platform_device *pdev)
456 {
457 	struct device *dev = &pdev->dev;
458 	struct rockchip_usb_phy_base *phy_base;
459 	struct phy_provider *phy_provider;
460 	struct device_node *child;
461 	int err;
462 
463 	phy_base = devm_kzalloc(dev, sizeof(*phy_base), GFP_KERNEL);
464 	if (!phy_base)
465 		return -ENOMEM;
466 
467 	phy_base->pdata = device_get_match_data(dev);
468 	if (!phy_base->pdata) {
469 		dev_err(dev, "missing phy data\n");
470 		return -EINVAL;
471 	}
472 
473 	phy_base->dev = dev;
474 	phy_base->reg_base = ERR_PTR(-ENODEV);
475 	if (dev->parent && dev->parent->of_node)
476 		phy_base->reg_base = syscon_node_to_regmap(
477 						dev->parent->of_node);
478 	if (IS_ERR(phy_base->reg_base))
479 		phy_base->reg_base = syscon_regmap_lookup_by_phandle(
480 						dev->of_node, "rockchip,grf");
481 	if (IS_ERR(phy_base->reg_base)) {
482 		dev_err(&pdev->dev, "Missing rockchip,grf property\n");
483 		return PTR_ERR(phy_base->reg_base);
484 	}
485 
486 	for_each_available_child_of_node(dev->of_node, child) {
487 		err = rockchip_usb_phy_init(phy_base, child);
488 		if (err) {
489 			of_node_put(child);
490 			return err;
491 		}
492 	}
493 
494 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
495 	return PTR_ERR_OR_ZERO(phy_provider);
496 }
497 
498 static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
499 	{ .compatible = "rockchip,rk3066a-usb-phy", .data = &rk3066a_pdata },
500 	{ .compatible = "rockchip,rk3188-usb-phy", .data = &rk3188_pdata },
501 	{ .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata },
502 	{}
503 };
504 
505 MODULE_DEVICE_TABLE(of, rockchip_usb_phy_dt_ids);
506 
507 static struct platform_driver rockchip_usb_driver = {
508 	.probe		= rockchip_usb_phy_probe,
509 	.driver		= {
510 		.name	= "rockchip-usb-phy",
511 		.of_match_table = rockchip_usb_phy_dt_ids,
512 	},
513 };
514 
515 module_platform_driver(rockchip_usb_driver);
516 
517 #ifndef MODULE
rockchip_init_usb_uart(void)518 static int __init rockchip_init_usb_uart(void)
519 {
520 	const struct of_device_id *match;
521 	const struct rockchip_usb_phy_pdata *data;
522 	struct device_node *np;
523 	struct regmap *grf;
524 	int ret;
525 
526 	if (!enable_usb_uart)
527 		return 0;
528 
529 	np = of_find_matching_node_and_match(NULL, rockchip_usb_phy_dt_ids,
530 					     &match);
531 	if (!np) {
532 		pr_err("%s: failed to find usbphy node\n", __func__);
533 		return -ENOTSUPP;
534 	}
535 
536 	pr_debug("%s: using settings for %s\n", __func__, match->compatible);
537 	data = match->data;
538 
539 	if (!data->init_usb_uart) {
540 		pr_err("%s: usb-uart not available on %s\n",
541 		       __func__, match->compatible);
542 		return -ENOTSUPP;
543 	}
544 
545 	grf = ERR_PTR(-ENODEV);
546 	if (np->parent)
547 		grf = syscon_node_to_regmap(np->parent);
548 	if (IS_ERR(grf))
549 		grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
550 	if (IS_ERR(grf)) {
551 		pr_err("%s: Missing rockchip,grf property, %lu\n",
552 		       __func__, PTR_ERR(grf));
553 		return PTR_ERR(grf);
554 	}
555 
556 	ret = data->init_usb_uart(grf, data);
557 	if (ret) {
558 		pr_err("%s: could not init usb_uart, %d\n", __func__, ret);
559 		enable_usb_uart = 0;
560 		return ret;
561 	}
562 
563 	return 0;
564 }
565 early_initcall(rockchip_init_usb_uart);
566 
rockchip_usb_uart(char * buf)567 static int __init rockchip_usb_uart(char *buf)
568 {
569 	enable_usb_uart = true;
570 	return 0;
571 }
572 early_param("rockchip.usb_uart", rockchip_usb_uart);
573 #endif
574 
575 MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
576 MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");
577 MODULE_LICENSE("GPL v2");
578