diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-03-01 21:20:28 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-03-01 21:20:28 +0400 |
commit | f9b0f5170918695891f42645737682ccb452ee13 (patch) | |
tree | 75eaab0ff54f8aadaa6375df140cc9d685f78d95 /drivers/usb/renesas_usbhs | |
parent | 8062d94a545457a83d5291bd62c3bfd14200bba0 (diff) | |
parent | 6440093f5eae9842feb06e40d41c3bd569b6b461 (diff) | |
download | linux-f9b0f5170918695891f42645737682ccb452ee13.tar.xz |
Merge tag 'gadget-for-v3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
USB: Gadget: changes for 3.4
This merge is rather big. Here's what it contains:
For am5536udc we have just simple coding style fixes. Nothing that has any
potential to cause any issues going forward.
With mv_udc, there's only one single change removing an unneeded NULL check.
at91_udc also only saw a single change this merge window, and that's only
removing a duplicated header.
The Renesas controller has a few more involved changes. Support for SUDMAC was
added, there's now a special handling of IRQ resources for when the IRQ line is
shared between Renesas controller and SUDMAC, we also had a bug fix where
Renesas controller would sleep in atomic context while doing DMA transfers from
a tasklet. There were also a set of minor cleanups.
The FSL UDC also had a scheduling in atomic context bug fix, but that's all.
Thanks to Sebastian, the dummy_hcd now works better than ever with support for
scatterlists and streams. Sebastian also added SuperSpeed descriptors to the
serial gadgets.
The highlight on this merge is the addition of a generic API for mapping and
unmapping usb_requests. This will avoid code duplication on all UDC controllers
and also kills all the defines for DMA_ADDR_INVALID which UDC controllers
sprinkled around. A few of the UDC controllers were already converted to use
this new API.
Conflicts:
drivers/usb/dwc3/gadget.c
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r-- | drivers/usb/renesas_usbhs/common.c | 11 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/common.h | 1 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.c | 29 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.h | 3 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod.c | 2 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod_gadget.c | 79 |
6 files changed, 46 insertions, 79 deletions
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index e9a5b1d2615e..a165490bae48 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -413,8 +413,7 @@ static int usbhs_probe(struct platform_device *pdev) struct renesas_usbhs_platform_info *info = pdev->dev.platform_data; struct renesas_usbhs_driver_callback *dfunc; struct usbhs_priv *priv; - struct resource *res; - unsigned int irq; + struct resource *res, *irq_res; int ret; /* check platform information */ @@ -426,8 +425,8 @@ static int usbhs_probe(struct platform_device *pdev) /* platform data */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || (int)irq <= 0) { + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res || !irq_res) { dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n"); return -ENODEV; } @@ -476,7 +475,9 @@ static int usbhs_probe(struct platform_device *pdev) /* * priv settings */ - priv->irq = irq; + priv->irq = irq_res->start; + if (irq_res->flags & IORESOURCE_IRQ_SHAREABLE) + priv->irqflags = IRQF_SHARED; priv->pdev = pdev; INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug); spin_lock_init(usbhs_priv_to_lock(priv)); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index d79b3e27db95..3f3ccd358753 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -242,6 +242,7 @@ struct usbhs_priv { void __iomem *base; unsigned int irq; + unsigned long irqflags; struct renesas_usbhs_platform_callback pfunc; struct renesas_usbhs_driver_param dparam; diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 72339bd6fcab..3648c82a17fe 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -23,6 +23,7 @@ #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) #define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo)) #define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo)) +#define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f) #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ @@ -75,8 +76,7 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, pipe->handler = &usbhsf_null_handler; } - list_del_init(&pkt->node); - list_add_tail(&pkt->node, &pipe->list); + list_move_tail(&pkt->node, &pipe->list); /* * each pkt must hold own handler. @@ -106,7 +106,7 @@ static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) if (list_empty(&pipe->list)) return NULL; - return list_entry(pipe->list.next, struct usbhs_pkt, node); + return list_first_entry(&pipe->list, struct usbhs_pkt, node); } struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) @@ -305,7 +305,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe, } /* "base" will be used below */ - usbhs_write(priv, fifo->sel, base | MBW_32); + if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo)) + usbhs_write(priv, fifo->sel, base); + else + usbhs_write(priv, fifo->sel, base | MBW_32); /* check ISEL and CURPIPE value */ while (timeout--) { @@ -762,9 +765,9 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) } static void usbhsf_dma_complete(void *arg); -static void usbhsf_dma_prepare_tasklet(unsigned long data) +static void xfer_work(struct work_struct *work) { - struct usbhs_pkt *pkt = (struct usbhs_pkt *)data; + struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work); struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); @@ -844,11 +847,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) pkt->trans = len; - tasklet_init(&fifo->tasklet, - usbhsf_dma_prepare_tasklet, - (unsigned long)pkt); - - tasklet_schedule(&fifo->tasklet); + INIT_WORK(&pkt->work, xfer_work); + schedule_work(&pkt->work); return 0; @@ -938,11 +938,8 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) pkt->trans = len; - tasklet_init(&fifo->tasklet, - usbhsf_dma_prepare_tasklet, - (unsigned long)pkt); - - tasklet_schedule(&fifo->tasklet); + INIT_WORK(&pkt->work, xfer_work); + schedule_work(&pkt->work); return 0; diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index f68609c0f489..c31731a843d1 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/sh_dma.h> +#include <linux/workqueue.h> #include <asm/dma.h> #include "pipe.h" @@ -31,7 +32,6 @@ struct usbhs_fifo { u32 ctr; /* xFIFOCTR */ struct usbhs_pipe *pipe; - struct tasklet_struct tasklet; struct dma_chan *tx_chan; struct dma_chan *rx_chan; @@ -53,6 +53,7 @@ struct usbhs_pkt { struct usbhs_pkt_handle *handler; void (*done)(struct usbhs_priv *priv, struct usbhs_pkt *pkt); + struct work_struct work; dma_addr_t dma; void *buf; int length; diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 1b97fb12694b..0871e816df45 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -152,7 +152,7 @@ int usbhs_mod_probe(struct usbhs_priv *priv) /* irq settings */ ret = request_irq(priv->irq, usbhs_interrupt, - 0, dev_name(dev), priv); + priv->irqflags, dev_name(dev), priv); if (ret) { dev_err(dev, "irq request err\n"); goto mod_init_gadget_err; diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 7542aa94a462..00bd2a5e0362 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -165,69 +165,32 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep, /* * dma map/unmap */ -static int usbhsg_dma_map(struct device *dev, - struct usbhs_pkt *pkt, - enum dma_data_direction dir) -{ - struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); - struct usb_request *req = &ureq->req; - - if (pkt->dma != DMA_ADDR_INVALID) { - dev_err(dev, "dma is already mapped\n"); - return -EIO; - } - - if (req->dma == DMA_ADDR_INVALID) { - pkt->dma = dma_map_single(dev, pkt->buf, pkt->length, dir); - } else { - dma_sync_single_for_device(dev, req->dma, req->length, dir); - pkt->dma = req->dma; - } - - if (dma_mapping_error(dev, pkt->dma)) { - dev_err(dev, "dma mapping error %llx\n", (u64)pkt->dma); - return -EIO; - } - - return 0; -} - -static int usbhsg_dma_unmap(struct device *dev, - struct usbhs_pkt *pkt, - enum dma_data_direction dir) +static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map) { struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); struct usb_request *req = &ureq->req; - - if (pkt->dma == DMA_ADDR_INVALID) { - dev_err(dev, "dma is not mapped\n"); - return -EIO; - } - - if (req->dma == DMA_ADDR_INVALID) - dma_unmap_single(dev, pkt->dma, pkt->length, dir); - else - dma_sync_single_for_cpu(dev, req->dma, req->length, dir); - - pkt->dma = DMA_ADDR_INVALID; - - return 0; -} - -static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map) -{ struct usbhs_pipe *pipe = pkt->pipe; struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); enum dma_data_direction dir; + int ret = 0; - dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + dir = usbhs_pipe_is_dir_host(pipe); - if (map) - return usbhsg_dma_map(dev, pkt, dir); - else - return usbhsg_dma_unmap(dev, pkt, dir); + if (map) { + /* it can not use scatter/gather */ + WARN_ON(req->num_sgs); + + ret = usb_gadget_map_request(&gpriv->gadget, req, dir); + if (ret < 0) + return ret; + + pkt->dma = req->dma; + } else { + usb_gadget_unmap_request(&gpriv->gadget, req, dir); + } + + return ret; } /* @@ -657,8 +620,6 @@ static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq)); - ureq->req.dma = DMA_ADDR_INVALID; - return &ureq->req; } @@ -941,6 +902,11 @@ static int usbhsg_stop(struct usbhs_priv *priv) return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED); } +static void usbhs_mod_gadget_release(struct device *pdev) +{ + /* do nothing */ +} + int usbhs_mod_gadget_probe(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv; @@ -989,6 +955,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) */ dev_set_name(&gpriv->gadget.dev, "gadget"); gpriv->gadget.dev.parent = dev; + gpriv->gadget.dev.release = usbhs_mod_gadget_release; gpriv->gadget.name = "renesas_usbhs_udc"; gpriv->gadget.ops = &usbhsg_gadget_ops; gpriv->gadget.max_speed = USB_SPEED_HIGH; |