/*
- * omap_udc.c -- for OMAP 1610 udc, with OTG support
+ * omap_udc.c -- for OMAP full speed udc; most chips support OTG.
*
* Copyright (C) 2004 Texas Instruments, Inc.
* Copyright (C) 2004 David Brownell
#undef USB_TRACE
-/* OUT-dma seems to be behaving */
+/* bulk DMA seems to be behaving for both IN and OUT */
#define USE_DMA
/* ISO too */
#define USE_ISO
-
#define DRIVER_DESC "OMAP UDC driver"
-#define DRIVER_VERSION "24 August 2004"
+#define DRIVER_VERSION "4 October 2004"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
module_param (fifo_mode, uint, 0);
MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)");
-
#ifdef USE_DMA
static unsigned use_dma = 1;
list_add(&ep->iso, &udc->iso);
/* maybe assign a DMA channel to this endpoint */
- if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK
- && !(ep->bEndpointAddress & USB_DIR_IN))
- /* FIXME ISO can dma, but prefers first channel.
- * IN can dma, but lacks debugging.
- */
+ if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK)
+ /* FIXME ISO can dma, but prefers first channel */
dma_channel_claim(ep, 0);
/* PIO OUT may RX packets */
if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC
&& !ep->has_dma
- && !(ep->bEndpointAddress & USB_DIR_IN))
+ && !(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
+ ep->ackwait = 1 + ep->double_buf;
+ }
spin_unlock_irqrestore(&udc->lock, flags);
VDBG("%s enabled\n", _ep->name);
ep->has_dma = 0;
UDC_CTRL_REG = UDC_SET_HALT;
list_del_init(&ep->iso);
+ del_timer(&ep->timer);
spin_unlock_irqrestore(&ep->udc->lock, flags);
u16 ep_stat = UDC_STAT_FLG_REG;
is_last = 0;
- if (ep_stat & FIFO_UNREADABLE)
+ if (ep_stat & FIFO_EMPTY) {
+ if (!ep->double_buf)
+ break;
+ ep->fnf = 1;
+ }
+ if (ep_stat & UDC_EP_HALTED)
break;
- if (ep_stat & (UDC_NON_ISO_FIFO_FULL|UDC_ISO_FIFO_FULL))
+ if (ep_stat & FIFO_FULL)
avail = ep->ep.maxpacket;
- else
+ else {
avail = UDC_RXFSTAT_REG;
+ ep->fnf = ep->double_buf;
+ }
count = read_packet(buf, req, avail);
- // FIXME double buffered PIO OUT wasn't behaving...
-
/* partial packet reads may not be errors */
if (count < ep->ep.maxpacket) {
is_last = 1;
if (!ep->bEndpointAddress)
break;
- if (!ep->double_buf) {
- UDC_CTRL_REG = UDC_SET_FIFO_EN;
- if (!is_last)
- break;
- }
-
- if (is_last) {
+ if (is_last)
done(ep, req, 0);
- if (list_empty(&ep->queue) || !ep->double_buf)
- break;
- req = container_of(ep->queue.next,
- struct omap_req, queue);
- is_last = 0;
- }
+ break;
}
return is_last;
}
/*-------------------------------------------------------------------------*/
+static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
+{
+ dma_addr_t end;
+
+ /* IN-DMA needs this on fault/cancel paths, so 15xx misreports
+ * the last transfer's bytecount by more than a FIFO's worth.
+ */
+ if (cpu_is_omap15xx())
+ return 0;
+
+ end = omap_readw(OMAP_DMA_CSAC(ep->lch));
+ if (end == ep->dma_counter)
+ return 0;
+
+ end |= start & (0xffff << 16);
+ if (end < start)
+ end += 0x10000;
+ return end - start;
+}
+
+#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
+ ? OMAP_DMA_CSAC(x) /* really: CPC */ \
+ : OMAP_DMA_CDAC(x))
+
+static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
+{
+ dma_addr_t end;
+
+ end = omap_readw(DMA_DEST_LAST(ep->lch));
+ if (end == ep->dma_counter)
+ return 0;
+
+ end |= start & (0xffff << 16);
+ if (cpu_is_omap15xx())
+ end++;
+ if (end < start)
+ end += 0x10000;
+ return end - start;
+}
+
+
/* Each USB transfer request using DMA maps to one or more DMA transfers.
* When DMA completion isn't request completion, the UDC continues with
* the next DMA transfer for that USB transfer.
{
u16 txdma_ctrl;
unsigned length = req->req.length - req->req.actual;
+ const int sync_mode = cpu_is_omap15xx()
+ ? OMAP_DMA_SYNC_FRAME
+ : OMAP_DMA_SYNC_ELEMENT;
/* measure length in either bytes or packets */
- if (length <= (UDC_TXN_TSC + 1)) {
+ if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
+ || (cpu_is_omap15xx() && length < ep->maxpacket)) {
txdma_ctrl = UDC_TXN_EOT | length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- length, 1, OMAP_DMA_SYNC_ELEMENT);
+ length, 1, sync_mode);
} else {
- length = max(length / ep->maxpacket,
+ length = min(length / ep->maxpacket,
(unsigned) UDC_TXN_TSC + 1);
txdma_ctrl = length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- ep->ep.maxpacket, length,
- OMAP_DMA_SYNC_ELEMENT);
+ ep->ep.maxpacket, length, sync_mode);
length *= ep->maxpacket;
}
-
omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
omap_start_dma(ep->lch);
+ ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel);
UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl;
req->dma_bytes = length;
&& req->dma_bytes != 0
&& (req->req.actual % ep->maxpacket) == 0)
return;
- } else {
- u32 last;
-
- // FIXME this surely isn't #bytes transferred
- last = (omap_readw(OMAP_DMA_CSSA_U(ep->lch)) << 16)
- | omap_readw(OMAP_DMA_CSSA_L(ep->lch));
- req->req.actual = last - req->req.dma;
- }
+ } else
+ req->req.actual += dma_src_len(ep, req->req.dma
+ + req->req.actual);
/* tx completion */
omap_stop_dma(ep->lch);
OMAP_DMA_SYNC_ELEMENT);
omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
+ ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
{
u16 count;
- /* FIXME must be a better way to see how much dma
- * happened, even when it never got going...
- */
- count = omap_readw(OMAP_DMA_CDAC(ep->lch));
- count -= 0xffff & (req->req.dma + req->req.actual);
+ if (status == 0)
+ ep->dma_counter = (u16) (req->req.dma + req->req.actual);
+ count = dma_dest_len(ep, req->req.dma + req->req.actual);
count += req->req.actual;
if (count <= req->req.length)
req->req.actual = count;
-
+
if (count != req->dma_bytes || status)
omap_stop_dma(ep->lch);
if (irq_src & UDC_RXN_CNT) {
ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)];
- DBG("%s, RX_CNT irq?\n", ep->ep.name);
+ ep->irqs++;
+ /* omap15xx does this unasked... */
+ VDBG("%s, RX_CNT irq?\n", ep->ep.name);
UDC_IRQ_SRC_REG = UDC_RXN_CNT;
}
}
omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
/* channel type P: hw synch (fifo) */
- omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
+ if (!cpu_is_omap15xx())
+ omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
}
just_restart:
use_ep(ep, UDC_EP_SEL);
(is_in ? write_fifo : read_fifo)(ep, req);
deselect_ep();
+ if (!is_in) {
+ UDC_CTRL_REG = UDC_SET_FIFO_EN;
+ ep->ackwait = 1 + ep->double_buf;
+ }
/* IN: 6 wait states before it'll tx */
}
}
UDC_TXDMA_CFG_REG &= ~mask;
if (req) {
- if (active)
- udelay(50);
finish_in_dma(ep, req, -ECONNRESET);
- if (UDC_TXDMA_CFG_REG & mask)
- WARN("%s, SPIN abort TX dma\n", ep->ep.name);
- }
- /* host may empty the fifo (or not...) */
+ /* clear FIFO; hosts probably won't empty it */
+ use_ep(ep, UDC_EP_SEL);
+ UDC_CTRL_REG = UDC_CLR_EP;
+ deselect_ep();
+ }
while (UDC_TXDMA_CFG_REG & mask)
udelay(10);
-
} else {
UDC_RXDMA_CFG_REG &= ~mask;
/* dma empties the fifo */
- while (active && (UDC_RXDMA_CFG_REG & mask))
+ while (UDC_RXDMA_CFG_REG & mask)
udelay(10);
- omap_stop_dma(ep->lch);
if (req)
finish_out_dma(ep, req, -ECONNRESET);
}
if ((is_in ? write_fifo : read_fifo)(ep, req) == 1)
req = 0;
deselect_ep();
+ if (!is_in) {
+ UDC_CTRL_REG = UDC_SET_FIFO_EN;
+ ep->ackwait = 1 + ep->double_buf;
+ }
/* IN: 6 wait states before it'll tx */
}
}
if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) {
int channel = ep->dma_channel;
- /* releasing the dma completion cancels the request,
+ /* releasing the channel cancels the request,
* reclaiming the channel restarts the queue
*/
dma_channel_release(ep);
use_ep(ep, 0);
UDC_CTRL_REG = UDC_RESET_EP;
ep->ackwait = 0;
- if (!(ep->bEndpointAddress & USB_DIR_IN))
+ if (!(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
+ ep->ackwait = 1 + ep->double_buf;
+ }
}
}
done:
{
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
#ifndef CONFIG_USB_OTG
- OTG_CTRL_REG |= OTG_BSESSVLD;
+ if (!cpu_is_omap15xx())
+ OTG_CTRL_REG |= OTG_BSESSVLD;
#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
}
static void pullup_disable(struct omap_udc *udc)
{
#ifndef CONFIG_USB_OTG
- OTG_CTRL_REG &= ~OTG_BSESSVLD;
+ if (!cpu_is_omap15xx())
+ OTG_CTRL_REG &= ~OTG_BSESSVLD;
#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
/*
* Called by whatever detects VBUS sessions: external transceiver
- * driver, or maybe GPIO0 VBUS IRQ.
+ * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock.
*/
static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
{
spin_lock_irqsave(&udc->lock, flags);
VDBG("VBUS %s\n", is_active ? "on" : "off");
udc->vbus_active = (is_active != 0);
+ if (cpu_is_omap15xx()) {
+ /* "software" detect, ignored if !VBUS_MODE_1510 */
+ if (is_active)
+ FUNC_MUX_CTRL_0_REG |= VBUS_CTRL_1510;
+ else
+ FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
+ }
if (can_pullup(udc))
pullup_enable(udc);
else
/* Clear any pending requests and then scrub any rx/tx state
* before starting to handle the SETUP request.
*/
- if (irq_src & UDC_SETUP)
+ if (irq_src & UDC_SETUP) {
+ u16 ack = irq_src & (UDC_EP0_TX|UDC_EP0_RX);
+
nuke(ep0, 0);
+ if (ack) {
+ UDC_IRQ_SRC_REG = ack;
+ irq_src = UDC_SETUP;
+ }
+ }
/* IN/OUT packets mean we're in the DATA or STATUS stage.
* This driver uses only uses protocol stalls (ep0 never halts),
use_ep(ep, 0);
UDC_CTRL_REG = UDC_RESET_EP;
ep->ackwait = 0;
- if (!(ep->bEndpointAddress & USB_DIR_IN))
+ if (!(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
+ ep->ackwait = 1 + ep->double_buf;
+ }
}
VDBG("%s halt cleared by host\n", ep->name);
goto ep0out_status_stage;
}
change &= ~UDC_SUS;
}
- if (change & OTG_FLAGS) {
+ if (!cpu_is_omap15xx() && (change & OTG_FLAGS)) {
update_otg(udc);
change &= ~OTG_FLAGS;
}
return status;
}
+/* workaround for seemingly-lost IRQs for RX ACKs... */
+#define PIO_OUT_TIMEOUT (jiffies + HZ/3)
+#define HALF_FULL(f) (!((f)&(UDC_NON_ISO_FIFO_FULL|UDC_NON_ISO_FIFO_EMPTY)))
+
+static void pio_out_timer(unsigned long _ep)
+{
+ struct omap_ep *ep = (void *) _ep;
+ unsigned long flags;
+ u16 stat_flg;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ if (!list_empty(&ep->queue) && ep->ackwait) {
+ use_ep(ep, 0);
+ stat_flg = UDC_STAT_FLG_REG;
+
+ if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
+ || (ep->double_buf && HALF_FULL(stat_flg)))) {
+ struct omap_req *req;
+
+ 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;
+ }
+ }
+ mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+}
+
static irqreturn_t
omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
{
ep = &udc->ep[epnum];
ep->irqs++;
- if (!list_empty(&ep->queue)) {
- UDC_EP_NUM_REG = epnum | UDC_EP_SEL;
- if ((UDC_STAT_FLG_REG & UDC_ACK)) {
+ UDC_EP_NUM_REG = epnum | UDC_EP_SEL;
+ ep->fnf = 0;
+ if ((UDC_STAT_FLG_REG & UDC_ACK)) {
+ ep->ackwait--;
+ if (!list_empty(&ep->queue)) {
int stat;
req = container_of(ep->queue.next,
struct omap_req, queue);
stat = read_fifo(ep, req);
- // FIXME double buffered PIO OUT should work
+ if (!ep->double_buf)
+ ep->fnf = 1;
}
- UDC_EP_NUM_REG = epnum;
}
+ /* min 6 clock delay before clearing EP_SEL ... */
+ epn_stat = UDC_EPN_STAT_REG;
+ epn_stat = UDC_EPN_STAT_REG;
+ UDC_EP_NUM_REG = epnum;
+
+ /* enabling fifo _after_ clearing ACK, contrary to docs,
+ * reduces lossage; timer still needed though (sigh).
+ */
+ if (ep->fnf) {
+ UDC_CTRL_REG = UDC_SET_FIFO_EN;
+ ep->ackwait = 1 + ep->double_buf;
+ }
+ mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
}
/* then IN transfers */
- if (irq_src & UDC_EPN_TX) {
+ else if (irq_src & UDC_EPN_TX) {
epnum = epn_stat & 0x0f;
UDC_IRQ_SRC_REG = UDC_EPN_TX;
status = IRQ_HANDLED;
ep = &udc->ep[16 + epnum];
ep->irqs++;
- ep->ackwait = 0;
- if (!list_empty(&ep->queue)) {
- UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL;
- if ((UDC_STAT_FLG_REG & UDC_ACK)) {
+ UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL;
+ if ((UDC_STAT_FLG_REG & UDC_ACK)) {
+ ep->ackwait = 0;
+ if (!list_empty(&ep->queue)) {
req = container_of(ep->queue.next,
struct omap_req, queue);
(void) write_fifo(ep, req);
}
- UDC_EP_NUM_REG = epnum | UDC_EP_DIR;
- /* 6 wait states before it'll tx */
}
+ /* min 6 clock delay before clearing EP_SEL ... */
+ epn_stat = UDC_EPN_STAT_REG;
+ epn_stat = UDC_EPN_STAT_REG;
+ UDC_EP_NUM_REG = epnum | UDC_EP_DIR;
+ /* then 6 clocks before it'd tx */
}
spin_unlock_irqrestore(&udc->lock, flags);
pullup_disable (udc);
}
+ if (machine_is_omap_innovator())
+ omap_vbus_session(&udc->gadget, 1);
+
done:
return status;
}
if (!driver || driver != udc->driver)
return -EINVAL;
+ if (machine_is_omap_innovator())
+ omap_vbus_session(&udc->gadget, 0);
+
if (udc->transceiver)
(void) otg_set_peripheral(udc->transceiver, 0);
else
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_OMAP_PROC
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
#include <linux/seq_file.h>
stat_flg = UDC_STAT_FLG_REG;
seq_printf(s,
- "\n%s %sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
- ep->name, buf, ep->irqs, stat_flg,
+ "\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
+ ep->name, buf,
+ ep->double_buf ? "dbuf " : "",
+ ({char *s; switch(ep->ackwait){
+ case 0: s = ""; break;
+ case 1: s = "(ackw) "; break;
+ case 2: s = "(ackw2) "; break;
+ default: s = "(?) "; break;
+ } s;}),
+ ep->irqs, stat_flg,
(stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "",
(stat_flg & UDC_MISS_IN) ? "miss_in " : "",
(stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "",
if (list_empty (&ep->queue))
seq_printf(s, "\t(queue empty)\n");
else
- list_for_each_entry (req, &ep->queue, queue)
+ list_for_each_entry (req, &ep->queue, queue) {
+ unsigned length = req->req.actual;
+
+ if (use_dma && buf[0]) {
+ length += ((ep->bEndpointAddress & USB_DIR_IN)
+ ? dma_src_len : dma_dest_len)
+ (ep, req->req.dma + length);
+ buf[0] = 0;
+ }
seq_printf(s, "\treq %p len %d/%d buf %p\n",
- &req->req, req->req.actual,
+ &req->req, length,
req->req.length, req->req.buf);
+ }
}
static char *trx_mode(unsigned m)
}
}
-static int proc_udc_show(struct seq_file *s, void *_)
+static int proc_otg_show(struct seq_file *s)
{
u32 tmp;
- struct omap_ep *ep;
- unsigned long flags;
-
- spin_lock_irqsave(&udc->lock, flags);
- seq_printf(s, "%s, version: " DRIVER_VERSION
-#ifdef USE_ISO
- " (iso)"
-#endif
- "%s\n",
- driver_desc,
- use_dma ? " (dma)" : "");
-
- tmp = UDC_REV_REG & 0xff;
- seq_printf(s,
- "UDC rev %d.%d, OTG rev %d.%d, fifo mode %d, gadget %s\n"
- "hmc %d, transceiver %08x %s\n",
+ tmp = OTG_REV_REG;
+ seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n",
tmp >> 4, tmp & 0xf,
- OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
- fifo_mode,
- udc->driver ? udc->driver->driver.name : "(none)",
- HMC, USB_TRANSCEIVER_CTRL_REG,
- udc->transceiver ? udc->transceiver->label : "");
-
- /* OTG controller registers */
+ USB_TRANSCEIVER_CTRL_REG);
tmp = OTG_SYSCON_1_REG;
seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
FOURBITS "\n", tmp,
seq_printf(s, "otg_outctrl %04x" "\n", tmp);
tmp = OTG_TEST_REG;
seq_printf(s, "otg_test %04x" "\n", tmp);
+}
+
+static int proc_udc_show(struct seq_file *s, void *_)
+{
+ u32 tmp;
+ struct omap_ep *ep;
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ seq_printf(s, "%s, version: " DRIVER_VERSION
+#ifdef USE_ISO
+ " (iso)"
+#endif
+ "%s\n",
+ driver_desc,
+ use_dma ? " (dma)" : "");
+
+ tmp = UDC_REV_REG & 0xff;
+ seq_printf(s,
+ "UDC rev %d.%d, fifo mode %d, gadget %s\n"
+ "hmc %d, transceiver %s\n",
+ tmp >> 4, tmp & 0xf,
+ fifo_mode,
+ udc->driver ? udc->driver->driver.name : "(none)",
+ HMC,
+ udc->transceiver ? udc->transceiver->label : "(none)");
+ seq_printf(s, "ULPD control %04x req %04x status %04x\n",
+ __REG16(ULPD_CLOCK_CTRL),
+ __REG16(ULPD_SOFT_REQ),
+ __REG16(ULPD_STATUS_REQ));
+
+ /* OTG controller registers */
+ if (!cpu_is_omap15xx())
+ proc_otg_show(s);
tmp = UDC_SYSCON1_REG;
seq_printf(s, "\nsyscon1 %04x" EIGHTBITS "\n", tmp,
epn_rxtx |= UDC_EPN_RX_ISO;
dbuf = 1;
} else {
- /* pio-out could potentially double-buffer,
- * as can (should!) DMA-IN
+ /* double-buffering "not supported" on 15xx,
+ * and ignored for PIO-IN on 16xx
*/
- if (!use_dma || (addr & USB_DIR_IN))
+ if (!use_dma || cpu_is_omap15xx())
dbuf = 0;
switch (maxp) {
}
if (dbuf && addr)
epn_rxtx |= UDC_EPN_RX_DB;
+ init_timer(&ep->timer);
+ ep->timer.function = pio_out_timer;
+ ep->timer.data = (unsigned long) ep;
}
if (addr)
epn_rxtx |= UDC_EPN_RX_VALID;
return -EBUSY;
}
- INFO("OMAP UDC rev %d.%d, OTG rev %d.%d, %s receptacle\n",
+ INFO("OMAP UDC rev %d.%d%s\n",
UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
- OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
- config->otg ? "Mini-AB" : "B/Mini-B");
+ config->otg ? ", Mini-AB" : "");
/* use the mode given to us by board init code */
- hmc = HMC;
- switch (hmc) {
- case 3:
- case 11:
- case 19:
- case 25:
- xceiv = otg_get_transceiver();
- if (!xceiv) {
- DBG("external transceiver not registered!\n");
- goto cleanup0;
+ if (cpu_is_omap15xx()) {
+ hmc = HMC_1510;
+ type = "(unknown)";
+
+ if (machine_is_omap_innovator()) {
+ /* just set up software VBUS detect, and then
+ * later rig it so we always report VBUS.
+ * FIXME without really sensing VBUS, we can't
+ * know when to turn PULLUP_EN on/off; and that
+ * means we always "need" the 48MHz clock.
+ */
+ u32 tmp = FUNC_MUX_CTRL_0_REG;
+
+ FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
+ tmp |= VBUS_MODE_1510;
+ tmp &= ~VBUS_CTRL_1510;
+ FUNC_MUX_CTRL_0_REG = tmp;
}
- type = xceiv->label;
- break;
- case 0: /* POWERUP DEFAULT == 0 */
- case 4:
- case 12:
- case 20:
- type = "INTEGRATED";
- break;
- case 21: /* internal loopback */
- type = "(loopback)";
- break;
- case 14: /* transceiverless */
- type = "(none)";
- break;
+ } else {
+ hmc = HMC_1610;
+ switch (hmc) {
+ case 3:
+ case 11:
+ case 16:
+ case 19:
+ case 25:
+ xceiv = otg_get_transceiver();
+ if (!xceiv) {
+ DBG("external transceiver not registered!\n");
+ if (config->otg)
+ goto cleanup0;
+ type = "(unknown external)";
+ } else
+ type = xceiv->label;
+ break;
+ case 0: /* POWERUP DEFAULT == 0 */
+ case 4:
+ case 12:
+ case 20:
+ type = "INTEGRATED";
+ break;
+ case 21: /* internal loopback */
+ type = "(loopback)";
+ break;
+ case 14: /* transceiverless */
+ type = "(none)";
+ break;
- default:
- ERR("unrecognized UDC HMC mode %d\n", hmc);
- return -ENODEV;
+ default:
+ ERR("unrecognized UDC HMC mode %d\n", hmc);
+ return -ENODEV;
+ }
}
INFO("hmc mode %d, transceiver %s\n", hmc, type);
xceiv = 0;
// "udc" is now valid
pullup_disable(udc);
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
udc->gadget.is_otg = (config->otg != 0);
+#endif
/* USB general purpose IRQ: ep0, state changes, dma, etc */
status = request_irq(odev->resource[1].start, omap_udc_irq,
static int __init udc_init(void)
{
- /* should work on many OMAP systems with at most minor changes,
- * but the 1510 doesn't have an OTG controller.
- */
- if (cpu_is_omap1510()) {
- DBG("no OMAP1510 support yet\n");
- return -ENODEV;
- }
- INFO("%s, version: " DRIVER_VERSION "%s\n", driver_desc,
+ INFO("%s, version: " DRIVER_VERSION
+#ifdef USE_ISO
+ " (iso)"
+#endif
+ "%s\n", driver_desc,
use_dma ? " (dma)" : "");
return driver_register(&udc_driver);
}