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