aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/omap2430.c
diff options
context:
space:
mode:
authorHema HK <hemahk@ti.com>2010-12-10 07:40:51 -0500
committerFelipe Balbi <balbi@ti.com>2010-12-10 07:56:31 -0500
commit594632efbb9a4ac323cbf8dbf37c608d418ca8c1 (patch)
treeffe5241162b40deeb2e34820394f5a82c5212749 /drivers/usb/musb/omap2430.c
parent221946d04aa9bd3cffd93e4876bcb2e616941df9 (diff)
usb: musb: Adding musb support for OMAP4430
OMAP4430 supports UTMI and ULPI types of transceiver interface. In UTMI mode: The PHY is embedded within OMAP4430. The transceiver functionality is split between the twl6030 PMIC chip and OMAP4430. The VBUS, ID pin sensing and OTG SRP generation part is integrated in TWL6030 and UTMI PHY functionality is embedded within the OMAP4430. There is no direct interactions between the MUSB controller and TWL6030 chip to communicate the session-valid, session-end and ID-GND events. It has to be done through a software by setting/resetting bits in one of the control module register of OMAP4430 which in turn toggles the appropriate signals to MUSB controller. musb driver is register for blocking notifications from the transceiver driver to get the event notifications for connect/disconnect and ID-GND. Based on these events call the transceiver init/shutdown function to configure the transceiver to toggle the VBUS valid, session end and ID_GND signals to musb and power on/off the internal PHY. For ID_GND event notifications, toggle the ID_GND signal and then wait for musb to be configured as "A" device, and then call the transceiver function to set the VBUS. In OTG mode and musb as a host, When the Micro A connector used, VBUS is turned on and session bit set. When the device is connected, enumeration goes through. When the device disconnected from the other end of the connector(ID is still grounded), link will detect the disconnect and end the session. When the device is connected back, there are no events generated in the TWL6030-usb, and link is already down. So the device is not detected. Removed the session bit disable code which will recognize the connect of the device. Limitation: In OTG host mode, if device is connected during boot, it does not get detected. If disconnect and connect it back or connect after boot only it works. Fix for this, I will submit seperate patch later. Signed-off-by: Hema HK <hemahk@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb/omap2430.c')
-rw-r--r--drivers/usb/musb/omap2430.c109
1 files changed, 98 insertions, 11 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 0a7e6824eae8..a3f12333fc41 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -57,12 +57,8 @@ static void musb_do_idle(unsigned long _musb)
57 57
58 spin_lock_irqsave(&musb->lock, flags); 58 spin_lock_irqsave(&musb->lock, flags);
59 59
60 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
61
62 switch (musb->xceiv->state) { 60 switch (musb->xceiv->state) {
63 case OTG_STATE_A_WAIT_BCON: 61 case OTG_STATE_A_WAIT_BCON:
64 devctl &= ~MUSB_DEVCTL_SESSION;
65 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
66 62
67 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); 63 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
68 if (devctl & MUSB_DEVCTL_BDEVICE) { 64 if (devctl & MUSB_DEVCTL_BDEVICE) {
@@ -142,6 +138,8 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
142static void omap2430_musb_set_vbus(struct musb *musb, int is_on) 138static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
143{ 139{
144 u8 devctl; 140 u8 devctl;
141 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
142 int ret = 1;
145 /* HDRC controls CPEN, but beware current surges during device 143 /* HDRC controls CPEN, but beware current surges during device
146 * connect. They can trigger transient overcurrent conditions 144 * connect. They can trigger transient overcurrent conditions
147 * that must be ignored. 145 * that must be ignored.
@@ -150,12 +148,35 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
150 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); 148 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
151 149
152 if (is_on) { 150 if (is_on) {
153 musb->is_active = 1; 151 if (musb->xceiv->state == OTG_STATE_A_IDLE) {
154 musb->xceiv->default_a = 1; 152 /* start the session */
155 musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; 153 devctl |= MUSB_DEVCTL_SESSION;
156 devctl |= MUSB_DEVCTL_SESSION; 154 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
157 155 /*
158 MUSB_HST_MODE(musb); 156 * Wait for the musb to set as A device to enable the
157 * VBUS
158 */
159 while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
160
161 cpu_relax();
162
163 if (time_after(jiffies, timeout)) {
164 dev_err(musb->controller,
165 "configured as A device timeout");
166 ret = -EINVAL;
167 break;
168 }
169 }
170
171 if (ret && musb->xceiv->set_vbus)
172 otg_set_vbus(musb->xceiv, 1);
173 } else {
174 musb->is_active = 1;
175 musb->xceiv->default_a = 1;
176 musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
177 devctl |= MUSB_DEVCTL_SESSION;
178 MUSB_HST_MODE(musb);
179 }
159 } else { 180 } else {
160 musb->is_active = 0; 181 musb->is_active = 0;
161 182
@@ -214,9 +235,64 @@ static inline void omap2430_low_level_init(struct musb *musb)
214 musb_writel(musb->mregs, OTG_FORCESTDBY, l); 235 musb_writel(musb->mregs, OTG_FORCESTDBY, l);
215} 236}
216 237
238/* blocking notifier support */
239static int musb_otg_notifications(struct notifier_block *nb,
240 unsigned long event, void *unused)
241{
242 struct musb *musb = container_of(nb, struct musb, nb);
243 struct device *dev = musb->controller;
244 struct musb_hdrc_platform_data *pdata = dev->platform_data;
245 struct omap_musb_board_data *data = pdata->board_data;
246
247 switch (event) {
248 case USB_EVENT_ID:
249 DBG(4, "ID GND\n");
250
251 if (is_otg_enabled(musb)) {
252#ifdef CONFIG_USB_GADGET_MUSB_HDRC
253 if (musb->gadget_driver) {
254 otg_init(musb->xceiv);
255
256 if (data->interface_type ==
257 MUSB_INTERFACE_UTMI)
258 omap2430_musb_set_vbus(musb, 1);
259
260 }
261#endif
262 } else {
263 otg_init(musb->xceiv);
264 if (data->interface_type ==
265 MUSB_INTERFACE_UTMI)
266 omap2430_musb_set_vbus(musb, 1);
267 }
268 break;
269
270 case USB_EVENT_VBUS:
271 DBG(4, "VBUS Connect\n");
272
273 otg_init(musb->xceiv);
274 break;
275
276 case USB_EVENT_NONE:
277 DBG(4, "VBUS Disconnect\n");
278
279 if (data->interface_type == MUSB_INTERFACE_UTMI) {
280 if (musb->xceiv->set_vbus)
281 otg_set_vbus(musb->xceiv, 0);
282 }
283 otg_shutdown(musb->xceiv);
284 break;
285 default:
286 DBG(4, "ID float\n");
287 return NOTIFY_DONE;
288 }
289
290 return NOTIFY_OK;
291}
292
217static int omap2430_musb_init(struct musb *musb) 293static int omap2430_musb_init(struct musb *musb)
218{ 294{
219 u32 l; 295 u32 l, status = 0;
220 struct device *dev = musb->controller; 296 struct device *dev = musb->controller;
221 struct musb_hdrc_platform_data *plat = dev->platform_data; 297 struct musb_hdrc_platform_data *plat = dev->platform_data;
222 struct omap_musb_board_data *data = plat->board_data; 298 struct omap_musb_board_data *data = plat->board_data;
@@ -268,6 +344,17 @@ static int omap2430_musb_init(struct musb *musb)
268 musb_readl(musb->mregs, OTG_INTERFSEL), 344 musb_readl(musb->mregs, OTG_INTERFSEL),
269 musb_readl(musb->mregs, OTG_SIMENABLE)); 345 musb_readl(musb->mregs, OTG_SIMENABLE));
270 346
347 musb->nb.notifier_call = musb_otg_notifications;
348 status = otg_register_notifier(musb->xceiv, &musb->nb);
349
350 if (status)
351 DBG(1, "notification register failed\n");
352
353 /* check whether cable is already connected */
354 if (musb->xceiv->state ==OTG_STATE_B_IDLE)
355 musb_otg_notifications(&musb->nb, 1,
356 musb->xceiv->gadget);
357
271 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); 358 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
272 359
273 return 0; 360 return 0;