#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
#define DRIVER_DESC "Inventra Dual-Role USB Controller Driver"
-#define MUSB_VERSION_BASE "2.2a/db-0.5.2"
+#define MUSB_VERSION_BASE "6.0"
#ifndef MUSB_VERSION_SUFFIX
#define MUSB_VERSION_SUFFIX ""
spin_lock_irqsave(&musb->lock, flags);
if (musb->xceiv.state == OTG_STATE_B_WAIT_ACON) {
- DBG(1, "HNP: B_WAIT_ACON timeout, going back to B_PERIPHERAL\n");
+ DBG(1, "HNP: B_WAIT_ACON timeout; back to B_PERIPHERAL\n");
musb_g_disconnect(musb);
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 0;
switch (musb->xceiv.state) {
case OTG_STATE_A_PERIPHERAL:
case OTG_STATE_A_WAIT_VFALL:
+ case OTG_STATE_A_WAIT_BCON:
DBG(1, "HNP: Switching back to A-host\n");
musb_g_disconnect(musb);
- musb_root_disconnect(musb);
musb->xceiv.state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
musb->is_active = 0;
break;
case OTG_STATE_B_HOST:
DBG(1, "HNP: Stopping in unknown state %s\n",
otg_state_string(musb));
}
+
+ /*
+ * When returning to A state after HNP, avoid hub_port_rebounce(),
+ * which cause occasional OPT A "Did not receive reset after connect"
+ * errors.
+ */
+ musb->port1_status &=
+ ~(1 << USB_PORT_FEAT_C_CONNECTION);
}
#endif
* not get a disconnect irq...
*/
if ((devctl & MUSB_DEVCTL_VBUS)
- != (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
+ != (3 << MUSB_DEVCTL_VBUS_SHIFT)
+ ) {
musb->int_usb |= MUSB_INTR_DISCONNECT;
musb->int_usb &= ~MUSB_INTR_SUSPEND;
break;
s = "<AValid"; break;
case 2 << MUSB_DEVCTL_VBUS_SHIFT:
s = "<VBusValid"; break;
- //case 3 << MUSB_DEVCTL_VBUS_SHIFT:
+ /* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */
default:
s = "VALID"; break;
}; s; }),
#ifdef CONFIG_USB_MUSB_OTG
/* flush endpoints when transitioning from Device Mode */
if (is_peripheral_active(musb)) {
- // REVISIT HNP; just force disconnect
+ /* REVISIT HNP; just force disconnect */
}
musb_writew(mbase, MUSB_INTRTXE, musb->epmask);
musb_writew(mbase, MUSB_INTRRXE, musb->epmask & 0xfffe);
switch (musb->xceiv.state) {
case OTG_STATE_B_PERIPHERAL:
if (int_usb & MUSB_INTR_SUSPEND) {
- DBG(1, "HNP: SUSPEND and CONNECT, now b_host\n");
+ DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
musb->xceiv.state = OTG_STATE_B_HOST;
hcd->self.is_b_host = 1;
int_usb &= ~MUSB_INTR_SUSPEND;
/*
* Looks like non-HS BABBLE can be ignored, but
* HS BABBLE is an error condition. For HS the solution
- * is to avoid babble in the first place and fix whatever
- * causes BABBLE. When HS BABBLE happens we can only stop
- * the session.
+ * is to avoid babble in the first place and fix what
+ * caused BABBLE. When HS BABBLE happens we can only
+ * stop the session.
*/
if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV))
DBG(1, "BABBLE devctl: %02x\n", devctl);
else {
- ERR("Stopping host session because of babble\n");
+ ERR("Stopping host session -- babble\n");
musb_writeb(mbase, MUSB_DEVCTL, 0);
}
} else if (is_peripheral_capable()) {
- DBG(1, "BUS RESET\n");
-
- musb_g_reset(musb);
+ DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_PERIPHERAL:
+ case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
+ musb_hnp_stop(musb);
+ break;
+ case OTG_STATE_B_IDLE:
+ musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ /* FALLTHROUGH */
+ case OTG_STATE_B_PERIPHERAL:
+ musb_g_reset(musb);
+ break;
+ default:
+ DBG(1, "Unhandled BUS RESET as %s\n",
+ otg_state_string(musb));
+ }
schedule_work(&musb->irq_work);
}
for (epnum = 1; (epnum < musb->nr_endpoints)
&& (musb->epmask >= (1 << epnum));
epnum++, ep++) {
- // FIXME handle framecounter wraps (12 bits)
- // eliminate duplicated StartUrb logic
+ /*
+ * FIXME handle framecounter wraps (12 bits)
+ * eliminate duplicated StartUrb logic
+ */
if (ep->dwWaitFrame >= frame) {
ep->dwWaitFrame = 0;
printk("SOF --> periodic TX%s on %d\n",
musb_hnp_stop(musb);
break;
case OTG_STATE_A_PERIPHERAL:
+ musb_hnp_stop(musb);
musb_root_disconnect(musb);
/* FALLTHROUGH */
case OTG_STATE_B_WAIT_ACON:
switch (musb->xceiv.state) {
#ifdef CONFIG_USB_MUSB_OTG
case OTG_STATE_A_PERIPHERAL:
- musb_hnp_stop(musb);
+ /*
+ * We cannot stop HNP here, devctl BDEVICE might be
+ * still set.
+ */
break;
#endif
case OTG_STATE_B_PERIPHERAL:
| MUSB_POWER_SOFTCONN
| MUSB_POWER_HSENAB
/* ENSUSPEND wedges tusb */
- // | MUSB_POWER_ENSUSPEND
+ /* | MUSB_POWER_ENSUSPEND */
);
musb->is_active = 0;
hw_ep->tx_double_buffered = hw_ep->rx_double_buffered;
hw_ep->max_packet_sz_tx = maxpacket;
- hw_ep->is_shared_fifo = TRUE;
+ hw_ep->is_shared_fifo = true;
break;
}
offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0);
- // assert(offset > 0)
+ /* assert(offset > 0) */
/* NOTE: for RTL versions >= 1.400 EPINFO and RAMINFO would
* be better than static MUSB_C_NUM_EPS and DYN_FIFO_SIZE...
/* shared TX/RX FIFO? */
if ((reg & 0xf0) == 0xf0) {
hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx;
- hw_ep->is_shared_fifo = TRUE;
+ hw_ep->is_shared_fifo = true;
continue;
} else {
hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4);
- hw_ep->is_shared_fifo = FALSE;
+ hw_ep->is_shared_fifo = false;
}
/* FIXME set up hw_ep->{rx,tx}_double_buffered */
if (reg & MUSB_CONFIGDATA_MPRXE) {
strcat(aInfo, ", bulk combine");
#ifdef C_MP_RX
- musb->bulk_combine = TRUE;
+ musb->bulk_combine = true;
#else
strcat(aInfo, " (X)"); /* no driver support */
#endif
if (reg & MUSB_CONFIGDATA_MPTXE) {
strcat(aInfo, ", bulk split");
#ifdef C_MP_TX
- musb->bulk_split = TRUE;
+ musb->bulk_split = true;
#else
strcat(aInfo, " (X)"); /* no driver support */
#endif
ep_num = 1;
while (reg) {
if (reg & 1) {
- // musb_ep_select(musb->mregs, ep_num);
+ /* musb_ep_select(musb->mregs, ep_num); */
/* REVISIT just retval = ep->rx_irq(...) */
retval = IRQ_HANDLED;
if (devctl & MUSB_DEVCTL_HM) {
ep_num = 1;
while (reg) {
if (reg & 1) {
- // musb_ep_select(musb->mregs, ep_num);
+ /* musb_ep_select(musb->mregs, ep_num); */
/* REVISIT just retval |= ep->tx_irq(...) */
retval = IRQ_HANDLED;
if (devctl & MUSB_DEVCTL_HM) {
unsigned long flags;
unsigned long val;
- spin_lock_irqsave(&musb->lock, flags);
if (sscanf(buf, "%lu", &val) < 1) {
printk(KERN_ERR "Invalid VBUS timeout ms value\n");
return -EINVAL;
}
+
+ spin_lock_irqsave(&musb->lock, flags);
musb->a_wait_bcon = val;
if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON)
musb->is_active = 0;
#endif /* sysfs */
-/* Only used to provide cable state change events */
+/* Only used to provide driver mode change events */
static void musb_irq_work(struct work_struct *data)
{
struct musb *musb = container_of(data, struct musb, irq_work);
+ static int old_state;
- sysfs_notify(&musb->controller->kobj, NULL, "cable");
+ if (musb->xceiv.state != old_state) {
+ old_state = musb->xceiv.state;
+ sysfs_notify(&musb->controller->kobj, NULL, "cable");
+ sysfs_notify(&musb->controller->kobj, NULL, "mode");
+ }
}
/* --------------------------------------------------------------------------
ep->epnum = epnum;
}
+#ifdef CONFIG_USB_MUSB_OTG
+ otg_set_transceiver(&musb->xceiv);
+#endif
musb->controller = dev;
return musb;
}
clk_put(musb->clock);
}
+#ifdef CONFIG_USB_MUSB_OTG
+ put_device(musb->xceiv.dev);
+#endif
+
#ifdef CONFIG_USB_MUSB_HDRC_HCD
usb_put_hcd(musb_to_hcd(musb));
#else
goto fail2;
}
musb->nIrq = nIrq;
-// FIXME this handles wakeup irqs wrong
+/* FIXME this handles wakeup irqs wrong */
if (enable_irq_wake(nIrq) == 0)
device_init_wakeup(dev, 1);