Merge branch 'next/cross-platform' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / regulator / tps65910-regulator.c
index d461fa7..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,15 +855,25 @@ 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;
        struct tps65910_board *pmic_plat_data;
-       static int desc_id;
        int i, err;
 
        pmic_plat_data = dev_get_platdata(tps65910->dev);
@@ -625,20 +894,39 @@ 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;
 
                pmic->desc[i].name = info->name;
-               pmic->desc[i].id = desc_id++;
+               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;