diff options
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/blackfin.c | 1 | ||||
-rw-r--r-- | drivers/usb/musb/da8xx.c | 70 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 57 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 14 | ||||
-rw-r--r-- | drivers/usb/musb/musb_cppi41.c | 9 | ||||
-rw-r--r-- | drivers/usb/musb/musb_debugfs.c | 22 | ||||
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 12 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 8 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.c | 12 | ||||
-rw-r--r-- | drivers/usb/musb/musb_virthub.c | 1 | ||||
-rw-r--r-- | drivers/usb/musb/musbhsdma.h | 2 | ||||
-rw-r--r-- | drivers/usb/musb/omap2430.c | 6 | ||||
-rw-r--r-- | drivers/usb/musb/sunxi.c | 25 |
13 files changed, 177 insertions, 62 deletions
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 310238c6b5cd..896798071817 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -469,6 +469,7 @@ static const struct musb_platform_ops bfin_ops = { .init = bfin_musb_init, .exit = bfin_musb_exit, + .fifo_offset = bfin_fifo_offset, .readb = bfin_readb, .writeb = bfin_writeb, .readw = bfin_readw, diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 2440f88e07a3..e89708d839e5 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -6,6 +6,9 @@ * Based on the DaVinci "glue layer" code. * Copyright (C) 2005-2006 by Texas Instruments * + * DT support + * Copyright (c) 2016 Petr Kulhavy <petr@barix.com> + * * This file is part of the Inventra Controller Driver for Linux. * * The Inventra Controller Driver for Linux is free software; you @@ -340,6 +343,13 @@ static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode) struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent); enum phy_mode phy_mode; + /* + * The PHY has some issues when it is forced in device or host mode. + * Unless the user request another mode, configure the PHY in OTG mode. + */ + if (!musb->is_initialized) + return phy_set_mode(glue->phy, PHY_MODE_USB_OTG); + switch (musb_mode) { case MUSB_HOST: /* Force VBUS valid, ID = 0 */ phy_mode = PHY_MODE_USB_HOST; @@ -366,6 +376,12 @@ static int da8xx_musb_init(struct musb *musb) musb->mregs += DA8XX_MENTOR_CORE_OFFSET; + ret = clk_prepare_enable(glue->clk); + if (ret) { + dev_err(glue->dev, "failed to enable clock\n"); + return ret; + } + /* Returns zero if e.g. not clocked */ rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG); if (!rev) @@ -377,12 +393,6 @@ static int da8xx_musb_init(struct musb *musb) goto fail; } - ret = clk_prepare_enable(glue->clk); - if (ret) { - dev_err(glue->dev, "failed to enable clock\n"); - goto fail; - } - setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); /* Reset the controller */ @@ -392,7 +402,7 @@ static int da8xx_musb_init(struct musb *musb) ret = phy_init(glue->phy); if (ret) { dev_err(glue->dev, "Failed to init phy.\n"); - goto err_phy_init; + goto fail; } ret = phy_power_on(glue->phy); @@ -412,9 +422,8 @@ static int da8xx_musb_init(struct musb *musb) err_phy_power_on: phy_exit(glue->phy); -err_phy_init: - clk_disable_unprepare(glue->clk); fail: + clk_disable_unprepare(glue->clk); return ret; } @@ -433,6 +442,21 @@ static int da8xx_musb_exit(struct musb *musb) return 0; } +static inline u8 get_vbus_power(struct device *dev) +{ + struct regulator *vbus_supply; + int current_uA; + + vbus_supply = regulator_get_optional(dev, "vbus"); + if (IS_ERR(vbus_supply)) + return 255; + current_uA = regulator_get_current_limit(vbus_supply); + regulator_put(vbus_supply); + if (current_uA <= 0 || current_uA > 510000) + return 255; + return current_uA / 1000 / 2; +} + static const struct musb_platform_ops da8xx_ops = { .quirks = MUSB_DMA_CPPI | MUSB_INDEXED_EP, .init = da8xx_musb_init, @@ -458,6 +482,12 @@ static const struct platform_device_info da8xx_dev_info = { .dma_mask = DMA_BIT_MASK(32), }; +static const struct musb_hdrc_config da8xx_config = { + .ram_bits = 10, + .num_eps = 5, + .multipoint = 1, +}; + static int da8xx_probe(struct platform_device *pdev) { struct resource musb_resources[2]; @@ -465,6 +495,7 @@ static int da8xx_probe(struct platform_device *pdev) struct da8xx_glue *glue; struct platform_device_info pinfo; struct clk *clk; + struct device_node *np = pdev->dev.of_node; int ret; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); @@ -487,6 +518,16 @@ static int da8xx_probe(struct platform_device *pdev) glue->dev = &pdev->dev; glue->clk = clk; + if (IS_ENABLED(CONFIG_OF) && np) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->config = &da8xx_config; + pdata->mode = musb_get_mode(&pdev->dev); + pdata->power = get_vbus_power(&pdev->dev); + } + pdata->platform_ops = &da8xx_ops; glue->usb_phy = usb_phy_generic_register(); @@ -537,11 +578,22 @@ static int da8xx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id da8xx_id_table[] = { + { + .compatible = "ti,da830-musb", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, da8xx_id_table); +#endif + static struct platform_driver da8xx_driver = { .probe = da8xx_probe, .remove = da8xx_remove, .driver = { .name = "musb-da8xx", + .of_match_table = of_match_ptr(da8xx_id_table), }, }; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index c3e172e15ec3..772f15821242 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -100,6 +100,7 @@ #include <linux/io.h> #include <linux/dma-mapping.h> #include <linux/usb.h> +#include <linux/usb/of.h> #include "musb_core.h" #include "musb_trace.h" @@ -130,6 +131,24 @@ static inline struct musb *dev_to_musb(struct device *dev) return dev_get_drvdata(dev); } +enum musb_mode musb_get_mode(struct device *dev) +{ + enum usb_dr_mode mode; + + mode = usb_get_dr_mode(dev); + switch (mode) { + case USB_DR_MODE_HOST: + return MUSB_HOST; + case USB_DR_MODE_PERIPHERAL: + return MUSB_PERIPHERAL; + case USB_DR_MODE_OTG: + case USB_DR_MODE_UNKNOWN: + default: + return MUSB_OTG; + } +} +EXPORT_SYMBOL_GPL(musb_get_mode); + /*-------------------------------------------------------------------------*/ #ifndef CONFIG_BLACKFIN @@ -569,20 +588,17 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (devctl & MUSB_DEVCTL_HM) { switch (musb->xceiv->otg->state) { case OTG_STATE_A_SUSPEND: - /* remote wakeup? later, GetPortStatus - * will stop RESUME signaling - */ - + /* remote wakeup? */ musb->port1_status |= (USB_PORT_STAT_C_SUSPEND << 16) | MUSB_PORT_STAT_RESUME; musb->rh_timer = jiffies + msecs_to_jiffies(USB_RESUME_TIMEOUT); - musb->need_finish_resume = 1; - musb->xceiv->otg->state = OTG_STATE_A_HOST; musb->is_active = 1; musb_host_resume_root_hub(musb); + schedule_delayed_work(&musb->finish_resume_work, + msecs_to_jiffies(USB_RESUME_TIMEOUT)); break; case OTG_STATE_B_WAIT_ACON: musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; @@ -1909,6 +1925,14 @@ static void musb_pm_runtime_check_session(struct musb *musb) static void musb_irq_work(struct work_struct *data) { struct musb *musb = container_of(data, struct musb, irq_work.work); + int error; + + error = pm_runtime_get_sync(musb->controller); + if (error < 0) { + dev_err(musb->controller, "Could not enable: %i\n", error); + + return; + } musb_pm_runtime_check_session(musb); @@ -1916,6 +1940,9 @@ static void musb_irq_work(struct work_struct *data) musb->xceiv_old_state = musb->xceiv->otg->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); } + + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); } static void musb_recover_from_babble(struct musb *musb) @@ -2034,6 +2061,7 @@ struct musb_pending_work { struct list_head node; }; +#ifdef CONFIG_PM /* * Called from musb_runtime_resume(), musb_resume(), and * musb_queue_resume_work(). Callers must take musb->lock. @@ -2061,6 +2089,7 @@ static int musb_run_resume_work(struct musb *musb) return error; } +#endif /* * Called to run work if device is active or else queue the work to happen @@ -2414,8 +2443,9 @@ fail2: musb_platform_exit(musb); fail1: - dev_err(musb->controller, - "musb_init_controller failed with status %d\n", status); + if (status != -EPROBE_DEFER) + dev_err(musb->controller, + "%s failed with status %d\n", __func__, status); musb_free(musb); @@ -2691,11 +2721,6 @@ static int musb_resume(struct device *dev) mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV; if ((devctl & mask) != (musb->context.devctl & mask)) musb->port1_status = 0; - if (musb->need_finish_resume) { - musb->need_finish_resume = 0; - schedule_delayed_work(&musb->finish_resume_work, - msecs_to_jiffies(USB_RESUME_TIMEOUT)); - } /* * The USB HUB code expects the device to be in RPM_ACTIVE once it came @@ -2747,12 +2772,6 @@ static int musb_runtime_resume(struct device *dev) musb_restore_context(musb); - if (musb->need_finish_resume) { - musb->need_finish_resume = 0; - schedule_delayed_work(&musb->finish_resume_work, - msecs_to_jiffies(USB_RESUME_TIMEOUT)); - } - spin_lock_irqsave(&musb->lock, flags); error = musb_run_resume_work(musb); if (error) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 91817d77d59c..ce5a18c98c6d 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -216,6 +216,7 @@ struct musb_platform_ops { void (*pre_root_reset_end)(struct musb *musb); void (*post_root_reset_end)(struct musb *musb); int (*phy_callback)(enum musb_vbus_id_status status); + void (*clear_ep_rxintr)(struct musb *musb, int epnum); }; /* @@ -409,7 +410,6 @@ struct musb { /* is_suspended means USB B_PERIPHERAL suspend */ unsigned is_suspended:1; - unsigned need_finish_resume :1; /* may_wakeup means remote wakeup is enabled */ unsigned may_wakeup:1; @@ -626,4 +626,16 @@ static inline void musb_platform_post_root_reset_end(struct musb *musb) musb->ops->post_root_reset_end(musb); } +static inline void musb_platform_clear_ep_rxintr(struct musb *musb, int epnum) +{ + if (musb->ops->clear_ep_rxintr) + musb->ops->clear_ep_rxintr(musb, epnum); +} + +/* + * gets the "dr_mode" property from DT and converts it into musb_mode + * if the property is not found or not recognized returns MUSB_OTG + */ +extern enum musb_mode musb_get_mode(struct device *dev); + #endif /* __MUSB_CORE_H__ */ diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index d4d7c56b48c7..16363852c034 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -197,8 +197,7 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) if (!list_empty(&controller->early_tx_list) && !hrtimer_is_queued(&controller->early_tx)) { ret = HRTIMER_RESTART; - hrtimer_forward_now(&controller->early_tx, - ktime_set(0, 20 * NSEC_PER_USEC)); + hrtimer_forward_now(&controller->early_tx, 20 * NSEC_PER_USEC); } spin_unlock_irqrestore(&musb->lock, flags); @@ -280,9 +279,9 @@ static void cppi41_dma_callback(void *private_data) unsigned long usecs = cppi41_channel->total_len / 10; hrtimer_start_range_ns(&controller->early_tx, - ktime_set(0, usecs * NSEC_PER_USEC), - 20 * NSEC_PER_USEC, - HRTIMER_MODE_REL); + usecs * NSEC_PER_USEC, + 20 * NSEC_PER_USEC, + HRTIMER_MODE_REL); } out: diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 9b22d946c089..dd70c88419d2 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -37,7 +37,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "musb_core.h" #include "musb_debug.h" @@ -114,6 +114,7 @@ static int musb_regdump_show(struct seq_file *s, void *unused) unsigned i; seq_printf(s, "MUSB (M)HDRC Register Dump\n"); + pm_runtime_get_sync(musb->controller); for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) { switch (musb_regmap[i].size) { @@ -132,6 +133,8 @@ static int musb_regdump_show(struct seq_file *s, void *unused) } } + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return 0; } @@ -145,7 +148,10 @@ static int musb_test_mode_show(struct seq_file *s, void *unused) struct musb *musb = s->private; unsigned test; + pm_runtime_get_sync(musb->controller); test = musb_readb(musb->mregs, MUSB_TESTMODE); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); if (test & MUSB_TEST_FORCE_HOST) seq_printf(s, "force host\n"); @@ -194,11 +200,12 @@ static ssize_t musb_test_mode_write(struct file *file, u8 test; char buf[18]; + pm_runtime_get_sync(musb->controller); test = musb_readb(musb->mregs, MUSB_TESTMODE); if (test) { dev_err(musb->controller, "Error: test mode is already set. " "Please do USB Bus Reset to start a new test.\n"); - return count; + goto ret; } memset(buf, 0x00, sizeof(buf)); @@ -234,6 +241,9 @@ static ssize_t musb_test_mode_write(struct file *file, musb_writeb(musb->mregs, MUSB_TESTMODE, test); +ret: + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return count; } @@ -254,8 +264,13 @@ static int musb_softconnect_show(struct seq_file *s, void *unused) switch (musb->xceiv->otg->state) { case OTG_STATE_A_HOST: case OTG_STATE_A_WAIT_BCON: + pm_runtime_get_sync(musb->controller); + reg = musb_readb(musb->mregs, MUSB_DEVCTL); connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0; + + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); break; default: connect = -1; @@ -284,6 +299,7 @@ static ssize_t musb_softconnect_write(struct file *file, if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; + pm_runtime_get_sync(musb->controller); if (!strncmp(buf, "0", 1)) { switch (musb->xceiv->otg->state) { case OTG_STATE_A_HOST: @@ -314,6 +330,8 @@ static ssize_t musb_softconnect_write(struct file *file, } } + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return count; } diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index feae1561b9ab..9f125e179acd 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -267,6 +267,17 @@ static void otg_timer(unsigned long _musb) pm_runtime_put_autosuspend(dev); } +void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) +{ + u32 epintr; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; + + /* musb->lock might already been held */ + epintr = (1 << epnum) << wrp->rxep_shift; + musb_writel(musb->ctrl_base, wrp->epintr_status, epintr); +} + static irqreturn_t dsps_interrupt(int irq, void *hci) { struct musb *musb = hci; @@ -622,6 +633,7 @@ static struct musb_platform_ops dsps_ops = { .set_mode = dsps_musb_set_mode, .recover = dsps_musb_recover, + .clear_ep_rxintr = dsps_musb_clear_ep_rxintr, }; static u64 musb_dmamask = DMA_BIT_MASK(32); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index a55173c9e564..1acc4864f9f6 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -974,8 +974,8 @@ static int musb_gadget_enable(struct usb_ep *ep, goto fail; /* REVISIT this rules out high bandwidth periodic transfers */ - tmp = usb_endpoint_maxp(desc); - if (tmp & ~0x07ff) { + tmp = usb_endpoint_maxp_mult(desc) - 1; + if (tmp) { int ok; if (usb_endpoint_dir_in(desc)) @@ -987,12 +987,12 @@ static int musb_gadget_enable(struct usb_ep *ep, musb_dbg(musb, "no support for high bandwidth ISO"); goto fail; } - musb_ep->hb_mult = (tmp >> 11) & 3; + musb_ep->hb_mult = tmp; } else { musb_ep->hb_mult = 0; } - musb_ep->packet_sz = tmp & 0x7ff; + musb_ep->packet_sz = usb_endpoint_maxp(desc); tmp = musb_ep->packet_sz * (musb_ep->hb_mult + 1); /* enable the interrupts for the endpoint, set the endpoint diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 53bc4ceefe89..ac3a4952abb4 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2237,7 +2237,7 @@ static int musb_urb_enqueue( * Some musb cores don't support high bandwidth ISO transfers; and * we don't (yet!) support high bandwidth interrupt transfers. */ - qh->hb_mult = 1 + ((qh->maxpacket >> 11) & 0x03); + qh->hb_mult = usb_endpoint_maxp_mult(epd); if (qh->hb_mult > 1) { int ok = (qh->type == USB_ENDPOINT_XFER_ISOC); @@ -2374,12 +2374,11 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) int is_in = usb_pipein(urb->pipe); int status = 0; u16 csr; + struct dma_channel *dma = NULL; musb_ep_select(regs, hw_end); if (is_dma_capable()) { - struct dma_channel *dma; - dma = is_in ? ep->rx_channel : ep->tx_channel; if (dma) { status = ep->musb->dma_controller->channel_abort(dma); @@ -2395,10 +2394,9 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) /* giveback saves bulk toggle */ csr = musb_h_flush_rxfifo(ep, 0); - /* REVISIT we still get an irq; should likely clear the - * endpoint's irq status here to avoid bogus irqs. - * clearing that status is platform-specific... - */ + /* clear the endpoint's irq status here to avoid bogus irqs */ + if (is_dma_capable() && dma) + musb_platform_clear_ep_rxintr(musb, ep->epnum); } else if (ep->epnum) { musb_h_tx_flush_fifo(ep); csr = musb_readw(epio, MUSB_TXCSR); diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 61b5f1c3c5bc..0b4595439d51 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -132,7 +132,6 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) musb_dbg(musb, "Root port resuming, power %02x", power); - /* later, GetPortStatus will stop RESUME signaling */ musb->port1_status |= MUSB_PORT_STAT_RESUME; schedule_delayed_work(&musb->finish_resume_work, msecs_to_jiffies(USB_RESUME_TIMEOUT)); diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h index f7b13fd25257..a3dcbd55e436 100644 --- a/drivers/usb/musb/musbhsdma.h +++ b/drivers/usb/musb/musbhsdma.h @@ -157,5 +157,5 @@ struct musb_dma_controller { void __iomem *base; u8 channel_count; u8 used_channels; - u8 irq; + int irq; }; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index e8be8e39ab8f..8b73214a9ea3 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -277,12 +277,12 @@ static int omap2430_musb_init(struct musb *musb) if (status == -ENXIO) return status; - pr_err("HS USB OTG: no transceiver configured\n"); + dev_dbg(dev, "HS USB OTG: no transceiver configured\n"); return -EPROBE_DEFER; } if (IS_ERR(musb->phy)) { - pr_err("HS USB OTG: no PHY configured\n"); + dev_err(dev, "HS USB OTG: no PHY configured\n"); return PTR_ERR(musb->phy); } musb->isr = omap2430_musb_interrupt; @@ -301,7 +301,7 @@ static int omap2430_musb_init(struct musb *musb) musb_writel(musb->mregs, OTG_INTERFSEL, l); - pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, " + dev_dbg(dev, "HS USB OTG: revision 0x%x, sysconfig 0x%02x, " "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n", musb_readl(musb->mregs, OTG_REVISION), musb_readl(musb->mregs, OTG_SYSCONFIG), diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 1408245be18e..d0be0eadd0d9 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -186,16 +186,6 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) if (musb->int_usb) writeb(musb->int_usb, musb->mregs + SUNXI_MUSB_INTRUSB); - /* - * sunxi musb often signals babble on low / full speed device - * disconnect, without ever raising MUSB_INTR_DISCONNECT, since - * normally babble never happens treat it as disconnect. - */ - if ((musb->int_usb & MUSB_INTR_BABBLE) && is_host_active(musb)) { - musb->int_usb &= ~MUSB_INTR_BABBLE; - musb->int_usb |= MUSB_INTR_DISCONNECT; - } - if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) { /* ep0 FADDR must be 0 when (re)entering peripheral mode */ musb_ep_select(musb->mregs, 0); @@ -390,6 +380,20 @@ static int sunxi_musb_set_mode(struct musb *musb, u8 mode) return 0; } +static int sunxi_musb_recover(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + /* + * Schedule a phy_set_mode with the current glue->phy_mode value, + * this will force end the current session. + */ + set_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags); + schedule_work(&glue->work); + + return 0; +} + /* * sunxi musb register layout * 0x00 - 0x17 fifo regs, 1 long per fifo @@ -618,6 +622,7 @@ static const struct musb_platform_ops sunxi_musb_ops = { .dma_init = sunxi_musb_dma_controller_create, .dma_exit = sunxi_musb_dma_controller_destroy, .set_mode = sunxi_musb_set_mode, + .recover = sunxi_musb_recover, .set_vbus = sunxi_musb_set_vbus, .pre_root_reset_end = sunxi_musb_pre_root_reset_end, .post_root_reset_end = sunxi_musb_post_root_reset_end, |