diff options
author | Bharat Nihalani <bnihalani@nvidia.com> | 2010-12-01 19:36:11 +0530 |
---|---|---|
committer | Bharat Nihalani <bnihalani@nvidia.com> | 2010-12-05 22:28:24 -0800 |
commit | cf1b67dab294e70458e4623f919384e949af8531 (patch) | |
tree | 3b2f3d8f30237efa0ebbe2754e20df50286da95f /drivers/usb | |
parent | af6b0b5a76b91343bd26151a4f7f5f1ad4aa2972 (diff) |
USB: fsl_udc_core: Merge changes from 2.6.32
Fixed the suspend and resume cases for LP0
Change-Id: I562bbe9118d4e84bcd7dc5894e9ff542522e7f12
Reviewed-on: http://git-master/r/11781
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Tested-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/fsl_udc_core.c | 139 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_usb2_udc.h | 2 |
2 files changed, 110 insertions, 31 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 248cfe5950ca..8964e58de2ba 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -367,6 +367,10 @@ static void dr_controller_stop(struct fsl_udc *udc) { unsigned int tmp; + /* Clear pending interrupt status bits */ + tmp = fsl_readl(&dr_regs->usbsts); + fsl_writel(tmp, &dr_regs->usbsts); + /* disable all INTR */ fsl_writel(0, &dr_regs->usbintr); @@ -931,12 +935,18 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* Stop the ep before we deal with the queue */ ep->stopped = 1; ep_num = ep_index(ep); - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl &= ~EPCTRL_TX_ENABLE; - else - epctrl &= ~EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + +#if defined(CONFIG_ARCH_TEGRA) + /* Touch the registers if cable is connected and phy is on */ +#endif + { + epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl &= ~EPCTRL_TX_ENABLE; + else + epctrl &= ~EPCTRL_RX_ENABLE; + fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + } /* make sure it's actually queued on this endpoint */ list_for_each_entry(req, &ep->queue, queue) { @@ -979,12 +989,19 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) done(ep, req, -ECONNRESET); /* Enable EP */ -out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl |= EPCTRL_TX_ENABLE; - else - epctrl |= EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); +out: +#if defined(CONFIG_ARCH_TEGRA) + /* Touch the registers if cable is connected and phy is on */ + if (fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS) +#endif + { + epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl |= EPCTRL_TX_ENABLE; + else + epctrl |= EPCTRL_RX_ENABLE; + fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + } ep->stopped = stopped; spin_unlock_irqrestore(&ep->udc->lock, flags); @@ -1114,6 +1131,7 @@ static int fsl_get_frame(struct usb_gadget *gadget) /*----------------------------------------------------------------------- * Tries to wake up the host connected to this gadget -----------------------------------------------------------------------*/ +#ifndef CONFIG_USB_ANDROID static int fsl_wakeup(struct usb_gadget *gadget) { struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget); @@ -1132,6 +1150,7 @@ static int fsl_wakeup(struct usb_gadget *gadget) fsl_writel(portsc, &dr_regs->portsc1); return 0; } +#endif static int can_pullup(struct fsl_udc *udc) { @@ -1229,7 +1248,9 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) /* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, +#ifndef CONFIG_USB_ANDROID .wakeup = fsl_wakeup, +#endif /* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */ .vbus_session = fsl_vbus_session, .vbus_draw = fsl_vbus_draw, @@ -1919,6 +1940,25 @@ static void reset_irq(struct fsl_udc *udc) #endif } +#if defined(CONFIG_ARCH_TEGRA) +/* + * Restart device controller in the OTG mode on VBUS detection + */ +static void fsl_udc_restart(struct fsl_udc *udc) +{ + /* setup the controller in the device mode */ + dr_controller_setup(udc); + /* setup EP0 for setup packet */ + ep0_setup(udc); + /* start the controller */ + dr_controller_run(udc); + /* initialize the USB and EP states */ + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; +} +#endif + /* * USB device controller interrupt handler */ @@ -2733,12 +2773,27 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) -----------------------------------------------------------------*/ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) { - if (udc_controller->transceiver && - udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) - return 0; - - dr_controller_stop(udc_controller); - return 0; + if (udc_controller->transceiver) { + if (udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) { + /* we are not in device mode, return */ + return 0; + } + } + if (udc_controller->vbus_active) { + spin_lock(&udc_controller->lock); + /* Reset all internal Queues and inform client driver */ + reset_queues(udc_controller); + udc_controller->vbus_active = 0; + udc_controller->usb_state = USB_STATE_DEFAULT; + spin_unlock(&udc_controller->lock); + } + /* stop the controller and turn off the clocks */ + dr_controller_stop(udc_controller); + if (udc_controller->transceiver) { + udc_controller->transceiver->state = OTG_STATE_UNDEFINED; + } + fsl_udc_clk_suspend(); + return 0; } /*----------------------------------------------------------------- @@ -2747,19 +2802,43 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) *-----------------------------------------------------------------*/ static int fsl_udc_resume(struct platform_device *pdev) { - if (udc_controller->transceiver && - udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) - return 0; + if (udc_controller->transceiver) { + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_ID_PIN_STATUS)) { + /* If ID status is low means host is connected, return */ + return 0; + } + /* enable clock and check for VBUS */ + fsl_udc_clk_resume(); + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) { + /* if there is no VBUS then power down the clocks and return */ + fsl_udc_clk_suspend(); + return 0; + } else { + /* Detected VBUS set the transceiver state to device mode */ + udc_controller->transceiver->state = OTG_STATE_B_PERIPHERAL; + } + } else { + /* enable the clocks to the controller */ + fsl_udc_clk_resume(); + } - /* Enable DR irq reg and set controller Run */ - if (udc_controller->stopped) { - dr_controller_setup(udc_controller); - dr_controller_run(udc_controller); - } - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - return 0; +#if defined(CONFIG_ARCH_TEGRA) + fsl_udc_restart(udc_controller); +#else + /* Enable DR irq reg and set controller Run */ + if (udc_controller->stopped) { + dr_controller_setup(udc_controller); + dr_controller_run(udc_controller); + } + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; +#endif + /* Power down the phy if cable is not connected */ + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) + fsl_udc_clk_suspend(); + + return 0; } /*------------------------------------------------------------------------- diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 8d5bd2fe7475..99c36054e66c 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -442,7 +442,7 @@ struct ep_td_struct { #define USB_SYS_VBUS_WAKEUP_INT_ENABLE 0x100 #define USB_SYS_VBUS_WAKEUP_INT_STATUS 0x200 #define USB_SYS_VBUS_STATUS 0x400 - +#define USB_SYS_ID_PIN_STATUS (0x4) /*-------------------------------------------------------------------------*/ /* ### driver private data |