xref: /openbmc/linux/drivers/regulator/lp3972.c (revision 964e1865)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25976f095SAxel Lin /*
35976f095SAxel Lin  * Regulator driver for National Semiconductors LP3972 PMIC chip
45976f095SAxel Lin  *
55976f095SAxel Lin  * Based on lp3971.c
65976f095SAxel Lin  */
75976f095SAxel Lin 
85976f095SAxel Lin #include <linux/bug.h>
95976f095SAxel Lin #include <linux/err.h>
105976f095SAxel Lin #include <linux/i2c.h>
1165602c32SPaul Gortmaker #include <linux/module.h>
125976f095SAxel Lin #include <linux/kernel.h>
135976f095SAxel Lin #include <linux/regulator/driver.h>
145976f095SAxel Lin #include <linux/regulator/lp3972.h>
155976f095SAxel Lin #include <linux/slab.h>
165976f095SAxel Lin 
175976f095SAxel Lin struct lp3972 {
185976f095SAxel Lin 	struct device *dev;
195976f095SAxel Lin 	struct mutex io_lock;
205976f095SAxel Lin 	struct i2c_client *i2c;
215976f095SAxel Lin };
225976f095SAxel Lin 
235976f095SAxel Lin /* LP3972 Control Registers */
245976f095SAxel Lin #define LP3972_SCR_REG		0x07
255976f095SAxel Lin #define LP3972_OVER1_REG	0x10
265976f095SAxel Lin #define LP3972_OVSR1_REG	0x11
275976f095SAxel Lin #define LP3972_OVER2_REG	0x12
285976f095SAxel Lin #define LP3972_OVSR2_REG	0x13
295976f095SAxel Lin #define LP3972_VCC1_REG		0x20
305976f095SAxel Lin #define LP3972_ADTV1_REG	0x23
315976f095SAxel Lin #define LP3972_ADTV2_REG	0x24
325976f095SAxel Lin #define LP3972_AVRC_REG		0x25
335976f095SAxel Lin #define LP3972_CDTC1_REG	0x26
345976f095SAxel Lin #define LP3972_CDTC2_REG	0x27
355976f095SAxel Lin #define LP3972_SDTV1_REG	0x29
365976f095SAxel Lin #define LP3972_SDTV2_REG	0x2A
375976f095SAxel Lin #define LP3972_MDTV1_REG	0x32
385976f095SAxel Lin #define LP3972_MDTV2_REG	0x33
395976f095SAxel Lin #define LP3972_L2VCR_REG	0x39
405976f095SAxel Lin #define LP3972_L34VCR_REG	0x3A
415976f095SAxel Lin #define LP3972_SCR1_REG		0x80
425976f095SAxel Lin #define LP3972_SCR2_REG		0x81
435976f095SAxel Lin #define LP3972_OEN3_REG		0x82
445976f095SAxel Lin #define LP3972_OSR3_REG		0x83
455976f095SAxel Lin #define LP3972_LOER4_REG	0x84
465976f095SAxel Lin #define LP3972_B2TV_REG		0x85
475976f095SAxel Lin #define LP3972_B3TV_REG		0x86
485976f095SAxel Lin #define LP3972_B32RC_REG	0x87
495976f095SAxel Lin #define LP3972_ISRA_REG		0x88
505976f095SAxel Lin #define LP3972_BCCR_REG		0x89
515976f095SAxel Lin #define LP3972_II1RR_REG	0x8E
525976f095SAxel Lin #define LP3972_II2RR_REG	0x8F
535976f095SAxel Lin 
545976f095SAxel Lin #define LP3972_SYS_CONTROL1_REG		LP3972_SCR1_REG
555976f095SAxel Lin /* System control register 1 initial value,
565976f095SAxel Lin  * bits 5, 6 and 7 are EPROM programmable */
575976f095SAxel Lin #define SYS_CONTROL1_INIT_VAL		0x02
585976f095SAxel Lin #define SYS_CONTROL1_INIT_MASK		0x1F
595976f095SAxel Lin 
605976f095SAxel Lin #define LP3972_VOL_CHANGE_REG		LP3972_VCC1_REG
615976f095SAxel Lin #define LP3972_VOL_CHANGE_FLAG_GO	0x01
625976f095SAxel Lin #define LP3972_VOL_CHANGE_FLAG_MASK	0x03
635976f095SAxel Lin 
645976f095SAxel Lin /* LDO output enable mask */
655976f095SAxel Lin #define LP3972_OEN3_L1EN	BIT(0)
665976f095SAxel Lin #define LP3972_OVER2_LDO2_EN	BIT(2)
675976f095SAxel Lin #define LP3972_OVER2_LDO3_EN	BIT(3)
685976f095SAxel Lin #define LP3972_OVER2_LDO4_EN	BIT(4)
695976f095SAxel Lin #define LP3972_OVER1_S_EN	BIT(2)
705976f095SAxel Lin 
714f73ccadSAxel Lin static const unsigned int ldo1_voltage_map[] = {
724f73ccadSAxel Lin 	1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000,
734f73ccadSAxel Lin 	1900000, 1925000, 1950000, 1975000, 2000000,
745976f095SAxel Lin };
755976f095SAxel Lin 
764f73ccadSAxel Lin static const unsigned int ldo23_voltage_map[] = {
774f73ccadSAxel Lin 	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
784f73ccadSAxel Lin 	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
795976f095SAxel Lin };
805976f095SAxel Lin 
814f73ccadSAxel Lin static const unsigned int ldo4_voltage_map[] = {
824f73ccadSAxel Lin 	1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
834f73ccadSAxel Lin 	1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
845976f095SAxel Lin };
855976f095SAxel Lin 
864f73ccadSAxel Lin static const unsigned int ldo5_voltage_map[] = {
874f73ccadSAxel Lin 	      0,       0,       0,       0,       0,  850000,  875000,  900000,
884f73ccadSAxel Lin 	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
894f73ccadSAxel Lin 	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
904f73ccadSAxel Lin 	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
915976f095SAxel Lin };
925976f095SAxel Lin 
934f73ccadSAxel Lin static const unsigned int buck1_voltage_map[] = {
944f73ccadSAxel Lin 	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
954f73ccadSAxel Lin 	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
964f73ccadSAxel Lin 	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
974f73ccadSAxel Lin 	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
985976f095SAxel Lin };
995976f095SAxel Lin 
1004f73ccadSAxel Lin static const unsigned int buck23_voltage_map[] = {
1014f73ccadSAxel Lin 	      0,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
1024f73ccadSAxel Lin 	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
1034f73ccadSAxel Lin 	1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
1044f73ccadSAxel Lin 	3000000, 3300000,
1055976f095SAxel Lin };
1065976f095SAxel Lin 
1075976f095SAxel Lin static const int ldo_output_enable_mask[] = {
1085976f095SAxel Lin 	LP3972_OEN3_L1EN,
1095976f095SAxel Lin 	LP3972_OVER2_LDO2_EN,
1105976f095SAxel Lin 	LP3972_OVER2_LDO3_EN,
1115976f095SAxel Lin 	LP3972_OVER2_LDO4_EN,
1125976f095SAxel Lin 	LP3972_OVER1_S_EN,
1135976f095SAxel Lin };
1145976f095SAxel Lin 
1155976f095SAxel Lin static const int ldo_output_enable_addr[] = {
1165976f095SAxel Lin 	LP3972_OEN3_REG,
1175976f095SAxel Lin 	LP3972_OVER2_REG,
1185976f095SAxel Lin 	LP3972_OVER2_REG,
1195976f095SAxel Lin 	LP3972_OVER2_REG,
1205976f095SAxel Lin 	LP3972_OVER1_REG,
1215976f095SAxel Lin };
1225976f095SAxel Lin 
1235976f095SAxel Lin static const int ldo_vol_ctl_addr[] = {
1245976f095SAxel Lin 	LP3972_MDTV1_REG,
1255976f095SAxel Lin 	LP3972_L2VCR_REG,
1265976f095SAxel Lin 	LP3972_L34VCR_REG,
1275976f095SAxel Lin 	LP3972_L34VCR_REG,
1285976f095SAxel Lin 	LP3972_SDTV1_REG,
1295976f095SAxel Lin };
1305976f095SAxel Lin 
1315976f095SAxel Lin static const int buck_vol_enable_addr[] = {
1325976f095SAxel Lin 	LP3972_OVER1_REG,
1335976f095SAxel Lin 	LP3972_OEN3_REG,
1345976f095SAxel Lin 	LP3972_OEN3_REG,
1355976f095SAxel Lin };
1365976f095SAxel Lin 
1375976f095SAxel Lin static const int buck_base_addr[] = {
1385976f095SAxel Lin 	LP3972_ADTV1_REG,
1395976f095SAxel Lin 	LP3972_B2TV_REG,
1405976f095SAxel Lin 	LP3972_B3TV_REG,
1415976f095SAxel Lin };
1425976f095SAxel Lin 
1435976f095SAxel Lin #define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
1445976f095SAxel Lin #define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x])
1455976f095SAxel Lin 
1465976f095SAxel Lin /*	LDO voltage control registers shift:
1475976f095SAxel Lin 	LP3972_LDO1 -> 0, LP3972_LDO2 -> 4
1485976f095SAxel Lin 	LP3972_LDO3 -> 0, LP3972_LDO4 -> 4
1495976f095SAxel Lin 	LP3972_LDO5 -> 0
1505976f095SAxel Lin */
1515976f095SAxel Lin #define LP3972_LDO_VOL_CONTR_SHIFT(x) (((x) & 1) << 2)
1525976f095SAxel Lin #define LP3972_LDO_VOL_CONTR_REG(x) (ldo_vol_ctl_addr[x])
1535976f095SAxel Lin #define LP3972_LDO_VOL_CHANGE_SHIFT(x) ((x) ? 4 : 6)
1545976f095SAxel Lin 
1555976f095SAxel Lin #define LP3972_LDO_VOL_MASK(x) (((x) % 4) ? 0x0f : 0x1f)
1565976f095SAxel Lin #define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00)
1575976f095SAxel Lin #define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c)
1585976f095SAxel Lin 
1595976f095SAxel Lin #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
1605976f095SAxel Lin #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
1615976f095SAxel Lin #define LP3972_BUCK_VOL_MASK 0x1f
1625976f095SAxel Lin 
lp3972_i2c_read(struct i2c_client * i2c,char reg,int count,u16 * dest)1635976f095SAxel Lin static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count,
1645976f095SAxel Lin 	u16 *dest)
1655976f095SAxel Lin {
1665976f095SAxel Lin 	int ret;
1675976f095SAxel Lin 
1685976f095SAxel Lin 	if (count != 1)
1695976f095SAxel Lin 		return -EIO;
1705976f095SAxel Lin 	ret = i2c_smbus_read_byte_data(i2c, reg);
1715976f095SAxel Lin 	if (ret < 0)
172993af7c0SAxel Lin 		return ret;
1735976f095SAxel Lin 
1745976f095SAxel Lin 	*dest = ret;
1755976f095SAxel Lin 	return 0;
1765976f095SAxel Lin }
1775976f095SAxel Lin 
lp3972_i2c_write(struct i2c_client * i2c,char reg,int count,const u16 * src)1785976f095SAxel Lin static int lp3972_i2c_write(struct i2c_client *i2c, char reg, int count,
1795976f095SAxel Lin 	const u16 *src)
1805976f095SAxel Lin {
1815976f095SAxel Lin 	if (count != 1)
1825976f095SAxel Lin 		return -EIO;
1835976f095SAxel Lin 	return i2c_smbus_write_byte_data(i2c, reg, *src);
1845976f095SAxel Lin }
1855976f095SAxel Lin 
lp3972_reg_read(struct lp3972 * lp3972,u8 reg)1865976f095SAxel Lin static u8 lp3972_reg_read(struct lp3972 *lp3972, u8 reg)
1875976f095SAxel Lin {
1885976f095SAxel Lin 	u16 val = 0;
1895976f095SAxel Lin 
1905976f095SAxel Lin 	mutex_lock(&lp3972->io_lock);
1915976f095SAxel Lin 
1925976f095SAxel Lin 	lp3972_i2c_read(lp3972->i2c, reg, 1, &val);
1935976f095SAxel Lin 
1945976f095SAxel Lin 	dev_dbg(lp3972->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
1955976f095SAxel Lin 		(unsigned)val & 0xff);
1965976f095SAxel Lin 
1975976f095SAxel Lin 	mutex_unlock(&lp3972->io_lock);
1985976f095SAxel Lin 
1995976f095SAxel Lin 	return val & 0xff;
2005976f095SAxel Lin }
2015976f095SAxel Lin 
lp3972_set_bits(struct lp3972 * lp3972,u8 reg,u16 mask,u16 val)2025976f095SAxel Lin static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val)
2035976f095SAxel Lin {
2045976f095SAxel Lin 	u16 tmp;
2055976f095SAxel Lin 	int ret;
2065976f095SAxel Lin 
2075976f095SAxel Lin 	mutex_lock(&lp3972->io_lock);
2085976f095SAxel Lin 
2095976f095SAxel Lin 	ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp);
2105976f095SAxel Lin 	if (ret == 0) {
2117cb7348fSDan Carpenter 		tmp = (tmp & ~mask) | val;
2125976f095SAxel Lin 		ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp);
2135976f095SAxel Lin 		dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
2145976f095SAxel Lin 			(unsigned)val & 0xff);
2155976f095SAxel Lin 	}
2165976f095SAxel Lin 	mutex_unlock(&lp3972->io_lock);
2175976f095SAxel Lin 
2185976f095SAxel Lin 	return ret;
2195976f095SAxel Lin }
2205976f095SAxel Lin 
lp3972_ldo_is_enabled(struct regulator_dev * dev)2215976f095SAxel Lin static int lp3972_ldo_is_enabled(struct regulator_dev *dev)
2225976f095SAxel Lin {
2235976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2245976f095SAxel Lin 	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2255976f095SAxel Lin 	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
2265976f095SAxel Lin 	u16 val;
2275976f095SAxel Lin 
2285976f095SAxel Lin 	val = lp3972_reg_read(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo));
2295976f095SAxel Lin 	return !!(val & mask);
2305976f095SAxel Lin }
2315976f095SAxel Lin 
lp3972_ldo_enable(struct regulator_dev * dev)2325976f095SAxel Lin static int lp3972_ldo_enable(struct regulator_dev *dev)
2335976f095SAxel Lin {
2345976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2355976f095SAxel Lin 	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2365976f095SAxel Lin 	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
2375976f095SAxel Lin 
2385976f095SAxel Lin 	return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo),
2395976f095SAxel Lin 				mask, mask);
2405976f095SAxel Lin }
2415976f095SAxel Lin 
lp3972_ldo_disable(struct regulator_dev * dev)2425976f095SAxel Lin static int lp3972_ldo_disable(struct regulator_dev *dev)
2435976f095SAxel Lin {
2445976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2455976f095SAxel Lin 	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2465976f095SAxel Lin 	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
2475976f095SAxel Lin 
2485976f095SAxel Lin 	return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo),
2495976f095SAxel Lin 				mask, 0);
2505976f095SAxel Lin }
2515976f095SAxel Lin 
lp3972_ldo_get_voltage_sel(struct regulator_dev * dev)252c8c14a39SAxel Lin static int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev)
2535976f095SAxel Lin {
2545976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2555976f095SAxel Lin 	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2565976f095SAxel Lin 	u16 mask = LP3972_LDO_VOL_MASK(ldo);
2575976f095SAxel Lin 	u16 val, reg;
2585976f095SAxel Lin 
2595976f095SAxel Lin 	reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
2605976f095SAxel Lin 	val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
2615976f095SAxel Lin 
262c8c14a39SAxel Lin 	return val;
2635976f095SAxel Lin }
2645976f095SAxel Lin 
lp3972_ldo_set_voltage_sel(struct regulator_dev * dev,unsigned int selector)26524c896f5SAxel Lin static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
26624c896f5SAxel Lin 				      unsigned int selector)
2675976f095SAxel Lin {
2685976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2695976f095SAxel Lin 	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2705976f095SAxel Lin 	int shift, ret;
2715976f095SAxel Lin 
2725976f095SAxel Lin 	shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo);
2735976f095SAxel Lin 	ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo),
27424c896f5SAxel Lin 		LP3972_LDO_VOL_MASK(ldo) << shift, selector << shift);
2755976f095SAxel Lin 
2765976f095SAxel Lin 	if (ret)
2775976f095SAxel Lin 		return ret;
2785976f095SAxel Lin 
279993af7c0SAxel Lin 	/*
280993af7c0SAxel Lin 	 * LDO1 and LDO5 support voltage control by either target voltage1
281993af7c0SAxel Lin 	 * or target voltage2 register.
282993af7c0SAxel Lin 	 * We use target voltage1 register for LDO1 and LDO5 in this driver.
283993af7c0SAxel Lin 	 * We need to update voltage change control register(0x20) to enable
284993af7c0SAxel Lin 	 * LDO1 and LDO5 to change to their programmed target values.
285993af7c0SAxel Lin 	 */
2865976f095SAxel Lin 	switch (ldo) {
2875976f095SAxel Lin 	case LP3972_LDO1:
2885976f095SAxel Lin 	case LP3972_LDO5:
2895976f095SAxel Lin 		shift = LP3972_LDO_VOL_CHANGE_SHIFT(ldo);
2905976f095SAxel Lin 		ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
2915976f095SAxel Lin 			LP3972_VOL_CHANGE_FLAG_MASK << shift,
2925976f095SAxel Lin 			LP3972_VOL_CHANGE_FLAG_GO << shift);
2935976f095SAxel Lin 		if (ret)
2945976f095SAxel Lin 			return ret;
2955976f095SAxel Lin 
2965976f095SAxel Lin 		ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
2975976f095SAxel Lin 			LP3972_VOL_CHANGE_FLAG_MASK << shift, 0);
2985976f095SAxel Lin 		break;
2995976f095SAxel Lin 	}
3005976f095SAxel Lin 
3015976f095SAxel Lin 	return ret;
3025976f095SAxel Lin }
3035976f095SAxel Lin 
304f75b4c5dSAxel Lin static const struct regulator_ops lp3972_ldo_ops = {
3054f73ccadSAxel Lin 	.list_voltage = regulator_list_voltage_table,
306b50003b6SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
3075976f095SAxel Lin 	.is_enabled = lp3972_ldo_is_enabled,
3085976f095SAxel Lin 	.enable = lp3972_ldo_enable,
3095976f095SAxel Lin 	.disable = lp3972_ldo_disable,
310c8c14a39SAxel Lin 	.get_voltage_sel = lp3972_ldo_get_voltage_sel,
31124c896f5SAxel Lin 	.set_voltage_sel = lp3972_ldo_set_voltage_sel,
3125976f095SAxel Lin };
3135976f095SAxel Lin 
lp3972_dcdc_is_enabled(struct regulator_dev * dev)3145976f095SAxel Lin static int lp3972_dcdc_is_enabled(struct regulator_dev *dev)
3155976f095SAxel Lin {
3165976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3175976f095SAxel Lin 	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3185976f095SAxel Lin 	u16 mask = 1 << (buck * 2);
3195976f095SAxel Lin 	u16 val;
3205976f095SAxel Lin 
3215976f095SAxel Lin 	val = lp3972_reg_read(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck));
3225976f095SAxel Lin 	return !!(val & mask);
3235976f095SAxel Lin }
3245976f095SAxel Lin 
lp3972_dcdc_enable(struct regulator_dev * dev)3255976f095SAxel Lin static int lp3972_dcdc_enable(struct regulator_dev *dev)
3265976f095SAxel Lin {
3275976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3285976f095SAxel Lin 	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3295976f095SAxel Lin 	u16 mask = 1 << (buck * 2);
3305976f095SAxel Lin 	u16 val;
3315976f095SAxel Lin 
3325976f095SAxel Lin 	val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck),
3335976f095SAxel Lin 				mask, mask);
3345976f095SAxel Lin 	return val;
3355976f095SAxel Lin }
3365976f095SAxel Lin 
lp3972_dcdc_disable(struct regulator_dev * dev)3375976f095SAxel Lin static int lp3972_dcdc_disable(struct regulator_dev *dev)
3385976f095SAxel Lin {
3395976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3405976f095SAxel Lin 	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3415976f095SAxel Lin 	u16 mask = 1 << (buck * 2);
3425976f095SAxel Lin 	u16 val;
3435976f095SAxel Lin 
3445976f095SAxel Lin 	val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck),
3455976f095SAxel Lin 				mask, 0);
3465976f095SAxel Lin 	return val;
3475976f095SAxel Lin }
3485976f095SAxel Lin 
lp3972_dcdc_get_voltage_sel(struct regulator_dev * dev)349c8c14a39SAxel Lin static int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev)
3505976f095SAxel Lin {
3515976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3525976f095SAxel Lin 	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3535976f095SAxel Lin 	u16 reg;
3545976f095SAxel Lin 
3555976f095SAxel Lin 	reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
3565976f095SAxel Lin 	reg &= LP3972_BUCK_VOL_MASK;
3575976f095SAxel Lin 
358c8c14a39SAxel Lin 	return reg;
3595976f095SAxel Lin }
3605976f095SAxel Lin 
lp3972_dcdc_set_voltage_sel(struct regulator_dev * dev,unsigned int selector)36124c896f5SAxel Lin static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
36224c896f5SAxel Lin 				       unsigned int selector)
3635976f095SAxel Lin {
3645976f095SAxel Lin 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3655976f095SAxel Lin 	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3665976f095SAxel Lin 	int ret;
3675976f095SAxel Lin 
3685976f095SAxel Lin 	ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck),
36924c896f5SAxel Lin 				LP3972_BUCK_VOL_MASK, selector);
3705976f095SAxel Lin 	if (ret)
3715976f095SAxel Lin 		return ret;
3725976f095SAxel Lin 
3735976f095SAxel Lin 	if (buck != 0)
3745976f095SAxel Lin 		return ret;
3755976f095SAxel Lin 
3765976f095SAxel Lin 	ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
3775976f095SAxel Lin 		LP3972_VOL_CHANGE_FLAG_MASK, LP3972_VOL_CHANGE_FLAG_GO);
3785976f095SAxel Lin 	if (ret)
3795976f095SAxel Lin 		return ret;
3805976f095SAxel Lin 
3815976f095SAxel Lin 	return lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
3825976f095SAxel Lin 				LP3972_VOL_CHANGE_FLAG_MASK, 0);
3835976f095SAxel Lin }
3845976f095SAxel Lin 
385f75b4c5dSAxel Lin static const struct regulator_ops lp3972_dcdc_ops = {
3864f73ccadSAxel Lin 	.list_voltage = regulator_list_voltage_table,
387b50003b6SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
3885976f095SAxel Lin 	.is_enabled = lp3972_dcdc_is_enabled,
3895976f095SAxel Lin 	.enable = lp3972_dcdc_enable,
3905976f095SAxel Lin 	.disable = lp3972_dcdc_disable,
391c8c14a39SAxel Lin 	.get_voltage_sel = lp3972_dcdc_get_voltage_sel,
39224c896f5SAxel Lin 	.set_voltage_sel = lp3972_dcdc_set_voltage_sel,
3935976f095SAxel Lin };
3945976f095SAxel Lin 
3951bdcf110SAxel Lin static const struct regulator_desc regulators[] = {
3965976f095SAxel Lin 	{
3975976f095SAxel Lin 		.name = "LDO1",
3985976f095SAxel Lin 		.id = LP3972_LDO1,
3995976f095SAxel Lin 		.ops = &lp3972_ldo_ops,
4005976f095SAxel Lin 		.n_voltages = ARRAY_SIZE(ldo1_voltage_map),
4014f73ccadSAxel Lin 		.volt_table = ldo1_voltage_map,
4025976f095SAxel Lin 		.type = REGULATOR_VOLTAGE,
4035976f095SAxel Lin 		.owner = THIS_MODULE,
4045976f095SAxel Lin 	},
4055976f095SAxel Lin 	{
4065976f095SAxel Lin 		.name = "LDO2",
4075976f095SAxel Lin 		.id = LP3972_LDO2,
4085976f095SAxel Lin 		.ops = &lp3972_ldo_ops,
4095976f095SAxel Lin 		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
4104f73ccadSAxel Lin 		.volt_table = ldo23_voltage_map,
4115976f095SAxel Lin 		.type = REGULATOR_VOLTAGE,
4125976f095SAxel Lin 		.owner = THIS_MODULE,
4135976f095SAxel Lin 	},
4145976f095SAxel Lin 	{
4155976f095SAxel Lin 		.name = "LDO3",
4165976f095SAxel Lin 		.id = LP3972_LDO3,
4175976f095SAxel Lin 		.ops = &lp3972_ldo_ops,
4185976f095SAxel Lin 		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
4194f73ccadSAxel Lin 		.volt_table = ldo23_voltage_map,
4205976f095SAxel Lin 		.type = REGULATOR_VOLTAGE,
4215976f095SAxel Lin 		.owner = THIS_MODULE,
4225976f095SAxel Lin 	},
4235976f095SAxel Lin 	{
4245976f095SAxel Lin 		.name = "LDO4",
4255976f095SAxel Lin 		.id = LP3972_LDO4,
4265976f095SAxel Lin 		.ops = &lp3972_ldo_ops,
4275976f095SAxel Lin 		.n_voltages = ARRAY_SIZE(ldo4_voltage_map),
4284f73ccadSAxel Lin 		.volt_table = ldo4_voltage_map,
4295976f095SAxel Lin 		.type = REGULATOR_VOLTAGE,
4305976f095SAxel Lin 		.owner = THIS_MODULE,
4315976f095SAxel Lin 	},
4325976f095SAxel Lin 	{
4335976f095SAxel Lin 		.name = "LDO5",
4345976f095SAxel Lin 		.id = LP3972_LDO5,
4355976f095SAxel Lin 		.ops = &lp3972_ldo_ops,
4365976f095SAxel Lin 		.n_voltages = ARRAY_SIZE(ldo5_voltage_map),
4374f73ccadSAxel Lin 		.volt_table = ldo5_voltage_map,
4385976f095SAxel Lin 		.type = REGULATOR_VOLTAGE,
4395976f095SAxel Lin 		.owner = THIS_MODULE,
4405976f095SAxel Lin 	},
4415976f095SAxel Lin 	{
4425976f095SAxel Lin 		.name = "DCDC1",
4435976f095SAxel Lin 		.id = LP3972_DCDC1,
4445976f095SAxel Lin 		.ops = &lp3972_dcdc_ops,
4455976f095SAxel Lin 		.n_voltages = ARRAY_SIZE(buck1_voltage_map),
4464f73ccadSAxel Lin 		.volt_table = buck1_voltage_map,
4475976f095SAxel Lin 		.type = REGULATOR_VOLTAGE,
4485976f095SAxel Lin 		.owner = THIS_MODULE,
4495976f095SAxel Lin 	},
4505976f095SAxel Lin 	{
4515976f095SAxel Lin 		.name = "DCDC2",
4525976f095SAxel Lin 		.id = LP3972_DCDC2,
4535976f095SAxel Lin 		.ops = &lp3972_dcdc_ops,
4545976f095SAxel Lin 		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
4554f73ccadSAxel Lin 		.volt_table = buck23_voltage_map,
4565976f095SAxel Lin 		.type = REGULATOR_VOLTAGE,
4575976f095SAxel Lin 		.owner = THIS_MODULE,
4585976f095SAxel Lin 	},
4595976f095SAxel Lin 	{
4605976f095SAxel Lin 		.name = "DCDC3",
4615976f095SAxel Lin 		.id = LP3972_DCDC3,
4625976f095SAxel Lin 		.ops = &lp3972_dcdc_ops,
4635976f095SAxel Lin 		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
4644f73ccadSAxel Lin 		.volt_table = buck23_voltage_map,
4655976f095SAxel Lin 		.type = REGULATOR_VOLTAGE,
4665976f095SAxel Lin 		.owner = THIS_MODULE,
4675976f095SAxel Lin 	},
4685976f095SAxel Lin };
4695976f095SAxel Lin 
setup_regulators(struct lp3972 * lp3972,struct lp3972_platform_data * pdata)470a5023574SBill Pemberton static int setup_regulators(struct lp3972 *lp3972,
4715976f095SAxel Lin 	struct lp3972_platform_data *pdata)
4725976f095SAxel Lin {
4735976f095SAxel Lin 	int i, err;
4745976f095SAxel Lin 
4755976f095SAxel Lin 	/* Instantiate the regulators */
4765976f095SAxel Lin 	for (i = 0; i < pdata->num_regulators; i++) {
4775976f095SAxel Lin 		struct lp3972_regulator_subdev *reg = &pdata->regulators[i];
478c172708dSMark Brown 		struct regulator_config config = { };
47993227c80SAxel Lin 		struct regulator_dev *rdev;
4805976f095SAxel Lin 
481c172708dSMark Brown 		config.dev = lp3972->dev;
482c172708dSMark Brown 		config.init_data = reg->initdata;
483c172708dSMark Brown 		config.driver_data = lp3972;
484c172708dSMark Brown 
48593227c80SAxel Lin 		rdev = devm_regulator_register(lp3972->dev,
48693227c80SAxel Lin 					       &regulators[reg->id], &config);
48793227c80SAxel Lin 		if (IS_ERR(rdev)) {
48893227c80SAxel Lin 			err = PTR_ERR(rdev);
4895976f095SAxel Lin 			dev_err(lp3972->dev, "regulator init failed: %d\n",
4905976f095SAxel Lin 				err);
49193227c80SAxel Lin 			return err;
4925976f095SAxel Lin 		}
4935976f095SAxel Lin 	}
4945976f095SAxel Lin 
4955976f095SAxel Lin 	return 0;
4965976f095SAxel Lin }
4975976f095SAxel Lin 
lp3972_i2c_probe(struct i2c_client * i2c)4982532d5f8SUwe Kleine-König static int lp3972_i2c_probe(struct i2c_client *i2c)
4995976f095SAxel Lin {
5005976f095SAxel Lin 	struct lp3972 *lp3972;
501dff91d0bSJingoo Han 	struct lp3972_platform_data *pdata = dev_get_platdata(&i2c->dev);
5025976f095SAxel Lin 	int ret;
5035976f095SAxel Lin 	u16 val;
5045976f095SAxel Lin 
5055976f095SAxel Lin 	if (!pdata) {
5065976f095SAxel Lin 		dev_dbg(&i2c->dev, "No platform init data supplied\n");
5075976f095SAxel Lin 		return -ENODEV;
5085976f095SAxel Lin 	}
5095976f095SAxel Lin 
5102af0af67SNikolay Balandin 	lp3972 = devm_kzalloc(&i2c->dev, sizeof(struct lp3972), GFP_KERNEL);
5115976f095SAxel Lin 	if (!lp3972)
5125976f095SAxel Lin 		return -ENOMEM;
5135976f095SAxel Lin 
5145976f095SAxel Lin 	lp3972->i2c = i2c;
5155976f095SAxel Lin 	lp3972->dev = &i2c->dev;
5165976f095SAxel Lin 
5175976f095SAxel Lin 	mutex_init(&lp3972->io_lock);
5185976f095SAxel Lin 
5195976f095SAxel Lin 	/* Detect LP3972 */
5205976f095SAxel Lin 	ret = lp3972_i2c_read(i2c, LP3972_SYS_CONTROL1_REG, 1, &val);
521993af7c0SAxel Lin 	if (ret == 0 &&
522993af7c0SAxel Lin 		(val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) {
5235976f095SAxel Lin 		ret = -ENODEV;
524993af7c0SAxel Lin 		dev_err(&i2c->dev, "chip reported: val = 0x%x\n", val);
525993af7c0SAxel Lin 	}
5265976f095SAxel Lin 	if (ret < 0) {
527993af7c0SAxel Lin 		dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret);
5282af0af67SNikolay Balandin 		return ret;
5295976f095SAxel Lin 	}
5305976f095SAxel Lin 
5315976f095SAxel Lin 	ret = setup_regulators(lp3972, pdata);
5325976f095SAxel Lin 	if (ret < 0)
5332af0af67SNikolay Balandin 		return ret;
5345976f095SAxel Lin 
5355976f095SAxel Lin 	i2c_set_clientdata(i2c, lp3972);
5365976f095SAxel Lin 	return 0;
5375976f095SAxel Lin }
5385976f095SAxel Lin 
5395976f095SAxel Lin static const struct i2c_device_id lp3972_i2c_id[] = {
5405976f095SAxel Lin 	{ "lp3972", 0 },
5415976f095SAxel Lin 	{ }
5425976f095SAxel Lin };
5435976f095SAxel Lin MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id);
5445976f095SAxel Lin 
5455976f095SAxel Lin static struct i2c_driver lp3972_i2c_driver = {
5465976f095SAxel Lin 	.driver = {
5475976f095SAxel Lin 		.name = "lp3972",
548259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
5495976f095SAxel Lin 	},
550*964e1865SUwe Kleine-König 	.probe = lp3972_i2c_probe,
5515976f095SAxel Lin 	.id_table = lp3972_i2c_id,
5525976f095SAxel Lin };
5535976f095SAxel Lin 
lp3972_module_init(void)5545976f095SAxel Lin static int __init lp3972_module_init(void)
5555976f095SAxel Lin {
5565976f095SAxel Lin 	return i2c_add_driver(&lp3972_i2c_driver);
5575976f095SAxel Lin }
5585976f095SAxel Lin subsys_initcall(lp3972_module_init);
5595976f095SAxel Lin 
lp3972_module_exit(void)5605976f095SAxel Lin static void __exit lp3972_module_exit(void)
5615976f095SAxel Lin {
5625976f095SAxel Lin 	i2c_del_driver(&lp3972_i2c_driver);
5635976f095SAxel Lin }
5645976f095SAxel Lin module_exit(lp3972_module_exit);
5655976f095SAxel Lin 
5665976f095SAxel Lin MODULE_LICENSE("GPL");
5675976f095SAxel Lin MODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>");
5685976f095SAxel Lin MODULE_DESCRIPTION("LP3972 PMIC driver");
569