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 | |
parent | 91b1f0f81833b6cbec2de6bcd3d2247cc140265a (diff) | |
download | kernel_samsung_espresso10-987583925df180b95e9191f8cd89e90986267202.zip kernel_samsung_espresso10-987583925df180b95e9191f8cd89e90986267202.tar.gz kernel_samsung_espresso10-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>
-rw-r--r-- | drivers/mfd/twl-core.c | 5 | ||||
-rw-r--r-- | drivers/mfd/twl6030-irq.c | 90 | ||||
-rw-r--r-- | include/linux/i2c/twl.h | 13 |
3 files changed, 106 insertions, 2 deletions
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 194a674..ed11f61 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -126,6 +126,7 @@ /* Last - for index max*/ #define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG +#define TWL6030_MODULE_LAST TWL6030_MODULE_SLAVE_RES #define TWL_NUM_SLAVES 4 @@ -141,7 +142,7 @@ #define SUB_CHIP_ID2 2 #define SUB_CHIP_ID3 3 -#define TWL_MODULE_LAST TWL4030_MODULE_LAST +#define TWL_MODULE_LAST TWL6030_MODULE_LAST /* Base Address defns for twl4030_map[] */ @@ -187,6 +188,7 @@ #define TWL6030_BASEADD_MEM 0x0017 #define TWL6030_BASEADD_PM_MASTER 0x001F #define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */ +#define TWL6030_BASEADD_PM_SLAVE_RES 0x00AD #define TWL6030_BASEADD_PM_MISC 0x00E2 #define TWL6030_BASEADD_PM_PUPD 0x00F0 @@ -333,6 +335,7 @@ static struct twl_mapping twl6030_map[] = { { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER }, + { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_RES }, }; /*----------------------------------------------------------------------*/ 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++) diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index a9bfb2a..a163c7d 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -71,6 +71,7 @@ #define TWL4030_MODULE_PM_RECEIVER 0x15 #define TWL4030_MODULE_RTC 0x16 #define TWL4030_MODULE_SECURED_REG 0x17 +#define TWL6030_MODULE_SLAVE_RES 0x19 #define TWL_MODULE_USB TWL4030_MODULE_USB #define TWL_MODULE_AUDIO_VOICE TWL4030_MODULE_AUDIO_VOICE @@ -81,6 +82,7 @@ #define TWL_MODULE_PM_RECEIVER TWL4030_MODULE_PM_RECEIVER #define TWL_MODULE_RTC TWL4030_MODULE_RTC #define TWL_MODULE_PWM TWL4030_MODULE_PWM0 +#define TWL_MODULE_PM_SLAVE_RES TWL6030_MODULE_SLAVE_RES #define TWL6030_MODULE_ID0 0x0D #define TWL6030_MODULE_ID1 0x0E @@ -100,6 +102,7 @@ * Offset from TWL6030_IRQ_BASE / pdata->irq_base */ #define PWR_INTR_OFFSET 0 +#define TWL_VLOW_INTR_OFFSET 6 #define HOTDIE_INTR_OFFSET 12 #define SMPSLDO_INTR_OFFSET 13 #define BATDETECT_INTR_OFFSET 14 @@ -151,6 +154,8 @@ #define MMC_PU (0x1 << 3) #define MMC_PD (0x1 << 2) +#define VLOW_INT_MASK (0x1 << 2) + #define TWL_SIL_TYPE(rev) ((rev) & 0x00FFFFFF) #define TWL_SIL_REV(rev) ((rev) >> 24) #define TWL_SIL_5030 0x09002F @@ -450,6 +455,14 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot) #define TWL4030_PM_MASTER_GLOBAL_TST 0xb6 +/* + * PM Slave resource module register offsets (use TWL6030_MODULE_SLAVE_RES) + */ + +#define REG_VBATMIN_HI_CFG_STATE 0x1D + +#define VBATMIN_VLOW_EN 0x21 + /*----------------------------------------------------------------------*/ /* Power bus message definitions */ |