diff options
author | Anatolij Gustschin <agust@denx.de> | 2011-04-18 16:02:00 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-02 19:59:38 -0400 |
commit | 83722bc9430424de1614ff31696f73a40b3d81a9 (patch) | |
tree | 4ff0ffe40e080ee03b9ede04b3e943b79335335f /drivers/usb/gadget | |
parent | 0807c500a1a6d7fa20cbd7bbe7fea14a66112463 (diff) |
USB: extend ehci-fsl and fsl_udc_core driver for OTG operation
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Li Yang <leoli@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/fsl_udc_core.c | 147 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_usb2_udc.h | 2 |
2 files changed, 134 insertions, 15 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 28b3a9f25f3b..999eafe89653 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c | |||
@@ -353,6 +353,19 @@ static void dr_controller_stop(struct fsl_udc *udc) | |||
353 | { | 353 | { |
354 | unsigned int tmp; | 354 | unsigned int tmp; |
355 | 355 | ||
356 | pr_debug("%s\n", __func__); | ||
357 | |||
358 | /* if we're in OTG mode, and the Host is currently using the port, | ||
359 | * stop now and don't rip the controller out from under the | ||
360 | * ehci driver | ||
361 | */ | ||
362 | if (udc->gadget.is_otg) { | ||
363 | if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { | ||
364 | pr_debug("udc: Leaving early\n"); | ||
365 | return; | ||
366 | } | ||
367 | } | ||
368 | |||
356 | /* disable all INTR */ | 369 | /* disable all INTR */ |
357 | fsl_writel(0, &dr_regs->usbintr); | 370 | fsl_writel(0, &dr_regs->usbintr); |
358 | 371 | ||
@@ -1668,6 +1681,9 @@ static void port_change_irq(struct fsl_udc *udc) | |||
1668 | { | 1681 | { |
1669 | u32 speed; | 1682 | u32 speed; |
1670 | 1683 | ||
1684 | if (udc->bus_reset) | ||
1685 | udc->bus_reset = 0; | ||
1686 | |||
1671 | /* Bus resetting is finished */ | 1687 | /* Bus resetting is finished */ |
1672 | if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) { | 1688 | if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) { |
1673 | /* Get the speed */ | 1689 | /* Get the speed */ |
@@ -1775,6 +1791,8 @@ static void reset_irq(struct fsl_udc *udc) | |||
1775 | 1791 | ||
1776 | if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { | 1792 | if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { |
1777 | VDBG("Bus reset"); | 1793 | VDBG("Bus reset"); |
1794 | /* Bus is reseting */ | ||
1795 | udc->bus_reset = 1; | ||
1778 | /* Reset all the queues, include XD, dTD, EP queue | 1796 | /* Reset all the queues, include XD, dTD, EP queue |
1779 | * head and TR Queue */ | 1797 | * head and TR Queue */ |
1780 | reset_queues(udc); | 1798 | reset_queues(udc); |
@@ -1852,6 +1870,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) | |||
1852 | 1870 | ||
1853 | /* Reset Received */ | 1871 | /* Reset Received */ |
1854 | if (irq_src & USB_STS_RESET) { | 1872 | if (irq_src & USB_STS_RESET) { |
1873 | VDBG("reset int"); | ||
1855 | reset_irq(udc); | 1874 | reset_irq(udc); |
1856 | status = IRQ_HANDLED; | 1875 | status = IRQ_HANDLED; |
1857 | } | 1876 | } |
@@ -1909,11 +1928,30 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, | |||
1909 | goto out; | 1928 | goto out; |
1910 | } | 1929 | } |
1911 | 1930 | ||
1912 | /* Enable DR IRQ reg and Set usbcmd reg Run bit */ | 1931 | if (udc_controller->transceiver) { |
1913 | dr_controller_run(udc_controller); | 1932 | /* Suspend the controller until OTG enable it */ |
1914 | udc_controller->usb_state = USB_STATE_ATTACHED; | 1933 | udc_controller->stopped = 1; |
1915 | udc_controller->ep0_state = WAIT_FOR_SETUP; | 1934 | printk(KERN_INFO "Suspend udc for OTG auto detect\n"); |
1916 | udc_controller->ep0_dir = 0; | 1935 | |
1936 | /* connect to bus through transceiver */ | ||
1937 | if (udc_controller->transceiver) { | ||
1938 | retval = otg_set_peripheral(udc_controller->transceiver, | ||
1939 | &udc_controller->gadget); | ||
1940 | if (retval < 0) { | ||
1941 | ERR("can't bind to transceiver\n"); | ||
1942 | driver->unbind(&udc_controller->gadget); | ||
1943 | udc_controller->gadget.dev.driver = 0; | ||
1944 | udc_controller->driver = 0; | ||
1945 | return retval; | ||
1946 | } | ||
1947 | } | ||
1948 | } else { | ||
1949 | /* Enable DR IRQ reg and set USBCMD reg Run bit */ | ||
1950 | dr_controller_run(udc_controller); | ||
1951 | udc_controller->usb_state = USB_STATE_ATTACHED; | ||
1952 | udc_controller->ep0_state = WAIT_FOR_SETUP; | ||
1953 | udc_controller->ep0_dir = 0; | ||
1954 | } | ||
1917 | printk(KERN_INFO "%s: bind to driver %s\n", | 1955 | printk(KERN_INFO "%s: bind to driver %s\n", |
1918 | udc_controller->gadget.name, driver->driver.name); | 1956 | udc_controller->gadget.name, driver->driver.name); |
1919 | 1957 | ||
@@ -2374,17 +2412,30 @@ static int __init fsl_udc_probe(struct platform_device *pdev) | |||
2374 | spin_lock_init(&udc_controller->lock); | 2412 | spin_lock_init(&udc_controller->lock); |
2375 | udc_controller->stopped = 1; | 2413 | udc_controller->stopped = 1; |
2376 | 2414 | ||
2415 | #ifdef CONFIG_USB_OTG | ||
2416 | if (pdata->operating_mode == FSL_USB2_DR_OTG) { | ||
2417 | udc_controller->transceiver = otg_get_transceiver(); | ||
2418 | if (!udc_controller->transceiver) { | ||
2419 | ERR("Can't find OTG driver!\n"); | ||
2420 | ret = -ENODEV; | ||
2421 | goto err_kfree; | ||
2422 | } | ||
2423 | } | ||
2424 | #endif | ||
2425 | |||
2377 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2426 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
2378 | if (!res) { | 2427 | if (!res) { |
2379 | ret = -ENXIO; | 2428 | ret = -ENXIO; |
2380 | goto err_kfree; | 2429 | goto err_kfree; |
2381 | } | 2430 | } |
2382 | 2431 | ||
2383 | if (!request_mem_region(res->start, res->end - res->start + 1, | 2432 | if (pdata->operating_mode == FSL_USB2_DR_DEVICE) { |
2384 | driver_name)) { | 2433 | if (!request_mem_region(res->start, res->end - res->start + 1, |
2385 | ERR("request mem region for %s failed\n", pdev->name); | 2434 | driver_name)) { |
2386 | ret = -EBUSY; | 2435 | ERR("request mem region for %s failed\n", pdev->name); |
2387 | goto err_kfree; | 2436 | ret = -EBUSY; |
2437 | goto err_kfree; | ||
2438 | } | ||
2388 | } | 2439 | } |
2389 | 2440 | ||
2390 | dr_regs = ioremap(res->start, resource_size(res)); | 2441 | dr_regs = ioremap(res->start, resource_size(res)); |
@@ -2455,9 +2506,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev) | |||
2455 | goto err_free_irq; | 2506 | goto err_free_irq; |
2456 | } | 2507 | } |
2457 | 2508 | ||
2458 | /* initialize usb hw reg except for regs for EP, | 2509 | if (!udc_controller->transceiver) { |
2459 | * leave usbintr reg untouched */ | 2510 | /* initialize usb hw reg except for regs for EP, |
2460 | dr_controller_setup(udc_controller); | 2511 | * leave usbintr reg untouched */ |
2512 | dr_controller_setup(udc_controller); | ||
2513 | } | ||
2461 | 2514 | ||
2462 | fsl_udc_clk_finalize(pdev); | 2515 | fsl_udc_clk_finalize(pdev); |
2463 | 2516 | ||
@@ -2477,6 +2530,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev) | |||
2477 | if (ret < 0) | 2530 | if (ret < 0) |
2478 | goto err_free_irq; | 2531 | goto err_free_irq; |
2479 | 2532 | ||
2533 | if (udc_controller->transceiver) | ||
2534 | udc_controller->gadget.is_otg = 1; | ||
2535 | |||
2480 | /* setup QH and epctrl for ep0 */ | 2536 | /* setup QH and epctrl for ep0 */ |
2481 | ep0_setup(udc_controller); | 2537 | ep0_setup(udc_controller); |
2482 | 2538 | ||
@@ -2521,7 +2577,8 @@ err_iounmap: | |||
2521 | err_iounmap_noclk: | 2577 | err_iounmap_noclk: |
2522 | iounmap(dr_regs); | 2578 | iounmap(dr_regs); |
2523 | err_release_mem_region: | 2579 | err_release_mem_region: |
2524 | release_mem_region(res->start, res->end - res->start + 1); | 2580 | if (pdata->operating_mode == FSL_USB2_DR_DEVICE) |
2581 | release_mem_region(res->start, res->end - res->start + 1); | ||
2525 | err_kfree: | 2582 | err_kfree: |
2526 | kfree(udc_controller); | 2583 | kfree(udc_controller); |
2527 | udc_controller = NULL; | 2584 | udc_controller = NULL; |
@@ -2555,7 +2612,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) | |||
2555 | dma_pool_destroy(udc_controller->td_pool); | 2612 | dma_pool_destroy(udc_controller->td_pool); |
2556 | free_irq(udc_controller->irq, udc_controller); | 2613 | free_irq(udc_controller->irq, udc_controller); |
2557 | iounmap(dr_regs); | 2614 | iounmap(dr_regs); |
2558 | release_mem_region(res->start, res->end - res->start + 1); | 2615 | if (pdata->operating_mode == FSL_USB2_DR_DEVICE) |
2616 | release_mem_region(res->start, res->end - res->start + 1); | ||
2559 | 2617 | ||
2560 | device_unregister(&udc_controller->gadget.dev); | 2618 | device_unregister(&udc_controller->gadget.dev); |
2561 | /* free udc --wait for the release() finished */ | 2619 | /* free udc --wait for the release() finished */ |
@@ -2598,6 +2656,62 @@ static int fsl_udc_resume(struct platform_device *pdev) | |||
2598 | return 0; | 2656 | return 0; |
2599 | } | 2657 | } |
2600 | 2658 | ||
2659 | static int fsl_udc_otg_suspend(struct device *dev, pm_message_t state) | ||
2660 | { | ||
2661 | struct fsl_udc *udc = udc_controller; | ||
2662 | u32 mode, usbcmd; | ||
2663 | |||
2664 | mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK; | ||
2665 | |||
2666 | pr_debug("%s(): mode 0x%x stopped %d\n", __func__, mode, udc->stopped); | ||
2667 | |||
2668 | /* | ||
2669 | * If the controller is already stopped, then this must be a | ||
2670 | * PM suspend. Remember this fact, so that we will leave the | ||
2671 | * controller stopped at PM resume time. | ||
2672 | */ | ||
2673 | if (udc->stopped) { | ||
2674 | pr_debug("gadget already stopped, leaving early\n"); | ||
2675 | udc->already_stopped = 1; | ||
2676 | return 0; | ||
2677 | } | ||
2678 | |||
2679 | if (mode != USB_MODE_CTRL_MODE_DEVICE) { | ||
2680 | pr_debug("gadget not in device mode, leaving early\n"); | ||
2681 | return 0; | ||
2682 | } | ||
2683 | |||
2684 | /* stop the controller */ | ||
2685 | usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; | ||
2686 | fsl_writel(usbcmd, &dr_regs->usbcmd); | ||
2687 | |||
2688 | udc->stopped = 1; | ||
2689 | |||
2690 | pr_info("USB Gadget suspended\n"); | ||
2691 | |||
2692 | return 0; | ||
2693 | } | ||
2694 | |||
2695 | static int fsl_udc_otg_resume(struct device *dev) | ||
2696 | { | ||
2697 | pr_debug("%s(): stopped %d already_stopped %d\n", __func__, | ||
2698 | udc_controller->stopped, udc_controller->already_stopped); | ||
2699 | |||
2700 | /* | ||
2701 | * If the controller was stopped at suspend time, then | ||
2702 | * don't resume it now. | ||
2703 | */ | ||
2704 | if (udc_controller->already_stopped) { | ||
2705 | udc_controller->already_stopped = 0; | ||
2706 | pr_debug("gadget was already stopped, leaving early\n"); | ||
2707 | return 0; | ||
2708 | } | ||
2709 | |||
2710 | pr_info("USB Gadget resume\n"); | ||
2711 | |||
2712 | return fsl_udc_resume(NULL); | ||
2713 | } | ||
2714 | |||
2601 | /*------------------------------------------------------------------------- | 2715 | /*------------------------------------------------------------------------- |
2602 | Register entry point for the peripheral controller driver | 2716 | Register entry point for the peripheral controller driver |
2603 | --------------------------------------------------------------------------*/ | 2717 | --------------------------------------------------------------------------*/ |
@@ -2610,6 +2724,9 @@ static struct platform_driver udc_driver = { | |||
2610 | .driver = { | 2724 | .driver = { |
2611 | .name = (char *)driver_name, | 2725 | .name = (char *)driver_name, |
2612 | .owner = THIS_MODULE, | 2726 | .owner = THIS_MODULE, |
2727 | /* udc suspend/resume called from OTG driver */ | ||
2728 | .suspend = fsl_udc_otg_suspend, | ||
2729 | .resume = fsl_udc_otg_resume, | ||
2613 | }, | 2730 | }, |
2614 | }; | 2731 | }; |
2615 | 2732 | ||
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 5647cc21b84c..1d51be83fda8 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h | |||
@@ -476,6 +476,7 @@ struct fsl_udc { | |||
476 | unsigned vbus_active:1; | 476 | unsigned vbus_active:1; |
477 | unsigned stopped:1; | 477 | unsigned stopped:1; |
478 | unsigned remote_wakeup:1; | 478 | unsigned remote_wakeup:1; |
479 | unsigned already_stopped:1; | ||
479 | unsigned big_endian_desc:1; | 480 | unsigned big_endian_desc:1; |
480 | 481 | ||
481 | struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ | 482 | struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ |
@@ -487,6 +488,7 @@ struct fsl_udc { | |||
487 | dma_addr_t ep_qh_dma; /* dma address of QH */ | 488 | dma_addr_t ep_qh_dma; /* dma address of QH */ |
488 | 489 | ||
489 | u32 max_pipes; /* Device max pipes */ | 490 | u32 max_pipes; /* Device max pipes */ |
491 | u32 bus_reset; /* Device is bus resetting */ | ||
490 | u32 resume_state; /* USB state to resume */ | 492 | u32 resume_state; /* USB state to resume */ |
491 | u32 usb_state; /* USB current state */ | 493 | u32 usb_state; /* USB current state */ |
492 | u32 ep0_state; /* Endpoint zero state */ | 494 | u32 ep0_state; /* Endpoint zero state */ |