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 46*055917acSAxel Lin /* Supported voltage values for regulators (in microVolts) */ 47*055917acSAxel Lin static const unsigned int VDCDCx_VSEL_table[] = { 48*055917acSAxel Lin 725000, 750000, 775000, 800000, 49*055917acSAxel Lin 825000, 850000, 875000, 900000, 50*055917acSAxel Lin 925000, 950000, 975000, 1000000, 51*055917acSAxel Lin 1025000, 1050000, 1075000, 1100000, 52*055917acSAxel Lin 1125000, 1150000, 1175000, 1200000, 53*055917acSAxel Lin 1225000, 1250000, 1275000, 1300000, 54*055917acSAxel Lin 1325000, 1350000, 1375000, 1400000, 55*055917acSAxel Lin 1425000, 1450000, 1475000, 1500000, 56*055917acSAxel Lin 1550000, 1600000, 1650000, 1700000, 57*055917acSAxel Lin 1750000, 1800000, 1850000, 1900000, 58*055917acSAxel Lin 1950000, 2000000, 2050000, 2100000, 59*055917acSAxel Lin 2150000, 2200000, 2250000, 2300000, 60*055917acSAxel Lin 2350000, 2400000, 2450000, 2500000, 61*055917acSAxel Lin 2550000, 2600000, 2650000, 2700000, 62*055917acSAxel Lin 2750000, 2800000, 2850000, 2900000, 63*055917acSAxel Lin 3000000, 3100000, 3200000, 3300000, 643fa5b8e0SAnuj Aggarwal }; 653fa5b8e0SAnuj Aggarwal 66*055917acSAxel Lin static const unsigned int LDO1_VSEL_table[] = { 67*055917acSAxel Lin 1000000, 1100000, 1200000, 1250000, 68*055917acSAxel Lin 1300000, 1350000, 1400000, 1500000, 69*055917acSAxel Lin 1600000, 1800000, 2500000, 2750000, 70*055917acSAxel Lin 2800000, 3000000, 3100000, 3300000, 713fa5b8e0SAnuj Aggarwal }; 723fa5b8e0SAnuj Aggarwal 73*055917acSAxel Lin static const unsigned int LDO2_VSEL_table[] = { 74*055917acSAxel Lin 725000, 750000, 775000, 800000, 75*055917acSAxel Lin 825000, 850000, 875000, 900000, 76*055917acSAxel Lin 925000, 950000, 975000, 1000000, 77*055917acSAxel Lin 1025000, 1050000, 1075000, 1100000, 78*055917acSAxel Lin 1125000, 1150000, 1175000, 1200000, 79*055917acSAxel Lin 1225000, 1250000, 1275000, 1300000, 80*055917acSAxel Lin 1325000, 1350000, 1375000, 1400000, 81*055917acSAxel Lin 1425000, 1450000, 1475000, 1500000, 82*055917acSAxel Lin 1550000, 1600000, 1650000, 1700000, 83*055917acSAxel Lin 1750000, 1800000, 1850000, 1900000, 84*055917acSAxel Lin 1950000, 2000000, 2050000, 2100000, 85*055917acSAxel Lin 2150000, 2200000, 2250000, 2300000, 86*055917acSAxel Lin 2350000, 2400000, 2450000, 2500000, 87*055917acSAxel Lin 2550000, 2600000, 2650000, 2700000, 88*055917acSAxel Lin 2750000, 2800000, 2850000, 2900000, 89*055917acSAxel Lin 3000000, 3100000, 3200000, 3300000, 903fa5b8e0SAnuj Aggarwal }; 913fa5b8e0SAnuj Aggarwal 923fa5b8e0SAnuj Aggarwal struct tps_info { 933fa5b8e0SAnuj Aggarwal const char *name; 943fa5b8e0SAnuj Aggarwal unsigned min_uV; 953fa5b8e0SAnuj Aggarwal unsigned max_uV; 963fa5b8e0SAnuj Aggarwal u8 table_len; 97*055917acSAxel Lin const unsigned int *table; 987d14831eSAnuj Aggarwal 997d14831eSAnuj Aggarwal /* Does DCDC high or the low register defines output voltage? */ 1007d14831eSAnuj Aggarwal bool defdcdc_default; 1013fa5b8e0SAnuj Aggarwal }; 1023fa5b8e0SAnuj Aggarwal 1037d14831eSAnuj Aggarwal static struct tps_info tps6507x_pmic_regs[] = { 10431dd6a26STodd Fischer { 10531dd6a26STodd Fischer .name = "VDCDC1", 10631dd6a26STodd Fischer .min_uV = 725000, 10731dd6a26STodd Fischer .max_uV = 3300000, 10831dd6a26STodd Fischer .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 10931dd6a26STodd Fischer .table = VDCDCx_VSEL_table, 11031dd6a26STodd Fischer }, 11131dd6a26STodd Fischer { 11231dd6a26STodd Fischer .name = "VDCDC2", 11331dd6a26STodd Fischer .min_uV = 725000, 11431dd6a26STodd Fischer .max_uV = 3300000, 11531dd6a26STodd Fischer .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 11631dd6a26STodd Fischer .table = VDCDCx_VSEL_table, 11731dd6a26STodd Fischer }, 11831dd6a26STodd Fischer { 11931dd6a26STodd Fischer .name = "VDCDC3", 12031dd6a26STodd Fischer .min_uV = 725000, 12131dd6a26STodd Fischer .max_uV = 3300000, 12231dd6a26STodd Fischer .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 12331dd6a26STodd Fischer .table = VDCDCx_VSEL_table, 12431dd6a26STodd Fischer }, 12531dd6a26STodd Fischer { 12631dd6a26STodd Fischer .name = "LDO1", 12731dd6a26STodd Fischer .min_uV = 1000000, 12831dd6a26STodd Fischer .max_uV = 3300000, 12931dd6a26STodd Fischer .table_len = ARRAY_SIZE(LDO1_VSEL_table), 13031dd6a26STodd Fischer .table = LDO1_VSEL_table, 13131dd6a26STodd Fischer }, 13231dd6a26STodd Fischer { 13331dd6a26STodd Fischer .name = "LDO2", 13431dd6a26STodd Fischer .min_uV = 725000, 13531dd6a26STodd Fischer .max_uV = 3300000, 13631dd6a26STodd Fischer .table_len = ARRAY_SIZE(LDO2_VSEL_table), 13731dd6a26STodd Fischer .table = LDO2_VSEL_table, 13831dd6a26STodd Fischer }, 13931dd6a26STodd Fischer }; 14031dd6a26STodd Fischer 1414ce5ba5bSTodd Fischer struct tps6507x_pmic { 1423fa5b8e0SAnuj Aggarwal struct regulator_desc desc[TPS6507X_NUM_REGULATOR]; 14331dd6a26STodd Fischer struct tps6507x_dev *mfd; 1443fa5b8e0SAnuj Aggarwal struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR]; 1457d14831eSAnuj Aggarwal struct tps_info *info[TPS6507X_NUM_REGULATOR]; 1463fa5b8e0SAnuj Aggarwal struct mutex io_lock; 1473fa5b8e0SAnuj Aggarwal }; 1484ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg) 1493fa5b8e0SAnuj Aggarwal { 15031dd6a26STodd Fischer u8 val; 15131dd6a26STodd Fischer int err; 15231dd6a26STodd Fischer 15331dd6a26STodd Fischer err = tps->mfd->read_dev(tps->mfd, reg, 1, &val); 15431dd6a26STodd Fischer 15531dd6a26STodd Fischer if (err) 15631dd6a26STodd Fischer return err; 15731dd6a26STodd Fischer 15831dd6a26STodd Fischer return val; 1593fa5b8e0SAnuj Aggarwal } 1603fa5b8e0SAnuj Aggarwal 1614ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val) 1623fa5b8e0SAnuj Aggarwal { 16331dd6a26STodd Fischer return tps->mfd->write_dev(tps->mfd, reg, 1, &val); 1643fa5b8e0SAnuj Aggarwal } 1653fa5b8e0SAnuj Aggarwal 1664ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask) 1673fa5b8e0SAnuj Aggarwal { 1683fa5b8e0SAnuj Aggarwal int err, data; 1693fa5b8e0SAnuj Aggarwal 1703fa5b8e0SAnuj Aggarwal mutex_lock(&tps->io_lock); 1713fa5b8e0SAnuj Aggarwal 1724ce5ba5bSTodd Fischer data = tps6507x_pmic_read(tps, reg); 1733fa5b8e0SAnuj Aggarwal if (data < 0) { 17431dd6a26STodd Fischer dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 1753fa5b8e0SAnuj Aggarwal err = data; 1763fa5b8e0SAnuj Aggarwal goto out; 1773fa5b8e0SAnuj Aggarwal } 1783fa5b8e0SAnuj Aggarwal 1793fa5b8e0SAnuj Aggarwal data |= mask; 1804ce5ba5bSTodd Fischer err = tps6507x_pmic_write(tps, reg, data); 1813fa5b8e0SAnuj Aggarwal if (err) 18231dd6a26STodd Fischer dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 1833fa5b8e0SAnuj Aggarwal 1843fa5b8e0SAnuj Aggarwal out: 1853fa5b8e0SAnuj Aggarwal mutex_unlock(&tps->io_lock); 1863fa5b8e0SAnuj Aggarwal return err; 1873fa5b8e0SAnuj Aggarwal } 1883fa5b8e0SAnuj Aggarwal 1894ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask) 1903fa5b8e0SAnuj Aggarwal { 1913fa5b8e0SAnuj Aggarwal int err, data; 1923fa5b8e0SAnuj Aggarwal 1933fa5b8e0SAnuj Aggarwal mutex_lock(&tps->io_lock); 1943fa5b8e0SAnuj Aggarwal 1954ce5ba5bSTodd Fischer data = tps6507x_pmic_read(tps, reg); 1963fa5b8e0SAnuj Aggarwal if (data < 0) { 19731dd6a26STodd Fischer dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 1983fa5b8e0SAnuj Aggarwal err = data; 1993fa5b8e0SAnuj Aggarwal goto out; 2003fa5b8e0SAnuj Aggarwal } 2013fa5b8e0SAnuj Aggarwal 2023fa5b8e0SAnuj Aggarwal data &= ~mask; 2034ce5ba5bSTodd Fischer err = tps6507x_pmic_write(tps, reg, data); 2043fa5b8e0SAnuj Aggarwal if (err) 20531dd6a26STodd Fischer dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 2063fa5b8e0SAnuj Aggarwal 2073fa5b8e0SAnuj Aggarwal out: 2083fa5b8e0SAnuj Aggarwal mutex_unlock(&tps->io_lock); 2093fa5b8e0SAnuj Aggarwal return err; 2103fa5b8e0SAnuj Aggarwal } 2113fa5b8e0SAnuj Aggarwal 2124ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg) 2133fa5b8e0SAnuj Aggarwal { 2143fa5b8e0SAnuj Aggarwal int data; 2153fa5b8e0SAnuj Aggarwal 2163fa5b8e0SAnuj Aggarwal mutex_lock(&tps->io_lock); 2173fa5b8e0SAnuj Aggarwal 2184ce5ba5bSTodd Fischer data = tps6507x_pmic_read(tps, reg); 2193fa5b8e0SAnuj Aggarwal if (data < 0) 22031dd6a26STodd Fischer dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 2213fa5b8e0SAnuj Aggarwal 2223fa5b8e0SAnuj Aggarwal mutex_unlock(&tps->io_lock); 2233fa5b8e0SAnuj Aggarwal return data; 2243fa5b8e0SAnuj Aggarwal } 2253fa5b8e0SAnuj Aggarwal 2264ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val) 2273fa5b8e0SAnuj Aggarwal { 2283fa5b8e0SAnuj Aggarwal int err; 2293fa5b8e0SAnuj Aggarwal 2303fa5b8e0SAnuj Aggarwal mutex_lock(&tps->io_lock); 2313fa5b8e0SAnuj Aggarwal 2324ce5ba5bSTodd Fischer err = tps6507x_pmic_write(tps, reg, val); 2333fa5b8e0SAnuj Aggarwal if (err < 0) 23431dd6a26STodd Fischer dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 2353fa5b8e0SAnuj Aggarwal 2363fa5b8e0SAnuj Aggarwal mutex_unlock(&tps->io_lock); 2373fa5b8e0SAnuj Aggarwal return err; 2383fa5b8e0SAnuj Aggarwal } 2393fa5b8e0SAnuj Aggarwal 240f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev) 2413fa5b8e0SAnuj Aggarwal { 2424ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 243f2933d33SAxel Lin int data, rid = rdev_get_id(dev); 2443fa5b8e0SAnuj Aggarwal u8 shift; 2453fa5b8e0SAnuj Aggarwal 246f2933d33SAxel Lin if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2473fa5b8e0SAnuj Aggarwal return -EINVAL; 2483fa5b8e0SAnuj Aggarwal 249f2933d33SAxel Lin shift = TPS6507X_MAX_REG_ID - rid; 2504ce5ba5bSTodd Fischer data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1); 2513fa5b8e0SAnuj Aggarwal 2523fa5b8e0SAnuj Aggarwal if (data < 0) 2533fa5b8e0SAnuj Aggarwal return data; 2543fa5b8e0SAnuj Aggarwal else 2553fa5b8e0SAnuj Aggarwal return (data & 1<<shift) ? 1 : 0; 2563fa5b8e0SAnuj Aggarwal } 2573fa5b8e0SAnuj Aggarwal 258f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev) 2593fa5b8e0SAnuj Aggarwal { 2604ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 261f2933d33SAxel Lin int rid = rdev_get_id(dev); 2623fa5b8e0SAnuj Aggarwal u8 shift; 2633fa5b8e0SAnuj Aggarwal 264f2933d33SAxel Lin if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2653fa5b8e0SAnuj Aggarwal return -EINVAL; 2663fa5b8e0SAnuj Aggarwal 267f2933d33SAxel Lin shift = TPS6507X_MAX_REG_ID - rid; 2684ce5ba5bSTodd Fischer return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); 2693fa5b8e0SAnuj Aggarwal } 2703fa5b8e0SAnuj Aggarwal 271f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev) 2723fa5b8e0SAnuj Aggarwal { 2734ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 274f2933d33SAxel Lin int rid = rdev_get_id(dev); 2753fa5b8e0SAnuj Aggarwal u8 shift; 2763fa5b8e0SAnuj Aggarwal 277f2933d33SAxel Lin if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2783fa5b8e0SAnuj Aggarwal return -EINVAL; 2793fa5b8e0SAnuj Aggarwal 280f2933d33SAxel Lin shift = TPS6507X_MAX_REG_ID - rid; 2814ce5ba5bSTodd Fischer return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 2824ce5ba5bSTodd Fischer 1 << shift); 2833fa5b8e0SAnuj Aggarwal } 2843fa5b8e0SAnuj Aggarwal 2857c842a1dSAxel Lin static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev) 2863fa5b8e0SAnuj Aggarwal { 2874ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 288f2933d33SAxel Lin int data, rid = rdev_get_id(dev); 289f2933d33SAxel Lin u8 reg, mask; 2903fa5b8e0SAnuj Aggarwal 291f2933d33SAxel Lin switch (rid) { 2923fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_1: 2933fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC1; 294f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 2953fa5b8e0SAnuj Aggarwal break; 2963fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_2: 297f2933d33SAxel Lin if (tps->info[rid]->defdcdc_default) 2987d14831eSAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC2_HIGH; 2997d14831eSAnuj Aggarwal else 3003fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC2_LOW; 301f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 3023fa5b8e0SAnuj Aggarwal break; 3033fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_3: 304f2933d33SAxel Lin if (tps->info[rid]->defdcdc_default) 3057d14831eSAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC3_HIGH; 3067d14831eSAnuj Aggarwal else 3073fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC3_LOW; 308f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 309f2933d33SAxel Lin break; 310f2933d33SAxel Lin case TPS6507X_LDO_1: 311f2933d33SAxel Lin reg = TPS6507X_REG_LDO_CTRL1; 312f2933d33SAxel Lin mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; 313f2933d33SAxel Lin break; 314f2933d33SAxel Lin case TPS6507X_LDO_2: 315f2933d33SAxel Lin reg = TPS6507X_REG_DEFLDO2; 316f2933d33SAxel Lin mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; 3173fa5b8e0SAnuj Aggarwal break; 3183fa5b8e0SAnuj Aggarwal default: 3193fa5b8e0SAnuj Aggarwal return -EINVAL; 3203fa5b8e0SAnuj Aggarwal } 3213fa5b8e0SAnuj Aggarwal 3224ce5ba5bSTodd Fischer data = tps6507x_pmic_reg_read(tps, reg); 3233fa5b8e0SAnuj Aggarwal if (data < 0) 3243fa5b8e0SAnuj Aggarwal return data; 3253fa5b8e0SAnuj Aggarwal 326f2933d33SAxel Lin data &= mask; 3277c842a1dSAxel Lin return data; 3283fa5b8e0SAnuj Aggarwal } 3293fa5b8e0SAnuj Aggarwal 330ca61a7bfSAxel Lin static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev, 331ca61a7bfSAxel Lin unsigned selector) 3323fa5b8e0SAnuj Aggarwal { 3334ce5ba5bSTodd Fischer struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 334ca61a7bfSAxel Lin int data, rid = rdev_get_id(dev); 335f2933d33SAxel Lin u8 reg, mask; 3363fa5b8e0SAnuj Aggarwal 337f2933d33SAxel Lin switch (rid) { 3383fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_1: 3393fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC1; 340f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 3413fa5b8e0SAnuj Aggarwal break; 3423fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_2: 343f2933d33SAxel Lin if (tps->info[rid]->defdcdc_default) 3447d14831eSAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC2_HIGH; 3457d14831eSAnuj Aggarwal else 3463fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC2_LOW; 347f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 3483fa5b8e0SAnuj Aggarwal break; 3493fa5b8e0SAnuj Aggarwal case TPS6507X_DCDC_3: 350f2933d33SAxel Lin if (tps->info[rid]->defdcdc_default) 3517d14831eSAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC3_HIGH; 3527d14831eSAnuj Aggarwal else 3533fa5b8e0SAnuj Aggarwal reg = TPS6507X_REG_DEFDCDC3_LOW; 354f2933d33SAxel Lin mask = TPS6507X_DEFDCDCX_DCDC_MASK; 355f2933d33SAxel Lin break; 356f2933d33SAxel Lin case TPS6507X_LDO_1: 357f2933d33SAxel Lin reg = TPS6507X_REG_LDO_CTRL1; 358f2933d33SAxel Lin mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; 359f2933d33SAxel Lin break; 360f2933d33SAxel Lin case TPS6507X_LDO_2: 361f2933d33SAxel Lin reg = TPS6507X_REG_DEFLDO2; 362f2933d33SAxel Lin mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; 3633fa5b8e0SAnuj Aggarwal break; 3643fa5b8e0SAnuj Aggarwal default: 3653fa5b8e0SAnuj Aggarwal return -EINVAL; 3663fa5b8e0SAnuj Aggarwal } 3673fa5b8e0SAnuj Aggarwal 3684ce5ba5bSTodd Fischer data = tps6507x_pmic_reg_read(tps, reg); 3693fa5b8e0SAnuj Aggarwal if (data < 0) 3703fa5b8e0SAnuj Aggarwal return data; 3713fa5b8e0SAnuj Aggarwal 3723fa5b8e0SAnuj Aggarwal data &= ~mask; 373ca61a7bfSAxel Lin data |= selector; 3743fa5b8e0SAnuj Aggarwal 3754ce5ba5bSTodd Fischer return tps6507x_pmic_reg_write(tps, reg, data); 3763fa5b8e0SAnuj Aggarwal } 3773fa5b8e0SAnuj Aggarwal 378f2933d33SAxel Lin static struct regulator_ops tps6507x_pmic_ops = { 379f2933d33SAxel Lin .is_enabled = tps6507x_pmic_is_enabled, 380f2933d33SAxel Lin .enable = tps6507x_pmic_enable, 381f2933d33SAxel Lin .disable = tps6507x_pmic_disable, 3827c842a1dSAxel Lin .get_voltage_sel = tps6507x_pmic_get_voltage_sel, 383ca61a7bfSAxel Lin .set_voltage_sel = tps6507x_pmic_set_voltage_sel, 384*055917acSAxel Lin .list_voltage = regulator_list_voltage_table, 3853fa5b8e0SAnuj Aggarwal }; 3863fa5b8e0SAnuj Aggarwal 387f2933d33SAxel Lin static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) 3883fa5b8e0SAnuj Aggarwal { 38931dd6a26STodd Fischer struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); 3907d14831eSAnuj Aggarwal struct tps_info *info = &tps6507x_pmic_regs[0]; 391c172708dSMark Brown struct regulator_config config = { }; 3923fa5b8e0SAnuj Aggarwal struct regulator_init_data *init_data; 3933fa5b8e0SAnuj Aggarwal struct regulator_dev *rdev; 3944ce5ba5bSTodd Fischer struct tps6507x_pmic *tps; 3950bc20bbaSTodd Fischer struct tps6507x_board *tps_board; 3963fa5b8e0SAnuj Aggarwal int i; 39756c23492SDmitry Torokhov int error; 3983fa5b8e0SAnuj Aggarwal 3993fa5b8e0SAnuj Aggarwal /** 4000bc20bbaSTodd Fischer * tps_board points to pmic related constants 4010bc20bbaSTodd Fischer * coming from the board-evm file. 4020bc20bbaSTodd Fischer */ 4030bc20bbaSTodd Fischer 40431dd6a26STodd Fischer tps_board = dev_get_platdata(tps6507x_dev->dev); 4050bc20bbaSTodd Fischer if (!tps_board) 4060bc20bbaSTodd Fischer return -EINVAL; 4070bc20bbaSTodd Fischer 4080bc20bbaSTodd Fischer /** 4093fa5b8e0SAnuj Aggarwal * init_data points to array of regulator_init structures 4103fa5b8e0SAnuj Aggarwal * coming from the board-evm file. 4113fa5b8e0SAnuj Aggarwal */ 4120bc20bbaSTodd Fischer init_data = tps_board->tps6507x_pmic_init_data; 4133fa5b8e0SAnuj Aggarwal if (!init_data) 4140bc20bbaSTodd Fischer return -EINVAL; 4153fa5b8e0SAnuj Aggarwal 4169eb0c421SAxel Lin tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL); 4173fa5b8e0SAnuj Aggarwal if (!tps) 4183fa5b8e0SAnuj Aggarwal return -ENOMEM; 4193fa5b8e0SAnuj Aggarwal 4203fa5b8e0SAnuj Aggarwal mutex_init(&tps->io_lock); 4213fa5b8e0SAnuj Aggarwal 4223fa5b8e0SAnuj Aggarwal /* common for all regulators */ 42331dd6a26STodd Fischer tps->mfd = tps6507x_dev; 4243fa5b8e0SAnuj Aggarwal 4253fa5b8e0SAnuj Aggarwal for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) { 4263fa5b8e0SAnuj Aggarwal /* Register the regulators */ 4273fa5b8e0SAnuj Aggarwal tps->info[i] = info; 4287d14831eSAnuj Aggarwal if (init_data->driver_data) { 4297d14831eSAnuj Aggarwal struct tps6507x_reg_platform_data *data = 4307d14831eSAnuj Aggarwal init_data->driver_data; 4317d14831eSAnuj Aggarwal tps->info[i]->defdcdc_default = data->defdcdc_default; 4327d14831eSAnuj Aggarwal } 4337d14831eSAnuj Aggarwal 4343fa5b8e0SAnuj Aggarwal tps->desc[i].name = info->name; 43577fa44d0SAxel Lin tps->desc[i].id = i; 4360fcdb109SAxel Lin tps->desc[i].n_voltages = info->table_len; 437*055917acSAxel Lin tps->desc[i].volt_table = info->table; 438f2933d33SAxel Lin tps->desc[i].ops = &tps6507x_pmic_ops; 4393fa5b8e0SAnuj Aggarwal tps->desc[i].type = REGULATOR_VOLTAGE; 4403fa5b8e0SAnuj Aggarwal tps->desc[i].owner = THIS_MODULE; 4413fa5b8e0SAnuj Aggarwal 442c172708dSMark Brown config.dev = tps6507x_dev->dev; 443c172708dSMark Brown config.init_data = init_data; 444c172708dSMark Brown config.driver_data = tps; 445c172708dSMark Brown 446c172708dSMark Brown rdev = regulator_register(&tps->desc[i], &config); 4473fa5b8e0SAnuj Aggarwal if (IS_ERR(rdev)) { 44831dd6a26STodd Fischer dev_err(tps6507x_dev->dev, 44931dd6a26STodd Fischer "failed to register %s regulator\n", 45031dd6a26STodd Fischer pdev->name); 45156c23492SDmitry Torokhov error = PTR_ERR(rdev); 45256c23492SDmitry Torokhov goto fail; 4533fa5b8e0SAnuj Aggarwal } 4543fa5b8e0SAnuj Aggarwal 4553fa5b8e0SAnuj Aggarwal /* Save regulator for cleanup */ 4563fa5b8e0SAnuj Aggarwal tps->rdev[i] = rdev; 4573fa5b8e0SAnuj Aggarwal } 4583fa5b8e0SAnuj Aggarwal 45931dd6a26STodd Fischer tps6507x_dev->pmic = tps; 460d7399fa8SAxel Lin platform_set_drvdata(pdev, tps6507x_dev); 4613fa5b8e0SAnuj Aggarwal 4623fa5b8e0SAnuj Aggarwal return 0; 46356c23492SDmitry Torokhov 46456c23492SDmitry Torokhov fail: 46556c23492SDmitry Torokhov while (--i >= 0) 46656c23492SDmitry Torokhov regulator_unregister(tps->rdev[i]); 46756c23492SDmitry Torokhov return error; 4683fa5b8e0SAnuj Aggarwal } 4693fa5b8e0SAnuj Aggarwal 47031dd6a26STodd Fischer static int __devexit tps6507x_pmic_remove(struct platform_device *pdev) 4713fa5b8e0SAnuj Aggarwal { 47231dd6a26STodd Fischer struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); 47331dd6a26STodd Fischer struct tps6507x_pmic *tps = tps6507x_dev->pmic; 4743fa5b8e0SAnuj Aggarwal int i; 4753fa5b8e0SAnuj Aggarwal 4763fa5b8e0SAnuj Aggarwal for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) 4773fa5b8e0SAnuj Aggarwal regulator_unregister(tps->rdev[i]); 4783fa5b8e0SAnuj Aggarwal return 0; 4793fa5b8e0SAnuj Aggarwal } 4803fa5b8e0SAnuj Aggarwal 48131dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = { 4823fa5b8e0SAnuj Aggarwal .driver = { 48331dd6a26STodd Fischer .name = "tps6507x-pmic", 4843fa5b8e0SAnuj Aggarwal .owner = THIS_MODULE, 4853fa5b8e0SAnuj Aggarwal }, 4864ce5ba5bSTodd Fischer .probe = tps6507x_pmic_probe, 4874ce5ba5bSTodd Fischer .remove = __devexit_p(tps6507x_pmic_remove), 4883fa5b8e0SAnuj Aggarwal }; 4893fa5b8e0SAnuj Aggarwal 4904ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void) 4913fa5b8e0SAnuj Aggarwal { 49231dd6a26STodd Fischer return platform_driver_register(&tps6507x_pmic_driver); 4933fa5b8e0SAnuj Aggarwal } 4944ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init); 4953fa5b8e0SAnuj Aggarwal 4964ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void) 4973fa5b8e0SAnuj Aggarwal { 49831dd6a26STodd Fischer platform_driver_unregister(&tps6507x_pmic_driver); 4993fa5b8e0SAnuj Aggarwal } 5004ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup); 5013fa5b8e0SAnuj Aggarwal 5023fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments"); 5033fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); 5043fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2"); 50531dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic"); 506