regulator: tps65911: Add new chip version
authorJorge Eduardo Candelaria <jedu@slimlogic.co.uk>
Mon, 16 May 2011 23:35:03 +0000 (18:35 -0500)
committerLiam Girdwood <lrg@slimlogic.co.uk>
Fri, 27 May 2011 09:49:10 +0000 (10:49 +0100)
The tps65911 chip introduces new features, including changes in
the regulator module.

- VDD1 and VDD2 remain unchanged.
- VDD3 is now named VDDCTRL and has a wider voltage range.
- LDOs are now named LDO1...8 and voltage ranges are sequential,
  making LDOs easier to handle.

Signed-off-by: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
drivers/regulator/tps65910-regulator.c
include/linux/mfd/tps65910.h

index 048ba47..55dd4e6 100644 (file)
 #define TPS65910_REG_VAUX33            11
 #define TPS65910_REG_VMMC              12
 
-#define TPS65910_NUM_REGULATOR         13
+#define TPS65911_REG_VDDCTRL           4
+#define TPS65911_REG_LDO1              5
+#define TPS65911_REG_LDO2              6
+#define TPS65911_REG_LDO3              7
+#define TPS65911_REG_LDO4              8
+#define TPS65911_REG_LDO5              9
+#define TPS65911_REG_LDO6              10
+#define TPS65911_REG_LDO7              11
+#define TPS65911_REG_LDO8              12
 
+#define TPS65910_NUM_REGULATOR         13
 #define TPS65910_SUPPLY_STATE_ENABLED  0x1
 
 /* supported VIO voltages in milivolts */
@@ -48,7 +57,9 @@ static const u16 VIO_VSEL_table[] = {
        1500, 1800, 2500, 3300,
 };
 
-/* supported VIO voltages in milivolts */
+/* VSEL tables for TPS65910 specific LDOs and dcdc's */
+
+/* supported VDD3 voltages in milivolts */
 static const u16 VDD3_VSEL_table[] = {
        5000,
 };
@@ -187,6 +198,71 @@ static struct tps_info tps65910_regs[] = {
        },
 };
 
+static struct tps_info tps65911_regs[] = {
+       {
+               .name = "VIO",
+               .min_uV = 1500000,
+               .max_uV = 3300000,
+               .table_len = ARRAY_SIZE(VIO_VSEL_table),
+               .table = VIO_VSEL_table,
+       },
+       {
+               .name = "VDD1",
+               .min_uV = 600000,
+               .max_uV = 4500000,
+       },
+       {
+               .name = "VDD2",
+               .min_uV = 600000,
+               .max_uV = 4500000,
+       },
+       {
+               .name = "VDDCTRL",
+               .min_uV = 600000,
+               .max_uV = 1400000,
+       },
+       {
+               .name = "LDO1",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO2",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO3",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO4",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO5",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO6",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO7",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO8",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+};
+
 struct tps65910_reg {
        struct regulator_desc desc[TPS65910_NUM_REGULATOR];
        struct tps65910 *mfd;
@@ -194,6 +270,7 @@ struct tps65910_reg {
        struct tps_info *info[TPS65910_NUM_REGULATOR];
        struct mutex mutex;
        int mode;
+       int  (*get_ctrl_reg)(int);
 };
 
 static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
@@ -300,12 +377,46 @@ static int tps65910_get_ctrl_register(int id)
        }
 }
 
+static int tps65911_get_ctrl_register(int id)
+{
+       switch (id) {
+       case TPS65910_REG_VRTC:
+               return TPS65910_VRTC;
+       case TPS65910_REG_VIO:
+               return TPS65910_VIO;
+       case TPS65910_REG_VDD1:
+               return TPS65910_VDD1;
+       case TPS65910_REG_VDD2:
+               return TPS65910_VDD2;
+       case TPS65911_REG_VDDCTRL:
+               return TPS65911_VDDCTRL;
+       case TPS65911_REG_LDO1:
+               return TPS65911_LDO1;
+       case TPS65911_REG_LDO2:
+               return TPS65911_LDO2;
+       case TPS65911_REG_LDO3:
+               return TPS65911_LDO3;
+       case TPS65911_REG_LDO4:
+               return TPS65911_LDO4;
+       case TPS65911_REG_LDO5:
+               return TPS65911_LDO5;
+       case TPS65911_REG_LDO6:
+               return TPS65911_LDO6;
+       case TPS65911_REG_LDO7:
+               return TPS65911_LDO7;
+       case TPS65911_REG_LDO8:
+               return TPS65911_LDO8;
+       default:
+               return -EINVAL;
+       }
+}
+
 static int tps65910_is_enabled(struct regulator_dev *dev)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int reg, value, id = rdev_get_id(dev);
 
-       reg = tps65910_get_ctrl_register(id);
+       reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
@@ -322,7 +433,7 @@ static int tps65910_enable(struct regulator_dev *dev)
        struct tps65910 *mfd = pmic->mfd;
        int reg, id = rdev_get_id(dev);
 
-       reg = tps65910_get_ctrl_register(id);
+       reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
@@ -335,7 +446,7 @@ static int tps65910_disable(struct regulator_dev *dev)
        struct tps65910 *mfd = pmic->mfd;
        int reg, id = rdev_get_id(dev);
 
-       reg = tps65910_get_ctrl_register(id);
+       reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
@@ -348,7 +459,8 @@ static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        struct tps65910 *mfd = pmic->mfd;
        int reg, value, id = rdev_get_id(dev);
-       reg = tps65910_get_ctrl_register(id);
+
+       reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
@@ -371,7 +483,7 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev)
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int reg, value, id = rdev_get_id(dev);
 
-       reg = tps65910_get_ctrl_register(id);
+       reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
@@ -391,7 +503,7 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int id = rdev_get_id(dev), voltage = 0;
-       int opvsel = 0, srvsel = 0, mult = 0, sr = 0;
+       int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0;
 
        switch (id) {
        case TPS65910_REG_VDD1:
@@ -402,6 +514,7 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
                sr = opvsel & VDD1_OP_CMD_MASK;
                opvsel &= VDD1_OP_SEL_MASK;
                srvsel &= VDD1_SR_SEL_MASK;
+               vselmax = 75;
                break;
        case TPS65910_REG_VDD2:
                opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP);
@@ -411,6 +524,15 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
                sr = opvsel & VDD2_OP_CMD_MASK;
                opvsel &= VDD2_OP_SEL_MASK;
                srvsel &= VDD2_SR_SEL_MASK;
+               vselmax = 75;
+               break;
+       case TPS65911_REG_VDDCTRL:
+               opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP);
+               srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR);
+               sr = opvsel & VDDCTRL_OP_CMD_MASK;
+               opvsel &= VDDCTRL_OP_SEL_MASK;
+               srvsel &= VDDCTRL_SR_SEL_MASK;
+               vselmax = 64;
                break;
        }
 
@@ -419,17 +541,21 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
                mult=1;
 
        if (sr) {
-               /* Valid range is 3-75 so normalise */
-               if (srvsel < 3) srvsel = 3;
-               if (srvsel > 75) srvsel = 75;
+               /* normalise to valid range */
+               if (srvsel < 3)
+                       srvsel = 3;
+               if (srvsel > vselmax)
+                       srvsel = vselmax;
                srvsel -= 3;
 
                voltage = (srvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100;
        } else {
 
-               /* Valid range is 3-75 so normalise */
-               if (opvsel < 3) opvsel = 3;
-               if (opvsel > 75) opvsel = 75;
+               /* normalise to valid range*/
+               if (opvsel < 3)
+                       opvsel = 3;
+               if (opvsel > vselmax)
+                       opvsel = vselmax;
                opvsel -= 3;
 
                voltage = (opvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100;
@@ -445,7 +571,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev)
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int reg, value, id = rdev_get_id(dev), voltage = 0;
 
-       reg = tps65910_get_ctrl_register(id);
+       reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
@@ -480,29 +606,88 @@ static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
        return 5 * 1000 * 1000;
 }
 
+static int tps65911_get_voltage(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int step_mv, id = rdev_get_id(dev);
+       u8 value, reg;
+
+       reg = pmic->get_ctrl_reg(id);
+
+       value = tps65910_reg_read(pmic, reg);
+
+       switch (id) {
+       case TPS65911_REG_LDO1:
+       case TPS65911_REG_LDO2:
+       case TPS65911_REG_LDO4:
+               value &= LDO1_SEL_MASK;
+               value >>= LDO_SEL_SHIFT;
+               /* The first 5 values of the selector correspond to 1V */
+               if (value < 5)
+                       value = 0;
+               else
+                       value -= 4;
+
+               step_mv = 50;
+               break;
+       case TPS65911_REG_LDO3:
+       case TPS65911_REG_LDO5:
+       case TPS65911_REG_LDO6:
+       case TPS65911_REG_LDO7:
+       case TPS65911_REG_LDO8:
+               value &= LDO3_SEL_MASK;
+               value >>= LDO_SEL_SHIFT;
+               /* The first 3 values of the selector correspond to 1V */
+               if (value < 3)
+                       value = 0;
+               else
+                       value -= 2;
+
+               step_mv = 100;
+               break;
+       case TPS65910_REG_VIO:
+               return pmic->info[id]->table[value] * 1000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return (LDO_MIN_VOLT + value * step_mv) * 1000;
+}
+
 static int tps65910_set_voltage_dcdc(struct regulator_dev *dev,
                                unsigned selector)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int id = rdev_get_id(dev), vsel;
-       int dcdc_mult;
+       int dcdc_mult = 0;
 
-       /* Split vsel into appropriate registers */
-       dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
-       if (dcdc_mult == 1) dcdc_mult--;
-
-       vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
+       switch (id) {
+       case TPS65910_REG_VDD1:
+               dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               if (dcdc_mult == 1)
+                       dcdc_mult--;
+               vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
 
-       if (id == TPS65910_REG_VDD1) {
                tps65910_modify_bits(pmic, TPS65910_VDD1,
                                (dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
                                                VDD1_VGAIN_SEL_MASK);
                tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel);
-       } else {
+               break;
+       case TPS65910_REG_VDD2:
+               dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               if (dcdc_mult == 1)
+                       dcdc_mult--;
+               vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
+
                tps65910_modify_bits(pmic, TPS65910_VDD2,
                                (dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
                                                VDD1_VGAIN_SEL_MASK);
                tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel);
+               break;
+       case TPS65911_REG_VDDCTRL:
+               vsel = selector;
+               tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
        }
 
        return 0;
@@ -513,7 +698,7 @@ static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector)
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int reg, id = rdev_get_id(dev);
 
-       reg = tps65910_get_ctrl_register(id);
+       reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
@@ -534,14 +719,49 @@ static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector)
        return -EINVAL;
 }
 
+static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int reg, id = rdev_get_id(dev);
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       switch (id) {
+       case TPS65911_REG_LDO1:
+       case TPS65911_REG_LDO2:
+       case TPS65911_REG_LDO4:
+               return tps65910_modify_bits(pmic, reg,
+                               (selector << LDO_SEL_SHIFT), LDO1_SEL_MASK);
+       case TPS65911_REG_LDO3:
+       case TPS65911_REG_LDO5:
+       case TPS65911_REG_LDO6:
+       case TPS65911_REG_LDO7:
+       case TPS65911_REG_LDO8:
+       case TPS65910_REG_VIO:
+               return tps65910_modify_bits(pmic, reg,
+                               (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK);
+       }
+
+       return -EINVAL;
+}
+
+
 static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
                                        unsigned selector)
 {
-       int mult, volt;
-
-       mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+       int volt, mult = 1, id = rdev_get_id(dev);
 
-       volt = VDD1_2_MIN_VOLT + (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
+       switch (id) {
+       case TPS65910_REG_VDD1:
+       case TPS65910_REG_VDD2:
+               mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               volt = VDD1_2_MIN_VOLT +
+                               (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
+       case TPS65911_REG_VDDCTRL:
+               volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
+       }
 
        return  volt * 100 * mult;
 }
@@ -563,6 +783,45 @@ static int tps65910_list_voltage(struct regulator_dev *dev,
        return voltage;
 }
 
+static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int step_mv = 0, id = rdev_get_id(dev);
+
+       switch(id) {
+       case TPS65911_REG_LDO1:
+       case TPS65911_REG_LDO2:
+       case TPS65911_REG_LDO4:
+               /* The first 5 values of the selector correspond to 1V */
+               if (selector < 5)
+                       selector = 0;
+               else
+                       selector -= 4;
+
+               step_mv = 50;
+               break;
+       case TPS65911_REG_LDO3:
+       case TPS65911_REG_LDO5:
+       case TPS65911_REG_LDO6:
+       case TPS65911_REG_LDO7:
+       case TPS65911_REG_LDO8:
+               /* The first 3 values of the selector correspond to 1V */
+               if (selector < 3)
+                       selector = 0;
+               else
+                       selector -= 2;
+
+               step_mv = 100;
+               break;
+       case TPS65910_REG_VIO:
+               return pmic->info[id]->table[selector] * 1000;
+       default:
+               return -EINVAL;
+       }
+
+       return (LDO_MIN_VOLT + selector * step_mv) * 1000;
+}
+
 /* Regulator ops (except VRTC) */
 static struct regulator_ops tps65910_ops_dcdc = {
        .is_enabled             = tps65910_is_enabled,
@@ -596,10 +855,21 @@ static struct regulator_ops tps65910_ops = {
        .list_voltage           = tps65910_list_voltage,
 };
 
+static struct regulator_ops tps65911_ops = {
+       .is_enabled             = tps65910_is_enabled,
+       .enable                 = tps65910_enable,
+       .disable                = tps65910_disable,
+       .set_mode               = tps65910_set_mode,
+       .get_mode               = tps65910_get_mode,
+       .get_voltage            = tps65911_get_voltage,
+       .set_voltage_sel        = tps65911_set_voltage,
+       .list_voltage           = tps65911_list_voltage,
+};
+
 static __devinit int tps65910_probe(struct platform_device *pdev)
 {
        struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
-       struct tps_info *info = tps65910_regs;
+       struct tps_info *info;
        struct regulator_init_data *reg_data;
        struct regulator_dev *rdev;
        struct tps65910_reg *pmic;
@@ -624,6 +894,18 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
        tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL,
                                DEVCTRL_SR_CTL_I2C_SEL_MASK);
 
+       switch(tps65910_chip_id(tps65910)) {
+       case TPS65910:
+               pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
+               info = tps65910_regs;
+       case TPS65911:
+               pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
+               info = tps65911_regs;
+       default:
+               pr_err("Invalid tps chip version\n");
+               return -ENODEV;
+       }
+
        for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) {
                /* Register the regulators */
                pmic->info[i] = info;
@@ -632,12 +914,19 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
                pmic->desc[i].id = i;
                pmic->desc[i].n_voltages = info->table_len;
 
-               if ((i == TPS65910_REG_VDD1) || (i == TPS65910_REG_VDD2))
+               if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) {
                        pmic->desc[i].ops = &tps65910_ops_dcdc;
-               else if (i == TPS65910_REG_VDD3)
-                       pmic->desc[i].ops = &tps65910_ops_vdd3;
-               else
-                       pmic->desc[i].ops = &tps65910_ops;
+               } else if (i == TPS65910_REG_VDD3) {
+                       if (tps65910_chip_id(tps65910) == TPS65910)
+                               pmic->desc[i].ops = &tps65910_ops_vdd3;
+                       else
+                               pmic->desc[i].ops = &tps65910_ops_dcdc;
+               } else {
+                       if (tps65910_chip_id(tps65910) == TPS65910)
+                               pmic->desc[i].ops = &tps65910_ops;
+                       else
+                               pmic->desc[i].ops = &tps65911_ops;
+               }
 
                pmic->desc[i].type = REGULATOR_VOLTAGE;
                pmic->desc[i].owner = THIS_MODULE;
index 6ceea0d..20359e6 100644 (file)
 #define VDD2_OP_SEL_MASK                               0x7F
 #define VDD2_OP_SEL_SHIFT                              0
 
-
 /*Register VDD2_SR  (0x80) register.RegisterDescription */
 #define VDD2_SR_SEL_MASK                               0x7F
 #define VDD2_SR_SEL_SHIFT                              0
 #define VDD3_CKINEN_SHIFT                              2
 #define VDD3_ST_MASK                                   0x03
 #define VDD3_ST_SHIFT                                  0
+#define VDDCTRL_MIN_VOLT                               6000
+#define VDDCTRL_OFFSET                                 125
 
 /*Registers VDIG (0x80) to VDAC register.RegisterDescription */
 #define LDO_SEL_MASK                                   0x0C
 #define LDO_ST_MODE_BIT                                        0x02    
 
 
+/* Registers LDO1 to LDO8 in tps65910 */
+#define LDO1_SEL_MASK                                  0xFC
+#define LDO3_SEL_MASK                                  0x7C
+#define LDO_MIN_VOLT                                   1000
+#define LDO_MAX_VOLT                                   3300;
+
+
 /*Register VDIG1  (0x80) register.RegisterDescription */
 #define VDIG1_SEL_MASK                                 0x0C
 #define VDIG1_SEL_SHIFT                                        2