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. 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@xxxxxxxxxxx> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- drivers/usb/gadget/s3c-hsotg.c | 30 +++++++++++++++++++----------- 1 files changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 02a3142..ad2ecce 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -144,7 +144,8 @@ struct s3c_hsotg_ep { * @ep0_buff: Buffer for EP0 reply data, if needed. * @ctrl_buff: Buffer for EP0 control requests. * @ctrl_req: Request for EP0 control packets. - * @setup: NAK management for EP0 SETUP + * @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[]; }; @@ -2391,23 +2393,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 */ @@ -2450,6 +2455,7 @@ irq_retry: writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS); call_gadget(hsotg, suspend); + s3c_hsotg_disconnect(hsotg); } if (gintsts & S3C_GINTSTS_WkUpInt) { @@ -2462,6 +2468,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 @@ -2804,7 +2812,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; -- 1.7.2.3 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html