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(®_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