Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1479e841 authored by Robert Baldyga's avatar Robert Baldyga Committed by Felipe Balbi
Browse files

usb: gadget: s3c-hsotg: add isochronous transfers support



This patch adds isochronous transfer support. It adds few modifications:
- Modify s3c_hsotg_epint() function. Some interrupts are ignored for
  isochronous endpoints, (e.g. INTknTXFEmpMsk) becouse isochronous request is
  always transfered in single transaction, which ends with XferCompl interrupt.
- Add Odd/Even microframe toggle to allow data transfering in each microframe
  in s3c_hsotg_epint() function.
- Fix s3c_hsotg_ep_enable() function by supporting isochronous endpoint type.

Signed-off-by: default avatarRobert Baldyga <r.baldyga@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 16b972a5
Loading
Loading
Loading
Loading
+23 −4
Original line number Diff line number Diff line
@@ -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;