USB: OTG: Use work_queue in set_vbus for TWL6030 transciever
With this commit: cccad6d4b1
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>
This commit is contained in:
Родитель
28f75f4db1
Коммит
5bf54506b0
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче