regulator: regulator driver for Palmas series chips
[linux-2.6.git] / drivers / regulator / tps6591x-regulator.c
old mode 100755 (executable)
new mode 100644 (file)
index 0fc6555..1b60b9c
@@ -22,6 +22,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/slab.h>
@@ -30,6 +31,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/tps6591x-regulator.h>
 #include <linux/mfd/tps6591x.h>
+#include <linux/module.h>
 
 /* supply control and voltage setting  */
 #define TPS6591X_VIO_ADD               0x20
@@ -50,6 +52,8 @@
 #define TPS6591X_LDO6_ADD              0x35
 #define TPS6591X_LDO7_ADD              0x34
 #define TPS6591X_LDO8_ADD              0x33
+#define TPS6591X_SLEEP_SET_LDO_OFF_ADD 0x43
+#define TPS6591X_SLEEP_SET_RES_OFF_ADD 0x44
 #define TPS6591X_EN1_LDO_ADD           0x45
 #define TPS6591X_EN1_SMPS_ADD          0x46
 #define TPS6591X_EN2_LDO_ADD           0x47
@@ -62,6 +66,7 @@ struct tps6591x_register_info {
        unsigned char addr;
        unsigned char nbits;
        unsigned char shift_bits;
+       uint8_t cache_val;
 };
 
 enum {
@@ -78,8 +83,17 @@ struct tps6591x_regulator {
        struct tps6591x_register_info op_reg;
        struct tps6591x_register_info sr_reg;
        struct tps6591x_register_info en1_reg;
+       struct tps6591x_register_info slp_off_reg;
 
        int *voltages;
+
+       int enable_delay; /* delay in us for regulator to stabilize */
+       enum tps6591x_ext_control ectrl;
+       int current_volt_uv;
+
+       /* Time (micro sec) taken for 1uV change */
+       int voltage_change_uv_per_us;
+       unsigned int config_flags;
 };
 
 static inline struct device *to_tps6591x_dev(struct regulator_dev *rdev)
@@ -87,72 +101,112 @@ static inline struct device *to_tps6591x_dev(struct regulator_dev *rdev)
        return rdev_get_dev(rdev)->parent->parent;
 }
 
+static int tps6591x_regulator_enable_time(struct regulator_dev *rdev)
+{
+       struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
+
+       return ri->enable_delay;
+}
+
 static int __tps6591x_ext_control_set(struct device *parent,
                                      struct tps6591x_regulator *ri,
                                      enum tps6591x_ext_control ectrl)
 {
        int ret;
-       uint8_t mask, reg_val, addr;
+       uint8_t mask, reg_val, addr, offset;
+       struct tps6591x_register_info *ext_reg;
 
        /* For regulator that has separate operational and sleep register make
           sure that operational is used and clear sleep register to turn
           regulator off when external control is inactive */
        if (ri->supply_type == supply_type_sr_op_reg) {
-               ret = tps6591x_read(parent, ri->op_reg.addr, &reg_val);
-               if (ret)
-                       return ret;
-
+               reg_val = ri->op_reg.cache_val;
                if (reg_val & 0x80) {   /* boot has used sr - switch to op */
-                       ret = tps6591x_read(parent, ri->sr_reg.addr, &reg_val);
-                       if (ret)
-                               return ret;
-
+                       reg_val = ri->sr_reg.cache_val;
                        mask = ((1 << ri->sr_reg.nbits) - 1)
                                << ri->sr_reg.shift_bits;
                        reg_val &= mask;
                        ret = tps6591x_write(parent, ri->op_reg.addr, reg_val);
                        if (ret)
                                return ret;
+                       ri->op_reg.cache_val = reg_val;
                }
                ret = tps6591x_write(parent, ri->sr_reg.addr, 0);
                if (ret)
                        return ret;
+               ri->sr_reg.cache_val = 0;
        }
 
+       offset = 0;
        switch (ectrl) {
+       case EXT_CTRL_EN2:
+               offset = EN1_EN2_OFFSET;
+               /* fall through to EXT_CTRL_EN1 */
        case EXT_CTRL_EN1:
-               addr = ri->en1_reg.addr;
+               ext_reg = &(ri->en1_reg);
                break;
-       case EXT_CTRL_EN2:
-               addr = ri->en1_reg.addr + EN1_EN2_OFFSET;
+       case EXT_CTRL_SLEEP_OFF:
+               ext_reg = &(ri->slp_off_reg);
                break;
        default:
                return -EINVAL;
        }
-       mask = ((1 << ri->en1_reg.nbits) - 1) << ri->en1_reg.shift_bits;
+
+       addr = ext_reg->addr + offset;
+       mask = ((1 << ext_reg->nbits) - 1) << ext_reg->shift_bits;
+
        return tps6591x_update(parent, addr, mask, mask);
 }
 
+static void wait_for_voltage_change(struct tps6591x_regulator *ri, int uV)
+{
+       int change_uv;
+       int change_us;
+
+       change_uv = abs(uV - ri->current_volt_uv);
+       change_us = change_uv/ri->voltage_change_uv_per_us + 1;
+       if (change_us >= 1000) {
+               mdelay(change_us/1000);
+               change_us -= (change_us/1000);
+       }
+       if (change_us)
+               udelay(change_us);
+       ri->current_volt_uv = uV;
+}
+
 static int __tps6591x_vio_set_voltage(struct device *parent,
                                      struct tps6591x_regulator *ri,
-                                     int min_uV, int max_uV)
+                                     int min_uV, int max_uV,
+                                     unsigned *selector)
 {
        int uV;
        uint8_t mask;
        uint8_t val;
+       int ret;
+       uint8_t reg_val;
 
        for (val = 0; val < ri->desc.n_voltages; val++) {
                uV = ri->voltages[val] * 1000;
 
                /* use the first in-range value */
                if (min_uV <= uV && uV <= max_uV) {
+                       if (selector)
+                               *selector = val;
 
+                       reg_val = ri->supply_reg.cache_val;
                        val <<= ri->supply_reg.shift_bits;
+
                        mask = ((1 << ri->supply_reg.nbits) - 1) <<
                                        ri->supply_reg.shift_bits;
+                       reg_val = (reg_val & ~mask) | (val & mask);
 
-                       return tps6591x_update(parent, ri->supply_reg.addr,
-                                       val, mask);
+                       ret = tps6591x_write(parent, ri->supply_reg.addr,
+                                       reg_val);
+                       if (ret >= 0) {
+                               wait_for_voltage_change(ri, uV);
+                               ri->supply_reg.cache_val = reg_val;
+                       }
+                       return ret;
                }
        }
 
@@ -160,24 +214,22 @@ static int __tps6591x_vio_set_voltage(struct device *parent,
 }
 
 static int tps6591x_vio_set_voltage(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV)
+                                   int min_uV, int max_uV,
+                                   unsigned *selector)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
        struct device *parent = to_tps6591x_dev(rdev);
 
-       return __tps6591x_vio_set_voltage(parent, ri, min_uV, max_uV);
+       return __tps6591x_vio_set_voltage(parent, ri, min_uV, max_uV,
+                                         selector);
 }
 
 static int tps6591x_vio_get_voltage(struct regulator_dev *rdev)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6591x_dev(rdev);
        uint8_t val, mask;
-       int ret;
 
-       ret = tps6591x_read(parent, ri->supply_reg.addr, &val);
-       if (ret)
-               return ret;
+       val = ri->supply_reg.cache_val;
 
        mask = ((1 << ri->supply_reg.nbits) - 1) << ri->supply_reg.shift_bits;
        val = (val & mask) >> ri->supply_reg.shift_bits;
@@ -198,24 +250,36 @@ static int tps6591x_ldo_list_voltage(struct regulator_dev *rdev,
 }
 
 static int __tps6591x_ldo1_set_voltage(struct device *parent,
-                                     struct tps6591x_regulator *ri,
-                                     int min_uV, int max_uV)
+                                      struct tps6591x_regulator *ri,
+                                      int min_uV, int max_uV,
+                                      unsigned *selector)
 {
        int val, uV;
        uint8_t mask;
+       uint8_t reg_val;
+       int ret;
 
        for (val = 0; val < ri->desc.n_voltages; val++) {
                uV = ri->voltages[val] * 1000;
 
                /* use the first in-range value */
                if (min_uV <= uV && uV <= max_uV) {
+                       if (selector)
+                               *selector = val;
+                       reg_val = ri->supply_reg.cache_val;
                        val += 4;
                        val <<= ri->supply_reg.shift_bits;
                        mask = ((1 << ri->supply_reg.nbits) - 1) <<
                                        ri->supply_reg.shift_bits;
 
-                       return tps6591x_update(parent, ri->supply_reg.addr,
-                                       val, mask);
+                       reg_val = (reg_val & ~mask) | (val & mask);
+                       ret = tps6591x_write(parent, ri->supply_reg.addr,
+                                       reg_val);
+                       if (ret >= 0) {
+                               wait_for_voltage_change(ri, uV);
+                               ri->supply_reg.cache_val = reg_val;
+                       }
+                       return ret;
                }
        }
 
@@ -223,25 +287,22 @@ static int __tps6591x_ldo1_set_voltage(struct device *parent,
 }
 
 static int tps6591x_ldo1_set_voltage(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV)
+                                    int min_uV, int max_uV,
+                                    unsigned *selector)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
        struct device *parent = to_tps6591x_dev(rdev);
 
-       return __tps6591x_ldo1_set_voltage(parent, ri, min_uV, max_uV);
+       return __tps6591x_ldo1_set_voltage(parent, ri, min_uV, max_uV,
+                                          selector);
 }
 
 static int tps6591x_ldo1_get_voltage(struct regulator_dev *rdev)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6591x_dev(rdev);
        uint8_t val, mask;
-       int ret;
-
-       ret = tps6591x_read(parent, ri->supply_reg.addr, &val);
-       if (ret)
-               return ret;
 
+       val = ri->supply_reg.cache_val;
        mask = ((1 << ri->supply_reg.nbits) - 1) << ri->supply_reg.shift_bits;
        val = (val & mask) >> ri->supply_reg.shift_bits;
 
@@ -258,23 +319,37 @@ static int tps6591x_ldo1_get_voltage(struct regulator_dev *rdev)
 }
 
 static int __tps6591x_ldo3_set_voltage(struct device *parent,
-               struct tps6591x_regulator *ri, int min_uV, int max_uV)
+                                      struct tps6591x_regulator *ri,
+                                      int min_uV, int max_uV,
+                                      unsigned *selector)
 {
        int val, uV;
        uint8_t mask;
+       int ret;
+       uint8_t reg_val;
 
        for (val = 0; val < ri->desc.n_voltages; val++) {
                uV = ri->voltages[val] * 1000;
 
                /* use the first in-range value */
                if (min_uV <= uV && uV <= max_uV) {
+                       if (selector)
+                               *selector = val;
+                       reg_val = ri->supply_reg.cache_val;
                        val += 2;
                        val <<= ri->supply_reg.shift_bits;
                        mask = ((1 << ri->supply_reg.nbits) - 1) <<
                                                ri->supply_reg.shift_bits;
 
-                       return tps6591x_update(parent, ri->supply_reg.addr,
-                                       val, mask);
+                       reg_val = (reg_val & ~mask) | (val & mask);
+
+                       ret = tps6591x_write(parent, ri->supply_reg.addr,
+                                       reg_val);
+                       if (ret >= 0) {
+                               wait_for_voltage_change(ri, uV);
+                               ri->supply_reg.cache_val = reg_val;
+                       }
+                       return ret;
                }
        }
 
@@ -282,25 +357,22 @@ static int __tps6591x_ldo3_set_voltage(struct device *parent,
 }
 
 static int tps6591x_ldo3_set_voltage(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV)
+                                    int min_uV, int max_uV,
+                                    unsigned *selector)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
        struct device *parent = to_tps6591x_dev(rdev);
 
-       return __tps6591x_ldo3_set_voltage(parent, ri, min_uV, max_uV);
+       return __tps6591x_ldo3_set_voltage(parent, ri, min_uV, max_uV,
+                                          selector);
 }
 
 static int tps6591x_ldo3_get_voltage(struct regulator_dev *rdev)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6591x_dev(rdev);
        uint8_t val, mask;
-       int ret;
-
-       ret = tps6591x_read(parent, ri->supply_reg.addr, &val);
-       if (ret)
-               return ret;
 
+       val = ri->supply_reg.cache_val;
        mask = ((1 << ri->supply_reg.nbits) - 1) << ri->supply_reg.shift_bits;
        val = (val & mask) >> ri->supply_reg.shift_bits;
 
@@ -318,33 +390,48 @@ static int tps6591x_ldo3_get_voltage(struct regulator_dev *rdev)
 
 static int __tps6591x_vdd_set_voltage(struct device *parent,
                                      struct tps6591x_regulator *ri,
-                                     int min_uV, int max_uV)
+                                     int min_uV, int max_uV,
+                                     unsigned *selector)
 {
        int val, uV, ret;
-       uint8_t mask, reg_val;
+       uint8_t mask;
+       uint8_t op_reg_val;
+       uint8_t sr_reg_val;
 
        for (val = 0; val < ri->desc.n_voltages; val++) {
                uV = ri->voltages[val] * 1000;
 
                /* use the first in-range value */
                if (min_uV <= uV && uV <= max_uV) {
-                       ret = tps6591x_read(parent, ri->op_reg.addr, &reg_val);
-                       if (ret)
-                               return ret;
+                       if (selector)
+                               *selector = val;
+                       op_reg_val = ri->op_reg.cache_val;
                        val += 3;
-                       if (reg_val & 0x80) {
+                       if (op_reg_val & 0x80) {
+                               sr_reg_val = ri->sr_reg.cache_val;
                                val <<= ri->sr_reg.shift_bits;
                                mask = ((1 << ri->sr_reg.nbits) - 1)
                                        << ri->sr_reg.shift_bits;
-                               return tps6591x_update(parent,
-                                       ri->sr_reg.addr, val, mask);
+                               sr_reg_val = (sr_reg_val & ~mask) |
+                                                       (val & mask);
+                               ret = tps6591x_write(parent,
+                                       ri->sr_reg.addr, sr_reg_val);
+                               if (!ret)
+                                       ri->sr_reg.cache_val = sr_reg_val;
                        } else {
                                val <<= ri->op_reg.shift_bits;
                                mask = ((1 << ri->op_reg.nbits) - 1)
                                        << ri->op_reg.shift_bits;
-                               return tps6591x_update(parent,
-                                       ri->op_reg.addr, val, mask);
+                               op_reg_val = (op_reg_val & ~mask) |
+                                                       (val & mask);
+                               ret = tps6591x_write(parent,
+                                       ri->op_reg.addr, op_reg_val);
+                               if (!ret)
+                                       ri->op_reg.cache_val = op_reg_val;
                        }
+                       if (ret >= 0)
+                               wait_for_voltage_change(ri, uV);
+                       return ret;
                }
        }
 
@@ -352,28 +439,23 @@ static int __tps6591x_vdd_set_voltage(struct device *parent,
 }
 
 static int tps6591x_vdd_set_voltage(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV)
+                                   int min_uV, int max_uV,
+                                   unsigned *selector)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
        struct device *parent = to_tps6591x_dev(rdev);
 
-       return __tps6591x_vdd_set_voltage(parent, ri, min_uV, max_uV);
+       return __tps6591x_vdd_set_voltage(parent, ri, min_uV, max_uV,
+                                         selector);
 }
 
 static int tps6591x_vdd_get_voltage(struct regulator_dev *rdev)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6591x_dev(rdev);
        uint8_t op_val, sr_val, val;
-       int ret;
-
-       ret = tps6591x_read(parent, ri->op_reg.addr, &op_val);
-       if (ret)
-               return ret;
 
-       ret = tps6591x_read(parent, ri->sr_reg.addr, &sr_val);
-       if (ret)
-               return ret;
+       op_val = ri->op_reg.cache_val;
+       sr_val = ri->sr_reg.cache_val;
 
        val = (op_val & 0x80) ? (sr_val & 0x7F) : (op_val & 0x7F);
 
@@ -396,30 +478,41 @@ static int tps6591x_regulator_enable(struct regulator_dev *rdev)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
        struct device *parent = to_tps6591x_dev(rdev);
+       uint8_t reg_val;
+       int ret;
+
+       reg_val = ri->supply_reg.cache_val;
+       reg_val |= 0x1;
 
-       return tps6591x_set_bits(parent, ri->supply_reg.addr, 0x1);
+       ret = tps6591x_write(parent, ri->supply_reg.addr, reg_val);
+       if (!ret)
+               ri->supply_reg.cache_val = reg_val;
+       return ret;
 }
 
 static int tps6591x_regulator_disable(struct regulator_dev *rdev)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
        struct device *parent = to_tps6591x_dev(rdev);
+       uint8_t reg_val;
+       int ret;
 
-       return tps6591x_clr_bits(parent, ri->supply_reg.addr, 0x1);
+       reg_val = ri->supply_reg.cache_val;
+       reg_val &= ~0x1;
+       ret = tps6591x_write(parent, ri->supply_reg.addr, reg_val);
+       if (!ret)
+               ri->supply_reg.cache_val = reg_val;
+       return ret;
 }
 
 static int tps6591x_regulator_is_enabled(struct regulator_dev *rdev)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6591x_dev(rdev);
        uint8_t reg_val;
-       int ret;
-
-       ret = tps6591x_read(parent, ri->supply_reg.addr, &reg_val);
-       if (ret)
-               return ret;
 
-       return !!(reg_val & 0x1);
+       reg_val = ri->supply_reg.cache_val;
+       reg_val &= 0x1;
+       return reg_val & 0x1;
 }
 
 static struct regulator_ops tps6591x_regulator_vio_ops = {
@@ -427,6 +520,7 @@ static struct regulator_ops tps6591x_regulator_vio_ops = {
        .get_voltage = tps6591x_vio_get_voltage,
        .set_voltage = tps6591x_vio_set_voltage,
 
+       .enable_time = tps6591x_regulator_enable_time,
        .is_enabled = tps6591x_regulator_is_enabled,
        .enable = tps6591x_regulator_enable,
        .disable = tps6591x_regulator_disable,
@@ -437,6 +531,7 @@ static struct regulator_ops tps6591x_regulator_ldo1_ops = {
        .get_voltage = tps6591x_ldo1_get_voltage,
        .set_voltage = tps6591x_ldo1_set_voltage,
 
+       .enable_time = tps6591x_regulator_enable_time,
        .is_enabled = tps6591x_regulator_is_enabled,
        .enable = tps6591x_regulator_enable,
        .disable = tps6591x_regulator_disable,
@@ -447,6 +542,7 @@ static struct regulator_ops tps6591x_regulator_ldo3_ops = {
        .get_voltage = tps6591x_ldo3_get_voltage,
        .set_voltage = tps6591x_ldo3_set_voltage,
 
+       .enable_time = tps6591x_regulator_enable_time,
        .is_enabled = tps6591x_regulator_is_enabled,
        .enable = tps6591x_regulator_enable,
        .disable = tps6591x_regulator_disable,
@@ -457,6 +553,7 @@ static struct regulator_ops tps6591x_regulator_vdd_ops = {
        .get_voltage = tps6591x_vdd_get_voltage,
        .set_voltage = tps6591x_vdd_set_voltage,
 
+       .enable_time = tps6591x_regulator_enable_time,
        .is_enabled = tps6591x_regulator_is_enabled,
        .enable = tps6591x_regulator_enable,
        .disable = tps6591x_regulator_disable,
@@ -503,7 +600,9 @@ static int tps6591x_vddctrl_voltages[] = {
 
 #define TPS6591X_REGULATOR(_id, vdata, _ops, s_addr, s_nbits, s_shift, \
                        s_type, op_addr, op_nbits, op_shift, sr_addr,   \
-                       sr_nbits, sr_shift, en1_addr, en1_shift)        \
+                       sr_nbits, sr_shift, en1_addr, en1_shift,        \
+                       slp_off_addr, slp_off_shift, en_time,           \
+                       change_rate)                                    \
        .desc   = {                                                     \
                .name   = tps6591x_rails(_id),                          \
                .ops    = &tps6591x_regulator_##_ops,                   \
@@ -533,58 +632,69 @@ static int tps6591x_vddctrl_voltages[] = {
                .nbits  = 1,                                            \
                .shift_bits = en1_shift,                                \
        },                                                              \
-       .voltages       = tps6591x_##vdata##_voltages,
+       .slp_off_reg    = {                                             \
+               .addr   = TPS6591X_SLEEP_SET_##slp_off_addr##_ADD,      \
+               .nbits  = 1,                                            \
+               .shift_bits = slp_off_shift,                            \
+       },                                                              \
+       .voltages       = tps6591x_##vdata##_voltages,                  \
+       .enable_delay           = en_time,                              \
+       .voltage_change_uv_per_us = change_rate,
 
 #define TPS6591X_VIO(_id, vdata, s_addr, s_nbits, s_shift, s_type,     \
-                       en1_shift)                                      \
+                       en1_shift, slp_off_shift, en_time)              \
 {                                                                      \
        TPS6591X_REGULATOR(_id, vdata, vio_ops, s_addr, s_nbits,        \
                        s_shift, s_type, INVALID, 0, 0, INVALID, 0, 0,  \
-                       EN1_SMPS, en1_shift)                            \
+                       EN1_SMPS, en1_shift, RES_OFF, slp_off_shift,    \
+                       en_time, 10000)                                 \
 }
 
 #define TPS6591X_LDO1(_id, vdata, s_addr, s_nbits, s_shift, s_type,    \
-                       en1_shift)                                      \
+                       en1_shift, slp_off_shift, en_time)              \
 {                                                                      \
        TPS6591X_REGULATOR(_id, vdata, ldo1_ops, s_addr, s_nbits,       \
-                       s_shift, s_type, INVALID, 0, 0, INVALID, 0, 0,  \
-                       EN1_LDO, en1_shift)                             \
+                       s_shift, s_type, INVALID, 0, 0, INVALID, 0, 0,  \
+                       EN1_LDO, en1_shift, LDO_OFF, slp_off_shift,     \
+                       en_time, 6000)                                  \
 }
 
 #define TPS6591X_LDO3(_id, vdata, s_addr, s_nbits, s_shift, s_type,    \
-                       en1_shift)                                      \
+                       en1_shift, slp_off_shift, en_time)              \
 {                                                                      \
        TPS6591X_REGULATOR(_id, vdata, ldo3_ops, s_addr, s_nbits,       \
-                       s_shift, s_type, INVALID, 0, 0, INVALID, 0, 0,  \
-                       EN1_LDO, en1_shift)                             \
+                       s_shift, s_type, INVALID, 0, 0, INVALID, 0, 0,  \
+                       EN1_LDO, en1_shift, LDO_OFF, slp_off_shift,     \
+                       en_time, 11000)                                 \
 }
 
 #define TPS6591X_VDD(_id, vdata, s_addr, s_nbits, s_shift, s_type,     \
                        op_addr, op_nbits, op_shift, sr_addr, sr_nbits, \
-                       sr_shift, en1_shift)                            \
+                       sr_shift, en1_shift, slp_off_shift, en_time)    \
 {                                                                      \
        TPS6591X_REGULATOR(_id, vdata, vdd_ops, s_addr, s_nbits,        \
                        s_shift, s_type, op_addr, op_nbits, op_shift,   \
                        sr_addr, sr_nbits, sr_shift, EN1_SMPS,          \
-                       en1_shift)                                      \
+                       en1_shift, RES_OFF, slp_off_shift, en_time,     \
+                       5000)                                           \
 }
 
 static struct tps6591x_regulator tps6591x_regulator[] = {
-       TPS6591X_VIO(VIO, vio, VIO, 2, 2, single_reg, 0),
-       TPS6591X_LDO1(LDO_1, ldo124, LDO1, 6, 2, single_reg, 1),
-       TPS6591X_LDO1(LDO_2, ldo124, LDO2, 6, 2, single_reg, 2),
-       TPS6591X_LDO3(LDO_3, ldo35678, LDO3, 5, 2, single_reg, 7),
-       TPS6591X_LDO1(LDO_4, ldo124, LDO4, 6, 2, single_reg, 6),
-       TPS6591X_LDO3(LDO_5, ldo35678, LDO5, 5, 2, single_reg, 3),
-       TPS6591X_LDO3(LDO_6, ldo35678, LDO6, 5, 2, single_reg, 0),
-       TPS6591X_LDO3(LDO_7, ldo35678, LDO7, 5, 2, single_reg, 5),
-       TPS6591X_LDO3(LDO_8, ldo35678, LDO8, 5, 2, single_reg, 4),
+       TPS6591X_VIO(VIO, vio, VIO, 2, 2, single_reg, 0, 0, 350),
+       TPS6591X_LDO1(LDO_1, ldo124, LDO1, 6, 2, single_reg, 1, 1, 420),
+       TPS6591X_LDO1(LDO_2, ldo124, LDO2, 6, 2, single_reg, 2, 2, 420),
+       TPS6591X_LDO3(LDO_3, ldo35678, LDO3, 5, 2, single_reg, 7, 7, 230),
+       TPS6591X_LDO1(LDO_4, ldo124, LDO4, 6, 2, single_reg, 6, 6, 230),
+       TPS6591X_LDO3(LDO_5, ldo35678, LDO5, 5, 2, single_reg, 3, 3, 230),
+       TPS6591X_LDO3(LDO_6, ldo35678, LDO6, 5, 2, single_reg, 0, 0, 230),
+       TPS6591X_LDO3(LDO_7, ldo35678, LDO7, 5, 2, single_reg, 5, 5, 230),
+       TPS6591X_LDO3(LDO_8, ldo35678, LDO8, 5, 2, single_reg, 4, 4, 230),
        TPS6591X_VDD(VDD_1, vdd, VDD1, 2, 0, sr_op_reg, VDD1_OP,
-               7, 0, VDD1_SR, 7, 0, 1),
+               7, 0, VDD1_SR, 7, 0, 1, 1, 350),
        TPS6591X_VDD(VDD_2, vdd, VDD2, 2, 0, sr_op_reg, VDD2_OP,
-               7, 0, VDD2_SR, 7, 0, 2),
+               7, 0, VDD2_SR, 7, 0, 2, 2, 350),
        TPS6591X_VDD(VDDCTRL, vddctrl, VDDCTRL, 2, 0, sr_op_reg,
-               VDDCTRL_OP, 7, 0, VDDCTRL_SR, 7, 0, 3),
+               VDDCTRL_OP, 7, 0, VDDCTRL_SR, 7, 0, 3, 3, 900),
 };
 
 static inline int tps6591x_regulator_preinit(struct device *parent,
@@ -592,6 +702,7 @@ static inline int tps6591x_regulator_preinit(struct device *parent,
                struct tps6591x_regulator_platform_data *tps6591x_pdata)
 {
        int ret;
+       uint8_t reg_val;
 
        if (tps6591x_pdata->ectrl != EXT_CTRL_NONE) {
                ret = __tps6591x_ext_control_set(
@@ -612,7 +723,7 @@ static inline int tps6591x_regulator_preinit(struct device *parent,
                case TPS6591X_ID_VIO:
                        ret = __tps6591x_vio_set_voltage(parent, ri,
                                        tps6591x_pdata->init_uV,
-                                       tps6591x_pdata->init_uV);
+                                       tps6591x_pdata->init_uV, 0);
                        break;
 
                case TPS6591X_ID_LDO_1:
@@ -620,7 +731,7 @@ static inline int tps6591x_regulator_preinit(struct device *parent,
                case TPS6591X_ID_LDO_4:
                        ret = __tps6591x_ldo1_set_voltage(parent, ri,
                                        tps6591x_pdata->init_uV,
-                                       tps6591x_pdata->init_uV);
+                                       tps6591x_pdata->init_uV, 0);
                        break;
 
                case TPS6591X_ID_LDO_3:
@@ -630,7 +741,7 @@ static inline int tps6591x_regulator_preinit(struct device *parent,
                case TPS6591X_ID_LDO_8:
                        ret = __tps6591x_ldo3_set_voltage(parent, ri,
                                        tps6591x_pdata->init_uV,
-                                       tps6591x_pdata->init_uV);
+                                       tps6591x_pdata->init_uV, 0);
                        break;
 
                case TPS6591X_ID_VDD_1:
@@ -638,7 +749,7 @@ static inline int tps6591x_regulator_preinit(struct device *parent,
                case TPS6591X_ID_VDDCTRL:
                        ret = __tps6591x_vdd_set_voltage(parent, ri,
                                        tps6591x_pdata->init_uV,
-                                       tps6591x_pdata->init_uV);
+                                       tps6591x_pdata->init_uV, 0);
                        break;
 
                default:
@@ -653,15 +764,35 @@ static inline int tps6591x_regulator_preinit(struct device *parent,
                }
        }
 
+       reg_val = ri->supply_reg.cache_val;
        if (tps6591x_pdata->init_enable)
-               ret = tps6591x_set_bits(parent, ri->supply_reg.addr, 0x1);
+               reg_val |= 0x1;
        else
-               ret = tps6591x_clr_bits(parent, ri->supply_reg.addr, 0x1);
+               reg_val &= ~0x1;
+       ret = tps6591x_write(parent, ri->supply_reg.addr, reg_val);
 
        if (ret < 0)
                pr_err("Not able to %s rail %d err %d\n",
                        (tps6591x_pdata->init_enable) ? "enable" : "disable",
                        ri->desc.id, ret);
+       else
+               ri->supply_reg.cache_val = reg_val;
+       return ret;
+}
+
+static inline int tps6591x_cache_regulator_register(struct device *parent,
+               struct tps6591x_regulator *ri)
+{
+       int ret;
+       ret = tps6591x_read(parent, ri->supply_reg.addr,
+                               &ri->supply_reg.cache_val);
+       if (!ret && (ri->supply_type == supply_type_sr_op_reg)) {
+               ret = tps6591x_read(parent, ri->op_reg.addr,
+                               &ri->op_reg.cache_val);
+               if (!ret)
+                       ret = tps6591x_read(parent, ri->sr_reg.addr,
+                               &ri->sr_reg.cache_val);
+       }
        return ret;
 }
 
@@ -678,6 +809,7 @@ static inline struct tps6591x_regulator *find_regulator_info(int id)
        return NULL;
 }
 
+
 static int __devinit tps6591x_regulator_probe(struct platform_device *pdev)
 {
        struct tps6591x_regulator *ri = NULL;
@@ -694,18 +826,34 @@ static int __devinit tps6591x_regulator_probe(struct platform_device *pdev)
                return -EINVAL;
        }
        tps_pdata = pdev->dev.platform_data;
+       ri->ectrl = tps_pdata->ectrl;
+       ri->config_flags = tps_pdata->flags;
+
+       if (tps_pdata->slew_rate_uV_per_us)
+               ri->voltage_change_uv_per_us = tps_pdata->slew_rate_uV_per_us;
+
+       err = tps6591x_cache_regulator_register(pdev->dev.parent, ri);
+       if (err) {
+               dev_err(&pdev->dev, "Error in caching registers error %d\n",
+                                                       err);
+               return err;
+       }
 
        err = tps6591x_regulator_preinit(pdev->dev.parent, ri, tps_pdata);
-       if (err)
+       if (err) {
+               dev_err(&pdev->dev, "Error in pre-initialization of regulator "
+                                       "error %d\n", err);
                return err;
+       }
 
        rdev = regulator_register(&ri->desc, &pdev->dev,
-                               &tps_pdata->regulator, ri);
+                               &tps_pdata->regulator, ri, NULL);
        if (IS_ERR_OR_NULL(rdev)) {
                dev_err(&pdev->dev, "failed to register regulator %s\n",
                                ri->desc.name);
                return PTR_ERR(rdev);
        }
+       ri->current_volt_uv = ri->desc.ops->get_voltage(rdev);
 
        platform_set_drvdata(pdev, rdev);
 
@@ -720,6 +868,65 @@ static int __devexit tps6591x_regulator_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void tps6591x_regulator_shutdown(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+       struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_tps6591x_dev(rdev);
+       int ret;
+
+       if (ri->ectrl == EXT_CTRL_EN1) {
+               ret = tps6591x_clr_bits(parent, ri->en1_reg.addr,
+                               (1 << ri->en1_reg.shift_bits));
+               if (ret < 0)
+                       dev_err(&pdev->dev, "Error in clearing external control\n");
+       }
+}
+
+static int tps6591x_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+       struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_tps6591x_dev(rdev);
+       int ret = 0;
+       uint8_t reg_val;
+
+       if (ri->config_flags & LDO_LOW_POWER_ON_SUSPEND) {
+               ret = tps6591x_clr_bits(parent, ri->en1_reg.addr,
+                               (1 << ri->en1_reg.shift_bits));
+               reg_val = ri->supply_reg.cache_val;
+               reg_val = (reg_val & ~0x3) | (0x3);
+               ret = tps6591x_write(parent, ri->supply_reg.addr, reg_val);
+               if (ret >= 0)
+                       ri->supply_reg.cache_val = reg_val;
+               else
+                       dev_err(&pdev->dev, "Error in updating the supply state\n");
+       }
+       return ret;
+}
+
+static int tps6591x_resume(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+       struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_tps6591x_dev(rdev);
+       int ret = 0;
+       uint8_t reg_val;
+
+       if (ri->config_flags & LDO_LOW_POWER_ON_SUSPEND) {
+               ret = tps6591x_clr_bits(parent, ri->en1_reg.addr,
+                               (1 << ri->en1_reg.shift_bits));
+               reg_val = ri->supply_reg.cache_val;
+               reg_val = (reg_val & ~0x3) | (0x1);
+               ret = tps6591x_write(parent, ri->supply_reg.addr, reg_val);
+               if (ret >= 0)
+                       ri->supply_reg.cache_val = reg_val;
+               else
+                       dev_err(&pdev->dev, "Error in updating the supply state\n");
+       }
+       return ret;
+}
+
 static struct platform_driver tps6591x_regulator_driver = {
        .driver = {
                .name   = "tps6591x-regulator",
@@ -727,6 +934,9 @@ static struct platform_driver tps6591x_regulator_driver = {
        },
        .probe          = tps6591x_regulator_probe,
        .remove         = __devexit_p(tps6591x_regulator_remove),
+       .shutdown       = tps6591x_regulator_shutdown,
+       .suspend        = tps6591x_suspend,
+       .resume         = tps6591x_resume,
 };
 
 static int __init tps6591x_regulator_init(void)