xref: /linux/drivers/regulator/tps6507x-regulator.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
12aec85b2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23fa5b8e0SAnuj Aggarwal /*
33fa5b8e0SAnuj Aggarwal  * tps6507x-regulator.c
43fa5b8e0SAnuj Aggarwal  *
53fa5b8e0SAnuj Aggarwal  * Regulator driver for TPS65073 PMIC
63fa5b8e0SAnuj Aggarwal  *
72ca76b3eSAlexander A. Klimov  * Copyright (C) 2009 Texas Instrument Incorporated - https://www.ti.com/
83fa5b8e0SAnuj Aggarwal  */
93fa5b8e0SAnuj Aggarwal 
103fa5b8e0SAnuj Aggarwal #include <linux/kernel.h>
113fa5b8e0SAnuj Aggarwal #include <linux/module.h>
123fa5b8e0SAnuj Aggarwal #include <linux/init.h>
133fa5b8e0SAnuj Aggarwal #include <linux/err.h>
143fa5b8e0SAnuj Aggarwal #include <linux/platform_device.h>
153fa5b8e0SAnuj Aggarwal #include <linux/regulator/driver.h>
163fa5b8e0SAnuj Aggarwal #include <linux/regulator/machine.h>
177d14831eSAnuj Aggarwal #include <linux/regulator/tps6507x.h>
186116ad94SVishwanathrao Badarkhe, Manish #include <linux/of.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
20d183fcc9STodd Fischer #include <linux/mfd/tps6507x.h>
216116ad94SVishwanathrao Badarkhe, Manish #include <linux/regulator/of_regulator.h>
223fa5b8e0SAnuj Aggarwal 
233fa5b8e0SAnuj Aggarwal /* DCDC's */
243fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_1				0
253fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_2				1
263fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_3				2
273fa5b8e0SAnuj Aggarwal /* LDOs */
283fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_1				3
293fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_2				4
303fa5b8e0SAnuj Aggarwal 
313fa5b8e0SAnuj Aggarwal #define TPS6507X_MAX_REG_ID			TPS6507X_LDO_2
323fa5b8e0SAnuj Aggarwal 
333fa5b8e0SAnuj Aggarwal /* Number of step-down converters available */
343fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_DCDC			3
353fa5b8e0SAnuj Aggarwal /* Number of LDO voltage regulators  available */
363fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_LDO			2
373fa5b8e0SAnuj Aggarwal /* Number of total regulators available */
383fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_REGULATOR		(TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
393fa5b8e0SAnuj Aggarwal 
40055917acSAxel Lin /* Supported voltage values for regulators (in microVolts) */
41055917acSAxel Lin static const unsigned int VDCDCx_VSEL_table[] = {
42055917acSAxel Lin 	725000, 750000, 775000, 800000,
43055917acSAxel Lin 	825000, 850000, 875000, 900000,
44055917acSAxel Lin 	925000, 950000, 975000, 1000000,
45055917acSAxel Lin 	1025000, 1050000, 1075000, 1100000,
46055917acSAxel Lin 	1125000, 1150000, 1175000, 1200000,
47055917acSAxel Lin 	1225000, 1250000, 1275000, 1300000,
48055917acSAxel Lin 	1325000, 1350000, 1375000, 1400000,
49055917acSAxel Lin 	1425000, 1450000, 1475000, 1500000,
50055917acSAxel Lin 	1550000, 1600000, 1650000, 1700000,
51055917acSAxel Lin 	1750000, 1800000, 1850000, 1900000,
52055917acSAxel Lin 	1950000, 2000000, 2050000, 2100000,
53055917acSAxel Lin 	2150000, 2200000, 2250000, 2300000,
54055917acSAxel Lin 	2350000, 2400000, 2450000, 2500000,
55055917acSAxel Lin 	2550000, 2600000, 2650000, 2700000,
56055917acSAxel Lin 	2750000, 2800000, 2850000, 2900000,
57055917acSAxel Lin 	3000000, 3100000, 3200000, 3300000,
583fa5b8e0SAnuj Aggarwal };
593fa5b8e0SAnuj Aggarwal 
60055917acSAxel Lin static const unsigned int LDO1_VSEL_table[] = {
61055917acSAxel Lin 	1000000, 1100000, 1200000, 1250000,
62055917acSAxel Lin 	1300000, 1350000, 1400000, 1500000,
63055917acSAxel Lin 	1600000, 1800000, 2500000, 2750000,
64055917acSAxel Lin 	2800000, 3000000, 3100000, 3300000,
653fa5b8e0SAnuj Aggarwal };
663fa5b8e0SAnuj Aggarwal 
6793b07e7bSAxel Lin /* The voltage mapping table for LDO2 is the same as VDCDCx */
6893b07e7bSAxel Lin #define LDO2_VSEL_table VDCDCx_VSEL_table
693fa5b8e0SAnuj Aggarwal 
703fa5b8e0SAnuj Aggarwal struct tps_info {
713fa5b8e0SAnuj Aggarwal 	const char *name;
723fa5b8e0SAnuj Aggarwal 	u8 table_len;
73055917acSAxel Lin 	const unsigned int *table;
747d14831eSAnuj Aggarwal 
757d14831eSAnuj Aggarwal 	/* Does DCDC high or the low register defines output voltage? */
767d14831eSAnuj Aggarwal 	bool defdcdc_default;
773fa5b8e0SAnuj Aggarwal };
783fa5b8e0SAnuj Aggarwal 
797d14831eSAnuj Aggarwal static struct tps_info tps6507x_pmic_regs[] = {
8031dd6a26STodd Fischer 	{
8131dd6a26STodd Fischer 		.name = "VDCDC1",
8231dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
8331dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
8431dd6a26STodd Fischer 	},
8531dd6a26STodd Fischer 	{
8631dd6a26STodd Fischer 		.name = "VDCDC2",
8731dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
8831dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
8931dd6a26STodd Fischer 	},
9031dd6a26STodd Fischer 	{
9131dd6a26STodd Fischer 		.name = "VDCDC3",
9231dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
9331dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
9431dd6a26STodd Fischer 	},
9531dd6a26STodd Fischer 	{
9631dd6a26STodd Fischer 		.name = "LDO1",
9731dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
9831dd6a26STodd Fischer 		.table = LDO1_VSEL_table,
9931dd6a26STodd Fischer 	},
10031dd6a26STodd Fischer 	{
10131dd6a26STodd Fischer 		.name = "LDO2",
10231dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
10331dd6a26STodd Fischer 		.table = LDO2_VSEL_table,
10431dd6a26STodd Fischer 	},
10531dd6a26STodd Fischer };
10631dd6a26STodd Fischer 
1074ce5ba5bSTodd Fischer struct tps6507x_pmic {
1083fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
10931dd6a26STodd Fischer 	struct tps6507x_dev *mfd;
1107d14831eSAnuj Aggarwal 	struct tps_info *info[TPS6507X_NUM_REGULATOR];
1113fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1123fa5b8e0SAnuj Aggarwal };
tps6507x_pmic_read(struct tps6507x_pmic * tps,u8 reg)1134ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
1143fa5b8e0SAnuj Aggarwal {
11531dd6a26STodd Fischer 	u8 val;
11631dd6a26STodd Fischer 	int err;
11731dd6a26STodd Fischer 
11831dd6a26STodd Fischer 	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
11931dd6a26STodd Fischer 
12031dd6a26STodd Fischer 	if (err)
12131dd6a26STodd Fischer 		return err;
12231dd6a26STodd Fischer 
12331dd6a26STodd Fischer 	return val;
1243fa5b8e0SAnuj Aggarwal }
1253fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_write(struct tps6507x_pmic * tps,u8 reg,u8 val)1264ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1273fa5b8e0SAnuj Aggarwal {
12831dd6a26STodd Fischer 	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
1293fa5b8e0SAnuj Aggarwal }
1303fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_set_bits(struct tps6507x_pmic * tps,u8 reg,u8 mask)1314ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1323fa5b8e0SAnuj Aggarwal {
1333fa5b8e0SAnuj Aggarwal 	int err, data;
1343fa5b8e0SAnuj Aggarwal 
1353fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1363fa5b8e0SAnuj Aggarwal 
1374ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1383fa5b8e0SAnuj Aggarwal 	if (data < 0) {
13931dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1403fa5b8e0SAnuj Aggarwal 		err = data;
1413fa5b8e0SAnuj Aggarwal 		goto out;
1423fa5b8e0SAnuj Aggarwal 	}
1433fa5b8e0SAnuj Aggarwal 
1443fa5b8e0SAnuj Aggarwal 	data |= mask;
1454ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1463fa5b8e0SAnuj Aggarwal 	if (err)
14731dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1483fa5b8e0SAnuj Aggarwal 
1493fa5b8e0SAnuj Aggarwal out:
1503fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1513fa5b8e0SAnuj Aggarwal 	return err;
1523fa5b8e0SAnuj Aggarwal }
1533fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_clear_bits(struct tps6507x_pmic * tps,u8 reg,u8 mask)1544ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1553fa5b8e0SAnuj Aggarwal {
1563fa5b8e0SAnuj Aggarwal 	int err, data;
1573fa5b8e0SAnuj Aggarwal 
1583fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1593fa5b8e0SAnuj Aggarwal 
1604ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1613fa5b8e0SAnuj Aggarwal 	if (data < 0) {
16231dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1633fa5b8e0SAnuj Aggarwal 		err = data;
1643fa5b8e0SAnuj Aggarwal 		goto out;
1653fa5b8e0SAnuj Aggarwal 	}
1663fa5b8e0SAnuj Aggarwal 
1673fa5b8e0SAnuj Aggarwal 	data &= ~mask;
1684ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1693fa5b8e0SAnuj Aggarwal 	if (err)
17031dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1713fa5b8e0SAnuj Aggarwal 
1723fa5b8e0SAnuj Aggarwal out:
1733fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1743fa5b8e0SAnuj Aggarwal 	return err;
1753fa5b8e0SAnuj Aggarwal }
1763fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_reg_read(struct tps6507x_pmic * tps,u8 reg)1774ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
1783fa5b8e0SAnuj Aggarwal {
1793fa5b8e0SAnuj Aggarwal 	int data;
1803fa5b8e0SAnuj Aggarwal 
1813fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1823fa5b8e0SAnuj Aggarwal 
1834ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1843fa5b8e0SAnuj Aggarwal 	if (data < 0)
18531dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1863fa5b8e0SAnuj Aggarwal 
1873fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1883fa5b8e0SAnuj Aggarwal 	return data;
1893fa5b8e0SAnuj Aggarwal }
1903fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_reg_write(struct tps6507x_pmic * tps,u8 reg,u8 val)1914ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1923fa5b8e0SAnuj Aggarwal {
1933fa5b8e0SAnuj Aggarwal 	int err;
1943fa5b8e0SAnuj Aggarwal 
1953fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1963fa5b8e0SAnuj Aggarwal 
1974ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, val);
1983fa5b8e0SAnuj Aggarwal 	if (err < 0)
19931dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2003fa5b8e0SAnuj Aggarwal 
2013fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2023fa5b8e0SAnuj Aggarwal 	return err;
2033fa5b8e0SAnuj Aggarwal }
2043fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_is_enabled(struct regulator_dev * dev)205f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev)
2063fa5b8e0SAnuj Aggarwal {
2074ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
208f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
2093fa5b8e0SAnuj Aggarwal 	u8 shift;
2103fa5b8e0SAnuj Aggarwal 
211f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2123fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2133fa5b8e0SAnuj Aggarwal 
214f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2154ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2163fa5b8e0SAnuj Aggarwal 
2173fa5b8e0SAnuj Aggarwal 	if (data < 0)
2183fa5b8e0SAnuj Aggarwal 		return data;
2193fa5b8e0SAnuj Aggarwal 	else
2203fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2213fa5b8e0SAnuj Aggarwal }
2223fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_enable(struct regulator_dev * dev)223f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev)
2243fa5b8e0SAnuj Aggarwal {
2254ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
226f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2273fa5b8e0SAnuj Aggarwal 	u8 shift;
2283fa5b8e0SAnuj Aggarwal 
229f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2303fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2313fa5b8e0SAnuj Aggarwal 
232f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2334ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
2343fa5b8e0SAnuj Aggarwal }
2353fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_disable(struct regulator_dev * dev)236f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev)
2373fa5b8e0SAnuj Aggarwal {
2384ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
239f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2403fa5b8e0SAnuj Aggarwal 	u8 shift;
2413fa5b8e0SAnuj Aggarwal 
242f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2433fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2443fa5b8e0SAnuj Aggarwal 
245f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2464ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
2474ce5ba5bSTodd Fischer 					1 << shift);
2483fa5b8e0SAnuj Aggarwal }
2493fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_get_voltage_sel(struct regulator_dev * dev)2507c842a1dSAxel Lin static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev)
2513fa5b8e0SAnuj Aggarwal {
2524ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
253f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
254f2933d33SAxel Lin 	u8 reg, mask;
2553fa5b8e0SAnuj Aggarwal 
256f2933d33SAxel Lin 	switch (rid) {
2573fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
2583fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
259f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2603fa5b8e0SAnuj Aggarwal 		break;
2613fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
262f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2637d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
2647d14831eSAnuj Aggarwal 		else
2653fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
266f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2673fa5b8e0SAnuj Aggarwal 		break;
2683fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
269f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2707d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
2717d14831eSAnuj Aggarwal 		else
2723fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
273f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
274f2933d33SAxel Lin 		break;
275f2933d33SAxel Lin 	case TPS6507X_LDO_1:
276f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
277f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
278f2933d33SAxel Lin 		break;
279f2933d33SAxel Lin 	case TPS6507X_LDO_2:
280f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
281f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
2823fa5b8e0SAnuj Aggarwal 		break;
2833fa5b8e0SAnuj Aggarwal 	default:
2843fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2853fa5b8e0SAnuj Aggarwal 	}
2863fa5b8e0SAnuj Aggarwal 
2874ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
2883fa5b8e0SAnuj Aggarwal 	if (data < 0)
2893fa5b8e0SAnuj Aggarwal 		return data;
2903fa5b8e0SAnuj Aggarwal 
291f2933d33SAxel Lin 	data &= mask;
2927c842a1dSAxel Lin 	return data;
2933fa5b8e0SAnuj Aggarwal }
2943fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_set_voltage_sel(struct regulator_dev * dev,unsigned selector)295ca61a7bfSAxel Lin static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
296ca61a7bfSAxel Lin 					  unsigned selector)
2973fa5b8e0SAnuj Aggarwal {
2984ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
299ca61a7bfSAxel Lin 	int data, rid = rdev_get_id(dev);
300f2933d33SAxel Lin 	u8 reg, mask;
3013fa5b8e0SAnuj Aggarwal 
302f2933d33SAxel Lin 	switch (rid) {
3033fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3043fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
305f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3063fa5b8e0SAnuj Aggarwal 		break;
3073fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
308f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3097d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3107d14831eSAnuj Aggarwal 		else
3113fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
312f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3133fa5b8e0SAnuj Aggarwal 		break;
3143fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
315f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3167d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3177d14831eSAnuj Aggarwal 		else
3183fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
319f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
320f2933d33SAxel Lin 		break;
321f2933d33SAxel Lin 	case TPS6507X_LDO_1:
322f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
323f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
324f2933d33SAxel Lin 		break;
325f2933d33SAxel Lin 	case TPS6507X_LDO_2:
326f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
327f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3283fa5b8e0SAnuj Aggarwal 		break;
3293fa5b8e0SAnuj Aggarwal 	default:
3303fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3313fa5b8e0SAnuj Aggarwal 	}
3323fa5b8e0SAnuj Aggarwal 
3334ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3343fa5b8e0SAnuj Aggarwal 	if (data < 0)
3353fa5b8e0SAnuj Aggarwal 		return data;
3363fa5b8e0SAnuj Aggarwal 
3373fa5b8e0SAnuj Aggarwal 	data &= ~mask;
338ca61a7bfSAxel Lin 	data |= selector;
3393fa5b8e0SAnuj Aggarwal 
3404ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
3413fa5b8e0SAnuj Aggarwal }
3423fa5b8e0SAnuj Aggarwal 
343646e268eSAxel Lin static const struct regulator_ops tps6507x_pmic_ops = {
344f2933d33SAxel Lin 	.is_enabled = tps6507x_pmic_is_enabled,
345f2933d33SAxel Lin 	.enable = tps6507x_pmic_enable,
346f2933d33SAxel Lin 	.disable = tps6507x_pmic_disable,
3477c842a1dSAxel Lin 	.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
348ca61a7bfSAxel Lin 	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
349055917acSAxel Lin 	.list_voltage = regulator_list_voltage_table,
350a1bb63a8SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
3513fa5b8e0SAnuj Aggarwal };
3523fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_of_parse_cb(struct device_node * np,const struct regulator_desc * desc,struct regulator_config * config)353f979c08fSAxel Lin static int tps6507x_pmic_of_parse_cb(struct device_node *np,
354f979c08fSAxel Lin 				     const struct regulator_desc *desc,
355f979c08fSAxel Lin 				     struct regulator_config *config)
3566116ad94SVishwanathrao Badarkhe, Manish {
357f979c08fSAxel Lin 	struct tps6507x_pmic *tps = config->driver_data;
358f979c08fSAxel Lin 	struct tps_info *info = tps->info[desc->id];
359f979c08fSAxel Lin 	u32 prop;
360f979c08fSAxel Lin 	int ret;
3616116ad94SVishwanathrao Badarkhe, Manish 
362f979c08fSAxel Lin 	ret = of_property_read_u32(np, "ti,defdcdc_default", &prop);
363f979c08fSAxel Lin 	if (!ret)
364f979c08fSAxel Lin 		info->defdcdc_default = prop;
3656116ad94SVishwanathrao Badarkhe, Manish 
366f979c08fSAxel Lin 	return 0;
3676116ad94SVishwanathrao Badarkhe, Manish }
3684246e55fSManish Badarkhe 
tps6507x_pmic_probe(struct platform_device * pdev)369a5023574SBill Pemberton static int tps6507x_pmic_probe(struct platform_device *pdev)
3703fa5b8e0SAnuj Aggarwal {
37131dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
3727d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
373c172708dSMark Brown 	struct regulator_config config = { };
374f979c08fSAxel Lin 	struct regulator_init_data *init_data = NULL;
3753fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
3764ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
3770bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
3783fa5b8e0SAnuj Aggarwal 	int i;
3793fa5b8e0SAnuj Aggarwal 
3803fa5b8e0SAnuj Aggarwal 	/**
3810bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
3820bc20bbaSTodd Fischer 	 * coming from the board-evm file.
3830bc20bbaSTodd Fischer 	 */
3840bc20bbaSTodd Fischer 
38531dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
386f979c08fSAxel Lin 	if (tps_board)
3870bc20bbaSTodd Fischer 		init_data = tps_board->tps6507x_pmic_init_data;
3883fa5b8e0SAnuj Aggarwal 
3899eb0c421SAxel Lin 	tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
3903fa5b8e0SAnuj Aggarwal 	if (!tps)
3913fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
3923fa5b8e0SAnuj Aggarwal 
3933fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
3943fa5b8e0SAnuj Aggarwal 
3953fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
39631dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
3973fa5b8e0SAnuj Aggarwal 
3987d293f56SAxel Lin 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++) {
3993fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
4003fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
4017d293f56SAxel Lin 		if (init_data && init_data[i].driver_data) {
4027d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
4037d293f56SAxel Lin 					init_data[i].driver_data;
404f979c08fSAxel Lin 			info->defdcdc_default = data->defdcdc_default;
4057d14831eSAnuj Aggarwal 		}
4067d14831eSAnuj Aggarwal 
4073fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
408f979c08fSAxel Lin 		tps->desc[i].of_match = of_match_ptr(info->name);
409f979c08fSAxel Lin 		tps->desc[i].regulators_node = of_match_ptr("regulators");
410f979c08fSAxel Lin 		tps->desc[i].of_parse_cb = tps6507x_pmic_of_parse_cb;
41177fa44d0SAxel Lin 		tps->desc[i].id = i;
4120fcdb109SAxel Lin 		tps->desc[i].n_voltages = info->table_len;
413055917acSAxel Lin 		tps->desc[i].volt_table = info->table;
414f2933d33SAxel Lin 		tps->desc[i].ops = &tps6507x_pmic_ops;
4153fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
4163fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
4173fa5b8e0SAnuj Aggarwal 
418c172708dSMark Brown 		config.dev = tps6507x_dev->dev;
419c172708dSMark Brown 		config.init_data = init_data;
420c172708dSMark Brown 		config.driver_data = tps;
421c172708dSMark Brown 
42271b710e7SSachin Kamat 		rdev = devm_regulator_register(&pdev->dev, &tps->desc[i],
42371b710e7SSachin Kamat 					       &config);
4243fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
42531dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
42631dd6a26STodd Fischer 				"failed to register %s regulator\n",
42731dd6a26STodd Fischer 				pdev->name);
42871b710e7SSachin Kamat 			return PTR_ERR(rdev);
4293fa5b8e0SAnuj Aggarwal 		}
4303fa5b8e0SAnuj Aggarwal 	}
4313fa5b8e0SAnuj Aggarwal 
43231dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
433d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
4343fa5b8e0SAnuj Aggarwal 
4353fa5b8e0SAnuj Aggarwal 	return 0;
4363fa5b8e0SAnuj Aggarwal }
4373fa5b8e0SAnuj Aggarwal 
43831dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
4393fa5b8e0SAnuj Aggarwal 	.driver = {
44031dd6a26STodd Fischer 		.name = "tps6507x-pmic",
441*259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
4423fa5b8e0SAnuj Aggarwal 	},
4434ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
4443fa5b8e0SAnuj Aggarwal };
4453fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_init(void)4464ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
4473fa5b8e0SAnuj Aggarwal {
44831dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
4493fa5b8e0SAnuj Aggarwal }
4504ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
4513fa5b8e0SAnuj Aggarwal 
tps6507x_pmic_cleanup(void)4524ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
4533fa5b8e0SAnuj Aggarwal {
45431dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
4553fa5b8e0SAnuj Aggarwal }
4564ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
4573fa5b8e0SAnuj Aggarwal 
4583fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
4593fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
4603fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
46131dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
462