usb: gadget: Enable/disable the gadget device on vbus_session calls

If we use an OTG driver, the driver will detect VBUS changes and notify
the gadget driver through vbus_session. Enable/disable the gadget driver
in vbus session so that there is no need to check the OTG state on every
interrupt.

Change-Id: I617ad5742be2632b2257b71314db8f330be463d5
Signed-off-by: Benoit Goby <benoit@android.com>
This commit is contained in:
Benoit Goby
2010-08-31 17:09:39 -07:00
committed by Colin Cross
parent c3b5093ac8
commit cf99404c25

View File

@@ -83,6 +83,7 @@ fsl_ep0_desc = {
};
static void fsl_ep_fifo_flush(struct usb_ep *_ep);
static int reset_queues(struct fsl_udc *udc);
#ifdef CONFIG_PPC32
#define fsl_readl(addr) in_le32(addr)
@@ -316,6 +317,8 @@ static void dr_controller_run(struct fsl_udc *udc)
fsl_writel(temp, &usb_sys_regs->vbus_wakeup);
}
#endif
/* Clear stopped bit */
udc->stopped = 0;
/* Enable DR irq reg */
temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
@@ -324,9 +327,6 @@ static void dr_controller_run(struct fsl_udc *udc)
fsl_writel(temp, &dr_regs->usbintr);
/* Clear stopped bit */
udc->stopped = 0;
/* Set the controller as device mode */
temp = fsl_readl(&dr_regs->usbmode);
temp |= USB_MODE_CTRL_MODE_DEVICE;
@@ -1151,7 +1151,37 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
udc = container_of(gadget, struct fsl_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
VDBG("VBUS %s", is_active ? "on" : "off");
if (udc->transceiver) {
if (udc->vbus_active && !is_active) {
/* reset all internal Queues and inform client driver */
reset_queues(udc);
/* stop the controller and turn off the clocks */
dr_controller_stop(udc);
dr_controller_reset(udc);
fsl_udc_clk_suspend();
udc->vbus_active = 0;
udc->usb_state = USB_STATE_DEFAULT;
} else if (!udc->vbus_active && is_active) {
fsl_udc_clk_resume();
/* 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;
udc->vbus_active = 1;
}
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
udc->vbus_active = (is_active != 0);
if (can_pullup(udc))
fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
@@ -1795,45 +1825,6 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
spin_lock_irqsave(&udc->lock, flags);
#ifdef CONFIG_ARCH_TEGRA
if (udc->transceiver) {
if (udc->transceiver->state == OTG_STATE_B_PERIPHERAL) {
if (!udc->vbus_active) {
/* set vbus active and enable the usb clocks */
udc->vbus_active = 1;
fsl_udc_clk_resume();
/* 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;
}
} else if (udc->transceiver->state == OTG_STATE_A_SUSPEND) {
if (udc->vbus_active) {
/* Reset all internal Queues and inform client driver */
reset_queues(udc);
/* stop the controller and turn off the clocks */
dr_controller_stop(udc);
dr_controller_reset(udc);
fsl_udc_clk_suspend();
udc->vbus_active = 0;
udc->usb_state = USB_STATE_DEFAULT;
} else {
spin_unlock_irqrestore(&udc->lock, flags);
return IRQ_NONE;
}
} else {
spin_unlock_irqrestore(&udc->lock, flags);
return IRQ_NONE;
}
}
#endif
/* Disable ISR for OTG host mode */
if (udc->stopped) {
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1846,33 +1837,6 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
/* VDBG("irq_src [0x%8x]", irq_src); */
#ifdef CONFIG_ARCH_TEGRA
if (!udc->transceiver) {
/* VBUS A session detection interrupts. When the interrupt is received,
* the mark the vbus active shadow.
*/
temp = fsl_readl(&usb_sys_regs->vbus_wakeup);
if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS) {
if (temp & USB_SYS_VBUS_STATUS) {
udc->vbus_active = 1;
} else {
reset_queues(udc);
udc->vbus_active = 0;
udc->usb_state = USB_STATE_DEFAULT;
}
/* write back the register to clear the interrupt */
fsl_writel(temp, &usb_sys_regs->vbus_wakeup);
if (udc->vbus_active)
fsl_udc_clk_resume();
else
fsl_udc_clk_suspend();
status = IRQ_HANDLED;
}
}
#endif
/* Need to resume? */
if (udc->usb_state == USB_STATE_SUSPENDED)
if ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SUSPEND) == 0)