xref: /openbmc/linux/drivers/regulator/lp3972.c (revision 7cb7348f)
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 					       &regulators[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