提交 12a1f4dc 编写于 作者: L Lukasz Majewski 提交者: Felipe Balbi

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: NLukasz Majewski <l.majewski@samsung.com>
Signed-off-by: NKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: NFelipe Balbi <balbi@ti.com>
上级 5e891342
...@@ -148,6 +148,7 @@ struct s3c_hsotg_ep { ...@@ -148,6 +148,7 @@ struct s3c_hsotg_ep {
* @ctrl_buff: Buffer for EP0 control requests. * @ctrl_buff: Buffer for EP0 control requests.
* @ctrl_req: Request for EP0 control packets. * @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 * @eps: The endpoints being supplied to the gadget framework
*/ */
struct s3c_hsotg { struct s3c_hsotg {
...@@ -175,6 +176,7 @@ struct s3c_hsotg { ...@@ -175,6 +176,7 @@ struct s3c_hsotg {
struct usb_gadget gadget; struct usb_gadget gadget;
unsigned int setup; unsigned int setup;
unsigned long last_rst;
struct s3c_hsotg_ep eps[]; struct s3c_hsotg_ep eps[];
}; };
...@@ -2377,23 +2379,26 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2377,23 +2379,26 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
} }
if (gintsts & S3C_GINTSTS_USBRst) { if (gintsts & S3C_GINTSTS_USBRst) {
u32 usb_status = readl(hsotg->regs + S3C_GOTGCTL);
dev_info(hsotg->dev, "%s: USBRst\n", __func__); dev_info(hsotg->dev, "%s: USBRst\n", __func__);
dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
readl(hsotg->regs + S3C_GNPTXSTS)); readl(hsotg->regs + S3C_GNPTXSTS));
writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS); 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 +
/* it seems after a reset we can end up with a situation msecs_to_jiffies(200))) {
* 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.
*/
s3c_hsotg_init_fifo(hsotg); kill_all_requests(hsotg, &hsotg->eps[0],
-ECONNRESET, true);
s3c_hsotg_enqueue_setup(hsotg); s3c_hsotg_core_init(hsotg);
hsotg->last_rst = jiffies;
}
}
} }
/* check both FIFOs */ /* check both FIFOs */
...@@ -2436,6 +2441,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2436,6 +2441,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS); writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);
call_gadget(hsotg, suspend); call_gadget(hsotg, suspend);
s3c_hsotg_disconnect(hsotg);
} }
if (gintsts & S3C_GINTSTS_WkUpInt) { if (gintsts & S3C_GINTSTS_WkUpInt) {
...@@ -2448,6 +2454,8 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2448,6 +2454,8 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
if (gintsts & S3C_GINTSTS_ErlySusp) { if (gintsts & S3C_GINTSTS_ErlySusp) {
dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n"); dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");
writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS); writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);
s3c_hsotg_disconnect(hsotg);
} }
/* these next two seem to crop-up occasionally causing the core /* 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, ...@@ -2823,7 +2831,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
} }
s3c_hsotg_core_init(hsotg); s3c_hsotg_core_init(hsotg);
hsotg->last_rst = jiffies;
dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
return 0; return 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册