summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVahram Aharonyan <vahrama@synopsys.com>2016-11-14 19:16:51 -0800
committerDongwoo Lee <dwoo08.lee@samsung.com>2018-11-08 08:56:36 +0900
commit1b3b85b1bd08ce9fea99852fa083787c7e02c995 (patch)
treef28c7863694701a47d6efabe2837769fc333d7d5
parente7904206b6fd76f7e651a1d4da2167cc44f80901 (diff)
downloadlinux-artik7-1b3b85b1bd08ce9fea99852fa083787c7e02c995.tar.gz
linux-artik7-1b3b85b1bd08ce9fea99852fa083787c7e02c995.tar.bz2
linux-artik7-1b3b85b1bd08ce9fea99852fa083787c7e02c995.zip
usb: dwc2: gadget: Correct dwc2_hsotg_ep_stop_xfr() function
Correct dwc2_hsotg_ep_stop_xfr() function to follow dwc2 programming guide for setting NAK on specific endpoint, disabling it and flushing corresponding FIFO. Current code does not take into account whether core acts in shared or dedicated FIFO mode, current endpoint is periodic or not. It does not clear EPDISBLD interrupt after programming of DXEPCTL_EPDIS, does not flush shared TX FIFO and tries to clear global out NAK in wrong manner instead of setting DCTL_CGOUTNAK. Signed-off-by: Vahram Aharonyan <vahrama@synopsys.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> [dwoo08.lee: back-ported from upstream commit ae79dd5dddb6] Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com> Change-Id: I8017bc33d0c8024ff9d46992727d2930769b8dab
-rw-r--r--drivers/usb/dwc2/gadget.c64
1 files changed, 41 insertions, 23 deletions
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index fc88bcb1b7f4..17914135a536 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -2987,23 +2987,35 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
DOEPINT(hs_ep->index);
dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__,
- hs_ep->name);
+ hs_ep->name);
+
if (hs_ep->dir_in) {
- __orr32(hsotg->regs + epctrl_reg, DXEPCTL_SNAK);
- /* Wait for Nak effect */
- if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg,
- DXEPINT_INEPNAKEFF, 100))
- dev_warn(hsotg->dev,
- "%s: timeout DIEPINT.NAKEFF\n", __func__);
+ if (hsotg->dedicated_fifos || hs_ep->periodic) {
+ __orr32(hsotg->regs + epctrl_reg, DXEPCTL_SNAK);
+ /* Wait for Nak effect */
+ if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg,
+ DXEPINT_INEPNAKEFF, 100))
+ dev_warn(hsotg->dev,
+ "%s: timeout DIEPINT.NAKEFF\n",
+ __func__);
+ } else {
+ __orr32(hsotg->regs + DCTL, DCTL_SGNPINNAK);
+ /* Wait for Nak effect */
+ if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
+ GINTSTS_GINNAKEFF, 100))
+ dev_warn(hsotg->dev,
+ "%s: timeout GINTSTS.GINNAKEFF\n",
+ __func__);
+ }
} else {
if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF))
__orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
/* Wait for global nak to take effect */
if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
- GINTSTS_GOUTNAKEFF, 100))
- dev_warn(hsotg->dev,
- "%s: timeout GINTSTS.GOUTNAKEFF\n", __func__);
+ GINTSTS_GOUTNAKEFF, 100))
+ dev_warn(hsotg->dev, "%s: timeout GINTSTS.GOUTNAKEFF\n",
+ __func__);
}
/* Disable ep */
@@ -3012,23 +3024,29 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
/* Wait for ep to be disabled */
if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100))
dev_warn(hsotg->dev,
- "%s: timeout DOEPCTL.EPDisable\n", __func__);
+ "%s: timeout DOEPCTL.EPDisable\n", __func__);
+
+ /* Clear EPDISBLD interrupt */
+ __orr32(hsotg->regs + epint_reg, DXEPINT_EPDISBLD);
if (hs_ep->dir_in) {
- if (hsotg->dedicated_fifos) {
- dwc2_writel(GRSTCTL_TXFNUM(hs_ep->fifo_index) |
- GRSTCTL_TXFFLSH, hsotg->regs + GRSTCTL);
- /* Wait for fifo flush */
- if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL,
- GRSTCTL_TXFFLSH, 100))
- dev_warn(hsotg->dev,
- "%s: timeout flushing fifos\n",
- __func__);
- }
- /* TODO: Flush shared tx fifo */
+ unsigned short fifo_index;
+
+ if (hsotg->dedicated_fifos || hs_ep->periodic)
+ fifo_index = hs_ep->fifo_index;
+ else
+ fifo_index = 0;
+
+ /* Flush TX FIFO */
+ dwc2_flush_tx_fifo(hsotg, fifo_index);
+
+ /* Clear Global In NP NAK in Shared FIFO for non periodic ep */
+ if (!hsotg->dedicated_fifos && !hs_ep->periodic)
+ __orr32(hsotg->regs + DCTL, DCTL_CGNPINNAK);
+
} else {
/* Remove global NAKs */
- __bic32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
+ __orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK);
}
}