aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-04-08 04:02:39 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2010-05-27 19:37:39 -0400
commitb03b4d7cdd8f18395494478634707c6f132080d6 (patch)
tree61f306b5b2842fa65c2813be85ccbbdf867aaddc
parent0d7e0e399d7fcd5ddc3313a1aa2135fab3226d8f (diff)
mfd: Ensure WM831x charger interrupts are acknowledged when suspending
The charger interrupts on the WM831x are unconditionally a wake source for the system. If the power driver is not able to monitor them (for example, due to the IRQ line not having been wired up on the system) then any charger interrupt will prevent the system suspending for any meaningful amount of time since nothing will ack them. Avoid this issue by manually acknowledging these interrupts when we suspend the WM831x core device if they are masked. If software is actually using the interrupts then they will be unmasked and this change will have no effect. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/mfd/wm831x-core.c47
-rw-r--r--include/linux/mfd/wm831x/core.h5
2 files changed, 50 insertions, 2 deletions
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index da00ca9e0c71..1a968f34d679 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1494,6 +1494,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1494 case WM8310: 1494 case WM8310:
1495 parent = WM8310; 1495 parent = WM8310;
1496 wm831x->num_gpio = 16; 1496 wm831x->num_gpio = 16;
1497 wm831x->charger_irq_wake = 1;
1497 if (rev > 0) { 1498 if (rev > 0) {
1498 wm831x->has_gpio_ena = 1; 1499 wm831x->has_gpio_ena = 1;
1499 wm831x->has_cs_sts = 1; 1500 wm831x->has_cs_sts = 1;
@@ -1505,6 +1506,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1505 case WM8311: 1506 case WM8311:
1506 parent = WM8311; 1507 parent = WM8311;
1507 wm831x->num_gpio = 16; 1508 wm831x->num_gpio = 16;
1509 wm831x->charger_irq_wake = 1;
1508 if (rev > 0) { 1510 if (rev > 0) {
1509 wm831x->has_gpio_ena = 1; 1511 wm831x->has_gpio_ena = 1;
1510 wm831x->has_cs_sts = 1; 1512 wm831x->has_cs_sts = 1;
@@ -1516,6 +1518,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1516 case WM8312: 1518 case WM8312:
1517 parent = WM8312; 1519 parent = WM8312;
1518 wm831x->num_gpio = 16; 1520 wm831x->num_gpio = 16;
1521 wm831x->charger_irq_wake = 1;
1519 if (rev > 0) { 1522 if (rev > 0) {
1520 wm831x->has_gpio_ena = 1; 1523 wm831x->has_gpio_ena = 1;
1521 wm831x->has_cs_sts = 1; 1524 wm831x->has_cs_sts = 1;
@@ -1654,6 +1657,42 @@ static void wm831x_device_exit(struct wm831x *wm831x)
1654 kfree(wm831x); 1657 kfree(wm831x);
1655} 1658}
1656 1659
1660static int wm831x_device_suspend(struct wm831x *wm831x)
1661{
1662 int reg, mask;
1663
1664 /* If the charger IRQs are a wake source then make sure we ack
1665 * them even if they're not actively being used (eg, no power
1666 * driver or no IRQ line wired up) then acknowledge the
1667 * interrupts otherwise suspend won't last very long.
1668 */
1669 if (wm831x->charger_irq_wake) {
1670 reg = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_2_MASK);
1671
1672 mask = WM831X_CHG_BATT_HOT_EINT |
1673 WM831X_CHG_BATT_COLD_EINT |
1674 WM831X_CHG_BATT_FAIL_EINT |
1675 WM831X_CHG_OV_EINT | WM831X_CHG_END_EINT |
1676 WM831X_CHG_TO_EINT | WM831X_CHG_MODE_EINT |
1677 WM831X_CHG_START_EINT;
1678
1679 /* If any of the interrupts are masked read the statuses */
1680 if (reg & mask)
1681 reg = wm831x_reg_read(wm831x,
1682 WM831X_INTERRUPT_STATUS_2);
1683
1684 if (reg & mask) {
1685 dev_info(wm831x->dev,
1686 "Acknowledging masked charger IRQs: %x\n",
1687 reg & mask);
1688 wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_2,
1689 reg & mask);
1690 }
1691 }
1692
1693 return 0;
1694}
1695
1657static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, 1696static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
1658 int bytes, void *dest) 1697 int bytes, void *dest)
1659{ 1698{
@@ -1728,6 +1767,13 @@ static int wm831x_i2c_remove(struct i2c_client *i2c)
1728 return 0; 1767 return 0;
1729} 1768}
1730 1769
1770static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
1771{
1772 struct wm831x *wm831x = i2c_get_clientdata(i2c);
1773
1774 return wm831x_device_suspend(wm831x);
1775}
1776
1731static const struct i2c_device_id wm831x_i2c_id[] = { 1777static const struct i2c_device_id wm831x_i2c_id[] = {
1732 { "wm8310", WM8310 }, 1778 { "wm8310", WM8310 },
1733 { "wm8311", WM8311 }, 1779 { "wm8311", WM8311 },
@@ -1745,6 +1791,7 @@ static struct i2c_driver wm831x_i2c_driver = {
1745 }, 1791 },
1746 .probe = wm831x_i2c_probe, 1792 .probe = wm831x_i2c_probe,
1747 .remove = wm831x_i2c_remove, 1793 .remove = wm831x_i2c_remove,
1794 .suspend = wm831x_i2c_suspend,
1748 .id_table = wm831x_i2c_id, 1795 .id_table = wm831x_i2c_id,
1749}; 1796};
1750 1797
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index 5915f6e3d9ab..eb5bd4e0e03c 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -256,8 +256,9 @@ struct wm831x {
256 int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */ 256 int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */
257 257
258 /* Chip revision based flags */ 258 /* Chip revision based flags */
259 unsigned has_gpio_ena:1; /* Has GPIO enable bit */ 259 unsigned has_gpio_ena:1; /* Has GPIO enable bit */
260 unsigned has_cs_sts:1; /* Has current sink status bit */ 260 unsigned has_cs_sts:1; /* Has current sink status bit */
261 unsigned charger_irq_wake:1; /* Are charger IRQs a wake source? */
261 262
262 int num_gpio; 263 int num_gpio;
263 264