|
@@ -83,9 +83,11 @@ struct s3c_hsotg_req;
|
|
|
* @dir_in: Set to true if this endpoint is of the IN direction, which
|
|
|
* means that it is sending data to the Host.
|
|
|
* @index: The index for the endpoint registers.
|
|
|
+ * @interval - Interval for periodic endpoints
|
|
|
* @name: The name array passed to the USB core.
|
|
|
* @halted: Set if the endpoint has been halted.
|
|
|
* @periodic: Set if this is a periodic ep, such as Interrupt
|
|
|
+ * @isochronous: Set if this is a isochronous ep
|
|
|
* @sent_zlp: Set if we've sent a zero-length packet.
|
|
|
* @total_data: The total number of data bytes done.
|
|
|
* @fifo_size: The size of the FIFO (for periodic IN endpoints)
|
|
@@ -121,9 +123,11 @@ struct s3c_hsotg_ep {
|
|
|
|
|
|
unsigned char dir_in;
|
|
|
unsigned char index;
|
|
|
+ unsigned char interval;
|
|
|
|
|
|
unsigned int halted:1;
|
|
|
unsigned int periodic:1;
|
|
|
+ unsigned int isochronous:1;
|
|
|
unsigned int sent_zlp:1;
|
|
|
|
|
|
char name[10];
|
|
@@ -1886,8 +1890,10 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|
|
u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
|
|
|
u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);
|
|
|
u32 ints;
|
|
|
+ u32 ctrl;
|
|
|
|
|
|
ints = readl(hsotg->regs + epint_reg);
|
|
|
+ ctrl = readl(hsotg->regs + epctl_reg);
|
|
|
|
|
|
/* Clear endpoint interrupts */
|
|
|
writel(ints, hsotg->regs + epint_reg);
|
|
@@ -1896,6 +1902,14 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|
|
__func__, idx, dir_in ? "in" : "out", ints);
|
|
|
|
|
|
if (ints & DxEPINT_XferCompl) {
|
|
|
+ if (hs_ep->isochronous && hs_ep->interval == 1) {
|
|
|
+ if (ctrl & DxEPCTL_EOFrNum)
|
|
|
+ ctrl |= DxEPCTL_SetEvenFr;
|
|
|
+ else
|
|
|
+ ctrl |= DxEPCTL_SetOddFr;
|
|
|
+ writel(ctrl, hsotg->regs + epctl_reg);
|
|
|
+ }
|
|
|
+
|
|
|
dev_dbg(hsotg->dev,
|
|
|
"%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n",
|
|
|
__func__, readl(hsotg->regs + epctl_reg),
|
|
@@ -1962,7 +1976,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|
|
if (ints & DxEPINT_Back2BackSetup)
|
|
|
dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
|
|
|
|
|
|
- if (dir_in) {
|
|
|
+ if (dir_in && !hs_ep->isochronous) {
|
|
|
/* not sure if this is important, but we'll clear it anyway */
|
|
|
if (ints & DIEPMSK_INTknTXFEmpMsk) {
|
|
|
dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
|
|
@@ -2581,13 +2595,18 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
|
|
|
s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps);
|
|
|
|
|
|
/* default, set to non-periodic */
|
|
|
+ hs_ep->isochronous = 0;
|
|
|
hs_ep->periodic = 0;
|
|
|
+ hs_ep->interval = desc->bInterval;
|
|
|
|
|
|
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
|
|
|
case USB_ENDPOINT_XFER_ISOC:
|
|
|
- dev_err(hsotg->dev, "no current ISOC support\n");
|
|
|
- ret = -EINVAL;
|
|
|
- goto out;
|
|
|
+ epctrl |= DxEPCTL_EPType_Iso;
|
|
|
+ epctrl |= DxEPCTL_SetEvenFr;
|
|
|
+ hs_ep->isochronous = 1;
|
|
|
+ if (dir_in)
|
|
|
+ hs_ep->periodic = 1;
|
|
|
+ break;
|
|
|
|
|
|
case USB_ENDPOINT_XFER_BULK:
|
|
|
epctrl |= DxEPCTL_EPType_Bulk;
|