regulator: regulator driver for Palmas series chips
[linux-2.6.git] / drivers / regulator / tps6591x-regulator.c
index 2fff27a..1b60b9c 100644 (file)
@@ -31,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
@@ -65,6 +66,7 @@ struct tps6591x_register_info {
        unsigned char addr;
        unsigned char nbits;
        unsigned char shift_bits;
+       uint8_t cache_val;
 };
 
 enum {
@@ -85,7 +87,13 @@ struct tps6591x_regulator {
 
        int *voltages;
 
-       int delay; /* delay in us for regulator to stabilize */
+       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)
@@ -97,7 +105,7 @@ static int tps6591x_regulator_enable_time(struct regulator_dev *rdev)
 {
        struct tps6591x_regulator *ri = rdev_get_drvdata(rdev);
 
-       return ri->delay;
+       return ri->enable_delay;
 }
 
 static int __tps6591x_ext_control_set(struct device *parent,
@@ -112,25 +120,21 @@ static int __tps6591x_ext_control_set(struct device *parent,
           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;
@@ -154,26 +158,55 @@ static int __tps6591x_ext_control_set(struct device *parent,
        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;
                }
        }
 
@@ -181,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;
@@ -219,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;
                }
        }
 
@@ -244,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;
 
@@ -279,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;
                }
        }
 
@@ -303,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;
 
@@ -339,35 +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;
-                               ret = tps6591x_update(parent,
-                                       ri->op_reg.addr, val, mask);
-                               udelay(100);
-                               return ret;
+                               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;
                }
        }
 
@@ -375,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);
 
@@ -419,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 = {
@@ -528,46 +598,48 @@ static int tps6591x_vddctrl_voltages[] = {
        1287, 1300, 1312, 1325, 1337, 1350, 1362, 1375, 1387, 1400,
 };
 
-#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, slp_off_addr,  \
-                       slp_off_shift, en_time)                                 \
-       .desc   = {                                                             \
-               .name   = tps6591x_rails(_id),                                  \
-               .ops    = &tps6591x_regulator_##_ops,                           \
-               .type   = REGULATOR_VOLTAGE,                                    \
-               .id     = TPS6591X_ID_##_id,                                    \
-               .n_voltages = ARRAY_SIZE(tps6591x_##vdata##_voltages),          \
-               .owner  = THIS_MODULE,                                          \
-       },                                                                      \
-       .supply_type    = supply_type_##s_type,                                 \
-       .supply_reg     = {                                                     \
-               .addr   = TPS6591X_##s_addr##_ADD,                              \
-               .nbits  = s_nbits,                                              \
-               .shift_bits = s_shift,                                          \
-       },                                                                      \
-       .op_reg         = {                                                     \
-               .addr   = TPS6591X_##op_addr##_ADD,                             \
-               .nbits  = op_nbits,                                             \
-               .shift_bits = op_shift,                                         \
-       },                                                                      \
-       .sr_reg         = {                                                     \
-               .addr   = TPS6591X_##sr_addr##_ADD,                             \
-               .nbits  = sr_nbits,                                             \
-               .shift_bits = sr_shift,                                         \
-       },                                                                      \
-       .en1_reg        = {                                                     \
-               .addr   = TPS6591X_##en1_addr##_ADD,                            \
-               .nbits  = 1,                                                    \
-               .shift_bits = en1_shift,                                        \
-       },                                                                      \
-       .slp_off_reg    = {                                                     \
-               .addr   = TPS6591X_SLEEP_SET_##slp_off_addr##_ADD,              \
-               .nbits  = 1,                                                    \
-               .shift_bits = slp_off_shift,                                    \
-       },                                                                      \
-       .voltages       = tps6591x_##vdata##_voltages,                          \
-       .delay          = en_time,
+#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,        \
+                       slp_off_addr, slp_off_shift, en_time,           \
+                       change_rate)                                    \
+       .desc   = {                                                     \
+               .name   = tps6591x_rails(_id),                          \
+               .ops    = &tps6591x_regulator_##_ops,                   \
+               .type   = REGULATOR_VOLTAGE,                            \
+               .id     = TPS6591X_ID_##_id,                            \
+               .n_voltages = ARRAY_SIZE(tps6591x_##vdata##_voltages),  \
+               .owner  = THIS_MODULE,                                  \
+       },                                                              \
+       .supply_type    = supply_type_##s_type,                         \
+       .supply_reg     = {                                             \
+               .addr   = TPS6591X_##s_addr##_ADD,                      \
+               .nbits  = s_nbits,                                      \
+               .shift_bits = s_shift,                                  \
+       },                                                              \
+       .op_reg         = {                                             \
+               .addr   = TPS6591X_##op_addr##_ADD,                     \
+               .nbits  = op_nbits,                                     \
+               .shift_bits = op_shift,                                 \
+       },                                                              \
+       .sr_reg         = {                                             \
+               .addr   = TPS6591X_##sr_addr##_ADD,                     \
+               .nbits  = sr_nbits,                                     \
+               .shift_bits = sr_shift,                                 \
+       },                                                              \
+       .en1_reg        = {                                             \
+               .addr   = TPS6591X_##en1_addr##_ADD,                    \
+               .nbits  = 1,                                            \
+               .shift_bits = en1_shift,                                \
+       },                                                              \
+       .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, slp_off_shift, en_time)              \
@@ -575,7 +647,7 @@ static int tps6591x_vddctrl_voltages[] = {
        TPS6591X_REGULATOR(_id, vdata, vio_ops, s_addr, s_nbits,        \
                        s_shift, s_type, INVALID, 0, 0, INVALID, 0, 0,  \
                        EN1_SMPS, en1_shift, RES_OFF, slp_off_shift,    \
-                       en_time)                                        \
+                       en_time, 10000)                                 \
 }
 
 #define TPS6591X_LDO1(_id, vdata, s_addr, s_nbits, s_shift, s_type,    \
@@ -584,7 +656,7 @@ static int tps6591x_vddctrl_voltages[] = {
        TPS6591X_REGULATOR(_id, vdata, ldo1_ops, s_addr, s_nbits,       \
                        s_shift, s_type, INVALID, 0, 0, INVALID, 0, 0,  \
                        EN1_LDO, en1_shift, LDO_OFF, slp_off_shift,     \
-                       en_time)                                        \
+                       en_time, 6000)                                  \
 }
 
 #define TPS6591X_LDO3(_id, vdata, s_addr, s_nbits, s_shift, s_type,    \
@@ -593,7 +665,7 @@ static int tps6591x_vddctrl_voltages[] = {
        TPS6591X_REGULATOR(_id, vdata, ldo3_ops, s_addr, s_nbits,       \
                        s_shift, s_type, INVALID, 0, 0, INVALID, 0, 0,  \
                        EN1_LDO, en1_shift, LDO_OFF, slp_off_shift,     \
-                       en_time)                                        \
+                       en_time, 11000)                                 \
 }
 
 #define TPS6591X_VDD(_id, vdata, s_addr, s_nbits, s_shift, s_type,     \
@@ -603,7 +675,8 @@ static int tps6591x_vddctrl_voltages[] = {
        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, RES_OFF, slp_off_shift, en_time)     \
+                       en1_shift, RES_OFF, slp_off_shift, en_time,     \
+                       5000)                                           \
 }
 
 static struct tps6591x_regulator tps6591x_regulator[] = {
@@ -629,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(
@@ -649,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:
@@ -657,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:
@@ -667,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:
@@ -675,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:
@@ -690,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;
 }
 
@@ -715,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;
@@ -731,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);
 
@@ -757,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",
@@ -764,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)