Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
[cascardo/linux.git] / drivers / regulator / twl-regulator.c
index 6a29285..87fe0f7 100644 (file)
@@ -51,8 +51,13 @@ struct twlreg_info {
        u16                     min_mV;
        u16                     max_mV;
 
+       u8                      flags;
+
        /* used by regulator core */
        struct regulator_desc   desc;
+
+       /* chip specific features */
+       unsigned long           features;
 };
 
 
@@ -70,12 +75,35 @@ struct twlreg_info {
 #define VREG_TRANS             1
 #define VREG_STATE             2
 #define VREG_VOLTAGE           3
+#define VREG_VOLTAGE_SMPS      4
 /* TWL6030 Misc register offsets */
 #define VREG_BC_ALL            1
 #define VREG_BC_REF            2
 #define VREG_BC_PROC           3
 #define VREG_BC_CLK_RST                4
 
+/* TWL6030 LDO register values for CFG_STATE */
+#define TWL6030_CFG_STATE_OFF  0x00
+#define TWL6030_CFG_STATE_ON   0x01
+#define TWL6030_CFG_STATE_OFF2 0x02
+#define TWL6030_CFG_STATE_SLEEP        0x03
+#define TWL6030_CFG_STATE_GRP_SHIFT    5
+#define TWL6030_CFG_STATE_APP_SHIFT    2
+#define TWL6030_CFG_STATE_APP_MASK     (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
+#define TWL6030_CFG_STATE_APP(v)       (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
+                                               TWL6030_CFG_STATE_APP_SHIFT)
+
+/* Flags for SMPS Voltage reading */
+#define SMPS_OFFSET_EN         BIT(0)
+#define SMPS_EXTENDED_EN       BIT(1)
+
+/* twl6025 SMPS EPROM values */
+#define TWL6030_SMPS_OFFSET            0xB0
+#define TWL6030_SMPS_MULT              0xB3
+#define SMPS_MULTOFFSET_SMPS4  BIT(0)
+#define SMPS_MULTOFFSET_VIO    BIT(1)
+#define SMPS_MULTOFFSET_SMPS3  BIT(6)
+
 static inline int
 twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset)
 {
@@ -118,21 +146,38 @@ static int twlreg_grp(struct regulator_dev *rdev)
 #define P2_GRP_6030    BIT(1)          /* "peripherals" */
 #define P1_GRP_6030    BIT(0)          /* CPU/Linux */
 
-static int twlreg_is_enabled(struct regulator_dev *rdev)
+static int twl4030reg_is_enabled(struct regulator_dev *rdev)
 {
        int     state = twlreg_grp(rdev);
 
        if (state < 0)
                return state;
 
-       if (twl_class_is_4030())
-               state &= P1_GRP_4030;
+       return state & P1_GRP_4030;
+}
+
+static int twl6030reg_is_enabled(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp = 0, val;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+       if (grp < 0)
+               return grp;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp &= P1_GRP_6030;
        else
-               state &= P1_GRP_6030;
-       return state;
+               grp = 1;
+
+       val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+       val = TWL6030_CFG_STATE_APP(val);
+
+       return grp && (val == TWL6030_CFG_STATE_ON);
 }
 
-static int twlreg_enable(struct regulator_dev *rdev)
+static int twl4030reg_enable(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     grp;
@@ -142,10 +187,7 @@ static int twlreg_enable(struct regulator_dev *rdev)
        if (grp < 0)
                return grp;
 
-       if (twl_class_is_4030())
-               grp |= P1_GRP_4030;
-       else
-               grp |= P1_GRP_6030;
+       grp |= P1_GRP_4030;
 
        ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
 
@@ -154,29 +196,63 @@ static int twlreg_enable(struct regulator_dev *rdev)
        return ret;
 }
 
-static int twlreg_disable(struct regulator_dev *rdev)
+static int twl6030reg_enable(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp = 0;
+       int                     ret;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+       if (grp < 0)
+               return grp;
+
+       ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+                       grp << TWL6030_CFG_STATE_GRP_SHIFT |
+                       TWL6030_CFG_STATE_ON);
+
+       udelay(info->delay);
+
+       return ret;
+}
+
+static int twl4030reg_disable(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     grp;
+       int                     ret;
 
        grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
        if (grp < 0)
                return grp;
 
-       if (twl_class_is_4030())
-               grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
-       else
-               grp &= ~(P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030);
+       grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
 
-       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+       ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+
+       return ret;
 }
 
-static int twlreg_get_status(struct regulator_dev *rdev)
+static int twl6030reg_disable(struct regulator_dev *rdev)
 {
-       int     state = twlreg_grp(rdev);
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp = 0;
+       int                     ret;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030;
+
+       /* For 6030, set the off state for all grps enabled */
+       ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+                       (grp) << TWL6030_CFG_STATE_GRP_SHIFT |
+                       TWL6030_CFG_STATE_OFF);
+
+       return ret;
+}
 
-       if (twl_class_is_6030())
-               return 0; /* FIXME return for 6030 regulator */
+static int twl4030reg_get_status(struct regulator_dev *rdev)
+{
+       int     state = twlreg_grp(rdev);
 
        if (state < 0)
                return state;
@@ -190,15 +266,39 @@ static int twlreg_get_status(struct regulator_dev *rdev)
                : REGULATOR_STATUS_STANDBY;
 }
 
-static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
+static int twl6030reg_get_status(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     val;
+
+       val = twlreg_grp(rdev);
+       if (val < 0)
+               return val;
+
+       val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+
+       switch (TWL6030_CFG_STATE_APP(val)) {
+       case TWL6030_CFG_STATE_ON:
+               return REGULATOR_STATUS_NORMAL;
+
+       case TWL6030_CFG_STATE_SLEEP:
+               return REGULATOR_STATUS_STANDBY;
+
+       case TWL6030_CFG_STATE_OFF:
+       case TWL6030_CFG_STATE_OFF2:
+       default:
+               break;
+       }
+
+       return REGULATOR_STATUS_OFF;
+}
+
+static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        unsigned                message;
        int                     status;
 
-       if (twl_class_is_6030())
-               return 0; /* FIXME return for 6030 regulator */
-
        /* We can only set the mode through state machine commands... */
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
@@ -227,6 +327,36 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
                        message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);
 }
 
+static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int grp = 0;
+       int val;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+
+       if (grp < 0)
+               return grp;
+
+       /* Compose the state register settings */
+       val = grp << TWL6030_CFG_STATE_GRP_SHIFT;
+       /* We can only set the mode through state machine commands... */
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               val |= TWL6030_CFG_STATE_ON;
+               break;
+       case REGULATOR_MODE_STANDBY:
+               val |= TWL6030_CFG_STATE_SLEEP;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val);
+}
+
 /*----------------------------------------------------------------------*/
 
 /*
@@ -375,13 +505,13 @@ static struct regulator_ops twl4030ldo_ops = {
        .set_voltage    = twl4030ldo_set_voltage,
        .get_voltage    = twl4030ldo_get_voltage,
 
-       .enable         = twlreg_enable,
-       .disable        = twlreg_disable,
-       .is_enabled     = twlreg_is_enabled,
+       .enable         = twl4030reg_enable,
+       .disable        = twl4030reg_disable,
+       .is_enabled     = twl4030reg_is_enabled,
 
-       .set_mode       = twlreg_set_mode,
+       .set_mode       = twl4030reg_set_mode,
 
-       .get_status     = twlreg_get_status,
+       .get_status     = twl4030reg_get_status,
 };
 
 static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
@@ -433,13 +563,13 @@ static struct regulator_ops twl6030ldo_ops = {
        .set_voltage    = twl6030ldo_set_voltage,
        .get_voltage    = twl6030ldo_get_voltage,
 
-       .enable         = twlreg_enable,
-       .disable        = twlreg_disable,
-       .is_enabled     = twlreg_is_enabled,
+       .enable         = twl6030reg_enable,
+       .disable        = twl6030reg_disable,
+       .is_enabled     = twl6030reg_is_enabled,
 
-       .set_mode       = twlreg_set_mode,
+       .set_mode       = twl6030reg_set_mode,
 
-       .get_status     = twlreg_get_status,
+       .get_status     = twl6030reg_get_status,
 };
 
 /*----------------------------------------------------------------------*/
@@ -461,25 +591,242 @@ static int twlfixed_get_voltage(struct regulator_dev *rdev)
        return info->min_mV * 1000;
 }
 
-static struct regulator_ops twlfixed_ops = {
+static struct regulator_ops twl4030fixed_ops = {
+       .list_voltage   = twlfixed_list_voltage,
+
+       .get_voltage    = twlfixed_get_voltage,
+
+       .enable         = twl4030reg_enable,
+       .disable        = twl4030reg_disable,
+       .is_enabled     = twl4030reg_is_enabled,
+
+       .set_mode       = twl4030reg_set_mode,
+
+       .get_status     = twl4030reg_get_status,
+};
+
+static struct regulator_ops twl6030fixed_ops = {
        .list_voltage   = twlfixed_list_voltage,
 
        .get_voltage    = twlfixed_get_voltage,
 
-       .enable         = twlreg_enable,
-       .disable        = twlreg_disable,
-       .is_enabled     = twlreg_is_enabled,
+       .enable         = twl6030reg_enable,
+       .disable        = twl6030reg_disable,
+       .is_enabled     = twl6030reg_is_enabled,
 
-       .set_mode       = twlreg_set_mode,
+       .set_mode       = twl6030reg_set_mode,
 
-       .get_status     = twlreg_get_status,
+       .get_status     = twl6030reg_get_status,
 };
 
 static struct regulator_ops twl6030_fixed_resource = {
-       .enable         = twlreg_enable,
-       .disable        = twlreg_disable,
-       .is_enabled     = twlreg_is_enabled,
-       .get_status     = twlreg_get_status,
+       .enable         = twl6030reg_enable,
+       .disable        = twl6030reg_disable,
+       .is_enabled     = twl6030reg_is_enabled,
+       .get_status     = twl6030reg_get_status,
+};
+
+/*
+ * SMPS status and control
+ */
+
+static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       int voltage = 0;
+
+       switch (info->flags) {
+       case SMPS_OFFSET_EN:
+               voltage = 100000;
+               /* fall through */
+       case 0:
+               switch (index) {
+               case 0:
+                       voltage = 0;
+                       break;
+               case 58:
+                       voltage = 1350 * 1000;
+                       break;
+               case 59:
+                       voltage = 1500 * 1000;
+                       break;
+               case 60:
+                       voltage = 1800 * 1000;
+                       break;
+               case 61:
+                       voltage = 1900 * 1000;
+                       break;
+               case 62:
+                       voltage = 2100 * 1000;
+                       break;
+               default:
+                       voltage += (600000 + (12500 * (index - 1)));
+               }
+               break;
+       case SMPS_EXTENDED_EN:
+               switch (index) {
+               case 0:
+                       voltage = 0;
+                       break;
+               case 58:
+                       voltage = 2084 * 1000;
+                       break;
+               case 59:
+                       voltage = 2315 * 1000;
+                       break;
+               case 60:
+                       voltage = 2778 * 1000;
+                       break;
+               case 61:
+                       voltage = 2932 * 1000;
+                       break;
+               case 62:
+                       voltage = 3241 * 1000;
+                       break;
+               default:
+                       voltage = (1852000 + (38600 * (index - 1)));
+               }
+               break;
+       case SMPS_OFFSET_EN | SMPS_EXTENDED_EN:
+               switch (index) {
+               case 0:
+                       voltage = 0;
+                       break;
+               case 58:
+                       voltage = 4167 * 1000;
+                       break;
+               case 59:
+                       voltage = 2315 * 1000;
+                       break;
+               case 60:
+                       voltage = 2778 * 1000;
+                       break;
+               case 61:
+                       voltage = 2932 * 1000;
+                       break;
+               case 62:
+                       voltage = 3241 * 1000;
+                       break;
+               default:
+                       voltage = (2161000 + (38600 * (index - 1)));
+               }
+               break;
+       }
+
+       return voltage;
+}
+
+static int
+twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+                       unsigned int *selector)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int     vsel = 0;
+
+       switch (info->flags) {
+       case 0:
+               if (min_uV == 0)
+                       vsel = 0;
+               else if ((min_uV >= 600000) && (max_uV <= 1300000)) {
+                       vsel = (min_uV - 600000) / 125;
+                       if (vsel % 100)
+                               vsel += 100;
+                       vsel /= 100;
+                       vsel++;
+               }
+               /* Values 1..57 for vsel are linear and can be calculated
+                * values 58..62 are non linear.
+                */
+               else if ((min_uV > 1900000) && (max_uV >= 2100000))
+                       vsel = 62;
+               else if ((min_uV > 1800000) && (max_uV >= 1900000))
+                       vsel = 61;
+               else if ((min_uV > 1500000) && (max_uV >= 1800000))
+                       vsel = 60;
+               else if ((min_uV > 1350000) && (max_uV >= 1500000))
+                       vsel = 59;
+               else if ((min_uV > 1300000) && (max_uV >= 1350000))
+                       vsel = 58;
+               else
+                       return -EINVAL;
+               break;
+       case SMPS_OFFSET_EN:
+               if (min_uV == 0)
+                       vsel = 0;
+               else if ((min_uV >= 700000) && (max_uV <= 1420000)) {
+                       vsel = (min_uV - 700000) / 125;
+                       if (vsel % 100)
+                               vsel += 100;
+                       vsel /= 100;
+                       vsel++;
+               }
+               /* Values 1..57 for vsel are linear and can be calculated
+                * values 58..62 are non linear.
+                */
+               else if ((min_uV > 1900000) && (max_uV >= 2100000))
+                       vsel = 62;
+               else if ((min_uV > 1800000) && (max_uV >= 1900000))
+                       vsel = 61;
+               else if ((min_uV > 1350000) && (max_uV >= 1800000))
+                       vsel = 60;
+               else if ((min_uV > 1350000) && (max_uV >= 1500000))
+                       vsel = 59;
+               else if ((min_uV > 1300000) && (max_uV >= 1350000))
+                       vsel = 58;
+               else
+                       return -EINVAL;
+               break;
+       case SMPS_EXTENDED_EN:
+               if (min_uV == 0)
+                       vsel = 0;
+               else if ((min_uV >= 1852000) && (max_uV <= 4013600)) {
+                       vsel = (min_uV - 1852000) / 386;
+                       if (vsel % 100)
+                               vsel += 100;
+                       vsel /= 100;
+                       vsel++;
+               }
+               break;
+       case SMPS_OFFSET_EN|SMPS_EXTENDED_EN:
+               if (min_uV == 0)
+                       vsel = 0;
+               else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
+                       vsel = (min_uV - 1852000) / 386;
+                       if (vsel % 100)
+                               vsel += 100;
+                       vsel /= 100;
+                       vsel++;
+               }
+               break;
+       }
+
+       *selector = vsel;
+
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS,
+                                                       vsel);
+}
+
+static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS);
+}
+
+static struct regulator_ops twlsmps_ops = {
+       .list_voltage           = twl6030smps_list_voltage,
+
+       .set_voltage            = twl6030smps_set_voltage,
+       .get_voltage_sel        = twl6030smps_get_voltage_sel,
+
+       .enable                 = twl6030reg_enable,
+       .disable                = twl6030reg_disable,
+       .is_enabled             = twl6030reg_is_enabled,
+
+       .set_mode               = twl6030reg_set_mode,
+
+       .get_status             = twl6030reg_get_status,
 };
 
 /*----------------------------------------------------------------------*/
@@ -487,11 +834,10 @@ static struct regulator_ops twl6030_fixed_resource = {
 #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
                        remap_conf) \
                TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
-                       remap_conf, TWL4030)
-#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
-                       remap_conf) \
+                       remap_conf, TWL4030, twl4030fixed_ops)
+#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \
                TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
-                       remap_conf, TWL6030)
+                       0x0, TWL6030, twl6030fixed_ops)
 
 #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \
        .base = offset, \
@@ -510,13 +856,11 @@ static struct regulator_ops twl6030_fixed_resource = {
                }, \
        }
 
-#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num, \
-               remap_conf) { \
+#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
        .base = offset, \
        .id = num, \
        .min_mV = min_mVolts, \
        .max_mV = max_mVolts, \
-       .remap = remap_conf, \
        .desc = { \
                .name = #label, \
                .id = TWL6030_REG_##label, \
@@ -527,9 +871,23 @@ static struct regulator_ops twl6030_fixed_resource = {
                }, \
        }
 
+#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
+       .base = offset, \
+       .id = num, \
+       .min_mV = min_mVolts, \
+       .max_mV = max_mVolts, \
+       .desc = { \
+               .name = #label, \
+               .id = TWL6025_REG_##label, \
+               .n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \
+               .ops = &twl6030ldo_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
 
 #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
-               family) { \
+               family, operations) { \
        .base = offset, \
        .id = num, \
        .min_mV = mVolts, \
@@ -539,17 +897,16 @@ static struct regulator_ops twl6030_fixed_resource = {
                .name = #label, \
                .id = family##_REG_##label, \
                .n_voltages = 1, \
-               .ops = &twlfixed_ops, \
+               .ops = &operations, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
                }, \
        }
 
-#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay, remap_conf) { \
+#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \
        .base = offset, \
        .id = num, \
        .delay = turnon_delay, \
-       .remap = remap_conf, \
        .desc = { \
                .name = #label, \
                .id = TWL6030_REG_##label, \
@@ -559,6 +916,21 @@ static struct regulator_ops twl6030_fixed_resource = {
                }, \
        }
 
+#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \
+       .base = offset, \
+       .id = num, \
+       .min_mV = 600, \
+       .max_mV = 2100, \
+       .desc = { \
+               .name = #label, \
+               .id = TWL6025_REG_##label, \
+               .n_voltages = 63, \
+               .ops = &twlsmps_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
+
 /*
  * We list regulators here if systems need some level of
  * software control over them after boot.
@@ -589,19 +961,52 @@ static struct twlreg_info twl_regs[] = {
        /* 6030 REG with base as PMC Slave Misc : 0x0030 */
        /* Turnon-delay and remap configuration values for 6030 are not
           verified since the specification is not public */
-       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7, 0x21),
-       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21),
-       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21),
-       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21),
-       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21),
-       TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0, 0x21),
+       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1),
+       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2),
+       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3),
+       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4),
+       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5),
+       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7),
+       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0),
+       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0),
+       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0),
+       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0),
+       TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0),
+
+       /* 6025 are renamed compared to 6030 versions */
+       TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1),
+       TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2),
+       TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3),
+       TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4),
+       TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5),
+       TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7),
+       TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16),
+       TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17),
+       TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18),
+
+       TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1),
+       TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2),
+       TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3),
 };
 
+static u8 twl_get_smps_offset(void)
+{
+       u8 value;
+
+       twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+                       TWL6030_SMPS_OFFSET);
+       return value;
+}
+
+static u8 twl_get_smps_mult(void)
+{
+       u8 value;
+
+       twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+                       TWL6030_SMPS_MULT);
+       return value;
+}
+
 static int __devinit twlreg_probe(struct platform_device *pdev)
 {
        int                             i;
@@ -623,6 +1028,9 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
        if (!initdata)
                return -EINVAL;
 
+       /* copy the features into regulator data */
+       info->features = (unsigned long)initdata->driver_data;
+
        /* Constrain board-specific capabilities according to what
         * this driver and the chip itself can actually do.
         */
@@ -645,6 +1053,27 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
                break;
        }
 
+       switch (pdev->id) {
+       case TWL6025_REG_SMPS3:
+               if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3)
+                       info->flags |= SMPS_EXTENDED_EN;
+               if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3)
+                       info->flags |= SMPS_OFFSET_EN;
+               break;
+       case TWL6025_REG_SMPS4:
+               if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4)
+                       info->flags |= SMPS_EXTENDED_EN;
+               if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4)
+                       info->flags |= SMPS_OFFSET_EN;
+               break;
+       case TWL6025_REG_VIO:
+               if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO)
+                       info->flags |= SMPS_EXTENDED_EN;
+               if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO)
+                       info->flags |= SMPS_OFFSET_EN;
+               break;
+       }
+
        rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
        if (IS_ERR(rdev)) {
                dev_err(&pdev->dev, "can't register %s, %ld\n",
@@ -653,7 +1082,8 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, rdev);
 
-       twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
+       if (twl_class_is_4030())
+               twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
                                                info->remap);
 
        /* NOTE:  many regulators support short-circuit IRQs (presentable