summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRakesh Bodla <rbodla@nvidia.com>2012-04-18 09:46:16 +0530
committerSimone Willett <swillett@nvidia.com>2012-04-18 16:46:42 -0700
commit56499875cb807e9485ea5ff6d0e9b50bb06196fa (patch)
tree4ccabfd286dc4b03ea3fc5562cb1627552f97b9e /drivers
parent69b3378dd9151627f621b40a5fe82fe697494ee3 (diff)
usb: gadget: fsl_udc: support udc driver without otg
Currently udc driver is dependent on otg driver. Added irq work to make gadget driver work with disabling otg driver. Bug 962366 Change-Id: Id782d8003da12ace553b8b812fa410567c281b34 Reviewed-on: http://git-master/r/95106 Reviewed-by: Rakesh Bodla <rbodla@nvidia.com> Tested-by: Rakesh Bodla <rbodla@nvidia.com> Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c200
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h3
2 files changed, 109 insertions, 94 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index c90e2d01f02c..e3196ba2833c 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -306,6 +306,11 @@ static void nuke(struct fsl_ep *ep, int status)
}
}
+static int can_pullup(struct fsl_udc *udc)
+{
+ return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
/*------------------------------------------------------------------
Internal Hardware related function
------------------------------------------------------------------*/
@@ -485,19 +490,24 @@ static void dr_controller_run(struct fsl_udc *udc)
/* Set controller to Run */
temp = fsl_readl(&dr_regs->usbcmd);
- temp |= USB_CMD_RUN_STOP;
+ if (can_pullup(udc))
+ temp |= USB_CMD_RUN_STOP;
+ else
+ temp &= ~USB_CMD_RUN_STOP;
fsl_writel(temp, &dr_regs->usbcmd);
#ifdef CONFIG_ARCH_TEGRA
- /* Wait for controller to start */
- timeout = jiffies + FSL_UDC_RUN_TIMEOUT;
- while ((fsl_readl(&dr_regs->usbcmd) & USB_CMD_RUN_STOP) !=
- USB_CMD_RUN_STOP) {
- if (time_after(jiffies, timeout)) {
- ERR("udc start timeout!\n");
- return;
+ if (can_pullup(udc)) {
+ /* Wait for controller to start */
+ timeout = jiffies + FSL_UDC_RUN_TIMEOUT;
+ while ((fsl_readl(&dr_regs->usbcmd) & USB_CMD_RUN_STOP) !=
+ USB_CMD_RUN_STOP) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc start timeout!\n");
+ return;
+ }
+ cpu_relax();
}
- cpu_relax();
}
#endif
@@ -1374,10 +1384,6 @@ static int fsl_wakeup(struct usb_gadget *gadget)
}
#endif
-static int can_pullup(struct fsl_udc *udc)
-{
- return udc->driver && udc->softconnect && udc->vbus_active;
-}
static int fsl_set_selfpowered(struct usb_gadget * gadget, int is_on)
{
@@ -1397,64 +1403,47 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
udc = container_of(gadget, struct fsl_udc, gadget);
VDBG("VBUS %s", is_active ? "on" : "off");
-
- if (udc->transceiver) {
- if (udc->vbus_active && !is_active) {
- /* If cable disconnected, cancel any delayed work */
- cancel_delayed_work(&udc->work);
- spin_lock_irqsave(&udc->lock, flags);
- /* 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);
- udc->vbus_active = 0;
- udc->usb_state = USB_STATE_DEFAULT;
- spin_unlock_irqrestore(&udc->lock, flags);
- fsl_udc_clk_suspend(false);
- if (udc->vbus_regulator) {
- /* set the current limit to 0mA */
- regulator_set_current_limit(
- udc->vbus_regulator, 0, 0);
- }
- } else if (!udc->vbus_active && is_active) {
- fsl_udc_clk_resume(false);
- /* setup the controller in the device mode */
- dr_controller_setup(udc);
- /* setup EP0 for setup packet */
- ep0_setup(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;
- /* start the controller */
- dr_controller_run(udc);
- if (udc->vbus_regulator) {
- /* set the current limit to 100mA */
- regulator_set_current_limit(
- udc->vbus_regulator, 0, 100);
- }
- /* Schedule work to wait for 1000 msec and check for
- * charger if setup packet is not received */
- schedule_delayed_work(&udc->work,
- USB_CHARGER_DETECTION_WAIT_TIME_MS);
+ if (udc->vbus_active && !is_active) {
+ /* If cable disconnected, cancel any delayed work */
+ cancel_delayed_work(&udc->work);
+ spin_lock_irqsave(&udc->lock, flags);
+ /* 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);
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ spin_unlock_irqrestore(&udc->lock, flags);
+ fsl_udc_clk_suspend(false);
+ if (udc->vbus_regulator) {
+ /* set the current limit to 0mA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0, 0);
}
-
-#ifndef CONFIG_USB_G_ANDROID
- return 0;
-#endif
+ } else if (!udc->vbus_active && is_active) {
+ fsl_udc_clk_resume(false);
+ /* setup the controller in the device mode */
+ dr_controller_setup(udc);
+ /* setup EP0 for setup packet */
+ ep0_setup(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;
+ /* start the controller */
+ dr_controller_run(udc);
+ if (udc->vbus_regulator) {
+ /* set the current limit to 100mA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0, 100);
+ }
+ /* Schedule work to wait for 1000 msec and check for
+ * charger if setup packet is not received */
+ schedule_delayed_work(&udc->work,
+ USB_CHARGER_DETECTION_WAIT_TIME_MS);
}
-
- spin_lock_irqsave(&udc->lock, flags);
- udc->vbus_active = (is_active != 0);
- if (can_pullup(udc))
- fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- else
- fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
@@ -1490,16 +1479,16 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
udc = container_of(gadget, struct fsl_udc, gadget);
udc->softconnect = (is_on != 0);
- if (udc_controller->transceiver) {
- if (udc_controller->transceiver->state == OTG_STATE_B_PERIPHERAL) {
- if (can_pullup(udc))
- fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- else
- fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- }
- }
+ if (udc_controller->transceiver &&
+ udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL)
+ return 0;
+
+ if (can_pullup(udc))
+ fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
+ &dr_regs->usbcmd);
+ else
+ fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
+ &dr_regs->usbcmd);
return 0;
}
@@ -2287,6 +2276,20 @@ static void fsl_udc_boost_cpu_frequency_work(struct work_struct* work)
}
#endif
+static void fsl_udc_irq_work(struct work_struct* irq_work)
+{
+ struct fsl_udc *udc = container_of (irq_work, struct fsl_udc, irq_work);
+ bool cable_connected = false;
+ u32 temp = 0;
+
+ temp = fsl_readl(&usb_sys_regs->vbus_wakeup);
+ /* Check whether cable is connected*/
+ if (temp & USB_SYS_VBUS_STATUS)
+ fsl_vbus_session(&udc->gadget, 1);
+ else
+ fsl_vbus_session(&udc->gadget, 0);
+}
+
/*
* If VBUS is detected and setup packet is not received in 100ms then
* work thread starts and checks for the USB charger detection.
@@ -2319,12 +2322,12 @@ static void fsl_udc_restart(struct fsl_udc *udc)
/* setup EP0 for setup packet */
ep0_setup(udc);
/* start the controller */
+ udc->vbus_active = 1;
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;
}
#endif
@@ -2340,10 +2343,21 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
spin_lock_irqsave(&udc->lock, flags);
+ if (!udc->transceiver)
+ {
+ u32 temp = fsl_readl(&usb_sys_regs->vbus_wakeup);
+ /* write back the register to clear the interrupt */
+ fsl_writel(temp, &usb_sys_regs->vbus_wakeup);
+ if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS) {
+ schedule_work(&udc->irq_work);
+ }
+ status = IRQ_HANDLED;
+ }
+
/* Disable ISR for OTG host mode */
if (udc->stopped) {
spin_unlock_irqrestore(&udc->lock, flags);
- return IRQ_NONE;
+ return status;
}
#ifdef CONFIG_ARCH_TEGRA
@@ -2466,6 +2480,7 @@ static int fsl_start(struct usb_gadget_driver *driver,
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_state = WAIT_FOR_SETUP;
udc_controller->ep0_dir = 0;
+ udc_controller->vbus_active = vbus_enabled();
}
printk(KERN_INFO "%s: bind to driver %s\n",
@@ -3108,6 +3123,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
INIT_WORK(&udc_controller->boost_cpufreq_work, fsl_udc_boost_cpu_frequency_work);
pm_qos_add_request(&boost_cpu_freq_req, PM_QOS_CPU_FREQ_MIN, PM_QOS_DEFAULT_VALUE);
#endif
+ /* create a work for controlling the clocks to the phy if otg is disabled */
+ INIT_WORK(&udc_controller->irq_work, fsl_udc_irq_work);
/* Get the regulator for drawing the vbus current in udc driver */
udc_controller->vbus_regulator = regulator_get(NULL, "usb_bat_chg");
@@ -3136,6 +3153,10 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
#endif
#endif
+ /* This should done ideally if board does not have pmu interrupt */
+ if (!udc_controller->transceiver)
+ fsl_udc_clk_enable();
+
return 0;
err_del_udc:
@@ -3267,23 +3288,16 @@ static int fsl_udc_resume(struct platform_device *pdev)
/* Detected VBUS set the transceiver state to device mode */
udc_controller->transceiver->state = OTG_STATE_B_PERIPHERAL;
}
+ } else {
+ fsl_udc_clk_resume(true);
}
fsl_udc_clk_resume(true);
-#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(false);
+ else
+ fsl_udc_restart(udc_controller);
return 0;
}
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 60055e77bf9a..814214f1c648 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -640,8 +640,9 @@ struct fsl_udc {
struct delayed_work work; /* delayed work for charger detection */
struct regulator *vbus_regulator; /* regulator for drawing VBUS */
u32 current_limit;
- struct work_struct charger_work; /* work for settting regulator current limit */
+ struct work_struct charger_work; /* work for setting regulator current limit */
struct work_struct boost_cpufreq_work; /* work for boosting cpu frequency */
+ struct work_struct irq_work; /* irq work for controlling the usb power*/
};
/*-------------------------------------------------------------------------*/