diff options
Diffstat (limited to 'drivers/usb/musb/musb_core.c')
| -rw-r--r-- | drivers/usb/musb/musb_core.c | 551 |
1 files changed, 278 insertions, 273 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index bb56a0e8b23..eff3c5cf84f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -83,7 +83,7 @@ * This gets many kinds of configuration information: * - Kconfig for everything user-configurable * - platform_device for addressing, irq, and platform_data - * - platform_data is mostly for board-specific informarion + * - platform_data is mostly for board-specific information * (plus recentrly, SOC or family details) * * Most of the conditional compilation will (someday) vanish. @@ -93,13 +93,11 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/list.h> #include <linux/kobject.h> #include <linux/prefetch.h> #include <linux/platform_device.h> #include <linux/io.h> -#include <linux/idr.h> #include <linux/dma-mapping.h> #include "musb_core.h" @@ -116,7 +114,6 @@ #define MUSB_DRIVER_NAME "musb-hdrc" const char musb_driver_name[] = MUSB_DRIVER_NAME; -static DEFINE_IDA(musb_ida); MODULE_DESCRIPTION(DRIVER_INFO); MODULE_AUTHOR(DRIVER_AUTHOR); @@ -133,35 +130,6 @@ static inline struct musb *dev_to_musb(struct device *dev) /*-------------------------------------------------------------------------*/ -int musb_get_id(struct device *dev, gfp_t gfp_mask) -{ - int ret; - int id; - - ret = ida_pre_get(&musb_ida, gfp_mask); - if (!ret) { - dev_err(dev, "failed to reserve resource for id\n"); - return -ENOMEM; - } - - ret = ida_get_new(&musb_ida, &id); - if (ret < 0) { - dev_err(dev, "failed to allocate a new id\n"); - return ret; - } - - return id; -} -EXPORT_SYMBOL_GPL(musb_get_id); - -void musb_put_id(struct device *dev, int id) -{ - - dev_dbg(dev, "removing id %d\n", id); - ida_remove(&musb_ida, id); -} -EXPORT_SYMBOL_GPL(musb_put_id); - #ifndef CONFIG_BLACKFIN static int musb_ulpi_read(struct usb_phy *phy, u32 offset) { @@ -281,7 +249,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) /* best case is 32bit-aligned source address */ if ((0x02 & (unsigned long) src) == 0) { if (len >= 4) { - writesl(fifo, src + index, len >> 2); + iowrite32_rep(fifo, src + index, len >> 2); index += len & ~0x03; } if (len & 0x02) { @@ -290,7 +258,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) } } else { if (len >= 2) { - writesw(fifo, src + index, len >> 1); + iowrite16_rep(fifo, src + index, len >> 1); index += len & ~0x01; } } @@ -298,7 +266,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) musb_writeb(fifo, 0, src[index]); } else { /* byte aligned */ - writesb(fifo, src, len); + iowrite8_rep(fifo, src, len); } } @@ -324,7 +292,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) /* best case is 32bit-aligned destination address */ if ((0x02 & (unsigned long) dst) == 0) { if (len >= 4) { - readsl(fifo, dst, len >> 2); + ioread32_rep(fifo, dst, len >> 2); index = len & ~0x03; } if (len & 0x02) { @@ -333,7 +301,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) } } else { if (len >= 2) { - readsw(fifo, dst, len >> 1); + ioread16_rep(fifo, dst, len >> 1); index = len & ~0x01; } } @@ -341,7 +309,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) dst[index] = musb_readb(fifo, 0); } else { /* byte aligned */ - readsb(fifo, dst, len); + ioread8_rep(fifo, dst, len); } } #endif @@ -402,15 +370,14 @@ static void musb_otg_timer_func(unsigned long data) case OTG_STATE_A_SUSPEND: case OTG_STATE_A_WAIT_BCON: dev_dbg(musb->controller, "HNP: %s timeout\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); musb_platform_set_vbus(musb, 0); musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; break; default: dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } - musb->ignore_disconnect = 0; spin_unlock_irqrestore(&musb->lock, flags); } @@ -419,21 +386,23 @@ static void musb_otg_timer_func(unsigned long data) */ void musb_hnp_stop(struct musb *musb) { - struct usb_hcd *hcd = musb_to_hcd(musb); + struct usb_hcd *hcd = musb->hcd; void __iomem *mbase = musb->mregs; u8 reg; - dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state)); + dev_dbg(musb->controller, "HNP: stop from %s\n", + usb_otg_state_string(musb->xceiv->state)); switch (musb->xceiv->state) { case OTG_STATE_A_PERIPHERAL: musb_g_disconnect(musb); dev_dbg(musb->controller, "HNP: back to %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); break; case OTG_STATE_B_HOST: dev_dbg(musb->controller, "HNP: Disabling HR\n"); - hcd->self.is_b_host = 0; + if (hcd) + hcd->self.is_b_host = 0; musb->xceiv->state = OTG_STATE_B_PERIPHERAL; MUSB_DEV_MODE(musb); reg = musb_readb(mbase, MUSB_POWER); @@ -443,7 +412,7 @@ void musb_hnp_stop(struct musb *musb) break; default: dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } /* @@ -467,12 +436,11 @@ void musb_hnp_stop(struct musb *musb) */ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, - u8 devctl, u8 power) + u8 devctl) { - struct usb_otg *otg = musb->xceiv->otg; irqreturn_t handled = IRQ_NONE; - dev_dbg(musb->controller, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl, + dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl, int_usb); /* in host mode, the peripheral may issue remote wakeup. @@ -481,10 +449,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, */ if (int_usb & MUSB_INTR_RESUME) { handled = IRQ_HANDLED; - dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state)); + dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state)); if (devctl & MUSB_DEVCTL_HM) { void __iomem *mbase = musb->mregs; + u8 power; switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: @@ -492,6 +461,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, * will stop RESUME signaling */ + power = musb_readb(musb->mregs, MUSB_POWER); if (power & MUSB_POWER_SUSPENDM) { /* spurious */ musb->int_usb &= ~MUSB_INTR_SUSPEND; @@ -507,11 +477,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, (USB_PORT_STAT_C_SUSPEND << 16) | MUSB_PORT_STAT_RESUME; musb->rh_timer = jiffies - + msecs_to_jiffies(20); + + msecs_to_jiffies(20); + schedule_delayed_work( + &musb->finish_resume_work, + msecs_to_jiffies(20)); musb->xceiv->state = OTG_STATE_A_HOST; musb->is_active = 1; - usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_host_resume_root_hub(musb); break; case OTG_STATE_B_WAIT_ACON: musb->xceiv->state = OTG_STATE_B_PERIPHERAL; @@ -521,14 +494,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, default: WARNING("bogus %s RESUME (%s)\n", "host", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } else { switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: /* possibly DISCONNECT is upcoming */ musb->xceiv->state = OTG_STATE_A_HOST; - usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_host_resume_root_hub(musb); break; case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_PERIPHERAL: @@ -550,7 +523,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, default: WARNING("bogus %s RESUME (%s)\n", "peripheral", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } } @@ -566,7 +539,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); /* IRQ arrives from ID pin sense or (later, if VBUS power * is removed) SRP. responses are time critical: @@ -630,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; } - dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", - otg_state_string(musb->xceiv->state), + dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller, + "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", + usb_otg_state_string(musb->xceiv->state), devctl, ({ char *s; switch (devctl & MUSB_DEVCTL_VBUS) { @@ -644,7 +618,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, /* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */ default: s = "VALID"; break; - }; s; }), + } s; }), VBUSERR_RETRY_COUNT - musb->vbuserr_retry, musb->port1_status); @@ -655,8 +629,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } if (int_usb & MUSB_INTR_SUSPEND) { - dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x power %02x\n", - otg_state_string(musb->xceiv->state), devctl, power); + dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", + usb_otg_state_string(musb->xceiv->state), devctl); handled = IRQ_HANDLED; switch (musb->xceiv->state) { @@ -669,7 +643,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, * undesired detour through A_WAIT_BCON. */ musb_hnp_stop(musb); - usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_host_resume_root_hub(musb); musb_root_disconnect(musb); musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(musb->a_wait_bcon @@ -681,7 +655,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; case OTG_STATE_B_PERIPHERAL: musb_g_suspend(musb); - musb->is_active = otg->gadget->b_hnp_enable; + musb->is_active = musb->g.b_hnp_enable; if (musb->is_active) { musb->xceiv->state = OTG_STATE_B_WAIT_ACON; dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); @@ -697,7 +671,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; case OTG_STATE_A_HOST: musb->xceiv->state = OTG_STATE_A_SUSPEND; - musb->is_active = otg->host->b_hnp_enable; + musb->is_active = musb->hcd->self.b_hnp_enable; break; case OTG_STATE_B_HOST: /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ @@ -711,7 +685,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } if (int_usb & MUSB_INTR_CONNECT) { - struct usb_hcd *hcd = musb_to_hcd(musb); + struct usb_hcd *hcd = musb->hcd; handled = IRQ_HANDLED; musb->is_active = 1; @@ -722,8 +696,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (is_peripheral_active(musb)) { /* REVISIT HNP; just force disconnect */ } - musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask); - musb_writew(musb->mregs, MUSB_INTRRXE, musb->epmask & 0xfffe); + musb->intrtxe = musb->epmask; + musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe); + musb->intrrxe = musb->epmask & 0xfffe; + musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7); musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED |USB_PORT_STAT_HIGH_SPEED @@ -750,40 +726,36 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n"); b_host: musb->xceiv->state = OTG_STATE_B_HOST; - hcd->self.is_b_host = 1; - musb->ignore_disconnect = 0; + if (musb->hcd) + musb->hcd->self.is_b_host = 1; del_timer(&musb->otg_timer); break; default: if ((devctl & MUSB_DEVCTL_VBUS) == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { musb->xceiv->state = OTG_STATE_A_HOST; - hcd->self.is_b_host = 0; + if (hcd) + hcd->self.is_b_host = 0; } break; } - /* poke the root hub */ - MUSB_HST_MODE(musb); - if (hcd->status_urb) - usb_hcd_poll_rh_status(hcd); - else - usb_hcd_resume_root_hub(hcd); + musb_host_poke_root_hub(musb); dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", - otg_state_string(musb->xceiv->state), devctl); + usb_otg_state_string(musb->xceiv->state), devctl); } - if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) { + if (int_usb & MUSB_INTR_DISCONNECT) { dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), MUSB_MODE(musb), devctl); handled = IRQ_HANDLED; switch (musb->xceiv->state) { case OTG_STATE_A_HOST: case OTG_STATE_A_SUSPEND: - usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_host_resume_root_hub(musb); musb_root_disconnect(musb); if (musb->a_wait_bcon != 0) musb_platform_try_idle(musb, jiffies @@ -796,7 +768,8 @@ b_host: * in hnp_stop() is currently not used... */ musb_root_disconnect(musb); - musb_to_hcd(musb)->self.is_b_host = 0; + if (musb->hcd) + musb->hcd->self.is_b_host = 0; musb->xceiv->state = OTG_STATE_B_PERIPHERAL; MUSB_DEV_MODE(musb); musb_g_disconnect(musb); @@ -813,7 +786,7 @@ b_host: break; default: WARNING("unhandled DISCONNECT transition (%s)\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); break; } } @@ -839,32 +812,26 @@ b_host: } } else { dev_dbg(musb->controller, "BUS RESET as %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: - /* We need to ignore disconnect on suspend - * otherwise tusb 2.0 won't reconnect after a - * power cycle, which breaks otg compliance. - */ - musb->ignore_disconnect = 1; musb_g_reset(musb); /* FALLTHROUGH */ case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ /* never use invalid T(a_wait_bcon) */ dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), TA_WAIT_BCON(musb)); mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies(TA_WAIT_BCON(musb))); break; case OTG_STATE_A_PERIPHERAL: - musb->ignore_disconnect = 0; del_timer(&musb->otg_timer); musb_g_reset(musb); break; case OTG_STATE_B_WAIT_ACON: dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb_g_reset(musb); break; @@ -876,11 +843,15 @@ b_host: break; default: dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } } + /* handle babble condition */ + if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) + schedule_work(&musb->recover_work); + #if 0 /* REVISIT ... this would be for multiplexing periodic endpoints, or * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -933,29 +904,53 @@ b_host: /*-------------------------------------------------------------------------*/ +static void musb_generic_disable(struct musb *musb) +{ + void __iomem *mbase = musb->mregs; + u16 temp; + + /* disable interrupts */ + musb_writeb(mbase, MUSB_INTRUSBE, 0); + musb->intrtxe = 0; + musb_writew(mbase, MUSB_INTRTXE, 0); + musb->intrrxe = 0; + musb_writew(mbase, MUSB_INTRRXE, 0); + + /* off */ + musb_writeb(mbase, MUSB_DEVCTL, 0); + + /* flush pending interrupts */ + temp = musb_readb(mbase, MUSB_INTRUSB); + temp = musb_readw(mbase, MUSB_INTRTX); + temp = musb_readw(mbase, MUSB_INTRRX); + +} + /* -* Program the HDRC to start (enable interrupts, dma, etc.). -*/ + * Program the HDRC to start (enable interrupts, dma, etc.). + */ void musb_start(struct musb *musb) { - void __iomem *regs = musb->mregs; - u8 devctl = musb_readb(regs, MUSB_DEVCTL); + void __iomem *regs = musb->mregs; + u8 devctl = musb_readb(regs, MUSB_DEVCTL); dev_dbg(musb->controller, "<== devctl %02x\n", devctl); /* Set INT enable registers, enable interrupts */ - musb_writew(regs, MUSB_INTRTXE, musb->epmask); - musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe); + musb->intrtxe = musb->epmask; + musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); + musb->intrrxe = musb->epmask & 0xfffe; + musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); musb_writeb(regs, MUSB_INTRUSBE, 0xf7); musb_writeb(regs, MUSB_TESTMODE, 0); /* put into basic highspeed mode and start session */ musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE - | MUSB_POWER_HSENAB - /* ENSUSPEND wedges tusb */ - /* | MUSB_POWER_ENSUSPEND */ - ); + | MUSB_POWER_HSENAB + /* ENSUSPEND wedges tusb */ + /* | MUSB_POWER_ENSUSPEND */ + ); musb->is_active = 0; devctl = musb_readb(regs, MUSB_DEVCTL); @@ -966,36 +961,17 @@ void musb_start(struct musb *musb) * (b) vbus present/connect IRQ, peripheral mode; * (c) peripheral initiates, using SRP */ - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) + if (musb->port_mode != MUSB_PORT_MODE_HOST && + (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { musb->is_active = 1; - else + } else { devctl |= MUSB_DEVCTL_SESSION; + } musb_platform_enable(musb); musb_writeb(regs, MUSB_DEVCTL, devctl); } - -static void musb_generic_disable(struct musb *musb) -{ - void __iomem *mbase = musb->mregs; - u16 temp; - - /* disable interrupts */ - musb_writeb(mbase, MUSB_INTRUSBE, 0); - musb_writew(mbase, MUSB_INTRTXE, 0); - musb_writew(mbase, MUSB_INTRRXE, 0); - - /* off */ - musb_writeb(mbase, MUSB_DEVCTL, 0); - - /* flush pending interrupts */ - temp = musb_readb(mbase, MUSB_INTRUSB); - temp = musb_readw(mbase, MUSB_INTRTX); - temp = musb_readw(mbase, MUSB_INTRRX); - -} - /* * Make the HDRC stop (disable interrupts, etc.); * reversible by musb_start @@ -1027,6 +1003,7 @@ static void musb_shutdown(struct platform_device *pdev) pm_runtime_get_sync(musb->controller); + musb_host_cleanup(musb); musb_gadget_cleanup(musb); spin_lock_irqsave(&musb->lock, flags); @@ -1062,12 +1039,12 @@ static void musb_shutdown(struct platform_device *pdev) || defined(CONFIG_USB_MUSB_AM35X_MODULE) \ || defined(CONFIG_USB_MUSB_DSPS) \ || defined(CONFIG_USB_MUSB_DSPS_MODULE) -static ushort __devinitdata fifo_mode = 4; +static ushort fifo_mode = 4; #elif defined(CONFIG_USB_MUSB_UX500) \ || defined(CONFIG_USB_MUSB_UX500_MODULE) -static ushort __devinitdata fifo_mode = 5; +static ushort fifo_mode = 5; #else -static ushort __devinitdata fifo_mode = 2; +static ushort fifo_mode = 2; #endif /* "modprobe ... fifo_mode=1" etc */ @@ -1080,7 +1057,7 @@ MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration"); */ /* mode 0 - fits in 2KB */ -static struct musb_fifo_cfg __devinitdata mode_0_cfg[] = { +static struct musb_fifo_cfg mode_0_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, }, @@ -1089,7 +1066,7 @@ static struct musb_fifo_cfg __devinitdata mode_0_cfg[] = { }; /* mode 1 - fits in 4KB */ -static struct musb_fifo_cfg __devinitdata mode_1_cfg[] = { +static struct musb_fifo_cfg mode_1_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, }, @@ -1098,7 +1075,7 @@ static struct musb_fifo_cfg __devinitdata mode_1_cfg[] = { }; /* mode 2 - fits in 4KB */ -static struct musb_fifo_cfg __devinitdata mode_2_cfg[] = { +static struct musb_fifo_cfg mode_2_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, @@ -1108,7 +1085,7 @@ static struct musb_fifo_cfg __devinitdata mode_2_cfg[] = { }; /* mode 3 - fits in 4KB */ -static struct musb_fifo_cfg __devinitdata mode_3_cfg[] = { +static struct musb_fifo_cfg mode_3_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, @@ -1118,7 +1095,7 @@ static struct musb_fifo_cfg __devinitdata mode_3_cfg[] = { }; /* mode 4 - fits in 16KB */ -static struct musb_fifo_cfg __devinitdata mode_4_cfg[] = { +static struct musb_fifo_cfg mode_4_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, @@ -1149,7 +1126,7 @@ static struct musb_fifo_cfg __devinitdata mode_4_cfg[] = { }; /* mode 5 - fits in 8KB */ -static struct musb_fifo_cfg __devinitdata mode_5_cfg[] = { +static struct musb_fifo_cfg mode_5_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, @@ -1185,7 +1162,7 @@ static struct musb_fifo_cfg __devinitdata mode_5_cfg[] = { * * returns negative errno or offset for next fifo. */ -static int __devinit +static int fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, const struct musb_fifo_cfg *cfg, u16 offset) { @@ -1215,7 +1192,7 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum); /* EP0 reserved endpoint for control, bidirectional; - * EP1 reserved for bulk, two unidirection halves. + * EP1 reserved for bulk, two unidirectional halves. */ if (hw_ep->epnum == 1) musb->bulk_ep = hw_ep; @@ -1256,11 +1233,11 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0)); } -static struct musb_fifo_cfg __devinitdata ep0_cfg = { +static struct musb_fifo_cfg ep0_cfg = { .style = FIFO_RXTX, .maxpacket = 64, }; -static int __devinit ep_config_from_table(struct musb *musb) +static int ep_config_from_table(struct musb *musb) { const struct musb_fifo_cfg *cfg; unsigned i, n; @@ -1351,7 +1328,7 @@ done: * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false * @param musb the controller */ -static int __devinit ep_config_from_hw(struct musb *musb) +static int ep_config_from_hw(struct musb *musb) { u8 epnum = 0; struct musb_hw_ep *hw_ep; @@ -1398,7 +1375,7 @@ enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, }; /* Initialize MUSB (M)HDRC part of the USB hardware subsystem; * configure endpoints, or take their config from silicon */ -static int __devinit musb_core_init(u16 musb_type, struct musb *musb) +static int musb_core_init(u16 musb_type, struct musb *musb) { u8 reg; char *type; @@ -1523,33 +1500,6 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb) /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \ - defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) - -static irqreturn_t generic_interrupt(int irq, void *__hci) -{ - unsigned long flags; - irqreturn_t retval = IRQ_NONE; - struct musb *musb = __hci; - - spin_lock_irqsave(&musb->lock, flags); - - musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); - musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); - musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - - if (musb->int_usb || musb->int_tx || musb->int_rx) - retval = musb_interrupt(musb); - - spin_unlock_irqrestore(&musb->lock, flags); - - return retval; -} - -#else -#define generic_interrupt NULL -#endif - /* * handle all the irqs defined by the HDRC core. for now we expect: other * irq sources (phy, dma, etc) will be handled first, musb->int_* values @@ -1560,12 +1510,11 @@ static irqreturn_t generic_interrupt(int irq, void *__hci) irqreturn_t musb_interrupt(struct musb *musb) { irqreturn_t retval = IRQ_NONE; - u8 devctl, power; + u8 devctl; int ep_num; u32 reg; devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - power = musb_readb(musb->mregs, MUSB_POWER); dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n", (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", @@ -1576,7 +1525,7 @@ irqreturn_t musb_interrupt(struct musb *musb) */ if (musb->int_usb) retval |= musb_stage0_irq(musb, musb->int_usb, - devctl, power); + devctl); /* "stage 1" is handling endpoint irqs */ @@ -1628,7 +1577,7 @@ irqreturn_t musb_interrupt(struct musb *musb) EXPORT_SYMBOL_GPL(musb_interrupt); #ifndef CONFIG_MUSB_PIO_ONLY -static bool __devinitdata use_dma = 1; +static bool use_dma = 1; /* "modprobe ... use_dma=0" etc */ module_param(use_dma, bool, 0); @@ -1674,8 +1623,6 @@ EXPORT_SYMBOL_GPL(musb_dma_completion); /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_SYSFS - static ssize_t musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1684,7 +1631,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) int ret = -EINVAL; spin_lock_irqsave(&musb->lock, flags); - ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state)); + ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state)); spin_unlock_irqrestore(&musb->lock, flags); return ret; @@ -1792,8 +1739,6 @@ static const struct attribute_group musb_attr_group = { .attrs = musb_attributes, }; -#endif /* sysfs */ - /* Only used to provide driver mode change events */ static void musb_irq_work(struct work_struct *data) { @@ -1805,35 +1750,56 @@ static void musb_irq_work(struct work_struct *data) } } +/* Recover from babble interrupt conditions */ +static void musb_recover_work(struct work_struct *data) +{ + struct musb *musb = container_of(data, struct musb, recover_work); + int status; + + musb_platform_reset(musb); + + usb_phy_vbus_off(musb->xceiv); + udelay(100); + + usb_phy_vbus_on(musb->xceiv); + udelay(100); + + /* + * When a babble condition occurs, the musb controller removes the + * session bit and the endpoint config is lost. + */ + if (musb->dyn_fifo) + status = ep_config_from_table(musb); + else + status = ep_config_from_hw(musb); + + /* start the session again */ + if (status == 0) + musb_start(musb); +} + /* -------------------------------------------------------------------------- * Init support */ -static struct musb *__devinit -allocate_instance(struct device *dev, +static struct musb *allocate_instance(struct device *dev, struct musb_hdrc_config *config, void __iomem *mbase) { struct musb *musb; struct musb_hw_ep *ep; int epnum; - struct usb_hcd *hcd; + int ret; - hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev)); - if (!hcd) + musb = devm_kzalloc(dev, sizeof(*musb), GFP_KERNEL); + if (!musb) return NULL; - /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ - musb = hcd_to_musb(hcd); INIT_LIST_HEAD(&musb->control); INIT_LIST_HEAD(&musb->in_bulk); INIT_LIST_HEAD(&musb->out_bulk); - hcd->uses_new_polling = 1; - hcd->has_tt = 1; - musb->vbuserr_retry = VBUSERR_RETRY_COUNT; musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON; - dev_set_drvdata(dev, musb); musb->mregs = mbase; musb->ctrl_base = mbase; musb->nIrq = -ENODEV; @@ -1848,7 +1814,16 @@ allocate_instance(struct device *dev, musb->controller = dev; + ret = musb_host_alloc(musb); + if (ret < 0) + goto err_free; + + dev_set_drvdata(dev, musb); + return musb; + +err_free: + return NULL; } static void musb_free(struct musb *musb) @@ -1867,14 +1842,23 @@ static void musb_free(struct musb *musb) disable_irq_wake(musb->nIrq); free_irq(musb->nIrq, musb); } - if (is_dma_capable() && musb->dma_controller) { - struct dma_controller *c = musb->dma_controller; - (void) c->stop(c); - dma_controller_destroy(c); - } + musb_host_free(musb); +} - usb_put_hcd(musb_to_hcd(musb)); +static void musb_deassert_reset(struct work_struct *work) +{ + struct musb *musb; + unsigned long flags; + + musb = container_of(work, struct musb, deassert_reset_work.work); + + spin_lock_irqsave(&musb->lock, flags); + + if (musb->port1_status & USB_PORT_STAT_RESET) + musb_port_reset(musb, false); + + spin_unlock_irqrestore(&musb->lock, flags); } /* @@ -1885,13 +1869,12 @@ static void musb_free(struct musb *musb) * @ctrl: virtual address of controller registers, * not yet corrected for platform-specific offsets */ -static int __devinit +static int musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) { int status; struct musb *musb; - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct usb_hcd *hcd; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); /* The driver might handle more features than the board; OK. * Fail when the board needs a feature that's not enabled. @@ -1917,10 +1900,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb->board_set_power = plat->set_power; musb->min_power = plat->min_power; musb->ops = plat->platform_ops; + musb->port_mode = plat->mode; /* The musb_platform_init() call: - * - adjusts musb->mregs and musb->isr if needed, - * - may initialize an integrated tranceiver + * - adjusts musb->mregs + * - sets the musb->isr + * - may initialize an integrated transceiver * - initializes musb->xceiv, usually by otg_get_phy() * - stops powering VBUS * @@ -1929,7 +1914,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) * external/discrete ones in various flavors (twl4030 family, * isp1504, non-OTG, etc) mostly hooking up through ULPI. */ - musb->isr = generic_interrupt; status = musb_platform_init(musb); if (status < 0) goto fail1; @@ -1947,24 +1931,24 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_get_sync(musb->controller); -#ifndef CONFIG_MUSB_PIO_ONLY if (use_dma && dev->dma_mask) { - struct dma_controller *c; - - c = dma_controller_create(musb, musb->mregs); - musb->dma_controller = c; - if (c) - (void) c->start(c); + musb->dma_controller = dma_controller_create(musb, musb->mregs); + if (IS_ERR(musb->dma_controller)) { + status = PTR_ERR(musb->dma_controller); + goto fail2_5; + } } -#endif - /* ideally this would be abstracted in platform setup */ - if (!is_dma_capable() || !musb->dma_controller) - dev->dma_mask = NULL; /* be sure interrupts are disabled before connecting ISR */ musb_platform_disable(musb); musb_generic_disable(musb); + /* Init IRQ workqueue before request_irq */ + INIT_WORK(&musb->irq_work, musb_irq_work); + INIT_WORK(&musb->recover_work, musb_recover_work); + INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); + INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); + /* setup musb parts of the core (especially endpoints) */ status = musb_core_init(plat->config->multipoint ? MUSB_CONTROLLER_MHDRC @@ -1974,9 +1958,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); - /* Init IRQ workqueue before request_irq */ - INIT_WORK(&musb->irq_work, musb_irq_work); - /* attach to the IRQ */ if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) { dev_err(dev, "request_irq %d failed!\n", nIrq); @@ -1992,13 +1973,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb->irq_wake = 0; } - /* host side needs more setup */ - hcd = musb_to_hcd(musb); - otg_set_host(musb->xceiv->otg, &hcd->self); - hcd->self.otg_port = 1; - musb->xceiv->otg->host = &hcd->self; - hcd->power_budget = 2 * (plat->power ? : 250); - /* program PHY to use external vBus if required */ if (plat->extvbus) { u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); @@ -2006,11 +1980,42 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb_write_ulpi_buscontrol(musb->mregs, busctl); } - MUSB_DEV_MODE(musb); - musb->xceiv->otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + if (musb->xceiv->otg->default_a) { + MUSB_HST_MODE(musb); + musb->xceiv->state = OTG_STATE_A_IDLE; + } else { + MUSB_DEV_MODE(musb); + musb->xceiv->state = OTG_STATE_B_IDLE; + } - status = musb_gadget_setup(musb); + switch (musb->port_mode) { + case MUSB_PORT_MODE_HOST: + status = musb_host_setup(musb, plat->power); + if (status < 0) + goto fail3; + status = musb_platform_set_mode(musb, MUSB_HOST); + break; + case MUSB_PORT_MODE_GADGET: + status = musb_gadget_setup(musb); + if (status < 0) + goto fail3; + status = musb_platform_set_mode(musb, MUSB_PERIPHERAL); + break; + case MUSB_PORT_MODE_DUAL_ROLE: + status = musb_host_setup(musb, plat->power); + if (status < 0) + goto fail3; + status = musb_gadget_setup(musb); + if (status) { + musb_host_cleanup(musb); + goto fail3; + } + status = musb_platform_set_mode(musb, MUSB_OTG); + break; + default: + dev_err(dev, "unsupported port mode %d\n", musb->port_mode); + break; + } if (status < 0) goto fail3; @@ -2019,11 +2024,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (status < 0) goto fail4; -#ifdef CONFIG_SYSFS status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group); if (status) goto fail5; -#endif pm_runtime_put(musb->controller); @@ -2034,8 +2037,16 @@ fail5: fail4: musb_gadget_cleanup(musb); + musb_host_cleanup(musb); fail3: + cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); + cancel_delayed_work_sync(&musb->finish_resume_work); + cancel_delayed_work_sync(&musb->deassert_reset_work); + if (musb->dma_controller) + dma_controller_destroy(musb->dma_controller); +fail2_5: pm_runtime_put_sync(musb->controller); fail2: @@ -2044,6 +2055,7 @@ fail2: musb_platform_exit(musb); fail1: + pm_runtime_disable(musb->controller); dev_err(musb->controller, "musb_init_controller failed with status %d\n", status); @@ -2060,11 +2072,10 @@ fail0: /* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just * bridge to a platform device; this driver then suffices. */ -static int __devinit musb_probe(struct platform_device *pdev) +static int musb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int irq = platform_get_irq_byname(pdev, "mc"); - int status; struct resource *iomem; void __iomem *base; @@ -2072,24 +2083,17 @@ static int __devinit musb_probe(struct platform_device *pdev) if (!iomem || irq <= 0) return -ENODEV; - base = ioremap(iomem->start, resource_size(iomem)); - if (!base) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } + base = devm_ioremap_resource(dev, iomem); + if (IS_ERR(base)) + return PTR_ERR(base); - status = musb_init_controller(dev, irq, base); - if (status < 0) - iounmap(base); - - return status; + return musb_init_controller(dev, irq, base); } -static int __devexit musb_remove(struct platform_device *pdev) +static int musb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct musb *musb = dev_to_musb(dev); - void __iomem *ctrl_base = musb->ctrl_base; /* this gets called on rmmod. * - Host mode: host may still be active @@ -2099,12 +2103,15 @@ static int __devexit musb_remove(struct platform_device *pdev) musb_exit_debugfs(musb); musb_shutdown(pdev); + if (musb->dma_controller) + dma_controller_destroy(musb->dma_controller); + + cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); + cancel_delayed_work_sync(&musb->finish_resume_work); + cancel_delayed_work_sync(&musb->deassert_reset_work); musb_free(musb); - iounmap(ctrl_base); device_init_wakeup(dev, 0); -#ifndef CONFIG_MUSB_PIO_ONLY - dma_set_mask(dev, *dev->parent->dma_mask); -#endif return 0; } @@ -2120,8 +2127,6 @@ static void musb_save_context(struct musb *musb) musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); musb->context.power = musb_readb(musb_base, MUSB_POWER); - musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); - musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); musb->context.index = musb_readb(musb_base, MUSB_INDEX); musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL); @@ -2189,13 +2194,21 @@ static void musb_restore_context(struct musb *musb) void __iomem *musb_base = musb->mregs; void __iomem *ep_target_regs; void __iomem *epio; + u8 power; musb_writew(musb_base, MUSB_FRAME, musb->context.frame); musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); - musb_writeb(musb_base, MUSB_POWER, musb->context.power); - musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe); - musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe); + + /* Don't affect SUSPENDM/RESUME bits in POWER reg */ + power = musb_readb(musb_base, MUSB_POWER); + power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME; + musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); + power |= musb->context.power; + musb_writeb(musb_base, MUSB_POWER, power); + + musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); + musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); @@ -2277,16 +2290,28 @@ static int musb_suspend(struct device *dev) */ } + musb_save_context(musb); + spin_unlock_irqrestore(&musb->lock, flags); return 0; } static int musb_resume_noirq(struct device *dev) { - /* for static cmos like DaVinci, register values were preserved + struct musb *musb = dev_to_musb(dev); + + /* + * For static cmos like DaVinci, register values were preserved * unless for some reason the whole soc powered down or the USB * module got reset through the PSC (vs just being disabled). + * + * For the DSPS glue layer though, a full register restore has to + * be done. As it shouldn't harm other platforms, we do it + * unconditionally. */ + + musb_restore_context(musb); + return 0; } @@ -2340,28 +2365,8 @@ static struct platform_driver musb_driver = { .pm = MUSB_DEV_PM_OPS, }, .probe = musb_probe, - .remove = __devexit_p(musb_remove), + .remove = musb_remove, .shutdown = musb_shutdown, }; -/*-------------------------------------------------------------------------*/ - -static int __init musb_init(void) -{ - if (usb_disabled()) - return 0; - - pr_info("%s: version " MUSB_VERSION ", " - "?dma?" - ", " - "otg (peripheral+host)", - musb_driver_name); - return platform_driver_register(&musb_driver); -} -module_init(musb_init); - -static void __exit musb_cleanup(void) -{ - platform_driver_unregister(&musb_driver); -} -module_exit(musb_cleanup); +module_platform_driver(musb_driver); |
