xref: /openbmc/linux/drivers/regulator/lp3971.c (revision dd8e2314)
10cbdf7bcSMarek Szyprowski /*
20cbdf7bcSMarek Szyprowski  * Regulator driver for National Semiconductors LP3971 PMIC chip
30cbdf7bcSMarek Szyprowski  *
40cbdf7bcSMarek Szyprowski  *  Copyright (C) 2009 Samsung Electronics
50cbdf7bcSMarek Szyprowski  *  Author: Marek Szyprowski <m.szyprowski@samsung.com>
60cbdf7bcSMarek Szyprowski  *
70cbdf7bcSMarek Szyprowski  * Based on wm8350.c
80cbdf7bcSMarek Szyprowski  *
90cbdf7bcSMarek Szyprowski  * This program is free software; you can redistribute it and/or modify
100cbdf7bcSMarek Szyprowski  * it under the terms of the GNU General Public License version 2 as
110cbdf7bcSMarek Szyprowski  * published by the Free Software Foundation.
120cbdf7bcSMarek Szyprowski  *
130cbdf7bcSMarek Szyprowski  */
140cbdf7bcSMarek Szyprowski 
150cbdf7bcSMarek Szyprowski #include <linux/bug.h>
160cbdf7bcSMarek Szyprowski #include <linux/err.h>
170cbdf7bcSMarek Szyprowski #include <linux/i2c.h>
180cbdf7bcSMarek Szyprowski #include <linux/kernel.h>
1965602c32SPaul Gortmaker #include <linux/module.h>
200cbdf7bcSMarek Szyprowski #include <linux/regulator/driver.h>
210cbdf7bcSMarek Szyprowski #include <linux/regulator/lp3971.h>
225a0e3ad6STejun Heo #include <linux/slab.h>
230cbdf7bcSMarek Szyprowski 
240cbdf7bcSMarek Szyprowski struct lp3971 {
250cbdf7bcSMarek Szyprowski 	struct device *dev;
260cbdf7bcSMarek Szyprowski 	struct mutex io_lock;
270cbdf7bcSMarek Szyprowski 	struct i2c_client *i2c;
280cbdf7bcSMarek Szyprowski 	int num_regulators;
290cbdf7bcSMarek Szyprowski 	struct regulator_dev **rdev;
300cbdf7bcSMarek Szyprowski };
310cbdf7bcSMarek Szyprowski 
320cbdf7bcSMarek Szyprowski static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg);
330cbdf7bcSMarek Szyprowski static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val);
340cbdf7bcSMarek Szyprowski 
350cbdf7bcSMarek Szyprowski #define LP3971_SYS_CONTROL1_REG 0x07
360cbdf7bcSMarek Szyprowski 
370cbdf7bcSMarek Szyprowski /* System control register 1 initial value,
380cbdf7bcSMarek Szyprowski    bits 4 and 5 are EPROM programmable */
390cbdf7bcSMarek Szyprowski #define SYS_CONTROL1_INIT_VAL 0x40
400cbdf7bcSMarek Szyprowski #define SYS_CONTROL1_INIT_MASK 0xCF
410cbdf7bcSMarek Szyprowski 
420cbdf7bcSMarek Szyprowski #define LP3971_BUCK_VOL_ENABLE_REG 0x10
430cbdf7bcSMarek Szyprowski #define LP3971_BUCK_VOL_CHANGE_REG 0x20
440cbdf7bcSMarek Szyprowski 
450cbdf7bcSMarek Szyprowski /*	Voltage control registers shift:
460cbdf7bcSMarek Szyprowski 	LP3971_BUCK1 -> 0
470cbdf7bcSMarek Szyprowski 	LP3971_BUCK2 -> 4
480cbdf7bcSMarek Szyprowski 	LP3971_BUCK3 -> 6
490cbdf7bcSMarek Szyprowski */
50451a73cdSAxel Lin #define BUCK_VOL_CHANGE_SHIFT(x) (((!!x) << 2) | (x & ~0x01))
510cbdf7bcSMarek Szyprowski #define BUCK_VOL_CHANGE_FLAG_GO 0x01
520cbdf7bcSMarek Szyprowski #define BUCK_VOL_CHANGE_FLAG_TARGET 0x02
530cbdf7bcSMarek Szyprowski #define BUCK_VOL_CHANGE_FLAG_MASK 0x03
540cbdf7bcSMarek Szyprowski 
550cbdf7bcSMarek Szyprowski #define LP3971_BUCK1_BASE 0x23
560cbdf7bcSMarek Szyprowski #define LP3971_BUCK2_BASE 0x29
570cbdf7bcSMarek Szyprowski #define LP3971_BUCK3_BASE 0x32
580cbdf7bcSMarek Szyprowski 
596faa7e0aSTobias Klauser static const int buck_base_addr[] = {
600cbdf7bcSMarek Szyprowski 	LP3971_BUCK1_BASE,
610cbdf7bcSMarek Szyprowski 	LP3971_BUCK2_BASE,
620cbdf7bcSMarek Szyprowski 	LP3971_BUCK3_BASE,
630cbdf7bcSMarek Szyprowski };
640cbdf7bcSMarek Szyprowski 
650cbdf7bcSMarek Szyprowski #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
660cbdf7bcSMarek Szyprowski #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
670cbdf7bcSMarek Szyprowski 
686faa7e0aSTobias Klauser static const int buck_voltage_map[] = {
690cbdf7bcSMarek Szyprowski 	   0,  800,  850,  900,  950, 1000, 1050, 1100,
700cbdf7bcSMarek Szyprowski 	1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
710cbdf7bcSMarek Szyprowski 	1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
720cbdf7bcSMarek Szyprowski 	3000, 3300,
730cbdf7bcSMarek Szyprowski };
740cbdf7bcSMarek Szyprowski 
750cbdf7bcSMarek Szyprowski #define BUCK_TARGET_VOL_MASK 0x3f
760cbdf7bcSMarek Szyprowski #define BUCK_TARGET_VOL_MIN_IDX 0x01
770cbdf7bcSMarek Szyprowski #define BUCK_TARGET_VOL_MAX_IDX 0x19
780cbdf7bcSMarek Szyprowski 
790cbdf7bcSMarek Szyprowski #define LP3971_BUCK_RAMP_REG(x)	(buck_base_addr[x]+2)
800cbdf7bcSMarek Szyprowski 
810cbdf7bcSMarek Szyprowski #define LP3971_LDO_ENABLE_REG 0x12
820cbdf7bcSMarek Szyprowski #define LP3971_LDO_VOL_CONTR_BASE 0x39
830cbdf7bcSMarek Szyprowski 
840cbdf7bcSMarek Szyprowski /*	Voltage control registers:
850cbdf7bcSMarek Szyprowski 	LP3971_LDO1 -> LP3971_LDO_VOL_CONTR_BASE + 0
860cbdf7bcSMarek Szyprowski 	LP3971_LDO2 -> LP3971_LDO_VOL_CONTR_BASE + 0
870cbdf7bcSMarek Szyprowski 	LP3971_LDO3 -> LP3971_LDO_VOL_CONTR_BASE + 1
880cbdf7bcSMarek Szyprowski 	LP3971_LDO4 -> LP3971_LDO_VOL_CONTR_BASE + 1
890cbdf7bcSMarek Szyprowski 	LP3971_LDO5 -> LP3971_LDO_VOL_CONTR_BASE + 2
900cbdf7bcSMarek Szyprowski */
910cbdf7bcSMarek Szyprowski #define LP3971_LDO_VOL_CONTR_REG(x)	(LP3971_LDO_VOL_CONTR_BASE + (x >> 1))
920cbdf7bcSMarek Szyprowski 
930cbdf7bcSMarek Szyprowski /*	Voltage control registers shift:
940cbdf7bcSMarek Szyprowski 	LP3971_LDO1 -> 0, LP3971_LDO2 -> 4
950cbdf7bcSMarek Szyprowski 	LP3971_LDO3 -> 0, LP3971_LDO4 -> 4
960cbdf7bcSMarek Szyprowski 	LP3971_LDO5 -> 0
970cbdf7bcSMarek Szyprowski */
980cbdf7bcSMarek Szyprowski #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
990cbdf7bcSMarek Szyprowski #define LDO_VOL_CONTR_MASK 0x0f
1000cbdf7bcSMarek Szyprowski 
1016faa7e0aSTobias Klauser static const int ldo45_voltage_map[] = {
1020cbdf7bcSMarek Szyprowski 	1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
1030cbdf7bcSMarek Szyprowski 	1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
1040cbdf7bcSMarek Szyprowski };
1050cbdf7bcSMarek Szyprowski 
1066faa7e0aSTobias Klauser static const int ldo123_voltage_map[] = {
1070cbdf7bcSMarek Szyprowski 	1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
1080cbdf7bcSMarek Szyprowski 	2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
1090cbdf7bcSMarek Szyprowski };
1100cbdf7bcSMarek Szyprowski 
1116faa7e0aSTobias Klauser static const int *ldo_voltage_map[] = {
1120cbdf7bcSMarek Szyprowski 	ldo123_voltage_map, /* LDO1 */
1130cbdf7bcSMarek Szyprowski 	ldo123_voltage_map, /* LDO2 */
1140cbdf7bcSMarek Szyprowski 	ldo123_voltage_map, /* LDO3 */
1150cbdf7bcSMarek Szyprowski 	ldo45_voltage_map, /* LDO4 */
1160cbdf7bcSMarek Szyprowski 	ldo45_voltage_map, /* LDO5 */
1170cbdf7bcSMarek Szyprowski };
1180cbdf7bcSMarek Szyprowski 
1190cbdf7bcSMarek Szyprowski #define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)])
1200cbdf7bcSMarek Szyprowski 
1210cbdf7bcSMarek Szyprowski #define LDO_VOL_MIN_IDX 0x00
1220cbdf7bcSMarek Szyprowski #define LDO_VOL_MAX_IDX 0x0f
1230cbdf7bcSMarek Szyprowski 
1240cbdf7bcSMarek Szyprowski static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
1250cbdf7bcSMarek Szyprowski {
1260cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
127dd8e2314SAxel Lin 
128dd8e2314SAxel Lin 	if (index > LDO_VOL_MAX_IDX)
129dd8e2314SAxel Lin 		return -EINVAL;
130dd8e2314SAxel Lin 
1310cbdf7bcSMarek Szyprowski 	return 1000 * LDO_VOL_VALUE_MAP(ldo)[index];
1320cbdf7bcSMarek Szyprowski }
1330cbdf7bcSMarek Szyprowski 
1340cbdf7bcSMarek Szyprowski static int lp3971_ldo_is_enabled(struct regulator_dev *dev)
1350cbdf7bcSMarek Szyprowski {
1360cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1370cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1380cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (1 + ldo);
1390cbdf7bcSMarek Szyprowski 	u16 val;
1400cbdf7bcSMarek Szyprowski 
1410cbdf7bcSMarek Szyprowski 	val = lp3971_reg_read(lp3971, LP3971_LDO_ENABLE_REG);
1420cbdf7bcSMarek Szyprowski 	return (val & mask) != 0;
1430cbdf7bcSMarek Szyprowski }
1440cbdf7bcSMarek Szyprowski 
1450cbdf7bcSMarek Szyprowski static int lp3971_ldo_enable(struct regulator_dev *dev)
1460cbdf7bcSMarek Szyprowski {
1470cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1480cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1490cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (1 + ldo);
1500cbdf7bcSMarek Szyprowski 
1510cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, mask);
1520cbdf7bcSMarek Szyprowski }
1530cbdf7bcSMarek Szyprowski 
1540cbdf7bcSMarek Szyprowski static int lp3971_ldo_disable(struct regulator_dev *dev)
1550cbdf7bcSMarek Szyprowski {
1560cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1570cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1580cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (1 + ldo);
1590cbdf7bcSMarek Szyprowski 
1600cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
1610cbdf7bcSMarek Szyprowski }
1620cbdf7bcSMarek Szyprowski 
1630cbdf7bcSMarek Szyprowski static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
1640cbdf7bcSMarek Szyprowski {
1650cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1660cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1670cbdf7bcSMarek Szyprowski 	u16 val, reg;
1680cbdf7bcSMarek Szyprowski 
1690cbdf7bcSMarek Szyprowski 	reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
1700cbdf7bcSMarek Szyprowski 	val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
1710cbdf7bcSMarek Szyprowski 
1720cbdf7bcSMarek Szyprowski 	return 1000 * LDO_VOL_VALUE_MAP(ldo)[val];
1730cbdf7bcSMarek Szyprowski }
1740cbdf7bcSMarek Szyprowski 
175dd8e2314SAxel Lin static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
176dd8e2314SAxel Lin 				      unsigned int selector)
1770cbdf7bcSMarek Szyprowski {
1780cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
1790cbdf7bcSMarek Szyprowski 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
1803a93f2a9SMark Brown 
1810cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo),
182cdb868f5SAxel Lin 			LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo),
183dd8e2314SAxel Lin 			selector << LDO_VOL_CONTR_SHIFT(ldo));
1840cbdf7bcSMarek Szyprowski }
1850cbdf7bcSMarek Szyprowski 
1860cbdf7bcSMarek Szyprowski static struct regulator_ops lp3971_ldo_ops = {
1870cbdf7bcSMarek Szyprowski 	.list_voltage = lp3971_ldo_list_voltage,
1880cbdf7bcSMarek Szyprowski 	.is_enabled = lp3971_ldo_is_enabled,
1890cbdf7bcSMarek Szyprowski 	.enable = lp3971_ldo_enable,
1900cbdf7bcSMarek Szyprowski 	.disable = lp3971_ldo_disable,
1910cbdf7bcSMarek Szyprowski 	.get_voltage = lp3971_ldo_get_voltage,
192dd8e2314SAxel Lin 	.set_voltage_sel = lp3971_ldo_set_voltage_sel,
1930cbdf7bcSMarek Szyprowski };
1940cbdf7bcSMarek Szyprowski 
1950cbdf7bcSMarek Szyprowski static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
1960cbdf7bcSMarek Szyprowski {
197dd8e2314SAxel Lin 	if (index < BUCK_TARGET_VOL_MIN_IDX || index > BUCK_TARGET_VOL_MAX_IDX)
198dd8e2314SAxel Lin 		return -EINVAL;
199dd8e2314SAxel Lin 
2000cbdf7bcSMarek Szyprowski 	return 1000 * buck_voltage_map[index];
2010cbdf7bcSMarek Szyprowski }
2020cbdf7bcSMarek Szyprowski 
2030cbdf7bcSMarek Szyprowski static int lp3971_dcdc_is_enabled(struct regulator_dev *dev)
2040cbdf7bcSMarek Szyprowski {
2050cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
2060cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
2070cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (buck * 2);
2080cbdf7bcSMarek Szyprowski 	u16 val;
2090cbdf7bcSMarek Szyprowski 
2100cbdf7bcSMarek Szyprowski 	val = lp3971_reg_read(lp3971, LP3971_BUCK_VOL_ENABLE_REG);
2110cbdf7bcSMarek Szyprowski 	return (val & mask) != 0;
2120cbdf7bcSMarek Szyprowski }
2130cbdf7bcSMarek Szyprowski 
2140cbdf7bcSMarek Szyprowski static int lp3971_dcdc_enable(struct regulator_dev *dev)
2150cbdf7bcSMarek Szyprowski {
2160cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
2170cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
2180cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (buck * 2);
2190cbdf7bcSMarek Szyprowski 
2200cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, mask);
2210cbdf7bcSMarek Szyprowski }
2220cbdf7bcSMarek Szyprowski 
2230cbdf7bcSMarek Szyprowski static int lp3971_dcdc_disable(struct regulator_dev *dev)
2240cbdf7bcSMarek Szyprowski {
2250cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
2260cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
2270cbdf7bcSMarek Szyprowski 	u16 mask = 1 << (buck * 2);
2280cbdf7bcSMarek Szyprowski 
2290cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
2300cbdf7bcSMarek Szyprowski }
2310cbdf7bcSMarek Szyprowski 
2320cbdf7bcSMarek Szyprowski static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
2330cbdf7bcSMarek Szyprowski {
2340cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
2350cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
2360cbdf7bcSMarek Szyprowski 	u16 reg;
2370cbdf7bcSMarek Szyprowski 	int val;
2380cbdf7bcSMarek Szyprowski 
2390cbdf7bcSMarek Szyprowski 	reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
2400cbdf7bcSMarek Szyprowski 	reg &= BUCK_TARGET_VOL_MASK;
2410cbdf7bcSMarek Szyprowski 
2420cbdf7bcSMarek Szyprowski 	if (reg <= BUCK_TARGET_VOL_MAX_IDX)
2430cbdf7bcSMarek Szyprowski 		val = 1000 * buck_voltage_map[reg];
2440cbdf7bcSMarek Szyprowski 	else {
2450cbdf7bcSMarek Szyprowski 		val = 0;
2460cbdf7bcSMarek Szyprowski 		dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
2470cbdf7bcSMarek Szyprowski 	}
2480cbdf7bcSMarek Szyprowski 
2490cbdf7bcSMarek Szyprowski 	return val;
2500cbdf7bcSMarek Szyprowski }
2510cbdf7bcSMarek Szyprowski 
252dd8e2314SAxel Lin static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
253dd8e2314SAxel Lin 				       unsigned int selector)
2540cbdf7bcSMarek Szyprowski {
2550cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
2560cbdf7bcSMarek Szyprowski 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
2570cbdf7bcSMarek Szyprowski 	int ret;
2580cbdf7bcSMarek Szyprowski 
2590cbdf7bcSMarek Szyprowski 	ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck),
260dd8e2314SAxel Lin 	       BUCK_TARGET_VOL_MASK, selector);
2610cbdf7bcSMarek Szyprowski 	if (ret)
2620cbdf7bcSMarek Szyprowski 		return ret;
2630cbdf7bcSMarek Szyprowski 
2640cbdf7bcSMarek Szyprowski 	ret = lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
2650cbdf7bcSMarek Szyprowski 	       BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
2660cbdf7bcSMarek Szyprowski 	       BUCK_VOL_CHANGE_FLAG_GO << BUCK_VOL_CHANGE_SHIFT(buck));
2670cbdf7bcSMarek Szyprowski 	if (ret)
2680cbdf7bcSMarek Szyprowski 		return ret;
2690cbdf7bcSMarek Szyprowski 
2700cbdf7bcSMarek Szyprowski 	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
2710cbdf7bcSMarek Szyprowski 	       BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
2720cbdf7bcSMarek Szyprowski 	       0 << BUCK_VOL_CHANGE_SHIFT(buck));
2730cbdf7bcSMarek Szyprowski }
2740cbdf7bcSMarek Szyprowski 
2750cbdf7bcSMarek Szyprowski static struct regulator_ops lp3971_dcdc_ops = {
2760cbdf7bcSMarek Szyprowski 	.list_voltage = lp3971_dcdc_list_voltage,
2770cbdf7bcSMarek Szyprowski 	.is_enabled = lp3971_dcdc_is_enabled,
2780cbdf7bcSMarek Szyprowski 	.enable = lp3971_dcdc_enable,
2790cbdf7bcSMarek Szyprowski 	.disable = lp3971_dcdc_disable,
2800cbdf7bcSMarek Szyprowski 	.get_voltage = lp3971_dcdc_get_voltage,
281dd8e2314SAxel Lin 	.set_voltage_sel = lp3971_dcdc_set_voltage_sel,
2820cbdf7bcSMarek Szyprowski };
2830cbdf7bcSMarek Szyprowski 
2840cbdf7bcSMarek Szyprowski static struct regulator_desc regulators[] = {
2850cbdf7bcSMarek Szyprowski 	{
2860cbdf7bcSMarek Szyprowski 		.name = "LDO1",
2870cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO1,
2880cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
2890cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
2900cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
2910cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
2920cbdf7bcSMarek Szyprowski 	},
2930cbdf7bcSMarek Szyprowski 	{
2940cbdf7bcSMarek Szyprowski 		.name = "LDO2",
2950cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO2,
2960cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
2970cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
2980cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
2990cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3000cbdf7bcSMarek Szyprowski 	},
3010cbdf7bcSMarek Szyprowski 	{
3020cbdf7bcSMarek Szyprowski 		.name = "LDO3",
3030cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO3,
3040cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
3050cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
3060cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
3070cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3080cbdf7bcSMarek Szyprowski 	},
3090cbdf7bcSMarek Szyprowski 	{
3100cbdf7bcSMarek Szyprowski 		.name = "LDO4",
3110cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO4,
3120cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
3130cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
3140cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
3150cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3160cbdf7bcSMarek Szyprowski 	},
3170cbdf7bcSMarek Szyprowski 	{
3180cbdf7bcSMarek Szyprowski 		.name = "LDO5",
3190cbdf7bcSMarek Szyprowski 		.id = LP3971_LDO5,
3200cbdf7bcSMarek Szyprowski 		.ops = &lp3971_ldo_ops,
3210cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
3220cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
3230cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3240cbdf7bcSMarek Szyprowski 	},
3250cbdf7bcSMarek Szyprowski 	{
3260cbdf7bcSMarek Szyprowski 		.name = "DCDC1",
3270cbdf7bcSMarek Szyprowski 		.id = LP3971_DCDC1,
3280cbdf7bcSMarek Szyprowski 		.ops = &lp3971_dcdc_ops,
3290cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
3300cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
3310cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3320cbdf7bcSMarek Szyprowski 	},
3330cbdf7bcSMarek Szyprowski 	{
3340cbdf7bcSMarek Szyprowski 		.name = "DCDC2",
3350cbdf7bcSMarek Szyprowski 		.id = LP3971_DCDC2,
3360cbdf7bcSMarek Szyprowski 		.ops = &lp3971_dcdc_ops,
3370cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
3380cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
3390cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3400cbdf7bcSMarek Szyprowski 	},
3410cbdf7bcSMarek Szyprowski 	{
3420cbdf7bcSMarek Szyprowski 		.name = "DCDC3",
3430cbdf7bcSMarek Szyprowski 		.id = LP3971_DCDC3,
3440cbdf7bcSMarek Szyprowski 		.ops = &lp3971_dcdc_ops,
3450cbdf7bcSMarek Szyprowski 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
3460cbdf7bcSMarek Szyprowski 		.type = REGULATOR_VOLTAGE,
3470cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
3480cbdf7bcSMarek Szyprowski 	},
3490cbdf7bcSMarek Szyprowski };
3500cbdf7bcSMarek Szyprowski 
3510cbdf7bcSMarek Szyprowski static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
3520cbdf7bcSMarek Szyprowski 	u16 *dest)
3530cbdf7bcSMarek Szyprowski {
3540cbdf7bcSMarek Szyprowski 	int ret;
3550cbdf7bcSMarek Szyprowski 
3560cbdf7bcSMarek Szyprowski 	if (count != 1)
3570cbdf7bcSMarek Szyprowski 		return -EIO;
3580cbdf7bcSMarek Szyprowski 	ret = i2c_smbus_read_byte_data(i2c, reg);
35927ef7f00SAxel Lin 	if (ret < 0)
3600cbdf7bcSMarek Szyprowski 		return -EIO;
3610cbdf7bcSMarek Szyprowski 
3620cbdf7bcSMarek Szyprowski 	*dest = ret;
3630cbdf7bcSMarek Szyprowski 	return 0;
3640cbdf7bcSMarek Szyprowski }
3650cbdf7bcSMarek Szyprowski 
3660cbdf7bcSMarek Szyprowski static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count,
3670cbdf7bcSMarek Szyprowski 	const u16 *src)
3680cbdf7bcSMarek Szyprowski {
3690cbdf7bcSMarek Szyprowski 	if (count != 1)
3700cbdf7bcSMarek Szyprowski 		return -EIO;
3711bddc2f5SAxel Lin 	return i2c_smbus_write_byte_data(i2c, reg, *src);
3720cbdf7bcSMarek Szyprowski }
3730cbdf7bcSMarek Szyprowski 
3740cbdf7bcSMarek Szyprowski static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg)
3750cbdf7bcSMarek Szyprowski {
3760cbdf7bcSMarek Szyprowski 	u16 val = 0;
3770cbdf7bcSMarek Szyprowski 
3780cbdf7bcSMarek Szyprowski 	mutex_lock(&lp3971->io_lock);
3790cbdf7bcSMarek Szyprowski 
3800cbdf7bcSMarek Szyprowski 	lp3971_i2c_read(lp3971->i2c, reg, 1, &val);
3810cbdf7bcSMarek Szyprowski 
3820cbdf7bcSMarek Szyprowski 	dev_dbg(lp3971->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
3830cbdf7bcSMarek Szyprowski 		(unsigned)val&0xff);
3840cbdf7bcSMarek Szyprowski 
3850cbdf7bcSMarek Szyprowski 	mutex_unlock(&lp3971->io_lock);
3860cbdf7bcSMarek Szyprowski 
3870cbdf7bcSMarek Szyprowski 	return val & 0xff;
3880cbdf7bcSMarek Szyprowski }
3890cbdf7bcSMarek Szyprowski 
3900cbdf7bcSMarek Szyprowski static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)
3910cbdf7bcSMarek Szyprowski {
3920cbdf7bcSMarek Szyprowski 	u16 tmp;
3930cbdf7bcSMarek Szyprowski 	int ret;
3940cbdf7bcSMarek Szyprowski 
3950cbdf7bcSMarek Szyprowski 	mutex_lock(&lp3971->io_lock);
3960cbdf7bcSMarek Szyprowski 
3970cbdf7bcSMarek Szyprowski 	ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp);
3980cbdf7bcSMarek Szyprowski 	tmp = (tmp & ~mask) | val;
3990cbdf7bcSMarek Szyprowski 	if (ret == 0) {
4000cbdf7bcSMarek Szyprowski 		ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp);
4010cbdf7bcSMarek Szyprowski 		dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
4020cbdf7bcSMarek Szyprowski 			(unsigned)val&0xff);
4030cbdf7bcSMarek Szyprowski 	}
4040cbdf7bcSMarek Szyprowski 	mutex_unlock(&lp3971->io_lock);
4050cbdf7bcSMarek Szyprowski 
4060cbdf7bcSMarek Szyprowski 	return ret;
4070cbdf7bcSMarek Szyprowski }
4080cbdf7bcSMarek Szyprowski 
409ebbed04fSDmitry Torokhov static int __devinit setup_regulators(struct lp3971 *lp3971,
4100cbdf7bcSMarek Szyprowski 				      struct lp3971_platform_data *pdata)
4110cbdf7bcSMarek Szyprowski {
4120cbdf7bcSMarek Szyprowski 	int i, err;
413ebbed04fSDmitry Torokhov 
414ebbed04fSDmitry Torokhov 	lp3971->num_regulators = pdata->num_regulators;
415ebbed04fSDmitry Torokhov 	lp3971->rdev = kcalloc(pdata->num_regulators,
416ebbed04fSDmitry Torokhov 				sizeof(struct regulator_dev *), GFP_KERNEL);
41767e46f34SDan Carpenter 	if (!lp3971->rdev) {
41867e46f34SDan Carpenter 		err = -ENOMEM;
41967e46f34SDan Carpenter 		goto err_nomem;
42067e46f34SDan Carpenter 	}
4210cbdf7bcSMarek Szyprowski 
4220cbdf7bcSMarek Szyprowski 	/* Instantiate the regulators */
423ebbed04fSDmitry Torokhov 	for (i = 0; i < pdata->num_regulators; i++) {
424ebbed04fSDmitry Torokhov 		struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
425ebbed04fSDmitry Torokhov 		lp3971->rdev[i] = regulator_register(&regulators[reg->id],
4262c043bcbSRajendra Nayak 				lp3971->dev, reg->initdata, lp3971, NULL);
4270cbdf7bcSMarek Szyprowski 
428d662fc82SJulia Lawall 		if (IS_ERR(lp3971->rdev[i])) {
429d662fc82SJulia Lawall 			err = PTR_ERR(lp3971->rdev[i]);
4300cbdf7bcSMarek Szyprowski 			dev_err(lp3971->dev, "regulator init failed: %d\n",
4310cbdf7bcSMarek Szyprowski 				err);
4320cbdf7bcSMarek Szyprowski 			goto error;
4330cbdf7bcSMarek Szyprowski 		}
4340cbdf7bcSMarek Szyprowski 	}
4350cbdf7bcSMarek Szyprowski 
4360cbdf7bcSMarek Szyprowski 	return 0;
437ebbed04fSDmitry Torokhov 
4380cbdf7bcSMarek Szyprowski error:
439ebbed04fSDmitry Torokhov 	while (--i >= 0)
4400cbdf7bcSMarek Szyprowski 		regulator_unregister(lp3971->rdev[i]);
4410cbdf7bcSMarek Szyprowski 	kfree(lp3971->rdev);
4420cbdf7bcSMarek Szyprowski 	lp3971->rdev = NULL;
44367e46f34SDan Carpenter err_nomem:
4440cbdf7bcSMarek Szyprowski 	return err;
4450cbdf7bcSMarek Szyprowski }
4460cbdf7bcSMarek Szyprowski 
4470cbdf7bcSMarek Szyprowski static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,
4480cbdf7bcSMarek Szyprowski 			    const struct i2c_device_id *id)
4490cbdf7bcSMarek Szyprowski {
4500cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971;
4510cbdf7bcSMarek Szyprowski 	struct lp3971_platform_data *pdata = i2c->dev.platform_data;
4520cbdf7bcSMarek Szyprowski 	int ret;
4530cbdf7bcSMarek Szyprowski 	u16 val;
4540cbdf7bcSMarek Szyprowski 
455ebbed04fSDmitry Torokhov 	if (!pdata) {
456ebbed04fSDmitry Torokhov 		dev_dbg(&i2c->dev, "No platform init data supplied\n");
457ebbed04fSDmitry Torokhov 		return -ENODEV;
4580cbdf7bcSMarek Szyprowski 	}
4590cbdf7bcSMarek Szyprowski 
460ebbed04fSDmitry Torokhov 	lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL);
461ebbed04fSDmitry Torokhov 	if (lp3971 == NULL)
462ebbed04fSDmitry Torokhov 		return -ENOMEM;
463ebbed04fSDmitry Torokhov 
4640cbdf7bcSMarek Szyprowski 	lp3971->i2c = i2c;
4650cbdf7bcSMarek Szyprowski 	lp3971->dev = &i2c->dev;
4660cbdf7bcSMarek Szyprowski 
4670cbdf7bcSMarek Szyprowski 	mutex_init(&lp3971->io_lock);
4680cbdf7bcSMarek Szyprowski 
4690cbdf7bcSMarek Szyprowski 	/* Detect LP3971 */
4700cbdf7bcSMarek Szyprowski 	ret = lp3971_i2c_read(i2c, LP3971_SYS_CONTROL1_REG, 1, &val);
4710cbdf7bcSMarek Szyprowski 	if (ret == 0 && (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL)
4720cbdf7bcSMarek Szyprowski 		ret = -ENODEV;
4730cbdf7bcSMarek Szyprowski 	if (ret < 0) {
4740cbdf7bcSMarek Szyprowski 		dev_err(&i2c->dev, "failed to detect device\n");
4750cbdf7bcSMarek Szyprowski 		goto err_detect;
4760cbdf7bcSMarek Szyprowski 	}
4770cbdf7bcSMarek Szyprowski 
4780cbdf7bcSMarek Szyprowski 	ret = setup_regulators(lp3971, pdata);
4790cbdf7bcSMarek Szyprowski 	if (ret < 0)
4800cbdf7bcSMarek Szyprowski 		goto err_detect;
4810cbdf7bcSMarek Szyprowski 
482ebbed04fSDmitry Torokhov 	i2c_set_clientdata(i2c, lp3971);
4830cbdf7bcSMarek Szyprowski 	return 0;
4840cbdf7bcSMarek Szyprowski 
4850cbdf7bcSMarek Szyprowski err_detect:
4860cbdf7bcSMarek Szyprowski 	kfree(lp3971);
4870cbdf7bcSMarek Szyprowski 	return ret;
4880cbdf7bcSMarek Szyprowski }
4890cbdf7bcSMarek Szyprowski 
4900cbdf7bcSMarek Szyprowski static int __devexit lp3971_i2c_remove(struct i2c_client *i2c)
4910cbdf7bcSMarek Szyprowski {
4920cbdf7bcSMarek Szyprowski 	struct lp3971 *lp3971 = i2c_get_clientdata(i2c);
4930cbdf7bcSMarek Szyprowski 	int i;
494ebbed04fSDmitry Torokhov 
495ebbed04fSDmitry Torokhov 	for (i = 0; i < lp3971->num_regulators; i++)
496ebbed04fSDmitry Torokhov 		regulator_unregister(lp3971->rdev[i]);
497ebbed04fSDmitry Torokhov 
498ebbed04fSDmitry Torokhov 	kfree(lp3971->rdev);
4990cbdf7bcSMarek Szyprowski 	kfree(lp3971);
5000cbdf7bcSMarek Szyprowski 
5010cbdf7bcSMarek Szyprowski 	return 0;
5020cbdf7bcSMarek Szyprowski }
5030cbdf7bcSMarek Szyprowski 
5040cbdf7bcSMarek Szyprowski static const struct i2c_device_id lp3971_i2c_id[] = {
5050cbdf7bcSMarek Szyprowski        { "lp3971", 0 },
5060cbdf7bcSMarek Szyprowski        { }
5070cbdf7bcSMarek Szyprowski };
5080cbdf7bcSMarek Szyprowski MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id);
5090cbdf7bcSMarek Szyprowski 
5100cbdf7bcSMarek Szyprowski static struct i2c_driver lp3971_i2c_driver = {
5110cbdf7bcSMarek Szyprowski 	.driver = {
5120cbdf7bcSMarek Szyprowski 		.name = "LP3971",
5130cbdf7bcSMarek Szyprowski 		.owner = THIS_MODULE,
5140cbdf7bcSMarek Szyprowski 	},
5150cbdf7bcSMarek Szyprowski 	.probe    = lp3971_i2c_probe,
5166113c3a5SLiam Girdwood 	.remove   = __devexit_p(lp3971_i2c_remove),
5170cbdf7bcSMarek Szyprowski 	.id_table = lp3971_i2c_id,
5180cbdf7bcSMarek Szyprowski };
5190cbdf7bcSMarek Szyprowski 
5200cbdf7bcSMarek Szyprowski static int __init lp3971_module_init(void)
5210cbdf7bcSMarek Szyprowski {
52212a1d933SWolfram Sang 	int ret;
5230cbdf7bcSMarek Szyprowski 
5240cbdf7bcSMarek Szyprowski 	ret = i2c_add_driver(&lp3971_i2c_driver);
5250cbdf7bcSMarek Szyprowski 	if (ret != 0)
5260cbdf7bcSMarek Szyprowski 		pr_err("Failed to register I2C driver: %d\n", ret);
5270cbdf7bcSMarek Szyprowski 
5280cbdf7bcSMarek Szyprowski 	return ret;
5290cbdf7bcSMarek Szyprowski }
5300cbdf7bcSMarek Szyprowski module_init(lp3971_module_init);
5310cbdf7bcSMarek Szyprowski 
5320cbdf7bcSMarek Szyprowski static void __exit lp3971_module_exit(void)
5330cbdf7bcSMarek Szyprowski {
5340cbdf7bcSMarek Szyprowski 	i2c_del_driver(&lp3971_i2c_driver);
5350cbdf7bcSMarek Szyprowski }
5360cbdf7bcSMarek Szyprowski module_exit(lp3971_module_exit);
5370cbdf7bcSMarek Szyprowski 
5380cbdf7bcSMarek Szyprowski MODULE_LICENSE("GPL");
5390cbdf7bcSMarek Szyprowski MODULE_AUTHOR("Marek Szyprowski <m.szyprowski@samsung.com>");
5400cbdf7bcSMarek Szyprowski MODULE_DESCRIPTION("LP3971 PMIC driver");
541