summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mfd/max8907c.c73
-rw-r--r--include/linux/mfd/max8907c.h31
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