diff options
Diffstat (limited to 'drivers/usb/otg/twl6030-usb.c')
-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; |