diff options
author | Danke Xie <d.xie@sta.samsung.com> | 2011-09-08 13:37:44 -0700 |
---|---|---|
committer | Todd Poynor <toddpoynor@google.com> | 2011-09-12 13:43:11 -0700 |
commit | 987583925df180b95e9191f8cd89e90986267202 (patch) | |
tree | 383e884346f0d158468c51dd9079db91d9ca650c /drivers/mfd/twl6030-irq.c | |
parent | 91b1f0f81833b6cbec2de6bcd3d2247cc140265a (diff) | |
download | kernel_samsung_tuna-987583925df180b95e9191f8cd89e90986267202.zip kernel_samsung_tuna-987583925df180b95e9191f8cd89e90986267202.tar.gz kernel_samsung_tuna-987583925df180b95e9191f8cd89e90986267202.tar.bz2 |
MFD: TWL 6030: Add VLOW interrupt handler to shutdown device
This change adds an interrupt handler to shutdown device when
battery voltage drops below TWL 6030 threshold VBATMIN_HI.
Change-Id: I6556fd213ab0fafa9ae78c37c1a4672d1440c304
Signed-off-by: Danke Xie <d.xie@sta.samsung.com>
Diffstat (limited to 'drivers/mfd/twl6030-irq.c')
-rw-r--r-- | drivers/mfd/twl6030-irq.c | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 7999d3f..67fb7ff 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -38,6 +38,7 @@ #include <linux/i2c/twl.h> #include <linux/platform_device.h> #include <linux/suspend.h> +#include <linux/reboot.h> #include "twl-core.h" @@ -56,7 +57,7 @@ static int twl6030_interrupt_mapping[24] = { PWR_INTR_OFFSET, /* Bit 0 PWRON */ PWR_INTR_OFFSET, /* Bit 1 RPWRON */ - PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */ + TWL_VLOW_INTR_OFFSET, /* Bit 2 BAT_VLOW */ RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */ RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */ HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */ @@ -216,6 +217,17 @@ static irqreturn_t handle_twl6030_pih(int irq, void *devid) return IRQ_HANDLED; } +/* + * handle_twl6030_vlow() is a threaded BAT_VLOW interrupt handler. BAT_VLOW + * is a secondary interrupt generated in twl6030_irq_thread(). + */ +static irqreturn_t handle_twl6030_vlow(int irq, void *unused) +{ + pr_info("handle_twl6030_vlow: kernel_power_off()\n"); + kernel_power_off(); + return IRQ_HANDLED; +} + /*----------------------------------------------------------------------*/ static inline void activate_irq(int irq) @@ -344,6 +356,70 @@ int twl6030_mmc_card_detect(struct device *dev, int slot) } EXPORT_SYMBOL(twl6030_mmc_card_detect); +int twl6030_vlow_init(int vlow_irq) +{ + int status; + u8 val; + + status = twl_i2c_read_u8(TWL_MODULE_PM_SLAVE_RES, &val, + REG_VBATMIN_HI_CFG_STATE); + if (status < 0) { + pr_err("twl6030: I2C err reading REG_VBATMIN_HI_CFG_STATE: %d\n", + status); + return status; + } + + status = twl_i2c_write_u8(TWL_MODULE_PM_SLAVE_RES, + val | VBATMIN_VLOW_EN, REG_VBATMIN_HI_CFG_STATE); + if (status < 0) { + pr_err("twl6030: I2C err writing REG_VBATMIN_HI_CFG_STATE: %d\n", + status); + return status; + } + + status = twl_i2c_read_u8(TWL_MODULE_PIH, &val, REG_INT_MSK_LINE_A); + if (status < 0) { + pr_err("twl6030: I2C err reading REG_INT_MSK_LINE_A: %d\n", + status); + return status; + } + + status = twl_i2c_write_u8(TWL_MODULE_PIH, val & ~VLOW_INT_MASK, + REG_INT_MSK_LINE_A); + if (status < 0) { + pr_err("twl6030: I2C err writing REG_INT_MSK_LINE_A: %d\n", + status); + return status; + } + + status = twl_i2c_read_u8(TWL_MODULE_PIH, &val, REG_INT_MSK_STS_A); + if (status < 0) { + pr_err("twl6030: I2C err reading REG_INT_MSK_STS_A: %d\n", + status); + return status; + } + + status = twl_i2c_write_u8(TWL_MODULE_PIH, val & ~VLOW_INT_MASK, + REG_INT_MSK_STS_A); + if (status < 0) { + pr_err("twl6030: I2C err writing REG_INT_MSK_STS_A: %d\n", + status); + return status; + } + + /* install an irq handler for vlow */ + status = request_threaded_irq(vlow_irq, NULL, handle_twl6030_vlow, + IRQF_ONESHOT, + "TWL6030-VLOW", handle_twl6030_vlow); + if (status < 0) { + pr_err("twl6030: could not claim vlow irq %d: %d\n", vlow_irq, + status); + return status; + } + + return 0; +} + int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) { @@ -403,7 +479,16 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) twl_irq = irq_num; register_pm_notifier(&twl6030_irq_pm_notifier_block); + + status = twl6030_vlow_init(twl6030_irq_base + TWL_VLOW_INTR_OFFSET); + if (status < 0) + goto fail_vlow; + return status; + +fail_vlow: + free_irq(irq_num, &irq_event); + fail_irq: free_irq(irq_num, &irq_event); @@ -426,6 +511,9 @@ int twl6030_exit_irq(void) return -ENOSYS; } + free_irq(twl6030_irq_base + TWL_VLOW_INTR_OFFSET, + handle_twl6030_vlow); + free_irq(twl_irq, &irq_event); for (i = twl6030_irq_base; i < twl6030_irq_end; i++) |