diff options
Diffstat (limited to 'drivers/usb/musb/blackfin.c')
-rw-r--r-- | drivers/usb/musb/blackfin.c | 181 |
1 files changed, 159 insertions, 22 deletions
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index fcb5206a65bd..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,28 +311,28 @@ 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 | static void musb_platform_reg_init(struct musb *musb) | 335 | static void bfin_musb_reg_init(struct musb *musb) |
328 | { | 336 | { |
329 | if (ANOMALY_05000346) { | 337 | if (ANOMALY_05000346) { |
330 | bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); | 338 | bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); |
@@ -362,7 +370,7 @@ static void musb_platform_reg_init(struct musb *musb) | |||
362 | SSYNC(); | 370 | SSYNC(); |
363 | } | 371 | } |
364 | 372 | ||
365 | int __init musb_platform_init(struct musb *musb, void *board_data) | 373 | static int bfin_musb_init(struct musb *musb) |
366 | { | 374 | { |
367 | 375 | ||
368 | /* | 376 | /* |
@@ -386,25 +394,124 @@ int __init musb_platform_init(struct musb *musb, void *board_data) | |||
386 | return -ENODEV; | 394 | return -ENODEV; |
387 | } | 395 | } |
388 | 396 | ||
389 | musb_platform_reg_init(musb); | 397 | bfin_musb_reg_init(musb); |
390 | 398 | ||
391 | if (is_host_enabled(musb)) { | 399 | if (is_host_enabled(musb)) { |
392 | musb->board_set_vbus = bfin_set_vbus; | ||
393 | setup_timer(&musb_conn_timer, | 400 | setup_timer(&musb_conn_timer, |
394 | musb_conn_timer_handler, (unsigned long) musb); | 401 | musb_conn_timer_handler, (unsigned long) musb); |
395 | } | 402 | } |
396 | if (is_peripheral_enabled(musb)) | 403 | if (is_peripheral_enabled(musb)) |
397 | musb->xceiv->set_power = bfin_set_power; | 404 | musb->xceiv->set_power = bfin_musb_set_power; |
398 | 405 | ||
399 | musb->isr = blackfin_interrupt; | 406 | musb->isr = blackfin_interrupt; |
400 | 407 | ||
401 | return 0; | 408 | return 0; |
402 | } | 409 | } |
403 | 410 | ||
411 | static int bfin_musb_exit(struct musb *musb) | ||
412 | { | ||
413 | gpio_free(musb->config->gpio_vrsel); | ||
414 | |||
415 | otg_put_transceiver(musb->xceiv); | ||
416 | usb_nop_xceiv_unregister(); | ||
417 | return 0; | ||
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 | |||
404 | #ifdef CONFIG_PM | 509 | #ifdef CONFIG_PM |
405 | void musb_platform_save_context(struct musb *musb, | 510 | static int bfin_suspend(struct device *dev) |
406 | struct musb_context_registers *musb_context) | ||
407 | { | 511 | { |
512 | struct bfin_glue *glue = dev_get_drvdata(dev); | ||
513 | struct musb *musb = glue_to_musb(glue); | ||
514 | |||
408 | if (is_host_active(musb)) | 515 | if (is_host_active(musb)) |
409 | /* | 516 | /* |
410 | * During hibernate gpio_vrsel will change from high to low | 517 | * During hibernate gpio_vrsel will change from high to low |
@@ -413,20 +520,50 @@ void musb_platform_save_context(struct musb *musb, | |||
413 | * wakeup event. | 520 | * wakeup event. |
414 | */ | 521 | */ |
415 | gpio_set_value(musb->config->gpio_vrsel, 0); | 522 | gpio_set_value(musb->config->gpio_vrsel, 0); |
523 | |||
524 | return 0; | ||
416 | } | 525 | } |
417 | 526 | ||
418 | void musb_platform_restore_context(struct musb *musb, | 527 | static int bfin_resume(struct device *dev) |
419 | struct musb_context_registers *musb_context) | ||
420 | { | 528 | { |
421 | musb_platform_reg_init(musb); | 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; | ||
422 | } | 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 | ||
423 | #endif | 545 | #endif |
424 | 546 | ||
425 | int musb_platform_exit(struct musb *musb) | 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) | ||
426 | { | 560 | { |
427 | gpio_free(musb->config->gpio_vrsel); | 561 | return platform_driver_probe(&bfin_driver, bfin_probe); |
562 | } | ||
563 | subsys_initcall(bfin_init); | ||
428 | 564 | ||
429 | otg_put_transceiver(musb->xceiv); | 565 | static void __exit bfin_exit(void) |
430 | usb_nop_xceiv_unregister(); | 566 | { |
431 | return 0; | 567 | platform_driver_unregister(&bfin_driver); |
432 | } | 568 | } |
569 | module_exit(bfin_exit); | ||