Merge "mfd: pm8xxx-misc: Move reset_pwr_off for pm8058" into msm-3.0
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index 7367e66..439cefe 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -32,9 +32,48 @@
#define PON_CTRL_1_WD_EN_RESET 0x08
#define PON_CTRL_1_WD_EN_PWR_OFF 0x00
-/* Regulator L22 control register */
+/* Regulator master enable addresses */
+#define REG_PM8058_VREG_EN_MSM 0x018
+#define REG_PM8058_VREG_EN_GRP_5_4 0x1C8
+
+/* Regulator control registers for shutdown/reset */
+#define REG_PM8058_S0_CTRL 0x004
+#define REG_PM8058_S1_CTRL 0x005
+#define REG_PM8058_S3_CTRL 0x111
+#define REG_PM8058_L21_CTRL 0x120
#define REG_PM8058_L22_CTRL 0x121
+#define PM8058_REGULATOR_ENABLE_MASK 0x80
+#define PM8058_REGULATOR_ENABLE 0x80
+#define PM8058_REGULATOR_DISABLE 0x00
+#define PM8058_REGULATOR_PULL_DOWN_MASK 0x40
+#define PM8058_REGULATOR_PULL_DOWN_EN 0x40
+
+/* Buck CTRL register */
+#define PM8058_SMPS_LEGACY_VREF_SEL 0x20
+#define PM8058_SMPS_LEGACY_VPROG_MASK 0x1F
+#define PM8058_SMPS_ADVANCED_BAND_MASK 0xC0
+#define PM8058_SMPS_ADVANCED_BAND_SHIFT 6
+#define PM8058_SMPS_ADVANCED_VPROG_MASK 0x3F
+
+/* Buck TEST2 registers for shutdown/reset */
+#define REG_PM8058_S0_TEST2 0x084
+#define REG_PM8058_S1_TEST2 0x085
+#define REG_PM8058_S3_TEST2 0x11A
+
+#define PM8058_REGULATOR_BANK_WRITE 0x80
+#define PM8058_REGULATOR_BANK_MASK 0x70
+#define PM8058_REGULATOR_BANK_SHIFT 4
+#define PM8058_REGULATOR_BANK_SEL(n) ((n) << PM8058_REGULATOR_BANK_SHIFT)
+
+/* Buck TEST2 register bank 1 */
+#define PM8058_SMPS_LEGACY_VLOW_SEL 0x01
+
+/* Buck TEST2 register bank 7 */
+#define PM8058_SMPS_ADVANCED_MODE_MASK 0x02
+#define PM8058_SMPS_ADVANCED_MODE 0x02
+#define PM8058_SMPS_LEGACY_MODE 0x00
+
/* SLEEP CTRL register */
#define REG_PM8058_SLEEP_CTRL 0x02B
#define REG_PM8921_SLEEP_CTRL 0x10A
@@ -89,6 +128,154 @@
return rc;
}
+/*
+ * Set an SMPS regulator to be disabled in its CTRL register, but enabled
+ * in the master enable register. Also set it's pull down enable bit.
+ * Take care to make sure that the output voltage doesn't change if switching
+ * from advanced mode to legacy mode.
+ */
+static int
+__pm8058_disable_smps_locally_set_pull_down(struct pm8xxx_misc_chip *chip,
+ u16 ctrl_addr, u16 test2_addr, u16 master_enable_addr,
+ u8 master_enable_bit)
+{
+ int rc = 0;
+ u8 vref_sel, vlow_sel, band, vprog, bank, reg;
+
+ bank = PM8058_REGULATOR_BANK_SEL(7);
+ rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
+ if (rc) {
+ pr_err("%s: pm8xxx_writeb(0x%03X) failed: rc=%d\n", __func__,
+ test2_addr, rc);
+ goto done;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, test2_addr, ®);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_readb(0x%03X): rc=%d\n",
+ __func__, test2_addr, rc);
+ goto done;
+ }
+
+ /* Check if in advanced mode. */
+ if ((reg & PM8058_SMPS_ADVANCED_MODE_MASK) ==
+ PM8058_SMPS_ADVANCED_MODE) {
+ /* Determine current output voltage. */
+ rc = pm8xxx_readb(chip->dev->parent, ctrl_addr, ®);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_readb(0x%03X): rc=%d\n",
+ __func__, ctrl_addr, rc);
+ goto done;
+ }
+
+ band = (reg & PM8058_SMPS_ADVANCED_BAND_MASK)
+ >> PM8058_SMPS_ADVANCED_BAND_SHIFT;
+ switch (band) {
+ case 3:
+ vref_sel = 0;
+ vlow_sel = 0;
+ break;
+ case 2:
+ vref_sel = PM8058_SMPS_LEGACY_VREF_SEL;
+ vlow_sel = 0;
+ break;
+ case 1:
+ vref_sel = PM8058_SMPS_LEGACY_VREF_SEL;
+ vlow_sel = PM8058_SMPS_LEGACY_VLOW_SEL;
+ break;
+ default:
+ pr_err("%s: regulator already disabled\n", __func__);
+ return -EPERM;
+ }
+ vprog = (reg & PM8058_SMPS_ADVANCED_VPROG_MASK);
+ /* Round up if fine step is in use. */
+ vprog = (vprog + 1) >> 1;
+ if (vprog > PM8058_SMPS_LEGACY_VPROG_MASK)
+ vprog = PM8058_SMPS_LEGACY_VPROG_MASK;
+
+ /* Set VLOW_SEL bit. */
+ bank = PM8058_REGULATOR_BANK_SEL(1);
+ rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_writeb(0x%03X): rc=%d\n",
+ __func__, test2_addr, rc);
+ goto done;
+ }
+
+ rc = pm8xxx_misc_masked_write(chip, test2_addr,
+ PM8058_REGULATOR_BANK_WRITE | PM8058_REGULATOR_BANK_MASK
+ | PM8058_SMPS_LEGACY_VLOW_SEL,
+ PM8058_REGULATOR_BANK_WRITE |
+ PM8058_REGULATOR_BANK_SEL(1) | vlow_sel);
+ if (rc)
+ goto done;
+
+ /* Switch to legacy mode */
+ bank = PM8058_REGULATOR_BANK_SEL(7);
+ rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
+ if (rc) {
+ pr_err("%s: FAIL pm8xxx_writeb(0x%03X): rc=%d\n",
+ __func__, test2_addr, rc);
+ goto done;
+ }
+ rc = pm8xxx_misc_masked_write(chip, test2_addr,
+ PM8058_REGULATOR_BANK_WRITE |
+ PM8058_REGULATOR_BANK_MASK |
+ PM8058_SMPS_ADVANCED_MODE_MASK,
+ PM8058_REGULATOR_BANK_WRITE |
+ PM8058_REGULATOR_BANK_SEL(7) |
+ PM8058_SMPS_LEGACY_MODE);
+ if (rc)
+ goto done;
+
+ /* Enable locally, enable pull down, keep voltage the same. */
+ rc = pm8xxx_misc_masked_write(chip, ctrl_addr,
+ PM8058_REGULATOR_ENABLE_MASK |
+ PM8058_REGULATOR_PULL_DOWN_MASK |
+ PM8058_SMPS_LEGACY_VREF_SEL |
+ PM8058_SMPS_LEGACY_VPROG_MASK,
+ PM8058_REGULATOR_ENABLE | PM8058_REGULATOR_PULL_DOWN_EN
+ | vref_sel | vprog);
+ if (rc)
+ goto done;
+ }
+
+ /* Enable in master control register. */
+ rc = pm8xxx_misc_masked_write(chip, master_enable_addr,
+ master_enable_bit, master_enable_bit);
+ if (rc)
+ goto done;
+
+ /* Disable locally and enable pull down. */
+ rc = pm8xxx_misc_masked_write(chip, ctrl_addr,
+ PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK,
+ PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN);
+
+done:
+ return rc;
+}
+
+static int
+__pm8058_disable_ldo_locally_set_pull_down(struct pm8xxx_misc_chip *chip,
+ u16 ctrl_addr, u16 master_enable_addr, u8 master_enable_bit)
+{
+ int rc;
+
+ /* Enable LDO in master control register. */
+ rc = pm8xxx_misc_masked_write(chip, master_enable_addr,
+ master_enable_bit, master_enable_bit);
+ if (rc)
+ goto done;
+
+ /* Disable LDO in CTRL register and set pull down */
+ rc = pm8xxx_misc_masked_write(chip, ctrl_addr,
+ PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK,
+ PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN);
+
+done:
+ return rc;
+}
+
static int __pm8018_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
{
int rc;
@@ -122,6 +309,24 @@
{
int rc;
+ /* When shutting down, enable active pulldowns on important rails. */
+ if (!reset) {
+ /* Disable SMPS's 0,1,3 locally and set pulldown enable bits. */
+ __pm8058_disable_smps_locally_set_pull_down(chip,
+ REG_PM8058_S0_CTRL, REG_PM8058_S0_TEST2,
+ REG_PM8058_VREG_EN_MSM, BIT(7));
+ __pm8058_disable_smps_locally_set_pull_down(chip,
+ REG_PM8058_S1_CTRL, REG_PM8058_S1_TEST2,
+ REG_PM8058_VREG_EN_MSM, BIT(6));
+ __pm8058_disable_smps_locally_set_pull_down(chip,
+ REG_PM8058_S3_CTRL, REG_PM8058_S3_TEST2,
+ REG_PM8058_VREG_EN_GRP_5_4, BIT(7) | BIT(4));
+ /* Disable LDO 21 locally and set pulldown enable bit. */
+ __pm8058_disable_ldo_locally_set_pull_down(chip,
+ REG_PM8058_L21_CTRL, REG_PM8058_VREG_EN_GRP_5_4,
+ BIT(1));
+ }
+
/*
* Fix-up: Set regulator LDO22 to 1.225 V in high power mode. Leave its
* pull-down state intact. This ensures a safe shutdown.