18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Regulator driver for National Semiconductors LP3972 PMIC chip
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based on lp3971.c
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bug.h>
98c2ecf20Sopenharmony_ci#include <linux/err.h>
108c2ecf20Sopenharmony_ci#include <linux/i2c.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
148c2ecf20Sopenharmony_ci#include <linux/regulator/lp3972.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistruct lp3972 {
188c2ecf20Sopenharmony_ci	struct device *dev;
198c2ecf20Sopenharmony_ci	struct mutex io_lock;
208c2ecf20Sopenharmony_ci	struct i2c_client *i2c;
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* LP3972 Control Registers */
248c2ecf20Sopenharmony_ci#define LP3972_SCR_REG		0x07
258c2ecf20Sopenharmony_ci#define LP3972_OVER1_REG	0x10
268c2ecf20Sopenharmony_ci#define LP3972_OVSR1_REG	0x11
278c2ecf20Sopenharmony_ci#define LP3972_OVER2_REG	0x12
288c2ecf20Sopenharmony_ci#define LP3972_OVSR2_REG	0x13
298c2ecf20Sopenharmony_ci#define LP3972_VCC1_REG		0x20
308c2ecf20Sopenharmony_ci#define LP3972_ADTV1_REG	0x23
318c2ecf20Sopenharmony_ci#define LP3972_ADTV2_REG	0x24
328c2ecf20Sopenharmony_ci#define LP3972_AVRC_REG		0x25
338c2ecf20Sopenharmony_ci#define LP3972_CDTC1_REG	0x26
348c2ecf20Sopenharmony_ci#define LP3972_CDTC2_REG	0x27
358c2ecf20Sopenharmony_ci#define LP3972_SDTV1_REG	0x29
368c2ecf20Sopenharmony_ci#define LP3972_SDTV2_REG	0x2A
378c2ecf20Sopenharmony_ci#define LP3972_MDTV1_REG	0x32
388c2ecf20Sopenharmony_ci#define LP3972_MDTV2_REG	0x33
398c2ecf20Sopenharmony_ci#define LP3972_L2VCR_REG	0x39
408c2ecf20Sopenharmony_ci#define LP3972_L34VCR_REG	0x3A
418c2ecf20Sopenharmony_ci#define LP3972_SCR1_REG		0x80
428c2ecf20Sopenharmony_ci#define LP3972_SCR2_REG		0x81
438c2ecf20Sopenharmony_ci#define LP3972_OEN3_REG		0x82
448c2ecf20Sopenharmony_ci#define LP3972_OSR3_REG		0x83
458c2ecf20Sopenharmony_ci#define LP3972_LOER4_REG	0x84
468c2ecf20Sopenharmony_ci#define LP3972_B2TV_REG		0x85
478c2ecf20Sopenharmony_ci#define LP3972_B3TV_REG		0x86
488c2ecf20Sopenharmony_ci#define LP3972_B32RC_REG	0x87
498c2ecf20Sopenharmony_ci#define LP3972_ISRA_REG		0x88
508c2ecf20Sopenharmony_ci#define LP3972_BCCR_REG		0x89
518c2ecf20Sopenharmony_ci#define LP3972_II1RR_REG	0x8E
528c2ecf20Sopenharmony_ci#define LP3972_II2RR_REG	0x8F
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define LP3972_SYS_CONTROL1_REG		LP3972_SCR1_REG
558c2ecf20Sopenharmony_ci/* System control register 1 initial value,
568c2ecf20Sopenharmony_ci * bits 5, 6 and 7 are EPROM programmable */
578c2ecf20Sopenharmony_ci#define SYS_CONTROL1_INIT_VAL		0x02
588c2ecf20Sopenharmony_ci#define SYS_CONTROL1_INIT_MASK		0x1F
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define LP3972_VOL_CHANGE_REG		LP3972_VCC1_REG
618c2ecf20Sopenharmony_ci#define LP3972_VOL_CHANGE_FLAG_GO	0x01
628c2ecf20Sopenharmony_ci#define LP3972_VOL_CHANGE_FLAG_MASK	0x03
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/* LDO output enable mask */
658c2ecf20Sopenharmony_ci#define LP3972_OEN3_L1EN	BIT(0)
668c2ecf20Sopenharmony_ci#define LP3972_OVER2_LDO2_EN	BIT(2)
678c2ecf20Sopenharmony_ci#define LP3972_OVER2_LDO3_EN	BIT(3)
688c2ecf20Sopenharmony_ci#define LP3972_OVER2_LDO4_EN	BIT(4)
698c2ecf20Sopenharmony_ci#define LP3972_OVER1_S_EN	BIT(2)
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic const unsigned int ldo1_voltage_map[] = {
728c2ecf20Sopenharmony_ci	1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000,
738c2ecf20Sopenharmony_ci	1900000, 1925000, 1950000, 1975000, 2000000,
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic const unsigned int ldo23_voltage_map[] = {
778c2ecf20Sopenharmony_ci	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
788c2ecf20Sopenharmony_ci	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic const unsigned int ldo4_voltage_map[] = {
828c2ecf20Sopenharmony_ci	1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
838c2ecf20Sopenharmony_ci	1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic const unsigned int ldo5_voltage_map[] = {
878c2ecf20Sopenharmony_ci	      0,       0,       0,       0,       0,  850000,  875000,  900000,
888c2ecf20Sopenharmony_ci	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
898c2ecf20Sopenharmony_ci	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
908c2ecf20Sopenharmony_ci	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
918c2ecf20Sopenharmony_ci};
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic const unsigned int buck1_voltage_map[] = {
948c2ecf20Sopenharmony_ci	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
958c2ecf20Sopenharmony_ci	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
968c2ecf20Sopenharmony_ci	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
978c2ecf20Sopenharmony_ci	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic const unsigned int buck23_voltage_map[] = {
1018c2ecf20Sopenharmony_ci	      0,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
1028c2ecf20Sopenharmony_ci	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
1038c2ecf20Sopenharmony_ci	1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
1048c2ecf20Sopenharmony_ci	3000000, 3300000,
1058c2ecf20Sopenharmony_ci};
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic const int ldo_output_enable_mask[] = {
1088c2ecf20Sopenharmony_ci	LP3972_OEN3_L1EN,
1098c2ecf20Sopenharmony_ci	LP3972_OVER2_LDO2_EN,
1108c2ecf20Sopenharmony_ci	LP3972_OVER2_LDO3_EN,
1118c2ecf20Sopenharmony_ci	LP3972_OVER2_LDO4_EN,
1128c2ecf20Sopenharmony_ci	LP3972_OVER1_S_EN,
1138c2ecf20Sopenharmony_ci};
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic const int ldo_output_enable_addr[] = {
1168c2ecf20Sopenharmony_ci	LP3972_OEN3_REG,
1178c2ecf20Sopenharmony_ci	LP3972_OVER2_REG,
1188c2ecf20Sopenharmony_ci	LP3972_OVER2_REG,
1198c2ecf20Sopenharmony_ci	LP3972_OVER2_REG,
1208c2ecf20Sopenharmony_ci	LP3972_OVER1_REG,
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic const int ldo_vol_ctl_addr[] = {
1248c2ecf20Sopenharmony_ci	LP3972_MDTV1_REG,
1258c2ecf20Sopenharmony_ci	LP3972_L2VCR_REG,
1268c2ecf20Sopenharmony_ci	LP3972_L34VCR_REG,
1278c2ecf20Sopenharmony_ci	LP3972_L34VCR_REG,
1288c2ecf20Sopenharmony_ci	LP3972_SDTV1_REG,
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic const int buck_vol_enable_addr[] = {
1328c2ecf20Sopenharmony_ci	LP3972_OVER1_REG,
1338c2ecf20Sopenharmony_ci	LP3972_OEN3_REG,
1348c2ecf20Sopenharmony_ci	LP3972_OEN3_REG,
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic const int buck_base_addr[] = {
1388c2ecf20Sopenharmony_ci	LP3972_ADTV1_REG,
1398c2ecf20Sopenharmony_ci	LP3972_B2TV_REG,
1408c2ecf20Sopenharmony_ci	LP3972_B3TV_REG,
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci#define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
1448c2ecf20Sopenharmony_ci#define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x])
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci/*	LDO voltage control registers shift:
1478c2ecf20Sopenharmony_ci	LP3972_LDO1 -> 0, LP3972_LDO2 -> 4
1488c2ecf20Sopenharmony_ci	LP3972_LDO3 -> 0, LP3972_LDO4 -> 4
1498c2ecf20Sopenharmony_ci	LP3972_LDO5 -> 0
1508c2ecf20Sopenharmony_ci*/
1518c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_CONTR_SHIFT(x) (((x) & 1) << 2)
1528c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_CONTR_REG(x) (ldo_vol_ctl_addr[x])
1538c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_CHANGE_SHIFT(x) ((x) ? 4 : 6)
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_MASK(x) (((x) % 4) ? 0x0f : 0x1f)
1568c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00)
1578c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c)
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
1608c2ecf20Sopenharmony_ci#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
1618c2ecf20Sopenharmony_ci#define LP3972_BUCK_VOL_MASK 0x1f
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count,
1648c2ecf20Sopenharmony_ci	u16 *dest)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	int ret;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if (count != 1)
1698c2ecf20Sopenharmony_ci		return -EIO;
1708c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte_data(i2c, reg);
1718c2ecf20Sopenharmony_ci	if (ret < 0)
1728c2ecf20Sopenharmony_ci		return ret;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	*dest = ret;
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int lp3972_i2c_write(struct i2c_client *i2c, char reg, int count,
1798c2ecf20Sopenharmony_ci	const u16 *src)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	if (count != 1)
1828c2ecf20Sopenharmony_ci		return -EIO;
1838c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(i2c, reg, *src);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic u8 lp3972_reg_read(struct lp3972 *lp3972, u8 reg)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	u16 val = 0;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	mutex_lock(&lp3972->io_lock);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	lp3972_i2c_read(lp3972->i2c, reg, 1, &val);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	dev_dbg(lp3972->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
1958c2ecf20Sopenharmony_ci		(unsigned)val & 0xff);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	mutex_unlock(&lp3972->io_lock);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return val & 0xff;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	u16 tmp;
2058c2ecf20Sopenharmony_ci	int ret;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	mutex_lock(&lp3972->io_lock);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp);
2108c2ecf20Sopenharmony_ci	if (ret == 0) {
2118c2ecf20Sopenharmony_ci		tmp = (tmp & ~mask) | val;
2128c2ecf20Sopenharmony_ci		ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp);
2138c2ecf20Sopenharmony_ci		dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
2148c2ecf20Sopenharmony_ci			(unsigned)val & 0xff);
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci	mutex_unlock(&lp3972->io_lock);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return ret;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic int lp3972_ldo_is_enabled(struct regulator_dev *dev)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2248c2ecf20Sopenharmony_ci	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2258c2ecf20Sopenharmony_ci	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
2268c2ecf20Sopenharmony_ci	u16 val;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	val = lp3972_reg_read(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo));
2298c2ecf20Sopenharmony_ci	return !!(val & mask);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int lp3972_ldo_enable(struct regulator_dev *dev)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2358c2ecf20Sopenharmony_ci	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2368c2ecf20Sopenharmony_ci	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo),
2398c2ecf20Sopenharmony_ci				mask, mask);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int lp3972_ldo_disable(struct regulator_dev *dev)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2458c2ecf20Sopenharmony_ci	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2468c2ecf20Sopenharmony_ci	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo),
2498c2ecf20Sopenharmony_ci				mask, 0);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2558c2ecf20Sopenharmony_ci	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2568c2ecf20Sopenharmony_ci	u16 mask = LP3972_LDO_VOL_MASK(ldo);
2578c2ecf20Sopenharmony_ci	u16 val, reg;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
2608c2ecf20Sopenharmony_ci	val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return val;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
2668c2ecf20Sopenharmony_ci				      unsigned int selector)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
2698c2ecf20Sopenharmony_ci	int ldo = rdev_get_id(dev) - LP3972_LDO1;
2708c2ecf20Sopenharmony_ci	int shift, ret;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo);
2738c2ecf20Sopenharmony_ci	ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo),
2748c2ecf20Sopenharmony_ci		LP3972_LDO_VOL_MASK(ldo) << shift, selector << shift);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (ret)
2778c2ecf20Sopenharmony_ci		return ret;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/*
2808c2ecf20Sopenharmony_ci	 * LDO1 and LDO5 support voltage control by either target voltage1
2818c2ecf20Sopenharmony_ci	 * or target voltage2 register.
2828c2ecf20Sopenharmony_ci	 * We use target voltage1 register for LDO1 and LDO5 in this driver.
2838c2ecf20Sopenharmony_ci	 * We need to update voltage change control register(0x20) to enable
2848c2ecf20Sopenharmony_ci	 * LDO1 and LDO5 to change to their programmed target values.
2858c2ecf20Sopenharmony_ci	 */
2868c2ecf20Sopenharmony_ci	switch (ldo) {
2878c2ecf20Sopenharmony_ci	case LP3972_LDO1:
2888c2ecf20Sopenharmony_ci	case LP3972_LDO5:
2898c2ecf20Sopenharmony_ci		shift = LP3972_LDO_VOL_CHANGE_SHIFT(ldo);
2908c2ecf20Sopenharmony_ci		ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
2918c2ecf20Sopenharmony_ci			LP3972_VOL_CHANGE_FLAG_MASK << shift,
2928c2ecf20Sopenharmony_ci			LP3972_VOL_CHANGE_FLAG_GO << shift);
2938c2ecf20Sopenharmony_ci		if (ret)
2948c2ecf20Sopenharmony_ci			return ret;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
2978c2ecf20Sopenharmony_ci			LP3972_VOL_CHANGE_FLAG_MASK << shift, 0);
2988c2ecf20Sopenharmony_ci		break;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return ret;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic const struct regulator_ops lp3972_ldo_ops = {
3058c2ecf20Sopenharmony_ci	.list_voltage = regulator_list_voltage_table,
3068c2ecf20Sopenharmony_ci	.map_voltage = regulator_map_voltage_ascend,
3078c2ecf20Sopenharmony_ci	.is_enabled = lp3972_ldo_is_enabled,
3088c2ecf20Sopenharmony_ci	.enable = lp3972_ldo_enable,
3098c2ecf20Sopenharmony_ci	.disable = lp3972_ldo_disable,
3108c2ecf20Sopenharmony_ci	.get_voltage_sel = lp3972_ldo_get_voltage_sel,
3118c2ecf20Sopenharmony_ci	.set_voltage_sel = lp3972_ldo_set_voltage_sel,
3128c2ecf20Sopenharmony_ci};
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int lp3972_dcdc_is_enabled(struct regulator_dev *dev)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3178c2ecf20Sopenharmony_ci	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3188c2ecf20Sopenharmony_ci	u16 mask = 1 << (buck * 2);
3198c2ecf20Sopenharmony_ci	u16 val;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	val = lp3972_reg_read(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck));
3228c2ecf20Sopenharmony_ci	return !!(val & mask);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic int lp3972_dcdc_enable(struct regulator_dev *dev)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3288c2ecf20Sopenharmony_ci	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3298c2ecf20Sopenharmony_ci	u16 mask = 1 << (buck * 2);
3308c2ecf20Sopenharmony_ci	u16 val;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck),
3338c2ecf20Sopenharmony_ci				mask, mask);
3348c2ecf20Sopenharmony_ci	return val;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic int lp3972_dcdc_disable(struct regulator_dev *dev)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3408c2ecf20Sopenharmony_ci	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3418c2ecf20Sopenharmony_ci	u16 mask = 1 << (buck * 2);
3428c2ecf20Sopenharmony_ci	u16 val;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck),
3458c2ecf20Sopenharmony_ci				mask, 0);
3468c2ecf20Sopenharmony_ci	return val;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3528c2ecf20Sopenharmony_ci	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3538c2ecf20Sopenharmony_ci	u16 reg;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
3568c2ecf20Sopenharmony_ci	reg &= LP3972_BUCK_VOL_MASK;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	return reg;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
3628c2ecf20Sopenharmony_ci				       unsigned int selector)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
3658c2ecf20Sopenharmony_ci	int buck = rdev_get_id(dev) - LP3972_DCDC1;
3668c2ecf20Sopenharmony_ci	int ret;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck),
3698c2ecf20Sopenharmony_ci				LP3972_BUCK_VOL_MASK, selector);
3708c2ecf20Sopenharmony_ci	if (ret)
3718c2ecf20Sopenharmony_ci		return ret;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (buck != 0)
3748c2ecf20Sopenharmony_ci		return ret;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
3778c2ecf20Sopenharmony_ci		LP3972_VOL_CHANGE_FLAG_MASK, LP3972_VOL_CHANGE_FLAG_GO);
3788c2ecf20Sopenharmony_ci	if (ret)
3798c2ecf20Sopenharmony_ci		return ret;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
3828c2ecf20Sopenharmony_ci				LP3972_VOL_CHANGE_FLAG_MASK, 0);
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic const struct regulator_ops lp3972_dcdc_ops = {
3868c2ecf20Sopenharmony_ci	.list_voltage = regulator_list_voltage_table,
3878c2ecf20Sopenharmony_ci	.map_voltage = regulator_map_voltage_ascend,
3888c2ecf20Sopenharmony_ci	.is_enabled = lp3972_dcdc_is_enabled,
3898c2ecf20Sopenharmony_ci	.enable = lp3972_dcdc_enable,
3908c2ecf20Sopenharmony_ci	.disable = lp3972_dcdc_disable,
3918c2ecf20Sopenharmony_ci	.get_voltage_sel = lp3972_dcdc_get_voltage_sel,
3928c2ecf20Sopenharmony_ci	.set_voltage_sel = lp3972_dcdc_set_voltage_sel,
3938c2ecf20Sopenharmony_ci};
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic const struct regulator_desc regulators[] = {
3968c2ecf20Sopenharmony_ci	{
3978c2ecf20Sopenharmony_ci		.name = "LDO1",
3988c2ecf20Sopenharmony_ci		.id = LP3972_LDO1,
3998c2ecf20Sopenharmony_ci		.ops = &lp3972_ldo_ops,
4008c2ecf20Sopenharmony_ci		.n_voltages = ARRAY_SIZE(ldo1_voltage_map),
4018c2ecf20Sopenharmony_ci		.volt_table = ldo1_voltage_map,
4028c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,
4038c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
4048c2ecf20Sopenharmony_ci	},
4058c2ecf20Sopenharmony_ci	{
4068c2ecf20Sopenharmony_ci		.name = "LDO2",
4078c2ecf20Sopenharmony_ci		.id = LP3972_LDO2,
4088c2ecf20Sopenharmony_ci		.ops = &lp3972_ldo_ops,
4098c2ecf20Sopenharmony_ci		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
4108c2ecf20Sopenharmony_ci		.volt_table = ldo23_voltage_map,
4118c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,
4128c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
4138c2ecf20Sopenharmony_ci	},
4148c2ecf20Sopenharmony_ci	{
4158c2ecf20Sopenharmony_ci		.name = "LDO3",
4168c2ecf20Sopenharmony_ci		.id = LP3972_LDO3,
4178c2ecf20Sopenharmony_ci		.ops = &lp3972_ldo_ops,
4188c2ecf20Sopenharmony_ci		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
4198c2ecf20Sopenharmony_ci		.volt_table = ldo23_voltage_map,
4208c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,
4218c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
4228c2ecf20Sopenharmony_ci	},
4238c2ecf20Sopenharmony_ci	{
4248c2ecf20Sopenharmony_ci		.name = "LDO4",
4258c2ecf20Sopenharmony_ci		.id = LP3972_LDO4,
4268c2ecf20Sopenharmony_ci		.ops = &lp3972_ldo_ops,
4278c2ecf20Sopenharmony_ci		.n_voltages = ARRAY_SIZE(ldo4_voltage_map),
4288c2ecf20Sopenharmony_ci		.volt_table = ldo4_voltage_map,
4298c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,
4308c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
4318c2ecf20Sopenharmony_ci	},
4328c2ecf20Sopenharmony_ci	{
4338c2ecf20Sopenharmony_ci		.name = "LDO5",
4348c2ecf20Sopenharmony_ci		.id = LP3972_LDO5,
4358c2ecf20Sopenharmony_ci		.ops = &lp3972_ldo_ops,
4368c2ecf20Sopenharmony_ci		.n_voltages = ARRAY_SIZE(ldo5_voltage_map),
4378c2ecf20Sopenharmony_ci		.volt_table = ldo5_voltage_map,
4388c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,
4398c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
4408c2ecf20Sopenharmony_ci	},
4418c2ecf20Sopenharmony_ci	{
4428c2ecf20Sopenharmony_ci		.name = "DCDC1",
4438c2ecf20Sopenharmony_ci		.id = LP3972_DCDC1,
4448c2ecf20Sopenharmony_ci		.ops = &lp3972_dcdc_ops,
4458c2ecf20Sopenharmony_ci		.n_voltages = ARRAY_SIZE(buck1_voltage_map),
4468c2ecf20Sopenharmony_ci		.volt_table = buck1_voltage_map,
4478c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,
4488c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
4498c2ecf20Sopenharmony_ci	},
4508c2ecf20Sopenharmony_ci	{
4518c2ecf20Sopenharmony_ci		.name = "DCDC2",
4528c2ecf20Sopenharmony_ci		.id = LP3972_DCDC2,
4538c2ecf20Sopenharmony_ci		.ops = &lp3972_dcdc_ops,
4548c2ecf20Sopenharmony_ci		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
4558c2ecf20Sopenharmony_ci		.volt_table = buck23_voltage_map,
4568c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,
4578c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
4588c2ecf20Sopenharmony_ci	},
4598c2ecf20Sopenharmony_ci	{
4608c2ecf20Sopenharmony_ci		.name = "DCDC3",
4618c2ecf20Sopenharmony_ci		.id = LP3972_DCDC3,
4628c2ecf20Sopenharmony_ci		.ops = &lp3972_dcdc_ops,
4638c2ecf20Sopenharmony_ci		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
4648c2ecf20Sopenharmony_ci		.volt_table = buck23_voltage_map,
4658c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,
4668c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
4678c2ecf20Sopenharmony_ci	},
4688c2ecf20Sopenharmony_ci};
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic int setup_regulators(struct lp3972 *lp3972,
4718c2ecf20Sopenharmony_ci	struct lp3972_platform_data *pdata)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	int i, err;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	/* Instantiate the regulators */
4768c2ecf20Sopenharmony_ci	for (i = 0; i < pdata->num_regulators; i++) {
4778c2ecf20Sopenharmony_ci		struct lp3972_regulator_subdev *reg = &pdata->regulators[i];
4788c2ecf20Sopenharmony_ci		struct regulator_config config = { };
4798c2ecf20Sopenharmony_ci		struct regulator_dev *rdev;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		config.dev = lp3972->dev;
4828c2ecf20Sopenharmony_ci		config.init_data = reg->initdata;
4838c2ecf20Sopenharmony_ci		config.driver_data = lp3972;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci		rdev = devm_regulator_register(lp3972->dev,
4868c2ecf20Sopenharmony_ci					       &regulators[reg->id], &config);
4878c2ecf20Sopenharmony_ci		if (IS_ERR(rdev)) {
4888c2ecf20Sopenharmony_ci			err = PTR_ERR(rdev);
4898c2ecf20Sopenharmony_ci			dev_err(lp3972->dev, "regulator init failed: %d\n",
4908c2ecf20Sopenharmony_ci				err);
4918c2ecf20Sopenharmony_ci			return err;
4928c2ecf20Sopenharmony_ci		}
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return 0;
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic int lp3972_i2c_probe(struct i2c_client *i2c,
4998c2ecf20Sopenharmony_ci			    const struct i2c_device_id *id)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct lp3972 *lp3972;
5028c2ecf20Sopenharmony_ci	struct lp3972_platform_data *pdata = dev_get_platdata(&i2c->dev);
5038c2ecf20Sopenharmony_ci	int ret;
5048c2ecf20Sopenharmony_ci	u16 val;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (!pdata) {
5078c2ecf20Sopenharmony_ci		dev_dbg(&i2c->dev, "No platform init data supplied\n");
5088c2ecf20Sopenharmony_ci		return -ENODEV;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	lp3972 = devm_kzalloc(&i2c->dev, sizeof(struct lp3972), GFP_KERNEL);
5128c2ecf20Sopenharmony_ci	if (!lp3972)
5138c2ecf20Sopenharmony_ci		return -ENOMEM;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	lp3972->i2c = i2c;
5168c2ecf20Sopenharmony_ci	lp3972->dev = &i2c->dev;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	mutex_init(&lp3972->io_lock);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	/* Detect LP3972 */
5218c2ecf20Sopenharmony_ci	ret = lp3972_i2c_read(i2c, LP3972_SYS_CONTROL1_REG, 1, &val);
5228c2ecf20Sopenharmony_ci	if (ret == 0 &&
5238c2ecf20Sopenharmony_ci		(val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) {
5248c2ecf20Sopenharmony_ci		ret = -ENODEV;
5258c2ecf20Sopenharmony_ci		dev_err(&i2c->dev, "chip reported: val = 0x%x\n", val);
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci	if (ret < 0) {
5288c2ecf20Sopenharmony_ci		dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret);
5298c2ecf20Sopenharmony_ci		return ret;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	ret = setup_regulators(lp3972, pdata);
5338c2ecf20Sopenharmony_ci	if (ret < 0)
5348c2ecf20Sopenharmony_ci		return ret;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	i2c_set_clientdata(i2c, lp3972);
5378c2ecf20Sopenharmony_ci	return 0;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic const struct i2c_device_id lp3972_i2c_id[] = {
5418c2ecf20Sopenharmony_ci	{ "lp3972", 0 },
5428c2ecf20Sopenharmony_ci	{ }
5438c2ecf20Sopenharmony_ci};
5448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lp3972_i2c_id);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic struct i2c_driver lp3972_i2c_driver = {
5478c2ecf20Sopenharmony_ci	.driver = {
5488c2ecf20Sopenharmony_ci		.name = "lp3972",
5498c2ecf20Sopenharmony_ci	},
5508c2ecf20Sopenharmony_ci	.probe    = lp3972_i2c_probe,
5518c2ecf20Sopenharmony_ci	.id_table = lp3972_i2c_id,
5528c2ecf20Sopenharmony_ci};
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_cistatic int __init lp3972_module_init(void)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	return i2c_add_driver(&lp3972_i2c_driver);
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_cisubsys_initcall(lp3972_module_init);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic void __exit lp3972_module_exit(void)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	i2c_del_driver(&lp3972_i2c_driver);
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_cimodule_exit(lp3972_module_exit);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
5678c2ecf20Sopenharmony_ciMODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>");
5688c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LP3972 PMIC driver");
569