#include <linux/usb_gadget.h>
#include <linux/usb_otg.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#undef USB_TRACE
/* bulk DMA seems to be behaving for both IN and OUT */
+#ifdef CONFIG_MACH_OMAP_H6300
+#undef USE_DMA
+#else
#define USE_DMA
+#endif
/* ISO too */
#define USE_ISO
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_enable(udc->dc_clk);
+ clk_enable(udc->hhc_clk);
+ udelay(100);
+ } else {
+ clk_disable(udc->hhc_clk);
+ clk_disable(udc->dc_clk);
+ }
+}
+
/*
* Called by whatever detects VBUS sessions: external transceiver
* driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock.
else
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))
pullup_enable(udc);
else
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);
return 0;
}
spin_lock_irqsave(&ep->udc->lock, flags);
if (!list_empty(&ep->queue) && ep->ackwait) {
- use_ep(ep, 0);
+ use_ep(ep, UDC_EP_SEL);
stat_flg = UDC_STAT_FLG_REG;
if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg);
req = container_of(ep->queue.next,
struct omap_req, queue);
- UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL;
(void) read_fifo(ep, req);
UDC_EP_NUM_REG = ep->bEndpointAddress;
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
+ else {
+ deselect_ep();
+ }
}
mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
spin_unlock_irqrestore(&ep->udc->lock, flags);
/*-------------------------------------------------------------------------*/
-static struct omap_udc *udc;
int usb_gadget_register_driver (struct usb_gadget_driver *driver)
{
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(1);
+
status = driver->bind (&udc->gadget);
if (status) {
DBG("bind to %s --> %d\n", driver->driver.name, status);
/* boards that don't have VBUS sensing can't autogate 48MHz;
* can't enter deep sleep while a gadget driver is active.
*/
- if (machine_is_omap_innovator() || machine_is_omap_osk())
+ if (machine_is_omap_innovator() || machine_is_omap_osk() || machine_is_omap_h6300())
omap_vbus_session(&udc->gadget, 1);
done:
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(0);
return status;
}
EXPORT_SYMBOL(usb_gadget_register_driver);
if (!driver || driver != udc->driver)
return -EINVAL;
- if (machine_is_omap_innovator() || machine_is_omap_osk())
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(1);
+
+ if (machine_is_omap_innovator() || machine_is_omap_osk() || machine_is_omap_h6300())
omap_vbus_session(&udc->gadget, 0);
if (udc->transceiver)
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(0);
DBG("unregistered driver '%s'\n", driver->driver.name);
return status;
}
struct otg_transceiver *xceiv = NULL;
const char *type = NULL;
struct omap_usb_config *config = pdev->dev.platform_data;
+ struct clk *dc_clk;
+ struct clk *hhc_clk;
/* NOTE: "knows" the order of the resources! */
if (!request_mem_region(pdev->resource[0].start,
return -EBUSY;
}
+ if (cpu_is_omap16xx()) {
+ dc_clk = clk_get(&pdev->dev, "usb_dc_ck");
+ hhc_clk = clk_get(&pdev->dev, "usb_hhc_ck");
+ BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
+ /* can't use omap_udc_enable_clock yet */
+ clk_enable(dc_clk);
+ clk_enable(hhc_clk);
+ udelay(100);
+ }
+
INFO("OMAP UDC rev %d.%d%s\n",
UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
config->otg ? ", Mini-AB" : "");
hmc = HMC_1510;
type = "(unknown)";
- if (machine_is_omap_innovator()) {
+ if (machine_is_omap_innovator() || machine_is_omap_h6300()) {
/* just set up software VBUS detect, and then
* later rig it so we always report VBUS.
* FIXME without really sensing VBUS, we can't
goto cleanup3;
}
#endif
+ if (cpu_is_omap16xx()) {
+ udc->dc_clk = dc_clk;
+ udc->hhc_clk = hhc_clk;
+ clk_disable(hhc_clk);
+ clk_disable(dc_clk);
+ }
create_proc_file();
device_add(&udc->gadget.dev);
cleanup0:
if (xceiv)
put_device(xceiv->dev);
+
+ if (cpu_is_omap16xx()) {
+ clk_disable(hhc_clk);
+ clk_disable(dc_clk);
+ clk_put(hhc_clk);
+ clk_put(dc_clk);
+ }
+
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
+
return status;
}
free_irq(pdev->resource[2].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,
pdev->resource[0].end - pdev->resource[0].start + 1);