diff options
author | Moiz Sonasath <m-sonasath@ti.com> | 2011-06-27 11:01:01 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-07-01 17:45:43 -0400 |
commit | 5bf54506b036412e05e6ea0f000d627d775e7afc (patch) | |
tree | e53b4a3129ea59396f513a647b2e0d7e7358f82c /drivers/usb/otg | |
parent | 28f75f4db1e5ea1366375b2a6c40d66659e0e7ec (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.c | 30 |
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 | ||
373 | static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled) | 377 | static 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 | |||
395 | static 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; |