summaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
authorTom Cherry <tcherry@nvidia.com>2011-02-18 12:03:24 -0800
committerVarun Colbert <vcolbert@nvidia.com>2011-03-03 10:38:25 -0800
commit4c5b7132e5321f577041945c95990d52bacd3003 (patch)
treecdef0db7f6471f7702e4a4c44f642ca6ee5e3d15 /drivers/mfd
parent29c5018516f0ed614d886b42d0b74787d89147fc (diff)
max8907c mfd: Add wake irq capability
This change allows the max8907c to wake the system when receiving an irq. It also masks all non-wake conditions from causing an irq when going into suspend and unmasks these conditions when resuming to not cause spurious wake-up events. Change-Id: I5eadb929ff4aded8a6ec11426ab424f0f692c042 Reviewed-on: http://git-master/r/20100 Tested-by: Thomas Cherry <tcherry@nvidia.com> Reviewed-by: Sachin Nikam <snikam@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/max8907c-irq.c109
1 files changed, 86 insertions, 23 deletions
diff --git a/drivers/mfd/max8907c-irq.c b/drivers/mfd/max8907c-irq.c
index e9773c0fe00e..c018e6601f67 100644
--- a/drivers/mfd/max8907c-irq.c
+++ b/drivers/mfd/max8907c-irq.c
@@ -24,6 +24,7 @@ struct max8907c_irq_data {
int enable; /* enable or not */
int offs; /* bit offset in mask register */
bool is_rtc;
+ int wake;
};
static struct max8907c_irq_data max8907c_irqs[] = {
@@ -190,19 +191,12 @@ static void max8907c_irq_sync_unlock(unsigned int irq)
{
struct max8907c *chip = get_irq_chip_data(irq);
struct max8907c_irq_data *irq_data;
- static unsigned char cache_chg[2] = {0xff, 0xff};
- static unsigned char cache_on[2] = {0xff, 0xff};
- static unsigned char cache_rtc = 0xff;
unsigned char irq_chg[2], irq_on[2];
unsigned char irq_rtc;
int i;
- /* Load cached value. In initial, all IRQs are masked */
- irq_chg[0] = cache_chg[0];
- irq_chg[1] = cache_chg[1];
- irq_on[0] = cache_on[0];
- irq_on[1] = cache_on[1];
- irq_rtc = cache_rtc;
+ irq_chg[0] = irq_chg[1] = irq_on[0] = irq_on[1] = irq_rtc = 0xFF;
+
for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) {
irq_data = &max8907c_irqs[i];
/* 1 -- disable, 0 -- enable */
@@ -228,28 +222,28 @@ static void max8907c_irq_sync_unlock(unsigned int irq)
}
}
/* update mask into registers */
- if (cache_chg[0] != irq_chg[0]) {
- cache_chg[0] = irq_chg[0];
+ if (chip->cache_chg[0] != irq_chg[0]) {
+ chip->cache_chg[0] = irq_chg[0];
max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK,
irq_chg[0]);
}
- if (cache_chg[1] != irq_chg[1]) {
- cache_chg[1] = irq_chg[1];
+ if (chip->cache_chg[1] != irq_chg[1]) {
+ chip->cache_chg[1] = irq_chg[1];
max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK,
irq_chg[1]);
}
- if (cache_on[0] != irq_on[0]) {
- cache_on[0] = irq_on[0];
+ if (chip->cache_on[0] != irq_on[0]) {
+ chip->cache_on[0] = irq_on[0];
max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK,
irq_on[0]);
}
- if (cache_on[1] != irq_on[1]) {
- cache_on[1] = irq_on[1];
+ if (chip->cache_on[1] != irq_on[1]) {
+ chip->cache_on[1] = irq_on[1];
max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK,
irq_on[1]);
}
- if (cache_rtc != irq_rtc) {
- cache_rtc = irq_rtc;
+ if (chip->cache_rtc != irq_rtc) {
+ chip->cache_rtc = irq_rtc;
max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK,
irq_rtc);
}
@@ -270,12 +264,25 @@ static void max8907c_irq_disable(unsigned int irq)
max8907c_irqs[irq - chip->irq_base].enable = 0;
}
+static int max8907c_irq_set_wake(unsigned int irq, unsigned int on)
+{
+ struct max8907c *chip = get_irq_chip_data(irq);
+ if (on) {
+ max8907c_irqs[irq - chip->irq_base].wake
+ = max8907c_irqs[irq - chip->irq_base].enable;
+ } else {
+ max8907c_irqs[irq - chip->irq_base].wake = 0;
+ }
+ return 0;
+}
+
static struct irq_chip max8907c_irq_chip = {
.name = "max8907c",
.bus_lock = max8907c_irq_lock,
.bus_sync_unlock = max8907c_irq_sync_unlock,
.enable = max8907c_irq_enable,
.disable = max8907c_irq_disable,
+ .set_wake = max8907c_irq_set_wake,
};
int max8907c_irq_init(struct max8907c *chip, int irq, int irq_base)
@@ -304,6 +311,10 @@ int max8907c_irq_init(struct max8907c *chip, int irq, int irq_base)
max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK, 0xff);
max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK, 0xff);
+ chip->cache_chg[0] = chip->cache_chg[1] =
+ chip->cache_on[0] = chip->cache_on[1] =
+ chip->cache_rtc = 0xFF;
+
mutex_init(&chip->irq_lock);
chip->core_irq = irq;
chip->irq_base = irq_base;
@@ -330,23 +341,75 @@ int max8907c_irq_init(struct max8907c *chip, int irq, int irq_base)
chip->core_irq = 0;
}
+ device_init_wakeup(chip->dev, 1);
+
return ret;
}
int max8907c_suspend(struct i2c_client *i2c, pm_message_t state)
{
- struct max8907c *max8907c = i2c_get_clientdata(i2c);
+ struct max8907c *chip = i2c_get_clientdata(i2c);
- disable_irq(max8907c->core_irq);
+ struct max8907c_irq_data *irq_data;
+ unsigned char irq_chg[2], irq_on[2];
+ unsigned char irq_rtc;
+ int i;
+
+ irq_chg[0] = irq_chg[1] = irq_on[0] = irq_on[1] = irq_rtc = 0xFF;
+
+ for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) {
+ irq_data = &max8907c_irqs[i];
+ /* 1 -- disable, 0 -- enable */
+ switch (irq_data->mask_reg) {
+ case MAX8907C_REG_CHG_IRQ1_MASK:
+ irq_chg[0] &= ~irq_data->wake;
+ break;
+ case MAX8907C_REG_CHG_IRQ2_MASK:
+ irq_chg[1] &= ~irq_data->wake;
+ break;
+ case MAX8907C_REG_ON_OFF_IRQ1_MASK:
+ irq_on[0] &= ~irq_data->wake;
+ break;
+ case MAX8907C_REG_ON_OFF_IRQ2_MASK:
+ irq_on[1] &= ~irq_data->wake;
+ break;
+ case MAX8907C_REG_RTC_IRQ_MASK:
+ irq_rtc &= ~irq_data->wake;
+ break;
+ default:
+ dev_err(chip->dev, "wrong IRQ\n");
+ break;
+ }
+ }
+
+ max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK, irq_chg[0]);
+ max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK, irq_chg[1]);
+ max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK, irq_on[0]);
+ max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK, irq_on[1]);
+ max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK, irq_rtc);
+
+ if (device_may_wakeup(chip->dev))
+ enable_irq_wake(chip->core_irq);
+ else
+ disable_irq(chip->core_irq);
return 0;
}
int max8907c_resume(struct i2c_client *i2c)
{
- struct max8907c *max8907c = i2c_get_clientdata(i2c);
+ struct max8907c *chip = i2c_get_clientdata(i2c);
+
+ if (device_may_wakeup(chip->dev))
+ disable_irq_wake(chip->core_irq);
+ else
+ enable_irq(chip->core_irq);
- enable_irq(max8907c->core_irq);
+ max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK, chip->cache_chg[0]);
+ max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK, chip->cache_chg[1]);
+ max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK, chip->cache_on[0]);
+ max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK, chip->cache_on[1]);
+ max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK, chip->cache_rtc);
return 0;
}