diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-12-16 13:05:06 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-12-16 13:05:06 -0500 |
commit | 36facadd9ea98f8415d0dbb63e0763b7ee9d3911 (patch) | |
tree | 99dea00b332ed852f2b0a4923b581dd723f03634 /drivers/usb/musb/blackfin.c | |
parent | 2faa83e2a519abea1055d156ce1b42b8fa57e87b (diff) | |
parent | 0b83ae960cd7d4a5ee02786ecf41ab45688999bf (diff) |
Merge branch 'usb-next' into musb-merge
* usb-next: (132 commits)
USB: uas: Use GFP_NOIO instead of GFP_KERNEL in I/O submission path
USB: uas: Ensure we only bind to a UAS interface
USB: uas: Rename sense pipe and sense urb to status pipe and status urb
USB: uas: Use kzalloc instead of kmalloc
USB: uas: Fix up the Sense IU
usb: musb: core: kill unneeded #include's
DA8xx: assign name to MUSB IRQ resource
usb: gadget: g_ncm added
usb: gadget: f_ncm.c added
usb: gadget: u_ether: prepare for NCM
usb: pch_udc: Fix setup transfers with data out
usb: pch_udc: Fix compile error, warnings and checkpatch warnings
usb: add ab8500 usb transceiver driver
USB: gadget: Implement runtime PM for MSM bus glue driver
USB: gadget: Implement runtime PM for ci13xxx gadget
USB: gadget: Add USB controller driver for MSM SoC
USB: gadget: Introduce ci13xxx_udc_driver struct
USB: gadget: Initialize ci13xxx gadget device's coherent DMA mask
USB: gadget: Fix "scheduling while atomic" bugs in ci13xxx_udc
USB: gadget: Separate out PCI bus code from ci13xxx_udc
...
Diffstat (limited to 'drivers/usb/musb/blackfin.c')
-rw-r--r-- | drivers/usb/musb/blackfin.c | 229 |
1 files changed, 196 insertions, 33 deletions
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 930a2611fe3e..eeba228eb2af 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c | |||
@@ -15,12 +15,20 @@ | |||
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/dma-mapping.h> | ||
18 | 20 | ||
19 | #include <asm/cacheflush.h> | 21 | #include <asm/cacheflush.h> |
20 | 22 | ||
21 | #include "musb_core.h" | 23 | #include "musb_core.h" |
22 | #include "blackfin.h" | 24 | #include "blackfin.h" |
23 | 25 | ||
26 | struct bfin_glue { | ||
27 | struct device *dev; | ||
28 | struct platform_device *musb; | ||
29 | }; | ||
30 | #define glue_to_musb(g) platform_get_drvdata(g->musb) | ||
31 | |||
24 | /* | 32 | /* |
25 | * Load an endpoint's FIFO | 33 | * Load an endpoint's FIFO |
26 | */ | 34 | */ |
@@ -278,7 +286,7 @@ static void musb_conn_timer_handler(unsigned long _musb) | |||
278 | DBG(4, "state is %s\n", otg_state_string(musb)); | 286 | DBG(4, "state is %s\n", otg_state_string(musb)); |
279 | } | 287 | } |
280 | 288 | ||
281 | void musb_platform_enable(struct musb *musb) | 289 | static void bfin_musb_enable(struct musb *musb) |
282 | { | 290 | { |
283 | if (!is_otg_enabled(musb) && is_host_enabled(musb)) { | 291 | if (!is_otg_enabled(musb) && is_host_enabled(musb)) { |
284 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); | 292 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); |
@@ -286,11 +294,11 @@ void musb_platform_enable(struct musb *musb) | |||
286 | } | 294 | } |
287 | } | 295 | } |
288 | 296 | ||
289 | void musb_platform_disable(struct musb *musb) | 297 | static void bfin_musb_disable(struct musb *musb) |
290 | { | 298 | { |
291 | } | 299 | } |
292 | 300 | ||
293 | static void bfin_set_vbus(struct musb *musb, int is_on) | 301 | static void bfin_musb_set_vbus(struct musb *musb, int is_on) |
294 | { | 302 | { |
295 | int value = musb->config->gpio_vrsel_active; | 303 | int value = musb->config->gpio_vrsel_active; |
296 | if (!is_on) | 304 | if (!is_on) |
@@ -303,51 +311,29 @@ static void bfin_set_vbus(struct musb *musb, int is_on) | |||
303 | musb_readb(musb->mregs, MUSB_DEVCTL)); | 311 | musb_readb(musb->mregs, MUSB_DEVCTL)); |
304 | } | 312 | } |
305 | 313 | ||
306 | static int bfin_set_power(struct otg_transceiver *x, unsigned mA) | 314 | static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA) |
307 | { | 315 | { |
308 | return 0; | 316 | return 0; |
309 | } | 317 | } |
310 | 318 | ||
311 | void musb_platform_try_idle(struct musb *musb, unsigned long timeout) | 319 | static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout) |
312 | { | 320 | { |
313 | if (!is_otg_enabled(musb) && is_host_enabled(musb)) | 321 | if (!is_otg_enabled(musb) && is_host_enabled(musb)) |
314 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); | 322 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); |
315 | } | 323 | } |
316 | 324 | ||
317 | int musb_platform_get_vbus_status(struct musb *musb) | 325 | static int bfin_musb_get_vbus_status(struct musb *musb) |
318 | { | 326 | { |
319 | return 0; | 327 | return 0; |
320 | } | 328 | } |
321 | 329 | ||
322 | int musb_platform_set_mode(struct musb *musb, u8 musb_mode) | 330 | static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode) |
323 | { | 331 | { |
324 | return -EIO; | 332 | return -EIO; |
325 | } | 333 | } |
326 | 334 | ||
327 | int __init musb_platform_init(struct musb *musb, void *board_data) | 335 | static void bfin_musb_reg_init(struct musb *musb) |
328 | { | 336 | { |
329 | |||
330 | /* | ||
331 | * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE | ||
332 | * and OTG HOST modes, while rev 1.1 and greater require PE7 to | ||
333 | * be low for DEVICE mode and high for HOST mode. We set it high | ||
334 | * here because we are in host mode | ||
335 | */ | ||
336 | |||
337 | if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) { | ||
338 | printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n", | ||
339 | musb->config->gpio_vrsel); | ||
340 | return -ENODEV; | ||
341 | } | ||
342 | gpio_direction_output(musb->config->gpio_vrsel, 0); | ||
343 | |||
344 | usb_nop_xceiv_register(); | ||
345 | musb->xceiv = otg_get_transceiver(); | ||
346 | if (!musb->xceiv) { | ||
347 | gpio_free(musb->config->gpio_vrsel); | ||
348 | return -ENODEV; | ||
349 | } | ||
350 | |||
351 | if (ANOMALY_05000346) { | 337 | if (ANOMALY_05000346) { |
352 | bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); | 338 | bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); |
353 | SSYNC(); | 339 | SSYNC(); |
@@ -382,21 +368,47 @@ int __init musb_platform_init(struct musb *musb, void *board_data) | |||
382 | EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA | | 368 | EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA | |
383 | EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA); | 369 | EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA); |
384 | SSYNC(); | 370 | SSYNC(); |
371 | } | ||
372 | |||
373 | static int bfin_musb_init(struct musb *musb) | ||
374 | { | ||
375 | |||
376 | /* | ||
377 | * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE | ||
378 | * and OTG HOST modes, while rev 1.1 and greater require PE7 to | ||
379 | * be low for DEVICE mode and high for HOST mode. We set it high | ||
380 | * here because we are in host mode | ||
381 | */ | ||
382 | |||
383 | if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) { | ||
384 | printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n", | ||
385 | musb->config->gpio_vrsel); | ||
386 | return -ENODEV; | ||
387 | } | ||
388 | gpio_direction_output(musb->config->gpio_vrsel, 0); | ||
389 | |||
390 | usb_nop_xceiv_register(); | ||
391 | musb->xceiv = otg_get_transceiver(); | ||
392 | if (!musb->xceiv) { | ||
393 | gpio_free(musb->config->gpio_vrsel); | ||
394 | return -ENODEV; | ||
395 | } | ||
396 | |||
397 | bfin_musb_reg_init(musb); | ||
385 | 398 | ||
386 | if (is_host_enabled(musb)) { | 399 | if (is_host_enabled(musb)) { |
387 | musb->board_set_vbus = bfin_set_vbus; | ||
388 | setup_timer(&musb_conn_timer, | 400 | setup_timer(&musb_conn_timer, |
389 | musb_conn_timer_handler, (unsigned long) musb); | 401 | musb_conn_timer_handler, (unsigned long) musb); |
390 | } | 402 | } |
391 | if (is_peripheral_enabled(musb)) | 403 | if (is_peripheral_enabled(musb)) |
392 | musb->xceiv->set_power = bfin_set_power; | 404 | musb->xceiv->set_power = bfin_musb_set_power; |
393 | 405 | ||
394 | musb->isr = blackfin_interrupt; | 406 | musb->isr = blackfin_interrupt; |
395 | 407 | ||
396 | return 0; | 408 | return 0; |
397 | } | 409 | } |
398 | 410 | ||
399 | int musb_platform_exit(struct musb *musb) | 411 | static int bfin_musb_exit(struct musb *musb) |
400 | { | 412 | { |
401 | gpio_free(musb->config->gpio_vrsel); | 413 | gpio_free(musb->config->gpio_vrsel); |
402 | 414 | ||
@@ -404,3 +416,154 @@ int musb_platform_exit(struct musb *musb) | |||
404 | usb_nop_xceiv_unregister(); | 416 | usb_nop_xceiv_unregister(); |
405 | return 0; | 417 | return 0; |
406 | } | 418 | } |
419 | |||
420 | static const struct musb_platform_ops bfin_ops = { | ||
421 | .init = bfin_musb_init, | ||
422 | .exit = bfin_musb_exit, | ||
423 | |||
424 | .enable = bfin_musb_enable, | ||
425 | .disable = bfin_musb_disable, | ||
426 | |||
427 | .set_mode = bfin_musb_set_mode, | ||
428 | .try_idle = bfin_musb_try_idle, | ||
429 | |||
430 | .vbus_status = bfin_musb_vbus_status, | ||
431 | .set_vbus = bfin_musb_set_vbus, | ||
432 | }; | ||
433 | |||
434 | static u64 bfin_dmamask = DMA_BIT_MASK(32); | ||
435 | |||
436 | static int __init bfin_probe(struct platform_device *pdev) | ||
437 | { | ||
438 | struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; | ||
439 | struct platform_device *musb; | ||
440 | struct bfin_glue *glue; | ||
441 | |||
442 | int ret = -ENOMEM; | ||
443 | |||
444 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | ||
445 | if (!glue) { | ||
446 | dev_err(&pdev->dev, "failed to allocate glue context\n"); | ||
447 | goto err0; | ||
448 | } | ||
449 | |||
450 | musb = platform_device_alloc("musb-hdrc", -1); | ||
451 | if (!musb) { | ||
452 | dev_err(&pdev->dev, "failed to allocate musb device\n"); | ||
453 | goto err1; | ||
454 | } | ||
455 | |||
456 | musb->dev.parent = &pdev->dev; | ||
457 | musb->dev.dma_mask = &bfin_dmamask; | ||
458 | musb->dev.coherent_dma_mask = bfin_dmamask; | ||
459 | |||
460 | glue->dev = &pdev->dev; | ||
461 | glue->musb = musb; | ||
462 | |||
463 | pdata->platform_ops = &bfin_ops; | ||
464 | |||
465 | platform_set_drvdata(pdev, glue); | ||
466 | |||
467 | ret = platform_device_add_resources(musb, pdev->resource, | ||
468 | pdev->num_resources); | ||
469 | if (ret) { | ||
470 | dev_err(&pdev->dev, "failed to add resources\n"); | ||
471 | goto err2; | ||
472 | } | ||
473 | |||
474 | ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); | ||
475 | if (ret) { | ||
476 | dev_err(&pdev->dev, "failed to add platform_data\n"); | ||
477 | goto err2; | ||
478 | } | ||
479 | |||
480 | ret = platform_device_add(musb); | ||
481 | if (ret) { | ||
482 | dev_err(&pdev->dev, "failed to register musb device\n"); | ||
483 | goto err2; | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | |||
488 | err2: | ||
489 | platform_device_put(musb); | ||
490 | |||
491 | err1: | ||
492 | kfree(glue); | ||
493 | |||
494 | err0: | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | static int __exit bfin_remove(struct platform_device *pdev) | ||
499 | { | ||
500 | struct bfin_glue *glue = platform_get_drvdata(pdev); | ||
501 | |||
502 | platform_device_del(glue->musb); | ||
503 | platform_device_put(glue->musb); | ||
504 | kfree(glue); | ||
505 | |||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | #ifdef CONFIG_PM | ||
510 | static int bfin_suspend(struct device *dev) | ||
511 | { | ||
512 | struct bfin_glue *glue = dev_get_drvdata(dev); | ||
513 | struct musb *musb = glue_to_musb(glue); | ||
514 | |||
515 | if (is_host_active(musb)) | ||
516 | /* | ||
517 | * During hibernate gpio_vrsel will change from high to low | ||
518 | * low which will generate wakeup event resume the system | ||
519 | * immediately. Set it to 0 before hibernate to avoid this | ||
520 | * wakeup event. | ||
521 | */ | ||
522 | gpio_set_value(musb->config->gpio_vrsel, 0); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int bfin_resume(struct device *dev) | ||
528 | { | ||
529 | struct bfin_glue *glue = dev_get_drvdata(dev); | ||
530 | struct musb *musb = glue_to_musb(glue); | ||
531 | |||
532 | bfin_musb_reg_init(musb); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static struct dev_pm_ops bfin_pm_ops = { | ||
538 | .suspend = bfin_suspend, | ||
539 | .resume = bfin_resume, | ||
540 | }; | ||
541 | |||
542 | #define DEV_PM_OPS &bfin_pm_op, | ||
543 | #else | ||
544 | #define DEV_PM_OPS NULL | ||
545 | #endif | ||
546 | |||
547 | static struct platform_driver bfin_driver = { | ||
548 | .remove = __exit_p(bfin_remove), | ||
549 | .driver = { | ||
550 | .name = "musb-bfin", | ||
551 | .pm = DEV_PM_OPS, | ||
552 | }, | ||
553 | }; | ||
554 | |||
555 | MODULE_DESCRIPTION("Blackfin MUSB Glue Layer"); | ||
556 | MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>"); | ||
557 | MODULE_LICENSE("GPL v2"); | ||
558 | |||
559 | static int __init bfin_init(void) | ||
560 | { | ||
561 | return platform_driver_probe(&bfin_driver, bfin_probe); | ||
562 | } | ||
563 | subsys_initcall(bfin_init); | ||
564 | |||
565 | static void __exit bfin_exit(void) | ||
566 | { | ||
567 | platform_driver_unregister(&bfin_driver); | ||
568 | } | ||
569 | module_exit(bfin_exit); | ||