diff options
Diffstat (limited to 'drivers/usb/musb/musb_core.c')
-rw-r--r-- | drivers/usb/musb/musb_core.c | 331 |
1 files changed, 140 insertions, 191 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 26f1befb4896..bb56a0e8b23b 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -99,6 +99,8 @@ #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" @@ -114,6 +116,7 @@ #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); @@ -130,6 +133,35 @@ 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) { @@ -234,6 +266,9 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; + if (unlikely(len == 0)) + return; + prefetch((u8 *)src); dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", @@ -276,6 +311,9 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; + if (unlikely(len == 0)) + return; + dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", 'R', hw_ep->epnum, fifo, len, dst); @@ -348,7 +386,7 @@ void musb_load_testpacket(struct musb *musb) /* * Handles OTG hnp timeouts, such as b_ase0_brst */ -void musb_otg_timer_func(unsigned long data) +static void musb_otg_timer_func(unsigned long data) { struct musb *musb = (struct musb *)data; unsigned long flags; @@ -643,8 +681,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 = is_otg_enabled(musb) - && otg->gadget->b_hnp_enable; + musb->is_active = otg->gadget->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"); @@ -660,8 +697,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 = is_otg_enabled(musb) - && otg->host->b_hnp_enable; + musb->is_active = otg->host->b_hnp_enable; break; case OTG_STATE_B_HOST: /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ @@ -749,7 +785,7 @@ b_host: case OTG_STATE_A_SUSPEND: usb_hcd_resume_root_hub(musb_to_hcd(musb)); musb_root_disconnect(musb); - if (musb->a_wait_bcon != 0 && is_otg_enabled(musb)) + if (musb->a_wait_bcon != 0) musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(musb->a_wait_bcon)); break; @@ -787,7 +823,7 @@ b_host: */ if (int_usb & MUSB_INTR_RESET) { handled = IRQ_HANDLED; - if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) { + if ((devctl & MUSB_DEVCTL_HM) != 0) { /* * Looks like non-HS BABBLE can be ignored, but * HS BABBLE is an error condition. For HS the solution @@ -801,7 +837,7 @@ b_host: ERR("Stopping host session -- babble\n"); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); } - } else if (is_peripheral_capable()) { + } else { dev_dbg(musb->controller, "BUS RESET as %s\n", otg_state_string(musb->xceiv->state)); switch (musb->xceiv->state) { @@ -925,25 +961,16 @@ void musb_start(struct musb *musb) devctl = musb_readb(regs, MUSB_DEVCTL); devctl &= ~MUSB_DEVCTL_SESSION; - if (is_otg_enabled(musb)) { - /* session started after: - * (a) ID-grounded irq, host mode; - * (b) vbus present/connect IRQ, peripheral mode; - * (c) peripheral initiates, using SRP - */ - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - else - devctl |= MUSB_DEVCTL_SESSION; - - } else if (is_host_enabled(musb)) { - /* assume ID pin is hard-wired to ground */ + /* session started after: + * (a) ID-grounded irq, host mode; + * (b) vbus present/connect IRQ, peripheral mode; + * (c) peripheral initiates, using SRP + */ + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) + musb->is_active = 1; + else devctl |= MUSB_DEVCTL_SESSION; - } else /* peripheral is enabled */ { - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - } musb_platform_enable(musb); musb_writeb(regs, MUSB_DEVCTL, devctl); } @@ -1007,8 +1034,6 @@ static void musb_shutdown(struct platform_device *pdev) musb_generic_disable(musb); spin_unlock_irqrestore(&musb->lock, flags); - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - usb_remove_hcd(musb_to_hcd(musb)); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_platform_exit(musb); @@ -1302,7 +1327,7 @@ done: if (offset < 0) { pr_debug("%s: mem overrun, ep %d\n", musb_driver_name, epn); - return -EINVAL; + return offset; } epn++; musb->nr_endpoints = max(epn, musb->nr_endpoints); @@ -1330,7 +1355,7 @@ static int __devinit ep_config_from_hw(struct musb *musb) { u8 epnum = 0; struct musb_hw_ep *hw_ep; - void *mbase = musb->mregs; + void __iomem *mbase = musb->mregs; int ret = 0; dev_dbg(musb->controller, "<== static silicon ep config\n"); @@ -1571,13 +1596,10 @@ irqreturn_t musb_interrupt(struct musb *musb) /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval = ep->rx_irq(...) */ retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, ep_num); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_rx(musb, ep_num); + else + musb_g_rx(musb, ep_num); } reg >>= 1; @@ -1592,13 +1614,10 @@ irqreturn_t musb_interrupt(struct musb *musb) /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval |= ep->tx_irq(...) */ retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, ep_num); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_tx(musb, ep_num); + else + musb_g_tx(musb, ep_num); } reg >>= 1; ep_num++; @@ -1634,22 +1653,16 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) } else { /* endpoints 1..15 */ if (transmit) { - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, epnum); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_tx(musb, epnum); + else + musb_g_tx(musb, epnum); } else { /* receive */ - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, epnum); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_rx(musb, epnum); + else + musb_g_rx(musb, epnum); } } } @@ -1785,10 +1798,9 @@ static const struct attribute_group musb_attr_group = { static void musb_irq_work(struct work_struct *data) { struct musb *musb = container_of(data, struct musb, irq_work); - static int old_state; - if (musb->xceiv->state != old_state) { - old_state = musb->xceiv->state; + if (musb->xceiv->state != musb->xceiv_old_state) { + musb->xceiv_old_state = musb->xceiv->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); } } @@ -1862,15 +1874,15 @@ static void musb_free(struct musb *musb) dma_controller_destroy(c); } - kfree(musb); + usb_put_hcd(musb_to_hcd(musb)); } /* * Perform generic per-controller initialization. * - * @pDevice: the controller (already clocked, etc) - * @nIrq: irq - * @mregs: virtual address of controller registers, + * @dev: the controller (already clocked, etc) + * @nIrq: IRQ number + * @ctrl: virtual address of controller registers, * not yet corrected for platform-specific offsets */ static int __devinit @@ -1879,6 +1891,7 @@ 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; /* The driver might handle more features than the board; OK. * Fail when the board needs a feature that's not enabled. @@ -1901,7 +1914,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_enable(musb->controller); spin_lock_init(&musb->lock); - musb->board_mode = plat->mode; musb->board_set_power = plat->set_power; musb->min_power = plat->min_power; musb->ops = plat->platform_ops; @@ -1972,7 +1984,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) goto fail3; } musb->nIrq = nIrq; -/* FIXME this handles wakeup irqs wrong */ + /* FIXME this handles wakeup irqs wrong */ if (enable_irq_wake(nIrq) == 0) { musb->irq_wake = 1; device_init_wakeup(dev, 1); @@ -1981,58 +1993,25 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) } /* host side needs more setup */ - if (is_host_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - otg_set_host(musb->xceiv->otg, &hcd->self); - - if (is_otg_enabled(musb)) - 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); - busctl |= MUSB_ULPI_USE_EXTVBUS; - musb_write_ulpi_buscontrol(musb->mregs, busctl); - } + 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); + busctl |= MUSB_ULPI_USE_EXTVBUS; + musb_write_ulpi_buscontrol(musb->mregs, busctl); } - /* For the host-only role, we can activate right away. - * (We expect the ID pin to be forcibly grounded!!) - * Otherwise, wait till the gadget driver hooks up. - */ - if (!is_otg_enabled(musb) && is_host_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - MUSB_HST_MODE(musb); - musb->xceiv->otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_IDLE; - - status = usb_add_hcd(musb_to_hcd(musb), 0, 0); - - hcd->self.uses_pio_for_control = 1; - dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n", - "HOST", status, - musb_readb(musb->mregs, MUSB_DEVCTL), - (musb_readb(musb->mregs, MUSB_DEVCTL) - & MUSB_DEVCTL_BDEVICE - ? 'B' : 'A')); - - } else /* peripheral is enabled */ { - MUSB_DEV_MODE(musb); - musb->xceiv->otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; - - status = musb_gadget_setup(musb); + MUSB_DEV_MODE(musb); + musb->xceiv->otg->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; - dev_dbg(musb->controller, "%s mode, status %d, dev%02x\n", - is_otg_enabled(musb) ? "OTG" : "PERIPHERAL", - status, - musb_readb(musb->mregs, MUSB_DEVCTL)); + status = musb_gadget_setup(musb); - } if (status < 0) goto fail3; @@ -2048,28 +2027,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_put(musb->controller); - dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n", - ({char *s; - switch (musb->board_mode) { - case MUSB_HOST: s = "Host"; break; - case MUSB_PERIPHERAL: s = "Peripheral"; break; - default: s = "OTG"; break; - }; s; }), - ctrl, - (is_dma_capable() && musb->dma_controller) - ? "DMA" : "PIO", - musb->nIrq); - return 0; fail5: musb_exit_debugfs(musb); fail4: - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - usb_remove_hcd(musb_to_hcd(musb)); - else - musb_gadget_cleanup(musb); + musb_gadget_cleanup(musb); fail3: pm_runtime_put_sync(musb->controller); @@ -2096,11 +2060,6 @@ fail0: /* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just * bridge to a platform device; this driver then suffices. */ - -#ifndef CONFIG_MUSB_PIO_ONLY -static u64 *orig_dma_mask; -#endif - static int __devinit musb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -2119,10 +2078,6 @@ static int __devinit musb_probe(struct platform_device *pdev) return -ENOMEM; } -#ifndef CONFIG_MUSB_PIO_ONLY - /* clobbered by use_dma=n */ - orig_dma_mask = dev->dma_mask; -#endif status = musb_init_controller(dev, irq, base); if (status < 0) iounmap(base); @@ -2132,7 +2087,8 @@ static int __devinit musb_probe(struct platform_device *pdev) static int __devexit musb_remove(struct platform_device *pdev) { - struct musb *musb = dev_to_musb(&pdev->dev); + struct device *dev = &pdev->dev; + struct musb *musb = dev_to_musb(dev); void __iomem *ctrl_base = musb->ctrl_base; /* this gets called on rmmod. @@ -2145,9 +2101,9 @@ static int __devexit musb_remove(struct platform_device *pdev) musb_free(musb); iounmap(ctrl_base); - device_init_wakeup(&pdev->dev, 0); + device_init_wakeup(dev, 0); #ifndef CONFIG_MUSB_PIO_ONLY - pdev->dev.dma_mask = orig_dma_mask; + dma_set_mask(dev, *dev->parent->dma_mask); #endif return 0; } @@ -2160,11 +2116,9 @@ static void musb_save_context(struct musb *musb) void __iomem *musb_base = musb->mregs; void __iomem *epio; - if (is_host_enabled(musb)) { - musb->context.frame = musb_readw(musb_base, MUSB_FRAME); - musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); - musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); - } + musb->context.frame = musb_readw(musb_base, MUSB_FRAME); + 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); @@ -2203,30 +2157,29 @@ static void musb_save_context(struct musb *musb) musb->context.index_regs[i].rxfifosz = musb_read_rxfifosz(musb_base); } - if (is_host_enabled(musb)) { - musb->context.index_regs[i].txtype = - musb_readb(epio, MUSB_TXTYPE); - musb->context.index_regs[i].txinterval = - musb_readb(epio, MUSB_TXINTERVAL); - musb->context.index_regs[i].rxtype = - musb_readb(epio, MUSB_RXTYPE); - musb->context.index_regs[i].rxinterval = - musb_readb(epio, MUSB_RXINTERVAL); - - musb->context.index_regs[i].txfunaddr = - musb_read_txfunaddr(musb_base, i); - musb->context.index_regs[i].txhubaddr = - musb_read_txhubaddr(musb_base, i); - musb->context.index_regs[i].txhubport = - musb_read_txhubport(musb_base, i); - - musb->context.index_regs[i].rxfunaddr = - musb_read_rxfunaddr(musb_base, i); - musb->context.index_regs[i].rxhubaddr = - musb_read_rxhubaddr(musb_base, i); - musb->context.index_regs[i].rxhubport = - musb_read_rxhubport(musb_base, i); - } + + musb->context.index_regs[i].txtype = + musb_readb(epio, MUSB_TXTYPE); + musb->context.index_regs[i].txinterval = + musb_readb(epio, MUSB_TXINTERVAL); + musb->context.index_regs[i].rxtype = + musb_readb(epio, MUSB_RXTYPE); + musb->context.index_regs[i].rxinterval = + musb_readb(epio, MUSB_RXINTERVAL); + + musb->context.index_regs[i].txfunaddr = + musb_read_txfunaddr(musb_base, i); + musb->context.index_regs[i].txhubaddr = + musb_read_txhubaddr(musb_base, i); + musb->context.index_regs[i].txhubport = + musb_read_txhubport(musb_base, i); + + musb->context.index_regs[i].rxfunaddr = + musb_read_rxfunaddr(musb_base, i); + musb->context.index_regs[i].rxhubaddr = + musb_read_rxhubaddr(musb_base, i); + musb->context.index_regs[i].rxhubport = + musb_read_rxhubport(musb_base, i); } } @@ -2237,11 +2190,9 @@ static void musb_restore_context(struct musb *musb) void __iomem *ep_target_regs; void __iomem *epio; - if (is_host_enabled(musb)) { - 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_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); @@ -2280,33 +2231,31 @@ static void musb_restore_context(struct musb *musb) musb->context.index_regs[i].rxfifoadd); } - if (is_host_enabled(musb)) { - musb_writeb(epio, MUSB_TXTYPE, + musb_writeb(epio, MUSB_TXTYPE, musb->context.index_regs[i].txtype); - musb_writeb(epio, MUSB_TXINTERVAL, + musb_writeb(epio, MUSB_TXINTERVAL, musb->context.index_regs[i].txinterval); - musb_writeb(epio, MUSB_RXTYPE, + musb_writeb(epio, MUSB_RXTYPE, musb->context.index_regs[i].rxtype); - musb_writeb(epio, MUSB_RXINTERVAL, + musb_writeb(epio, MUSB_RXINTERVAL, - musb->context.index_regs[i].rxinterval); - musb_write_txfunaddr(musb_base, i, + musb->context.index_regs[i].rxinterval); + musb_write_txfunaddr(musb_base, i, musb->context.index_regs[i].txfunaddr); - musb_write_txhubaddr(musb_base, i, + musb_write_txhubaddr(musb_base, i, musb->context.index_regs[i].txhubaddr); - musb_write_txhubport(musb_base, i, + musb_write_txhubport(musb_base, i, musb->context.index_regs[i].txhubport); - ep_target_regs = - musb_read_target_reg_base(i, musb_base); + ep_target_regs = + musb_read_target_reg_base(i, musb_base); - musb_write_rxfunaddr(ep_target_regs, + musb_write_rxfunaddr(ep_target_regs, musb->context.index_regs[i].rxfunaddr); - musb_write_rxhubaddr(ep_target_regs, + musb_write_rxhubaddr(ep_target_regs, musb->context.index_regs[i].rxhubaddr); - musb_write_rxhubport(ep_target_regs, + musb_write_rxhubport(ep_target_regs, musb->context.index_regs[i].rxhubport); - } } musb_writeb(musb_base, MUSB_INDEX, musb->context.index); } |