xref: /openbmc/linux/drivers/regulator/tps6507x-regulator.c (revision 646e268e66ec8664317ae677a3b774b7dc812c84)
13fa5b8e0SAnuj Aggarwal /*
23fa5b8e0SAnuj Aggarwal  * tps6507x-regulator.c
33fa5b8e0SAnuj Aggarwal  *
43fa5b8e0SAnuj Aggarwal  * Regulator driver for TPS65073 PMIC
53fa5b8e0SAnuj Aggarwal  *
63fa5b8e0SAnuj Aggarwal  * Copyright (C) 2009 Texas Instrument Incorporated - http://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;
1183fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
1197d14831eSAnuj Aggarwal 	struct tps_info *info[TPS6507X_NUM_REGULATOR];
1203fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1213fa5b8e0SAnuj Aggarwal };
1224ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
1233fa5b8e0SAnuj Aggarwal {
12431dd6a26STodd Fischer 	u8 val;
12531dd6a26STodd Fischer 	int err;
12631dd6a26STodd Fischer 
12731dd6a26STodd Fischer 	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
12831dd6a26STodd Fischer 
12931dd6a26STodd Fischer 	if (err)
13031dd6a26STodd Fischer 		return err;
13131dd6a26STodd Fischer 
13231dd6a26STodd Fischer 	return val;
1333fa5b8e0SAnuj Aggarwal }
1343fa5b8e0SAnuj Aggarwal 
1354ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1363fa5b8e0SAnuj Aggarwal {
13731dd6a26STodd Fischer 	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
1383fa5b8e0SAnuj Aggarwal }
1393fa5b8e0SAnuj Aggarwal 
1404ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1413fa5b8e0SAnuj Aggarwal {
1423fa5b8e0SAnuj Aggarwal 	int err, data;
1433fa5b8e0SAnuj Aggarwal 
1443fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1453fa5b8e0SAnuj Aggarwal 
1464ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1473fa5b8e0SAnuj Aggarwal 	if (data < 0) {
14831dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1493fa5b8e0SAnuj Aggarwal 		err = data;
1503fa5b8e0SAnuj Aggarwal 		goto out;
1513fa5b8e0SAnuj Aggarwal 	}
1523fa5b8e0SAnuj Aggarwal 
1533fa5b8e0SAnuj Aggarwal 	data |= mask;
1544ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1553fa5b8e0SAnuj Aggarwal 	if (err)
15631dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1573fa5b8e0SAnuj Aggarwal 
1583fa5b8e0SAnuj Aggarwal out:
1593fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1603fa5b8e0SAnuj Aggarwal 	return err;
1613fa5b8e0SAnuj Aggarwal }
1623fa5b8e0SAnuj Aggarwal 
1634ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1643fa5b8e0SAnuj Aggarwal {
1653fa5b8e0SAnuj Aggarwal 	int err, data;
1663fa5b8e0SAnuj Aggarwal 
1673fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1683fa5b8e0SAnuj Aggarwal 
1694ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1703fa5b8e0SAnuj Aggarwal 	if (data < 0) {
17131dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1723fa5b8e0SAnuj Aggarwal 		err = data;
1733fa5b8e0SAnuj Aggarwal 		goto out;
1743fa5b8e0SAnuj Aggarwal 	}
1753fa5b8e0SAnuj Aggarwal 
1763fa5b8e0SAnuj Aggarwal 	data &= ~mask;
1774ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1783fa5b8e0SAnuj Aggarwal 	if (err)
17931dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1803fa5b8e0SAnuj Aggarwal 
1813fa5b8e0SAnuj Aggarwal out:
1823fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1833fa5b8e0SAnuj Aggarwal 	return err;
1843fa5b8e0SAnuj Aggarwal }
1853fa5b8e0SAnuj Aggarwal 
1864ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
1873fa5b8e0SAnuj Aggarwal {
1883fa5b8e0SAnuj Aggarwal 	int data;
1893fa5b8e0SAnuj Aggarwal 
1903fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1913fa5b8e0SAnuj Aggarwal 
1924ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1933fa5b8e0SAnuj Aggarwal 	if (data < 0)
19431dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1953fa5b8e0SAnuj Aggarwal 
1963fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1973fa5b8e0SAnuj Aggarwal 	return data;
1983fa5b8e0SAnuj Aggarwal }
1993fa5b8e0SAnuj Aggarwal 
2004ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
2013fa5b8e0SAnuj Aggarwal {
2023fa5b8e0SAnuj Aggarwal 	int err;
2033fa5b8e0SAnuj Aggarwal 
2043fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2053fa5b8e0SAnuj Aggarwal 
2064ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, val);
2073fa5b8e0SAnuj Aggarwal 	if (err < 0)
20831dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2093fa5b8e0SAnuj Aggarwal 
2103fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2113fa5b8e0SAnuj Aggarwal 	return err;
2123fa5b8e0SAnuj Aggarwal }
2133fa5b8e0SAnuj Aggarwal 
214f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev)
2153fa5b8e0SAnuj Aggarwal {
2164ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
217f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
2183fa5b8e0SAnuj Aggarwal 	u8 shift;
2193fa5b8e0SAnuj Aggarwal 
220f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2213fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2223fa5b8e0SAnuj Aggarwal 
223f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2244ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2253fa5b8e0SAnuj Aggarwal 
2263fa5b8e0SAnuj Aggarwal 	if (data < 0)
2273fa5b8e0SAnuj Aggarwal 		return data;
2283fa5b8e0SAnuj Aggarwal 	else
2293fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2303fa5b8e0SAnuj Aggarwal }
2313fa5b8e0SAnuj Aggarwal 
232f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev)
2333fa5b8e0SAnuj Aggarwal {
2344ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
235f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2363fa5b8e0SAnuj Aggarwal 	u8 shift;
2373fa5b8e0SAnuj Aggarwal 
238f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2393fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2403fa5b8e0SAnuj Aggarwal 
241f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2424ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
2433fa5b8e0SAnuj Aggarwal }
2443fa5b8e0SAnuj Aggarwal 
245f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev)
2463fa5b8e0SAnuj Aggarwal {
2474ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
248f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2493fa5b8e0SAnuj Aggarwal 	u8 shift;
2503fa5b8e0SAnuj Aggarwal 
251f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2523fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2533fa5b8e0SAnuj Aggarwal 
254f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2554ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
2564ce5ba5bSTodd Fischer 					1 << shift);
2573fa5b8e0SAnuj Aggarwal }
2583fa5b8e0SAnuj Aggarwal 
2597c842a1dSAxel Lin static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev)
2603fa5b8e0SAnuj Aggarwal {
2614ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
262f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
263f2933d33SAxel Lin 	u8 reg, mask;
2643fa5b8e0SAnuj Aggarwal 
265f2933d33SAxel Lin 	switch (rid) {
2663fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
2673fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
268f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2693fa5b8e0SAnuj Aggarwal 		break;
2703fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
271f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2727d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
2737d14831eSAnuj Aggarwal 		else
2743fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
275f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2763fa5b8e0SAnuj Aggarwal 		break;
2773fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
278f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2797d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
2807d14831eSAnuj Aggarwal 		else
2813fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
282f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
283f2933d33SAxel Lin 		break;
284f2933d33SAxel Lin 	case TPS6507X_LDO_1:
285f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
286f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
287f2933d33SAxel Lin 		break;
288f2933d33SAxel Lin 	case TPS6507X_LDO_2:
289f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
290f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
2913fa5b8e0SAnuj Aggarwal 		break;
2923fa5b8e0SAnuj Aggarwal 	default:
2933fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2943fa5b8e0SAnuj Aggarwal 	}
2953fa5b8e0SAnuj Aggarwal 
2964ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
2973fa5b8e0SAnuj Aggarwal 	if (data < 0)
2983fa5b8e0SAnuj Aggarwal 		return data;
2993fa5b8e0SAnuj Aggarwal 
300f2933d33SAxel Lin 	data &= mask;
3017c842a1dSAxel Lin 	return data;
3023fa5b8e0SAnuj Aggarwal }
3033fa5b8e0SAnuj Aggarwal 
304ca61a7bfSAxel Lin static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
305ca61a7bfSAxel Lin 					  unsigned selector)
3063fa5b8e0SAnuj Aggarwal {
3074ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
308ca61a7bfSAxel Lin 	int data, rid = rdev_get_id(dev);
309f2933d33SAxel Lin 	u8 reg, mask;
3103fa5b8e0SAnuj Aggarwal 
311f2933d33SAxel Lin 	switch (rid) {
3123fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3133fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
314f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3153fa5b8e0SAnuj Aggarwal 		break;
3163fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
317f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3187d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3197d14831eSAnuj Aggarwal 		else
3203fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
321f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3223fa5b8e0SAnuj Aggarwal 		break;
3233fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
324f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3257d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3267d14831eSAnuj Aggarwal 		else
3273fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
328f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
329f2933d33SAxel Lin 		break;
330f2933d33SAxel Lin 	case TPS6507X_LDO_1:
331f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
332f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
333f2933d33SAxel Lin 		break;
334f2933d33SAxel Lin 	case TPS6507X_LDO_2:
335f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
336f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3373fa5b8e0SAnuj Aggarwal 		break;
3383fa5b8e0SAnuj Aggarwal 	default:
3393fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3403fa5b8e0SAnuj Aggarwal 	}
3413fa5b8e0SAnuj Aggarwal 
3424ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3433fa5b8e0SAnuj Aggarwal 	if (data < 0)
3443fa5b8e0SAnuj Aggarwal 		return data;
3453fa5b8e0SAnuj Aggarwal 
3463fa5b8e0SAnuj Aggarwal 	data &= ~mask;
347ca61a7bfSAxel Lin 	data |= selector;
3483fa5b8e0SAnuj Aggarwal 
3494ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
3503fa5b8e0SAnuj Aggarwal }
3513fa5b8e0SAnuj Aggarwal 
352*646e268eSAxel Lin static const struct regulator_ops tps6507x_pmic_ops = {
353f2933d33SAxel Lin 	.is_enabled = tps6507x_pmic_is_enabled,
354f2933d33SAxel Lin 	.enable = tps6507x_pmic_enable,
355f2933d33SAxel Lin 	.disable = tps6507x_pmic_disable,
3567c842a1dSAxel Lin 	.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
357ca61a7bfSAxel Lin 	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
358055917acSAxel Lin 	.list_voltage = regulator_list_voltage_table,
359a1bb63a8SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
3603fa5b8e0SAnuj Aggarwal };
3613fa5b8e0SAnuj Aggarwal 
3626116ad94SVishwanathrao Badarkhe, Manish static struct of_regulator_match tps6507x_matches[] = {
3636116ad94SVishwanathrao Badarkhe, Manish 	{ .name = "VDCDC1"},
3646116ad94SVishwanathrao Badarkhe, Manish 	{ .name = "VDCDC2"},
3656116ad94SVishwanathrao Badarkhe, Manish 	{ .name = "VDCDC3"},
3666116ad94SVishwanathrao Badarkhe, Manish 	{ .name = "LDO1"},
3676116ad94SVishwanathrao Badarkhe, Manish 	{ .name = "LDO2"},
3686116ad94SVishwanathrao Badarkhe, Manish };
3696116ad94SVishwanathrao Badarkhe, Manish 
3706116ad94SVishwanathrao Badarkhe, Manish static struct tps6507x_board *tps6507x_parse_dt_reg_data(
3716116ad94SVishwanathrao Badarkhe, Manish 		struct platform_device *pdev,
3726116ad94SVishwanathrao Badarkhe, Manish 		struct of_regulator_match **tps6507x_reg_matches)
3736116ad94SVishwanathrao Badarkhe, Manish {
3746116ad94SVishwanathrao Badarkhe, Manish 	struct tps6507x_board *tps_board;
3756116ad94SVishwanathrao Badarkhe, Manish 	struct device_node *np = pdev->dev.parent->of_node;
3766116ad94SVishwanathrao Badarkhe, Manish 	struct device_node *regulators;
3776116ad94SVishwanathrao Badarkhe, Manish 	struct of_regulator_match *matches;
378e98d5fefSAxel Lin 	struct regulator_init_data *reg_data;
3796116ad94SVishwanathrao Badarkhe, Manish 	int idx = 0, count, ret;
3806116ad94SVishwanathrao Badarkhe, Manish 
3816116ad94SVishwanathrao Badarkhe, Manish 	tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),
3826116ad94SVishwanathrao Badarkhe, Manish 					GFP_KERNEL);
383fe23ce08SSachin Kamat 	if (!tps_board)
3846116ad94SVishwanathrao Badarkhe, Manish 		return NULL;
3856116ad94SVishwanathrao Badarkhe, Manish 
386e3d4edfdSSachin Kamat 	regulators = of_get_child_by_name(np, "regulators");
3876116ad94SVishwanathrao Badarkhe, Manish 	if (!regulators) {
3886116ad94SVishwanathrao Badarkhe, Manish 		dev_err(&pdev->dev, "regulator node not found\n");
3896116ad94SVishwanathrao Badarkhe, Manish 		return NULL;
3906116ad94SVishwanathrao Badarkhe, Manish 	}
3916116ad94SVishwanathrao Badarkhe, Manish 
3926116ad94SVishwanathrao Badarkhe, Manish 	count = ARRAY_SIZE(tps6507x_matches);
3936116ad94SVishwanathrao Badarkhe, Manish 	matches = tps6507x_matches;
3946116ad94SVishwanathrao Badarkhe, Manish 
3950ce7d00dSAxel Lin 	ret = of_regulator_match(&pdev->dev, regulators, matches, count);
396aaacb0e9SSachin Kamat 	of_node_put(regulators);
3976116ad94SVishwanathrao Badarkhe, Manish 	if (ret < 0) {
3986116ad94SVishwanathrao Badarkhe, Manish 		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
3996116ad94SVishwanathrao Badarkhe, Manish 			ret);
4006116ad94SVishwanathrao Badarkhe, Manish 		return NULL;
4016116ad94SVishwanathrao Badarkhe, Manish 	}
4026116ad94SVishwanathrao Badarkhe, Manish 
4036116ad94SVishwanathrao Badarkhe, Manish 	*tps6507x_reg_matches = matches;
4046116ad94SVishwanathrao Badarkhe, Manish 
4056116ad94SVishwanathrao Badarkhe, Manish 	reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
4066116ad94SVishwanathrao Badarkhe, Manish 					* TPS6507X_NUM_REGULATOR), GFP_KERNEL);
407fe23ce08SSachin Kamat 	if (!reg_data)
4086116ad94SVishwanathrao Badarkhe, Manish 		return NULL;
4096116ad94SVishwanathrao Badarkhe, Manish 
4106116ad94SVishwanathrao Badarkhe, Manish 	tps_board->tps6507x_pmic_init_data = reg_data;
4116116ad94SVishwanathrao Badarkhe, Manish 
4126116ad94SVishwanathrao Badarkhe, Manish 	for (idx = 0; idx < count; idx++) {
4136116ad94SVishwanathrao Badarkhe, Manish 		if (!matches[idx].init_data || !matches[idx].of_node)
4146116ad94SVishwanathrao Badarkhe, Manish 			continue;
4156116ad94SVishwanathrao Badarkhe, Manish 
4166116ad94SVishwanathrao Badarkhe, Manish 		memcpy(&reg_data[idx], matches[idx].init_data,
4176116ad94SVishwanathrao Badarkhe, Manish 				sizeof(struct regulator_init_data));
4186116ad94SVishwanathrao Badarkhe, Manish 
4196116ad94SVishwanathrao Badarkhe, Manish 	}
4206116ad94SVishwanathrao Badarkhe, Manish 
4216116ad94SVishwanathrao Badarkhe, Manish 	return tps_board;
4226116ad94SVishwanathrao Badarkhe, Manish }
4234246e55fSManish Badarkhe 
424a5023574SBill Pemberton static int tps6507x_pmic_probe(struct platform_device *pdev)
4253fa5b8e0SAnuj Aggarwal {
42631dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
4277d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
428c172708dSMark Brown 	struct regulator_config config = { };
4293fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
4303fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
4314ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
4320bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
4336116ad94SVishwanathrao Badarkhe, Manish 	struct of_regulator_match *tps6507x_reg_matches = NULL;
4343fa5b8e0SAnuj Aggarwal 	int i;
43556c23492SDmitry Torokhov 	int error;
4366116ad94SVishwanathrao Badarkhe, Manish 	unsigned int prop;
4373fa5b8e0SAnuj Aggarwal 
4383fa5b8e0SAnuj Aggarwal 	/**
4390bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
4400bc20bbaSTodd Fischer 	 * coming from the board-evm file.
4410bc20bbaSTodd Fischer 	 */
4420bc20bbaSTodd Fischer 
44331dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
4444246e55fSManish Badarkhe 	if (IS_ENABLED(CONFIG_OF) && !tps_board &&
4454246e55fSManish Badarkhe 		tps6507x_dev->dev->of_node)
4466116ad94SVishwanathrao Badarkhe, Manish 		tps_board = tps6507x_parse_dt_reg_data(pdev,
4476116ad94SVishwanathrao Badarkhe, Manish 				&tps6507x_reg_matches);
4480bc20bbaSTodd Fischer 	if (!tps_board)
4490bc20bbaSTodd Fischer 		return -EINVAL;
4500bc20bbaSTodd Fischer 
4510bc20bbaSTodd Fischer 	/**
4523fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
4533fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
4543fa5b8e0SAnuj Aggarwal 	 */
4550bc20bbaSTodd Fischer 	init_data = tps_board->tps6507x_pmic_init_data;
4563fa5b8e0SAnuj Aggarwal 	if (!init_data)
4570bc20bbaSTodd Fischer 		return -EINVAL;
4583fa5b8e0SAnuj Aggarwal 
4599eb0c421SAxel Lin 	tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
4603fa5b8e0SAnuj Aggarwal 	if (!tps)
4613fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
4623fa5b8e0SAnuj Aggarwal 
4633fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
4643fa5b8e0SAnuj Aggarwal 
4653fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
46631dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
4673fa5b8e0SAnuj Aggarwal 
4683fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
4693fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
4703fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
4717d14831eSAnuj Aggarwal 		if (init_data->driver_data) {
4727d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
4737d14831eSAnuj Aggarwal 					init_data->driver_data;
4747d14831eSAnuj Aggarwal 			tps->info[i]->defdcdc_default = data->defdcdc_default;
4757d14831eSAnuj Aggarwal 		}
4767d14831eSAnuj Aggarwal 
4773fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
47877fa44d0SAxel Lin 		tps->desc[i].id = i;
4790fcdb109SAxel Lin 		tps->desc[i].n_voltages = info->table_len;
480055917acSAxel Lin 		tps->desc[i].volt_table = info->table;
481f2933d33SAxel Lin 		tps->desc[i].ops = &tps6507x_pmic_ops;
4823fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
4833fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
4843fa5b8e0SAnuj Aggarwal 
485c172708dSMark Brown 		config.dev = tps6507x_dev->dev;
486c172708dSMark Brown 		config.init_data = init_data;
487c172708dSMark Brown 		config.driver_data = tps;
488c172708dSMark Brown 
4896116ad94SVishwanathrao Badarkhe, Manish 		if (tps6507x_reg_matches) {
4906116ad94SVishwanathrao Badarkhe, Manish 			error = of_property_read_u32(
4916116ad94SVishwanathrao Badarkhe, Manish 				tps6507x_reg_matches[i].of_node,
4926116ad94SVishwanathrao Badarkhe, Manish 					"ti,defdcdc_default", &prop);
4936116ad94SVishwanathrao Badarkhe, Manish 
4946116ad94SVishwanathrao Badarkhe, Manish 			if (!error)
4956116ad94SVishwanathrao Badarkhe, Manish 				tps->info[i]->defdcdc_default = prop;
4966116ad94SVishwanathrao Badarkhe, Manish 
4976116ad94SVishwanathrao Badarkhe, Manish 			config.of_node = tps6507x_reg_matches[i].of_node;
4986116ad94SVishwanathrao Badarkhe, Manish 		}
4996116ad94SVishwanathrao Badarkhe, Manish 
50071b710e7SSachin Kamat 		rdev = devm_regulator_register(&pdev->dev, &tps->desc[i],
50171b710e7SSachin Kamat 					       &config);
5023fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
50331dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
50431dd6a26STodd Fischer 				"failed to register %s regulator\n",
50531dd6a26STodd Fischer 				pdev->name);
50671b710e7SSachin Kamat 			return PTR_ERR(rdev);
5073fa5b8e0SAnuj Aggarwal 		}
5083fa5b8e0SAnuj Aggarwal 
5093fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
5103fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
5113fa5b8e0SAnuj Aggarwal 	}
5123fa5b8e0SAnuj Aggarwal 
51331dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
514d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
5153fa5b8e0SAnuj Aggarwal 
5163fa5b8e0SAnuj Aggarwal 	return 0;
5173fa5b8e0SAnuj Aggarwal }
5183fa5b8e0SAnuj Aggarwal 
51931dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
5203fa5b8e0SAnuj Aggarwal 	.driver = {
52131dd6a26STodd Fischer 		.name = "tps6507x-pmic",
5223fa5b8e0SAnuj Aggarwal 	},
5234ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
5243fa5b8e0SAnuj Aggarwal };
5253fa5b8e0SAnuj Aggarwal 
5264ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
5273fa5b8e0SAnuj Aggarwal {
52831dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
5293fa5b8e0SAnuj Aggarwal }
5304ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
5313fa5b8e0SAnuj Aggarwal 
5324ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
5333fa5b8e0SAnuj Aggarwal {
53431dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
5353fa5b8e0SAnuj Aggarwal }
5364ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
5373fa5b8e0SAnuj Aggarwal 
5383fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
5393fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
5403fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
54131dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
542