xref: /openbmc/linux/drivers/regulator/tps6507x-regulator.c (revision 2ca76b3e4954ea6bbb365005edc8d5237b488cf1)
13fa5b8e0SAnuj Aggarwal /*
23fa5b8e0SAnuj Aggarwal  * tps6507x-regulator.c
33fa5b8e0SAnuj Aggarwal  *
43fa5b8e0SAnuj Aggarwal  * Regulator driver for TPS65073 PMIC
53fa5b8e0SAnuj Aggarwal  *
6*2ca76b3eSAlexander A. Klimov  * Copyright (C) 2009 Texas Instrument Incorporated - https://www.ti.com/
73fa5b8e0SAnuj Aggarwal  *
83fa5b8e0SAnuj Aggarwal  * This program is free software; you can redistribute it and/or
93fa5b8e0SAnuj Aggarwal  * modify it under the terms of the GNU General Public License as
103fa5b8e0SAnuj Aggarwal  * published by the Free Software Foundation version 2.
113fa5b8e0SAnuj Aggarwal  *
123fa5b8e0SAnuj Aggarwal  * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
133fa5b8e0SAnuj Aggarwal  * whether express or implied; without even the implied warranty of
143fa5b8e0SAnuj Aggarwal  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
153fa5b8e0SAnuj Aggarwal  * General Public License for more details.
163fa5b8e0SAnuj Aggarwal  */
173fa5b8e0SAnuj Aggarwal 
183fa5b8e0SAnuj Aggarwal #include <linux/kernel.h>
193fa5b8e0SAnuj Aggarwal #include <linux/module.h>
203fa5b8e0SAnuj Aggarwal #include <linux/init.h>
213fa5b8e0SAnuj Aggarwal #include <linux/err.h>
223fa5b8e0SAnuj Aggarwal #include <linux/platform_device.h>
233fa5b8e0SAnuj Aggarwal #include <linux/regulator/driver.h>
243fa5b8e0SAnuj Aggarwal #include <linux/regulator/machine.h>
257d14831eSAnuj Aggarwal #include <linux/regulator/tps6507x.h>
266116ad94SVishwanathrao Badarkhe, Manish #include <linux/of.h>
275a0e3ad6STejun Heo #include <linux/slab.h>
28d183fcc9STodd Fischer #include <linux/mfd/tps6507x.h>
296116ad94SVishwanathrao Badarkhe, Manish #include <linux/regulator/of_regulator.h>
303fa5b8e0SAnuj Aggarwal 
313fa5b8e0SAnuj Aggarwal /* DCDC's */
323fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_1				0
333fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_2				1
343fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_3				2
353fa5b8e0SAnuj Aggarwal /* LDOs */
363fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_1				3
373fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_2				4
383fa5b8e0SAnuj Aggarwal 
393fa5b8e0SAnuj Aggarwal #define TPS6507X_MAX_REG_ID			TPS6507X_LDO_2
403fa5b8e0SAnuj Aggarwal 
413fa5b8e0SAnuj Aggarwal /* Number of step-down converters available */
423fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_DCDC			3
433fa5b8e0SAnuj Aggarwal /* Number of LDO voltage regulators  available */
443fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_LDO			2
453fa5b8e0SAnuj Aggarwal /* Number of total regulators available */
463fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_REGULATOR		(TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
473fa5b8e0SAnuj Aggarwal 
48055917acSAxel Lin /* Supported voltage values for regulators (in microVolts) */
49055917acSAxel Lin static const unsigned int VDCDCx_VSEL_table[] = {
50055917acSAxel Lin 	725000, 750000, 775000, 800000,
51055917acSAxel Lin 	825000, 850000, 875000, 900000,
52055917acSAxel Lin 	925000, 950000, 975000, 1000000,
53055917acSAxel Lin 	1025000, 1050000, 1075000, 1100000,
54055917acSAxel Lin 	1125000, 1150000, 1175000, 1200000,
55055917acSAxel Lin 	1225000, 1250000, 1275000, 1300000,
56055917acSAxel Lin 	1325000, 1350000, 1375000, 1400000,
57055917acSAxel Lin 	1425000, 1450000, 1475000, 1500000,
58055917acSAxel Lin 	1550000, 1600000, 1650000, 1700000,
59055917acSAxel Lin 	1750000, 1800000, 1850000, 1900000,
60055917acSAxel Lin 	1950000, 2000000, 2050000, 2100000,
61055917acSAxel Lin 	2150000, 2200000, 2250000, 2300000,
62055917acSAxel Lin 	2350000, 2400000, 2450000, 2500000,
63055917acSAxel Lin 	2550000, 2600000, 2650000, 2700000,
64055917acSAxel Lin 	2750000, 2800000, 2850000, 2900000,
65055917acSAxel Lin 	3000000, 3100000, 3200000, 3300000,
663fa5b8e0SAnuj Aggarwal };
673fa5b8e0SAnuj Aggarwal 
68055917acSAxel Lin static const unsigned int LDO1_VSEL_table[] = {
69055917acSAxel Lin 	1000000, 1100000, 1200000, 1250000,
70055917acSAxel Lin 	1300000, 1350000, 1400000, 1500000,
71055917acSAxel Lin 	1600000, 1800000, 2500000, 2750000,
72055917acSAxel Lin 	2800000, 3000000, 3100000, 3300000,
733fa5b8e0SAnuj Aggarwal };
743fa5b8e0SAnuj Aggarwal 
7593b07e7bSAxel Lin /* The voltage mapping table for LDO2 is the same as VDCDCx */
7693b07e7bSAxel Lin #define LDO2_VSEL_table VDCDCx_VSEL_table
773fa5b8e0SAnuj Aggarwal 
783fa5b8e0SAnuj Aggarwal struct tps_info {
793fa5b8e0SAnuj Aggarwal 	const char *name;
803fa5b8e0SAnuj Aggarwal 	u8 table_len;
81055917acSAxel Lin 	const unsigned int *table;
827d14831eSAnuj Aggarwal 
837d14831eSAnuj Aggarwal 	/* Does DCDC high or the low register defines output voltage? */
847d14831eSAnuj Aggarwal 	bool defdcdc_default;
853fa5b8e0SAnuj Aggarwal };
863fa5b8e0SAnuj Aggarwal 
877d14831eSAnuj Aggarwal static struct tps_info tps6507x_pmic_regs[] = {
8831dd6a26STodd Fischer 	{
8931dd6a26STodd Fischer 		.name = "VDCDC1",
9031dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
9131dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
9231dd6a26STodd Fischer 	},
9331dd6a26STodd Fischer 	{
9431dd6a26STodd Fischer 		.name = "VDCDC2",
9531dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
9631dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
9731dd6a26STodd Fischer 	},
9831dd6a26STodd Fischer 	{
9931dd6a26STodd Fischer 		.name = "VDCDC3",
10031dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
10131dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
10231dd6a26STodd Fischer 	},
10331dd6a26STodd Fischer 	{
10431dd6a26STodd Fischer 		.name = "LDO1",
10531dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
10631dd6a26STodd Fischer 		.table = LDO1_VSEL_table,
10731dd6a26STodd Fischer 	},
10831dd6a26STodd Fischer 	{
10931dd6a26STodd Fischer 		.name = "LDO2",
11031dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
11131dd6a26STodd Fischer 		.table = LDO2_VSEL_table,
11231dd6a26STodd Fischer 	},
11331dd6a26STodd Fischer };
11431dd6a26STodd Fischer 
1154ce5ba5bSTodd Fischer struct tps6507x_pmic {
1163fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
11731dd6a26STodd Fischer 	struct tps6507x_dev *mfd;
1187d14831eSAnuj Aggarwal 	struct tps_info *info[TPS6507X_NUM_REGULATOR];
1193fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1203fa5b8e0SAnuj Aggarwal };
1214ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
1223fa5b8e0SAnuj Aggarwal {
12331dd6a26STodd Fischer 	u8 val;
12431dd6a26STodd Fischer 	int err;
12531dd6a26STodd Fischer 
12631dd6a26STodd Fischer 	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
12731dd6a26STodd Fischer 
12831dd6a26STodd Fischer 	if (err)
12931dd6a26STodd Fischer 		return err;
13031dd6a26STodd Fischer 
13131dd6a26STodd Fischer 	return val;
1323fa5b8e0SAnuj Aggarwal }
1333fa5b8e0SAnuj Aggarwal 
1344ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1353fa5b8e0SAnuj Aggarwal {
13631dd6a26STodd Fischer 	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
1373fa5b8e0SAnuj Aggarwal }
1383fa5b8e0SAnuj Aggarwal 
1394ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1403fa5b8e0SAnuj Aggarwal {
1413fa5b8e0SAnuj Aggarwal 	int err, data;
1423fa5b8e0SAnuj Aggarwal 
1433fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1443fa5b8e0SAnuj Aggarwal 
1454ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1463fa5b8e0SAnuj Aggarwal 	if (data < 0) {
14731dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1483fa5b8e0SAnuj Aggarwal 		err = data;
1493fa5b8e0SAnuj Aggarwal 		goto out;
1503fa5b8e0SAnuj Aggarwal 	}
1513fa5b8e0SAnuj Aggarwal 
1523fa5b8e0SAnuj Aggarwal 	data |= mask;
1534ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1543fa5b8e0SAnuj Aggarwal 	if (err)
15531dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1563fa5b8e0SAnuj Aggarwal 
1573fa5b8e0SAnuj Aggarwal out:
1583fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1593fa5b8e0SAnuj Aggarwal 	return err;
1603fa5b8e0SAnuj Aggarwal }
1613fa5b8e0SAnuj Aggarwal 
1624ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1633fa5b8e0SAnuj Aggarwal {
1643fa5b8e0SAnuj Aggarwal 	int err, data;
1653fa5b8e0SAnuj Aggarwal 
1663fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1673fa5b8e0SAnuj Aggarwal 
1684ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1693fa5b8e0SAnuj Aggarwal 	if (data < 0) {
17031dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1713fa5b8e0SAnuj Aggarwal 		err = data;
1723fa5b8e0SAnuj Aggarwal 		goto out;
1733fa5b8e0SAnuj Aggarwal 	}
1743fa5b8e0SAnuj Aggarwal 
1753fa5b8e0SAnuj Aggarwal 	data &= ~mask;
1764ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1773fa5b8e0SAnuj Aggarwal 	if (err)
17831dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1793fa5b8e0SAnuj Aggarwal 
1803fa5b8e0SAnuj Aggarwal out:
1813fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1823fa5b8e0SAnuj Aggarwal 	return err;
1833fa5b8e0SAnuj Aggarwal }
1843fa5b8e0SAnuj Aggarwal 
1854ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
1863fa5b8e0SAnuj Aggarwal {
1873fa5b8e0SAnuj Aggarwal 	int data;
1883fa5b8e0SAnuj Aggarwal 
1893fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1903fa5b8e0SAnuj Aggarwal 
1914ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1923fa5b8e0SAnuj Aggarwal 	if (data < 0)
19331dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1943fa5b8e0SAnuj Aggarwal 
1953fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1963fa5b8e0SAnuj Aggarwal 	return data;
1973fa5b8e0SAnuj Aggarwal }
1983fa5b8e0SAnuj Aggarwal 
1994ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
2003fa5b8e0SAnuj Aggarwal {
2013fa5b8e0SAnuj Aggarwal 	int err;
2023fa5b8e0SAnuj Aggarwal 
2033fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2043fa5b8e0SAnuj Aggarwal 
2054ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, val);
2063fa5b8e0SAnuj Aggarwal 	if (err < 0)
20731dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2083fa5b8e0SAnuj Aggarwal 
2093fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2103fa5b8e0SAnuj Aggarwal 	return err;
2113fa5b8e0SAnuj Aggarwal }
2123fa5b8e0SAnuj Aggarwal 
213f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev)
2143fa5b8e0SAnuj Aggarwal {
2154ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
216f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
2173fa5b8e0SAnuj Aggarwal 	u8 shift;
2183fa5b8e0SAnuj Aggarwal 
219f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2203fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2213fa5b8e0SAnuj Aggarwal 
222f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2234ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2243fa5b8e0SAnuj Aggarwal 
2253fa5b8e0SAnuj Aggarwal 	if (data < 0)
2263fa5b8e0SAnuj Aggarwal 		return data;
2273fa5b8e0SAnuj Aggarwal 	else
2283fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2293fa5b8e0SAnuj Aggarwal }
2303fa5b8e0SAnuj Aggarwal 
231f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev)
2323fa5b8e0SAnuj Aggarwal {
2334ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
234f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2353fa5b8e0SAnuj Aggarwal 	u8 shift;
2363fa5b8e0SAnuj Aggarwal 
237f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2383fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2393fa5b8e0SAnuj Aggarwal 
240f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2414ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
2423fa5b8e0SAnuj Aggarwal }
2433fa5b8e0SAnuj Aggarwal 
244f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev)
2453fa5b8e0SAnuj Aggarwal {
2464ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
247f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2483fa5b8e0SAnuj Aggarwal 	u8 shift;
2493fa5b8e0SAnuj Aggarwal 
250f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2513fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2523fa5b8e0SAnuj Aggarwal 
253f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2544ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
2554ce5ba5bSTodd Fischer 					1 << shift);
2563fa5b8e0SAnuj Aggarwal }
2573fa5b8e0SAnuj Aggarwal 
2587c842a1dSAxel Lin static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev)
2593fa5b8e0SAnuj Aggarwal {
2604ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
261f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
262f2933d33SAxel Lin 	u8 reg, mask;
2633fa5b8e0SAnuj Aggarwal 
264f2933d33SAxel Lin 	switch (rid) {
2653fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
2663fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
267f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2683fa5b8e0SAnuj Aggarwal 		break;
2693fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
270f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2717d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
2727d14831eSAnuj Aggarwal 		else
2733fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
274f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2753fa5b8e0SAnuj Aggarwal 		break;
2763fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
277f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2787d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
2797d14831eSAnuj Aggarwal 		else
2803fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
281f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
282f2933d33SAxel Lin 		break;
283f2933d33SAxel Lin 	case TPS6507X_LDO_1:
284f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
285f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
286f2933d33SAxel Lin 		break;
287f2933d33SAxel Lin 	case TPS6507X_LDO_2:
288f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
289f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
2903fa5b8e0SAnuj Aggarwal 		break;
2913fa5b8e0SAnuj Aggarwal 	default:
2923fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2933fa5b8e0SAnuj Aggarwal 	}
2943fa5b8e0SAnuj Aggarwal 
2954ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
2963fa5b8e0SAnuj Aggarwal 	if (data < 0)
2973fa5b8e0SAnuj Aggarwal 		return data;
2983fa5b8e0SAnuj Aggarwal 
299f2933d33SAxel Lin 	data &= mask;
3007c842a1dSAxel Lin 	return data;
3013fa5b8e0SAnuj Aggarwal }
3023fa5b8e0SAnuj Aggarwal 
303ca61a7bfSAxel Lin static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
304ca61a7bfSAxel Lin 					  unsigned selector)
3053fa5b8e0SAnuj Aggarwal {
3064ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
307ca61a7bfSAxel Lin 	int data, rid = rdev_get_id(dev);
308f2933d33SAxel Lin 	u8 reg, mask;
3093fa5b8e0SAnuj Aggarwal 
310f2933d33SAxel Lin 	switch (rid) {
3113fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3123fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
313f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3143fa5b8e0SAnuj Aggarwal 		break;
3153fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
316f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3177d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3187d14831eSAnuj Aggarwal 		else
3193fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
320f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3213fa5b8e0SAnuj Aggarwal 		break;
3223fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
323f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3247d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3257d14831eSAnuj Aggarwal 		else
3263fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
327f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
328f2933d33SAxel Lin 		break;
329f2933d33SAxel Lin 	case TPS6507X_LDO_1:
330f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
331f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
332f2933d33SAxel Lin 		break;
333f2933d33SAxel Lin 	case TPS6507X_LDO_2:
334f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
335f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3363fa5b8e0SAnuj Aggarwal 		break;
3373fa5b8e0SAnuj Aggarwal 	default:
3383fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3393fa5b8e0SAnuj Aggarwal 	}
3403fa5b8e0SAnuj Aggarwal 
3414ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3423fa5b8e0SAnuj Aggarwal 	if (data < 0)
3433fa5b8e0SAnuj Aggarwal 		return data;
3443fa5b8e0SAnuj Aggarwal 
3453fa5b8e0SAnuj Aggarwal 	data &= ~mask;
346ca61a7bfSAxel Lin 	data |= selector;
3473fa5b8e0SAnuj Aggarwal 
3484ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
3493fa5b8e0SAnuj Aggarwal }
3503fa5b8e0SAnuj Aggarwal 
351646e268eSAxel Lin static const struct regulator_ops tps6507x_pmic_ops = {
352f2933d33SAxel Lin 	.is_enabled = tps6507x_pmic_is_enabled,
353f2933d33SAxel Lin 	.enable = tps6507x_pmic_enable,
354f2933d33SAxel Lin 	.disable = tps6507x_pmic_disable,
3557c842a1dSAxel Lin 	.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
356ca61a7bfSAxel Lin 	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
357055917acSAxel Lin 	.list_voltage = regulator_list_voltage_table,
358a1bb63a8SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
3593fa5b8e0SAnuj Aggarwal };
3603fa5b8e0SAnuj Aggarwal 
361f979c08fSAxel Lin static int tps6507x_pmic_of_parse_cb(struct device_node *np,
362f979c08fSAxel Lin 				     const struct regulator_desc *desc,
363f979c08fSAxel Lin 				     struct regulator_config *config)
3646116ad94SVishwanathrao Badarkhe, Manish {
365f979c08fSAxel Lin 	struct tps6507x_pmic *tps = config->driver_data;
366f979c08fSAxel Lin 	struct tps_info *info = tps->info[desc->id];
367f979c08fSAxel Lin 	u32 prop;
368f979c08fSAxel Lin 	int ret;
3696116ad94SVishwanathrao Badarkhe, Manish 
370f979c08fSAxel Lin 	ret = of_property_read_u32(np, "ti,defdcdc_default", &prop);
371f979c08fSAxel Lin 	if (!ret)
372f979c08fSAxel Lin 		info->defdcdc_default = prop;
3736116ad94SVishwanathrao Badarkhe, Manish 
374f979c08fSAxel Lin 	return 0;
3756116ad94SVishwanathrao Badarkhe, Manish }
3764246e55fSManish Badarkhe 
377a5023574SBill Pemberton static int tps6507x_pmic_probe(struct platform_device *pdev)
3783fa5b8e0SAnuj Aggarwal {
37931dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
3807d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
381c172708dSMark Brown 	struct regulator_config config = { };
382f979c08fSAxel Lin 	struct regulator_init_data *init_data = NULL;
3833fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
3844ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
3850bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
3863fa5b8e0SAnuj Aggarwal 	int i;
3873fa5b8e0SAnuj Aggarwal 
3883fa5b8e0SAnuj Aggarwal 	/**
3890bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
3900bc20bbaSTodd Fischer 	 * coming from the board-evm file.
3910bc20bbaSTodd Fischer 	 */
3920bc20bbaSTodd Fischer 
39331dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
394f979c08fSAxel Lin 	if (tps_board)
3950bc20bbaSTodd Fischer 		init_data = tps_board->tps6507x_pmic_init_data;
3963fa5b8e0SAnuj Aggarwal 
3979eb0c421SAxel Lin 	tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
3983fa5b8e0SAnuj Aggarwal 	if (!tps)
3993fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
4003fa5b8e0SAnuj Aggarwal 
4013fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
4023fa5b8e0SAnuj Aggarwal 
4033fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
40431dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
4053fa5b8e0SAnuj Aggarwal 
4067d293f56SAxel Lin 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++) {
4073fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
4083fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
4097d293f56SAxel Lin 		if (init_data && init_data[i].driver_data) {
4107d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
4117d293f56SAxel Lin 					init_data[i].driver_data;
412f979c08fSAxel Lin 			info->defdcdc_default = data->defdcdc_default;
4137d14831eSAnuj Aggarwal 		}
4147d14831eSAnuj Aggarwal 
4153fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
416f979c08fSAxel Lin 		tps->desc[i].of_match = of_match_ptr(info->name);
417f979c08fSAxel Lin 		tps->desc[i].regulators_node = of_match_ptr("regulators");
418f979c08fSAxel Lin 		tps->desc[i].of_parse_cb = tps6507x_pmic_of_parse_cb;
41977fa44d0SAxel Lin 		tps->desc[i].id = i;
4200fcdb109SAxel Lin 		tps->desc[i].n_voltages = info->table_len;
421055917acSAxel Lin 		tps->desc[i].volt_table = info->table;
422f2933d33SAxel Lin 		tps->desc[i].ops = &tps6507x_pmic_ops;
4233fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
4243fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
4253fa5b8e0SAnuj Aggarwal 
426c172708dSMark Brown 		config.dev = tps6507x_dev->dev;
427c172708dSMark Brown 		config.init_data = init_data;
428c172708dSMark Brown 		config.driver_data = tps;
429c172708dSMark Brown 
43071b710e7SSachin Kamat 		rdev = devm_regulator_register(&pdev->dev, &tps->desc[i],
43171b710e7SSachin Kamat 					       &config);
4323fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
43331dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
43431dd6a26STodd Fischer 				"failed to register %s regulator\n",
43531dd6a26STodd Fischer 				pdev->name);
43671b710e7SSachin Kamat 			return PTR_ERR(rdev);
4373fa5b8e0SAnuj Aggarwal 		}
4383fa5b8e0SAnuj Aggarwal 	}
4393fa5b8e0SAnuj Aggarwal 
44031dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
441d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
4423fa5b8e0SAnuj Aggarwal 
4433fa5b8e0SAnuj Aggarwal 	return 0;
4443fa5b8e0SAnuj Aggarwal }
4453fa5b8e0SAnuj Aggarwal 
44631dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
4473fa5b8e0SAnuj Aggarwal 	.driver = {
44831dd6a26STodd Fischer 		.name = "tps6507x-pmic",
4493fa5b8e0SAnuj Aggarwal 	},
4504ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
4513fa5b8e0SAnuj Aggarwal };
4523fa5b8e0SAnuj Aggarwal 
4534ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
4543fa5b8e0SAnuj Aggarwal {
45531dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
4563fa5b8e0SAnuj Aggarwal }
4574ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
4583fa5b8e0SAnuj Aggarwal 
4594ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
4603fa5b8e0SAnuj Aggarwal {
46131dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
4623fa5b8e0SAnuj Aggarwal }
4634ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
4643fa5b8e0SAnuj Aggarwal 
4653fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
4663fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
4673fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
46831dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
469