Skip to content

Commit

Permalink
dwc2-hcd: perform port reset request synchronously
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Arlott <sa.me.uk>
  • Loading branch information
nomis committed Jun 3, 2012
1 parent 713b7e2 commit 9a90499
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 32 deletions.
44 changes: 29 additions & 15 deletions drivers/usb/host/dwc2-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ static irqreturn_t dwc2_hcd_irq(struct usb_hcd *hcd)
if (status & DWC_RESET_DETECT_INT)
dev_warn(dwc->dev, "%s: DWC_RESET_DETECT_INT\n", __func__);

/* FIXME: remove this and the copy of the _chg flags */
if (status & DWC_PORT_INT) {
dev_dbg(dwc->dev, "%s: DWC_PORT_INT\n", __func__);

Expand Down Expand Up @@ -756,7 +755,7 @@ static int dwc2_hcd_hub_control(struct usb_hcd *hcd,
}

case SetPortFeature: {
int ret;
int ret, i;

if (wIndex != 1)
break;
Expand All @@ -777,12 +776,37 @@ static int dwc2_hcd_hub_control(struct usb_hcd *hcd,
dev_dbg(dwc->dev, "SetPortFeature USB_PORT_FEAT_RESET\n");
spin_lock_irq(&dwc->lock);
dwc2_hcd_get_hprt(hcd);

/* Perform port reset */
dwc->disable = false;
dwc->reset_req = true;
dwc->reset_res = false;
dwc->hprt.reset = true;
dwc2_hcd_set_hprt(hcd);

/* Wait for it to complete */
for (i = 0; i < DWC_PORT_RESET_TIMEOUT; i++) {
dwc2_hcd_get_hprt(hcd);
if (dwc->reset_res) {
dev_dbg(dwc->dev,
"%s: port reset in %d\n",
__func__, i+1);
break;
}
udelay(1);
}
if (i == DWC_PORT_RESET_TIMEOUT) {
dev_err(dwc->dev, "%s: port reset did not complete", __func__);
/* Cancel reset */
dwc->reset_req = false;
dwc->reset_res = false;
dwc2_hcd_set_hprt(hcd);
ret = -ETIMEDOUT;
} else {
ret = 0;
}

spin_unlock_irq(&dwc->lock);
return 0;
return ret;
}
break;
}
Expand Down Expand Up @@ -852,17 +876,7 @@ static int dwc2_hcd_hub_control(struct usb_hcd *hcd,

spin_lock_irq(&dwc->lock);
dev_dbg(dwc->dev, "GetPortStatus:\n");

if (dwc->reset_req && !dwc->reset_res) {
dwc2_hcd_get_hprt(hcd);
if (dwc->reset_res) {
dwc2_hcd_set_hprt(hcd);
dwc2_hcd_get_hprt(hcd);
if (!dwc->hprt.enable)
dwc2_hcd_get_hprt(hcd);
}
}


if (dwc->connect) {
dev_dbg(dwc->dev, "USB_PORT_STAT_C_CONNECTION\n");
status |= USB_PORT_STAT_C_CONNECTION << 16;
Expand Down
42 changes: 25 additions & 17 deletions drivers/usb/host/dwc2-hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#define DWC_AHB_TIMEOUT 10000
#define DWC_FIFO_FLUSH_TIMEOUT 10000
#define DWC_CHAN_HALT_TIMEOUT 10000
#define DWC_PORT_RESET_TIMEOUT 10000
#define DWC_RX_FIFO_SZ 20480 /* 16 to 32768 */
#define DWC_NP_TX_FIFO_SZ 20480 /* 16 to 32768 */
#define DWC_HP_TX_FIFO_SZ 20480 /* 16 to 32768 */
Expand Down Expand Up @@ -662,6 +663,24 @@ static void dwc2_hcd_set_lpm_cfg(struct usb_hcd *hcd)
__func__, value, dwc->__lpm_cfg);
}

static void dwc2_hcd_set_hprt(struct usb_hcd *hcd)
{
struct dwc2_hcd *dwc = hcd_to_dwc(hcd);
dwc->hprt.connect_chg = false;
dwc->hprt.enable_chg = false;
dwc->hprt.overcurrent_chg = false;

/* Send enable after a reset or the port will be disabled */
dwc->hprt.enable = !dwc->disable;

/* Send reset until successful or the reset will be aborted */
dwc->hprt.reset = dwc->reset_req;

dev_dbg(dwc->dev, "%s: e=%d r=%d\n", __func__, dwc->hprt.enable,
dwc->hprt.reset);
writel(dwc->__hprt, hcd->regs + DWC_HOST_PORT_REG);
}

static void dwc2_hcd_get_hprt(struct usb_hcd *hcd)
{
struct dwc2_hcd *dwc = hcd_to_dwc(hcd);
Expand All @@ -678,32 +697,21 @@ static void dwc2_hcd_get_hprt(struct usb_hcd *hcd)

/* Clear reset */
dwc->hprt.reset = false;
} else if (dwc->reset_req) {
/* Send reset until successful or the reset will be aborted */
dwc->hprt.reset = true;
dwc2_hcd_set_hprt(hcd);
}
}

static void dwc2_hcd_set_hprt(struct usb_hcd *hcd)
{
struct dwc2_hcd *dwc = hcd_to_dwc(hcd);
dwc->hprt.connect_chg = false;
dwc->hprt.enable_chg = false;
dwc->hprt.overcurrent_chg = false;
/* Send enable after a reset or the port will be disabled */
dwc->hprt.enable = !dwc->disable;
dev_dbg(dwc->dev, "%s: e=%d r=%d\n", __func__, dwc->hprt.enable,
dwc->hprt.reset);
writel(dwc->__hprt, hcd->regs + DWC_HOST_PORT_REG);
dwc->reset_req = dwc->hprt.reset;
}

static void dwc2_hcd_ack_hprt(struct usb_hcd *hcd)
{
struct dwc2_hcd *dwc = hcd_to_dwc(hcd);
dwc2_hcd_get_hprt(hcd);

/* Send enable after a reset or the port will be disabled */
dwc->hprt.enable = !dwc->disable;

/* Send reset until successful or the reset will be aborted */
dwc->hprt.reset = dwc->reset_req;

dev_dbg(dwc->dev, "%s: e=%d r=%d\n", __func__, dwc->hprt.enable,
dwc->hprt.reset);
writel(dwc->__hprt, hcd->regs + DWC_HOST_PORT_REG);
Expand Down

0 comments on commit 9a90499

Please sign in to comment.