diff options
author | Sundar R Iyer <sundar.iyer@stericsson.com> | 2010-07-21 11:41:07 +0530 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2010-08-12 11:28:00 +0200 |
commit | 5981f4e65cb455a820b3d07b8e4bac506233f3ea (patch) | |
tree | 541a0ba41593bda73d1ce9b3ce004de43dcccd85 /drivers/mfd | |
parent | 3faeb35ccc57e1af70c54b82063fdf4a88846084 (diff) |
mfd: Add stmpe auto sleep feature
Some STMPE devices support entering sleep mode automatically on a
specified timeout of inactivity on the I2C bus with the host system.
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Acked-by: Rabin Vincent <rabin.vincent@stericsson.com>
Signed-off-by: Sundar R Iyer <sundar.iyer@stericsson.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/stmpe.c | 70 | ||||
-rw-r--r-- | drivers/mfd/stmpe.h | 7 |
2 files changed, 77 insertions, 0 deletions
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index a7f3099fdcfd..0754c5e91995 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -455,6 +455,67 @@ static struct stmpe_variant_block stmpe1601_blocks[] = { }, }; +/* supported autosleep timeout delay (in msecs) */ +static const int stmpe_autosleep_delay[] = { + 4, 16, 32, 64, 128, 256, 512, 1024, +}; + +static int stmpe_round_timeout(int timeout) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(stmpe_autosleep_delay); i++) { + if (stmpe_autosleep_delay[i] >= timeout) + return i; + } + + /* + * requests for delays longer than supported should not return the + * longest supported delay + */ + return -EINVAL; +} + +static int stmpe_autosleep(struct stmpe *stmpe, int autosleep_timeout) +{ + int ret; + + if (!stmpe->variant->enable_autosleep) + return -ENOSYS; + + mutex_lock(&stmpe->lock); + ret = stmpe->variant->enable_autosleep(stmpe, autosleep_timeout); + mutex_unlock(&stmpe->lock); + + return ret; +} + +/* + * Both stmpe 1601/2403 support same layout for autosleep + */ +static int stmpe1601_autosleep(struct stmpe *stmpe, + int autosleep_timeout) +{ + int ret, timeout; + + /* choose the best available timeout */ + timeout = stmpe_round_timeout(autosleep_timeout); + if (timeout < 0) { + dev_err(stmpe->dev, "invalid timeout\n"); + return timeout; + } + + ret = __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2, + STMPE1601_AUTOSLEEP_TIMEOUT_MASK, + timeout); + if (ret < 0) + return ret; + + return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2, + STPME1601_AUTOSLEEP_ENABLE, + STPME1601_AUTOSLEEP_ENABLE); +} + static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks, bool enable) { @@ -497,6 +558,7 @@ static struct stmpe_variant_info stmpe1601 = { .num_irqs = STMPE1601_NR_INTERNAL_IRQS, .enable = stmpe1601_enable, .get_altfunc = stmpe1601_get_altfunc, + .enable_autosleep = stmpe1601_autosleep, }; /* @@ -589,6 +651,7 @@ static struct stmpe_variant_info stmpe2403 = { .num_irqs = STMPE24XX_NR_INTERNAL_IRQS, .enable = stmpe24xx_enable, .get_altfunc = stmpe24xx_get_altfunc, + .enable_autosleep = stmpe1601_autosleep, /* same as stmpe1601 */ }; static struct stmpe_variant_info *stmpe_variant_info[] = { @@ -731,6 +794,7 @@ static void stmpe_irq_remove(struct stmpe *stmpe) static int __devinit stmpe_chip_init(struct stmpe *stmpe) { unsigned int irq_trigger = stmpe->pdata->irq_trigger; + int autosleep_timeout = stmpe->pdata->autosleep_timeout; struct stmpe_variant_info *variant = stmpe->variant; u8 icr = STMPE_ICR_LSB_GIM; unsigned int id; @@ -766,6 +830,12 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe) if (stmpe->pdata->irq_invert_polarity) icr ^= STMPE_ICR_LSB_HIGH; + if (stmpe->pdata->autosleep) { + ret = stmpe_autosleep(stmpe, autosleep_timeout); + if (ret) + return ret; + } + return stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_ICR_LSB], icr); } diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index 991f0ecbeb34..0dbdc4e8cd77 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h @@ -49,6 +49,7 @@ struct stmpe_variant_block { * Called with the I/O lock held. * @get_altfunc: callback to get the alternate function number for the * specific block + * @enable_autosleep: callback to configure autosleep with specified timeout */ struct stmpe_variant_info { const char *name; @@ -62,6 +63,7 @@ struct stmpe_variant_info { int num_irqs; int (*enable)(struct stmpe *stmpe, unsigned int blocks, bool enable); int (*get_altfunc)(struct stmpe *stmpe, enum stmpe_block block); + int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout); }; #define STMPE_ICR_LSB_HIGH (1 << 2) @@ -118,6 +120,7 @@ struct stmpe_variant_info { #define STMPE1601_NR_INTERNAL_IRQS 9 #define STMPE1601_REG_SYS_CTRL 0x02 +#define STMPE1601_REG_SYS_CTRL2 0x03 #define STMPE1601_REG_ICR_LSB 0x11 #define STMPE1601_REG_IER_LSB 0x13 #define STMPE1601_REG_ISR_MSB 0x14 @@ -137,6 +140,10 @@ struct stmpe_variant_info { #define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1) #define STMPE1601_SYSCON_ENABLE_SPWM (1 << 0) +/* The 1601/2403 share the same masks */ +#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7) +#define STPME1601_AUTOSLEEP_ENABLE (1 << 3) + /* * STMPE24xx */ |