aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/s3c-hsotg.c
diff options
context:
space:
mode:
authorLukasz Majewski <l.majewski@samsung.com>2012-05-04 08:17:08 -0400
committerFelipe Balbi <balbi@ti.com>2012-05-04 08:53:14 -0400
commit12a1f4dc0dfe4c72e565dc02d6a1c021f3f98b61 (patch)
treefa9c3414a5cdc802368f67c05b79a639a10ebba2 /drivers/usb/gadget/s3c-hsotg.c
parent5e891342fd0761fed36c187587115e706c0fa358 (diff)
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>
Diffstat (limited to 'drivers/usb/gadget/s3c-hsotg.c')
-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 7e3b59106e67..ca9041634c04 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -148,6 +148,7 @@ struct s3c_hsotg_ep {
148 * @ctrl_buff: Buffer for EP0 control requests. 148 * @ctrl_buff: Buffer for EP0 control requests.
149 * @ctrl_req: Request for EP0 control packets. 149 * @ctrl_req: Request for EP0 control packets.
150 * @setup: NAK management for EP0 SETUP 150 * @setup: NAK management for EP0 SETUP
151 * @last_rst: Time of last reset
151 * @eps: The endpoints being supplied to the gadget framework 152 * @eps: The endpoints being supplied to the gadget framework
152 */ 153 */
153struct s3c_hsotg { 154struct s3c_hsotg {
@@ -175,6 +176,7 @@ struct s3c_hsotg {
175 176
176 struct usb_gadget gadget; 177 struct usb_gadget gadget;
177 unsigned int setup; 178 unsigned int setup;
179 unsigned long last_rst;
178 struct s3c_hsotg_ep eps[]; 180 struct s3c_hsotg_ep eps[];
179}; 181};
180 182
@@ -2377,23 +2379,26 @@ irq_retry:
2377 } 2379 }
2378 2380
2379 if (gintsts & S3C_GINTSTS_USBRst) { 2381 if (gintsts & S3C_GINTSTS_USBRst) {
2382
2383 u32 usb_status = readl(hsotg->regs + S3C_GOTGCTL);
2384
2380 dev_info(hsotg->dev, "%s: USBRst\n", __func__); 2385 dev_info(hsotg->dev, "%s: USBRst\n", __func__);
2381 dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 2386 dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
2382 readl(hsotg->regs + S3C_GNPTXSTS)); 2387 readl(hsotg->regs + S3C_GNPTXSTS));
2383 2388
2384 writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS); 2389 writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
2385 2390
2386 kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); 2391 if (usb_status & S3C_GOTGCTL_BSESVLD) {
2392 if (time_after(jiffies, hsotg->last_rst +
2393 msecs_to_jiffies(200))) {
2387 2394
2388 /* it seems after a reset we can end up with a situation 2395 kill_all_requests(hsotg, &hsotg->eps[0],
2389 * where the TXFIFO still has data in it... the docs 2396 -ECONNRESET, true);
2390 * suggest resetting all the fifos, so use the init_fifo
2391 * code to relayout and flush the fifos.
2392 */
2393 2397
2394 s3c_hsotg_init_fifo(hsotg); 2398 s3c_hsotg_core_init(hsotg);
2395 2399 hsotg->last_rst = jiffies;
2396 s3c_hsotg_enqueue_setup(hsotg); 2400 }
2401 }
2397 } 2402 }
2398 2403
2399 /* check both FIFOs */ 2404 /* check both FIFOs */
@@ -2436,6 +2441,7 @@ irq_retry:
2436 writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS); 2441 writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);
2437 2442
2438 call_gadget(hsotg, suspend); 2443 call_gadget(hsotg, suspend);
2444 s3c_hsotg_disconnect(hsotg);
2439 } 2445 }
2440 2446
2441 if (gintsts & S3C_GINTSTS_WkUpInt) { 2447 if (gintsts & S3C_GINTSTS_WkUpInt) {
@@ -2448,6 +2454,8 @@ irq_retry:
2448 if (gintsts & S3C_GINTSTS_ErlySusp) { 2454 if (gintsts & S3C_GINTSTS_ErlySusp) {
2449 dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n"); 2455 dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");
2450 writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS); 2456 writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);
2457
2458 s3c_hsotg_disconnect(hsotg);
2451 } 2459 }
2452 2460
2453 /* these next two seem to crop-up occasionally causing the core 2461 /* 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 } 2831 }
2824 2832
2825 s3c_hsotg_core_init(hsotg); 2833 s3c_hsotg_core_init(hsotg);
2826 2834 hsotg->last_rst = jiffies;
2827 dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 2835 dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
2828 return 0; 2836 return 0;
2829 2837