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> 265a0e3ad6STejun Heo #include <linux/slab.h> 27d183fcc9STodd Fischer #include <linux/mfd/tps6507x.h> 283fa5b8e0SAnuj Aggarwal 293fa5b8e0SAnuj Aggarwal /* DCDC's */ 303fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_1 0 313fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_2 1 323fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_3 2 333fa5b8e0SAnuj Aggarwal /* LDOs */ 343fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_1 3 353fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_2 4 363fa5b8e0SAnuj Aggarwal 373fa5b8e0SAnuj Aggarwal #define TPS6507X_MAX_REG_ID TPS6507X_LDO_2 383fa5b8e0SAnuj Aggarwal 393fa5b8e0SAnuj Aggarwal /* Number of step-down converters available */ 403fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_DCDC 3 413fa5b8e0SAnuj Aggarwal /* Number of LDO voltage regulators available */ 423fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_LDO 2 433fa5b8e0SAnuj Aggarwal /* Number of total regulators available */ 443fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_REGULATOR (TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO) 453fa5b8e0SAnuj Aggarwal 46055917acSAxel Lin /* Supported voltage values for regulators (in microVolts) */ 47055917acSAxel Lin static const unsigned int VDCDCx_VSEL_table[] = { 48055917acSAxel Lin 725000, 750000, 775000, 800000, 49055917acSAxel Lin 825000, 850000, 875000, 900000, 50055917acSAxel Lin 925000, 950000, 975000, 1000000, 51055917acSAxel Lin 1025000, 1050000, 1075000, 1100000, 52055917acSAxel Lin 1125000, 1150000, 1175000, 1200000, 53055917acSAxel Lin 1225000, 1250000, 1275000, 1300000, 54055917acSAxel Lin 1325000, 1350000, 1375000, 1400000, 55055917acSAxel Lin 1425000, 1450000, 1475000, 1500000, 56055917acSAxel Lin 1550000, 1600000, 1650000, 1700000, 57055917acSAxel Lin 1750000, 1800000, 1850000, 1900000, 58055917acSAxel Lin 1950000, 2000000, 2050000, 2100000, 59055917acSAxel Lin 2150000, 2200000, 2250000, 2300000, 60055917acSAxel Lin 2350000, 2400000, 2450000, 2500000, 61055917acSAxel Lin 2550000, 2600000, 2650000, 2700000, 62055917acSAxel Lin 2750000, 2800000, 2850000, 2900000, 63055917acSAxel Lin 3000000, 3100000, 3200000, 3300000, 643fa5b8e0SAnuj Aggarwal }; 653fa5b8e0SAnuj Aggarwal 66055917acSAxel Lin static const unsigned int LDO1_VSEL_table[] = { 67055917acSAxel Lin 1000000, 1100000, 1200000, 1250000, 68055917acSAxel Lin 1300000, 1350000, 1400000, 1500000, 69055917acSAxel Lin 1600000, 1800000, 2500000, 2750000, 70055917acSAxel Lin 2800000, 3000000, 3100000, 3300000, 713fa5b8e0SAnuj Aggarwal }; 723fa5b8e0SAnuj Aggarwal 73*93b07e7bSAxel Lin /* The voltage mapping table for LDO2 is the same as VDCDCx */ 74*93b07e7bSAxel Lin #define LDO2_VSEL_table VDCDCx_VSEL_table 753fa5b8e0SAnuj Aggarwal 763fa5b8e0SAnuj Aggarwal struct tps_info { 773fa5b8e0SAnuj Aggarwal const char *name; 783fa5b8e0SAnuj Aggarwal u8 table_len; 79055917acSAxel Lin const unsigned int *table; 807d14831eSAnuj Aggarwal 817d14831eSAnuj Aggarwal /* Does DCDC high or the low register defines output voltage? */ 827d14831eSAnuj Aggarwal bool defdcdc_default; 833fa5b8e0SAnuj Aggarwal }; 843fa5b8e0SAnuj Aggarwal 857d14831eSAnuj Aggarwal static struct tps_info tps6507x_pmic_regs[] = { 8631dd6a26STodd Fischer { 8731dd6a26STodd Fischer .name = "VDCDC1", 8831dd6a26STodd Fischer .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 8931dd6a26STodd Fischer .table = VDCDCx_VSEL_table, 9031dd6a26STodd Fischer }, 9131dd6a26STodd Fischer { 9231dd6a26STodd Fischer .name = "VDCDC2", 9331dd6a26STodd Fischer .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 9431dd6a26STodd Fischer .table = VDCDCx_VSEL_table, 9531dd6a26STodd Fischer }, 9631dd6a26STodd Fischer { 9731dd6a26STodd Fischer .name = "VDCDC3", 9831dd6a26STodd Fischer .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 9931dd6a26STodd Fischer .table = VDCDCx_VSEL_table, 10031dd6a26STodd Fischer }, 10131dd6a26STodd Fischer { 10231dd6a26STodd Fischer .name = "LDO1", 10331dd6a26STodd Fischer .table_len = ARRAY_SIZE(LDO1_VSEL_table), 10431dd6a26STodd Fischer .table = LDO1_VSEL_table, 10531dd6a26STodd Fischer }, 10631dd6a26STodd Fischer { 10731dd6a26STodd Fischer .name = "LDO2", 10831dd6a26STodd Fischer .table_len = ARRAY_SIZE(LDO2_VSEL_table), 10931dd6a26STodd Fischer .table = LDO2_VSEL_table, 11031dd6a26STodd Fischer }, 11131dd6a26STodd Fischer }; 11231dd6a26STodd Fischer 1134ce5ba5bSTodd Fischer struct tps6507x_pmic { 1143fa5b8e0SAnuj Aggarwal struct regulator_desc desc[TPS6507X_NUM_REGULATOR]; 11531dd6a26STodd Fischer struct tps6507x_dev *mfd; 1163fa5b8e0SAnuj Aggarwal struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR]; 1177d14831eSAnuj Aggarwal struct tps_info *info[TPS6507X_NUM_REGULATOR]; 1183fa5b8e0SAnuj Aggarwal struct mutex io_lock; 1193fa5b8e0SAnuj Aggarwal }; 1204ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg) 1213fa5b8e0SAnuj Aggarwal { 12231dd6a26STodd Fischer u8 val; 12331dd6a26STodd Fischer int err; 12431dd6a26STodd Fischer 12531dd6a26STodd Fischer err = tps->mfd->read_dev(tps->mfd, reg, 1, &val); 12631dd6a26STodd Fischer 12731dd6a26STodd Fischer if (err) 12831dd6a26STodd Fischer return err; 12931dd6a26STodd Fischer 13031dd6a26STodd Fischer return val; 1313fa5b8e0SAnuj Aggarwal } 1323fa5b8e0SAnuj Aggarwal 1334ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val) 1343fa5b8e0SAnuj Aggarwal { 13531dd6a26STodd Fischer return tps->mfd->write_dev(tps->mfd, reg, 1, &val); 1363fa5b8e0SAnuj Aggarwal } 1373fa5b8e0SAnuj Aggarwal 1384ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask) 1393fa5b8e0SAnuj Aggarwal { 1403fa5b8e0SAnuj Aggarwal int err, data; 1413fa5b8e0SAnuj Aggarwal 1423fa5b8e0SAnuj Aggarwal mutex_lock(&tps->io_lock); 1433fa5b8e0SAnuj Aggarwal 1444ce5ba5bSTodd Fischer data = tps6507x_pmic_read(tps, reg); 1453fa5b8e0SAnuj Aggarwal if (data < 0) { 14631dd6a26STodd Fischer dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 1473fa5b8e0SAnuj Aggarwal err = data; 1483fa5b8e0SAnuj Aggarwal goto out; 1493fa5b8e0SAnuj Aggarwal } 1503fa5b8e0SAnuj Aggarwal 1513fa5b8e0SAnuj Aggarwal data |= mask; 1524ce5ba5bSTodd Fischer err = tps6507x_pmic_write(tps, reg, data); 1533fa5b8e0SAnuj Aggarwal if (err) 15431dd6a26STodd Fischer dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 1553fa5b8e0SAnuj Aggarwal 1563fa5b8e0SAnuj Aggarwal out: 1573fa5b8e0SAnuj Aggarwal mutex_unlock(&tps->io_lock); 1583fa5b8e0SAnuj Aggarwal return err; 1593fa5b8e0SAnuj Aggarwal } 1603fa5b8e0SAnuj Aggarwal 1614ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask) 1623fa5b8e0SAnuj Aggarwal { 1633fa5b8e0SAnuj Aggarwal int err, data; 1643fa5b8e0SAnuj Aggarwal 1653fa5b8e0SAnuj Aggarwal mutex_lock(&tps->io_lock); 1663fa5b8e0SAnuj Aggarwal 1674ce5ba5bSTodd Fischer data = tps6507x_pmic_read(tps, reg); 1683fa5b8e0SAnuj Aggarwal if (data < 0) { 16931dd6a26STodd Fischer dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 1703fa5b8e0SAnuj Aggarwal err = data; 1713fa5b8e0SAnuj Aggarwal goto out; 1723fa5b8e0SAnuj Aggarwal } 1733fa5b8e0SAnuj Aggarwal 1743fa5b8e0SAnuj Aggarwal data &= ~mask; 1754ce5ba5bSTodd Fischer err = tps6507x_pmic_write(tps, reg, data); 1763fa5b8e0SAnuj Aggarwal if (err) 17731dd6a26STodd Fischer dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 1783fa5b8e0SAnuj Aggarwal 1793fa5b8e0SAnuj Aggarwal out: 1803fa5b8e0SAnuj Aggarwal mutex_unlock(&tps->io_lock); 1813fa5b8e0SAnuj Aggarwal return err; 1823fa5b8e0SAnuj Aggarwal } 1833fa5b8e0SAnuj Aggarwal 1844ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg) 1853fa5b8e0SAnuj Aggarwal { 1863fa5b8e0SAnuj Aggarwal int data; 1873fa5b8e0SAnuj Aggarwal 1883fa5b8e0SAnuj Aggarwal mutex_lock(&tps->io_lock); 1893fa5b8e0SAnuj Aggarwal 1904ce5ba5bSTodd Fischer data = tps6507x_pmic_read(tps, reg); 1913fa5b8e0SAnuj Aggarwal if (data < 0) 19231dd6a26STodd Fischer dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 1933fa5b8e0SAnuj Aggarwal 1943fa5b8e0SAnuj Aggarwal mutex_unlock(&tps->io_lock); 1953fa5b8e0SAnuj Aggarwal return data; 1963fa5b8e0SAnuj Aggarwal } 1973fa5b8e0SAnuj Aggarwal 1984ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val) 1993fa5b8e0SAnuj Aggarwal { 2003fa5b8e0SAnuj Aggarwal int err; 2013fa5b8e0SAnuj Aggarwal 2023fa5b8e0SAnuj Aggarwal mutex_lock(&tps->io_lock); 2033fa5b8e0SAnuj Aggarwal 2044ce5ba5bSTodd Fischer err = tps6507x_pmic_write(tps, reg, val); 2053fa5b8e0SAnuj Aggarwal if (err < 0) 20631dd6a26STodd Fischer dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 2073fa5b8e0SAnuj Aggarwal 2083fa5b8e0SAnuj Aggarwal mutex_unlock(&tps->io_lock); 2093fa5b8e0SAnuj Aggarwal return err; 2103fa5b8e0SAnuj Aggarwal } 2113fa5b8e0SAnuj Aggarwal 212f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev) 2133fa5b8e0SAnuj Aggarwal { 2144ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 215f2933d33SAxel Lin int data, rid = rdev_get_id(dev); 2163fa5b8e0SAnuj Aggarwal u8 shift; 2173fa5b8e0SAnuj Aggarwal 218f2933d33SAxel Lin if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2193fa5b8e0SAnuj Aggarwal return -EINVAL; 2203fa5b8e0SAnuj Aggarwal 221f2933d33SAxel Lin shift = TPS6507X_MAX_REG_ID - rid; 2224ce5ba5bSTodd Fischer data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1); 2233fa5b8e0SAnuj Aggarwal 2243fa5b8e0SAnuj Aggarwal if (data < 0) 2253fa5b8e0SAnuj Aggarwal return data; 2263fa5b8e0SAnuj Aggarwal else 2273fa5b8e0SAnuj Aggarwal return (data & 1<<shift) ? 1 : 0; 2283fa5b8e0SAnuj Aggarwal } 2293fa5b8e0SAnuj Aggarwal 230f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev) 2313fa5b8e0SAnuj Aggarwal { 2324ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 233f2933d33SAxel Lin int rid = rdev_get_id(dev); 2343fa5b8e0SAnuj Aggarwal u8 shift; 2353fa5b8e0SAnuj Aggarwal 236f2933d33SAxel Lin if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2373fa5b8e0SAnuj Aggarwal return -EINVAL; 2383fa5b8e0SAnuj Aggarwal 239f2933d33SAxel Lin shift = TPS6507X_MAX_REG_ID - rid; 2404ce5ba5bSTodd Fischer return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); 2413fa5b8e0SAnuj Aggarwal } 2423fa5b8e0SAnuj Aggarwal 243f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev) 2443fa5b8e0SAnuj Aggarwal { 2454ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 246f2933d33SAxel Lin int rid = rdev_get_id(dev); 2473fa5b8e0SAnuj Aggarwal u8 shift; 2483fa5b8e0SAnuj Aggarwal 249f2933d33SAxel Lin if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2503fa5b8e0SAnuj Aggarwal return -EINVAL; 2513fa5b8e0SAnuj Aggarwal 252f2933d33SAxel Lin shift = TPS6507X_MAX_REG_ID - rid; 2534ce5ba5bSTodd Fischer return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 2544ce5ba5bSTodd Fischer 1 << shift); 2553fa5b8e0SAnuj Aggarwal } 2563fa5b8e0SAnuj Aggarwal 2577c842a1dSAxel Lin static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev) 2583fa5b8e0SAnuj Aggarwal { 2594ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 260f2933d33SAxel Lin int data, rid = rdev_get_id(dev); 261f2933d33SAxel Lin u8 reg, mask; 2623fa5b8e0SAnuj Aggarwal 263f2933d33SAxel Lin switch (rid) { 2643fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_1: 2653fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC1; 266f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 2673fa5b8e0SAnuj Aggarwal break; 2683fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_2: 269f2933d33SAxel Lin if (tps->info[rid]->defdcdc_default) 2707d14831eSAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC2_HIGH; 2717d14831eSAnuj Aggarwal else 2723fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC2_LOW; 273f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 2743fa5b8e0SAnuj Aggarwal break; 2753fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_3: 276f2933d33SAxel Lin if (tps->info[rid]->defdcdc_default) 2777d14831eSAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC3_HIGH; 2787d14831eSAnuj Aggarwal else 2793fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC3_LOW; 280f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 281f2933d33SAxel Lin break; 282f2933d33SAxel Lin case TPS6507X_LDO_1: 283f2933d33SAxel Lin reg = TPS6507X_REG_LDO_CTRL1; 284f2933d33SAxel Lin mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; 285f2933d33SAxel Lin break; 286f2933d33SAxel Lin case TPS6507X_LDO_2: 287f2933d33SAxel Lin reg = TPS6507X_REG_DEFLDO2; 288f2933d33SAxel Lin mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; 2893fa5b8e0SAnuj Aggarwal break; 2903fa5b8e0SAnuj Aggarwal default: 2913fa5b8e0SAnuj Aggarwal return -EINVAL; 2923fa5b8e0SAnuj Aggarwal } 2933fa5b8e0SAnuj Aggarwal 2944ce5ba5bSTodd Fischer data = tps6507x_pmic_reg_read(tps, reg); 2953fa5b8e0SAnuj Aggarwal if (data < 0) 2963fa5b8e0SAnuj Aggarwal return data; 2973fa5b8e0SAnuj Aggarwal 298f2933d33SAxel Lin data &= mask; 2997c842a1dSAxel Lin return data; 3003fa5b8e0SAnuj Aggarwal } 3013fa5b8e0SAnuj Aggarwal 302ca61a7bfSAxel Lin static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev, 303ca61a7bfSAxel Lin unsigned selector) 3043fa5b8e0SAnuj Aggarwal { 3054ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 306ca61a7bfSAxel Lin int data, rid = rdev_get_id(dev); 307f2933d33SAxel Lin u8 reg, mask; 3083fa5b8e0SAnuj Aggarwal 309f2933d33SAxel Lin switch (rid) { 3103fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_1: 3113fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC1; 312f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 3133fa5b8e0SAnuj Aggarwal break; 3143fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_2: 315f2933d33SAxel Lin if (tps->info[rid]->defdcdc_default) 3167d14831eSAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC2_HIGH; 3177d14831eSAnuj Aggarwal else 3183fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC2_LOW; 319f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 3203fa5b8e0SAnuj Aggarwal break; 3213fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_3: 322f2933d33SAxel Lin if (tps->info[rid]->defdcdc_default) 3237d14831eSAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC3_HIGH; 3247d14831eSAnuj Aggarwal else 3253fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC3_LOW; 326f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 327f2933d33SAxel Lin break; 328f2933d33SAxel Lin case TPS6507X_LDO_1: 329f2933d33SAxel Lin reg = TPS6507X_REG_LDO_CTRL1; 330f2933d33SAxel Lin mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; 331f2933d33SAxel Lin break; 332f2933d33SAxel Lin case TPS6507X_LDO_2: 333f2933d33SAxel Lin reg = TPS6507X_REG_DEFLDO2; 334f2933d33SAxel Lin mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; 3353fa5b8e0SAnuj Aggarwal break; 3363fa5b8e0SAnuj Aggarwal default: 3373fa5b8e0SAnuj Aggarwal return -EINVAL; 3383fa5b8e0SAnuj Aggarwal } 3393fa5b8e0SAnuj Aggarwal 3404ce5ba5bSTodd Fischer data = tps6507x_pmic_reg_read(tps, reg); 3413fa5b8e0SAnuj Aggarwal if (data < 0) 3423fa5b8e0SAnuj Aggarwal return data; 3433fa5b8e0SAnuj Aggarwal 3443fa5b8e0SAnuj Aggarwal data &= ~mask; 345ca61a7bfSAxel Lin data |= selector; 3463fa5b8e0SAnuj Aggarwal 3474ce5ba5bSTodd Fischer return tps6507x_pmic_reg_write(tps, reg, data); 3483fa5b8e0SAnuj Aggarwal } 3493fa5b8e0SAnuj Aggarwal 350f2933d33SAxel Lin static struct regulator_ops tps6507x_pmic_ops = { 351f2933d33SAxel Lin .is_enabled = tps6507x_pmic_is_enabled, 352f2933d33SAxel Lin .enable = tps6507x_pmic_enable, 353f2933d33SAxel Lin .disable = tps6507x_pmic_disable, 3547c842a1dSAxel Lin .get_voltage_sel = tps6507x_pmic_get_voltage_sel, 355ca61a7bfSAxel Lin .set_voltage_sel = tps6507x_pmic_set_voltage_sel, 356055917acSAxel Lin .list_voltage = regulator_list_voltage_table, 3573fa5b8e0SAnuj Aggarwal }; 3583fa5b8e0SAnuj Aggarwal 359f2933d33SAxel Lin static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) 3603fa5b8e0SAnuj Aggarwal { 36131dd6a26STodd Fischer struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); 3627d14831eSAnuj Aggarwal struct tps_info *info = &tps6507x_pmic_regs[0]; 363c172708dSMark Brown struct regulator_config config = { }; 3643fa5b8e0SAnuj Aggarwal struct regulator_init_data *init_data; 3653fa5b8e0SAnuj Aggarwal struct regulator_dev *rdev; 3664ce5ba5bSTodd Fischer struct tps6507x_pmic *tps; 3670bc20bbaSTodd Fischer struct tps6507x_board *tps_board; 3683fa5b8e0SAnuj Aggarwal int i; 36956c23492SDmitry Torokhov int error; 3703fa5b8e0SAnuj Aggarwal 3713fa5b8e0SAnuj Aggarwal /** 3720bc20bbaSTodd Fischer * tps_board points to pmic related constants 3730bc20bbaSTodd Fischer * coming from the board-evm file. 3740bc20bbaSTodd Fischer */ 3750bc20bbaSTodd Fischer 37631dd6a26STodd Fischer tps_board = dev_get_platdata(tps6507x_dev->dev); 3770bc20bbaSTodd Fischer if (!tps_board) 3780bc20bbaSTodd Fischer return -EINVAL; 3790bc20bbaSTodd Fischer 3800bc20bbaSTodd Fischer /** 3813fa5b8e0SAnuj Aggarwal * init_data points to array of regulator_init structures 3823fa5b8e0SAnuj Aggarwal * coming from the board-evm file. 3833fa5b8e0SAnuj Aggarwal */ 3840bc20bbaSTodd Fischer init_data = tps_board->tps6507x_pmic_init_data; 3853fa5b8e0SAnuj Aggarwal if (!init_data) 3860bc20bbaSTodd Fischer return -EINVAL; 3873fa5b8e0SAnuj Aggarwal 3889eb0c421SAxel Lin tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL); 3893fa5b8e0SAnuj Aggarwal if (!tps) 3903fa5b8e0SAnuj Aggarwal return -ENOMEM; 3913fa5b8e0SAnuj Aggarwal 3923fa5b8e0SAnuj Aggarwal mutex_init(&tps->io_lock); 3933fa5b8e0SAnuj Aggarwal 3943fa5b8e0SAnuj Aggarwal /* common for all regulators */ 39531dd6a26STodd Fischer tps->mfd = tps6507x_dev; 3963fa5b8e0SAnuj Aggarwal 3973fa5b8e0SAnuj Aggarwal for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) { 3983fa5b8e0SAnuj Aggarwal /* Register the regulators */ 3993fa5b8e0SAnuj Aggarwal tps->info[i] = info; 4007d14831eSAnuj Aggarwal if (init_data->driver_data) { 4017d14831eSAnuj Aggarwal struct tps6507x_reg_platform_data *data = 4027d14831eSAnuj Aggarwal init_data->driver_data; 4037d14831eSAnuj Aggarwal tps->info[i]->defdcdc_default = data->defdcdc_default; 4047d14831eSAnuj Aggarwal } 4057d14831eSAnuj Aggarwal 4063fa5b8e0SAnuj Aggarwal tps->desc[i].name = info->name; 40777fa44d0SAxel Lin tps->desc[i].id = i; 4080fcdb109SAxel Lin tps->desc[i].n_voltages = info->table_len; 409055917acSAxel Lin tps->desc[i].volt_table = info->table; 410f2933d33SAxel Lin tps->desc[i].ops = &tps6507x_pmic_ops; 4113fa5b8e0SAnuj Aggarwal tps->desc[i].type = REGULATOR_VOLTAGE; 4123fa5b8e0SAnuj Aggarwal tps->desc[i].owner = THIS_MODULE; 4133fa5b8e0SAnuj Aggarwal 414c172708dSMark Brown config.dev = tps6507x_dev->dev; 415c172708dSMark Brown config.init_data = init_data; 416c172708dSMark Brown config.driver_data = tps; 417c172708dSMark Brown 418c172708dSMark Brown rdev = regulator_register(&tps->desc[i], &config); 4193fa5b8e0SAnuj Aggarwal if (IS_ERR(rdev)) { 42031dd6a26STodd Fischer dev_err(tps6507x_dev->dev, 42131dd6a26STodd Fischer "failed to register %s regulator\n", 42231dd6a26STodd Fischer pdev->name); 42356c23492SDmitry Torokhov error = PTR_ERR(rdev); 42456c23492SDmitry Torokhov goto fail; 4253fa5b8e0SAnuj Aggarwal } 4263fa5b8e0SAnuj Aggarwal 4273fa5b8e0SAnuj Aggarwal /* Save regulator for cleanup */ 4283fa5b8e0SAnuj Aggarwal tps->rdev[i] = rdev; 4293fa5b8e0SAnuj Aggarwal } 4303fa5b8e0SAnuj Aggarwal 43131dd6a26STodd Fischer tps6507x_dev->pmic = tps; 432d7399fa8SAxel Lin platform_set_drvdata(pdev, tps6507x_dev); 4333fa5b8e0SAnuj Aggarwal 4343fa5b8e0SAnuj Aggarwal return 0; 43556c23492SDmitry Torokhov 43656c23492SDmitry Torokhov fail: 43756c23492SDmitry Torokhov while (--i >= 0) 43856c23492SDmitry Torokhov regulator_unregister(tps->rdev[i]); 43956c23492SDmitry Torokhov return error; 4403fa5b8e0SAnuj Aggarwal } 4413fa5b8e0SAnuj Aggarwal 44231dd6a26STodd Fischer static int __devexit tps6507x_pmic_remove(struct platform_device *pdev) 4433fa5b8e0SAnuj Aggarwal { 44431dd6a26STodd Fischer struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); 44531dd6a26STodd Fischer struct tps6507x_pmic *tps = tps6507x_dev->pmic; 4463fa5b8e0SAnuj Aggarwal int i; 4473fa5b8e0SAnuj Aggarwal 4483fa5b8e0SAnuj Aggarwal for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) 4493fa5b8e0SAnuj Aggarwal regulator_unregister(tps->rdev[i]); 4503fa5b8e0SAnuj Aggarwal return 0; 4513fa5b8e0SAnuj Aggarwal } 4523fa5b8e0SAnuj Aggarwal 45331dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = { 4543fa5b8e0SAnuj Aggarwal .driver = { 45531dd6a26STodd Fischer .name = "tps6507x-pmic", 4563fa5b8e0SAnuj Aggarwal .owner = THIS_MODULE, 4573fa5b8e0SAnuj Aggarwal }, 4584ce5ba5bSTodd Fischer .probe = tps6507x_pmic_probe, 4594ce5ba5bSTodd Fischer .remove = __devexit_p(tps6507x_pmic_remove), 4603fa5b8e0SAnuj Aggarwal }; 4613fa5b8e0SAnuj Aggarwal 4624ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void) 4633fa5b8e0SAnuj Aggarwal { 46431dd6a26STodd Fischer return platform_driver_register(&tps6507x_pmic_driver); 4653fa5b8e0SAnuj Aggarwal } 4664ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init); 4673fa5b8e0SAnuj Aggarwal 4684ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void) 4693fa5b8e0SAnuj Aggarwal { 47031dd6a26STodd Fischer platform_driver_unregister(&tps6507x_pmic_driver); 4713fa5b8e0SAnuj Aggarwal } 4724ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup); 4733fa5b8e0SAnuj Aggarwal 4743fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments"); 4753fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); 4763fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2"); 47731dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic"); 478