|
@@ -95,11 +95,15 @@ struct twl6030_usb {
|
|
|
|
|
|
struct regulator *usb3v3;
|
|
|
|
|
|
+ /* used to set vbus, in atomic path */
|
|
|
+ struct work_struct set_vbus_work;
|
|
|
+
|
|
|
int irq1;
|
|
|
int irq2;
|
|
|
u8 linkstat;
|
|
|
u8 asleep;
|
|
|
bool irq_enabled;
|
|
|
+ bool vbus_enable;
|
|
|
unsigned long features;
|
|
|
};
|
|
|
|
|
@@ -370,20 +374,31 @@ static int twl6030_enable_irq(struct otg_transceiver *x)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled)
|
|
|
+static void otg_set_vbus_work(struct work_struct *data)
|
|
|
{
|
|
|
- struct twl6030_usb *twl = xceiv_to_twl(x);
|
|
|
+ struct twl6030_usb *twl = container_of(data, struct twl6030_usb,
|
|
|
+ set_vbus_work);
|
|
|
|
|
|
/*
|
|
|
* Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
|
|
|
* register. This enables boost mode.
|
|
|
*/
|
|
|
- if (enabled)
|
|
|
+
|
|
|
+ if (twl->vbus_enable)
|
|
|
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40,
|
|
|
- CHARGERUSB_CTRL1);
|
|
|
- else
|
|
|
+ CHARGERUSB_CTRL1);
|
|
|
+ else
|
|
|
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
|
|
|
- CHARGERUSB_CTRL1);
|
|
|
+ CHARGERUSB_CTRL1);
|
|
|
+}
|
|
|
+
|
|
|
+static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled)
|
|
|
+{
|
|
|
+ struct twl6030_usb *twl = xceiv_to_twl(x);
|
|
|
+
|
|
|
+ twl->vbus_enable = enabled;
|
|
|
+ schedule_work(&twl->set_vbus_work);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -444,6 +459,8 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
|
|
|
|
|
|
ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
|
|
|
|
|
|
+ INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
|
|
|
+
|
|
|
twl->irq_enabled = true;
|
|
|
status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
|
|
|
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
|
@@ -494,6 +511,7 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev)
|
|
|
regulator_put(twl->usb3v3);
|
|
|
pdata->phy_exit(twl->dev);
|
|
|
device_remove_file(twl->dev, &dev_attr_vbus);
|
|
|
+ cancel_work_sync(&twl->set_vbus_work);
|
|
|
kfree(twl);
|
|
|
|
|
|
return 0;
|