xref: /openbmc/linux/drivers/regulator/tps6507x-regulator.c (revision 4246e55fa830aa48cc5a7c3c023eee6553415b4b)
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 
352f2933d33SAxel Lin static 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;
3786116ad94SVishwanathrao Badarkhe, Manish 	static 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);
3836116ad94SVishwanathrao Badarkhe, Manish 	if (!tps_board) {
3846116ad94SVishwanathrao Badarkhe, Manish 		dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
3856116ad94SVishwanathrao Badarkhe, Manish 		return NULL;
3866116ad94SVishwanathrao Badarkhe, Manish 	}
3876116ad94SVishwanathrao Badarkhe, Manish 
3886116ad94SVishwanathrao Badarkhe, Manish 	regulators = of_find_node_by_name(np, "regulators");
3896116ad94SVishwanathrao Badarkhe, Manish 	if (!regulators) {
3906116ad94SVishwanathrao Badarkhe, Manish 		dev_err(&pdev->dev, "regulator node not found\n");
3916116ad94SVishwanathrao Badarkhe, Manish 		return NULL;
3926116ad94SVishwanathrao Badarkhe, Manish 	}
3936116ad94SVishwanathrao Badarkhe, Manish 
3946116ad94SVishwanathrao Badarkhe, Manish 	count = ARRAY_SIZE(tps6507x_matches);
3956116ad94SVishwanathrao Badarkhe, Manish 	matches = tps6507x_matches;
3966116ad94SVishwanathrao Badarkhe, Manish 
3970ce7d00dSAxel Lin 	ret = of_regulator_match(&pdev->dev, regulators, matches, count);
3986116ad94SVishwanathrao Badarkhe, Manish 	if (ret < 0) {
3996116ad94SVishwanathrao Badarkhe, Manish 		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
4006116ad94SVishwanathrao Badarkhe, Manish 			ret);
4016116ad94SVishwanathrao Badarkhe, Manish 		return NULL;
4026116ad94SVishwanathrao Badarkhe, Manish 	}
4036116ad94SVishwanathrao Badarkhe, Manish 
4046116ad94SVishwanathrao Badarkhe, Manish 	*tps6507x_reg_matches = matches;
4056116ad94SVishwanathrao Badarkhe, Manish 
4066116ad94SVishwanathrao Badarkhe, Manish 	reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
4076116ad94SVishwanathrao Badarkhe, Manish 					* TPS6507X_NUM_REGULATOR), GFP_KERNEL);
4086116ad94SVishwanathrao Badarkhe, Manish 	if (!reg_data) {
4096116ad94SVishwanathrao Badarkhe, Manish 		dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n");
4106116ad94SVishwanathrao Badarkhe, Manish 		return NULL;
4116116ad94SVishwanathrao Badarkhe, Manish 	}
4126116ad94SVishwanathrao Badarkhe, Manish 
4136116ad94SVishwanathrao Badarkhe, Manish 	tps_board->tps6507x_pmic_init_data = reg_data;
4146116ad94SVishwanathrao Badarkhe, Manish 
4156116ad94SVishwanathrao Badarkhe, Manish 	for (idx = 0; idx < count; idx++) {
4166116ad94SVishwanathrao Badarkhe, Manish 		if (!matches[idx].init_data || !matches[idx].of_node)
4176116ad94SVishwanathrao Badarkhe, Manish 			continue;
4186116ad94SVishwanathrao Badarkhe, Manish 
4196116ad94SVishwanathrao Badarkhe, Manish 		memcpy(&reg_data[idx], matches[idx].init_data,
4206116ad94SVishwanathrao Badarkhe, Manish 				sizeof(struct regulator_init_data));
4216116ad94SVishwanathrao Badarkhe, Manish 
4226116ad94SVishwanathrao Badarkhe, Manish 	}
4236116ad94SVishwanathrao Badarkhe, Manish 
4246116ad94SVishwanathrao Badarkhe, Manish 	return tps_board;
4256116ad94SVishwanathrao Badarkhe, Manish }
426*4246e55fSManish Badarkhe 
427a5023574SBill Pemberton static int tps6507x_pmic_probe(struct platform_device *pdev)
4283fa5b8e0SAnuj Aggarwal {
42931dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
4307d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
431c172708dSMark Brown 	struct regulator_config config = { };
4323fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
4333fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
4344ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
4350bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
4366116ad94SVishwanathrao Badarkhe, Manish 	struct of_regulator_match *tps6507x_reg_matches = NULL;
4373fa5b8e0SAnuj Aggarwal 	int i;
43856c23492SDmitry Torokhov 	int error;
4396116ad94SVishwanathrao Badarkhe, Manish 	unsigned int prop;
4403fa5b8e0SAnuj Aggarwal 
4413fa5b8e0SAnuj Aggarwal 	/**
4420bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
4430bc20bbaSTodd Fischer 	 * coming from the board-evm file.
4440bc20bbaSTodd Fischer 	 */
4450bc20bbaSTodd Fischer 
44631dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
447*4246e55fSManish Badarkhe 	if (IS_ENABLED(CONFIG_OF) && !tps_board &&
448*4246e55fSManish Badarkhe 		tps6507x_dev->dev->of_node)
4496116ad94SVishwanathrao Badarkhe, Manish 		tps_board = tps6507x_parse_dt_reg_data(pdev,
4506116ad94SVishwanathrao Badarkhe, Manish 				&tps6507x_reg_matches);
4510bc20bbaSTodd Fischer 	if (!tps_board)
4520bc20bbaSTodd Fischer 		return -EINVAL;
4530bc20bbaSTodd Fischer 
4540bc20bbaSTodd Fischer 	/**
4553fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
4563fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
4573fa5b8e0SAnuj Aggarwal 	 */
4580bc20bbaSTodd Fischer 	init_data = tps_board->tps6507x_pmic_init_data;
4593fa5b8e0SAnuj Aggarwal 	if (!init_data)
4600bc20bbaSTodd Fischer 		return -EINVAL;
4613fa5b8e0SAnuj Aggarwal 
4629eb0c421SAxel Lin 	tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
4633fa5b8e0SAnuj Aggarwal 	if (!tps)
4643fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
4653fa5b8e0SAnuj Aggarwal 
4663fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
4673fa5b8e0SAnuj Aggarwal 
4683fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
46931dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
4703fa5b8e0SAnuj Aggarwal 
4713fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
4723fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
4733fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
4747d14831eSAnuj Aggarwal 		if (init_data->driver_data) {
4757d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
4767d14831eSAnuj Aggarwal 					init_data->driver_data;
4777d14831eSAnuj Aggarwal 			tps->info[i]->defdcdc_default = data->defdcdc_default;
4787d14831eSAnuj Aggarwal 		}
4797d14831eSAnuj Aggarwal 
4803fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
48177fa44d0SAxel Lin 		tps->desc[i].id = i;
4820fcdb109SAxel Lin 		tps->desc[i].n_voltages = info->table_len;
483055917acSAxel Lin 		tps->desc[i].volt_table = info->table;
484f2933d33SAxel Lin 		tps->desc[i].ops = &tps6507x_pmic_ops;
4853fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
4863fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
4873fa5b8e0SAnuj Aggarwal 
488c172708dSMark Brown 		config.dev = tps6507x_dev->dev;
489c172708dSMark Brown 		config.init_data = init_data;
490c172708dSMark Brown 		config.driver_data = tps;
491c172708dSMark Brown 
4926116ad94SVishwanathrao Badarkhe, Manish 		if (tps6507x_reg_matches) {
4936116ad94SVishwanathrao Badarkhe, Manish 			error = of_property_read_u32(
4946116ad94SVishwanathrao Badarkhe, Manish 				tps6507x_reg_matches[i].of_node,
4956116ad94SVishwanathrao Badarkhe, Manish 					"ti,defdcdc_default", &prop);
4966116ad94SVishwanathrao Badarkhe, Manish 
4976116ad94SVishwanathrao Badarkhe, Manish 			if (!error)
4986116ad94SVishwanathrao Badarkhe, Manish 				tps->info[i]->defdcdc_default = prop;
4996116ad94SVishwanathrao Badarkhe, Manish 
5006116ad94SVishwanathrao Badarkhe, Manish 			config.of_node = tps6507x_reg_matches[i].of_node;
5016116ad94SVishwanathrao Badarkhe, Manish 		}
5026116ad94SVishwanathrao Badarkhe, Manish 
50371b710e7SSachin Kamat 		rdev = devm_regulator_register(&pdev->dev, &tps->desc[i],
50471b710e7SSachin Kamat 					       &config);
5053fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
50631dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
50731dd6a26STodd Fischer 				"failed to register %s regulator\n",
50831dd6a26STodd Fischer 				pdev->name);
50971b710e7SSachin Kamat 			return PTR_ERR(rdev);
5103fa5b8e0SAnuj Aggarwal 		}
5113fa5b8e0SAnuj Aggarwal 
5123fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
5133fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
5143fa5b8e0SAnuj Aggarwal 	}
5153fa5b8e0SAnuj Aggarwal 
51631dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
517d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
5183fa5b8e0SAnuj Aggarwal 
5193fa5b8e0SAnuj Aggarwal 	return 0;
5203fa5b8e0SAnuj Aggarwal }
5213fa5b8e0SAnuj Aggarwal 
52231dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
5233fa5b8e0SAnuj Aggarwal 	.driver = {
52431dd6a26STodd Fischer 		.name = "tps6507x-pmic",
5253fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
5263fa5b8e0SAnuj Aggarwal 	},
5274ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
5283fa5b8e0SAnuj Aggarwal };
5293fa5b8e0SAnuj Aggarwal 
5304ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
5313fa5b8e0SAnuj Aggarwal {
53231dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
5333fa5b8e0SAnuj Aggarwal }
5344ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
5353fa5b8e0SAnuj Aggarwal 
5364ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
5373fa5b8e0SAnuj Aggarwal {
53831dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
5393fa5b8e0SAnuj Aggarwal }
5404ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
5413fa5b8e0SAnuj Aggarwal 
5423fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
5433fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
5443fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
54531dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
546