xref: /rk3399_rockchip-uboot/drivers/usb/host/ohci-da8xx.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
125f8bf6eSSughosh Ganu /*
225f8bf6eSSughosh Ganu  * Copyright (C) 2012 Sughosh Ganu <urwithsughosh@gmail.com>
325f8bf6eSSughosh Ganu  *
41a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
525f8bf6eSSughosh Ganu  */
625f8bf6eSSughosh Ganu 
725f8bf6eSSughosh Ganu #include <common.h>
8dff9f0f7SAdam Ford #include <asm/io.h>
9dff9f0f7SAdam Ford #include <clk.h>
10dff9f0f7SAdam Ford #include <dm.h>
11dff9f0f7SAdam Ford #include <dm/ofnode.h>
12dff9f0f7SAdam Ford #include <generic-phy.h>
13dff9f0f7SAdam Ford #include <reset.h>
14dff9f0f7SAdam Ford #include "ohci.h"
1525f8bf6eSSughosh Ganu #include <asm/arch/da8xx-usb.h>
1625f8bf6eSSughosh Ganu 
17dff9f0f7SAdam Ford struct da8xx_ohci {
18dff9f0f7SAdam Ford 	ohci_t ohci;
19dff9f0f7SAdam Ford 	struct clk *clocks;	/* clock list */
20dff9f0f7SAdam Ford 	struct phy phy;
21dff9f0f7SAdam Ford 	int clock_count;	/* number of clock in clock list */
22dff9f0f7SAdam Ford };
23dff9f0f7SAdam Ford 
usb_phy_on(void)24dff9f0f7SAdam Ford static int usb_phy_on(void)
25dff9f0f7SAdam Ford {
26dff9f0f7SAdam Ford 	unsigned long timeout;
27dff9f0f7SAdam Ford 
28dff9f0f7SAdam Ford 	clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
29dff9f0f7SAdam Ford 			(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN |
30dff9f0f7SAdam Ford 			CFGCHIP2_OTGPWRDN | CFGCHIP2_OTGMODE |
31dff9f0f7SAdam Ford 			CFGCHIP2_REFFREQ | CFGCHIP2_USB1PHYCLKMUX),
32dff9f0f7SAdam Ford 			(CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN |
33dff9f0f7SAdam Ford 			CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ |
34dff9f0f7SAdam Ford 			CFGCHIP2_USB2PHYCLKMUX | CFGCHIP2_USB1SUSPENDM));
35dff9f0f7SAdam Ford 
36dff9f0f7SAdam Ford 	/* wait until the usb phy pll locks */
37dff9f0f7SAdam Ford 	timeout = get_timer(0);
38dff9f0f7SAdam Ford 	while (get_timer(timeout) < 10) {
39dff9f0f7SAdam Ford 		if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD)
40dff9f0f7SAdam Ford 			return 1;
41dff9f0f7SAdam Ford 	}
42dff9f0f7SAdam Ford 
43dff9f0f7SAdam Ford 	/* USB phy was not turned on */
44dff9f0f7SAdam Ford 	return 0;
45dff9f0f7SAdam Ford }
46dff9f0f7SAdam Ford 
usb_phy_off(void)47dff9f0f7SAdam Ford static void usb_phy_off(void)
48dff9f0f7SAdam Ford {
49dff9f0f7SAdam Ford 	/* Power down the on-chip PHY. */
50dff9f0f7SAdam Ford 	clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
51dff9f0f7SAdam Ford 			CFGCHIP2_PHY_PLLON | CFGCHIP2_USB1SUSPENDM,
52dff9f0f7SAdam Ford 			CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN |
53dff9f0f7SAdam Ford 			CFGCHIP2_RESET);
54dff9f0f7SAdam Ford }
55dff9f0f7SAdam Ford 
usb_cpu_init(void)5625f8bf6eSSughosh Ganu int usb_cpu_init(void)
5725f8bf6eSSughosh Ganu {
5825f8bf6eSSughosh Ganu 	/* enable psc for usb2.0 */
5925f8bf6eSSughosh Ganu 	lpsc_on(DAVINCI_LPSC_USB20);
6025f8bf6eSSughosh Ganu 
6125f8bf6eSSughosh Ganu 	/* enable psc for usb1.0 */
6225f8bf6eSSughosh Ganu 	lpsc_on(DAVINCI_LPSC_USB11);
6325f8bf6eSSughosh Ganu 
6425f8bf6eSSughosh Ganu 	/* start the on-chip usb phy and its pll */
6525f8bf6eSSughosh Ganu 	if (usb_phy_on())
6625f8bf6eSSughosh Ganu 		return 0;
6725f8bf6eSSughosh Ganu 
6825f8bf6eSSughosh Ganu 	return 1;
6925f8bf6eSSughosh Ganu }
7025f8bf6eSSughosh Ganu 
usb_cpu_stop(void)7125f8bf6eSSughosh Ganu int usb_cpu_stop(void)
7225f8bf6eSSughosh Ganu {
7325f8bf6eSSughosh Ganu 	usb_phy_off();
7425f8bf6eSSughosh Ganu 
7525f8bf6eSSughosh Ganu 	/* turn off the usb clock and assert the module reset */
7625f8bf6eSSughosh Ganu 	lpsc_disable(DAVINCI_LPSC_USB11);
7725f8bf6eSSughosh Ganu 	lpsc_disable(DAVINCI_LPSC_USB20);
7825f8bf6eSSughosh Ganu 
7925f8bf6eSSughosh Ganu 	return 0;
8025f8bf6eSSughosh Ganu }
8125f8bf6eSSughosh Ganu 
usb_cpu_init_fail(void)8225f8bf6eSSughosh Ganu int usb_cpu_init_fail(void)
8325f8bf6eSSughosh Ganu {
8425f8bf6eSSughosh Ganu 	return usb_cpu_stop();
8525f8bf6eSSughosh Ganu }
86dff9f0f7SAdam Ford 
87dff9f0f7SAdam Ford #if CONFIG_IS_ENABLED(DM_USB)
ohci_da8xx_probe(struct udevice * dev)88dff9f0f7SAdam Ford static int ohci_da8xx_probe(struct udevice *dev)
89dff9f0f7SAdam Ford {
90dff9f0f7SAdam Ford 	struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
91dff9f0f7SAdam Ford 	struct da8xx_ohci *priv = dev_get_priv(dev);
92dff9f0f7SAdam Ford 	int i, err, ret, clock_nb;
93dff9f0f7SAdam Ford 
94dff9f0f7SAdam Ford 	err = 0;
95dff9f0f7SAdam Ford 	priv->clock_count = 0;
96dff9f0f7SAdam Ford 	clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
97*0620c8adSAdam Ford 
98*0620c8adSAdam Ford 	if (clock_nb < 0)
99*0620c8adSAdam Ford 		return clock_nb;
100*0620c8adSAdam Ford 
101dff9f0f7SAdam Ford 	if (clock_nb > 0) {
102dff9f0f7SAdam Ford 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
103dff9f0f7SAdam Ford 					    GFP_KERNEL);
104dff9f0f7SAdam Ford 		if (!priv->clocks)
105dff9f0f7SAdam Ford 			return -ENOMEM;
106dff9f0f7SAdam Ford 
107dff9f0f7SAdam Ford 		for (i = 0; i < clock_nb; i++) {
108dff9f0f7SAdam Ford 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
109dff9f0f7SAdam Ford 			if (err < 0)
110dff9f0f7SAdam Ford 				break;
111dff9f0f7SAdam Ford 
112dff9f0f7SAdam Ford 			err = clk_enable(&priv->clocks[i]);
113dff9f0f7SAdam Ford 			if (err) {
114dff9f0f7SAdam Ford 				dev_err(dev, "failed to enable clock %d\n", i);
115dff9f0f7SAdam Ford 				clk_free(&priv->clocks[i]);
116dff9f0f7SAdam Ford 				goto clk_err;
117dff9f0f7SAdam Ford 			}
118dff9f0f7SAdam Ford 			priv->clock_count++;
119dff9f0f7SAdam Ford 		}
120dff9f0f7SAdam Ford 	}
121dff9f0f7SAdam Ford 
122dff9f0f7SAdam Ford 	err = usb_cpu_init();
123dff9f0f7SAdam Ford 
124dff9f0f7SAdam Ford 	if (err)
125dff9f0f7SAdam Ford 		goto clk_err;
126dff9f0f7SAdam Ford 
127dff9f0f7SAdam Ford 	err = ohci_register(dev, regs);
128dff9f0f7SAdam Ford 	if (err)
129dff9f0f7SAdam Ford 		goto phy_err;
130dff9f0f7SAdam Ford 
131dff9f0f7SAdam Ford 	return 0;
132dff9f0f7SAdam Ford 
133dff9f0f7SAdam Ford phy_err:
134dff9f0f7SAdam Ford 	ret = usb_cpu_stop();
135dff9f0f7SAdam Ford 	if (ret)
136dff9f0f7SAdam Ford 		dev_err(dev, "failed to shutdown usb phy\n");
137dff9f0f7SAdam Ford 
138dff9f0f7SAdam Ford clk_err:
139dff9f0f7SAdam Ford 	ret = clk_release_all(priv->clocks, priv->clock_count);
140dff9f0f7SAdam Ford 	if (ret)
141dff9f0f7SAdam Ford 		dev_err(dev, "failed to disable all clocks\n");
142dff9f0f7SAdam Ford 
143dff9f0f7SAdam Ford 	return err;
144dff9f0f7SAdam Ford }
145dff9f0f7SAdam Ford 
ohci_da8xx_remove(struct udevice * dev)146dff9f0f7SAdam Ford static int ohci_da8xx_remove(struct udevice *dev)
147dff9f0f7SAdam Ford {
148dff9f0f7SAdam Ford 	struct da8xx_ohci *priv = dev_get_priv(dev);
149dff9f0f7SAdam Ford 	int ret;
150dff9f0f7SAdam Ford 
151dff9f0f7SAdam Ford 	ret = ohci_deregister(dev);
152dff9f0f7SAdam Ford 	if (ret)
153dff9f0f7SAdam Ford 		return ret;
154dff9f0f7SAdam Ford 
155dff9f0f7SAdam Ford 	ret = usb_cpu_stop();
156dff9f0f7SAdam Ford 	if (ret)
157dff9f0f7SAdam Ford 		return ret;
158dff9f0f7SAdam Ford 
159dff9f0f7SAdam Ford 	return clk_release_all(priv->clocks, priv->clock_count);
160dff9f0f7SAdam Ford }
161dff9f0f7SAdam Ford 
162dff9f0f7SAdam Ford static const struct udevice_id da8xx_ohci_ids[] = {
163dff9f0f7SAdam Ford 	{ .compatible = "ti,da830-ohci" },
164dff9f0f7SAdam Ford 	{ }
165dff9f0f7SAdam Ford };
166dff9f0f7SAdam Ford 
167dff9f0f7SAdam Ford U_BOOT_DRIVER(ohci_generic) = {
168dff9f0f7SAdam Ford 	.name	= "ohci-da8xx",
169dff9f0f7SAdam Ford 	.id	= UCLASS_USB,
170dff9f0f7SAdam Ford 	.of_match = da8xx_ohci_ids,
171dff9f0f7SAdam Ford 	.probe = ohci_da8xx_probe,
172dff9f0f7SAdam Ford 	.remove = ohci_da8xx_remove,
173dff9f0f7SAdam Ford 	.ops	= &ohci_usb_ops,
174dff9f0f7SAdam Ford 	.priv_auto_alloc_size = sizeof(struct da8xx_ohci),
175*0620c8adSAdam Ford 	.flags	= DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE,
176dff9f0f7SAdam Ford };
177dff9f0f7SAdam Ford #endif
178