summaryrefslogtreecommitdiff
path: root/drivers/usb/chipidea
diff options
context:
space:
mode:
authorMichael Grzeschik <mgr@pengutronix.de>2013-06-13 17:59:47 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-17 13:45:46 -0700
commite4ce4ecd962e17a92974b3c7ba063d29fce8c86f (patch)
tree2671f6d09147c13d91eab6aff1717153037dbc18 /drivers/usb/chipidea
parentf6a57507f685bb24b83893a12e65623a2fc69489 (diff)
usb: chipidea: udc: configure iso endpoints
This patch adds iso endpoint support to the device controller. It makes use of the multiplication bits in the maxpacket field of the endpoint and calculates the multiplier bits for each transfer description on every request. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Reviewed-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/chipidea')
-rw-r--r--drivers/usb/chipidea/core.c2
-rw-r--r--drivers/usb/chipidea/udc.c20
-rw-r--r--drivers/usb/chipidea/udc.h1
3 files changed, 21 insertions, 2 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 475c9c114689..ade1b91b5ae7 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -43,7 +43,7 @@
*
* TODO List
* - OTG
- * - Isochronous & Interrupt Traffic
+ * - Interrupt Traffic
* - Handle requests which spawns into several TDs
* - GET_STATUS(device) - always reports 0
* - Gadget API (majority of optional features)
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index b501346484ae..8aed28855c04 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -466,6 +466,14 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
mEp->qh.ptr->td.token &=
cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
+ if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
+ u32 mul = mReq->req.length / mEp->ep.maxpacket;
+
+ if (mReq->req.length % mEp->ep.maxpacket)
+ mul++;
+ mEp->qh.ptr->cap |= mul << __ffs(QH_MULT);
+ }
+
wmb(); /* synchronize before ep prime */
ret = hw_ep_prime(ci, mEp->num, mEp->dir,
@@ -678,6 +686,12 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
}
}
+ if (usb_endpoint_xfer_isoc(mEp->ep.desc) &&
+ mReq->req.length > (1 + mEp->ep.mult) * mEp->ep.maxpacket) {
+ dev_err(mEp->ci->dev, "request length too big for isochronous\n");
+ return -EMSGSIZE;
+ }
+
/* first nuke then test link, e.g. previous status has not sent */
if (!list_empty(&mReq->queue)) {
dev_err(mEp->ci->dev, "request already in queue\n");
@@ -1060,7 +1074,8 @@ static int ep_enable(struct usb_ep *ep,
mEp->num = usb_endpoint_num(desc);
mEp->type = usb_endpoint_type(desc);
- mEp->ep.maxpacket = usb_endpoint_maxp(desc);
+ mEp->ep.maxpacket = usb_endpoint_maxp(desc) & 0x07ff;
+ mEp->ep.mult = QH_ISO_MULT(usb_endpoint_maxp(desc));
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
cap |= QH_IOS;
@@ -1246,6 +1261,9 @@ static int ep_set_halt(struct usb_ep *ep, int value)
if (ep == NULL || mEp->ep.desc == NULL)
return -EINVAL;
+ if (usb_endpoint_xfer_isoc(mEp->ep.desc))
+ return -EOPNOTSUPP;
+
spin_lock_irqsave(mEp->lock, flags);
#ifndef STALL_IN
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index d12e8b59b110..a75724a19e1a 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -50,6 +50,7 @@ struct ci13xxx_qh {
#define QH_MAX_PKT (0x07FFUL << 16)
#define QH_ZLT BIT(29)
#define QH_MULT (0x0003UL << 30)
+#define QH_ISO_MULT(x) ((x >> 11) & 0x03)
/* 1 */
u32 curr;
/* 2 - 8 */