diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-03-24 22:57:49 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-03-24 22:57:49 +0100 |
commit | 1c41a9570a02cec80be5fb4f7f9cf206220d84a5 (patch) | |
tree | 21eeee43b0cb88415ea809bfab3f2b432fd5ac45 /drivers/usb/musb | |
parent | Merge 4.0-rc5 into usb-next (diff) | |
parent | usb: musb: Fix fifo reads for dm816x with musb_dsps (diff) | |
download | linux-1c41a9570a02cec80be5fb4f7f9cf206220d84a5.tar.xz linux-1c41a9570a02cec80be5fb4f7f9cf206220d84a5.zip |
Merge tag 'usb-for-v4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:
usb: patches for v4.1 merge window
As usual, a big pile of commits. This time a total
of 111 non-merge commits.
Other than the usual set of cleanups and non-critical
fixes, we have some interesting work for AM335x's MUSB
babble recovery. Now that takes a lot less time and we
don't have to Reset MUSB all the time.
The printer gadget has been converted to configfs interface
and the atmel udc has learned suspend/resume with wakeup.
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/musb_core.c | 214 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 14 | ||||
-rw-r--r-- | drivers/usb/musb/musb_cppi41.c | 84 | ||||
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 105 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 40 |
5 files changed, 201 insertions, 256 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 067920f2d570..a48b5a9c6c47 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -507,7 +507,8 @@ void musb_hnp_stop(struct musb *musb) musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16); } -static void musb_generic_disable(struct musb *musb); +static void musb_recover_from_babble(struct musb *musb); + /* * Interrupt Service Routine to record USB "global" interrupts. * Since these do not happen often and signify things of @@ -534,30 +535,16 @@ 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", usb_otg_state_string(musb->xceiv->otg->state)); + dev_dbg(musb->controller, "RESUME (%s)\n", + usb_otg_state_string(musb->xceiv->otg->state)); if (devctl & MUSB_DEVCTL_HM) { - void __iomem *mbase = musb->mregs; - u8 power; - switch (musb->xceiv->otg->state) { case OTG_STATE_A_SUSPEND: /* remote wakeup? later, GetPortStatus * will stop RESUME signaling */ - power = musb_readb(musb->mregs, MUSB_POWER); - if (power & MUSB_POWER_SUSPENDM) { - /* spurious */ - musb->int_usb &= ~MUSB_INTR_SUSPEND; - dev_dbg(musb->controller, "Spurious SUSPENDM\n"); - break; - } - - power &= ~MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, - power | MUSB_POWER_RESUME); - musb->port1_status |= (USB_PORT_STAT_C_SUSPEND << 16) | MUSB_PORT_STAT_RESUME; @@ -775,10 +762,6 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->ep0_stage = MUSB_EP0_START; - /* flush endpoints when transitioning from Device Mode */ - if (is_peripheral_active(musb)) { - /* REVISIT HNP; just force disconnect */ - } musb->intrtxe = musb->epmask; musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe); musb->intrrxe = musb->epmask & 0xfffe; @@ -879,20 +862,19 @@ b_host: */ if (int_usb & MUSB_INTR_RESET) { handled = IRQ_HANDLED; - if ((devctl & MUSB_DEVCTL_HM) != 0) { + if (devctl & MUSB_DEVCTL_HM) { /* - * 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 what - * caused BABBLE. When HS BABBLE happens we can only - * stop the session. + * When BABBLE happens what we can depends on which + * platform MUSB is running, because some platforms + * implemented proprietary means for 'recovering' from + * Babble conditions. One such platform is AM335x. In + * most cases, however, the only thing we can do is + * drop the session. */ - if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV)) - dev_dbg(musb->controller, "BABBLE devctl: %02x\n", devctl); - else { - ERR("Stopping host session -- babble\n"); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - } + dev_err(musb->controller, "Babble\n"); + + if (is_host_active(musb)) + musb_recover_from_babble(musb); } else { dev_dbg(musb->controller, "BUS RESET as %s\n", usb_otg_state_string(musb->xceiv->otg->state)); @@ -931,13 +913,6 @@ b_host: } } - /* handle babble condition */ - if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) { - musb_generic_disable(musb); - schedule_delayed_work(&musb->recover_work, - msecs_to_jiffies(100)); - } - #if 0 /* REVISIT ... this would be for multiplexing periodic endpoints, or * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -990,7 +965,7 @@ b_host: /*-------------------------------------------------------------------------*/ -static void musb_generic_disable(struct musb *musb) +static void musb_disable_interrupts(struct musb *musb) { void __iomem *mbase = musb->mregs; u16 temp; @@ -1002,14 +977,33 @@ static void musb_generic_disable(struct musb *musb) 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); +} + +static void musb_enable_interrupts(struct musb *musb) +{ + void __iomem *regs = musb->mregs; + + /* Set INT enable registers, enable interrupts */ + 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); + +} + +static void musb_generic_disable(struct musb *musb) +{ + void __iomem *mbase = musb->mregs; + musb_disable_interrupts(musb); + + /* off */ + musb_writeb(mbase, MUSB_DEVCTL, 0); } /* @@ -1022,13 +1016,7 @@ void musb_start(struct musb *musb) dev_dbg(musb->controller, "<== devctl %02x\n", devctl); - /* Set INT enable registers, enable interrupts */ - 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_enable_interrupts(musb); musb_writeb(regs, MUSB_TESTMODE, 0); /* put into basic highspeed mode and start session */ @@ -1587,9 +1575,12 @@ static int musb_core_init(u16 musb_type, struct musb *musb) irqreturn_t musb_interrupt(struct musb *musb) { irqreturn_t retval = IRQ_NONE; + unsigned long status; + unsigned long epnum; u8 devctl; - int ep_num; - u32 reg; + + if (!musb->int_usb && !musb->int_tx && !musb->int_rx) + return IRQ_NONE; devctl = musb_readb(musb->mregs, MUSB_DEVCTL); @@ -1597,56 +1588,57 @@ irqreturn_t musb_interrupt(struct musb *musb) is_host_active(musb) ? "host" : "peripheral", musb->int_usb, musb->int_tx, musb->int_rx); - /* the core can interrupt us for multiple reasons; docs have - * a generic interrupt flowchart to follow + /** + * According to Mentor Graphics' documentation, flowchart on page 98, + * IRQ should be handled as follows: + * + * . Resume IRQ + * . Session Request IRQ + * . VBUS Error IRQ + * . Suspend IRQ + * . Connect IRQ + * . Disconnect IRQ + * . Reset/Babble IRQ + * . SOF IRQ (we're not using this one) + * . Endpoint 0 IRQ + * . TX Endpoints + * . RX Endpoints + * + * We will be following that flowchart in order to avoid any problems + * that might arise with internal Finite State Machine. */ - if (musb->int_usb) - retval |= musb_stage0_irq(musb, musb->int_usb, - devctl); - /* "stage 1" is handling endpoint irqs */ + if (musb->int_usb) + retval |= musb_stage0_irq(musb, musb->int_usb, devctl); - /* handle endpoint 0 first */ if (musb->int_tx & 1) { if (is_host_active(musb)) retval |= musb_h_ep0_irq(musb); else retval |= musb_g_ep0_irq(musb); + + /* we have just handled endpoint 0 IRQ, clear it */ + musb->int_tx &= ~BIT(0); } - /* RX on endpoints 1-15 */ - reg = musb->int_rx >> 1; - ep_num = 1; - while (reg) { - if (reg & 1) { - /* musb_ep_select(musb->mregs, ep_num); */ - /* REVISIT just retval = ep->rx_irq(...) */ - retval = IRQ_HANDLED; - if (is_host_active(musb)) - musb_host_rx(musb, ep_num); - else - musb_g_rx(musb, ep_num); - } + status = musb->int_tx; - reg >>= 1; - ep_num++; + for_each_set_bit(epnum, &status, 16) { + retval = IRQ_HANDLED; + if (is_host_active(musb)) + musb_host_tx(musb, epnum); + else + musb_g_tx(musb, epnum); } - /* TX on endpoints 1-15 */ - reg = musb->int_tx >> 1; - ep_num = 1; - while (reg) { - if (reg & 1) { - /* musb_ep_select(musb->mregs, ep_num); */ - /* REVISIT just retval |= ep->tx_irq(...) */ - retval = IRQ_HANDLED; - if (is_host_active(musb)) - musb_host_tx(musb, ep_num); - else - musb_g_tx(musb, ep_num); - } - reg >>= 1; - ep_num++; + status = musb->int_rx; + + for_each_set_bit(epnum, &status, 16) { + retval = IRQ_HANDLED; + if (is_host_active(musb)) + musb_host_rx(musb, epnum); + else + musb_g_rx(musb, epnum); } return retval; @@ -1825,33 +1817,44 @@ static void musb_irq_work(struct work_struct *data) } } -/* Recover from babble interrupt conditions */ -static void musb_recover_work(struct work_struct *data) +static void musb_recover_from_babble(struct musb *musb) { - struct musb *musb = container_of(data, struct musb, recover_work.work); - int status, ret; + int ret; + u8 devctl; - ret = musb_platform_reset(musb); - if (ret) + musb_disable_interrupts(musb); + + /* + * wait at least 320 cycles of 60MHz clock. That's 5.3us, we will give + * it some slack and wait for 10us. + */ + udelay(10); + + ret = musb_platform_recover(musb); + if (ret) { + musb_enable_interrupts(musb); return; + } - usb_phy_vbus_off(musb->xceiv); - usleep_range(100, 200); + /* drop session bit */ + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + devctl &= ~MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - usb_phy_vbus_on(musb->xceiv); - usleep_range(100, 200); + /* tell usbcore about it */ + musb_root_disconnect(musb); /* * 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); + ret = ep_config_from_table(musb); else - status = ep_config_from_hw(musb); + ret = ep_config_from_hw(musb); - /* start the session again */ - if (status == 0) + /* restart session */ + if (ret == 0) musb_start(musb); } @@ -2087,7 +2090,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* Init IRQ workqueue before request_irq */ INIT_WORK(&musb->irq_work, musb_irq_work); - INIT_DELAYED_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); @@ -2183,7 +2185,6 @@ fail4: fail3: cancel_work_sync(&musb->irq_work); - cancel_delayed_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) @@ -2249,7 +2250,6 @@ static int musb_remove(struct platform_device *pdev) dma_controller_destroy(musb->dma_controller); cancel_work_sync(&musb->irq_work); - cancel_delayed_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); musb_free(musb); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 5e65958f7915..3877249a8b2d 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -160,7 +160,8 @@ struct musb_io; * @init: turns on clocks, sets up platform-specific registers, etc * @exit: undoes @init * @set_mode: forcefully changes operating mode - * @try_ilde: tries to idle the IP + * @try_idle: tries to idle the IP + * @recover: platform-specific babble recovery * @vbus_status: returns vbus status if possible * @set_vbus: forces vbus status * @adjust_channel_params: pre check for standard dma channel_program func @@ -196,7 +197,7 @@ struct musb_platform_ops { void (*write_fifo)(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf); int (*set_mode)(struct musb *musb, u8 mode); void (*try_idle)(struct musb *musb, unsigned long timeout); - int (*reset)(struct musb *musb); + int (*recover)(struct musb *musb); int (*vbus_status)(struct musb *musb); void (*set_vbus)(struct musb *musb, int on); @@ -300,7 +301,6 @@ struct musb { irqreturn_t (*isr)(int, void *); struct work_struct irq_work; - struct delayed_work recover_work; struct delayed_work deassert_reset_work; struct delayed_work finish_resume_work; u16 hwvers; @@ -558,12 +558,12 @@ static inline void musb_platform_try_idle(struct musb *musb, musb->ops->try_idle(musb, timeout); } -static inline int musb_platform_reset(struct musb *musb) +static inline int musb_platform_recover(struct musb *musb) { - if (!musb->ops->reset) - return -EINVAL; + if (!musb->ops->recover) + return 0; - return musb->ops->reset(musb); + return musb->ops->recover(musb); } static inline int musb_platform_get_vbus_status(struct musb *musb) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index be84562d021b..8bd8c5e26921 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -225,10 +225,12 @@ static void cppi41_dma_callback(void *private_data) struct dma_channel *channel = private_data; struct cppi41_dma_channel *cppi41_channel = channel->private_data; struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + struct cppi41_dma_controller *controller; struct musb *musb = hw_ep->musb; unsigned long flags; struct dma_tx_state txstate; u32 transferred; + int is_hs = 0; bool empty; spin_lock_irqsave(&musb->lock, flags); @@ -248,61 +250,59 @@ static void cppi41_dma_callback(void *private_data) transferred < cppi41_channel->packet_sz) cppi41_channel->prog_len = 0; - empty = musb_is_tx_fifo_empty(hw_ep); - if (empty) { + if (cppi41_channel->is_tx) + empty = musb_is_tx_fifo_empty(hw_ep); + + if (!cppi41_channel->is_tx || empty) { cppi41_trans_done(cppi41_channel); - } else { - struct cppi41_dma_controller *controller; - int is_hs = 0; - /* - * On AM335x it has been observed that the TX interrupt fires - * too early that means the TXFIFO is not yet empty but the DMA - * engine says that it is done with the transfer. We don't - * receive a FIFO empty interrupt so the only thing we can do is - * to poll for the bit. On HS it usually takes 2us, on FS around - * 110us - 150us depending on the transfer size. - * We spin on HS (no longer than than 25us and setup a timer on - * FS to check for the bit and complete the transfer. - */ - controller = cppi41_channel->controller; + goto out; + } - if (is_host_active(musb)) { - if (musb->port1_status & USB_PORT_STAT_HIGH_SPEED) - is_hs = 1; - } else { - if (musb->g.speed == USB_SPEED_HIGH) - is_hs = 1; - } - if (is_hs) { - unsigned wait = 25; - - do { - empty = musb_is_tx_fifo_empty(hw_ep); - if (empty) - break; - wait--; - if (!wait) - break; - udelay(1); - } while (1); + /* + * On AM335x it has been observed that the TX interrupt fires + * too early that means the TXFIFO is not yet empty but the DMA + * engine says that it is done with the transfer. We don't + * receive a FIFO empty interrupt so the only thing we can do is + * to poll for the bit. On HS it usually takes 2us, on FS around + * 110us - 150us depending on the transfer size. + * We spin on HS (no longer than than 25us and setup a timer on + * FS to check for the bit and complete the transfer. + */ + controller = cppi41_channel->controller; + + if (is_host_active(musb)) { + if (musb->port1_status & USB_PORT_STAT_HIGH_SPEED) + is_hs = 1; + } else { + if (musb->g.speed == USB_SPEED_HIGH) + is_hs = 1; + } + if (is_hs) { + unsigned wait = 25; + do { empty = musb_is_tx_fifo_empty(hw_ep); if (empty) { cppi41_trans_done(cppi41_channel); goto out; } - } - list_add_tail(&cppi41_channel->tx_check, - &controller->early_tx_list); - if (!hrtimer_is_queued(&controller->early_tx)) { - unsigned long usecs = cppi41_channel->total_len / 10; + wait--; + if (!wait) + break; + cpu_relax(); + } while (1); + } + list_add_tail(&cppi41_channel->tx_check, + &controller->early_tx_list); + if (!hrtimer_is_queued(&controller->early_tx)) { + unsigned long usecs = cppi41_channel->total_len / 10; - hrtimer_start_range_ns(&controller->early_tx, + hrtimer_start_range_ns(&controller->early_tx, ktime_set(0, usecs * NSEC_PER_USEC), 20 * NSEC_PER_USEC, HRTIMER_MODE_REL); - } } + out: spin_unlock_irqrestore(&musb->lock, flags); } diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index a900c9877195..b23ad150a165 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -119,7 +119,7 @@ struct dsps_musb_wrapper { unsigned iddig:5; unsigned iddig_mux:5; /* miscellaneous stuff */ - u8 poll_seconds; + unsigned poll_timeout; }; /* @@ -225,9 +225,8 @@ static void dsps_musb_enable(struct musb *musb) dsps_writel(reg_base, wrp->epintr_set, epmask); dsps_writel(reg_base, wrp->coreintr_set, coremask); - /* Force the DRVVBUS IRQ so we can start polling for ID change. */ - dsps_writel(reg_base, wrp->coreintr_set, - (1 << wrp->drvvbus) << wrp->usb_shift); + /* start polling for ID change. */ + mod_timer(&glue->timer, jiffies + msecs_to_jiffies(wrp->poll_timeout)); dsps_musb_try_idle(musb, 0); } @@ -285,7 +284,8 @@ static void otg_timer(unsigned long _musb) } if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); + mod_timer(&glue->timer, jiffies + + msecs_to_jiffies(wrp->poll_timeout)); break; case OTG_STATE_A_WAIT_VFALL: musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; @@ -330,28 +330,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", usbintr, epintr); - /* - * DRVVBUS IRQs are the only proxy we have (a very poor one!) for - * DSPS IP's missing ID change IRQ. We need an ID change IRQ to - * switch appropriately between halves of the OTG state machine. - * Managing DEVCTL.SESSION per Mentor docs requires that we know its - * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. - * Also, DRVVBUS pulses for SRP (but not at 5V) ... - */ - if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) { - pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); - - /* - * When a babble condition occurs, the musb controller removes - * the session and is no longer in host mode. Hence, all - * devices connected to its root hub get disconnected. - * - * Hand this error down to the musb core isr, so it can - * recover. - */ - musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; - musb->int_tx = musb->int_rx = 0; - } if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { int drvvbus = dsps_readl(reg_base, wrp->status); @@ -374,8 +352,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; - mod_timer(&glue->timer, - jiffies + wrp->poll_seconds * HZ); + mod_timer(&glue->timer, jiffies + + msecs_to_jiffies(wrp->poll_timeout)); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); @@ -404,7 +382,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) /* Poll for ID change in OTG port mode */ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); + mod_timer(&glue->timer, jiffies + + msecs_to_jiffies(wrp->poll_timeout)); out: spin_unlock_irqrestore(&musb->lock, flags); @@ -453,7 +432,7 @@ static int dsps_musb_init(struct musb *musb) musb->ctrl_base = reg_base; /* NOP driver needs change if supporting dual instance */ - musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0); + musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "phys", 0); if (IS_ERR(musb->xceiv)) return PTR_ERR(musb->xceiv); @@ -497,7 +476,7 @@ static int dsps_musb_init(struct musb *musb) * logic enabled. */ val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); - if (val == MUSB_BABBLE_RCV_DISABLE) { + if (val & MUSB_BABBLE_RCV_DISABLE) { glue->sw_babble_enabled = true; val |= MUSB_BABBLE_SW_SESSION_CTRL; dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); @@ -571,7 +550,7 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) return 0; } -static bool sw_babble_control(struct musb *musb) +static bool dsps_sw_babble_control(struct musb *musb) { u8 babble_ctl; bool session_restart = false; @@ -622,37 +601,36 @@ static bool sw_babble_control(struct musb *musb) return session_restart; } -static int dsps_musb_reset(struct musb *musb) +static int dsps_musb_recover(struct musb *musb) { struct device *dev = musb->controller; struct dsps_glue *glue = dev_get_drvdata(dev->parent); - const struct dsps_musb_wrapper *wrp = glue->wrp; - int session_restart = 0, error; + int session_restart = 0; if (glue->sw_babble_enabled) - session_restart = sw_babble_control(musb); - /* - * In case of new silicon version babble condition can be recovered - * without resetting the MUSB. But for older silicon versions, MUSB - * reset is needed - */ - if (session_restart || !glue->sw_babble_enabled) { - dev_info(musb->controller, "Restarting MUSB to recover from Babble\n"); - dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); - usleep_range(100, 200); - usb_phy_shutdown(musb->xceiv); - error = phy_power_off(musb->phy); - if (error) - dev_err(dev, "phy shutdown failed: %i\n", error); - usleep_range(100, 200); - usb_phy_init(musb->xceiv); - error = phy_power_on(musb->phy); - if (error) - dev_err(dev, "phy powerup failed: %i\n", error); + session_restart = dsps_sw_babble_control(musb); + else session_restart = 1; + + return session_restart ? 0 : -EPIPE; +} + +/* Similar to am35x, dm81xx support only 32-bit read operation */ +static void dsps_read_fifo32(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) +{ + void __iomem *fifo = hw_ep->fifo; + + if (len >= 4) { + readsl(fifo, dst, len >> 2); + dst += len & ~0x03; + len &= 0x03; } - return !session_restart; + /* Read any remaining 1 to 3 bytes */ + if (len > 0) { + u32 val = musb_readl(fifo, 0); + memcpy(dst, &val, len); + } } static struct musb_platform_ops dsps_ops = { @@ -665,7 +643,7 @@ static struct musb_platform_ops dsps_ops = { .try_idle = dsps_musb_try_idle, .set_mode = dsps_musb_set_mode, - .reset = dsps_musb_reset, + .recover = dsps_musb_recover, }; static u64 musb_dmamask = DMA_BIT_MASK(32); @@ -737,7 +715,6 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, musb->dev.parent = dev; musb->dev.dma_mask = &musb_dmamask; musb->dev.coherent_dma_mask = musb_dmamask; - musb->dev.of_node = of_node_get(dn); glue->musb = musb; @@ -802,6 +779,9 @@ static int dsps_probe(struct platform_device *pdev) } wrp = match->data; + if (of_device_is_compatible(pdev->dev.of_node, "ti,musb-dm816")) + dsps_ops.read_fifo = dsps_read_fifo32; + /* allocate glue */ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) @@ -873,12 +853,14 @@ static const struct dsps_musb_wrapper am33xx_driver_data = { .rxep_shift = 16, .rxep_mask = 0xfffe, .rxep_bitmap = (0xfffe << 16), - .poll_seconds = 2, + .poll_timeout = 2000, /* ms */ }; static const struct of_device_id musb_dsps_of_match[] = { { .compatible = "ti,musb-am33xx", - .data = (void *) &am33xx_driver_data, }, + .data = &am33xx_driver_data, }, + { .compatible = "ti,musb-dm816", + .data = &am33xx_driver_data, }, { }, }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); @@ -929,7 +911,8 @@ static int dsps_resume(struct device *dev) dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); + mod_timer(&glue->timer, jiffies + + msecs_to_jiffies(wrp->poll_timeout)); return 0; } diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index b2d9040c7685..4c481cd66c77 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1876,44 +1876,6 @@ err: return retval; } -static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) -{ - int i; - struct musb_hw_ep *hw_ep; - - /* don't disconnect if it's not connected */ - if (musb->g.speed == USB_SPEED_UNKNOWN) - driver = NULL; - else - musb->g.speed = USB_SPEED_UNKNOWN; - - /* deactivate the hardware */ - if (musb->softconnect) { - musb->softconnect = 0; - musb_pullup(musb, 0); - } - musb_stop(musb); - - /* killing any outstanding requests will quiesce the driver; - * then report disconnect - */ - if (driver) { - for (i = 0, hw_ep = musb->endpoints; - i < musb->nr_endpoints; - i++, hw_ep++) { - musb_ep_select(musb->mregs, i); - if (hw_ep->is_shared_fifo /* || !epnum */) { - nuke(&hw_ep->ep_in, -ESHUTDOWN); - } else { - if (hw_ep->max_packet_sz_tx) - nuke(&hw_ep->ep_in, -ESHUTDOWN); - if (hw_ep->max_packet_sz_rx) - nuke(&hw_ep->ep_out, -ESHUTDOWN); - } - } - } -} - /* * Unregister the gadget driver. Used by gadget drivers when * unregistering themselves from the controller. @@ -1940,7 +1902,7 @@ static int musb_gadget_stop(struct usb_gadget *g) (void) musb_gadget_vbus_draw(&musb->g, 0); musb->xceiv->otg->state = OTG_STATE_UNDEFINED; - stop_activity(musb, NULL); + musb_stop(musb); otg_set_peripheral(musb->xceiv->otg, NULL); musb->is_active = 0; |