15976f095SAxel Lin /* 25976f095SAxel Lin * Regulator driver for National Semiconductors LP3972 PMIC chip 35976f095SAxel Lin * 45976f095SAxel Lin * Based on lp3971.c 55976f095SAxel Lin * 65976f095SAxel Lin * This program is free software; you can redistribute it and/or modify 75976f095SAxel Lin * it under the terms of the GNU General Public License version 2 as 85976f095SAxel Lin * published by the Free Software Foundation. 95976f095SAxel Lin * 105976f095SAxel Lin */ 115976f095SAxel Lin 125976f095SAxel Lin #include <linux/bug.h> 135976f095SAxel Lin #include <linux/err.h> 145976f095SAxel Lin #include <linux/i2c.h> 1565602c32SPaul Gortmaker #include <linux/module.h> 165976f095SAxel Lin #include <linux/kernel.h> 175976f095SAxel Lin #include <linux/regulator/driver.h> 185976f095SAxel Lin #include <linux/regulator/lp3972.h> 195976f095SAxel Lin #include <linux/slab.h> 205976f095SAxel Lin 215976f095SAxel Lin struct lp3972 { 225976f095SAxel Lin struct device *dev; 235976f095SAxel Lin struct mutex io_lock; 245976f095SAxel Lin struct i2c_client *i2c; 255976f095SAxel Lin }; 265976f095SAxel Lin 275976f095SAxel Lin /* LP3972 Control Registers */ 285976f095SAxel Lin #define LP3972_SCR_REG 0x07 295976f095SAxel Lin #define LP3972_OVER1_REG 0x10 305976f095SAxel Lin #define LP3972_OVSR1_REG 0x11 315976f095SAxel Lin #define LP3972_OVER2_REG 0x12 325976f095SAxel Lin #define LP3972_OVSR2_REG 0x13 335976f095SAxel Lin #define LP3972_VCC1_REG 0x20 345976f095SAxel Lin #define LP3972_ADTV1_REG 0x23 355976f095SAxel Lin #define LP3972_ADTV2_REG 0x24 365976f095SAxel Lin #define LP3972_AVRC_REG 0x25 375976f095SAxel Lin #define LP3972_CDTC1_REG 0x26 385976f095SAxel Lin #define LP3972_CDTC2_REG 0x27 395976f095SAxel Lin #define LP3972_SDTV1_REG 0x29 405976f095SAxel Lin #define LP3972_SDTV2_REG 0x2A 415976f095SAxel Lin #define LP3972_MDTV1_REG 0x32 425976f095SAxel Lin #define LP3972_MDTV2_REG 0x33 435976f095SAxel Lin #define LP3972_L2VCR_REG 0x39 445976f095SAxel Lin #define LP3972_L34VCR_REG 0x3A 455976f095SAxel Lin #define LP3972_SCR1_REG 0x80 465976f095SAxel Lin #define LP3972_SCR2_REG 0x81 475976f095SAxel Lin #define LP3972_OEN3_REG 0x82 485976f095SAxel Lin #define LP3972_OSR3_REG 0x83 495976f095SAxel Lin #define LP3972_LOER4_REG 0x84 505976f095SAxel Lin #define LP3972_B2TV_REG 0x85 515976f095SAxel Lin #define LP3972_B3TV_REG 0x86 525976f095SAxel Lin #define LP3972_B32RC_REG 0x87 535976f095SAxel Lin #define LP3972_ISRA_REG 0x88 545976f095SAxel Lin #define LP3972_BCCR_REG 0x89 555976f095SAxel Lin #define LP3972_II1RR_REG 0x8E 565976f095SAxel Lin #define LP3972_II2RR_REG 0x8F 575976f095SAxel Lin 585976f095SAxel Lin #define LP3972_SYS_CONTROL1_REG LP3972_SCR1_REG 595976f095SAxel Lin /* System control register 1 initial value, 605976f095SAxel Lin * bits 5, 6 and 7 are EPROM programmable */ 615976f095SAxel Lin #define SYS_CONTROL1_INIT_VAL 0x02 625976f095SAxel Lin #define SYS_CONTROL1_INIT_MASK 0x1F 635976f095SAxel Lin 645976f095SAxel Lin #define LP3972_VOL_CHANGE_REG LP3972_VCC1_REG 655976f095SAxel Lin #define LP3972_VOL_CHANGE_FLAG_GO 0x01 665976f095SAxel Lin #define LP3972_VOL_CHANGE_FLAG_MASK 0x03 675976f095SAxel Lin 685976f095SAxel Lin /* LDO output enable mask */ 695976f095SAxel Lin #define LP3972_OEN3_L1EN BIT(0) 705976f095SAxel Lin #define LP3972_OVER2_LDO2_EN BIT(2) 715976f095SAxel Lin #define LP3972_OVER2_LDO3_EN BIT(3) 725976f095SAxel Lin #define LP3972_OVER2_LDO4_EN BIT(4) 735976f095SAxel Lin #define LP3972_OVER1_S_EN BIT(2) 745976f095SAxel Lin 754f73ccadSAxel Lin static const unsigned int ldo1_voltage_map[] = { 764f73ccadSAxel Lin 1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000, 774f73ccadSAxel Lin 1900000, 1925000, 1950000, 1975000, 2000000, 785976f095SAxel Lin }; 795976f095SAxel Lin 804f73ccadSAxel Lin static const unsigned int ldo23_voltage_map[] = { 814f73ccadSAxel Lin 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, 824f73ccadSAxel Lin 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, 835976f095SAxel Lin }; 845976f095SAxel Lin 854f73ccadSAxel Lin static const unsigned int ldo4_voltage_map[] = { 864f73ccadSAxel Lin 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000, 874f73ccadSAxel Lin 1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000, 885976f095SAxel Lin }; 895976f095SAxel Lin 904f73ccadSAxel Lin static const unsigned int ldo5_voltage_map[] = { 914f73ccadSAxel Lin 0, 0, 0, 0, 0, 850000, 875000, 900000, 924f73ccadSAxel Lin 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 934f73ccadSAxel Lin 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 944f73ccadSAxel Lin 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, 955976f095SAxel Lin }; 965976f095SAxel Lin 974f73ccadSAxel Lin static const unsigned int buck1_voltage_map[] = { 984f73ccadSAxel Lin 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, 994f73ccadSAxel Lin 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 1004f73ccadSAxel Lin 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1014f73ccadSAxel Lin 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, 1025976f095SAxel Lin }; 1035976f095SAxel Lin 1044f73ccadSAxel Lin static const unsigned int buck23_voltage_map[] = { 1054f73ccadSAxel Lin 0, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1064f73ccadSAxel Lin 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1074f73ccadSAxel Lin 1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000, 1084f73ccadSAxel Lin 3000000, 3300000, 1095976f095SAxel Lin }; 1105976f095SAxel Lin 1115976f095SAxel Lin static const int ldo_output_enable_mask[] = { 1125976f095SAxel Lin LP3972_OEN3_L1EN, 1135976f095SAxel Lin LP3972_OVER2_LDO2_EN, 1145976f095SAxel Lin LP3972_OVER2_LDO3_EN, 1155976f095SAxel Lin LP3972_OVER2_LDO4_EN, 1165976f095SAxel Lin LP3972_OVER1_S_EN, 1175976f095SAxel Lin }; 1185976f095SAxel Lin 1195976f095SAxel Lin static const int ldo_output_enable_addr[] = { 1205976f095SAxel Lin LP3972_OEN3_REG, 1215976f095SAxel Lin LP3972_OVER2_REG, 1225976f095SAxel Lin LP3972_OVER2_REG, 1235976f095SAxel Lin LP3972_OVER2_REG, 1245976f095SAxel Lin LP3972_OVER1_REG, 1255976f095SAxel Lin }; 1265976f095SAxel Lin 1275976f095SAxel Lin static const int ldo_vol_ctl_addr[] = { 1285976f095SAxel Lin LP3972_MDTV1_REG, 1295976f095SAxel Lin LP3972_L2VCR_REG, 1305976f095SAxel Lin LP3972_L34VCR_REG, 1315976f095SAxel Lin LP3972_L34VCR_REG, 1325976f095SAxel Lin LP3972_SDTV1_REG, 1335976f095SAxel Lin }; 1345976f095SAxel Lin 1355976f095SAxel Lin static const int buck_vol_enable_addr[] = { 1365976f095SAxel Lin LP3972_OVER1_REG, 1375976f095SAxel Lin LP3972_OEN3_REG, 1385976f095SAxel Lin LP3972_OEN3_REG, 1395976f095SAxel Lin }; 1405976f095SAxel Lin 1415976f095SAxel Lin static const int buck_base_addr[] = { 1425976f095SAxel Lin LP3972_ADTV1_REG, 1435976f095SAxel Lin LP3972_B2TV_REG, 1445976f095SAxel Lin LP3972_B3TV_REG, 1455976f095SAxel Lin }; 1465976f095SAxel Lin 1475976f095SAxel Lin #define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x]) 1485976f095SAxel Lin #define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x]) 1495976f095SAxel Lin 1505976f095SAxel Lin /* LDO voltage control registers shift: 1515976f095SAxel Lin LP3972_LDO1 -> 0, LP3972_LDO2 -> 4 1525976f095SAxel Lin LP3972_LDO3 -> 0, LP3972_LDO4 -> 4 1535976f095SAxel Lin LP3972_LDO5 -> 0 1545976f095SAxel Lin */ 1555976f095SAxel Lin #define LP3972_LDO_VOL_CONTR_SHIFT(x) (((x) & 1) << 2) 1565976f095SAxel Lin #define LP3972_LDO_VOL_CONTR_REG(x) (ldo_vol_ctl_addr[x]) 1575976f095SAxel Lin #define LP3972_LDO_VOL_CHANGE_SHIFT(x) ((x) ? 4 : 6) 1585976f095SAxel Lin 1595976f095SAxel Lin #define LP3972_LDO_VOL_MASK(x) (((x) % 4) ? 0x0f : 0x1f) 1605976f095SAxel Lin #define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00) 1615976f095SAxel Lin #define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c) 1625976f095SAxel Lin 1635976f095SAxel Lin #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x]) 1645976f095SAxel Lin #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x]) 1655976f095SAxel Lin #define LP3972_BUCK_VOL_MASK 0x1f 1665976f095SAxel Lin 1675976f095SAxel Lin static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count, 1685976f095SAxel Lin u16 *dest) 1695976f095SAxel Lin { 1705976f095SAxel Lin int ret; 1715976f095SAxel Lin 1725976f095SAxel Lin if (count != 1) 1735976f095SAxel Lin return -EIO; 1745976f095SAxel Lin ret = i2c_smbus_read_byte_data(i2c, reg); 1755976f095SAxel Lin if (ret < 0) 176993af7c0SAxel Lin return ret; 1775976f095SAxel Lin 1785976f095SAxel Lin *dest = ret; 1795976f095SAxel Lin return 0; 1805976f095SAxel Lin } 1815976f095SAxel Lin 1825976f095SAxel Lin static int lp3972_i2c_write(struct i2c_client *i2c, char reg, int count, 1835976f095SAxel Lin const u16 *src) 1845976f095SAxel Lin { 1855976f095SAxel Lin if (count != 1) 1865976f095SAxel Lin return -EIO; 1875976f095SAxel Lin return i2c_smbus_write_byte_data(i2c, reg, *src); 1885976f095SAxel Lin } 1895976f095SAxel Lin 1905976f095SAxel Lin static u8 lp3972_reg_read(struct lp3972 *lp3972, u8 reg) 1915976f095SAxel Lin { 1925976f095SAxel Lin u16 val = 0; 1935976f095SAxel Lin 1945976f095SAxel Lin mutex_lock(&lp3972->io_lock); 1955976f095SAxel Lin 1965976f095SAxel Lin lp3972_i2c_read(lp3972->i2c, reg, 1, &val); 1975976f095SAxel Lin 1985976f095SAxel Lin dev_dbg(lp3972->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg, 1995976f095SAxel Lin (unsigned)val & 0xff); 2005976f095SAxel Lin 2015976f095SAxel Lin mutex_unlock(&lp3972->io_lock); 2025976f095SAxel Lin 2035976f095SAxel Lin return val & 0xff; 2045976f095SAxel Lin } 2055976f095SAxel Lin 2065976f095SAxel Lin static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val) 2075976f095SAxel Lin { 2085976f095SAxel Lin u16 tmp; 2095976f095SAxel Lin int ret; 2105976f095SAxel Lin 2115976f095SAxel Lin mutex_lock(&lp3972->io_lock); 2125976f095SAxel Lin 2135976f095SAxel Lin ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp); 2145976f095SAxel Lin if (ret == 0) { 2157cb7348fSDan Carpenter tmp = (tmp & ~mask) | val; 2165976f095SAxel Lin ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp); 2175976f095SAxel Lin dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, 2185976f095SAxel Lin (unsigned)val & 0xff); 2195976f095SAxel Lin } 2205976f095SAxel Lin mutex_unlock(&lp3972->io_lock); 2215976f095SAxel Lin 2225976f095SAxel Lin return ret; 2235976f095SAxel Lin } 2245976f095SAxel Lin 2255976f095SAxel Lin static int lp3972_ldo_is_enabled(struct regulator_dev *dev) 2265976f095SAxel Lin { 2275976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2285976f095SAxel Lin int ldo = rdev_get_id(dev) - LP3972_LDO1; 2295976f095SAxel Lin u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); 2305976f095SAxel Lin u16 val; 2315976f095SAxel Lin 2325976f095SAxel Lin val = lp3972_reg_read(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo)); 2335976f095SAxel Lin return !!(val & mask); 2345976f095SAxel Lin } 2355976f095SAxel Lin 2365976f095SAxel Lin static int lp3972_ldo_enable(struct regulator_dev *dev) 2375976f095SAxel Lin { 2385976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2395976f095SAxel Lin int ldo = rdev_get_id(dev) - LP3972_LDO1; 2405976f095SAxel Lin u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); 2415976f095SAxel Lin 2425976f095SAxel Lin return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo), 2435976f095SAxel Lin mask, mask); 2445976f095SAxel Lin } 2455976f095SAxel Lin 2465976f095SAxel Lin static int lp3972_ldo_disable(struct regulator_dev *dev) 2475976f095SAxel Lin { 2485976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2495976f095SAxel Lin int ldo = rdev_get_id(dev) - LP3972_LDO1; 2505976f095SAxel Lin u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); 2515976f095SAxel Lin 2525976f095SAxel Lin return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo), 2535976f095SAxel Lin mask, 0); 2545976f095SAxel Lin } 2555976f095SAxel Lin 256c8c14a39SAxel Lin static int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev) 2575976f095SAxel Lin { 2585976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2595976f095SAxel Lin int ldo = rdev_get_id(dev) - LP3972_LDO1; 2605976f095SAxel Lin u16 mask = LP3972_LDO_VOL_MASK(ldo); 2615976f095SAxel Lin u16 val, reg; 2625976f095SAxel Lin 2635976f095SAxel Lin reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo)); 2645976f095SAxel Lin val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask; 2655976f095SAxel Lin 266c8c14a39SAxel Lin return val; 2675976f095SAxel Lin } 2685976f095SAxel Lin 26924c896f5SAxel Lin static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, 27024c896f5SAxel Lin unsigned int selector) 2715976f095SAxel Lin { 2725976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2735976f095SAxel Lin int ldo = rdev_get_id(dev) - LP3972_LDO1; 2745976f095SAxel Lin int shift, ret; 2755976f095SAxel Lin 2765976f095SAxel Lin shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo); 2775976f095SAxel Lin ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo), 27824c896f5SAxel Lin LP3972_LDO_VOL_MASK(ldo) << shift, selector << shift); 2795976f095SAxel Lin 2805976f095SAxel Lin if (ret) 2815976f095SAxel Lin return ret; 2825976f095SAxel Lin 283993af7c0SAxel Lin /* 284993af7c0SAxel Lin * LDO1 and LDO5 support voltage control by either target voltage1 285993af7c0SAxel Lin * or target voltage2 register. 286993af7c0SAxel Lin * We use target voltage1 register for LDO1 and LDO5 in this driver. 287993af7c0SAxel Lin * We need to update voltage change control register(0x20) to enable 288993af7c0SAxel Lin * LDO1 and LDO5 to change to their programmed target values. 289993af7c0SAxel Lin */ 2905976f095SAxel Lin switch (ldo) { 2915976f095SAxel Lin case LP3972_LDO1: 2925976f095SAxel Lin case LP3972_LDO5: 2935976f095SAxel Lin shift = LP3972_LDO_VOL_CHANGE_SHIFT(ldo); 2945976f095SAxel Lin ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, 2955976f095SAxel Lin LP3972_VOL_CHANGE_FLAG_MASK << shift, 2965976f095SAxel Lin LP3972_VOL_CHANGE_FLAG_GO << shift); 2975976f095SAxel Lin if (ret) 2985976f095SAxel Lin return ret; 2995976f095SAxel Lin 3005976f095SAxel Lin ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, 3015976f095SAxel Lin LP3972_VOL_CHANGE_FLAG_MASK << shift, 0); 3025976f095SAxel Lin break; 3035976f095SAxel Lin } 3045976f095SAxel Lin 3055976f095SAxel Lin return ret; 3065976f095SAxel Lin } 3075976f095SAxel Lin 3085976f095SAxel Lin static struct regulator_ops lp3972_ldo_ops = { 3094f73ccadSAxel Lin .list_voltage = regulator_list_voltage_table, 310b50003b6SAxel Lin .map_voltage = regulator_map_voltage_ascend, 3115976f095SAxel Lin .is_enabled = lp3972_ldo_is_enabled, 3125976f095SAxel Lin .enable = lp3972_ldo_enable, 3135976f095SAxel Lin .disable = lp3972_ldo_disable, 314c8c14a39SAxel Lin .get_voltage_sel = lp3972_ldo_get_voltage_sel, 31524c896f5SAxel Lin .set_voltage_sel = lp3972_ldo_set_voltage_sel, 3165976f095SAxel Lin }; 3175976f095SAxel Lin 3185976f095SAxel Lin static int lp3972_dcdc_is_enabled(struct regulator_dev *dev) 3195976f095SAxel Lin { 3205976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3215976f095SAxel Lin int buck = rdev_get_id(dev) - LP3972_DCDC1; 3225976f095SAxel Lin u16 mask = 1 << (buck * 2); 3235976f095SAxel Lin u16 val; 3245976f095SAxel Lin 3255976f095SAxel Lin val = lp3972_reg_read(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck)); 3265976f095SAxel Lin return !!(val & mask); 3275976f095SAxel Lin } 3285976f095SAxel Lin 3295976f095SAxel Lin static int lp3972_dcdc_enable(struct regulator_dev *dev) 3305976f095SAxel Lin { 3315976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3325976f095SAxel Lin int buck = rdev_get_id(dev) - LP3972_DCDC1; 3335976f095SAxel Lin u16 mask = 1 << (buck * 2); 3345976f095SAxel Lin u16 val; 3355976f095SAxel Lin 3365976f095SAxel Lin val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck), 3375976f095SAxel Lin mask, mask); 3385976f095SAxel Lin return val; 3395976f095SAxel Lin } 3405976f095SAxel Lin 3415976f095SAxel Lin static int lp3972_dcdc_disable(struct regulator_dev *dev) 3425976f095SAxel Lin { 3435976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3445976f095SAxel Lin int buck = rdev_get_id(dev) - LP3972_DCDC1; 3455976f095SAxel Lin u16 mask = 1 << (buck * 2); 3465976f095SAxel Lin u16 val; 3475976f095SAxel Lin 3485976f095SAxel Lin val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck), 3495976f095SAxel Lin mask, 0); 3505976f095SAxel Lin return val; 3515976f095SAxel Lin } 3525976f095SAxel Lin 353c8c14a39SAxel Lin static int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev) 3545976f095SAxel Lin { 3555976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3565976f095SAxel Lin int buck = rdev_get_id(dev) - LP3972_DCDC1; 3575976f095SAxel Lin u16 reg; 3585976f095SAxel Lin 3595976f095SAxel Lin reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck)); 3605976f095SAxel Lin reg &= LP3972_BUCK_VOL_MASK; 3615976f095SAxel Lin 362c8c14a39SAxel Lin return reg; 3635976f095SAxel Lin } 3645976f095SAxel Lin 36524c896f5SAxel Lin static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev, 36624c896f5SAxel Lin unsigned int selector) 3675976f095SAxel Lin { 3685976f095SAxel Lin struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3695976f095SAxel Lin int buck = rdev_get_id(dev) - LP3972_DCDC1; 3705976f095SAxel Lin int ret; 3715976f095SAxel Lin 3725976f095SAxel Lin ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck), 37324c896f5SAxel Lin LP3972_BUCK_VOL_MASK, selector); 3745976f095SAxel Lin if (ret) 3755976f095SAxel Lin return ret; 3765976f095SAxel Lin 3775976f095SAxel Lin if (buck != 0) 3785976f095SAxel Lin return ret; 3795976f095SAxel Lin 3805976f095SAxel Lin ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, 3815976f095SAxel Lin LP3972_VOL_CHANGE_FLAG_MASK, LP3972_VOL_CHANGE_FLAG_GO); 3825976f095SAxel Lin if (ret) 3835976f095SAxel Lin return ret; 3845976f095SAxel Lin 3855976f095SAxel Lin return lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, 3865976f095SAxel Lin LP3972_VOL_CHANGE_FLAG_MASK, 0); 3875976f095SAxel Lin } 3885976f095SAxel Lin 3895976f095SAxel Lin static struct regulator_ops lp3972_dcdc_ops = { 3904f73ccadSAxel Lin .list_voltage = regulator_list_voltage_table, 391b50003b6SAxel Lin .map_voltage = regulator_map_voltage_ascend, 3925976f095SAxel Lin .is_enabled = lp3972_dcdc_is_enabled, 3935976f095SAxel Lin .enable = lp3972_dcdc_enable, 3945976f095SAxel Lin .disable = lp3972_dcdc_disable, 395c8c14a39SAxel Lin .get_voltage_sel = lp3972_dcdc_get_voltage_sel, 39624c896f5SAxel Lin .set_voltage_sel = lp3972_dcdc_set_voltage_sel, 3975976f095SAxel Lin }; 3985976f095SAxel Lin 3991bdcf110SAxel Lin static const struct regulator_desc regulators[] = { 4005976f095SAxel Lin { 4015976f095SAxel Lin .name = "LDO1", 4025976f095SAxel Lin .id = LP3972_LDO1, 4035976f095SAxel Lin .ops = &lp3972_ldo_ops, 4045976f095SAxel Lin .n_voltages = ARRAY_SIZE(ldo1_voltage_map), 4054f73ccadSAxel Lin .volt_table = ldo1_voltage_map, 4065976f095SAxel Lin .type = REGULATOR_VOLTAGE, 4075976f095SAxel Lin .owner = THIS_MODULE, 4085976f095SAxel Lin }, 4095976f095SAxel Lin { 4105976f095SAxel Lin .name = "LDO2", 4115976f095SAxel Lin .id = LP3972_LDO2, 4125976f095SAxel Lin .ops = &lp3972_ldo_ops, 4135976f095SAxel Lin .n_voltages = ARRAY_SIZE(ldo23_voltage_map), 4144f73ccadSAxel Lin .volt_table = ldo23_voltage_map, 4155976f095SAxel Lin .type = REGULATOR_VOLTAGE, 4165976f095SAxel Lin .owner = THIS_MODULE, 4175976f095SAxel Lin }, 4185976f095SAxel Lin { 4195976f095SAxel Lin .name = "LDO3", 4205976f095SAxel Lin .id = LP3972_LDO3, 4215976f095SAxel Lin .ops = &lp3972_ldo_ops, 4225976f095SAxel Lin .n_voltages = ARRAY_SIZE(ldo23_voltage_map), 4234f73ccadSAxel Lin .volt_table = ldo23_voltage_map, 4245976f095SAxel Lin .type = REGULATOR_VOLTAGE, 4255976f095SAxel Lin .owner = THIS_MODULE, 4265976f095SAxel Lin }, 4275976f095SAxel Lin { 4285976f095SAxel Lin .name = "LDO4", 4295976f095SAxel Lin .id = LP3972_LDO4, 4305976f095SAxel Lin .ops = &lp3972_ldo_ops, 4315976f095SAxel Lin .n_voltages = ARRAY_SIZE(ldo4_voltage_map), 4324f73ccadSAxel Lin .volt_table = ldo4_voltage_map, 4335976f095SAxel Lin .type = REGULATOR_VOLTAGE, 4345976f095SAxel Lin .owner = THIS_MODULE, 4355976f095SAxel Lin }, 4365976f095SAxel Lin { 4375976f095SAxel Lin .name = "LDO5", 4385976f095SAxel Lin .id = LP3972_LDO5, 4395976f095SAxel Lin .ops = &lp3972_ldo_ops, 4405976f095SAxel Lin .n_voltages = ARRAY_SIZE(ldo5_voltage_map), 4414f73ccadSAxel Lin .volt_table = ldo5_voltage_map, 4425976f095SAxel Lin .type = REGULATOR_VOLTAGE, 4435976f095SAxel Lin .owner = THIS_MODULE, 4445976f095SAxel Lin }, 4455976f095SAxel Lin { 4465976f095SAxel Lin .name = "DCDC1", 4475976f095SAxel Lin .id = LP3972_DCDC1, 4485976f095SAxel Lin .ops = &lp3972_dcdc_ops, 4495976f095SAxel Lin .n_voltages = ARRAY_SIZE(buck1_voltage_map), 4504f73ccadSAxel Lin .volt_table = buck1_voltage_map, 4515976f095SAxel Lin .type = REGULATOR_VOLTAGE, 4525976f095SAxel Lin .owner = THIS_MODULE, 4535976f095SAxel Lin }, 4545976f095SAxel Lin { 4555976f095SAxel Lin .name = "DCDC2", 4565976f095SAxel Lin .id = LP3972_DCDC2, 4575976f095SAxel Lin .ops = &lp3972_dcdc_ops, 4585976f095SAxel Lin .n_voltages = ARRAY_SIZE(buck23_voltage_map), 4594f73ccadSAxel Lin .volt_table = buck23_voltage_map, 4605976f095SAxel Lin .type = REGULATOR_VOLTAGE, 4615976f095SAxel Lin .owner = THIS_MODULE, 4625976f095SAxel Lin }, 4635976f095SAxel Lin { 4645976f095SAxel Lin .name = "DCDC3", 4655976f095SAxel Lin .id = LP3972_DCDC3, 4665976f095SAxel Lin .ops = &lp3972_dcdc_ops, 4675976f095SAxel Lin .n_voltages = ARRAY_SIZE(buck23_voltage_map), 4684f73ccadSAxel Lin .volt_table = buck23_voltage_map, 4695976f095SAxel Lin .type = REGULATOR_VOLTAGE, 4705976f095SAxel Lin .owner = THIS_MODULE, 4715976f095SAxel Lin }, 4725976f095SAxel Lin }; 4735976f095SAxel Lin 474a5023574SBill Pemberton static int setup_regulators(struct lp3972 *lp3972, 4755976f095SAxel Lin struct lp3972_platform_data *pdata) 4765976f095SAxel Lin { 4775976f095SAxel Lin int i, err; 4785976f095SAxel Lin 4795976f095SAxel Lin /* Instantiate the regulators */ 4805976f095SAxel Lin for (i = 0; i < pdata->num_regulators; i++) { 4815976f095SAxel Lin struct lp3972_regulator_subdev *reg = &pdata->regulators[i]; 482c172708dSMark Brown struct regulator_config config = { }; 48393227c80SAxel Lin struct regulator_dev *rdev; 4845976f095SAxel Lin 485c172708dSMark Brown config.dev = lp3972->dev; 486c172708dSMark Brown config.init_data = reg->initdata; 487c172708dSMark Brown config.driver_data = lp3972; 488c172708dSMark Brown 48993227c80SAxel Lin rdev = devm_regulator_register(lp3972->dev, 49093227c80SAxel Lin ®ulators[reg->id], &config); 49193227c80SAxel Lin if (IS_ERR(rdev)) { 49293227c80SAxel Lin err = PTR_ERR(rdev); 4935976f095SAxel Lin dev_err(lp3972->dev, "regulator init failed: %d\n", 4945976f095SAxel Lin err); 49593227c80SAxel Lin return err; 4965976f095SAxel Lin } 4975976f095SAxel Lin } 4985976f095SAxel Lin 4995976f095SAxel Lin return 0; 5005976f095SAxel Lin } 5015976f095SAxel Lin 502a5023574SBill Pemberton static int lp3972_i2c_probe(struct i2c_client *i2c, 5035976f095SAxel Lin const struct i2c_device_id *id) 5045976f095SAxel Lin { 5055976f095SAxel Lin struct lp3972 *lp3972; 506dff91d0bSJingoo Han struct lp3972_platform_data *pdata = dev_get_platdata(&i2c->dev); 5075976f095SAxel Lin int ret; 5085976f095SAxel Lin u16 val; 5095976f095SAxel Lin 5105976f095SAxel Lin if (!pdata) { 5115976f095SAxel Lin dev_dbg(&i2c->dev, "No platform init data supplied\n"); 5125976f095SAxel Lin return -ENODEV; 5135976f095SAxel Lin } 5145976f095SAxel Lin 5152af0af67SNikolay Balandin lp3972 = devm_kzalloc(&i2c->dev, sizeof(struct lp3972), GFP_KERNEL); 5165976f095SAxel Lin if (!lp3972) 5175976f095SAxel Lin return -ENOMEM; 5185976f095SAxel Lin 5195976f095SAxel Lin lp3972->i2c = i2c; 5205976f095SAxel Lin lp3972->dev = &i2c->dev; 5215976f095SAxel Lin 5225976f095SAxel Lin mutex_init(&lp3972->io_lock); 5235976f095SAxel Lin 5245976f095SAxel Lin /* Detect LP3972 */ 5255976f095SAxel Lin ret = lp3972_i2c_read(i2c, LP3972_SYS_CONTROL1_REG, 1, &val); 526993af7c0SAxel Lin if (ret == 0 && 527993af7c0SAxel Lin (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) { 5285976f095SAxel Lin ret = -ENODEV; 529993af7c0SAxel Lin dev_err(&i2c->dev, "chip reported: val = 0x%x\n", val); 530993af7c0SAxel Lin } 5315976f095SAxel Lin if (ret < 0) { 532993af7c0SAxel Lin dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret); 5332af0af67SNikolay Balandin return ret; 5345976f095SAxel Lin } 5355976f095SAxel Lin 5365976f095SAxel Lin ret = setup_regulators(lp3972, pdata); 5375976f095SAxel Lin if (ret < 0) 5382af0af67SNikolay Balandin return ret; 5395976f095SAxel Lin 5405976f095SAxel Lin i2c_set_clientdata(i2c, lp3972); 5415976f095SAxel Lin return 0; 5425976f095SAxel Lin } 5435976f095SAxel Lin 5445976f095SAxel Lin static const struct i2c_device_id lp3972_i2c_id[] = { 5455976f095SAxel Lin { "lp3972", 0 }, 5465976f095SAxel Lin { } 5475976f095SAxel Lin }; 5485976f095SAxel Lin MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id); 5495976f095SAxel Lin 5505976f095SAxel Lin static struct i2c_driver lp3972_i2c_driver = { 5515976f095SAxel Lin .driver = { 5525976f095SAxel Lin .name = "lp3972", 5535976f095SAxel Lin }, 5545976f095SAxel Lin .probe = lp3972_i2c_probe, 5555976f095SAxel Lin .id_table = lp3972_i2c_id, 5565976f095SAxel Lin }; 5575976f095SAxel Lin 5585976f095SAxel Lin static int __init lp3972_module_init(void) 5595976f095SAxel Lin { 5605976f095SAxel Lin return i2c_add_driver(&lp3972_i2c_driver); 5615976f095SAxel Lin } 5625976f095SAxel Lin subsys_initcall(lp3972_module_init); 5635976f095SAxel Lin 5645976f095SAxel Lin static void __exit lp3972_module_exit(void) 5655976f095SAxel Lin { 5665976f095SAxel Lin i2c_del_driver(&lp3972_i2c_driver); 5675976f095SAxel Lin } 5685976f095SAxel Lin module_exit(lp3972_module_exit); 5695976f095SAxel Lin 5705976f095SAxel Lin MODULE_LICENSE("GPL"); 5715976f095SAxel Lin MODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>"); 5725976f095SAxel Lin MODULE_DESCRIPTION("LP3972 PMIC driver"); 573