summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorBharat Nihalani <bnihalani@nvidia.com>2010-12-01 19:36:11 +0530
committerBharat Nihalani <bnihalani@nvidia.com>2010-12-05 22:28:24 -0800
commitcf1b67dab294e70458e4623f919384e949af8531 (patch)
tree3b2f3d8f30237efa0ebbe2754e20df50286da95f /drivers/usb
parentaf6b0b5a76b91343bd26151a4f7f5f1ad4aa2972 (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.c139
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h2
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