aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2014-11-21 09:14:47 -0500
committerFelipe Balbi <balbi@ti.com>2014-11-21 10:07:34 -0500
commit4ace06e8b3c32d6a601474af31580bbc1027fa9f (patch)
tree387a8e26a4c04d001676e1b14a1539a48d919875
parented692a99f31c92ec649ee2f7a0ecb4aa0f69d853 (diff)
usb: dwc2: gadget: rework disconnect event handling
This patch adds a call to s3c_hsotg_disconnect() from 'end session' interrupt (GOTGINT_SES_END_DET) to correctly notify gadget subsystem about unplugged usb cable. DISCONNINT interrupt cannot be used for this purpose, because it is asserted only in host mode. To avoid reporting disconnect event more than once, a disconnect call has been moved from USB_REQ_SET_ADDRESS handling function to SESSREQINT interrupt. This way driver ensures that disconnect event is reported either when usb cable is unplugged or every time the host starts a new session. To handle devices which has been synthesized without SRP support, connected state is set in ENUMDONE interrupt. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Acked-by: Paul Zimmerman <paulz@synopsys.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/dwc2/core.h3
-rw-r--r--drivers/usb/dwc2/core_intr.c9
-rw-r--r--drivers/usb/dwc2/gadget.c10
3 files changed, 19 insertions, 3 deletions
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 4710935fbad3..2cb0ac31ae86 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -687,6 +687,7 @@ struct dwc2_hsotg {
687 u8 ctrl_buff[8]; 687 u8 ctrl_buff[8];
688 688
689 struct usb_gadget gadget; 689 struct usb_gadget gadget;
690 unsigned int connected:1;
690 unsigned int setup; 691 unsigned int setup;
691 unsigned long last_rst; 692 unsigned long last_rst;
692 struct s3c_hsotg_ep *eps; 693 struct s3c_hsotg_ep *eps;
@@ -968,6 +969,7 @@ extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
968extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq); 969extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
969extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2); 970extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2);
970extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg); 971extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
972extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
971#else 973#else
972static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2) 974static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
973{ return 0; } 975{ return 0; }
@@ -979,6 +981,7 @@ static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
979{ return 0; } 981{ return 0; }
980static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {} 982static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {}
981static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {} 983static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
984static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
982#endif 985#endif
983 986
984#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) 987#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index b176c2fc34e5..ad43c5bc1ef1 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -128,6 +128,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
128 dwc2_op_state_str(hsotg)); 128 dwc2_op_state_str(hsotg));
129 gotgctl = readl(hsotg->regs + GOTGCTL); 129 gotgctl = readl(hsotg->regs + GOTGCTL);
130 130
131 if (dwc2_is_device_mode(hsotg))
132 s3c_hsotg_disconnect(hsotg);
133
131 if (hsotg->op_state == OTG_STATE_B_HOST) { 134 if (hsotg->op_state == OTG_STATE_B_HOST) {
132 hsotg->op_state = OTG_STATE_B_PERIPHERAL; 135 hsotg->op_state = OTG_STATE_B_PERIPHERAL;
133 } else { 136 } else {
@@ -314,6 +317,12 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
314 317
315 /* Clear interrupt */ 318 /* Clear interrupt */
316 writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); 319 writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
320
321 /*
322 * Report disconnect if there is any previous session established
323 */
324 if (dwc2_is_device_mode(hsotg))
325 s3c_hsotg_disconnect(hsotg);
317} 326}
318 327
319/* 328/*
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 367689b3d645..3cd789139f3f 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -1030,7 +1030,6 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
1030} 1030}
1031 1031
1032static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 1032static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg);
1033static void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg);
1034 1033
1035/** 1034/**
1036 * s3c_hsotg_stall_ep0 - stall ep0 1035 * s3c_hsotg_stall_ep0 - stall ep0
@@ -1108,7 +1107,6 @@ static void s3c_hsotg_process_control(struct dwc2_hsotg *hsotg,
1108 if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 1107 if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
1109 switch (ctrl->bRequest) { 1108 switch (ctrl->bRequest) {
1110 case USB_REQ_SET_ADDRESS: 1109 case USB_REQ_SET_ADDRESS:
1111 s3c_hsotg_disconnect(hsotg);
1112 dcfg = readl(hsotg->regs + DCFG); 1110 dcfg = readl(hsotg->regs + DCFG);
1113 dcfg &= ~DCFG_DEVADDR_MASK; 1111 dcfg &= ~DCFG_DEVADDR_MASK;
1114 dcfg |= (le16_to_cpu(ctrl->wValue) << 1112 dcfg |= (le16_to_cpu(ctrl->wValue) <<
@@ -2028,15 +2026,20 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg,
2028 * transactions and signal the gadget driver that this 2026 * transactions and signal the gadget driver that this
2029 * has happened. 2027 * has happened.
2030 */ 2028 */
2031static void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg) 2029void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg)
2032{ 2030{
2033 unsigned ep; 2031 unsigned ep;
2034 2032
2033 if (!hsotg->connected)
2034 return;
2035
2036 hsotg->connected = 0;
2035 for (ep = 0; ep < hsotg->num_of_eps; ep++) 2037 for (ep = 0; ep < hsotg->num_of_eps; ep++)
2036 kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); 2038 kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
2037 2039
2038 call_gadget(hsotg, disconnect); 2040 call_gadget(hsotg, disconnect);
2039} 2041}
2042EXPORT_SYMBOL_GPL(s3c_hsotg_disconnect);
2040 2043
2041/** 2044/**
2042 * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 2045 * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler
@@ -2289,6 +2292,7 @@ irq_retry:
2289 writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); 2292 writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);
2290 2293
2291 s3c_hsotg_irq_enumdone(hsotg); 2294 s3c_hsotg_irq_enumdone(hsotg);
2295 hsotg->connected = 1;
2292 } 2296 }
2293 2297
2294 if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 2298 if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {