diff options
-rw-r--r-- | drivers/mfd/max8907c.c | 73 | ||||
-rw-r--r-- | include/linux/mfd/max8907c.h | 31 |
2 files changed, 103 insertions, 1 deletions
diff --git a/drivers/mfd/max8907c.c b/drivers/mfd/max8907c.c index 8bf47822f5c3..1a5f613ffdb7 100644 --- a/drivers/mfd/max8907c.c +++ b/drivers/mfd/max8907c.c @@ -161,6 +161,28 @@ int max8907c_power_off(void) MAX8907C_MASK_POWER_OFF, 0x40); } +void max8907c_deep_sleep(int enter) +{ + if (!max8907c_client) + return; + + if (enter) { + max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT1, + MAX8907C_POWER_UP_DELAY_CNT12); + max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT2, + MAX8907C_DELAY_CNT0); + max8907c_reg_write(max8907c_client, MAX8907C_REG_SDCTL2, + MAX8907C_SD_SEQ2); + } else { + max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT1, + MAX8907C_DELAY_CNT0); + max8907c_reg_write(max8907c_client, MAX8907C_REG_SDCTL2, + MAX8907C_SD_SEQ1); + max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT2, + MAX8907C_POWER_UP_DELAY_CNT1 | MAX8907C_POWER_DOWN_DELAY_CNT12); + } +} + static int max8907c_remove_subdev(struct device *dev, void *unused) { platform_device_unregister(to_platform_device(dev)); @@ -198,6 +220,54 @@ error: return ret; } +int max8907c_pwr_en_config(void) +{ + int ret; + u8 data; + + if (!max8907c_client) + return -EINVAL; + + /* + * Enable/disable PWREN h/w control mechanism (PWREN signal must be + * inactive = high at this time) + */ + ret = max8907c_set_bits(max8907c_client, MAX8907C_REG_RESET_CNFG, + MAX8907C_MASK_PWR_EN, MAX8907C_PWR_EN); + if (ret != 0) + return ret; + + /* + * When enabled, connect PWREN to SEQ2 by clearing SEQ2 configuration + * settings for silicon revision that requires s/w WAR. On other + * MAX8907B revisions PWREN is always connected to SEQ2. + */ + data = max8907c_reg_read(max8907c_client, MAX8907C_REG_II2RR); + + if (data == MAX8907B_II2RR_PWREN_WAR) { + data = 0x00; + ret = max8907c_reg_write(max8907c_client, MAX8907C_REG_SEQ2CNFG, data); + } + return ret; +} + +int max8907c_pwr_en_attach(void) +{ + int ret; + + if (!max8907c_client) + return -EINVAL; + + /* No sequencer delay for CPU rail when it is attached */ + ret = max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT1, + MAX8907C_DELAY_CNT0); + if (ret != 0) + return ret; + + return max8907c_set_bits(max8907c_client, MAX8907C_REG_SDCTL1, + MAX8907C_MASK_CTL_SEQ, MAX8907C_CTL_SEQ); +} + static int max8907c_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -238,6 +308,9 @@ static int max8907c_i2c_probe(struct i2c_client *i2c, ret = max8097c_add_subdevs(max8907c, pdata); + if (pdata->max8907c_setup) + return pdata->max8907c_setup(); + return ret; } diff --git a/include/linux/mfd/max8907c.h b/include/linux/mfd/max8907c.h index 4f51b3d4c58f..76dbdcc03046 100644 --- a/include/linux/mfd/max8907c.h +++ b/include/linux/mfd/max8907c.h @@ -163,10 +163,35 @@ #define MAX8907C_MASK_OUT5V_EN 0x01 /* Power off bit in RESET_CNFG reg */ -#define MAX8907C_MASK_POWER_OFF 0x40 +#define MAX8907C_MASK_POWER_OFF 0x40 + +#define MAX8907C_MASK_PWR_EN 0x80 +#define MAX8907C_MASK_CTL_SEQ 0x1C + +#define MAX8907C_PWR_EN 0x80 +#define MAX8907C_CTL_SEQ 0x04 + +#define MAX8907C_SD_SEQ1 0x02 +#define MAX8907C_SD_SEQ2 0x06 + +#define MAX8907C_DELAY_CNT0 0x00 + +#define MAX8907C_POWER_UP_DELAY_CNT1 0x10 +#define MAX8907C_POWER_UP_DELAY_CNT12 0xC0 + +#define MAX8907C_POWER_DOWN_DELAY_CNT12 0x0C #define RTC_I2C_ADDR 0x68 +/* + * MAX8907B revision requires s/w WAR to connect PWREN input to + * sequencer 2 because of the bug in the silicon. + */ +#define MAX8907B_II2RR_PWREN_WAR (0x12) + +/* Defines common for all supplies PWREN sequencer selection */ +#define MAX8907B_SEQSEL_PWREN_LXX 1 /* SEQ2 (PWREN) */ + /* IRQ definitions */ enum { MAX8907C_IRQ_VCHG_DC_OVP, @@ -214,6 +239,7 @@ struct max8907c_platform_data { int num_subdevs; struct platform_device **subdevs; int irq_base; + int (*max8907c_setup)(void); }; int max8907c_reg_read(struct i2c_client *i2c, u8 reg); @@ -227,4 +253,7 @@ void max8907c_irq_free(struct max8907c *chip); int max8907c_suspend(struct i2c_client *i2c, pm_message_t state); int max8907c_resume(struct i2c_client *i2c); int max8907c_power_off(void); +void max8907c_deep_sleep(int enter); +int max8907c_pwr_en_config(void); +int max8907c_pwr_en_attach(void); #endif |