Commit 141891a6 authored by Tony Lindgren's avatar Tony Lindgren

[PATCH] ARM: OMAP: USB clock changes from Juha

This patch from Juha Yrjola adds two missing USB clocks.

Please note that CONFIG_OMAP_RESET_CLOCKS may still need to be
disabled in .config for USB to work on some platforms (OSK).
parent 824711c6
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/hardware/clock.h>
#include <asm/arch/dma.h> #include <asm/arch/dma.h>
#include <asm/arch/usb.h> #include <asm/arch/usb.h>
...@@ -1306,6 +1307,23 @@ static void pullup_disable(struct omap_udc *udc) ...@@ -1306,6 +1307,23 @@ static void pullup_disable(struct omap_udc *udc)
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
} }
static struct omap_udc *udc;
static void omap_udc_enable_clock(int enable)
{
if (udc == NULL || udc->dc_clk == NULL || udc->hhc_clk == NULL)
return;
if (enable) {
clk_use(udc->dc_clk);
clk_use(udc->hhc_clk);
udelay(100);
} else {
clk_unuse(udc->hhc_clk);
clk_unuse(udc->dc_clk);
}
}
/* /*
* Called by whatever detects VBUS sessions: external transceiver * Called by whatever detects VBUS sessions: external transceiver
* driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock. * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock.
...@@ -1326,10 +1344,22 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active) ...@@ -1326,10 +1344,22 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
else else
FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510; FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
} }
if (udc->dc_clk != NULL && is_active) {
if (!udc->clk_requested) {
omap_udc_enable_clock(1);
udc->clk_requested = 1;
}
}
if (can_pullup(udc)) if (can_pullup(udc))
pullup_enable(udc); pullup_enable(udc);
else else
pullup_disable(udc); pullup_disable(udc);
if (udc->dc_clk != NULL && !is_active) {
if (udc->clk_requested) {
omap_udc_enable_clock(0);
udc->clk_requested = 0;
}
}
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
return 0; return 0;
} }
...@@ -2039,7 +2069,6 @@ omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r) ...@@ -2039,7 +2069,6 @@ omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct omap_udc *udc;
int usb_gadget_register_driver (struct usb_gadget_driver *driver) int usb_gadget_register_driver (struct usb_gadget_driver *driver)
{ {
...@@ -2082,6 +2111,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) ...@@ -2082,6 +2111,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
udc->gadget.dev.driver = &driver->driver; udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
if (udc->dc_clk != NULL)
omap_udc_enable_clock(1);
status = driver->bind (&udc->gadget); status = driver->bind (&udc->gadget);
if (status) { if (status) {
DBG("bind to %s --> %d\n", driver->driver.name, status); DBG("bind to %s --> %d\n", driver->driver.name, status);
...@@ -2117,6 +2149,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) ...@@ -2117,6 +2149,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
omap_vbus_session(&udc->gadget, 1); omap_vbus_session(&udc->gadget, 1);
done: done:
if (udc->dc_clk != NULL)
omap_udc_enable_clock(0);
return status; return status;
} }
EXPORT_SYMBOL(usb_gadget_register_driver); EXPORT_SYMBOL(usb_gadget_register_driver);
...@@ -2131,6 +2165,9 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) ...@@ -2131,6 +2165,9 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
if (!driver || driver != udc->driver) if (!driver || driver != udc->driver)
return -EINVAL; return -EINVAL;
if (udc->dc_clk != NULL)
omap_udc_enable_clock(1);
if (machine_is_omap_innovator() || machine_is_omap_osk()) if (machine_is_omap_innovator() || machine_is_omap_osk())
omap_vbus_session(&udc->gadget, 0); omap_vbus_session(&udc->gadget, 0);
...@@ -2147,6 +2184,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) ...@@ -2147,6 +2184,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
udc->gadget.dev.driver = NULL; udc->gadget.dev.driver = NULL;
udc->driver = NULL; udc->driver = NULL;
if (udc->dc_clk != NULL)
omap_udc_enable_clock(0);
DBG("unregistered driver '%s'\n", driver->driver.name); DBG("unregistered driver '%s'\n", driver->driver.name);
return status; return status;
} }
...@@ -2720,6 +2759,8 @@ static int __init omap_udc_probe(struct platform_device *pdev) ...@@ -2720,6 +2759,8 @@ static int __init omap_udc_probe(struct platform_device *pdev)
struct otg_transceiver *xceiv = NULL; struct otg_transceiver *xceiv = NULL;
const char *type = NULL; const char *type = NULL;
struct omap_usb_config *config = pdev->dev.platform_data; struct omap_usb_config *config = pdev->dev.platform_data;
struct clk *dc_clk;
struct clk *hhc_clk;
/* NOTE: "knows" the order of the resources! */ /* NOTE: "knows" the order of the resources! */
if (!request_mem_region(pdev->resource[0].start, if (!request_mem_region(pdev->resource[0].start,
...@@ -2729,6 +2770,16 @@ static int __init omap_udc_probe(struct platform_device *pdev) ...@@ -2729,6 +2770,16 @@ static int __init omap_udc_probe(struct platform_device *pdev)
return -EBUSY; return -EBUSY;
} }
if (cpu_is_omap16xx()) {
dc_clk = clk_get(dev, "usb_dc_ck");
hhc_clk = clk_get(dev, "usb_hhc_ck");
BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
/* can't use omap_udc_enable_clock yet */
clk_use(dc_clk);
clk_use(hhc_clk);
udelay(100);
}
INFO("OMAP UDC rev %d.%d%s\n", INFO("OMAP UDC rev %d.%d%s\n",
UDC_REV_REG >> 4, UDC_REV_REG & 0xf, UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
config->otg ? ", Mini-AB" : ""); config->otg ? ", Mini-AB" : "");
...@@ -2851,6 +2902,12 @@ bad_on_1710: ...@@ -2851,6 +2902,12 @@ bad_on_1710:
goto cleanup3; goto cleanup3;
} }
#endif #endif
if (cpu_is_omap16xx()) {
udc->dc_clk = dc_clk;
udc->hhc_clk = hhc_clk;
clk_unuse(hhc_clk);
clk_unuse(dc_clk);
}
create_proc_file(); create_proc_file();
device_add(&udc->gadget.dev); device_add(&udc->gadget.dev);
...@@ -2871,8 +2928,17 @@ cleanup1: ...@@ -2871,8 +2928,17 @@ cleanup1:
cleanup0: cleanup0:
if (xceiv) if (xceiv)
put_device(xceiv->dev); put_device(xceiv->dev);
if (cpu_is_omap16xx()) {
clk_unuse(hhc_clk);
clk_unuse(dc_clk);
clk_put(hhc_clk);
clk_put(dc_clk);
}
release_mem_region(pdev->resource[0].start, release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1); pdev->resource[0].end - pdev->resource[0].start + 1);
return status; return status;
} }
...@@ -2900,6 +2966,13 @@ static int __exit omap_udc_remove(struct platform_device *pdev) ...@@ -2900,6 +2966,13 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
free_irq(pdev->resource[2].start, udc); free_irq(pdev->resource[2].start, udc);
free_irq(pdev->resource[1].start, udc); free_irq(pdev->resource[1].start, udc);
if (udc->dc_clk) {
if (udc->clk_requested)
omap_udc_enable_clock(0);
clk_put(udc->hhc_clk);
clk_put(udc->dc_clk);
}
release_mem_region(pdev->resource[0].start, release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1); pdev->resource[0].end - pdev->resource[0].start + 1);
......
...@@ -175,6 +175,9 @@ struct omap_udc { ...@@ -175,6 +175,9 @@ struct omap_udc {
unsigned ep0_reset_config:1; unsigned ep0_reset_config:1;
unsigned ep0_setup:1; unsigned ep0_setup:1;
struct completion *done; struct completion *done;
struct clk *dc_clk;
struct clk *hhc_clk;
unsigned clk_requested:1;
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -66,15 +66,20 @@ extern int usb_disabled(void); ...@@ -66,15 +66,20 @@ extern int usb_disabled(void);
extern int ocpi_enable(void); extern int ocpi_enable(void);
static struct clk *usb_host_ck; static struct clk *usb_host_ck;
static struct clk *usb_dc_ck;
static int host_enabled;
static int host_initialized;
static void omap_ohci_clock_power(int on) static void omap_ohci_clock_power(int on)
{ {
if (on) { if (on) {
clk_use(usb_dc_ck);
clk_use(usb_host_ck); clk_use(usb_host_ck);
/* guesstimate for T5 == 1x 32K clock + APLL lock time */ /* guesstimate for T5 == 1x 32K clock + APLL lock time */
udelay(100); udelay(100);
} else { } else {
clk_unuse(usb_host_ck); clk_unuse(usb_host_ck);
clk_unuse(usb_dc_ck);
} }
} }
...@@ -280,6 +285,43 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *); ...@@ -280,6 +285,43 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
/* always called with process context; sleeping is OK */ /* always called with process context; sleeping is OK */
int ohci_omap_host_enable(struct usb_bus *host, int enable)
{
struct usb_hcd *hcd;
struct ohci_hcd *ohci;
int retval;
if (host_enabled == enable)
return 0;
host_enabled = enable;
if (!host_initialized)
return 0;
hcd = (struct usb_hcd *)host->hcpriv;
ohci = hcd_to_ohci(hcd);
if (enable) {
omap_ohci_clock_power(1);
if ((retval = ohci_init(ohci)) < 0) {
dev_err(hcd->self.controller, "init error %d\n",
retval);
return retval;
}
if ((retval = hcd->driver->start(hcd)) < 0) {
dev_err(hcd->self.controller, "startup error %d\n",
retval);
return retval;
}
} else {
usb_disconnect(&hcd->self.root_hub);
hcd->driver->stop(hcd);
omap_ohci_clock_power(0);
}
return 0;
}
/** /**
* usb_hcd_omap_probe - initialize OMAP-based HCDs * usb_hcd_omap_probe - initialize OMAP-based HCDs
* Context: !in_interrupt() * Context: !in_interrupt()
...@@ -311,6 +353,13 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, ...@@ -311,6 +353,13 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
if (IS_ERR(usb_host_ck)) if (IS_ERR(usb_host_ck))
return PTR_ERR(usb_host_ck); return PTR_ERR(usb_host_ck);
usb_dc_ck = clk_get(0, "usb_dc_ck");
if (IS_ERR(usb_dc_ck)) {
clk_put(usb_host_ck);
return PTR_ERR(usb_dc_ck);
}
hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id); hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
if (!hcd) { if (!hcd) {
retval = -ENOMEM; retval = -ENOMEM;
...@@ -330,20 +379,32 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, ...@@ -330,20 +379,32 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
ohci = hcd_to_ohci(hcd); ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci); ohci_hcd_init(ohci);
host_initialized = 0;
host_enabled = 1;
retval = omap_start_hc(ohci, pdev); retval = omap_start_hc(ohci, pdev);
if (retval < 0) if (retval < 0)
goto err2; goto err2;
retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT); retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
if (retval == 0)
return retval;
if (retval)
goto err3;
host_initialized = 1;
if (!host_enabled)
omap_ohci_clock_power(0);
return 0;
err3:
omap_stop_hc(pdev); omap_stop_hc(pdev);
err2: err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len); release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1: err1:
usb_put_hcd(hcd); usb_put_hcd(hcd);
err0: err0:
clk_put(usb_dc_ck);
clk_put(usb_host_ck); clk_put(usb_host_ck);
return retval; return retval;
} }
...@@ -369,18 +430,21 @@ void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) ...@@ -369,18 +430,21 @@ void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
omap_stop_hc(pdev); omap_stop_hc(pdev);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len); release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd); usb_put_hcd(hcd);
clk_put(usb_dc_ck);
clk_put(usb_host_ck); clk_put(usb_host_ck);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int __devinit static int
ohci_omap_start (struct usb_hcd *hcd) ohci_omap_start (struct usb_hcd *hcd)
{ {
struct omap_usb_config *config; struct omap_usb_config *config;
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret; int ret;
if (!host_enabled)
return 0;
config = hcd->self.controller->platform_data; config = hcd->self.controller->platform_data;
if (config->otg || config->rwc) if (config->otg || config->rwc)
writel(OHCI_CTRL_RWC, &ohci->regs->control); writel(OHCI_CTRL_RWC, &ohci->regs->control);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment