summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukasz Majewski <l.majewski@samsung.com>2012-05-04 14:17:08 +0200
committerFelipe Balbi <balbi@ti.com>2012-05-04 15:53:14 +0300
commit12a1f4dc0dfe4c72e565dc02d6a1c021f3f98b61 (patch)
treefa9c3414a5cdc802368f67c05b79a639a10ebba2
parent5e891342fd0761fed36c187587115e706c0fa358 (diff)
downloadop-kernel-dev-12a1f4dc0dfe4c72e565dc02d6a1c021f3f98b61.zip
op-kernel-dev-12a1f4dc0dfe4c72e565dc02d6a1c021f3f98b61.tar.gz
usb:hsotg:samsung: Cable disconnection recovery code
This code allows Samsung SoC's to recover its state when device is disconnected and connected during transfer. It is necessary, in such a scenario, to reinitialize the USB core to assure correct initial state of the driver. This operation is needed since the disconnect interrupt is only available at HOST mode, which is not supported by this driver. A simple mechanism with jiffies has been used to perform core reset only once. Tested with: - DFU gadget (various size of the sent data - also packet = MPS) - Ethernet gadget (CDC and RNDIS) - Multi Function Gadget (g_multi) HW: - Samsung's C210 Universal rev.0 Signed-off-by: Lukasz Majewski <l.majewski@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 7e3b591..ca90416 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -148,6 +148,7 @@ struct s3c_hsotg_ep {
* @ctrl_buff: Buffer for EP0 control requests.
* @ctrl_req: Request for EP0 control packets.
* @setup: NAK management for EP0 SETUP
+ * @last_rst: Time of last reset
* @eps: The endpoints being supplied to the gadget framework
*/
struct s3c_hsotg {
@@ -175,6 +176,7 @@ struct s3c_hsotg {
struct usb_gadget gadget;
unsigned int setup;
+ unsigned long last_rst;
struct s3c_hsotg_ep eps[];
};
@@ -2377,23 +2379,26 @@ irq_retry:
}
if (gintsts & S3C_GINTSTS_USBRst) {
+
+ u32 usb_status = readl(hsotg->regs + S3C_GOTGCTL);
+
dev_info(hsotg->dev, "%s: USBRst\n", __func__);
dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
readl(hsotg->regs + S3C_GNPTXSTS));
writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
- kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
+ if (usb_status & S3C_GOTGCTL_BSESVLD) {
+ if (time_after(jiffies, hsotg->last_rst +
+ msecs_to_jiffies(200))) {
- /* it seems after a reset we can end up with a situation
- * where the TXFIFO still has data in it... the docs
- * suggest resetting all the fifos, so use the init_fifo
- * code to relayout and flush the fifos.
- */
+ kill_all_requests(hsotg, &hsotg->eps[0],
+ -ECONNRESET, true);
- s3c_hsotg_init_fifo(hsotg);
-
- s3c_hsotg_enqueue_setup(hsotg);
+ s3c_hsotg_core_init(hsotg);
+ hsotg->last_rst = jiffies;
+ }
+ }
}
/* check both FIFOs */
@@ -2436,6 +2441,7 @@ irq_retry:
writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);
call_gadget(hsotg, suspend);
+ s3c_hsotg_disconnect(hsotg);
}
if (gintsts & S3C_GINTSTS_WkUpInt) {
@@ -2448,6 +2454,8 @@ irq_retry:
if (gintsts & S3C_GINTSTS_ErlySusp) {
dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");
writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);
+
+ s3c_hsotg_disconnect(hsotg);
}
/* these next two seem to crop-up occasionally causing the core
@@ -2823,7 +2831,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
}
s3c_hsotg_core_init(hsotg);
-
+ hsotg->last_rst = jiffies;
dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
return 0;
OpenPOWER on IntegriCloud