Commit | Line | Data |
---|---|---|
86cad160 DL |
1 | /* |
2 | * DA8xx USB | |
3 | */ | |
0004b02a DL |
4 | #include <linux/clk.h> |
5 | #include <linux/delay.h> | |
86cad160 DL |
6 | #include <linux/dma-mapping.h> |
7 | #include <linux/init.h> | |
0004b02a | 8 | #include <linux/mfd/da8xx-cfgchip.h> |
9b504750 | 9 | #include <linux/phy/phy.h> |
86cad160 DL |
10 | #include <linux/platform_data/usb-davinci.h> |
11 | #include <linux/platform_device.h> | |
12 | #include <linux/usb/musb.h> | |
13 | ||
0004b02a | 14 | #include <mach/clock.h> |
86cad160 DL |
15 | #include <mach/common.h> |
16 | #include <mach/cputype.h> | |
17 | #include <mach/da8xx.h> | |
18 | #include <mach/irqs.h> | |
19 | ||
0004b02a DL |
20 | #include "clock.h" |
21 | ||
86cad160 DL |
22 | #define DA8XX_USB0_BASE 0x01e00000 |
23 | #define DA8XX_USB1_BASE 0x01e25000 | |
24 | ||
9b504750 DL |
25 | static struct platform_device da8xx_usb_phy = { |
26 | .name = "da8xx-usb-phy", | |
27 | .id = -1, | |
0004b02a DL |
28 | .dev = { |
29 | /* | |
30 | * Setting init_name so that clock lookup will work in | |
31 | * da8xx_register_usb11_phy_clk() even if this device is not | |
32 | * registered yet. | |
33 | */ | |
34 | .init_name = "da8xx-usb-phy", | |
35 | }, | |
9b504750 DL |
36 | }; |
37 | ||
38 | int __init da8xx_register_usb_phy(void) | |
39 | { | |
40 | return platform_device_register(&da8xx_usb_phy); | |
41 | } | |
42 | ||
86cad160 DL |
43 | static struct musb_hdrc_config musb_config = { |
44 | .multipoint = true, | |
45 | .num_eps = 5, | |
46 | .ram_bits = 10, | |
47 | }; | |
48 | ||
49 | static struct musb_hdrc_platform_data usb_data = { | |
50 | /* OTG requires a Mini-AB connector */ | |
51 | .mode = MUSB_OTG, | |
52 | .clock = "usb20", | |
53 | .config = &musb_config, | |
54 | }; | |
55 | ||
56 | static struct resource da8xx_usb20_resources[] = { | |
57 | { | |
58 | .start = DA8XX_USB0_BASE, | |
59 | .end = DA8XX_USB0_BASE + SZ_64K - 1, | |
60 | .flags = IORESOURCE_MEM, | |
61 | }, | |
62 | { | |
63 | .start = IRQ_DA8XX_USB_INT, | |
64 | .flags = IORESOURCE_IRQ, | |
65 | .name = "mc", | |
66 | }, | |
67 | }; | |
68 | ||
69 | static u64 usb_dmamask = DMA_BIT_MASK(32); | |
70 | ||
0004b02a | 71 | static struct platform_device da8xx_usb20_dev = { |
86cad160 DL |
72 | .name = "musb-da8xx", |
73 | .id = -1, | |
74 | .dev = { | |
0004b02a DL |
75 | /* |
76 | * Setting init_name so that clock lookup will work in | |
77 | * usb20_phy_clk_enable() even if this device is not registered. | |
78 | */ | |
79 | .init_name = "musb-da8xx", | |
86cad160 DL |
80 | .platform_data = &usb_data, |
81 | .dma_mask = &usb_dmamask, | |
82 | .coherent_dma_mask = DMA_BIT_MASK(32), | |
83 | }, | |
84 | .resource = da8xx_usb20_resources, | |
85 | .num_resources = ARRAY_SIZE(da8xx_usb20_resources), | |
86 | }; | |
87 | ||
88 | int __init da8xx_register_usb20(unsigned int mA, unsigned int potpgt) | |
89 | { | |
90 | usb_data.power = mA > 510 ? 255 : mA / 2; | |
91 | usb_data.potpgt = (potpgt + 1) / 2; | |
92 | ||
0004b02a | 93 | return platform_device_register(&da8xx_usb20_dev); |
86cad160 DL |
94 | } |
95 | ||
86cad160 DL |
96 | static struct resource da8xx_usb11_resources[] = { |
97 | [0] = { | |
98 | .start = DA8XX_USB1_BASE, | |
99 | .end = DA8XX_USB1_BASE + SZ_4K - 1, | |
100 | .flags = IORESOURCE_MEM, | |
101 | }, | |
102 | [1] = { | |
103 | .start = IRQ_DA8XX_IRQN, | |
104 | .end = IRQ_DA8XX_IRQN, | |
105 | .flags = IORESOURCE_IRQ, | |
106 | }, | |
107 | }; | |
108 | ||
109 | static u64 da8xx_usb11_dma_mask = DMA_BIT_MASK(32); | |
110 | ||
111 | static struct platform_device da8xx_usb11_device = { | |
8439a1d7 AH |
112 | .name = "ohci-da8xx", |
113 | .id = -1, | |
86cad160 DL |
114 | .dev = { |
115 | .dma_mask = &da8xx_usb11_dma_mask, | |
116 | .coherent_dma_mask = DMA_BIT_MASK(32), | |
117 | }, | |
118 | .num_resources = ARRAY_SIZE(da8xx_usb11_resources), | |
119 | .resource = da8xx_usb11_resources, | |
120 | }; | |
121 | ||
122 | int __init da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata) | |
123 | { | |
124 | da8xx_usb11_device.dev.platform_data = pdata; | |
125 | return platform_device_register(&da8xx_usb11_device); | |
126 | } | |
0004b02a DL |
127 | |
128 | static struct clk usb_refclkin = { | |
129 | .name = "usb_refclkin", | |
130 | .set_rate = davinci_simple_set_rate, | |
131 | }; | |
132 | ||
133 | static struct clk_lookup usb_refclkin_lookup = | |
134 | CLK(NULL, "usb_refclkin", &usb_refclkin); | |
135 | ||
136 | /** | |
137 | * da8xx_register_usb_refclkin - register USB_REFCLKIN clock | |
138 | * | |
139 | * @rate: The clock rate in Hz | |
140 | * | |
141 | * This clock is only needed if the board provides an external USB_REFCLKIN | |
142 | * signal, in which case it will be used as the parent of usb20_phy_clk and/or | |
143 | * usb11_phy_clk. | |
144 | */ | |
145 | int __init da8xx_register_usb_refclkin(int rate) | |
146 | { | |
147 | int ret; | |
148 | ||
149 | usb_refclkin.rate = rate; | |
150 | ret = clk_register(&usb_refclkin); | |
151 | if (ret) | |
152 | return ret; | |
153 | ||
154 | clkdev_add(&usb_refclkin_lookup); | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
159 | static void usb20_phy_clk_enable(struct clk *clk) | |
160 | { | |
161 | struct clk *usb20_clk; | |
162 | int err; | |
163 | u32 val; | |
164 | u32 timeout = 500000; /* 500 msec */ | |
165 | ||
166 | val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
167 | ||
168 | usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20"); | |
169 | if (IS_ERR(usb20_clk)) { | |
170 | pr_err("could not get usb20 clk: %ld\n", PTR_ERR(usb20_clk)); | |
171 | return; | |
172 | } | |
173 | ||
174 | /* The USB 2.O PLL requires that the USB 2.O PSC is enabled as well. */ | |
175 | err = clk_prepare_enable(usb20_clk); | |
176 | if (err) { | |
177 | pr_err("failed to enable usb20 clk: %d\n", err); | |
178 | clk_put(usb20_clk); | |
179 | return; | |
180 | } | |
181 | ||
182 | /* | |
183 | * Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1 | |
184 | * host may use the PLL clock without USB 2.0 OTG being used. | |
185 | */ | |
186 | val &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN); | |
187 | val |= CFGCHIP2_PHY_PLLON; | |
188 | ||
189 | writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
190 | ||
191 | while (--timeout) { | |
192 | val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
193 | if (val & CFGCHIP2_PHYCLKGD) | |
194 | goto done; | |
195 | udelay(1); | |
196 | } | |
197 | ||
198 | pr_err("Timeout waiting for USB 2.0 PHY clock good\n"); | |
199 | done: | |
200 | clk_disable_unprepare(usb20_clk); | |
201 | clk_put(usb20_clk); | |
202 | } | |
203 | ||
204 | static void usb20_phy_clk_disable(struct clk *clk) | |
205 | { | |
206 | u32 val; | |
207 | ||
208 | val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
209 | val |= CFGCHIP2_PHYPWRDN; | |
210 | writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
211 | } | |
212 | ||
213 | static int usb20_phy_clk_set_parent(struct clk *clk, struct clk *parent) | |
214 | { | |
215 | u32 val; | |
216 | ||
217 | val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
218 | ||
219 | /* Set the mux depending on the parent clock. */ | |
220 | if (parent == &usb_refclkin) { | |
221 | val &= ~CFGCHIP2_USB2PHYCLKMUX; | |
222 | } else if (strcmp(parent->name, "pll0_aux_clk") == 0) { | |
223 | val |= CFGCHIP2_USB2PHYCLKMUX; | |
224 | } else { | |
225 | pr_err("Bad parent on USB 2.0 PHY clock\n"); | |
226 | return -EINVAL; | |
227 | } | |
228 | ||
229 | /* reference frequency also comes from parent clock */ | |
230 | val &= ~CFGCHIP2_REFFREQ_MASK; | |
231 | switch (clk_get_rate(parent)) { | |
232 | case 12000000: | |
233 | val |= CFGCHIP2_REFFREQ_12MHZ; | |
234 | break; | |
235 | case 13000000: | |
236 | val |= CFGCHIP2_REFFREQ_13MHZ; | |
237 | break; | |
238 | case 19200000: | |
239 | val |= CFGCHIP2_REFFREQ_19_2MHZ; | |
240 | break; | |
241 | case 20000000: | |
242 | val |= CFGCHIP2_REFFREQ_20MHZ; | |
243 | break; | |
244 | case 24000000: | |
245 | val |= CFGCHIP2_REFFREQ_24MHZ; | |
246 | break; | |
247 | case 26000000: | |
248 | val |= CFGCHIP2_REFFREQ_26MHZ; | |
249 | break; | |
250 | case 38400000: | |
251 | val |= CFGCHIP2_REFFREQ_38_4MHZ; | |
252 | break; | |
253 | case 40000000: | |
254 | val |= CFGCHIP2_REFFREQ_40MHZ; | |
255 | break; | |
256 | case 48000000: | |
257 | val |= CFGCHIP2_REFFREQ_48MHZ; | |
258 | break; | |
259 | default: | |
260 | pr_err("Bad parent clock rate on USB 2.0 PHY clock\n"); | |
261 | return -EINVAL; | |
262 | } | |
263 | ||
264 | writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
265 | ||
266 | return 0; | |
267 | } | |
268 | ||
269 | static struct clk usb20_phy_clk = { | |
270 | .name = "usb20_phy", | |
271 | .clk_enable = usb20_phy_clk_enable, | |
272 | .clk_disable = usb20_phy_clk_disable, | |
273 | .set_parent = usb20_phy_clk_set_parent, | |
274 | }; | |
275 | ||
276 | static struct clk_lookup usb20_phy_clk_lookup = | |
277 | CLK("da8xx-usb-phy", "usb20_phy", &usb20_phy_clk); | |
278 | ||
279 | /** | |
280 | * da8xx_register_usb20_phy_clk - register USB0PHYCLKMUX clock | |
281 | * | |
282 | * @use_usb_refclkin: Selects the parent clock - either "usb_refclkin" if true | |
283 | * or "pll0_aux" if false. | |
284 | */ | |
285 | int __init da8xx_register_usb20_phy_clk(bool use_usb_refclkin) | |
286 | { | |
287 | struct clk *parent; | |
288 | int ret = 0; | |
289 | ||
290 | parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" : "pll0_aux"); | |
291 | if (IS_ERR(parent)) | |
292 | return PTR_ERR(parent); | |
293 | ||
294 | usb20_phy_clk.parent = parent; | |
295 | ret = clk_register(&usb20_phy_clk); | |
296 | if (!ret) | |
297 | clkdev_add(&usb20_phy_clk_lookup); | |
298 | ||
299 | clk_put(parent); | |
300 | ||
301 | return ret; | |
302 | } | |
303 | ||
304 | static int usb11_phy_clk_set_parent(struct clk *clk, struct clk *parent) | |
305 | { | |
306 | u32 val; | |
307 | ||
308 | val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
309 | ||
310 | /* Set the USB 1.1 PHY clock mux based on the parent clock. */ | |
311 | if (parent == &usb20_phy_clk) { | |
312 | val &= ~CFGCHIP2_USB1PHYCLKMUX; | |
313 | } else if (parent == &usb_refclkin) { | |
314 | val |= CFGCHIP2_USB1PHYCLKMUX; | |
315 | } else { | |
316 | pr_err("Bad parent on USB 1.1 PHY clock\n"); | |
317 | return -EINVAL; | |
318 | } | |
319 | ||
320 | writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); | |
321 | ||
322 | return 0; | |
323 | } | |
324 | ||
325 | static struct clk usb11_phy_clk = { | |
326 | .name = "usb11_phy", | |
327 | .set_parent = usb11_phy_clk_set_parent, | |
328 | }; | |
329 | ||
330 | static struct clk_lookup usb11_phy_clk_lookup = | |
331 | CLK("da8xx-usb-phy", "usb11_phy", &usb11_phy_clk); | |
332 | ||
333 | /** | |
334 | * da8xx_register_usb11_phy_clk - register USB1PHYCLKMUX clock | |
335 | * | |
336 | * @use_usb_refclkin: Selects the parent clock - either "usb_refclkin" if true | |
337 | * or "usb20_phy" if false. | |
338 | */ | |
339 | int __init da8xx_register_usb11_phy_clk(bool use_usb_refclkin) | |
340 | { | |
341 | struct clk *parent; | |
342 | int ret = 0; | |
343 | ||
344 | if (use_usb_refclkin) | |
345 | parent = clk_get(NULL, "usb_refclkin"); | |
346 | else | |
347 | parent = clk_get(&da8xx_usb_phy.dev, "usb20_phy"); | |
348 | if (IS_ERR(parent)) | |
349 | return PTR_ERR(parent); | |
350 | ||
351 | usb11_phy_clk.parent = parent; | |
352 | ret = clk_register(&usb11_phy_clk); | |
353 | if (!ret) | |
354 | clkdev_add(&usb11_phy_clk_lookup); | |
355 | ||
356 | clk_put(parent); | |
357 | ||
358 | return ret; | |
359 | } |