aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/otg
diff options
context:
space:
mode:
authorMoiz Sonasath <m-sonasath@ti.com>2011-06-27 11:01:01 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-07-01 17:45:43 -0400
commit5bf54506b036412e05e6ea0f000d627d775e7afc (patch)
treee53b4a3129ea59396f513a647b2e0d7e7358f82c /drivers/usb/otg
parent28f75f4db1e5ea1366375b2a6c40d66659e0e7ec (diff)
USB: OTG: Use work_queue in set_vbus for TWL6030 transciever
With this commit: cccad6d4b103e53fb3d1fc1467f654ecb572d047 usb: otg: notifier: switch to atomic notifier Following dumps are observed on attach/detach for MUSB HOST mode and on a detach for MUSB Device mode. BUG: sleeping function called from invalid context at kernel/mutex.c:85 where, the source is: twl6030_usb_irq ->atomic_notifier_call_chain ->musb_otg_notifications ->twl6030_set_vbus ->twl_i2c_write_u8 ->mutex_lock This patch moves the i2c writes in set_vbus function to a work-queue thereby avoiding I2C writes in atomic context. Tested HOST and Device mode functionality on OMAP4460 Signed-off-by: Moiz Sonasath <m-sonasath@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r--drivers/usb/otg/twl6030-usb.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index cfb5aa72b196..b4d2c0972b3d 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -95,11 +95,15 @@ struct twl6030_usb {
95 95
96 struct regulator *usb3v3; 96 struct regulator *usb3v3;
97 97
98 /* used to set vbus, in atomic path */
99 struct work_struct set_vbus_work;
100
98 int irq1; 101 int irq1;
99 int irq2; 102 int irq2;
100 u8 linkstat; 103 u8 linkstat;
101 u8 asleep; 104 u8 asleep;
102 bool irq_enabled; 105 bool irq_enabled;
106 bool vbus_enable;
103 unsigned long features; 107 unsigned long features;
104}; 108};
105 109
@@ -370,20 +374,31 @@ static int twl6030_enable_irq(struct otg_transceiver *x)
370 return 0; 374 return 0;
371} 375}
372 376
373static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled) 377static void otg_set_vbus_work(struct work_struct *data)
374{ 378{
375 struct twl6030_usb *twl = xceiv_to_twl(x); 379 struct twl6030_usb *twl = container_of(data, struct twl6030_usb,
380 set_vbus_work);
376 381
377 /* 382 /*
378 * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1 383 * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
379 * register. This enables boost mode. 384 * register. This enables boost mode.
380 */ 385 */
381 if (enabled) 386
387 if (twl->vbus_enable)
382 twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40, 388 twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40,
383 CHARGERUSB_CTRL1); 389 CHARGERUSB_CTRL1);
384 else 390 else
385 twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00, 391 twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
386 CHARGERUSB_CTRL1); 392 CHARGERUSB_CTRL1);
393}
394
395static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled)
396{
397 struct twl6030_usb *twl = xceiv_to_twl(x);
398
399 twl->vbus_enable = enabled;
400 schedule_work(&twl->set_vbus_work);
401
387 return 0; 402 return 0;
388} 403}
389 404
@@ -444,6 +459,8 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
444 459
445 ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier); 460 ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
446 461
462 INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
463
447 twl->irq_enabled = true; 464 twl->irq_enabled = true;
448 status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, 465 status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
449 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 466 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
@@ -494,6 +511,7 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev)
494 regulator_put(twl->usb3v3); 511 regulator_put(twl->usb3v3);
495 pdata->phy_exit(twl->dev); 512 pdata->phy_exit(twl->dev);
496 device_remove_file(twl->dev, &dev_attr_vbus); 513 device_remove_file(twl->dev, &dev_attr_vbus);
514 cancel_work_sync(&twl->set_vbus_work);
497 kfree(twl); 515 kfree(twl);
498 516
499 return 0; 517 return 0;