]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
25f8bf6e SG |
2 | /* |
3 | * Copyright (C) 2012 Sughosh Ganu <[email protected]> | |
25f8bf6e SG |
4 | */ |
5 | ||
6 | #include <common.h> | |
336d4615 | 7 | #include <malloc.h> |
9da54743 AF |
8 | #include <asm/io.h> |
9 | #include <clk.h> | |
10 | #include <dm.h> | |
336d4615 | 11 | #include <dm/device_compat.h> |
61b29b82 | 12 | #include <dm/devres.h> |
9da54743 AF |
13 | #include <dm/ofnode.h> |
14 | #include <generic-phy.h> | |
15 | #include <reset.h> | |
16 | #include "ohci.h" | |
25f8bf6e SG |
17 | #include <asm/arch/da8xx-usb.h> |
18 | ||
9da54743 AF |
19 | struct da8xx_ohci { |
20 | ohci_t ohci; | |
21 | struct clk *clocks; /* clock list */ | |
22 | struct phy phy; | |
23 | int clock_count; /* number of clock in clock list */ | |
24 | }; | |
25 | ||
26 | static int usb_phy_on(void) | |
27 | { | |
28 | unsigned long timeout; | |
29 | ||
30 | clrsetbits_le32(&davinci_syscfg_regs->cfgchip2, | |
31 | (CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | | |
32 | CFGCHIP2_OTGPWRDN | CFGCHIP2_OTGMODE | | |
33 | CFGCHIP2_REFFREQ | CFGCHIP2_USB1PHYCLKMUX), | |
34 | (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN | | |
35 | CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ | | |
36 | CFGCHIP2_USB2PHYCLKMUX | CFGCHIP2_USB1SUSPENDM)); | |
37 | ||
38 | /* wait until the usb phy pll locks */ | |
39 | timeout = get_timer(0); | |
40 | while (get_timer(timeout) < 10) { | |
41 | if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD) | |
42 | return 1; | |
43 | } | |
44 | ||
45 | /* USB phy was not turned on */ | |
46 | return 0; | |
47 | } | |
48 | ||
49 | static void usb_phy_off(void) | |
50 | { | |
51 | /* Power down the on-chip PHY. */ | |
52 | clrsetbits_le32(&davinci_syscfg_regs->cfgchip2, | |
53 | CFGCHIP2_PHY_PLLON | CFGCHIP2_USB1SUSPENDM, | |
54 | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | | |
55 | CFGCHIP2_RESET); | |
56 | } | |
57 | ||
25f8bf6e SG |
58 | int usb_cpu_init(void) |
59 | { | |
60 | /* enable psc for usb2.0 */ | |
61 | lpsc_on(DAVINCI_LPSC_USB20); | |
62 | ||
63 | /* enable psc for usb1.0 */ | |
64 | lpsc_on(DAVINCI_LPSC_USB11); | |
65 | ||
66 | /* start the on-chip usb phy and its pll */ | |
67 | if (usb_phy_on()) | |
68 | return 0; | |
69 | ||
70 | return 1; | |
71 | } | |
72 | ||
73 | int usb_cpu_stop(void) | |
74 | { | |
75 | usb_phy_off(); | |
76 | ||
77 | /* turn off the usb clock and assert the module reset */ | |
78 | lpsc_disable(DAVINCI_LPSC_USB11); | |
79 | lpsc_disable(DAVINCI_LPSC_USB20); | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | int usb_cpu_init_fail(void) | |
85 | { | |
86 | return usb_cpu_stop(); | |
87 | } | |
9da54743 AF |
88 | |
89 | #if CONFIG_IS_ENABLED(DM_USB) | |
90 | static int ohci_da8xx_probe(struct udevice *dev) | |
91 | { | |
8613c8d8 | 92 | struct ohci_regs *regs = dev_read_addr_ptr(dev); |
9da54743 AF |
93 | struct da8xx_ohci *priv = dev_get_priv(dev); |
94 | int i, err, ret, clock_nb; | |
95 | ||
96 | err = 0; | |
97 | priv->clock_count = 0; | |
89f68302 PD |
98 | clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells", |
99 | 0); | |
3a90b50a AF |
100 | |
101 | if (clock_nb < 0) | |
102 | return clock_nb; | |
103 | ||
9da54743 AF |
104 | if (clock_nb > 0) { |
105 | priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), | |
106 | GFP_KERNEL); | |
107 | if (!priv->clocks) | |
108 | return -ENOMEM; | |
109 | ||
110 | for (i = 0; i < clock_nb; i++) { | |
111 | err = clk_get_by_index(dev, i, &priv->clocks[i]); | |
112 | if (err < 0) | |
113 | break; | |
114 | ||
115 | err = clk_enable(&priv->clocks[i]); | |
116 | if (err) { | |
117 | dev_err(dev, "failed to enable clock %d\n", i); | |
118 | clk_free(&priv->clocks[i]); | |
119 | goto clk_err; | |
120 | } | |
121 | priv->clock_count++; | |
122 | } | |
9da54743 AF |
123 | } |
124 | ||
125 | err = usb_cpu_init(); | |
126 | ||
127 | if (err) | |
128 | goto clk_err; | |
129 | ||
130 | err = ohci_register(dev, regs); | |
131 | if (err) | |
132 | goto phy_err; | |
133 | ||
134 | return 0; | |
135 | ||
136 | phy_err: | |
137 | ret = usb_cpu_stop(); | |
138 | if (ret) | |
139 | dev_err(dev, "failed to shutdown usb phy\n"); | |
140 | ||
141 | clk_err: | |
142 | ret = clk_release_all(priv->clocks, priv->clock_count); | |
143 | if (ret) | |
144 | dev_err(dev, "failed to disable all clocks\n"); | |
145 | ||
146 | return err; | |
147 | } | |
148 | ||
149 | static int ohci_da8xx_remove(struct udevice *dev) | |
150 | { | |
151 | struct da8xx_ohci *priv = dev_get_priv(dev); | |
152 | int ret; | |
153 | ||
154 | ret = ohci_deregister(dev); | |
155 | if (ret) | |
156 | return ret; | |
157 | ||
158 | ret = usb_cpu_stop(); | |
159 | if (ret) | |
160 | return ret; | |
161 | ||
162 | return clk_release_all(priv->clocks, priv->clock_count); | |
163 | } | |
164 | ||
165 | static const struct udevice_id da8xx_ohci_ids[] = { | |
166 | { .compatible = "ti,da830-ohci" }, | |
167 | { } | |
168 | }; | |
169 | ||
170 | U_BOOT_DRIVER(ohci_generic) = { | |
171 | .name = "ohci-da8xx", | |
172 | .id = UCLASS_USB, | |
173 | .of_match = da8xx_ohci_ids, | |
174 | .probe = ohci_da8xx_probe, | |
175 | .remove = ohci_da8xx_remove, | |
176 | .ops = &ohci_usb_ops, | |
41575d8e | 177 | .priv_auto = sizeof(struct da8xx_ohci), |
3a90b50a | 178 | .flags = DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE, |
9da54743 AF |
179 | }; |
180 | #endif |