summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorJun Li <r65092@freescale.com>2009-12-01 21:16:33 +0800
committerAlejandro Gonzalez <alex.gonzalez@digi.com>2010-02-12 17:19:42 +0100
commit146083d23c4f8337d53c014790e794f098bb33e3 (patch)
tree3b1ae8eb3061e7f3b278f7dc9f17b16d4d33f001 /drivers/usb/gadget
parent537d1eef7468cbd391c40822277f53d819261ca1 (diff)
ENGR00117147-2 USB clock gating and PHY low power mode.
1. If there is no usb devices connectted or all connectted usb devices are in suspend state, usb host can suspend its whole bus, then put the PHY into low power mode and close all usb clocks. 2. close all usb clocks for usb device low power mode. (The patch is splitted 2 patches, this is FSL specific driver part.) Signed-off-by: Li Jun <r65092@freescale.com>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/arcotg_udc.c77
1 files changed, 53 insertions, 24 deletions
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index acc1b9508da9..7772c39a1044 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -109,7 +109,7 @@ dr_wake_up_enable(struct fsl_udc *udc, bool enable)
struct fsl_usb2_platform_data *pdata;
pdata = udc->pdata;
- if (device_can_wakeup(udc_controller->gadget.dev.parent)) {
+ if (device_may_wakeup(udc_controller->gadget.dev.parent)) {
if (pdata->wake_up_enable)
pdata->wake_up_enable(pdata, enable);
}
@@ -272,19 +272,21 @@ static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable)
{
u32 temp;
- if (!device_can_wakeup(udc_controller->gadget.dev.parent))
+ if (!device_may_wakeup(udc_controller->gadget.dev.parent))
return;
- temp = fsl_readl(&dr_regs->portsc1);
- if ((enable) && !(temp & PORTSCX_PHY_LOW_POWER_SPD)) {
+
+ if (enable) {
+ temp = fsl_readl(&dr_regs->portsc1);
temp |= PORTSCX_PHY_LOW_POWER_SPD;
fsl_writel(temp, &dr_regs->portsc1);
if (udc_controller->pdata->usb_clock_for_pm)
udc_controller->pdata->usb_clock_for_pm(false);
- } else if ((!enable) && (temp & PORTSCX_PHY_LOW_POWER_SPD)) {
+ } else {
if (udc_controller->pdata->usb_clock_for_pm)
udc_controller->pdata->usb_clock_for_pm(true);
+ temp = fsl_readl(&dr_regs->portsc1);
temp &= ~PORTSCX_PHY_LOW_POWER_SPD;
fsl_writel(temp, &dr_regs->portsc1);
}
@@ -411,11 +413,7 @@ static void dr_controller_run(struct fsl_udc *udc)
fsl_writel(temp, &dr_regs->usbintr);
- /* If PHY clock is disabled, enable it */
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(1);
-
- if (device_can_wakeup(udc_controller->gadget.dev.parent)) {
+ if (device_may_wakeup(udc_controller->gadget.dev.parent)) {
/* enable BSV irq */
temp = fsl_readl(&dr_regs->otgsc);
temp |= OTGSC_B_SESSION_VALID_IRQ_EN;
@@ -424,7 +422,7 @@ static void dr_controller_run(struct fsl_udc *udc)
/* If vbus not on and used low power mode */
if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID)
- && device_can_wakeup(udc_controller->gadget.dev.parent)) {
+ && device_may_wakeup(udc_controller->gadget.dev.parent)) {
/* enable wake up */
dr_wake_up_enable(udc, true);
/* Set stopped before low power mode */
@@ -1939,8 +1937,7 @@ static void wake_up_irq(struct fsl_udc *udc)
/* disable wake up irq */
dr_wake_up_enable(udc_controller, false);
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(true);
+
udc->stopped = 0;
}
@@ -2030,16 +2027,21 @@ bool try_wake_up_udc(struct fsl_udc *udc)
/* when udc is stopped, only handle wake up irq */
if (udc->stopped) {
- if (!device_can_wakeup(&(udc->pdata->pdev->dev)))
+ if (!device_may_wakeup(&(udc->pdata->pdev->dev)))
return false;
+
+ dr_phy_low_power_mode(udc_controller, false);
+
/* check to see if wake up irq */
irq_src = fsl_readl(&dr_regs->usbctrl);
if (irq_src & USB_CTRL_OTG_WUIR) {
wake_up_irq(udc);
+ } else {
+ dr_phy_low_power_mode(udc_controller, true);
}
}
- if (!device_can_wakeup(udc_controller->gadget.dev.parent))
+ if (!device_may_wakeup(udc_controller->gadget.dev.parent))
return true;
/* check if Vbus change irq */
@@ -2151,6 +2153,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
int retval = -ENODEV;
unsigned long flags = 0;
+ u32 portsc;
if (!udc_controller)
return -ENODEV;
@@ -2173,7 +2176,13 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
udc_controller->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
- dr_phy_low_power_mode(udc_controller, false);
+ portsc = fsl_readl(&dr_regs->portsc1);
+ portsc &= ~PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(portsc, &dr_regs->portsc1);
+
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(true);
+
/* bind udc driver to gadget driver */
retval = driver->bind(&udc_controller->gadget);
if (retval) {
@@ -2227,6 +2236,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
struct fsl_ep *loop_ep;
unsigned long flags;
+ u32 portsc;
if (!udc_controller)
return -ENODEV;
@@ -2237,11 +2247,12 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (udc_controller->transceiver)
(void)otg_set_peripheral(udc_controller->transceiver, 0);
- /* stop DR, disable intr */
- dr_controller_stop(udc_controller);
/* open phy clock for following operation */
dr_phy_low_power_mode(udc_controller, false);
+ /* stop DR, disable intr */
+ dr_controller_stop(udc_controller);
+
/* in fact, no needed */
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_dir = 0;
@@ -2264,7 +2275,13 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
udc_controller->driver = 0;
dr_wake_up_enable(udc_controller, false);
- dr_phy_low_power_mode(udc_controller, true);
+
+ portsc = fsl_readl(&dr_regs->portsc1);
+ portsc |= PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(portsc, &dr_regs->portsc1);
+
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(false);
printk(KERN_INFO "unregistered gadget driver '%s'\r\n",
driver->driver.name);
@@ -2662,7 +2679,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
int ret = -ENODEV;
unsigned int i;
- u32 dccparams;
+ u32 dccparams, portsc;
if (strcmp(pdev->name, driver_name)) {
VDBG("Wrong device\n");
@@ -2840,7 +2857,13 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
dr_wake_up_enable(udc_controller, false);
udc_controller->stopped = 1;
- dr_phy_low_power_mode(udc_controller, true);
+
+ portsc = fsl_readl(&dr_regs->portsc1);
+ portsc |= PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(portsc, &dr_regs->portsc1);
+
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(false);
create_proc_file();
return 0;
@@ -2920,6 +2943,10 @@ static int udc_suspend(struct fsl_udc *udc)
{
u32 mode, usbcmd;
+ /* open clock for register access */
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(true);
+
mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK;
usbcmd = fsl_readl(&dr_regs->usbcmd);
@@ -2933,12 +2960,12 @@ static int udc_suspend(struct fsl_udc *udc)
if (udc->stopped) {
pr_debug("gadget already stopped, leaving early\n");
udc->already_stopped = 1;
- return 0;
+ goto out;
}
if (mode != USB_MODE_CTRL_MODE_DEVICE) {
pr_debug("gadget not in device mode, leaving early\n");
- return 0;
+ goto out;
}
udc->stopped = 1;
@@ -2954,7 +2981,9 @@ static int udc_suspend(struct fsl_udc *udc)
fsl_writel(usbcmd, &dr_regs->usbcmd);
printk(KERN_INFO "USB Gadget suspended\n");
-
+out:
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(false);
return 0;
}