regulator: tps80031: adjust tolerance if req minuV > dev minuV
[linux-2.6.git] / drivers / regulator / max77663-regulator.c
index 99f087f..ef25f92 100644 (file)
@@ -2,8 +2,8 @@
  * drivers/regulator/max77663-regulator.c
  * Maxim LDO and Buck regulators driver
  *
- * Copyright 2011 Maxim Integrated Products, Inc.
- * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright 2011-2012 Maxim Integrated Products, Inc.
+ * Copyright (C) 2011-2012 NVIDIA Corporation
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -21,6 +21,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/i2c.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/max77663-core.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
@@ -28,7 +29,8 @@
 
 /* Regulator types */
 #define REGULATOR_TYPE_SD              0
-#define REGULATOR_TYPE_LDO             1
+#define REGULATOR_TYPE_LDO_N           1
+#define REGULATOR_TYPE_LDO_P           2
 
 /* SD and LDO Registers */
 #define MAX77663_REG_SD0               0x16
@@ -63,6 +65,7 @@
 #define MAX77663_REG_LDO7_CFG2         0x32
 #define MAX77663_REG_LDO8_CFG          0x33
 #define MAX77663_REG_LDO8_CFG2         0x34
+#define MAX77663_REG_LDO_CFG3          0x35
 
 /* Power Mode */
 #define POWER_MODE_NORMAL              3
 #define SD_FSRADE_MASK                 0x01
 #define SD_FSRADE_SHIFT                0
 
+/* LDO Configuration 3 */
+#define TRACK4_MASK                    0x20
+#define TRACK4_SHIFT                   5
+
 /* Voltage */
 #define SDX_VOLT_MASK                  0xFF
 #define SD1_VOLT_MASK                  0x3F
 #define FPS_PD_PERIOD_MASK             0x07
 #define FPS_PD_PERIOD_SHIFT            0
 
+/* Chip Identification Register */
+#define MAX77663_REG_CID5              0x5D
+
+#define CID_DIDM_MASK                  0xF0
+#define CID_DIDM_SHIFT                 4
+
+#define SD_SAFE_DOWN_UV                        50000 /* 50mV */
+
+enum {
+       VOLT_REG = 0,
+       CFG_REG,
+       FPS_REG,
+};
+
+struct max77663_register {
+       u8 addr;
+       u8 val;
+};
+
 struct max77663_regulator {
        struct regulator_dev *rdev;
        struct device *dev;
+       struct max77663_regulator_platform_data *pdata;
 
        u8 id;
        u8 type;
        u32 min_uV;
        u32 max_uV;
        u32 step_uV;
+       int safe_down_uV; /* for stable down scaling */
        u32 regulator_mode;
 
-       u8 volt_reg;
-       u8 cfg_reg;
-       u8 fps_reg;
-
+       struct max77663_register regs[3]; /* volt, cfg, fps */
        enum max77663_regulator_fps_src fps_src;
 
        u8 volt_mask;
@@ -158,16 +183,22 @@ struct max77663_regulator {
        fps_src == FPS_SRC_2 ? "FPS_SRC_2" : "FPS_SRC_NONE")
 
 static int fps_cfg_init;
-static u8 fps_cfg_reg[] = {
-       MAX77663_REG_FPS_CFG0,
-       MAX77663_REG_FPS_CFG1,
-       MAX77663_REG_FPS_CFG2
+static struct max77663_register fps_cfg_regs[] = {
+       {
+               .addr = MAX77663_REG_FPS_CFG0,
+       },
+       {
+               .addr = MAX77663_REG_FPS_CFG1,
+       },
+       {
+               .addr = MAX77663_REG_FPS_CFG2,
+       },
 };
 
 static inline struct max77663_regulator_platform_data
 *_to_pdata(struct max77663_regulator *reg)
 {
-       return reg->dev->platform_data;
+       return reg->pdata;
 }
 
 static inline struct device *_to_parent(struct max77663_regulator *reg)
@@ -175,14 +206,32 @@ static inline struct device *_to_parent(struct max77663_regulator *reg)
        return reg->dev->parent;
 }
 
+static inline int max77663_regulator_cache_write(struct max77663_regulator *reg,
+                                       u8 addr, u8 mask, u8 val, u8 *cache)
+{
+       struct device *parent = _to_parent(reg);
+       u8 new_val;
+       int ret;
+
+       new_val = (*cache & ~mask) | (val & mask);
+       if (*cache != new_val) {
+               ret = max77663_write(parent, addr, &new_val, 1, 0);
+               if (ret < 0)
+                       return ret;
+
+               *cache = new_val;
+       }
+       return 0;
+}
+
 static int
 max77663_regulator_set_fps_src(struct max77663_regulator *reg,
                               enum max77663_regulator_fps_src fps_src)
 {
-       struct device *parent = _to_parent(reg);
        int ret;
 
-       if (reg->fps_reg == MAX77663_REG_FPS_NONE)
+       if ((reg->regs[FPS_REG].addr == MAX77663_REG_FPS_NONE) ||
+                       (reg->fps_src == fps_src))
                return 0;
 
        switch (fps_src) {
@@ -197,8 +246,9 @@ max77663_regulator_set_fps_src(struct max77663_regulator *reg,
                return -EINVAL;
        }
 
-       ret = max77663_set_bits(parent, reg->fps_reg, FPS_SRC_MASK,
-                               fps_src << FPS_SRC_SHIFT, 0);
+       ret = max77663_regulator_cache_write(reg, reg->regs[FPS_REG].addr,
+                                       FPS_SRC_MASK, fps_src << FPS_SRC_SHIFT,
+                                       &reg->regs[FPS_REG].val);
        if (ret < 0)
                return ret;
 
@@ -209,11 +259,10 @@ max77663_regulator_set_fps_src(struct max77663_regulator *reg,
 static int max77663_regulator_set_fps(struct max77663_regulator *reg)
 {
        struct max77663_regulator_platform_data *pdata = _to_pdata(reg);
-       struct device *parent = _to_parent(reg);
        u8 fps_val = 0, fps_mask = 0;
        int ret = 0;
 
-       if (reg->fps_reg == MAX77663_REG_FPS_NONE)
+       if (reg->regs[FPS_REG].addr == MAX77663_REG_FPS_NONE)
                return 0;
 
        if (reg->fps_src == FPS_SRC_NONE)
@@ -231,9 +280,10 @@ static int max77663_regulator_set_fps(struct max77663_regulator *reg)
                fps_mask |= FPS_PD_PERIOD_MASK;
        }
 
-       if (fps_val)
-               ret = max77663_set_bits(parent, reg->fps_reg, fps_mask,
-                                       fps_val, 0);
+       if (fps_val || fps_mask)
+               ret = max77663_regulator_cache_write(reg,
+                                       reg->regs[FPS_REG].addr, fps_mask,
+                                       fps_val, &reg->regs[FPS_REG].val);
 
        return ret;
 }
@@ -242,13 +292,11 @@ static int
 max77663_regulator_set_fps_cfg(struct max77663_regulator *reg,
                               struct max77663_regulator_fps_cfg *fps_cfg)
 {
-       struct device *parent = _to_parent(reg);
-       u8 addr, val, mask;
+       u8 val, mask;
 
        if ((fps_cfg->src < FPS_SRC_0) || (fps_cfg->src > FPS_SRC_2))
                return -EINVAL;
 
-       addr = fps_cfg_reg[fps_cfg->src];
        val = (fps_cfg->en_src << FPS_EN_SRC_SHIFT);
        mask = FPS_EN_SRC_MASK;
 
@@ -257,7 +305,9 @@ max77663_regulator_set_fps_cfg(struct max77663_regulator *reg,
                mask |= FPS_TIME_PERIOD_MASK;
        }
 
-       return max77663_set_bits(parent, addr, mask, val, 0);
+       return max77663_regulator_cache_write(reg,
+                                       fps_cfg_regs[fps_cfg->src].addr, mask,
+                                       val, &fps_cfg_regs[fps_cfg->src].val);
 }
 
 static int
@@ -265,11 +315,19 @@ max77663_regulator_set_fps_cfgs(struct max77663_regulator *reg,
                                struct max77663_regulator_fps_cfg *fps_cfgs,
                                int num_fps_cfgs)
 {
+       struct device *parent = _to_parent(reg);
        int i, ret;
 
        if (fps_cfg_init)
                return 0;
 
+       for (i = 0; i <= FPS_SRC_2; i++) {
+               ret = max77663_read(parent, fps_cfg_regs[i].addr,
+                                   &fps_cfg_regs[i].val, 1, 0);
+               if (ret < 0)
+                       return ret;
+       }
+
        for (i = 0; i < num_fps_cfgs; i++) {
                ret = max77663_regulator_set_fps_cfg(reg, &fps_cfgs[i]);
                if (ret < 0)
@@ -283,18 +341,21 @@ max77663_regulator_set_fps_cfgs(struct max77663_regulator *reg,
 static int
 max77663_regulator_set_power_mode(struct max77663_regulator *reg, u8 power_mode)
 {
-       struct device *parent = _to_parent(reg);
-       u8 addr;
        u8 mask = reg->power_mode_mask;
        u8 shift = reg->power_mode_shift;
        int ret;
 
        if (reg->type == REGULATOR_TYPE_SD)
-               addr = reg->cfg_reg;
+               ret = max77663_regulator_cache_write(reg,
+                                                    reg->regs[CFG_REG].addr,
+                                                    mask, power_mode << shift,
+                                                    &reg->regs[CFG_REG].val);
        else
-               addr = reg->volt_reg;
+               ret = max77663_regulator_cache_write(reg,
+                                                    reg->regs[VOLT_REG].addr,
+                                                    mask, power_mode << shift,
+                                                    &reg->regs[VOLT_REG].val);
 
-       ret = max77663_set_bits(parent, addr, mask, power_mode << shift, 0);
        if (ret < 0)
                return ret;
 
@@ -304,36 +365,65 @@ max77663_regulator_set_power_mode(struct max77663_regulator *reg, u8 power_mode)
 
 static u8 max77663_regulator_get_power_mode(struct max77663_regulator *reg)
 {
-       struct device *parent = _to_parent(reg);
-       u8 addr, val;
        u8 mask = reg->power_mode_mask;
        u8 shift = reg->power_mode_shift;
-       int ret;
 
        if (reg->type == REGULATOR_TYPE_SD)
-               addr = reg->cfg_reg;
+               reg->power_mode = (reg->regs[CFG_REG].val & mask) >> shift;
        else
-               addr = reg->volt_reg;
-
-       ret = max77663_read(parent, addr, &val, 1, 0);
-       if (ret < 0)
-               return ret;
+               reg->power_mode = (reg->regs[VOLT_REG].val & mask) >> shift;
 
-       reg->power_mode = (val & mask) >> shift;
        return reg->power_mode;
 }
 
 static int max77663_regulator_do_set_voltage(struct max77663_regulator *reg,
                                             int min_uV, int max_uV)
 {
-       struct device *parent = _to_parent(reg);
+       u8 addr = reg->regs[VOLT_REG].addr;
+       u8 mask = reg->volt_mask;
+       u8 *cache = &reg->regs[VOLT_REG].val;
        u8 val;
+       int old_uV, new_uV, safe_uV;
+       int i, steps = 1;
+       int ret = 0;
 
        if (min_uV < reg->min_uV || max_uV > reg->max_uV)
                return -EDOM;
 
-       val = (min_uV - reg->min_uV) / reg->step_uV;
-       return max77663_set_bits(parent, reg->volt_reg, reg->volt_mask, val, 0);
+       old_uV = (*cache & mask) * reg->step_uV + reg->min_uV;
+
+       if ((old_uV > min_uV) && (reg->safe_down_uV >= reg->step_uV)) {
+               steps = DIV_ROUND_UP(old_uV - min_uV, reg->safe_down_uV);
+               safe_uV = -reg->safe_down_uV;
+       }
+
+       if (steps == 1) {
+               val = (min_uV - reg->min_uV) / reg->step_uV;
+               ret = max77663_regulator_cache_write(reg, addr, mask, val,
+                                                    cache);
+       } else {
+               for (i = 0; i < steps; i++) {
+                       if (abs(min_uV - old_uV) > abs(safe_uV))
+                               new_uV = old_uV + safe_uV;
+                       else
+                               new_uV = min_uV;
+
+                       dev_dbg(&reg->rdev->dev, "do_set_voltage: name=%s, "
+                               "%d/%d, old_uV=%d, new_uV=%d\n",
+                               reg->rdev->desc->name, i + 1, steps, old_uV,
+                               new_uV);
+
+                       val = (new_uV - reg->min_uV) / reg->step_uV;
+                       ret = max77663_regulator_cache_write(reg, addr, mask,
+                                                            val, cache);
+                       if (ret < 0)
+                               return ret;
+
+                       old_uV = new_uV;
+               }
+       }
+
+       return ret;
 }
 
 static int max77663_regulator_set_voltage(struct regulator_dev *rdev,
@@ -350,19 +440,13 @@ static int max77663_regulator_set_voltage(struct regulator_dev *rdev,
 static int max77663_regulator_get_voltage(struct regulator_dev *rdev)
 {
        struct max77663_regulator *reg = rdev_get_drvdata(rdev);
-       struct device *parent = _to_parent(reg);
-       u8 val;
        int volt;
-       int ret;
 
-       ret = max77663_read(parent, reg->volt_reg, &val, 1, 0);
-       if (ret < 0)
-               return ret;
-
-       volt = (val & reg->volt_mask) * reg->step_uV + reg->min_uV;
+       volt = (reg->regs[VOLT_REG].val & reg->volt_mask)
+               * reg->step_uV + reg->min_uV;
 
        dev_dbg(&rdev->dev, "get_voltage: name=%s, volt=%d, val=0x%02x\n",
-               rdev->desc->name, volt, val);
+               rdev->desc->name, volt, reg->regs[VOLT_REG].val);
        return volt;
 }
 
@@ -370,7 +454,8 @@ static int max77663_regulator_enable(struct regulator_dev *rdev)
 {
        struct max77663_regulator *reg = rdev_get_drvdata(rdev);
        struct max77663_regulator_platform_data *pdata = _to_pdata(reg);
-       int power_mode = POWER_MODE_NORMAL;
+       int power_mode = (pdata->flags & GLPM_ENABLE) ?
+                        POWER_MODE_GLPM : POWER_MODE_NORMAL;
 
        if (reg->fps_src != FPS_SRC_NONE) {
                dev_dbg(&rdev->dev, "enable: Regulator %s using %s\n",
@@ -386,7 +471,9 @@ static int max77663_regulator_enable(struct regulator_dev *rdev)
                return 0;
        }
 
-       if (reg->regulator_mode == REGULATOR_MODE_STANDBY)
+       /* N-Channel LDOs don't support Low-Power mode. */
+       if ((reg->type != REGULATOR_TYPE_LDO_N) &&
+                       (reg->regulator_mode == REGULATOR_MODE_STANDBY))
                power_mode = POWER_MODE_LPM;
 
        return max77663_regulator_set_power_mode(reg, power_mode);
@@ -412,7 +499,7 @@ static int max77663_regulator_disable(struct regulator_dev *rdev)
                return 0;
        }
 
-       return max77663_regulator_set_power_mode(reg, power_mode);;
+       return max77663_regulator_set_power_mode(reg, power_mode);
 }
 
 static int max77663_regulator_is_enabled(struct regulator_dev *rdev)
@@ -445,14 +532,18 @@ static int max77663_regulator_set_mode(struct regulator_dev *rdev,
                                       unsigned int mode)
 {
        struct max77663_regulator *reg = rdev_get_drvdata(rdev);
+       struct max77663_regulator_platform_data *pdata = _to_pdata(reg);
        u8 power_mode;
        int ret;
 
        if (mode == REGULATOR_MODE_NORMAL)
-               power_mode = POWER_MODE_NORMAL;
-       else if (mode == REGULATOR_MODE_STANDBY)
-               power_mode = POWER_MODE_LPM;
-       else
+               power_mode = (pdata->flags & GLPM_ENABLE) ?
+                            POWER_MODE_GLPM : POWER_MODE_NORMAL;
+       else if (mode == REGULATOR_MODE_STANDBY) {
+               /* N-Channel LDOs don't support Low-Power mode. */
+               power_mode = (reg->type != REGULATOR_TYPE_LDO_N) ?
+                            POWER_MODE_LPM : POWER_MODE_NORMAL;
+       } else
                return -EINVAL;
 
        ret = max77663_regulator_set_power_mode(reg, power_mode);
@@ -483,20 +574,90 @@ static int max77663_regulator_preinit(struct max77663_regulator *reg)
 {
        struct max77663_regulator_platform_data *pdata = _to_pdata(reg);
        struct device *parent = _to_parent(reg);
-       u8 val;
+       int i;
+       u8 val, mask;
        int ret;
 
+       /* Update registers */
+       for (i = 0; i <= FPS_REG; i++) {
+               ret = max77663_read(parent, reg->regs[i].addr,
+                                   &reg->regs[i].val, 1, 0);
+               if (ret < 0) {
+                       dev_err(reg->dev,
+                               "preinit: Failed to get register 0x%x\n",
+                               reg->regs[i].addr);
+                       return ret;
+               }
+       }
+
        /* Update FPS source */
-       if (reg->fps_reg == MAX77663_REG_FPS_NONE)
+       if (reg->regs[FPS_REG].addr == MAX77663_REG_FPS_NONE)
                reg->fps_src = FPS_SRC_NONE;
-       else {
-               ret = max77663_read(parent, reg->fps_reg, &val, 1, 0);
+       else
+               reg->fps_src = (reg->regs[FPS_REG].val & FPS_SRC_MASK)
+                               >> FPS_SRC_SHIFT;
+
+       dev_dbg(reg->dev, "preinit: initial fps_src=%s\n",
+               fps_src_name(reg->fps_src));
+
+       /* Update power mode */
+       max77663_regulator_get_power_mode(reg);
+
+       /* Check Chip Identification */
+       ret = max77663_read(parent, MAX77663_REG_CID5, &val, 1, 0);
+       if (ret < 0) {
+               dev_err(reg->dev, "preinit: Failed to get register 0x%x\n",
+                       MAX77663_REG_CID5);
+               return ret;
+       }
+
+       /* If metal revision is less than rev.3,
+        * set safe_down_uV for stable down scaling. */
+       if ((reg->type == REGULATOR_TYPE_SD) &&
+                       ((val & CID_DIDM_MASK) >> CID_DIDM_SHIFT) <= 2)
+               reg->safe_down_uV = SD_SAFE_DOWN_UV;
+       else
+               reg->safe_down_uV = 0;
+
+       /* Set FPS */
+       ret = max77663_regulator_set_fps_cfgs(reg, pdata->fps_cfgs,
+                                             pdata->num_fps_cfgs);
+       if (ret < 0) {
+               dev_err(reg->dev, "preinit: Failed to set FPSCFG\n");
+               return ret;
+       }
+
+       /* N-Channel LDOs don't support Low-Power mode. */
+       if ((reg->type == REGULATOR_TYPE_LDO_N) &&
+                       (pdata->flags & GLPM_ENABLE))
+               pdata->flags &= ~GLPM_ENABLE;
+
+       /* To prevent power rail turn-off when change FPS source,
+        * it must set power mode to NORMAL before change FPS source to NONE
+        * from SRC_0, SRC_1 and SRC_2. */
+       if ((reg->fps_src != FPS_SRC_NONE) && (pdata->fps_src == FPS_SRC_NONE)
+                       && (reg->power_mode != POWER_MODE_NORMAL)) {
+               val = (pdata->flags & GLPM_ENABLE) ?
+                     POWER_MODE_GLPM : POWER_MODE_NORMAL;
+               ret = max77663_regulator_set_power_mode(reg, val);
                if (ret < 0) {
-                       dev_err(reg->dev,
-                               "preinit: Failed to get FPS source\n");
+                       dev_err(reg->dev, "preinit: Failed to "
+                               "set power mode to POWER_MODE_NORMAL\n");
                        return ret;
                }
-               reg->fps_src = (val & FPS_SRC_MASK) >> FPS_SRC_SHIFT;
+       }
+
+       ret = max77663_regulator_set_fps_src(reg, pdata->fps_src);
+       if (ret < 0) {
+               dev_err(reg->dev, "preinit: Failed to set FPSSRC to %d\n",
+                       pdata->fps_src);
+               return ret;
+       }
+
+       ret = max77663_regulator_set_fps(reg);
+       if (ret < 0) {
+               dev_err(reg->dev, "preinit: Failed to set FPS\n");
+               return ret;
        }
 
        /* Set initial state */
@@ -514,7 +675,8 @@ static int max77663_regulator_preinit(struct max77663_regulator *reg)
        }
 
        if (pdata->init_enable)
-               val = POWER_MODE_NORMAL;
+               val = (pdata->flags & GLPM_ENABLE) ?
+                     POWER_MODE_GLPM : POWER_MODE_NORMAL;
        else
                val = POWER_MODE_DISABLE;
 
@@ -525,46 +687,39 @@ static int max77663_regulator_preinit(struct max77663_regulator *reg)
                return ret;
        }
 
-
 skip_init_apply:
        if (reg->type == REGULATOR_TYPE_SD) {
+               val = 0;
+               mask = 0;
+
                if (pdata->flags & SD_SLEW_RATE_MASK) {
+                       mask |= SD_SR_MASK;
                        if (pdata->flags & SD_SLEW_RATE_SLOWEST)
-                               val = SD_SR_13_75 << SD_SR_SHIFT;
+                               val |= (SD_SR_13_75 << SD_SR_SHIFT);
                        else if (pdata->flags & SD_SLEW_RATE_SLOW)
-                               val = SD_SR_27_5 << SD_SR_SHIFT;
+                               val |= (SD_SR_27_5 << SD_SR_SHIFT);
                        else if (pdata->flags & SD_SLEW_RATE_FAST)
-                               val = SD_SR_55 << SD_SR_SHIFT;
+                               val |= (SD_SR_55 << SD_SR_SHIFT);
                        else
-                               val = SD_SR_100 << SD_SR_SHIFT;
-
-                       ret = max77663_set_bits(parent, reg->cfg_reg,
-                                               SD_SR_MASK, val, 0);
-                       if (ret < 0) {
-                               dev_err(reg->dev,
-                                       "preinit: Failed to set slew rate\n");
-                               return ret;
-                       }
+                               val |= (SD_SR_100 << SD_SR_SHIFT);
                }
 
-               if (pdata->flags & SD_FORCED_PWM_MODE) {
-                       ret = max77663_set_bits(parent, reg->cfg_reg,
-                                               SD_FPWM_MASK, SD_FPWM_MASK, 0);
-                       if (ret < 0) {
-                               dev_err(reg->dev, "preinit: "
-                                       "Failed to set forced pwm mode\n");
-                               return ret;
-                       }
-               }
+               mask |= SD_FPWM_MASK;
+               if (pdata->flags & SD_FORCED_PWM_MODE)
+                       val |= SD_FPWM_MASK;
 
-               if (pdata->flags & SD_FSRADE_DISABLE) {
-                       ret = max77663_set_bits(parent, reg->cfg_reg,
-                                               SD_FSRADE_MASK, SD_FSRADE_MASK, 0);
-                       if (ret < 0) {
-                               dev_err(reg->dev, "preinit: "
-                                       "Failed to set falling slew-rate discharge mode\n");
-                               return ret;
-                       }
+               mask |= SD_FSRADE_MASK;
+               if (pdata->flags & SD_FSRADE_DISABLE)
+                       val |= SD_FSRADE_MASK;
+
+               ret = max77663_regulator_cache_write(reg,
+                               reg->regs[CFG_REG].addr, mask, val,
+                               &reg->regs[CFG_REG].val);
+               if (ret < 0) {
+                       dev_err(reg->dev, "preinit: "
+                               "Failed to set register 0x%x\n",
+                               reg->regs[CFG_REG].addr);
+                       return ret;
                }
 
                if ((reg->id == MAX77663_REGULATOR_ID_SD0)
@@ -578,9 +733,6 @@ skip_init_apply:
                                return ret;
                        }
 
-                       if (reg->fps_src == FPS_SRC_NONE)
-                               return 0;
-
                        ret = max77663_regulator_set_fps_src(reg, FPS_SRC_NONE);
                        if (ret < 0) {
                                dev_err(reg->dev, "preinit: "
@@ -591,24 +743,16 @@ skip_init_apply:
                }
        }
 
-       ret = max77663_regulator_set_fps_cfgs(reg, pdata->fps_cfgs,
-                                             pdata->num_fps_cfgs);
-       if (ret < 0) {
-               dev_err(reg->dev, "preinit: Failed to set FPSCFG\n");
-               return ret;
-       }
-
-       ret = max77663_regulator_set_fps_src(reg, pdata->fps_src);
-       if (ret < 0) {
-               dev_err(reg->dev, "preinit: Failed to set FPSSRC to %d\n",
-                       pdata->fps_src);
-               return ret;
-       }
-
-       ret = max77663_regulator_set_fps(reg);
-       if (ret < 0) {
-               dev_err(reg->dev, "preinit: Failed to set FPS\n");
-               return ret;
+       if ((reg->id == MAX77663_REGULATOR_ID_LDO4)
+                       && (pdata->flags & LDO4_EN_TRACKING)) {
+               val = TRACK4_MASK;
+               ret = max77663_write(parent, MAX77663_REG_LDO_CFG3, &val, 1, 0);
+               if (ret < 0) {
+                       dev_err(reg->dev, "preinit: "
+                               "Failed to set register 0x%x\n",
+                               MAX77663_REG_LDO_CFG3);
+                       return ret;
+               }
        }
 
        return 0;
@@ -618,10 +762,18 @@ skip_init_apply:
        [MAX77663_REGULATOR_ID_##_id] = {                       \
                .id = MAX77663_REGULATOR_ID_##_id,              \
                .type = REGULATOR_TYPE_SD,                      \
-               .volt_reg = MAX77663_REG_##_id,                 \
                .volt_mask = _volt_mask##_VOLT_MASK,            \
-               .cfg_reg = MAX77663_REG_##_id##_CFG,            \
-               .fps_reg = MAX77663_REG_FPS_##_fps_reg,         \
+               .regs = {                                       \
+                       [VOLT_REG] = {                          \
+                               .addr = MAX77663_REG_##_id,     \
+                       },                                      \
+                       [CFG_REG] = {                           \
+                               .addr = MAX77663_REG_##_id##_CFG, \
+                       },                                      \
+                       [FPS_REG] = {                           \
+                               .addr = MAX77663_REG_FPS_##_fps_reg, \
+                       },                                      \
+               },                                              \
                .min_uV = _min_uV,                              \
                .max_uV = _max_uV,                              \
                .step_uV = _step_uV,                            \
@@ -631,14 +783,22 @@ skip_init_apply:
                .power_mode_shift = SD_POWER_MODE_SHIFT,        \
        }
 
-#define REGULATOR_LDO(_id, _min_uV, _max_uV, _step_uV)         \
+#define REGULATOR_LDO(_id, _type, _min_uV, _max_uV, _step_uV)  \
        [MAX77663_REGULATOR_ID_##_id] = {                       \
                .id = MAX77663_REGULATOR_ID_##_id,              \
-               .type = REGULATOR_TYPE_LDO,                     \
-               .volt_reg = MAX77663_REG_##_id##_CFG,           \
+               .type = REGULATOR_TYPE_LDO_##_type,             \
                .volt_mask = LDO_VOLT_MASK,                     \
-               .cfg_reg = MAX77663_REG_##_id##_CFG2,           \
-               .fps_reg = MAX77663_REG_FPS_##_id,              \
+               .regs = {                                       \
+                       [VOLT_REG] = {                          \
+                               .addr = MAX77663_REG_##_id##_CFG, \
+                       },                                      \
+                       [CFG_REG] = {                           \
+                               .addr = MAX77663_REG_##_id##_CFG2, \
+                       },                                      \
+                       [FPS_REG] = {                           \
+                               .addr = MAX77663_REG_FPS_##_id, \
+                       },                                      \
+               },                                              \
                .min_uV = _min_uV,                              \
                .max_uV = _max_uV,                              \
                .step_uV = _step_uV,                            \
@@ -657,15 +817,15 @@ static struct max77663_regulator max77663_regs[MAX77663_REGULATOR_ID_NR] = {
        REGULATOR_SD(SD3,    SDX, SD3,  600000, 3387500, 12500),
        REGULATOR_SD(SD4,    SDX, SD4,  600000, 3387500, 12500),
 
-       REGULATOR_LDO(LDO0, 800000, 2350000, 25000),
-       REGULATOR_LDO(LDO1, 800000, 2350000, 25000),
-       REGULATOR_LDO(LDO2, 800000, 3950000, 50000),
-       REGULATOR_LDO(LDO3, 800000, 3950000, 50000),
-       REGULATOR_LDO(LDO4, 800000, 1587500, 12500),
-       REGULATOR_LDO(LDO5, 800000, 3950000, 50000),
-       REGULATOR_LDO(LDO6, 800000, 3950000, 50000),
-       REGULATOR_LDO(LDO7, 800000, 3950000, 50000),
-       REGULATOR_LDO(LDO8, 800000, 3950000, 50000),
+       REGULATOR_LDO(LDO0, N, 800000, 2350000, 25000),
+       REGULATOR_LDO(LDO1, N, 800000, 2350000, 25000),
+       REGULATOR_LDO(LDO2, P, 800000, 3950000, 50000),
+       REGULATOR_LDO(LDO3, P, 800000, 3950000, 50000),
+       REGULATOR_LDO(LDO4, P, 800000, 1587500, 12500),
+       REGULATOR_LDO(LDO5, P, 800000, 3950000, 50000),
+       REGULATOR_LDO(LDO6, P, 800000, 3950000, 50000),
+       REGULATOR_LDO(LDO7, N, 800000, 3950000, 50000),
+       REGULATOR_LDO(LDO8, N, 800000, 3950000, 50000),
 };
 
 #define REGULATOR_DESC(_id, _name)                     \
@@ -700,7 +860,6 @@ static int max77663_regulator_probe(struct platform_device *pdev)
 {
        struct regulator_desc *rdesc;
        struct max77663_regulator *reg;
-       struct max77663_regulator_platform_data *pdata;
        int ret = 0;
 
        if ((pdev->id < 0) || (pdev->id >= MAX77663_REGULATOR_ID_NR)) {
@@ -711,7 +870,7 @@ static int max77663_regulator_probe(struct platform_device *pdev)
        rdesc = &max77663_rdesc[pdev->id];
        reg = &max77663_regs[pdev->id];
        reg->dev = &pdev->dev;
-       pdata = reg->dev->platform_data;
+       reg->pdata = dev_get_platdata(&pdev->dev);
 
        dev_dbg(&pdev->dev, "probe: name=%s\n", rdesc->name);
 
@@ -722,8 +881,8 @@ static int max77663_regulator_probe(struct platform_device *pdev)
                return ret;
        }
 
-       reg->rdev = regulator_register(rdesc, &pdev->dev, &pdata->init_data,
-                                      reg);
+       reg->rdev = regulator_register(rdesc, &pdev->dev,
+                                      &reg->pdata->init_data, reg, NULL);
        if (IS_ERR(reg->rdev)) {
                dev_err(&pdev->dev, "probe: Failed to register regulator %s\n",
                        rdesc->name);