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