diff options
author | Heikki Krogerus <heikki.krogerus@nokia.com> | 2011-02-25 13:56:36 +0200 |
---|---|---|
committer | Anton Vorontsov <cbouatmailru@gmail.com> | 2011-02-28 17:31:51 +0300 |
commit | d6ccc442b12102414c1343f0adacaa8a1aaa516c (patch) | |
tree | cdfec16052084bff8161ef6d7491c36441264c78 /drivers/power | |
parent | 6501f728c56f831626d52b236023e556bca37f51 (diff) | |
download | linux-d6ccc442b12102414c1343f0adacaa8a1aaa516c.tar.bz2 |
twl4030_charger: Make the driver atomic notifier safe
This queues work from the otg notification where the
i2c operations can be safely made. Needed for atomic otg
notifiers.
Signed-off-by: Heikki Krogerus <heikki.krogerus@nokia.com>
Tested-by: Grazvydas Ignotas <notasas@gmail.com>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/twl4030_charger.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index ff1f42398a2e..92c16e1677bd 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -71,8 +71,11 @@ struct twl4030_bci { struct power_supply usb; struct otg_transceiver *transceiver; struct notifier_block otg_nb; + struct work_struct work; int irq_chg; int irq_bci; + + unsigned long event; }; /* @@ -258,14 +261,11 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) return IRQ_HANDLED; } -static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, - void *priv) +static void twl4030_bci_usb_work(struct work_struct *data) { - struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); + struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work); - dev_dbg(bci->dev, "OTG notify %lu\n", val); - - switch (val) { + switch (bci->event) { case USB_EVENT_VBUS: case USB_EVENT_CHARGER: twl4030_charger_enable_usb(bci, true); @@ -274,6 +274,17 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, twl4030_charger_enable_usb(bci, false); break; } +} + +static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, + void *priv) +{ + struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); + + dev_dbg(bci->dev, "OTG notify %lu\n", val); + + bci->event = val; + schedule_work(&bci->work); return NOTIFY_OK; } @@ -466,6 +477,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) goto fail_bci_irq; } + INIT_WORK(&bci->work, twl4030_bci_usb_work); + bci->transceiver = otg_get_transceiver(); if (bci->transceiver != NULL) { bci->otg_nb.notifier_call = twl4030_bci_usb_ncb; |