aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/omap2430.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/usb/musb/omap2430.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'drivers/usb/musb/omap2430.c')
-rw-r--r--drivers/usb/musb/omap2430.c416
1 files changed, 324 insertions, 92 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 2111a241dd03..c5d4c44d0ffa 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -31,10 +31,19 @@
31#include <linux/list.h> 31#include <linux/list.h>
32#include <linux/clk.h> 32#include <linux/clk.h>
33#include <linux/io.h> 33#include <linux/io.h>
34#include <linux/platform_device.h>
35#include <linux/dma-mapping.h>
36#include <linux/pm_runtime.h>
37#include <linux/err.h>
34 38
35#include "musb_core.h" 39#include "musb_core.h"
36#include "omap2430.h" 40#include "omap2430.h"
37 41
42struct omap2430_glue {
43 struct device *dev;
44 struct platform_device *musb;
45};
46#define glue_to_musb(g) platform_get_drvdata(g->musb)
38 47
39static struct timer_list musb_idle_timer; 48static struct timer_list musb_idle_timer;
40 49
@@ -49,12 +58,8 @@ static void musb_do_idle(unsigned long _musb)
49 58
50 spin_lock_irqsave(&musb->lock, flags); 59 spin_lock_irqsave(&musb->lock, flags);
51 60
52 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
53
54 switch (musb->xceiv->state) { 61 switch (musb->xceiv->state) {
55 case OTG_STATE_A_WAIT_BCON: 62 case OTG_STATE_A_WAIT_BCON:
56 devctl &= ~MUSB_DEVCTL_SESSION;
57 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
58 63
59 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); 64 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
60 if (devctl & MUSB_DEVCTL_BDEVICE) { 65 if (devctl & MUSB_DEVCTL_BDEVICE) {
@@ -71,7 +76,7 @@ static void musb_do_idle(unsigned long _musb)
71 if (musb->port1_status & MUSB_PORT_STAT_RESUME) { 76 if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
72 power = musb_readb(musb->mregs, MUSB_POWER); 77 power = musb_readb(musb->mregs, MUSB_POWER);
73 power &= ~MUSB_POWER_RESUME; 78 power &= ~MUSB_POWER_RESUME;
74 DBG(1, "root port resume stopped, power %02x\n", power); 79 dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power);
75 musb_writeb(musb->mregs, MUSB_POWER, power); 80 musb_writeb(musb->mregs, MUSB_POWER, power);
76 musb->is_active = 1; 81 musb->is_active = 1;
77 musb->port1_status &= ~(USB_PORT_STAT_SUSPEND 82 musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
@@ -98,7 +103,7 @@ static void musb_do_idle(unsigned long _musb)
98} 103}
99 104
100 105
101void musb_platform_try_idle(struct musb *musb, unsigned long timeout) 106static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
102{ 107{
103 unsigned long default_timeout = jiffies + msecs_to_jiffies(3); 108 unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
104 static unsigned long last_timer; 109 static unsigned long last_timer;
@@ -109,7 +114,8 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
109 /* Never idle if active, or when VBUS timeout is not set as host */ 114 /* Never idle if active, or when VBUS timeout is not set as host */
110 if (musb->is_active || ((musb->a_wait_bcon == 0) 115 if (musb->is_active || ((musb->a_wait_bcon == 0)
111 && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { 116 && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
112 DBG(4, "%s active, deleting timer\n", otg_state_string(musb)); 117 dev_dbg(musb->controller, "%s active, deleting timer\n",
118 otg_state_string(musb->xceiv->state));
113 del_timer(&musb_idle_timer); 119 del_timer(&musb_idle_timer);
114 last_timer = jiffies; 120 last_timer = jiffies;
115 return; 121 return;
@@ -119,27 +125,23 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
119 if (!timer_pending(&musb_idle_timer)) 125 if (!timer_pending(&musb_idle_timer))
120 last_timer = timeout; 126 last_timer = timeout;
121 else { 127 else {
122 DBG(4, "Longer idle timer already pending, ignoring\n"); 128 dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");
123 return; 129 return;
124 } 130 }
125 } 131 }
126 last_timer = timeout; 132 last_timer = timeout;
127 133
128 DBG(4, "%s inactive, for idle timer for %lu ms\n", 134 dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
129 otg_state_string(musb), 135 otg_state_string(musb->xceiv->state),
130 (unsigned long)jiffies_to_msecs(timeout - jiffies)); 136 (unsigned long)jiffies_to_msecs(timeout - jiffies));
131 mod_timer(&musb_idle_timer, timeout); 137 mod_timer(&musb_idle_timer, timeout);
132} 138}
133 139
134void musb_platform_enable(struct musb *musb) 140static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
135{
136}
137void musb_platform_disable(struct musb *musb)
138{
139}
140static void omap_set_vbus(struct musb *musb, int is_on)
141{ 141{
142 u8 devctl; 142 u8 devctl;
143 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
144 int ret = 1;
143 /* HDRC controls CPEN, but beware current surges during device 145 /* HDRC controls CPEN, but beware current surges during device
144 * connect. They can trigger transient overcurrent conditions 146 * connect. They can trigger transient overcurrent conditions
145 * that must be ignored. 147 * that must be ignored.
@@ -148,12 +150,35 @@ static void omap_set_vbus(struct musb *musb, int is_on)
148 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); 150 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
149 151
150 if (is_on) { 152 if (is_on) {
151 musb->is_active = 1; 153 if (musb->xceiv->state == OTG_STATE_A_IDLE) {
152 musb->xceiv->default_a = 1; 154 /* start the session */
153 musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; 155 devctl |= MUSB_DEVCTL_SESSION;
154 devctl |= MUSB_DEVCTL_SESSION; 156 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
155 157 /*
156 MUSB_HST_MODE(musb); 158 * Wait for the musb to set as A device to enable the
159 * VBUS
160 */
161 while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
162
163 cpu_relax();
164
165 if (time_after(jiffies, timeout)) {
166 dev_err(musb->controller,
167 "configured as A device timeout");
168 ret = -EINVAL;
169 break;
170 }
171 }
172
173 if (ret && musb->xceiv->set_vbus)
174 otg_set_vbus(musb->xceiv, 1);
175 } else {
176 musb->is_active = 1;
177 musb->xceiv->default_a = 1;
178 musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
179 devctl |= MUSB_DEVCTL_SESSION;
180 MUSB_HST_MODE(musb);
181 }
157 } else { 182 } else {
158 musb->is_active = 0; 183 musb->is_active = 0;
159 184
@@ -169,15 +194,13 @@ static void omap_set_vbus(struct musb *musb, int is_on)
169 } 194 }
170 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); 195 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
171 196
172 DBG(1, "VBUS %s, devctl %02x " 197 dev_dbg(musb->controller, "VBUS %s, devctl %02x "
173 /* otg %3x conf %08x prcm %08x */ "\n", 198 /* otg %3x conf %08x prcm %08x */ "\n",
174 otg_state_string(musb), 199 otg_state_string(musb->xceiv->state),
175 musb_readb(musb->mregs, MUSB_DEVCTL)); 200 musb_readb(musb->mregs, MUSB_DEVCTL));
176} 201}
177 202
178static int musb_platform_resume(struct musb *musb); 203static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
179
180int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
181{ 204{
182 u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); 205 u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
183 206
@@ -187,10 +210,95 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
187 return 0; 210 return 0;
188} 211}
189 212
190int __init musb_platform_init(struct musb *musb, void *board_data) 213static inline void omap2430_low_level_exit(struct musb *musb)
191{ 214{
192 u32 l; 215 u32 l;
193 struct omap_musb_board_data *data = board_data; 216
217 /* in any role */
218 l = musb_readl(musb->mregs, OTG_FORCESTDBY);
219 l |= ENABLEFORCE; /* enable MSTANDBY */
220 musb_writel(musb->mregs, OTG_FORCESTDBY, l);
221}
222
223static inline void omap2430_low_level_init(struct musb *musb)
224{
225 u32 l;
226
227 l = musb_readl(musb->mregs, OTG_FORCESTDBY);
228 l &= ~ENABLEFORCE; /* disable MSTANDBY */
229 musb_writel(musb->mregs, OTG_FORCESTDBY, l);
230}
231
232/* blocking notifier support */
233static int musb_otg_notifications(struct notifier_block *nb,
234 unsigned long event, void *unused)
235{
236 struct musb *musb = container_of(nb, struct musb, nb);
237 struct device *dev = musb->controller;
238 struct musb_hdrc_platform_data *pdata = dev->platform_data;
239 struct omap_musb_board_data *data = pdata->board_data;
240
241 switch (event) {
242 case USB_EVENT_ID:
243 dev_dbg(musb->controller, "ID GND\n");
244
245 if (is_otg_enabled(musb)) {
246#ifdef CONFIG_USB_GADGET_MUSB_HDRC
247 if (musb->gadget_driver) {
248 pm_runtime_get_sync(musb->controller);
249 otg_init(musb->xceiv);
250 omap2430_musb_set_vbus(musb, 1);
251 }
252#endif
253 } else {
254 pm_runtime_get_sync(musb->controller);
255 otg_init(musb->xceiv);
256 omap2430_musb_set_vbus(musb, 1);
257 }
258 break;
259
260 case USB_EVENT_VBUS:
261 dev_dbg(musb->controller, "VBUS Connect\n");
262
263#ifdef CONFIG_USB_GADGET_MUSB_HDRC
264 if (musb->gadget_driver)
265 pm_runtime_get_sync(musb->controller);
266#endif
267 otg_init(musb->xceiv);
268 break;
269
270 case USB_EVENT_NONE:
271 dev_dbg(musb->controller, "VBUS Disconnect\n");
272
273#ifdef CONFIG_USB_GADGET_MUSB_HDRC
274 if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
275 if (musb->gadget_driver)
276#endif
277 {
278 pm_runtime_mark_last_busy(musb->controller);
279 pm_runtime_put_autosuspend(musb->controller);
280 }
281
282 if (data->interface_type == MUSB_INTERFACE_UTMI) {
283 if (musb->xceiv->set_vbus)
284 otg_set_vbus(musb->xceiv, 0);
285 }
286 otg_shutdown(musb->xceiv);
287 break;
288 default:
289 dev_dbg(musb->controller, "ID float\n");
290 return NOTIFY_DONE;
291 }
292
293 return NOTIFY_OK;
294}
295
296static int omap2430_musb_init(struct musb *musb)
297{
298 u32 l, status = 0;
299 struct device *dev = musb->controller;
300 struct musb_hdrc_platform_data *plat = dev->platform_data;
301 struct omap_musb_board_data *data = plat->board_data;
194 302
195 /* We require some kind of external transceiver, hooked 303 /* We require some kind of external transceiver, hooked
196 * up through ULPI. TWL4030-family PMICs include one, 304 * up through ULPI. TWL4030-family PMICs include one,
@@ -202,22 +310,11 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
202 return -ENODEV; 310 return -ENODEV;
203 } 311 }
204 312
205 musb_platform_resume(musb); 313 status = pm_runtime_get_sync(dev);
206 314 if (status < 0) {
207 l = musb_readl(musb->mregs, OTG_SYSCONFIG); 315 dev_err(dev, "pm_runtime_get_sync FAILED");
208 l &= ~ENABLEWAKEUP; /* disable wakeup */ 316 goto err1;
209 l &= ~NOSTDBY; /* remove possible nostdby */ 317 }
210 l |= SMARTSTDBY; /* enable smart standby */
211 l &= ~AUTOIDLE; /* disable auto idle */
212 l &= ~NOIDLE; /* remove possible noidle */
213 l |= SMARTIDLE; /* enable smart idle */
214 /*
215 * MUSB AUTOIDLE don't work in 3430.
216 * Workaround by Richard Woodruff/TI
217 */
218 if (!cpu_is_omap3430())
219 l |= AUTOIDLE; /* enable auto idle */
220 musb_writel(musb->mregs, OTG_SYSCONFIG, l);
221 318
222 l = musb_readl(musb->mregs, OTG_INTERFSEL); 319 l = musb_readl(musb->mregs, OTG_INTERFSEL);
223 320
@@ -239,86 +336,221 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
239 musb_readl(musb->mregs, OTG_INTERFSEL), 336 musb_readl(musb->mregs, OTG_INTERFSEL),
240 musb_readl(musb->mregs, OTG_SIMENABLE)); 337 musb_readl(musb->mregs, OTG_SIMENABLE));
241 338
242 if (is_host_enabled(musb)) 339 musb->nb.notifier_call = musb_otg_notifications;
243 musb->board_set_vbus = omap_set_vbus; 340 status = otg_register_notifier(musb->xceiv, &musb->nb);
341
342 if (status)
343 dev_dbg(musb->controller, "notification register failed\n");
244 344
245 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); 345 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
246 346
247 return 0; 347 return 0;
348
349err1:
350 pm_runtime_disable(dev);
351 return status;
248} 352}
249 353
250#ifdef CONFIG_PM 354static void omap2430_musb_enable(struct musb *musb)
251void musb_platform_save_context(struct musb *musb,
252 struct musb_context_registers *musb_context)
253{ 355{
254 musb_context->otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG); 356 u8 devctl;
255 musb_context->otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY); 357 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
358 struct device *dev = musb->controller;
359 struct musb_hdrc_platform_data *pdata = dev->platform_data;
360 struct omap_musb_board_data *data = pdata->board_data;
361
362 switch (musb->xceiv->last_event) {
363
364 case USB_EVENT_ID:
365 otg_init(musb->xceiv);
366 if (data->interface_type == MUSB_INTERFACE_UTMI) {
367 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
368 /* start the session */
369 devctl |= MUSB_DEVCTL_SESSION;
370 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
371 while (musb_readb(musb->mregs, MUSB_DEVCTL) &
372 MUSB_DEVCTL_BDEVICE) {
373 cpu_relax();
374
375 if (time_after(jiffies, timeout)) {
376 dev_err(musb->controller,
377 "configured as A device timeout");
378 break;
379 }
380 }
381 }
382 break;
383
384 case USB_EVENT_VBUS:
385 otg_init(musb->xceiv);
386 break;
387
388 default:
389 break;
390 }
256} 391}
257 392
258void musb_platform_restore_context(struct musb *musb, 393static void omap2430_musb_disable(struct musb *musb)
259 struct musb_context_registers *musb_context)
260{ 394{
261 musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig); 395 if (musb->xceiv->last_event)
262 musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby); 396 otg_shutdown(musb->xceiv);
263} 397}
264#endif
265 398
266static int musb_platform_suspend(struct musb *musb) 399static int omap2430_musb_exit(struct musb *musb)
267{ 400{
268 u32 l; 401 del_timer_sync(&musb_idle_timer);
269 402
270 if (!musb->clock) 403 omap2430_low_level_exit(musb);
271 return 0; 404 otg_put_transceiver(musb->xceiv);
272 405
273 /* in any role */ 406 return 0;
274 l = musb_readl(musb->mregs, OTG_FORCESTDBY); 407}
275 l |= ENABLEFORCE; /* enable MSTANDBY */
276 musb_writel(musb->mregs, OTG_FORCESTDBY, l);
277 408
278 l = musb_readl(musb->mregs, OTG_SYSCONFIG); 409static const struct musb_platform_ops omap2430_ops = {
279 l |= ENABLEWAKEUP; /* enable wakeup */ 410 .init = omap2430_musb_init,
280 musb_writel(musb->mregs, OTG_SYSCONFIG, l); 411 .exit = omap2430_musb_exit,
281 412
282 otg_set_suspend(musb->xceiv, 1); 413 .set_mode = omap2430_musb_set_mode,
414 .try_idle = omap2430_musb_try_idle,
415
416 .set_vbus = omap2430_musb_set_vbus,
417
418 .enable = omap2430_musb_enable,
419 .disable = omap2430_musb_disable,
420};
283 421
284 if (musb->set_clock) 422static u64 omap2430_dmamask = DMA_BIT_MASK(32);
285 musb->set_clock(musb->clock, 0); 423
286 else 424static int __init omap2430_probe(struct platform_device *pdev)
287 clk_disable(musb->clock); 425{
426 struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
427 struct platform_device *musb;
428 struct omap2430_glue *glue;
429 int ret = -ENOMEM;
430
431 glue = kzalloc(sizeof(*glue), GFP_KERNEL);
432 if (!glue) {
433 dev_err(&pdev->dev, "failed to allocate glue context\n");
434 goto err0;
435 }
436
437 musb = platform_device_alloc("musb-hdrc", -1);
438 if (!musb) {
439 dev_err(&pdev->dev, "failed to allocate musb device\n");
440 goto err1;
441 }
442
443 musb->dev.parent = &pdev->dev;
444 musb->dev.dma_mask = &omap2430_dmamask;
445 musb->dev.coherent_dma_mask = omap2430_dmamask;
446
447 glue->dev = &pdev->dev;
448 glue->musb = musb;
449
450 pdata->platform_ops = &omap2430_ops;
451
452 platform_set_drvdata(pdev, glue);
453
454 ret = platform_device_add_resources(musb, pdev->resource,
455 pdev->num_resources);
456 if (ret) {
457 dev_err(&pdev->dev, "failed to add resources\n");
458 goto err2;
459 }
460
461 ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
462 if (ret) {
463 dev_err(&pdev->dev, "failed to add platform_data\n");
464 goto err2;
465 }
466
467 ret = platform_device_add(musb);
468 if (ret) {
469 dev_err(&pdev->dev, "failed to register musb device\n");
470 goto err2;
471 }
472
473 pm_runtime_enable(&pdev->dev);
288 474
289 return 0; 475 return 0;
476
477err2:
478 platform_device_put(musb);
479
480err1:
481 kfree(glue);
482
483err0:
484 return ret;
290} 485}
291 486
292static int musb_platform_resume(struct musb *musb) 487static int __exit omap2430_remove(struct platform_device *pdev)
293{ 488{
294 u32 l; 489 struct omap2430_glue *glue = platform_get_drvdata(pdev);
295 490
296 if (!musb->clock) 491 platform_device_del(glue->musb);
297 return 0; 492 platform_device_put(glue->musb);
493 pm_runtime_put(&pdev->dev);
494 pm_runtime_disable(&pdev->dev);
495 kfree(glue);
298 496
299 otg_set_suspend(musb->xceiv, 0); 497 return 0;
498}
300 499
301 if (musb->set_clock) 500#ifdef CONFIG_PM
302 musb->set_clock(musb->clock, 1);
303 else
304 clk_enable(musb->clock);
305 501
306 l = musb_readl(musb->mregs, OTG_SYSCONFIG); 502static int omap2430_runtime_suspend(struct device *dev)
307 l &= ~ENABLEWAKEUP; /* disable wakeup */ 503{
308 musb_writel(musb->mregs, OTG_SYSCONFIG, l); 504 struct omap2430_glue *glue = dev_get_drvdata(dev);
505 struct musb *musb = glue_to_musb(glue);
309 506
310 l = musb_readl(musb->mregs, OTG_FORCESTDBY); 507 omap2430_low_level_exit(musb);
311 l &= ~ENABLEFORCE; /* disable MSTANDBY */ 508 otg_set_suspend(musb->xceiv, 1);
312 musb_writel(musb->mregs, OTG_FORCESTDBY, l);
313 509
314 return 0; 510 return 0;
315} 511}
316 512
317 513static int omap2430_runtime_resume(struct device *dev)
318int musb_platform_exit(struct musb *musb)
319{ 514{
515 struct omap2430_glue *glue = dev_get_drvdata(dev);
516 struct musb *musb = glue_to_musb(glue);
320 517
321 musb_platform_suspend(musb); 518 omap2430_low_level_init(musb);
519 otg_set_suspend(musb->xceiv, 0);
322 520
323 return 0; 521 return 0;
324} 522}
523
524static struct dev_pm_ops omap2430_pm_ops = {
525 .runtime_suspend = omap2430_runtime_suspend,
526 .runtime_resume = omap2430_runtime_resume,
527};
528
529#define DEV_PM_OPS (&omap2430_pm_ops)
530#else
531#define DEV_PM_OPS NULL
532#endif
533
534static struct platform_driver omap2430_driver = {
535 .remove = __exit_p(omap2430_remove),
536 .driver = {
537 .name = "musb-omap2430",
538 .pm = DEV_PM_OPS,
539 },
540};
541
542MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
543MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
544MODULE_LICENSE("GPL v2");
545
546static int __init omap2430_init(void)
547{
548 return platform_driver_probe(&omap2430_driver, omap2430_probe);
549}
550subsys_initcall(omap2430_init);
551
552static void __exit omap2430_exit(void)
553{
554 platform_driver_unregister(&omap2430_driver);
555}
556module_exit(omap2430_exit);