xref: /openbmc/linux/drivers/regulator/lp3971.c (revision 964e1865)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20cbdf7bcSMarek Szyprowski /*
30cbdf7bcSMarek Szyprowski  * Regulator driver for National Semiconductors LP3971 PMIC chip
40cbdf7bcSMarek Szyprowski  *
50cbdf7bcSMarek Szyprowski  *  Copyright (C) 2009 Samsung Electronics
60cbdf7bcSMarek Szyprowski  *  Author: Marek Szyprowski <m.szyprowski@samsung.com>
70cbdf7bcSMarek Szyprowski  *
80cbdf7bcSMarek Szyprowski  * Based on wm8350.c
90cbdf7bcSMarek Szyprowski  */
100cbdf7bcSMarek Szyprowski 
110cbdf7bcSMarek Szyprowski #include <linux/bug.h>
120cbdf7bcSMarek Szyprowski #include <linux/err.h>
130cbdf7bcSMarek Szyprowski #include <linux/i2c.h>
140cbdf7bcSMarek Szyprowski #include <linux/kernel.h>
1565602c32SPaul Gortmaker #include <linux/module.h>
160cbdf7bcSMarek Szyprowski #include <linux/regulator/driver.h>
170cbdf7bcSMarek Szyprowski #include <linux/regulator/lp3971.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
190cbdf7bcSMarek Szyprowski 
200cbdf7bcSMarek Szyprowski struct lp3971 {
210cbdf7bcSMarek Szyprowski 	struct device *dev;
220cbdf7bcSMarek Szyprowski 	struct mutex io_lock;
230cbdf7bcSMarek Szyprowski 	struct i2c_client *i2c;
240cbdf7bcSMarek Szyprowski };
250cbdf7bcSMarek Szyprowski 
260cbdf7bcSMarek Szyprowski static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg);
270cbdf7bcSMarek Szyprowski static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val);
280cbdf7bcSMarek Szyprowski 
290cbdf7bcSMarek Szyprowski #define LP3971_SYS_CONTROL1_REG 0x07
300cbdf7bcSMarek Szyprowski 
310cbdf7bcSMarek Szyprowski /* System control register 1 initial value,
320cbdf7bcSMarek Szyprowski    bits 4 and 5 are EPROM programmable */
330cbdf7bcSMarek Szyprowski #define SYS_CONTROL1_INIT_VAL 0x40
340cbdf7bcSMarek Szyprowski #define SYS_CONTROL1_INIT_MASK 0xCF
350cbdf7bcSMarek Szyprowski 
360cbdf7bcSMarek Szyprowski #define LP3971_BUCK_VOL_ENABLE_REG 0x10
370cbdf7bcSMarek Szyprowski #define LP3971_BUCK_VOL_CHANGE_REG 0x20
380cbdf7bcSMarek Szyprowski 
390cbdf7bcSMarek Szyprowski /*	Voltage control registers shift:
400cbdf7bcSMarek Szyprowski 	LP3971_BUCK1 -> 0
410cbdf7bcSMarek Szyprowski 	LP3971_BUCK2 -> 4
420cbdf7bcSMarek Szyprowski 	LP3971_BUCK3 -> 6
430cbdf7bcSMarek Szyprowski */
44451a73cdSAxel Lin #define BUCK_VOL_CHANGE_SHIFT(x) (((!!x) << 2) | (x & ~0x01))
450cbdf7bcSMarek Szyprowski #define BUCK_VOL_CHANGE_FLAG_GO 0x01
460cbdf7bcSMarek Szyprowski #define BUCK_VOL_CHANGE_FLAG_TARGET 0x02
470cbdf7bcSMarek Szyprowski #define BUCK_VOL_CHANGE_FLAG_MASK 0x03
480cbdf7bcSMarek Szyprowski 
490cbdf7bcSMarek Szyprowski #define LP3971_BUCK1_BASE 0x23
500cbdf7bcSMarek Szyprowski #define LP3971_BUCK2_BASE 0x29
510cbdf7bcSMarek Szyprowski #define LP3971_BUCK3_BASE 0x32
520cbdf7bcSMarek Szyprowski 
536faa7e0aSTobias Klauser static const int buck_base_addr[] = {
540cbdf7bcSMarek Szyprowski 	LP3971_BUCK1_BASE,
550cbdf7bcSMarek Szyprowski 	LP3971_BUCK2_BASE,
560cbdf7bcSMarek Szyprowski 	LP3971_BUCK3_BASE,
570cbdf7bcSMarek Szyprowski };
580cbdf7bcSMarek Szyprowski 
590cbdf7bcSMarek Szyprowski #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
600cbdf7bcSMarek Szyprowski #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
610cbdf7bcSMarek Szyprowski 
62cad8d76eSAxel Lin static const unsigned int buck_voltage_map[] = {
63cad8d76eSAxel Lin 	      0,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
64cad8d76eSAxel Lin 	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
65cad8d76eSAxel Lin 	1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
66cad8d76eSAxel Lin 	3000000, 3300000,
670cbdf7bcSMarek Szyprowski };
680cbdf7bcSMarek Szyprowski 
690cbdf7bcSMarek Szyprowski #define BUCK_TARGET_VOL_MASK 0x3f
700cbdf7bcSMarek Szyprowski 
710cbdf7bcSMarek Szyprowski #define LP3971_BUCK_RAMP_REG(x)	(buck_base_addr[x]+2)
720cbdf7bcSMarek Szyprowski 
730cbdf7bcSMarek Szyprowski #define LP3971_LDO_ENABLE_REG 0x12
740cbdf7bcSMarek Szyprowski #define LP3971_LDO_VOL_CONTR_BASE 0x39
750cbdf7bcSMarek Szyprowski 
760cbdf7bcSMarek Szyprowski /*	Voltage control registers:
770cbdf7bcSMarek Szyprowski 	LP3971_LDO1 -> LP3971_LDO_VOL_CONTR_BASE + 0
780cbdf7bcSMarek Szyprowski 	LP3971_LDO2 -> LP3971_LDO_VOL_CONTR_BASE + 0
790cbdf7bcSMarek Szyprowski 	LP3971_LDO3 -> LP3971_LDO_VOL_CONTR_BASE + 1
800cbdf7bcSMarek Szyprowski 	LP3971_LDO4 -> LP3971_LDO_VOL_CONTR_BASE + 1
810cbdf7bcSMarek Szyprowski 	LP3971_LDO5 -> LP3971_LDO_VOL_CONTR_BASE + 2
820cbdf7bcSMarek Szyprowski */
830cbdf7bcSMarek Szyprowski #define LP3971_LDO_VOL_CONTR_REG(x)	(LP3971_LDO_VOL_CONTR_BASE + (x >> 1))
840cbdf7bcSMarek Szyprowski 
850cbdf7bcSMarek Szyprowski /*	Voltage control registers shift:
860cbdf7bcSMarek Szyprowski 	LP3971_LDO1 -> 0, LP3971_LDO2 -> 4
870cbdf7bcSMarek Szyprowski 	LP3971_LDO3 -> 0, LP3971_LDO4 -> 4
880cbdf7bcSMarek Szyprowski 	LP3971_LDO5 -> 0
890cbdf7bcSMarek Szyprowski */
900cbdf7bcSMarek Szyprowski #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
910cbdf7bcSMarek Szyprowski #define LDO_VOL_CONTR_MASK 0x0f
920cbdf7bcSMarek Szyprowski 
93cad8d76eSAxel Lin static const unsigned int ldo45_voltage_map[] = {
94cad8d76eSAxel Lin 	1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
95cad8d76eSAxel Lin 	1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
960cbdf7bcSMarek Szyprowski };
970cbdf7bcSMarek Szyprowski 
98cad8d76eSAxel Lin static const unsigned int ldo123_voltage_map[] = {
99cad8d76eSAxel Lin 	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
100cad8d76eSAxel Lin 	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
1010cbdf7bcSMarek Szyprowski };
1020cbdf7bcSMarek Szyprowski 
1030cbdf7bcSMarek Szyprowski #define LDO_VOL_MIN_IDX 0x00
1040cbdf7bcSMarek Szyprowski #define LDO_VOL_MAX_IDX 0x0f
1050cbdf7bcSMarek Szyprowski 
lp3971_ldo_is_enabled(struct regulator_dev * dev)1060cbdf7bcSMarek Szyprowski static int lp3971_ldo_is_enabled(struct regulator_dev *dev)
1070cbdf7bcSMarek Szyprowski {
1080cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1090cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1100cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (1 + ldo);
1110cbdf7bcSMarek Szyprowski 	u16 val;
1120cbdf7bcSMarek Szyprowski 
1130cbdf7bcSMarek Szyprowski 	val = lp3971_reg_read(lp3971, LP3971_LDO_ENABLE_REG);
1140cbdf7bcSMarek Szyprowski 	return (val & mask) != 0;
1150cbdf7bcSMarek Szyprowski }
1160cbdf7bcSMarek Szyprowski 
lp3971_ldo_enable(struct regulator_dev * dev)1170cbdf7bcSMarek Szyprowski static int lp3971_ldo_enable(struct regulator_dev *dev)
1180cbdf7bcSMarek Szyprowski {
1190cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1200cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1210cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (1 + ldo);
1220cbdf7bcSMarek Szyprowski 
1230cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, mask);
1240cbdf7bcSMarek Szyprowski }
1250cbdf7bcSMarek Szyprowski 
lp3971_ldo_disable(struct regulator_dev * dev)1260cbdf7bcSMarek Szyprowski static int lp3971_ldo_disable(struct regulator_dev *dev)
1270cbdf7bcSMarek Szyprowski {
1280cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1290cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1300cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (1 + ldo);
1310cbdf7bcSMarek Szyprowski 
1320cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
1330cbdf7bcSMarek Szyprowski }
1340cbdf7bcSMarek Szyprowski 
lp3971_ldo_get_voltage_sel(struct regulator_dev * dev)135f38482faSAxel Lin static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev)
1360cbdf7bcSMarek Szyprowski {
1370cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1380cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1390cbdf7bcSMarek Szyprowski 	u16 val, reg;
1400cbdf7bcSMarek Szyprowski 
1410cbdf7bcSMarek Szyprowski 	reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
1420cbdf7bcSMarek Szyprowski 	val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
1430cbdf7bcSMarek Szyprowski 
144f38482faSAxel Lin 	return val;
1450cbdf7bcSMarek Szyprowski }
1460cbdf7bcSMarek Szyprowski 
lp3971_ldo_set_voltage_sel(struct regulator_dev * dev,unsigned int selector)147dd8e2314SAxel Lin static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
148dd8e2314SAxel Lin 				      unsigned int selector)
1490cbdf7bcSMarek Szyprowski {
1500cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1510cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1523a93f2a9SMark Brown 
1530cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo),
154cdb868f5SAxel Lin 			LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo),
155dd8e2314SAxel Lin 			selector << LDO_VOL_CONTR_SHIFT(ldo));
1560cbdf7bcSMarek Szyprowski }
1570cbdf7bcSMarek Szyprowski 
15893b84ea5SAxel Lin static const struct regulator_ops lp3971_ldo_ops = {
159cad8d76eSAxel Lin 	.list_voltage = regulator_list_voltage_table,
1603e655618SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
1610cbdf7bcSMarek Szyprowski 	.is_enabled = lp3971_ldo_is_enabled,
1620cbdf7bcSMarek Szyprowski 	.enable = lp3971_ldo_enable,
1630cbdf7bcSMarek Szyprowski 	.disable = lp3971_ldo_disable,
164f38482faSAxel Lin 	.get_voltage_sel = lp3971_ldo_get_voltage_sel,
165dd8e2314SAxel Lin 	.set_voltage_sel = lp3971_ldo_set_voltage_sel,
1660cbdf7bcSMarek Szyprowski };
1670cbdf7bcSMarek Szyprowski 
lp3971_dcdc_is_enabled(struct regulator_dev * dev)1680cbdf7bcSMarek Szyprowski static int lp3971_dcdc_is_enabled(struct regulator_dev *dev)
1690cbdf7bcSMarek Szyprowski {
1700cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1710cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
1720cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (buck * 2);
1730cbdf7bcSMarek Szyprowski 	u16 val;
1740cbdf7bcSMarek Szyprowski 
1750cbdf7bcSMarek Szyprowski 	val = lp3971_reg_read(lp3971, LP3971_BUCK_VOL_ENABLE_REG);
1760cbdf7bcSMarek Szyprowski 	return (val & mask) != 0;
1770cbdf7bcSMarek Szyprowski }
1780cbdf7bcSMarek Szyprowski 
lp3971_dcdc_enable(struct regulator_dev * dev)1790cbdf7bcSMarek Szyprowski static int lp3971_dcdc_enable(struct regulator_dev *dev)
1800cbdf7bcSMarek Szyprowski {
1810cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1820cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
1830cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (buck * 2);
1840cbdf7bcSMarek Szyprowski 
1850cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, mask);
1860cbdf7bcSMarek Szyprowski }
1870cbdf7bcSMarek Szyprowski 
lp3971_dcdc_disable(struct regulator_dev * dev)1880cbdf7bcSMarek Szyprowski static int lp3971_dcdc_disable(struct regulator_dev *dev)
1890cbdf7bcSMarek Szyprowski {
1900cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1910cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
1920cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (buck * 2);
1930cbdf7bcSMarek Szyprowski 
1940cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
1950cbdf7bcSMarek Szyprowski }
1960cbdf7bcSMarek Szyprowski 
lp3971_dcdc_get_voltage_sel(struct regulator_dev * dev)197f38482faSAxel Lin static int lp3971_dcdc_get_voltage_sel(struct regulator_dev *dev)
1980cbdf7bcSMarek Szyprowski {
1990cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
2000cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
2010cbdf7bcSMarek Szyprowski 	u16 reg;
2020cbdf7bcSMarek Szyprowski 
2030cbdf7bcSMarek Szyprowski 	reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
2040cbdf7bcSMarek Szyprowski 	reg &= BUCK_TARGET_VOL_MASK;
2050cbdf7bcSMarek Szyprowski 
206f38482faSAxel Lin 	return reg;
2070cbdf7bcSMarek Szyprowski }
2080cbdf7bcSMarek Szyprowski 
lp3971_dcdc_set_voltage_sel(struct regulator_dev * dev,unsigned int selector)209dd8e2314SAxel Lin static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
210dd8e2314SAxel Lin 				       unsigned int selector)
2110cbdf7bcSMarek Szyprowski {
2120cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
2130cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
2140cbdf7bcSMarek Szyprowski 	int ret;
2150cbdf7bcSMarek Szyprowski 
2160cbdf7bcSMarek Szyprowski 	ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck),
217dd8e2314SAxel Lin 	       BUCK_TARGET_VOL_MASK, selector);
2180cbdf7bcSMarek Szyprowski 	if (ret)
2190cbdf7bcSMarek Szyprowski 		return ret;
2200cbdf7bcSMarek Szyprowski 
2210cbdf7bcSMarek Szyprowski 	ret = lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
2220cbdf7bcSMarek Szyprowski 	       BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
2230cbdf7bcSMarek Szyprowski 	       BUCK_VOL_CHANGE_FLAG_GO << BUCK_VOL_CHANGE_SHIFT(buck));
2240cbdf7bcSMarek Szyprowski 	if (ret)
2250cbdf7bcSMarek Szyprowski 		return ret;
2260cbdf7bcSMarek Szyprowski 
2270cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
2280cbdf7bcSMarek Szyprowski 	       BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
2290cbdf7bcSMarek Szyprowski 	       0 << BUCK_VOL_CHANGE_SHIFT(buck));
2300cbdf7bcSMarek Szyprowski }
2310cbdf7bcSMarek Szyprowski 
23293b84ea5SAxel Lin static const struct regulator_ops lp3971_dcdc_ops = {
233cad8d76eSAxel Lin 	.list_voltage = regulator_list_voltage_table,
2343e655618SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
2350cbdf7bcSMarek Szyprowski 	.is_enabled = lp3971_dcdc_is_enabled,
2360cbdf7bcSMarek Szyprowski 	.enable = lp3971_dcdc_enable,
2370cbdf7bcSMarek Szyprowski 	.disable = lp3971_dcdc_disable,
238f38482faSAxel Lin 	.get_voltage_sel = lp3971_dcdc_get_voltage_sel,
239dd8e2314SAxel Lin 	.set_voltage_sel = lp3971_dcdc_set_voltage_sel,
2400cbdf7bcSMarek Szyprowski };
2410cbdf7bcSMarek Szyprowski 
24214add4ffSAxel Lin static const struct regulator_desc regulators[] = {
2430cbdf7bcSMarek Szyprowski 	{
2440cbdf7bcSMarek Szyprowski 		.name = "LDO1",
2450cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO1,
2460cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
2470cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
248cad8d76eSAxel Lin 		.volt_table = ldo123_voltage_map,
2490cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
2500cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
2510cbdf7bcSMarek Szyprowski 	},
2520cbdf7bcSMarek Szyprowski 	{
2530cbdf7bcSMarek Szyprowski 		.name = "LDO2",
2540cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO2,
2550cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
2560cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
257cad8d76eSAxel Lin 		.volt_table = ldo123_voltage_map,
2580cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
2590cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
2600cbdf7bcSMarek Szyprowski 	},
2610cbdf7bcSMarek Szyprowski 	{
2620cbdf7bcSMarek Szyprowski 		.name = "LDO3",
2630cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO3,
2640cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
2650cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
266cad8d76eSAxel Lin 		.volt_table = ldo123_voltage_map,
2670cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
2680cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
2690cbdf7bcSMarek Szyprowski 	},
2700cbdf7bcSMarek Szyprowski 	{
2710cbdf7bcSMarek Szyprowski 		.name = "LDO4",
2720cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO4,
2730cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
2740cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
275cad8d76eSAxel Lin 		.volt_table = ldo45_voltage_map,
2760cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
2770cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
2780cbdf7bcSMarek Szyprowski 	},
2790cbdf7bcSMarek Szyprowski 	{
2800cbdf7bcSMarek Szyprowski 		.name = "LDO5",
2810cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO5,
2820cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
2830cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
284cad8d76eSAxel Lin 		.volt_table = ldo45_voltage_map,
2850cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
2860cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
2870cbdf7bcSMarek Szyprowski 	},
2880cbdf7bcSMarek Szyprowski 	{
2890cbdf7bcSMarek Szyprowski 		.name = "DCDC1",
2900cbdf7bcSMarek Szyprowski 		.id = LP3971_DCDC1,
2910cbdf7bcSMarek Szyprowski 		.ops = &lp3971_dcdc_ops,
2920cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
293cad8d76eSAxel Lin 		.volt_table = buck_voltage_map,
2940cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
2950cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
2960cbdf7bcSMarek Szyprowski 	},
2970cbdf7bcSMarek Szyprowski 	{
2980cbdf7bcSMarek Szyprowski 		.name = "DCDC2",
2990cbdf7bcSMarek Szyprowski 		.id = LP3971_DCDC2,
3000cbdf7bcSMarek Szyprowski 		.ops = &lp3971_dcdc_ops,
3010cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
302cad8d76eSAxel Lin 		.volt_table = buck_voltage_map,
3030cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
3040cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3050cbdf7bcSMarek Szyprowski 	},
3060cbdf7bcSMarek Szyprowski 	{
3070cbdf7bcSMarek Szyprowski 		.name = "DCDC3",
3080cbdf7bcSMarek Szyprowski 		.id = LP3971_DCDC3,
3090cbdf7bcSMarek Szyprowski 		.ops = &lp3971_dcdc_ops,
3100cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
311cad8d76eSAxel Lin 		.volt_table = buck_voltage_map,
3120cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
3130cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3140cbdf7bcSMarek Szyprowski 	},
3150cbdf7bcSMarek Szyprowski };
3160cbdf7bcSMarek Szyprowski 
lp3971_i2c_read(struct i2c_client * i2c,char reg,int count,u16 * dest)3170cbdf7bcSMarek Szyprowski static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
3180cbdf7bcSMarek Szyprowski 	u16 *dest)
3190cbdf7bcSMarek Szyprowski {
3200cbdf7bcSMarek Szyprowski 	int ret;
3210cbdf7bcSMarek Szyprowski 
3220cbdf7bcSMarek Szyprowski 	if (count != 1)
3230cbdf7bcSMarek Szyprowski 		return -EIO;
3240cbdf7bcSMarek Szyprowski 	ret = i2c_smbus_read_byte_data(i2c, reg);
32527ef7f00SAxel Lin 	if (ret < 0)
326a1985d46SSachin Kamat 		return ret;
3270cbdf7bcSMarek Szyprowski 
3280cbdf7bcSMarek Szyprowski 	*dest = ret;
3290cbdf7bcSMarek Szyprowski 	return 0;
3300cbdf7bcSMarek Szyprowski }
3310cbdf7bcSMarek Szyprowski 
lp3971_i2c_write(struct i2c_client * i2c,char reg,int count,const u16 * src)3320cbdf7bcSMarek Szyprowski static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count,
3330cbdf7bcSMarek Szyprowski 	const u16 *src)
3340cbdf7bcSMarek Szyprowski {
3350cbdf7bcSMarek Szyprowski 	if (count != 1)
3360cbdf7bcSMarek Szyprowski 		return -EIO;
3371bddc2f5SAxel Lin 	return i2c_smbus_write_byte_data(i2c, reg, *src);
3380cbdf7bcSMarek Szyprowski }
3390cbdf7bcSMarek Szyprowski 
lp3971_reg_read(struct lp3971 * lp3971,u8 reg)3400cbdf7bcSMarek Szyprowski static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg)
3410cbdf7bcSMarek Szyprowski {
3420cbdf7bcSMarek Szyprowski 	u16 val = 0;
3430cbdf7bcSMarek Szyprowski 
3440cbdf7bcSMarek Szyprowski 	mutex_lock(&lp3971->io_lock);
3450cbdf7bcSMarek Szyprowski 
3460cbdf7bcSMarek Szyprowski 	lp3971_i2c_read(lp3971->i2c, reg, 1, &val);
3470cbdf7bcSMarek Szyprowski 
3480cbdf7bcSMarek Szyprowski 	dev_dbg(lp3971->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
3490cbdf7bcSMarek Szyprowski 		(unsigned)val&0xff);
3500cbdf7bcSMarek Szyprowski 
3510cbdf7bcSMarek Szyprowski 	mutex_unlock(&lp3971->io_lock);
3520cbdf7bcSMarek Szyprowski 
3530cbdf7bcSMarek Szyprowski 	return val & 0xff;
3540cbdf7bcSMarek Szyprowski }
3550cbdf7bcSMarek Szyprowski 
lp3971_set_bits(struct lp3971 * lp3971,u8 reg,u16 mask,u16 val)3560cbdf7bcSMarek Szyprowski static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)
3570cbdf7bcSMarek Szyprowski {
3580cbdf7bcSMarek Szyprowski 	u16 tmp;
3590cbdf7bcSMarek Szyprowski 	int ret;
3600cbdf7bcSMarek Szyprowski 
3610cbdf7bcSMarek Szyprowski 	mutex_lock(&lp3971->io_lock);
3620cbdf7bcSMarek Szyprowski 
3630cbdf7bcSMarek Szyprowski 	ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp);
3640cbdf7bcSMarek Szyprowski 	if (ret == 0) {
36540e1d79eSDan Carpenter 		tmp = (tmp & ~mask) | val;
3660cbdf7bcSMarek Szyprowski 		ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp);
3670cbdf7bcSMarek Szyprowski 		dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
3680cbdf7bcSMarek Szyprowski 			(unsigned)val&0xff);
3690cbdf7bcSMarek Szyprowski 	}
3700cbdf7bcSMarek Szyprowski 	mutex_unlock(&lp3971->io_lock);
3710cbdf7bcSMarek Szyprowski 
3720cbdf7bcSMarek Szyprowski 	return ret;
3730cbdf7bcSMarek Szyprowski }
3740cbdf7bcSMarek Szyprowski 
setup_regulators(struct lp3971 * lp3971,struct lp3971_platform_data * pdata)375a5023574SBill Pemberton static int setup_regulators(struct lp3971 *lp3971,
3760cbdf7bcSMarek Szyprowski 				      struct lp3971_platform_data *pdata)
3770cbdf7bcSMarek Szyprowski {
3780cbdf7bcSMarek Szyprowski 	int i, err;
379ebbed04fSDmitry Torokhov 
3800cbdf7bcSMarek Szyprowski 	/* Instantiate the regulators */
381ebbed04fSDmitry Torokhov 	for (i = 0; i < pdata->num_regulators; i++) {
382c172708dSMark Brown 		struct regulator_config config = { };
383ebbed04fSDmitry Torokhov 		struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
38456dde80aSAxel Lin 		struct regulator_dev *rdev;
3850cbdf7bcSMarek Szyprowski 
386c172708dSMark Brown 		config.dev = lp3971->dev;
387c172708dSMark Brown 		config.init_data = reg->initdata;
388c172708dSMark Brown 		config.driver_data = lp3971;
389c172708dSMark Brown 
39056dde80aSAxel Lin 		rdev = devm_regulator_register(lp3971->dev,
39156dde80aSAxel Lin 					       &regulators[reg->id], &config);
39256dde80aSAxel Lin 		if (IS_ERR(rdev)) {
39356dde80aSAxel Lin 			err = PTR_ERR(rdev);
3940cbdf7bcSMarek Szyprowski 			dev_err(lp3971->dev, "regulator init failed: %d\n",
3950cbdf7bcSMarek Szyprowski 				err);
39656dde80aSAxel Lin 			return err;
3970cbdf7bcSMarek Szyprowski 		}
3980cbdf7bcSMarek Szyprowski 	}
3990cbdf7bcSMarek Szyprowski 
4000cbdf7bcSMarek Szyprowski 	return 0;
4010cbdf7bcSMarek Szyprowski }
4020cbdf7bcSMarek Szyprowski 
lp3971_i2c_probe(struct i2c_client * i2c)40377e29598SAxel Lin static int lp3971_i2c_probe(struct i2c_client *i2c)
4040cbdf7bcSMarek Szyprowski {
4050cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971;
406dff91d0bSJingoo Han 	struct lp3971_platform_data *pdata = dev_get_platdata(&i2c->dev);
4070cbdf7bcSMarek Szyprowski 	int ret;
4080cbdf7bcSMarek Szyprowski 	u16 val;
4090cbdf7bcSMarek Szyprowski 
410ebbed04fSDmitry Torokhov 	if (!pdata) {
411ebbed04fSDmitry Torokhov 		dev_dbg(&i2c->dev, "No platform init data supplied\n");
412ebbed04fSDmitry Torokhov 		return -ENODEV;
4130cbdf7bcSMarek Szyprowski 	}
4140cbdf7bcSMarek Szyprowski 
4152af0af67SNikolay Balandin 	lp3971 = devm_kzalloc(&i2c->dev, sizeof(struct lp3971), GFP_KERNEL);
416ebbed04fSDmitry Torokhov 	if (lp3971 == NULL)
417ebbed04fSDmitry Torokhov 		return -ENOMEM;
418ebbed04fSDmitry Torokhov 
4190cbdf7bcSMarek Szyprowski 	lp3971->i2c = i2c;
4200cbdf7bcSMarek Szyprowski 	lp3971->dev = &i2c->dev;
4210cbdf7bcSMarek Szyprowski 
4220cbdf7bcSMarek Szyprowski 	mutex_init(&lp3971->io_lock);
4230cbdf7bcSMarek Szyprowski 
4240cbdf7bcSMarek Szyprowski 	/* Detect LP3971 */
4250cbdf7bcSMarek Szyprowski 	ret = lp3971_i2c_read(i2c, LP3971_SYS_CONTROL1_REG, 1, &val);
4260cbdf7bcSMarek Szyprowski 	if (ret == 0 && (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL)
4270cbdf7bcSMarek Szyprowski 		ret = -ENODEV;
4280cbdf7bcSMarek Szyprowski 	if (ret < 0) {
4290cbdf7bcSMarek Szyprowski 		dev_err(&i2c->dev, "failed to detect device\n");
4302af0af67SNikolay Balandin 		return ret;
4310cbdf7bcSMarek Szyprowski 	}
4320cbdf7bcSMarek Szyprowski 
4330cbdf7bcSMarek Szyprowski 	ret = setup_regulators(lp3971, pdata);
4340cbdf7bcSMarek Szyprowski 	if (ret < 0)
4352af0af67SNikolay Balandin 		return ret;
4360cbdf7bcSMarek Szyprowski 
437ebbed04fSDmitry Torokhov 	i2c_set_clientdata(i2c, lp3971);
4380cbdf7bcSMarek Szyprowski 	return 0;
4390cbdf7bcSMarek Szyprowski }
4400cbdf7bcSMarek Szyprowski 
4410cbdf7bcSMarek Szyprowski static const struct i2c_device_id lp3971_i2c_id[] = {
4420cbdf7bcSMarek Szyprowski 	{ "lp3971", 0 },
4430cbdf7bcSMarek Szyprowski 	{ }
4440cbdf7bcSMarek Szyprowski };
4450cbdf7bcSMarek Szyprowski MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id);
4460cbdf7bcSMarek Szyprowski 
4470cbdf7bcSMarek Szyprowski static struct i2c_driver lp3971_i2c_driver = {
4480cbdf7bcSMarek Szyprowski 	.driver = {
4490cbdf7bcSMarek Szyprowski 		.name = "LP3971",
450259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
4510cbdf7bcSMarek Szyprowski 	},
452*964e1865SUwe Kleine-König 	.probe = lp3971_i2c_probe,
4530cbdf7bcSMarek Szyprowski 	.id_table = lp3971_i2c_id,
4540cbdf7bcSMarek Szyprowski };
4550cbdf7bcSMarek Szyprowski 
4565af34e60SMark Brown module_i2c_driver(lp3971_i2c_driver);
4570cbdf7bcSMarek Szyprowski 
4580cbdf7bcSMarek Szyprowski MODULE_LICENSE("GPL");
4590cbdf7bcSMarek Szyprowski MODULE_AUTHOR("Marek Szyprowski <m.szyprowski@samsung.com>");
4600cbdf7bcSMarek Szyprowski MODULE_DESCRIPTION("LP3971 PMIC driver");
461