aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/musb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r--drivers/usb/musb/Kconfig6
-rw-r--r--drivers/usb/musb/blackfin.c31
-rw-r--r--drivers/usb/musb/cppi_dma.c27
-rw-r--r--drivers/usb/musb/musb_core.c80
-rw-r--r--drivers/usb/musb/musb_core.h30
-rw-r--r--drivers/usb/musb/musb_dma.h3
-rw-r--r--drivers/usb/musb/musb_gadget.c292
-rw-r--r--drivers/usb/musb/musb_gadget.h15
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c24
-rw-r--r--drivers/usb/musb/musb_host.c15
-rw-r--r--drivers/usb/musb/musb_virthub.c4
-rw-r--r--drivers/usb/musb/musbhsdma.c8
-rw-r--r--drivers/usb/musb/musbhsdma.h21
-rw-r--r--drivers/usb/musb/omap2430.c178
-rw-r--r--drivers/usb/musb/tusb6010.c2
-rw-r--r--drivers/usb/musb/tusb6010_omap.c4
-rw-r--r--drivers/usb/musb/ux500.c2
17 files changed, 442 insertions, 300 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 4cbb7e4b368..74073b363c3 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -14,7 +14,7 @@ config USB_MUSB_HDRC
select TWL4030_USB if MACH_OMAP_3430SDP
select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
select USB_OTG_UTILS
- tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
+ bool 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
help
Say Y here if your system has a dual role high speed USB
controller based on the Mentor Graphics silicon IP. Then
@@ -30,8 +30,8 @@ config USB_MUSB_HDRC
If you do not know what this is, please say N.
- To compile this driver as a module, choose M here; the
- module will be called "musb-hdrc".
+# To compile this driver as a module, choose M here; the
+# module will be called "musb-hdrc".
choice
prompt "Platform Glue Layer"
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index eeba228eb2a..8e2a1ff8a35 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -21,6 +21,7 @@
#include <asm/cacheflush.h>
#include "musb_core.h"
+#include "musbhsdma.h"
#include "blackfin.h"
struct bfin_glue {
@@ -322,7 +323,7 @@ static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
}
-static int bfin_musb_get_vbus_status(struct musb *musb)
+static int bfin_musb_vbus_status(struct musb *musb)
{
return 0;
}
@@ -332,6 +333,27 @@ static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
return -EIO;
}
+static int bfin_musb_adjust_channel_params(struct dma_channel *channel,
+ u16 packet_sz, u8 *mode,
+ dma_addr_t *dma_addr, u32 *len)
+{
+ struct musb_dma_channel *musb_channel = channel->private_data;
+
+ /*
+ * Anomaly 05000450 might cause data corruption when using DMA
+ * MODE 1 transmits with short packet. So to work around this,
+ * we truncate all MODE 1 transfers down to a multiple of the
+ * max packet size, and then do the last short packet transfer
+ * (if there is any) using MODE 0.
+ */
+ if (ANOMALY_05000450) {
+ if (musb_channel->transmit && *mode == 1)
+ *len = *len - (*len % packet_sz);
+ }
+
+ return 0;
+}
+
static void bfin_musb_reg_init(struct musb *musb)
{
if (ANOMALY_05000346) {
@@ -404,6 +426,7 @@ static int bfin_musb_init(struct musb *musb)
musb->xceiv->set_power = bfin_musb_set_power;
musb->isr = blackfin_interrupt;
+ musb->double_buffer_not_ok = true;
return 0;
}
@@ -429,6 +452,8 @@ static const struct musb_platform_ops bfin_ops = {
.vbus_status = bfin_musb_vbus_status,
.set_vbus = bfin_musb_set_vbus,
+
+ .adjust_channel_params = bfin_musb_adjust_channel_params,
};
static u64 bfin_dmamask = DMA_BIT_MASK(32);
@@ -539,7 +564,7 @@ static struct dev_pm_ops bfin_pm_ops = {
.resume = bfin_resume,
};
-#define DEV_PM_OPS &bfin_pm_op,
+#define DEV_PM_OPS &bfin_pm_ops
#else
#define DEV_PM_OPS NULL
#endif
@@ -547,7 +572,7 @@ static struct dev_pm_ops bfin_pm_ops = {
static struct platform_driver bfin_driver = {
.remove = __exit_p(bfin_remove),
.driver = {
- .name = "musb-bfin",
+ .name = "musb-blackfin",
.pm = DEV_PM_OPS,
},
};
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index de55a3c3259..ab434fbd8c3 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -597,12 +597,12 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
length = min(n_bds * maxpacket, length);
}
- DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%x len %u\n",
+ DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n",
tx->index,
maxpacket,
rndis ? "rndis" : "transparent",
n_bds,
- addr, length);
+ (unsigned long long)addr, length);
cppi_rndis_update(tx, 0, musb->ctrl_base, rndis);
@@ -820,7 +820,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
length = min(n_bds * maxpacket, length);
DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
- "dma 0x%x len %u %u/%u\n",
+ "dma 0x%llx len %u %u/%u\n",
rx->index, maxpacket,
onepacket
? (is_rndis ? "rndis" : "onepacket")
@@ -829,7 +829,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
musb_readl(tibase,
DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
& 0xffff,
- addr, length, rx->channel.actual_len, rx->buf_len);
+ (unsigned long long)addr, length,
+ rx->channel.actual_len, rx->buf_len);
/* only queue one segment at a time, since the hardware prevents
* correct queue shutdown after unexpected short packets
@@ -1039,9 +1040,9 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
if (!completed && (bd->hw_options & CPPI_OWN_SET))
break;
- DBG(5, "C/RXBD %08x: nxt %08x buf %08x "
+ DBG(5, "C/RXBD %llx: nxt %08x buf %08x "
"off.len %08x opt.len %08x (%d)\n",
- bd->dma, bd->hw_next, bd->hw_bufp,
+ (unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp,
bd->hw_off_len, bd->hw_options,
rx->channel.actual_len);
@@ -1111,11 +1112,12 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
musb_ep_select(cppi->mregs, rx->index + 1);
csr = musb_readw(regs, MUSB_RXCSR);
if (csr & MUSB_RXCSR_DMAENAB) {
- DBG(4, "list%d %p/%p, last %08x%s, csr %04x\n",
+ DBG(4, "list%d %p/%p, last %llx%s, csr %04x\n",
rx->index,
rx->head, rx->tail,
rx->last_processed
- ? rx->last_processed->dma
+ ? (unsigned long long)
+ rx->last_processed->dma
: 0,
completed ? ", completed" : "",
csr);
@@ -1167,8 +1169,11 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
- if (!tx && !rx)
+ if (!tx && !rx) {
+ if (cppi->irq)
+ spin_unlock_irqrestore(&musb->lock, flags);
return IRQ_NONE;
+ }
DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
@@ -1199,7 +1204,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
*/
if (NULL == bd) {
DBG(1, "null BD\n");
- tx_ram->tx_complete = 0;
+ musb_writel(&tx_ram->tx_complete, 0, 0);
continue;
}
@@ -1452,7 +1457,7 @@ static int cppi_channel_abort(struct dma_channel *channel)
* compare mode by writing 1 to the tx_complete register.
*/
cppi_reset_tx(tx_ram, 1);
- cppi_ch->head = 0;
+ cppi_ch->head = NULL;
musb_writel(&tx_ram->tx_complete, 0, 1);
cppi_dump_tx(5, cppi_ch, " (done teardown)");
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 07cf394e491..f10ff00ca09 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -128,12 +128,7 @@ MODULE_ALIAS("platform:" MUSB_DRIVER_NAME);
static inline struct musb *dev_to_musb(struct device *dev)
{
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- /* usbcore insists dev->driver_data is a "struct hcd *" */
- return hcd_to_musb(dev_get_drvdata(dev));
-#else
return dev_get_drvdata(dev);
-#endif
}
/*-------------------------------------------------------------------------*/
@@ -1035,6 +1030,7 @@ static void musb_shutdown(struct platform_device *pdev)
struct musb *musb = dev_to_musb(&pdev->dev);
unsigned long flags;
+ pm_runtime_get_sync(musb->controller);
spin_lock_irqsave(&musb->lock, flags);
musb_platform_disable(musb);
musb_generic_disable(musb);
@@ -1045,6 +1041,7 @@ static void musb_shutdown(struct platform_device *pdev)
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_platform_exit(musb);
+ pm_runtime_put(musb->controller);
/* FIXME power down */
}
@@ -1535,7 +1532,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \
+#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) || \
defined(CONFIG_ARCH_U5500)
@@ -1869,6 +1866,7 @@ allocate_instance(struct device *dev,
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;
@@ -1876,10 +1874,9 @@ allocate_instance(struct device *dev,
musb = kzalloc(sizeof *musb, GFP_KERNEL);
if (!musb)
return NULL;
- dev_set_drvdata(dev, musb);
#endif
-
+ dev_set_drvdata(dev, musb);
musb->mregs = mbase;
musb->ctrl_base = mbase;
musb->nIrq = -ENODEV;
@@ -1955,31 +1952,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
goto fail0;
}
- switch (plat->mode) {
- case MUSB_HOST:
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- break;
-#else
- goto bad_config;
-#endif
- case MUSB_PERIPHERAL:
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- break;
-#else
- goto bad_config;
-#endif
- case MUSB_OTG:
-#ifdef CONFIG_USB_MUSB_OTG
- break;
-#else
-bad_config:
-#endif
- default:
- dev_err(dev, "incompatible Kconfig role setting\n");
- status = -EINVAL;
- goto fail0;
- }
-
/* allocate */
musb = allocate_instance(dev, plat->config, ctrl);
if (!musb) {
@@ -1987,6 +1959,10 @@ bad_config:
goto fail0;
}
+ pm_runtime_use_autosuspend(musb->controller);
+ pm_runtime_set_autosuspend_delay(musb->controller, 200);
+ pm_runtime_enable(musb->controller);
+
spin_lock_init(&musb->lock);
musb->board_mode = plat->mode;
musb->board_set_power = plat->set_power;
@@ -2122,6 +2098,8 @@ bad_config:
if (status < 0)
goto fail3;
+ pm_runtime_put(musb->controller);
+
status = musb_init_debugfs(musb);
if (status < 0)
goto fail4;
@@ -2191,7 +2169,7 @@ static int __init musb_probe(struct platform_device *pdev)
void __iomem *base;
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iomem || irq == 0)
+ if (!iomem || irq <= 0)
return -ENODEV;
base = ioremap(iomem->start, resource_size(iomem));
@@ -2221,9 +2199,11 @@ static int __exit musb_remove(struct platform_device *pdev)
* - Peripheral mode: peripheral is deactivated (or never-activated)
* - OTG mode: both roles are deactivated (or never-activated)
*/
+ pm_runtime_get_sync(musb->controller);
musb_exit_debugfs(musb);
musb_shutdown(pdev);
+ pm_runtime_put(musb->controller);
musb_free(musb);
iounmap(ctrl_base);
device_init_wakeup(&pdev->dev, 0);
@@ -2409,9 +2389,41 @@ static int musb_resume_noirq(struct device *dev)
return 0;
}
+static int musb_runtime_suspend(struct device *dev)
+{
+ struct musb *musb = dev_to_musb(dev);
+
+ musb_save_context(musb);
+
+ return 0;
+}
+
+static int musb_runtime_resume(struct device *dev)
+{
+ struct musb *musb = dev_to_musb(dev);
+ static int first = 1;
+
+ /*
+ * When pm_runtime_get_sync called for the first time in driver
+ * init, some of the structure is still not initialized which is
+ * used in restore function. But clock needs to be
+ * enabled before any register access, so
+ * pm_runtime_get_sync has to be called.
+ * Also context restore without save does not make
+ * any sense
+ */
+ if (!first)
+ musb_restore_context(musb);
+ first = 0;
+
+ return 0;
+}
+
static const struct dev_pm_ops musb_dev_pm_ops = {
.suspend = musb_suspend,
.resume_noirq = musb_resume_noirq,
+ .runtime_suspend = musb_runtime_suspend,
+ .runtime_resume = musb_runtime_resume,
};
#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops)
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index d0c236f8e19..0e053b58796 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -212,8 +212,8 @@ enum musb_g_ep0_state {
* directly with the "flat" model, or after setting up an index register.
*/
-#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \
- || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN) \
+#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \
+ || defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_BLACKFIN) \
|| defined(CONFIG_ARCH_OMAP4)
/* REVISIT indexed access seemed to
* misbehave (on DaVinci) for at least peripheral IN ...
@@ -261,6 +261,7 @@ enum musb_g_ep0_state {
* @try_ilde: tries to idle the IP
* @vbus_status: returns vbus status if possible
* @set_vbus: forces vbus status
+ * @channel_program: pre check for standard dma channel_program func
*/
struct musb_platform_ops {
int (*init)(struct musb *musb);
@@ -274,6 +275,10 @@ struct musb_platform_ops {
int (*vbus_status)(struct musb *musb);
void (*set_vbus)(struct musb *musb, int on);
+
+ int (*adjust_channel_params)(struct dma_channel *channel,
+ u16 packet_sz, u8 *mode,
+ dma_addr_t *dma_addr, u32 *len);
};
/*
@@ -328,7 +333,7 @@ struct musb_hw_ep {
#endif
};
-static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep)
+static inline struct musb_request *next_in_request(struct musb_hw_ep *hw_ep)
{
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
return next_request(&hw_ep->ep_in);
@@ -337,7 +342,7 @@ static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep)
#endif
}
-static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep)
+static inline struct musb_request *next_out_request(struct musb_hw_ep *hw_ep)
{
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
return next_request(&hw_ep->ep_out);
@@ -358,10 +363,6 @@ struct musb_csr_regs {
struct musb_context_registers {
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
- defined(CONFIG_ARCH_OMAP4)
- u32 otg_sysconfig, otg_forcestandby;
-#endif
u8 power;
u16 intrtxe, intrrxe;
u8 intrusbe;
@@ -497,6 +498,19 @@ struct musb {
struct usb_gadget_driver *gadget_driver; /* its driver */
#endif
+ /*
+ * FIXME: Remove this flag.
+ *
+ * This is only added to allow Blackfin to work
+ * with current driver. For some unknown reason
+ * Blackfin doesn't work with double buffering
+ * and that's enabled by default.
+ *
+ * We added this flag to forcefully disable double
+ * buffering until we get it working.
+ */
+ unsigned double_buffer_not_ok:1 __deprecated;
+
struct musb_hdrc_config *config;
#ifdef MUSB_CONFIG_PROC_FS
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 916065ba9e7..3a97c4e2d4f 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -169,6 +169,9 @@ struct dma_controller {
dma_addr_t dma_addr,
u32 length);
int (*channel_abort)(struct dma_channel *);
+ int (*is_compatible)(struct dma_channel *channel,
+ u16 maxpacket,
+ void *buf, u32 length);
};
/* called after channel_program(), may indicate a fault */
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index ed58c6c8f15..6dfbf9ffd7a 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -92,11 +92,33 @@
/* ----------------------------------------------------------------------- */
+#define is_buffer_mapped(req) (is_dma_capable() && \
+ (req->map_state != UN_MAPPED))
+
/* Maps the buffer to dma */
static inline void map_dma_buffer(struct musb_request *request,
- struct musb *musb)
+ struct musb *musb, struct musb_ep *musb_ep)
{
+ int compatible = true;
+ struct dma_controller *dma = musb->dma_controller;
+
+ request->map_state = UN_MAPPED;
+
+ if (!is_dma_capable() || !musb_ep->dma)
+ return;
+
+ /* Check if DMA engine can handle this request.
+ * DMA code must reject the USB request explicitly.
+ * Default behaviour is to map the request.
+ */
+ if (dma->is_compatible)
+ compatible = dma->is_compatible(musb_ep->dma,
+ musb_ep->packet_sz, request->request.buf,
+ request->request.length);
+ if (!compatible)
+ return;
+
if (request->request.dma == DMA_ADDR_INVALID) {
request->request.dma = dma_map_single(
musb->controller,
@@ -105,7 +127,7 @@ static inline void map_dma_buffer(struct musb_request *request,
request->tx
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
- request->mapped = 1;
+ request->map_state = MUSB_MAPPED;
} else {
dma_sync_single_for_device(musb->controller,
request->request.dma,
@@ -113,7 +135,7 @@ static inline void map_dma_buffer(struct musb_request *request,
request->tx
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
- request->mapped = 0;
+ request->map_state = PRE_MAPPED;
}
}
@@ -121,11 +143,14 @@ static inline void map_dma_buffer(struct musb_request *request,
static inline void unmap_dma_buffer(struct musb_request *request,
struct musb *musb)
{
+ if (!is_buffer_mapped(request))
+ return;
+
if (request->request.dma == DMA_ADDR_INVALID) {
DBG(20, "not unmapping a never mapped buffer\n");
return;
}
- if (request->mapped) {
+ if (request->map_state == MUSB_MAPPED) {
dma_unmap_single(musb->controller,
request->request.dma,
request->request.length,
@@ -133,16 +158,15 @@ static inline void unmap_dma_buffer(struct musb_request *request,
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
request->request.dma = DMA_ADDR_INVALID;
- request->mapped = 0;
- } else {
+ } else { /* PRE_MAPPED */
dma_sync_single_for_cpu(musb->controller,
request->request.dma,
request->request.length,
request->tx
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
-
}
+ request->map_state = UN_MAPPED;
}
/*
@@ -165,15 +189,14 @@ __acquires(ep->musb->lock)
req = to_musb_request(request);
- list_del(&request->list);
+ list_del(&req->list);
if (req->request.status == -EINPROGRESS)
req->request.status = status;
musb = req->musb;
ep->busy = 1;
spin_unlock(&musb->lock);
- if (is_dma_capable() && ep->dma)
- unmap_dma_buffer(req, musb);
+ unmap_dma_buffer(req, musb);
if (request->status == 0)
DBG(5, "%s done request %p, %d/%d\n",
ep->end_point.name, request,
@@ -228,9 +251,8 @@ static void nuke(struct musb_ep *ep, const int status)
ep->dma = NULL;
}
- while (!list_empty(&(ep->req_list))) {
- req = container_of(ep->req_list.next, struct musb_request,
- request.list);
+ while (!list_empty(&ep->req_list)) {
+ req = list_first_entry(&ep->req_list, struct musb_request, list);
musb_g_giveback(ep, &req->request, status);
}
}
@@ -335,7 +357,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
csr);
#ifndef CONFIG_MUSB_PIO_ONLY
- if (is_dma_capable() && musb_ep->dma) {
+ if (is_buffer_mapped(req)) {
struct dma_controller *c = musb->dma_controller;
size_t request_size;
@@ -436,8 +458,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
* Unmap the dma buffer back to cpu if dma channel
* programming fails
*/
- if (is_dma_capable() && musb_ep->dma)
- unmap_dma_buffer(req, musb);
+ unmap_dma_buffer(req, musb);
musb_write_fifo(musb_ep->hw_ep, fifo_count,
(u8 *) (request->buf + request->actual));
@@ -463,6 +484,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
void musb_g_tx(struct musb *musb, u8 epnum)
{
u16 csr;
+ struct musb_request *req;
struct usb_request *request;
u8 __iomem *mbase = musb->mregs;
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_in;
@@ -470,7 +492,8 @@ void musb_g_tx(struct musb *musb, u8 epnum)
struct dma_channel *dma;
musb_ep_select(mbase, epnum);
- request = next_request(musb_ep);
+ req = next_request(musb_ep);
+ request = &req->request;
csr = musb_readw(epio, MUSB_TXCSR);
DBG(4, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr);
@@ -512,7 +535,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
is_dma = 1;
csr |= MUSB_TXCSR_P_WZC_BITS;
csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
- MUSB_TXCSR_TXPKTRDY);
+ MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET);
musb_writew(epio, MUSB_TXCSR, csr);
/* Ensure writebuffer is empty. */
csr = musb_readw(epio, MUSB_TXCSR);
@@ -549,15 +572,15 @@ void musb_g_tx(struct musb *musb, u8 epnum)
if (request->actual == request->length) {
musb_g_giveback(musb_ep, request, 0);
- request = musb_ep->desc ? next_request(musb_ep) : NULL;
- if (!request) {
+ req = musb_ep->desc ? next_request(musb_ep) : NULL;
+ if (!req) {
DBG(4, "%s idle now\n",
musb_ep->end_point.name);
return;
}
}
- txstate(musb, to_musb_request(request));
+ txstate(musb, req);
}
}
@@ -627,7 +650,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
return;
}
- if (is_cppi_enabled() && musb_ep->dma) {
+ if (is_cppi_enabled() && is_buffer_mapped(req)) {
struct dma_controller *c = musb->dma_controller;
struct dma_channel *channel = musb_ep->dma;
@@ -658,7 +681,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
len = musb_readw(epio, MUSB_RXCOUNT);
if (request->actual < request->length) {
#ifdef CONFIG_USB_INVENTRA_DMA
- if (is_dma_capable() && musb_ep->dma) {
+ if (is_buffer_mapped(req)) {
struct dma_controller *c;
struct dma_channel *channel;
int use_dma = 0;
@@ -742,7 +765,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
fifo_count = min_t(unsigned, len, fifo_count);
#ifdef CONFIG_USB_TUSB_OMAP_DMA
- if (tusb_dma_omap() && musb_ep->dma) {
+ if (tusb_dma_omap() && is_buffer_mapped(req)) {
struct dma_controller *c = musb->dma_controller;
struct dma_channel *channel = musb_ep->dma;
u32 dma_addr = request->dma + request->actual;
@@ -762,7 +785,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* programming fails. This buffer is mapped if the
* channel allocation is successful
*/
- if (is_dma_capable() && musb_ep->dma) {
+ if (is_buffer_mapped(req)) {
unmap_dma_buffer(req, musb);
/*
@@ -799,6 +822,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
void musb_g_rx(struct musb *musb, u8 epnum)
{
u16 csr;
+ struct musb_request *req;
struct usb_request *request;
void __iomem *mbase = musb->mregs;
struct musb_ep *musb_ep;
@@ -813,10 +837,12 @@ void musb_g_rx(struct musb *musb, u8 epnum)
musb_ep_select(mbase, epnum);
- request = next_request(musb_ep);
- if (!request)
+ req = next_request(musb_ep);
+ if (!req)
return;
+ request = &req->request;
+
csr = musb_readw(epio, MUSB_RXCSR);
dma = is_dma_capable() ? musb_ep->dma : NULL;
@@ -892,15 +918,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
#endif
musb_g_giveback(musb_ep, request, 0);
- request = next_request(musb_ep);
- if (!request)
+ req = next_request(musb_ep);
+ if (!req)
return;
}
#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
exit:
#endif
/* Analyze request */
- rxstate(musb, to_musb_request(request));
+ rxstate(musb, req);
}
/* ------------------------------------------------------------ */
@@ -952,7 +978,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
ok = musb->hb_iso_rx;
if (!ok) {
- DBG(4, "%s: not support ISO high bandwidth\n", __func__);
+ DBG(4, "no support for high bandwidth ISO\n");
goto fail;
}
musb_ep->hb_mult = (tmp >> 11) & 3;
@@ -976,7 +1002,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
goto fail;
if (tmp > hw_ep->max_packet_sz_tx) {
- DBG(4, "%s: packet size beyond hw fifo size\n", __func__);
+ DBG(4, "packet size beyond hardware FIFO size\n");
goto fail;
}
@@ -989,7 +1015,11 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* Set TXMAXP with the FIFO size of the endpoint
* to disable double buffering mode.
*/
- musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+ if (musb->double_buffer_not_ok)
+ musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
+ else
+ musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz
+ | (musb_ep->hb_mult << 11));
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
if (musb_readw(regs, MUSB_TXCSR)
@@ -1012,7 +1042,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
goto fail;
if (tmp > hw_ep->max_packet_sz_rx) {
- DBG(4, "%s: packet size beyond hw fifo size\n", __func__);
+ DBG(4, "packet size beyond hardware FIFO size\n");
goto fail;
}
@@ -1025,7 +1055,11 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* Set RXMAXP with the FIFO size of the endpoint
* to disable double buffering mode.
*/
- musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+ if (musb->double_buffer_not_ok)
+ musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_tx);
+ else
+ musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz
+ | (musb_ep->hb_mult << 11));
/* force shared fifo to OUT-only mode */
if (hw_ep->is_shared_fifo) {
@@ -1141,7 +1175,6 @@ struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
return NULL;
}
- INIT_LIST_HEAD(&request->request.list);
request->request.dma = DMA_ADDR_INVALID;
request->epnum = musb_ep->current_epnum;
request->ep = musb_ep;
@@ -1214,10 +1247,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
request->epnum = musb_ep->current_epnum;
request->tx = musb_ep->is_in;
- if (is_dma_capable() && musb_ep->dma)
- map_dma_buffer(request, musb);
- else
- request->mapped = 0;
+ map_dma_buffer(request, musb, musb_ep);
spin_lock_irqsave(&musb->lock, lockflags);
@@ -1230,10 +1260,10 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
}
/* add request to the list */
- list_add_tail(&(request->request.list), &(musb_ep->req_list));
+ list_add_tail(&request->list, &musb_ep->req_list);
/* it this is the head of the queue, start i/o ... */
- if (!musb_ep->busy && &request->request.list == musb_ep->req_list.next)
+ if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
musb_ep_restart(musb, request);
cleanup:
@@ -1244,7 +1274,8 @@ cleanup:
static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
{
struct musb_ep *musb_ep = to_musb_ep(ep);
- struct usb_request *r;
+ struct musb_request *req = to_musb_request(request);
+ struct musb_request *r;
unsigned long flags;
int status = 0;
struct musb *musb = musb_ep->musb;
@@ -1255,17 +1286,17 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
spin_lock_irqsave(&musb->lock, flags);
list_for_each_entry(r, &musb_ep->req_list, list) {
- if (r == request)
+ if (r == req)
break;
}
- if (r != request) {
+ if (r != req) {
DBG(3, "request %p not queued to %s\n", request, ep->name);
status = -EINVAL;
goto done;
}
/* if the hardware doesn't have the request, easy ... */
- if (musb_ep->req_list.next != &request->list || musb_ep->busy)
+ if (musb_ep->req_list.next != &req->list || musb_ep->busy)
musb_g_giveback(musb_ep, request, -ECONNRESET);
/* ... else abort the dma transfer ... */
@@ -1322,7 +1353,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)
musb_ep_select(mbase, epnum);
- request = to_musb_request(next_request(musb_ep));
+ request = next_request(musb_ep);
if (value) {
if (request) {
DBG(3, "request in progress, cannot halt %s\n",
@@ -1774,90 +1805,105 @@ void musb_gadget_cleanup(struct musb *musb)
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
- int retval;
- unsigned long flags;
- struct musb *musb = the_gadget;
+ struct musb *musb = the_gadget;
+ unsigned long flags;
+ int retval = -EINVAL;
if (!driver
|| driver->speed != USB_SPEED_HIGH
|| !bind || !driver->setup)
- return -EINVAL;
+ goto err0;
/* driver must be initialized to support peripheral mode */
if (!musb) {
- DBG(1, "%s, no dev??\n", __func__);
- return -ENODEV;
+ DBG(1, "no dev??\n");
+ retval = -ENODEV;
+ goto err0;
}
+ pm_runtime_get_sync(musb->controller);
+
DBG(3, "registering driver %s\n", driver->function);
- spin_lock_irqsave(&musb->lock, flags);
if (musb->gadget_driver) {
DBG(1, "%s is already bound to %s\n",
musb_driver_name,
musb->gadget_driver->driver.name);
retval = -EBUSY;
- } else {
- musb->gadget_driver = driver;
- musb->g.dev.driver = &driver->driver;
- driver->driver.bus = NULL;
- musb->softconnect = 1;
- retval = 0;
+ goto err0;
}
+ spin_lock_irqsave(&musb->lock, flags);
+ musb->gadget_driver = driver;
+ musb->g.dev.driver = &driver->driver;
+ driver->driver.bus = NULL;
+ musb->softconnect = 1;
spin_unlock_irqrestore(&musb->lock, flags);
- if (retval == 0) {
- retval = bind(&musb->g);
- if (retval != 0) {
- DBG(3, "bind to driver %s failed --> %d\n",
- driver->driver.name, retval);
- musb->gadget_driver = NULL;
- musb->g.dev.driver = NULL;
- }
+ retval = bind(&musb->g);
+ if (retval) {
+ DBG(3, "bind to driver %s failed --> %d\n",
+ driver->driver.name, retval);
+ goto err1;
+ }
- spin_lock_irqsave(&musb->lock, flags);
+ spin_lock_irqsave(&musb->lock, flags);
- otg_set_peripheral(musb->xceiv, &musb->g);
- musb->xceiv->state = OTG_STATE_B_IDLE;
- musb->is_active = 1;
+ otg_set_peripheral(musb->xceiv, &musb->g);
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->is_active = 1;
- /* FIXME this ignores the softconnect flag. Drivers are
- * allowed hold the peripheral inactive until for example
- * userspace hooks up printer hardware or DSP codecs, so
- * hosts only see fully functional devices.
- */
+ /*
+ * FIXME this ignores the softconnect flag. Drivers are
+ * allowed hold the peripheral inactive until for example
+ * userspace hooks up printer hardware or DSP codecs, so
+ * hosts only see fully functional devices.
+ */
- if (!is_otg_enabled(musb))
- musb_start(musb);
+ if (!is_otg_enabled(musb))
+ musb_start(musb);
- otg_set_peripheral(musb->xceiv, &musb->g);
+ otg_set_peripheral(musb->xceiv, &musb->g);
- spin_unlock_irqrestore(&musb->lock, flags);
+ spin_unlock_irqrestore(&musb->lock, flags);
- if (is_otg_enabled(musb)) {
- struct usb_hcd *hcd = musb_to_hcd(musb);
+ if (is_otg_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
- DBG(3, "OTG startup...\n");
+ DBG(3, "OTG startup...\n");
- /* REVISIT: funcall to other code, which also
- * handles power budgeting ... this way also
- * ensures HdrcStart is indirectly called.
- */
- retval = usb_add_hcd(musb_to_hcd(musb), -1, 0);
- if (retval < 0) {
- DBG(1, "add_hcd failed, %d\n", retval);
- spin_lock_irqsave(&musb->lock, flags);
- otg_set_peripheral(musb->xceiv, NULL);
- musb->gadget_driver = NULL;
- musb->g.dev.driver = NULL;
- spin_unlock_irqrestore(&musb->lock, flags);
- } else {
- hcd->self.uses_pio_for_control = 1;
- }
+ /* REVISIT: funcall to other code, which also
+ * handles power budgeting ... this way also
+ * ensures HdrcStart is indirectly called.
+ */
+ retval = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ if (retval < 0) {
+ DBG(1, "add_hcd failed, %d\n", retval);
+ goto err2;
}
+
+ if ((musb->xceiv->last_event == USB_EVENT_ID)
+ && musb->xceiv->set_vbus)
+ otg_set_vbus(musb->xceiv, 1);
+
+ hcd->self.uses_pio_for_control = 1;
+
+ if (musb->xceiv->last_event == USB_EVENT_NONE)
+ pm_runtime_put(musb->controller);
+
}
+ return 0;
+
+err2:
+ if (!is_otg_enabled(musb))
+ musb_stop(musb);
+
+err1:
+ musb->gadget_driver = NULL;
+ musb->g.dev.driver = NULL;
+
+err0:
return retval;
}
EXPORT_SYMBOL(usb_gadget_probe_driver);
@@ -1912,14 +1958,20 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
*/
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
- unsigned long flags;
- int retval = 0;
struct musb *musb = the_gadget;
+ unsigned long flags;
if (!driver || !driver->unbind || !musb)
return -EINVAL;
- /* REVISIT always use otg_set_peripheral() here too;
+ if (!musb->gadget_driver)
+ return -EINVAL;
+
+ if (musb->xceiv->last_event == USB_EVENT_NONE)
+ pm_runtime_get_sync(musb->controller);
+
+ /*
+ * REVISIT always use otg_set_peripheral() here too;
* this needs to shut down the OTG engine.
*/
@@ -1929,29 +1981,26 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
musb_hnp_stop(musb);
#endif
- if (musb->gadget_driver == driver) {
+ (void) musb_gadget_vbus_draw(&musb->g, 0);
- (void) musb_gadget_vbus_draw(&musb->g, 0);
+ musb->xceiv->state = OTG_STATE_UNDEFINED;
+ stop_activity(musb, driver);
+ otg_set_peripheral(musb->xceiv, NULL);
- musb->xceiv->state = OTG_STATE_UNDEFINED;
- stop_activity(musb, driver);
- otg_set_peripheral(musb->xceiv, NULL);
+ DBG(3, "unregistering driver %s\n", driver->function);
- DBG(3, "unregistering driver %s\n", driver->function);
- spin_unlock_irqrestore(&musb->lock, flags);
- driver->unbind(&musb->g);
- spin_lock_irqsave(&musb->lock, flags);
+ spin_unlock_irqrestore(&musb->lock, flags);
+ driver->unbind(&musb->g);
+ spin_lock_irqsave(&musb->lock, flags);
- musb->gadget_driver = NULL;
- musb->g.dev.driver = NULL;
+ musb->gadget_driver = NULL;
+ musb->g.dev.driver = NULL;
- musb->is_active = 0;
- musb_platform_try_idle(musb, 0);
- } else
- retval = -EINVAL;
+ musb->is_active = 0;
+ musb_platform_try_idle(musb, 0);
spin_unlock_irqrestore(&musb->lock, flags);
- if (is_otg_enabled(musb) && retval == 0) {
+ if (is_otg_enabled(musb)) {
usb_remove_hcd(musb_to_hcd(musb));
/* FIXME we need to be able to register another
* gadget driver here and have everything work;
@@ -1959,7 +2008,12 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
*/
}
- return retval;
+ if (!is_otg_enabled(musb))
+ musb_stop(musb);
+
+ pm_runtime_put(musb->controller);
+
+ return 0;
}
EXPORT_SYMBOL(usb_gadget_unregister_driver);
diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h
index dec8dc00819..66b7c5e0fb4 100644
--- a/drivers/usb/musb/musb_gadget.h
+++ b/drivers/usb/musb/musb_gadget.h
@@ -35,13 +35,22 @@
#ifndef __MUSB_GADGET_H
#define __MUSB_GADGET_H
+#include <linux/list.h>
+
+enum buffer_map_state {
+ UN_MAPPED = 0,
+ PRE_MAPPED,
+ MUSB_MAPPED
+};
+
struct musb_request {
struct usb_request request;
+ struct list_head list;
struct musb_ep *ep;
struct musb *musb;
u8 tx; /* endpoint direction */
u8 epnum;
- u8 mapped;
+ enum buffer_map_state map_state;
};
static inline struct musb_request *to_musb_request(struct usb_request *req)
@@ -88,13 +97,13 @@ static inline struct musb_ep *to_musb_ep(struct usb_ep *ep)
return ep ? container_of(ep, struct musb_ep, end_point) : NULL;
}
-static inline struct usb_request *next_request(struct musb_ep *ep)
+static inline struct musb_request *next_request(struct musb_ep *ep)
{
struct list_head *queue = &ep->req_list;
if (list_empty(queue))
return NULL;
- return container_of(queue->next, struct usb_request, list);
+ return container_of(queue->next, struct musb_request, list);
}
extern void musb_g_tx(struct musb *musb, u8 epnum);
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 6dd03f4c5f4..75a542e42fd 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -304,8 +304,7 @@ __acquires(musb->lock)
}
/* Maybe start the first request in the queue */
- request = to_musb_request(
- next_request(musb_ep));
+ request = next_request(musb_ep);
if (!musb_ep->busy && request) {
DBG(3, "restarting the request\n");
musb_ep_restart(musb, request);
@@ -491,10 +490,12 @@ stall:
static void ep0_rxstate(struct musb *musb)
{
void __iomem *regs = musb->control_ep->regs;
+ struct musb_request *request;
struct usb_request *req;
u16 count, csr;
- req = next_ep0_request(musb);
+ request = next_ep0_request(musb);
+ req = &request->request;
/* read packet and ack; or stall because of gadget driver bug:
* should have provided the rx buffer before setup() returned.
@@ -544,17 +545,20 @@ static void ep0_rxstate(struct musb *musb)
static void ep0_txstate(struct musb *musb)
{
void __iomem *regs = musb->control_ep->regs;
- struct usb_request *request = next_ep0_request(musb);
+ struct musb_request *req = next_ep0_request(musb);
+ struct usb_request *request;
u16 csr = MUSB_CSR0_TXPKTRDY;
u8 *fifo_src;
u8 fifo_count;
- if (!request) {
+ if (!req) {
/* WARN_ON(1); */
DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0));
return;
}
+ request = &req->request;
+
/* load the data */
fifo_src = (u8 *) request->buf + request->actual;
fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE,
@@ -598,7 +602,7 @@ static void ep0_txstate(struct musb *musb)
static void
musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)
{
- struct usb_request *r;
+ struct musb_request *r;
void __iomem *regs = musb->control_ep->regs;
musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req);
@@ -616,7 +620,7 @@ musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)
/* clean up any leftover transfers */
r = next_ep0_request(musb);
if (r)
- musb_g_ep0_giveback(musb, r);
+ musb_g_ep0_giveback(musb, &r->request);
/* For zero-data requests we want to delay the STATUS stage to
* avoid SETUPEND errors. If we read data (OUT), delay accepting
@@ -758,11 +762,11 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
case MUSB_EP0_STAGE_STATUSOUT:
/* end of sequence #1: write to host (TX state) */
{
- struct usb_request *req;
+ struct musb_request *req;
req = next_ep0_request(musb);
if (req)
- musb_g_ep0_giveback(musb, req);
+ musb_g_ep0_giveback(musb, &req->request);
}
/*
@@ -961,7 +965,7 @@ musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
}
/* add request to the list */
- list_add_tail(&(req->request.list), &(ep->req_list));
+ list_add_tail(&req->list, &ep->req_list);
DBG(3, "queue to %s (%s), length=%d\n",
ep->name, ep->is_in ? "IN/TX" : "OUT/RX",
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 4d5bcb4e14d..5eef4a8847d 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -609,7 +609,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
/* Set RXMAXP with the FIFO size of the endpoint
* to disable double buffer mode.
*/
- if (musb->hwvers < MUSB_HWVERS_2000)
+ if (musb->double_buffer_not_ok)
musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx);
else
musb_writew(ep->regs, MUSB_RXMAXP,
@@ -784,14 +784,13 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
/* protocol/endpoint/interval/NAKlimit */
if (epnum) {
musb_writeb(epio, MUSB_TXTYPE, qh->type_reg);
- if (can_bulk_split(musb, qh->type))
+ if (musb->double_buffer_not_ok)
musb_writew(epio, MUSB_TXMAXP,
- packet_sz
- | ((hw_ep->max_packet_sz_tx /
- packet_sz) - 1) << 11);
+ hw_ep->max_packet_sz_tx);
else
musb_writew(epio, MUSB_TXMAXP,
- packet_sz);
+ qh->maxpacket |
+ ((qh->hb_mult - 1) << 11));
musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg);
} else {
musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg);
@@ -1336,7 +1335,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
if (length > qh->maxpacket)
length = qh->maxpacket;
/* Unmap the buffer so that CPU can use it */
- unmap_urb_for_dma(musb_to_hcd(musb), urb);
+ usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
qh->segsize = length;
@@ -1758,7 +1757,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
if (!dma) {
/* Unmap the buffer so that CPU can use it */
- unmap_urb_for_dma(musb_to_hcd(musb), urb);
+ usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
done = musb_host_packet_rx(musb, urb,
epnum, iso_err);
DBG(6, "read %spacket\n", done ? "last " : "");
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index b46d1877e28..489104a5ae1 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -305,8 +305,8 @@ int musb_hub_control(
desc->bHubContrCurrent = 0;
/* workaround bogus struct definition */
- desc->DeviceRemovable[0] = 0x02; /* port 1 */
- desc->DeviceRemovable[1] = 0xff;
+ desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */
+ desc->u.hs.DeviceRemovable[1] = 0xff;
}
break;
case GetHubStatus:
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 0144a2d481f..d281792db05 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -169,6 +169,14 @@ static int dma_channel_program(struct dma_channel *channel,
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
+ /* Let targets check/tweak the arguments */
+ if (musb->ops->adjust_channel_params) {
+ int ret = musb->ops->adjust_channel_params(channel,
+ packet_sz, &mode, &dma_addr, &len);
+ if (ret)
+ return ret;
+ }
+
/*
* The DMA engine in RTL1.8 and above cannot handle
* DMA addresses that are not aligned to a 4 byte boundary.
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index f763d62f151..320fd4afb93 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -31,7 +31,7 @@
*
*/
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430)
#include "omap2430.h"
#endif
@@ -94,24 +94,33 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase,
{
musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW),
- ((u16)((u32) dma_addr & 0xFFFF)));
+ dma_addr);
musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH),
- ((u16)(((u32) dma_addr >> 16) & 0xFFFF)));
+ (dma_addr >> 16));
}
static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel)
{
- return musb_readl(mbase,
+ u32 count = musb_readw(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH));
+
+ count = count << 16;
+
+ count |= musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW));
+
+ return count;
}
static inline void musb_write_hsdma_count(void __iomem *mbase,
u8 bchannel, u32 len)
{
- musb_writel(mbase,
+ musb_writew(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),len);
+ musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH),
- len);
+ (len >> 16));
}
#endif /* CONFIG_BLACKFIN */
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index a3f12333fc4..57a27fa954b 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -33,6 +33,8 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/err.h>
#include "musb_core.h"
#include "omap2430.h"
@@ -40,7 +42,6 @@
struct omap2430_glue {
struct device *dev;
struct platform_device *musb;
- struct clk *clk;
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
@@ -216,20 +217,12 @@ static inline void omap2430_low_level_exit(struct musb *musb)
l = musb_readl(musb->mregs, OTG_FORCESTDBY);
l |= ENABLEFORCE; /* enable MSTANDBY */
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
-
- l = musb_readl(musb->mregs, OTG_SYSCONFIG);
- l |= ENABLEWAKEUP; /* enable wakeup */
- musb_writel(musb->mregs, OTG_SYSCONFIG, l);
}
static inline void omap2430_low_level_init(struct musb *musb)
{
u32 l;
- l = musb_readl(musb->mregs, OTG_SYSCONFIG);
- l &= ~ENABLEWAKEUP; /* disable wakeup */
- musb_writel(musb->mregs, OTG_SYSCONFIG, l);
-
l = musb_readl(musb->mregs, OTG_FORCESTDBY);
l &= ~ENABLEFORCE; /* disable MSTANDBY */
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
@@ -251,31 +244,40 @@ static int musb_otg_notifications(struct notifier_block *nb,
if (is_otg_enabled(musb)) {
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
if (musb->gadget_driver) {
+ pm_runtime_get_sync(musb->controller);
otg_init(musb->xceiv);
-
- if (data->interface_type ==
- MUSB_INTERFACE_UTMI)
- omap2430_musb_set_vbus(musb, 1);
-
+ omap2430_musb_set_vbus(musb, 1);
}
#endif
} else {
+ pm_runtime_get_sync(musb->controller);
otg_init(musb->xceiv);
- if (data->interface_type ==
- MUSB_INTERFACE_UTMI)
- omap2430_musb_set_vbus(musb, 1);
+ omap2430_musb_set_vbus(musb, 1);
}
break;
case USB_EVENT_VBUS:
DBG(4, "VBUS Connect\n");
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ if (musb->gadget_driver)
+ pm_runtime_get_sync(musb->controller);
+#endif
otg_init(musb->xceiv);
break;
case USB_EVENT_NONE:
DBG(4, "VBUS Disconnect\n");
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ if (is_otg_enabled(musb))
+ if (musb->gadget_driver)
+#endif
+ {
+ pm_runtime_mark_last_busy(musb->controller);
+ pm_runtime_put_autosuspend(musb->controller);
+ }
+
if (data->interface_type == MUSB_INTERFACE_UTMI) {
if (musb->xceiv->set_vbus)
otg_set_vbus(musb->xceiv, 0);
@@ -307,22 +309,11 @@ static int omap2430_musb_init(struct musb *musb)
return -ENODEV;
}
- omap2430_low_level_init(musb);
-
- l = musb_readl(musb->mregs, OTG_SYSCONFIG);
- l &= ~ENABLEWAKEUP; /* disable wakeup */
- l &= ~NOSTDBY; /* remove possible nostdby */
- l |= SMARTSTDBY; /* enable smart standby */
- l &= ~AUTOIDLE; /* disable auto idle */
- l &= ~NOIDLE; /* remove possible noidle */
- l |= SMARTIDLE; /* enable smart idle */
- /*
- * MUSB AUTOIDLE don't work in 3430.
- * Workaround by Richard Woodruff/TI
- */
- if (!cpu_is_omap3430())
- l |= AUTOIDLE; /* enable auto idle */
- musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+ status = pm_runtime_get_sync(dev);
+ if (status < 0) {
+ dev_err(dev, "pm_runtime_get_sync FAILED");
+ goto err1;
+ }
l = musb_readl(musb->mregs, OTG_INTERFSEL);
@@ -350,18 +341,63 @@ static int omap2430_musb_init(struct musb *musb)
if (status)
DBG(1, "notification register failed\n");
- /* check whether cable is already connected */
- if (musb->xceiv->state ==OTG_STATE_B_IDLE)
- musb_otg_notifications(&musb->nb, 1,
- musb->xceiv->gadget);
-
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
return 0;
+
+err1:
+ pm_runtime_disable(dev);
+ return status;
+}
+
+static void omap2430_musb_enable(struct musb *musb)
+{
+ u8 devctl;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *pdata = dev->platform_data;
+ struct omap_musb_board_data *data = pdata->board_data;
+
+ switch (musb->xceiv->last_event) {
+
+ case USB_EVENT_ID:
+ otg_init(musb->xceiv);
+ if (data->interface_type == MUSB_INTERFACE_UTMI) {
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ /* start the session */
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+ while (musb_readb(musb->mregs, MUSB_DEVCTL) &
+ MUSB_DEVCTL_BDEVICE) {
+ cpu_relax();
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(musb->controller,
+ "configured as A device timeout");
+ break;
+ }
+ }
+ }
+ break;
+
+ case USB_EVENT_VBUS:
+ otg_init(musb->xceiv);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void omap2430_musb_disable(struct musb *musb)
+{
+ if (musb->xceiv->last_event)
+ otg_shutdown(musb->xceiv);
}
static int omap2430_musb_exit(struct musb *musb)
{
+ del_timer_sync(&musb_idle_timer);
omap2430_low_level_exit(musb);
otg_put_transceiver(musb->xceiv);
@@ -377,6 +413,9 @@ static const struct musb_platform_ops omap2430_ops = {
.try_idle = omap2430_musb_try_idle,
.set_vbus = omap2430_musb_set_vbus,
+
+ .enable = omap2430_musb_enable,
+ .disable = omap2430_musb_disable,
};
static u64 omap2430_dmamask = DMA_BIT_MASK(32);
@@ -386,8 +425,6 @@ static int __init omap2430_probe(struct platform_device *pdev)
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
struct omap2430_glue *glue;
- struct clk *clk;
-
int ret = -ENOMEM;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
@@ -402,26 +439,12 @@ static int __init omap2430_probe(struct platform_device *pdev)
goto err1;
}
- clk = clk_get(&pdev->dev, "ick");
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "failed to get clock\n");
- ret = PTR_ERR(clk);
- goto err2;
- }
-
- ret = clk_enable(clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable clock\n");
- goto err3;
- }
-
musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &omap2430_dmamask;
musb->dev.coherent_dma_mask = omap2430_dmamask;
glue->dev = &pdev->dev;
glue->musb = musb;
- glue->clk = clk;
pdata->platform_ops = &omap2430_ops;
@@ -431,28 +454,24 @@ static int __init omap2430_probe(struct platform_device *pdev)
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
- goto err4;
+ goto err2;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err4;
+ goto err2;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
- goto err4;
+ goto err2;
}
- return 0;
-
-err4:
- clk_disable(clk);
+ pm_runtime_enable(&pdev->dev);
-err3:
- clk_put(clk);
+ return 0;
err2:
platform_device_put(musb);
@@ -470,61 +489,40 @@ static int __exit omap2430_remove(struct platform_device *pdev)
platform_device_del(glue->musb);
platform_device_put(glue->musb);
- clk_disable(glue->clk);
- clk_put(glue->clk);
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
kfree(glue);
return 0;
}
#ifdef CONFIG_PM
-static void omap2430_save_context(struct musb *musb)
-{
- musb->context.otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
- musb->context.otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
-}
-
-static void omap2430_restore_context(struct musb *musb)
-{
- musb_writel(musb->mregs, OTG_SYSCONFIG, musb->context.otg_sysconfig);
- musb_writel(musb->mregs, OTG_FORCESTDBY, musb->context.otg_forcestandby);
-}
-static int omap2430_suspend(struct device *dev)
+static int omap2430_runtime_suspend(struct device *dev)
{
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
omap2430_low_level_exit(musb);
otg_set_suspend(musb->xceiv, 1);
- omap2430_save_context(musb);
- clk_disable(glue->clk);
return 0;
}
-static int omap2430_resume(struct device *dev)
+static int omap2430_runtime_resume(struct device *dev)
{
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
- int ret;
-
- ret = clk_enable(glue->clk);
- if (ret) {
- dev_err(dev, "faled to enable clock\n");
- return ret;
- }
omap2430_low_level_init(musb);
- omap2430_restore_context(musb);
otg_set_suspend(musb->xceiv, 0);
return 0;
}
static struct dev_pm_ops omap2430_pm_ops = {
- .suspend = omap2430_suspend,
- .resume = omap2430_resume,
+ .runtime_suspend = omap2430_runtime_suspend,
+ .runtime_resume = omap2430_runtime_resume,
};
#define DEV_PM_OPS (&omap2430_pm_ops)
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 2ba3b070ed0..c47aac4a1f9 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -943,7 +943,7 @@ static void tusb_musb_enable(struct musb *musb)
musb_writel(tbase, TUSB_INT_CTRL_CONF,
TUSB_INT_CTRL_CONF_INT_RELCYC(0));
- set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW);
+ irq_set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW);
/* maybe force into the Default-A OTG state machine */
if (!(musb_readl(tbase, TUSB_DEV_OTG_STAT)
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index c061a88f2b0..99cb541e4ef 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -680,7 +680,7 @@ dma_controller_create(struct musb *musb, void __iomem *base)
tusb_dma = kzalloc(sizeof(struct tusb_omap_dma), GFP_KERNEL);
if (!tusb_dma)
- goto cleanup;
+ goto out;
tusb_dma->musb = musb;
tusb_dma->tbase = musb->ctrl_base;
@@ -721,6 +721,6 @@ dma_controller_create(struct musb *musb, void __iomem *base)
cleanup:
dma_controller_destroy(&tusb_dma->controller);
-
+out:
return NULL;
}
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index d6384e4aeef..f7e04bf34a1 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -93,6 +93,8 @@ static int __init ux500_probe(struct platform_device *pdev)
}
musb->dev.parent = &pdev->dev;
+ musb->dev.dma_mask = pdev->dev.dma_mask;
+ musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
glue->dev = &pdev->dev;
glue->musb = musb;