[PATCHv4 2/6] regulator: tps65911: Add new chip version

From: Jorge Eduardo Candelaria
Date: Mon May 16 2011 - 19:35:34 EST


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@xxxxxxxxxxxxxxx>
Acked-by: Mark Brown <broonie@xxxxxxxxxxxxxxxxxxxxxxxxxxx>
---
drivers/regulator/tps65910-regulator.c | 357 +++++++++++++++++++++++++++++---
include/linux/mfd/tps65910.h | 10 +-
2 files changed, 332 insertions(+), 35 deletions(-)

diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 048ba47..d3c8673 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -39,8 +39,17 @@
#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;
diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h
index 6ceea0d..20359e6 100644
--- a/include/linux/mfd/tps65910.h
+++ b/include/linux/mfd/tps65910.h
@@ -232,7 +232,6 @@
#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
@@ -249,6 +248,8 @@
#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
@@ -259,6 +260,13 @@
#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
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/