379b748e0da7145d78cfb8b5cd7f34c2f77908d2
[glsdk/meta-ti-glsdk.git] / recipes-kernel / linux / linux-ti33x-psp-3.2 / 3.2.16 / 0053-usb-gadget-pch_udc-Fix-usb-gadget-pch_udc-Fix-ether-.patch
1 From 9200ef1704e7415a883be5ff751f486da1df7212 Mon Sep 17 00:00:00 2001
2 From: Tomoya MORINAGA <tomoya.rohm@gmail.com>
3 Date: Thu, 12 Jan 2012 11:27:08 +0900
4 Subject: [PATCH 53/69] usb: gadget: pch_udc: Fix usb/gadget/pch_udc: Fix
5 ether gadget connect/disconnect issue
7 commit 1c575d2d2e3ff2a7cb3c2e2165064199cfd8ad32 upstream.
9 ISSUE:
10 After a USB cable is connect/disconnected, the system rarely freezes.
12 CAUSE:
13 Since the USB device controller cannot know to disconnect the USB cable, when
14 it is used without detecting VBUS by GPIO, the UDC driver does not notify to
15 USB Gadget.
17 Since USB Gadget cannot know to disconnect, a false setting occurred when the
18 USB cable is connected/disconnect repeatedly.
20 Signed-off-by: Tomoya MORINAGA <tomoya.rohm@gmail.com>
21 Signed-off-by: Felipe Balbi <balbi@ti.com>
22 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
23 ---
24 drivers/usb/gadget/pch_udc.c | 70 +++++++++++++++++++++++++++++++++++++++---
25 1 file changed, 66 insertions(+), 4 deletions(-)
27 diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
28 index 3ab799c..f232e65 100644
29 --- a/drivers/usb/gadget/pch_udc.c
30 +++ b/drivers/usb/gadget/pch_udc.c
31 @@ -311,6 +311,7 @@ struct pch_udc_ep {
32 * @registered: driver regsitered with system
33 * @suspended: driver in suspended state
34 * @connected: gadget driver associated
35 + * @vbus_session: required vbus_session state
36 * @set_cfg_not_acked: pending acknowledgement 4 setup
37 * @waiting_zlp_ack: pending acknowledgement 4 ZLP
38 * @data_requests: DMA pool for data requests
39 @@ -337,6 +338,7 @@ struct pch_udc_dev {
40 registered:1,
41 suspended:1,
42 connected:1,
43 + vbus_session:1,
44 set_cfg_not_acked:1,
45 waiting_zlp_ack:1;
46 struct pci_pool *data_requests;
47 @@ -554,6 +556,31 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
48 }
50 /**
51 + * pch_udc_reconnect() - This API initializes usb device controller,
52 + * and clear the disconnect status.
53 + * @dev: Reference to pch_udc_regs structure
54 + */
55 +static void pch_udc_init(struct pch_udc_dev *dev);
56 +static void pch_udc_reconnect(struct pch_udc_dev *dev)
57 +{
58 + pch_udc_init(dev);
59 +
60 + /* enable device interrupts */
61 + /* pch_udc_enable_interrupts() */
62 + pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR,
63 + UDC_DEVINT_UR | UDC_DEVINT_US |
64 + UDC_DEVINT_ENUM |
65 + UDC_DEVINT_SI | UDC_DEVINT_SC);
66 +
67 + /* Clear the disconnect */
68 + pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
69 + pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
70 + mdelay(1);
71 + /* Resume USB signalling */
72 + pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
73 +}
74 +
75 +/**
76 * pch_udc_vbus_session() - set or clearr the disconnect status.
77 * @dev: Reference to pch_udc_regs structure
78 * @is_active: Parameter specifying the action
79 @@ -563,10 +590,18 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
80 static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
81 int is_active)
82 {
83 - if (is_active)
84 - pch_udc_clear_disconnect(dev);
85 - else
86 + if (is_active) {
87 + pch_udc_reconnect(dev);
88 + dev->vbus_session = 1;
89 + } else {
90 + if (dev->driver && dev->driver->disconnect) {
91 + spin_unlock(&dev->lock);
92 + dev->driver->disconnect(&dev->gadget);
93 + spin_lock(&dev->lock);
94 + }
95 pch_udc_set_disconnect(dev);
96 + dev->vbus_session = 0;
97 + }
98 }
100 /**
101 @@ -1126,7 +1161,17 @@ static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
102 if (!gadget)
103 return -EINVAL;
104 dev = container_of(gadget, struct pch_udc_dev, gadget);
105 - pch_udc_vbus_session(dev, is_on);
106 + if (is_on) {
107 + pch_udc_reconnect(dev);
108 + } else {
109 + if (dev->driver && dev->driver->disconnect) {
110 + spin_unlock(&dev->lock);
111 + dev->driver->disconnect(&dev->gadget);
112 + spin_lock(&dev->lock);
113 + }
114 + pch_udc_set_disconnect(dev);
115 + }
116 +
117 return 0;
118 }
120 @@ -2482,6 +2527,15 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
121 dev->driver->suspend(&dev->gadget);
122 spin_lock(&dev->lock);
123 }
124 +
125 + if (dev->vbus_session == 0) {
126 + if (dev->driver && dev->driver->disconnect) {
127 + spin_unlock(&dev->lock);
128 + dev->driver->disconnect(&dev->gadget);
129 + spin_lock(&dev->lock);
130 + }
131 + pch_udc_reconnect(dev);
132 + }
133 dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
134 }
135 /* Clear the SOF interrupt, if enabled */
136 @@ -2509,6 +2563,14 @@ static irqreturn_t pch_udc_isr(int irq, void *pdev)
137 dev_intr = pch_udc_read_device_interrupts(dev);
138 ep_intr = pch_udc_read_ep_interrupts(dev);
140 + /* For a hot plug, this find that the controller is hung up. */
141 + if (dev_intr == ep_intr)
142 + if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
143 + dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
144 + /* The controller is reset */
145 + pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
146 + return IRQ_HANDLED;
147 + }
148 if (dev_intr)
149 /* Clear device interrupts */
150 pch_udc_write_device_interrupts(dev, dev_intr);
151 --
152 1.7.9.5