USB: pxa2xx_udc: fix misuse of clock enable/disable calls

Fix pxa2xx_udc to balance calls to clk_enable/clk_disable.

[db: remove inline #ifdefs for IXP non-support of <linux/clk.h> calls]

Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Dmitry Baryshkov 2008-02-22 17:17:19 -08:00 committed by Greg Kroah-Hartman
parent 546d7eec38
commit 64cc2dd937
2 changed files with 53 additions and 39 deletions

View File

@ -103,6 +103,12 @@ static const char ep0name [] = "ep0";
#error "Can't configure both IXP and PXA" #error "Can't configure both IXP and PXA"
#endif #endif
/* IXP doesn't yet support <linux/clk.h> */
#define clk_get(dev,name) NULL
#define clk_enable(clk) do { } while (0)
#define clk_disable(clk) do { } while (0)
#define clk_put(clk) do { } while (0)
#endif #endif
#include "pxa2xx_udc.h" #include "pxa2xx_udc.h"
@ -934,20 +940,31 @@ static void udc_disable(struct pxa2xx_udc *);
/* We disable the UDC -- and its 48 MHz clock -- whenever it's not /* We disable the UDC -- and its 48 MHz clock -- whenever it's not
* in active use. * in active use.
*/ */
static int pullup(struct pxa2xx_udc *udc, int is_active) static int pullup(struct pxa2xx_udc *udc)
{ {
is_active = is_active && udc->vbus && udc->pullup; int is_active = udc->vbus && udc->pullup && !udc->suspended;
DMSG("%s\n", is_active ? "active" : "inactive"); DMSG("%s\n", is_active ? "active" : "inactive");
if (is_active) if (is_active) {
udc_enable(udc); if (!udc->active) {
else { udc->active = 1;
if (udc->gadget.speed != USB_SPEED_UNKNOWN) { /* Enable clock for USB device */
DMSG("disconnect %s\n", udc->driver clk_enable(udc->clk);
? udc->driver->driver.name udc_enable(udc);
: "(no driver)");
stop_activity(udc, udc->driver);
} }
udc_disable(udc); } else {
if (udc->active) {
if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
DMSG("disconnect %s\n", udc->driver
? udc->driver->driver.name
: "(no driver)");
stop_activity(udc, udc->driver);
}
udc_disable(udc);
/* Disable clock for USB device */
clk_disable(udc->clk);
udc->active = 0;
}
} }
return 0; return 0;
} }
@ -958,9 +975,9 @@ static int pxa2xx_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
struct pxa2xx_udc *udc; struct pxa2xx_udc *udc;
udc = container_of(_gadget, struct pxa2xx_udc, gadget); udc = container_of(_gadget, struct pxa2xx_udc, gadget);
udc->vbus = is_active = (is_active != 0); udc->vbus = (is_active != 0);
DMSG("vbus %s\n", is_active ? "supplied" : "inactive"); DMSG("vbus %s\n", is_active ? "supplied" : "inactive");
pullup(udc, is_active); pullup(udc);
return 0; return 0;
} }
@ -975,9 +992,8 @@ static int pxa2xx_udc_pullup(struct usb_gadget *_gadget, int is_active)
if (!udc->mach->gpio_pullup && !udc->mach->udc_command) if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
return -EOPNOTSUPP; return -EOPNOTSUPP;
is_active = (is_active != 0); udc->pullup = (is_active != 0);
udc->pullup = is_active; pullup(udc);
pullup(udc, is_active);
return 0; return 0;
} }
@ -997,7 +1013,7 @@ static const struct usb_gadget_ops pxa2xx_udc_ops = {
#ifdef CONFIG_USB_GADGET_DEBUG_FS #ifdef CONFIG_USB_GADGET_DEBUG_FS
static int static int
udc_seq_show(struct seq_file *m, void *d) udc_seq_show(struct seq_file *m, void *_d)
{ {
struct pxa2xx_udc *dev = m->private; struct pxa2xx_udc *dev = m->private;
unsigned long flags; unsigned long flags;
@ -1146,11 +1162,6 @@ static void udc_disable(struct pxa2xx_udc *dev)
udc_clear_mask_UDCCR(UDCCR_UDE); udc_clear_mask_UDCCR(UDCCR_UDE);
#ifdef CONFIG_ARCH_PXA
/* Disable clock for USB device */
clk_disable(dev->clk);
#endif
ep0_idle (dev); ep0_idle (dev);
dev->gadget.speed = USB_SPEED_UNKNOWN; dev->gadget.speed = USB_SPEED_UNKNOWN;
} }
@ -1191,11 +1202,6 @@ static void udc_enable (struct pxa2xx_udc *dev)
{ {
udc_clear_mask_UDCCR(UDCCR_UDE); udc_clear_mask_UDCCR(UDCCR_UDE);
#ifdef CONFIG_ARCH_PXA
/* Enable clock for USB device */
clk_enable(dev->clk);
#endif
/* try to clear these bits before we enable the udc */ /* try to clear these bits before we enable the udc */
udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR); udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
@ -1286,7 +1292,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
* for set_configuration as well as eventual disconnect. * for set_configuration as well as eventual disconnect.
*/ */
DMSG("registered gadget driver '%s'\n", driver->driver.name); DMSG("registered gadget driver '%s'\n", driver->driver.name);
pullup(dev, 1); pullup(dev);
dump_state(dev); dump_state(dev);
return 0; return 0;
} }
@ -1329,7 +1335,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
return -EINVAL; return -EINVAL;
local_irq_disable(); local_irq_disable();
pullup(dev, 0); dev->pullup = 0;
pullup(dev);
stop_activity(dev, driver); stop_activity(dev, driver);
local_irq_enable(); local_irq_enable();
@ -2131,13 +2138,11 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (irq < 0) if (irq < 0)
return -ENODEV; return -ENODEV;
#ifdef CONFIG_ARCH_PXA
dev->clk = clk_get(&pdev->dev, "UDCCLK"); dev->clk = clk_get(&pdev->dev, "UDCCLK");
if (IS_ERR(dev->clk)) { if (IS_ERR(dev->clk)) {
retval = PTR_ERR(dev->clk); retval = PTR_ERR(dev->clk);
goto err_clk; goto err_clk;
} }
#endif
pr_debug("%s: IRQ %d%s%s\n", driver_name, irq, pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,
dev->has_cfr ? "" : " (!cfr)", dev->has_cfr ? "" : " (!cfr)",
@ -2250,10 +2255,8 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (dev->mach->gpio_vbus) if (dev->mach->gpio_vbus)
gpio_free(dev->mach->gpio_vbus); gpio_free(dev->mach->gpio_vbus);
err_gpio_vbus: err_gpio_vbus:
#ifdef CONFIG_ARCH_PXA
clk_put(dev->clk); clk_put(dev->clk);
err_clk: err_clk:
#endif
return retval; return retval;
} }
@ -2269,7 +2272,9 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
if (dev->driver) if (dev->driver)
return -EBUSY; return -EBUSY;
udc_disable(dev); dev->pullup = 0;
pullup(dev);
remove_debug_files(dev); remove_debug_files(dev);
if (dev->got_irq) { if (dev->got_irq) {
@ -2289,9 +2294,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
if (dev->mach->gpio_pullup) if (dev->mach->gpio_pullup)
gpio_free(dev->mach->gpio_pullup); gpio_free(dev->mach->gpio_pullup);
#ifdef CONFIG_ARCH_PXA
clk_put(dev->clk); clk_put(dev->clk);
#endif
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
the_controller = NULL; the_controller = NULL;
@ -2317,10 +2320,15 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state) static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state)
{ {
struct pxa2xx_udc *udc = platform_get_drvdata(dev); struct pxa2xx_udc *udc = platform_get_drvdata(dev);
unsigned long flags;
if (!udc->mach->gpio_pullup && !udc->mach->udc_command) if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
WARN("USB host won't detect disconnect!\n"); WARN("USB host won't detect disconnect!\n");
pullup(udc, 0); udc->suspended = 1;
local_irq_save(flags);
pullup(udc);
local_irq_restore(flags);
return 0; return 0;
} }
@ -2328,8 +2336,12 @@ static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state)
static int pxa2xx_udc_resume(struct platform_device *dev) static int pxa2xx_udc_resume(struct platform_device *dev)
{ {
struct pxa2xx_udc *udc = platform_get_drvdata(dev); struct pxa2xx_udc *udc = platform_get_drvdata(dev);
unsigned long flags;
pullup(udc, 1); udc->suspended = 0;
local_irq_save(flags);
pullup(udc);
local_irq_restore(flags);
return 0; return 0;
} }

View File

@ -119,7 +119,9 @@ struct pxa2xx_udc {
has_cfr : 1, has_cfr : 1,
req_pending : 1, req_pending : 1,
req_std : 1, req_std : 1,
req_config : 1; req_config : 1,
suspended : 1,
active : 1;
#define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200)) #define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200))
struct timer_list timer; struct timer_list timer;