summaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-21 11:33:41 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-21 11:33:41 -0700
commit61fe2d75f138992f116ee70e83f10ff2d7e79143 (patch)
treec08ba135803a93852583a2916cd96981f53cfd06 /drivers/usb/musb
parent499b3803d3e2f062f73bf22372b38393369ffcbf (diff)
parent8346b33fad01cfe93f0fd0e64cd32ff40bd4ba41 (diff)
downloadop-kernel-dev-61fe2d75f138992f116ee70e83f10ff2d7e79143.zip
op-kernel-dev-61fe2d75f138992f116ee70e83f10ff2d7e79143.tar.gz
Merge tag 'usb-for-v3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes: usb: patches for v3.17 merge window Surprisingly enough, while a big set of patches, the majority is composed of cleanups (using devm_*, fixing sparse errors, moving code around, adding const, etc). The highlights are addition of new support for PLX USB338x devices, and support for USB 2.0-only configurations of the DWC3 IP core. Signed-of-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r--drivers/usb/musb/blackfin.c20
-rw-r--r--drivers/usb/musb/davinci.c20
-rw-r--r--drivers/usb/musb/jz4740.c3
-rw-r--r--drivers/usb/musb/musb_core.c41
-rw-r--r--drivers/usb/musb/musb_core.h12
-rw-r--r--drivers/usb/musb/musb_cppi41.c70
-rw-r--r--drivers/usb/musb/musb_dma.h1
-rw-r--r--drivers/usb/musb/musb_dsps.c104
-rw-r--r--drivers/usb/musb/musb_host.c19
-rw-r--r--drivers/usb/musb/musb_regs.h7
-rw-r--r--drivers/usb/musb/tusb6010.c16
-rw-r--r--drivers/usb/musb/ux500.c28
12 files changed, 188 insertions, 153 deletions
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index d40d5f0..ac4422b 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -455,7 +455,7 @@ static int bfin_probe(struct platform_device *pdev)
int ret = -ENOMEM;
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
@@ -464,7 +464,7 @@ static int bfin_probe(struct platform_device *pdev)
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
- goto err1;
+ goto err0;
}
musb->dev.parent = &pdev->dev;
@@ -478,7 +478,7 @@ static int bfin_probe(struct platform_device *pdev)
glue->phy = usb_phy_generic_register();
if (IS_ERR(glue->phy))
- goto err2;
+ goto err1;
platform_set_drvdata(pdev, glue);
memset(musb_resources, 0x00, sizeof(*musb_resources) *
@@ -498,31 +498,28 @@ static int bfin_probe(struct platform_device *pdev)
ARRAY_SIZE(musb_resources));
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
- goto err3;
+ goto err2;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err3;
+ goto err2;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
- goto err3;
+ goto err2;
}
return 0;
-err3:
- usb_phy_generic_unregister(glue->phy);
-
err2:
- platform_device_put(musb);
+ usb_phy_generic_unregister(glue->phy);
err1:
- kfree(glue);
+ platform_device_put(musb);
err0:
return ret;
@@ -534,7 +531,6 @@ static int bfin_remove(struct platform_device *pdev)
platform_device_unregister(glue->musb);
usb_phy_generic_unregister(glue->phy);
- kfree(glue);
return 0;
}
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index de8492b..110b784 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -519,23 +519,23 @@ static int davinci_probe(struct platform_device *pdev)
int ret = -ENOMEM;
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
}
- clk = clk_get(&pdev->dev, "usb");
+ clk = devm_clk_get(&pdev->dev, "usb");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk);
- goto err3;
+ goto err0;
}
ret = clk_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
- goto err4;
+ goto err0;
}
glue->dev = &pdev->dev;
@@ -579,20 +579,14 @@ static int davinci_probe(struct platform_device *pdev)
if (IS_ERR(musb)) {
ret = PTR_ERR(musb);
dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);
- goto err5;
+ goto err1;
}
return 0;
-err5:
+err1:
clk_disable(clk);
-err4:
- clk_put(clk);
-
-err3:
- kfree(glue);
-
err0:
return ret;
}
@@ -604,8 +598,6 @@ static int davinci_remove(struct platform_device *pdev)
platform_device_unregister(glue->musb);
usb_phy_generic_unregister();
clk_disable(glue->clk);
- clk_put(glue->clk);
- kfree(glue);
return 0;
}
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index 5f30537..d118729 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/usb/usb_phy_generic.h>
#include "musb_core.h"
@@ -80,6 +81,7 @@ static struct musb_hdrc_platform_data jz4740_musb_platform_data = {
static int jz4740_musb_init(struct musb *musb)
{
+ usb_phy_generic_register();
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv) {
pr_err("HS UDC: no transceiver configured\n");
@@ -182,6 +184,7 @@ static int jz4740_remove(struct platform_device *pdev)
struct jz4740_glue *glue = platform_get_drvdata(pdev);
platform_device_unregister(glue->musb);
+ usb_phy_generic_unregister(pdev);
clk_disable_unprepare(glue->clk);
return 0;
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index eff3c5c..b841ee0 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -850,7 +850,8 @@ b_host:
/* handle babble condition */
if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb))
- schedule_work(&musb->recover_work);
+ schedule_delayed_work(&musb->recover_work,
+ msecs_to_jiffies(100));
#if 0
/* REVISIT ... this would be for multiplexing periodic endpoints, or
@@ -1517,7 +1518,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n",
- (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral",
+ 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
@@ -1531,7 +1532,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
/* handle endpoint 0 first */
if (musb->int_tx & 1) {
- if (devctl & MUSB_DEVCTL_HM)
+ if (is_host_active(musb))
retval |= musb_h_ep0_irq(musb);
else
retval |= musb_g_ep0_irq(musb);
@@ -1545,7 +1546,7 @@ 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_active(musb))
musb_host_rx(musb, ep_num);
else
musb_g_rx(musb, ep_num);
@@ -1563,7 +1564,7 @@ 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_active(musb))
musb_host_tx(musb, ep_num);
else
musb_g_tx(musb, ep_num);
@@ -1585,15 +1586,13 @@ MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
{
- u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-
/* called with controller lock already held */
if (!epnum) {
#ifndef CONFIG_USB_TUSB_OMAP_DMA
if (!is_cppi_enabled()) {
/* endpoint 0 */
- if (devctl & MUSB_DEVCTL_HM)
+ if (is_host_active(musb))
musb_h_ep0_irq(musb);
else
musb_g_ep0_irq(musb);
@@ -1602,13 +1601,13 @@ 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_active(musb))
musb_host_tx(musb, epnum);
else
musb_g_tx(musb, epnum);
} else {
/* receive */
- if (devctl & MUSB_DEVCTL_HM)
+ if (is_host_active(musb))
musb_host_rx(musb, epnum);
else
musb_g_rx(musb, epnum);
@@ -1753,20 +1752,22 @@ 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;
+ struct musb *musb = container_of(data, struct musb, recover_work.work);
+ int status, ret;
- musb_platform_reset(musb);
+ ret = musb_platform_reset(musb);
+ if (ret)
+ return;
usb_phy_vbus_off(musb->xceiv);
- udelay(100);
+ usleep_range(100, 200);
usb_phy_vbus_on(musb->xceiv);
- udelay(100);
+ usleep_range(100, 200);
/*
- * When a babble condition occurs, the musb controller removes the
- * session bit and the endpoint config is lost.
+ * 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);
@@ -1945,7 +1946,7 @@ 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_WORK(&musb->recover_work, musb_recover_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);
@@ -2041,7 +2042,7 @@ fail4:
fail3:
cancel_work_sync(&musb->irq_work);
- cancel_work_sync(&musb->recover_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)
@@ -2107,7 +2108,7 @@ static int musb_remove(struct platform_device *pdev)
dma_controller_destroy(musb->dma_controller);
cancel_work_sync(&musb->irq_work);
- cancel_work_sync(&musb->recover_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 d155a15..414e57a 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -192,7 +192,7 @@ struct musb_platform_ops {
int (*set_mode)(struct musb *musb, u8 mode);
void (*try_idle)(struct musb *musb, unsigned long timeout);
- void (*reset)(struct musb *musb);
+ int (*reset)(struct musb *musb);
int (*vbus_status)(struct musb *musb);
void (*set_vbus)(struct musb *musb, int on);
@@ -297,7 +297,7 @@ struct musb {
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
- struct work_struct recover_work;
+ struct delayed_work recover_work;
struct delayed_work deassert_reset_work;
struct delayed_work finish_resume_work;
u16 hwvers;
@@ -555,10 +555,12 @@ static inline void musb_platform_try_idle(struct musb *musb,
musb->ops->try_idle(musb, timeout);
}
-static inline void musb_platform_reset(struct musb *musb)
+static inline int musb_platform_reset(struct musb *musb)
{
- if (musb->ops->reset)
- musb->ops->reset(musb);
+ if (!musb->ops->reset)
+ return -EINVAL;
+
+ return musb->ops->reset(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 5341bb2..47ae645 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -39,7 +39,6 @@ struct cppi41_dma_channel {
u32 transferred;
u32 packet_sz;
struct list_head tx_check;
- struct work_struct dma_completion;
};
#define MUSB_DMA_NUM_CHANNELS 15
@@ -74,15 +73,18 @@ static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
{
+ struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
u16 csr;
u8 toggle;
if (cppi41_channel->is_tx)
return;
- if (!is_host_active(cppi41_channel->controller->musb))
+ if (!is_host_active(musb))
return;
- csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+ musb_ep_select(musb->mregs, hw_ep->epnum);
+ csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
/*
@@ -107,24 +109,13 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)
void __iomem *epio = musb->endpoints[epnum].regs;
u16 csr;
+ musb_ep_select(musb->mregs, hw_ep->epnum);
csr = musb_readw(epio, MUSB_TXCSR);
if (csr & MUSB_TXCSR_TXPKTRDY)
return false;
return true;
}
-static bool is_isoc(struct musb_hw_ep *hw_ep, bool in)
-{
- if (in && hw_ep->in_qh) {
- if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC)
- return true;
- } else if (hw_ep->out_qh) {
- if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC)
- return true;
- }
- return false;
-}
-
static void cppi41_dma_callback(void *private_data);
static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
@@ -139,6 +130,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
cppi41_channel->channel.actual_len =
cppi41_channel->transferred;
cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ cppi41_channel->channel.rx_packet_done = true;
musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
} else {
/* next iteration, reload */
@@ -172,6 +164,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
dma_async_issue_pending(dc);
if (!cppi41_channel->is_tx) {
+ musb_ep_select(musb->mregs, hw_ep->epnum);
csr = musb_readw(epio, MUSB_RXCSR);
csr |= MUSB_RXCSR_H_REQPKT;
musb_writew(epio, MUSB_RXCSR, csr);
@@ -179,32 +172,6 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
}
}
-static void cppi_trans_done_work(struct work_struct *work)
-{
- unsigned long flags;
- struct cppi41_dma_channel *cppi41_channel =
- container_of(work, struct cppi41_dma_channel, dma_completion);
- struct cppi41_dma_controller *controller = cppi41_channel->controller;
- struct musb *musb = controller->musb;
- struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
- bool empty;
-
- if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) {
- spin_lock_irqsave(&musb->lock, flags);
- cppi41_trans_done(cppi41_channel);
- spin_unlock_irqrestore(&musb->lock, flags);
- } else {
- empty = musb_is_tx_fifo_empty(hw_ep);
- if (empty) {
- spin_lock_irqsave(&musb->lock, flags);
- cppi41_trans_done(cppi41_channel);
- spin_unlock_irqrestore(&musb->lock, flags);
- } else {
- schedule_work(&cppi41_channel->dma_completion);
- }
- }
-}
-
static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
{
struct cppi41_dma_controller *controller;
@@ -233,7 +200,7 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
if (!list_empty(&controller->early_tx_list)) {
ret = HRTIMER_RESTART;
hrtimer_forward_now(&controller->early_tx,
- ktime_set(0, 150 * NSEC_PER_USEC));
+ ktime_set(0, 50 * NSEC_PER_USEC));
}
spin_unlock_irqrestore(&musb->lock, flags);
@@ -268,14 +235,6 @@ static void cppi41_dma_callback(void *private_data)
transferred < cppi41_channel->packet_sz)
cppi41_channel->prog_len = 0;
- if (!cppi41_channel->is_tx) {
- if (is_isoc(hw_ep, 1))
- schedule_work(&cppi41_channel->dma_completion);
- else
- cppi41_trans_done(cppi41_channel);
- goto out;
- }
-
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) {
cppi41_trans_done(cppi41_channel);
@@ -312,15 +271,13 @@ static void cppi41_dma_callback(void *private_data)
goto out;
}
}
- if (is_isoc(hw_ep, 0)) {
- schedule_work(&cppi41_channel->dma_completion);
- 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;
+
hrtimer_start_range_ns(&controller->early_tx,
- ktime_set(0, 140 * NSEC_PER_USEC),
+ ktime_set(0, usecs * NSEC_PER_USEC),
40 * NSEC_PER_USEC,
HRTIMER_MODE_REL);
}
@@ -450,6 +407,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
dma_desc->callback = cppi41_dma_callback;
dma_desc->callback_param = channel;
cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+ cppi41_channel->channel.rx_packet_done = false;
save_rx_toggle(cppi41_channel);
dma_async_issue_pending(dc);
@@ -672,8 +630,6 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
cppi41_channel->port_num = port;
cppi41_channel->is_tx = is_tx;
INIT_LIST_HEAD(&cppi41_channel->tx_check);
- INIT_WORK(&cppi41_channel->dma_completion,
- cppi_trans_done_work);
musb_dma = &cppi41_channel->channel;
musb_dma->private_data = cppi41_channel;
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 1345a4f..1d44faa 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -129,6 +129,7 @@ struct dma_channel {
size_t actual_len;
enum dma_channel_status status;
bool desired_mode;
+ bool rx_packet_done;
};
/*
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 09529f9..c791ba5 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -56,16 +56,24 @@ static const struct of_device_id musb_dsps_of_match[];
* dependent on musb core layer symbols.
*/
static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
- { return __raw_readb(addr + offset); }
+{
+ return __raw_readb(addr + offset);
+}
static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
- { return __raw_readl(addr + offset); }
+{
+ return __raw_readl(addr + offset);
+}
static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
- { __raw_writeb(data, addr + offset); }
+{
+ __raw_writeb(data, addr + offset);
+}
static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
- { __raw_writel(data, addr + offset); }
+{
+ __raw_writel(data, addr + offset);
+}
/**
* DSPS musb wrapper register offset.
@@ -136,6 +144,7 @@ struct dsps_glue {
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
struct timer_list timer; /* otg_workaround timer */
unsigned long last_timer; /* last timer data for each instance */
+ bool sw_babble_enabled;
struct dsps_context context;
struct debugfs_regset32 regset;
@@ -469,6 +478,19 @@ static int dsps_musb_init(struct musb *musb)
val &= ~(1 << wrp->otg_disable);
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
+ /*
+ * Check whether the dsps version has babble control enabled.
+ * In latest silicon revision the babble control logic is enabled.
+ * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control
+ * logic enabled.
+ */
+ val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+ 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);
+ }
+
ret = dsps_musb_dbg_init(musb, glue);
if (ret)
return ret;
@@ -535,14 +557,82 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode)
return 0;
}
-static void dsps_musb_reset(struct musb *musb)
+static bool sw_babble_control(struct musb *musb)
+{
+ u8 babble_ctl;
+ bool session_restart = false;
+
+ babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+ dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n",
+ babble_ctl);
+ /*
+ * check line monitor flag to check whether babble is
+ * due to noise
+ */
+ dev_dbg(musb->controller, "STUCK_J is %s\n",
+ babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset");
+
+ if (babble_ctl & MUSB_BABBLE_STUCK_J) {
+ int timeout = 10;
+
+ /*
+ * babble is due to noise, then set transmit idle (d7 bit)
+ * to resume normal operation
+ */
+ babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+ babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE;
+ dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl);
+
+ /* wait till line monitor flag cleared */
+ dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n");
+ do {
+ babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+ udelay(1);
+ } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--);
+
+ /* check whether stuck_at_j bit cleared */
+ if (babble_ctl & MUSB_BABBLE_STUCK_J) {
+ /*
+ * real babble condition has occurred
+ * restart the controller to start the
+ * session again
+ */
+ dev_dbg(musb->controller, "J not cleared, misc (%x)\n",
+ babble_ctl);
+ session_restart = true;
+ }
+ } else {
+ session_restart = true;
+ }
+
+ return session_restart;
+}
+
+static int dsps_musb_reset(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;
+
+ 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);
+ usleep_range(100, 200);
+ usb_phy_init(musb->xceiv);
+ session_restart = 1;
+ }
- dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset));
- udelay(100);
+ return !session_restart;
}
static struct musb_platform_ops dsps_ops = {
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index eb06291..855793d 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -120,7 +120,7 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
if (csr != lastcsr)
dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
lastcsr = csr;
- csr |= MUSB_TXCSR_FLUSHFIFO;
+ csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_TXPKTRDY;
musb_writew(epio, MUSB_TXCSR, csr);
csr = musb_readw(epio, MUSB_TXCSR);
if (WARN(retries-- < 1,
@@ -1295,7 +1295,7 @@ done:
if (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma->status = MUSB_DMA_STATUS_CORE_ABORT;
- (void) musb->dma_controller->channel_abort(dma);
+ musb->dma_controller->channel_abort(dma);
}
/* do the proper sequence to abort the transfer in the
@@ -1640,7 +1640,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
/* clean up dma and collect transfer count */
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma->status = MUSB_DMA_STATUS_CORE_ABORT;
- (void) musb->dma_controller->channel_abort(dma);
+ musb->dma_controller->channel_abort(dma);
xfer_len = dma->actual_len;
}
musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG);
@@ -1671,7 +1671,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
*/
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma->status = MUSB_DMA_STATUS_CORE_ABORT;
- (void) musb->dma_controller->channel_abort(dma);
+ musb->dma_controller->channel_abort(dma);
xfer_len = dma->actual_len;
done = true;
}
@@ -1734,10 +1734,11 @@ void musb_host_rx(struct musb *musb, u8 epnum)
}
} else {
- /* done if urb buffer is full or short packet is recd */
- done = (urb->actual_length + xfer_len >=
- urb->transfer_buffer_length
- || dma->actual_len < qh->maxpacket);
+ /* done if urb buffer is full or short packet is recd */
+ done = (urb->actual_length + xfer_len >=
+ urb->transfer_buffer_length
+ || dma->actual_len < qh->maxpacket
+ || dma->rx_packet_done);
}
/* send IN token for next packet, without AUTOREQ */
@@ -1957,7 +1958,7 @@ static int musb_schedule(
struct musb_qh *qh,
int is_in)
{
- int idle;
+ int idle = 0;
int best_diff;
int best_end, epnum;
struct musb_hw_ep *hw_ep = NULL;
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 03f2655..b9bcda5 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -72,6 +72,12 @@
#define MUSB_DEVCTL_HR 0x02
#define MUSB_DEVCTL_SESSION 0x01
+/* BABBLE_CTL */
+#define MUSB_BABBLE_FORCE_TXIDLE 0x80
+#define MUSB_BABBLE_SW_SESSION_CTRL 0x40
+#define MUSB_BABBLE_STUCK_J 0x20
+#define MUSB_BABBLE_RCV_DISABLE 0x04
+
/* MUSB ULPI VBUSCONTROL */
#define MUSB_ULPI_USE_EXTVBUS 0x01
#define MUSB_ULPI_USE_EXTVBUSIND 0x02
@@ -246,6 +252,7 @@
*/
#define MUSB_DEVCTL 0x60 /* 8 bit */
+#define MUSB_BABBLE_CTL 0x61 /* 8 bit */
/* These are always controlled through the INDEX register */
#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 159ef4b..7dfc6cb 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -22,6 +22,7 @@
#include <linux/usb.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/usb/usb_phy_generic.h>
@@ -1160,12 +1161,12 @@ static int tusb_probe(struct platform_device *pdev)
struct platform_device *musb;
struct tusb6010_glue *glue;
struct platform_device_info pinfo;
- int ret = -ENOMEM;
+ int ret;
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
- goto err0;
+ return -ENOMEM;
}
glue->dev = &pdev->dev;
@@ -1204,16 +1205,10 @@ static int tusb_probe(struct platform_device *pdev)
if (IS_ERR(musb)) {
ret = PTR_ERR(musb);
dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);
- goto err3;
+ return ret;
}
return 0;
-
-err3:
- kfree(glue);
-
-err0:
- return ret;
}
static int tusb_remove(struct platform_device *pdev)
@@ -1222,7 +1217,6 @@ static int tusb_remove(struct platform_device *pdev)
platform_device_unregister(glue->musb);
usb_phy_generic_unregister(glue->phy);
- kfree(glue);
return 0;
}
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index f202e50..dc666e9 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -246,7 +246,7 @@ static int ux500_probe(struct platform_device *pdev)
}
}
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
@@ -255,20 +255,20 @@ static int ux500_probe(struct platform_device *pdev)
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
- goto err1;
+ goto err0;
}
- clk = clk_get(&pdev->dev, NULL);
+ clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk);
- goto err3;
+ goto err1;
}
ret = clk_prepare_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
- goto err4;
+ goto err1;
}
musb->dev.parent = &pdev->dev;
@@ -301,34 +301,28 @@ static int ux500_probe(struct platform_device *pdev)
ARRAY_SIZE(musb_resources));
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
- goto err5;
+ goto err2;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err5;
+ goto err2;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
- goto err5;
+ goto err2;
}
return 0;
-err5:
+err2:
clk_disable_unprepare(clk);
-err4:
- clk_put(clk);
-
-err3:
- platform_device_put(musb);
-
err1:
- kfree(glue);
+ platform_device_put(musb);
err0:
return ret;
@@ -340,8 +334,6 @@ static int ux500_remove(struct platform_device *pdev)
platform_device_unregister(glue->musb);
clk_disable_unprepare(glue->clk);
- clk_put(glue->clk);
- kfree(glue);
return 0;
}
OpenPOWER on IntegriCloud