Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9aca0e7c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6:
  regulator: max8952 - fix max8952_set_voltage
  regulator: max8952 - fix max8952_pmic_probe error path
  regulator: fix build when CONFIG_REGULATOR_DUMMY=n
  regulator: avoid deadlock when disabling regulator with supply
  regulator: Add option for machine drivers to enable the dummy regulator
  Regulator: lp3972 cleanup
  Regulator: LP3972 PMIC regulator driver
  MAX8952 PMIC Driver Initial Release
parents a0e33907 ec10b0e9
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -100,6 +100,14 @@ config REGULATOR_MAX8925
	help
	  Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC.

config REGULATOR_MAX8952
	tristate "Maxim MAX8952 Power Management IC"
	depends on I2C
	help
	  This driver controls a Maxim 8952 voltage output regulator
	  via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS
	  modes ranging from 0.77V to 1.40V by 0.01V steps.

config REGULATOR_MAX8998
	tristate "Maxim 8998 voltage regulator"
	depends on MFD_MAX8998
@@ -164,6 +172,13 @@ config REGULATOR_LP3971
	 Say Y here to support the voltage regulators and convertors
	 on National Semiconductors LP3971 PMIC

config REGULATOR_LP3972
	tristate "National Semiconductors LP3972 PMIC regulator driver"
	depends on I2C
	help
	 Say Y here to support the voltage regulators and convertors
	 on National Semiconductors LP3972 PMIC

config REGULATOR_PCAP
	tristate "PCAP2 regulator driver"
	depends on EZX_PCAP
+3 −2
Original line number Diff line number Diff line
@@ -3,20 +3,21 @@
#


obj-$(CONFIG_REGULATOR) += core.o
obj-$(CONFIG_REGULATOR) += core.o dummy.o
obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o

obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
obj-$(CONFIG_REGULATOR_MAX8649)	+= max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
+48 −9
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_list);
static LIST_HEAD(regulator_map_list);
static int has_full_constraints;
static bool board_wants_dummy_regulator;

/*
 * struct regulator_map
@@ -63,7 +64,8 @@ struct regulator {
};

static int _regulator_is_enabled(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator_dev *rdev,
		struct regulator_dev **supply_rdev_ptr);
static int _regulator_get_voltage(struct regulator_dev *rdev);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
@@ -1108,6 +1110,11 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
		}
	}

	if (board_wants_dummy_regulator) {
		rdev = dummy_regulator_rdev;
		goto found;
	}

#ifdef CONFIG_REGULATOR_DUMMY
	if (!devname)
		devname = "deviceless";
@@ -1348,7 +1355,8 @@ int regulator_enable(struct regulator *regulator)
EXPORT_SYMBOL_GPL(regulator_enable);

/* locks held by regulator_disable() */
static int _regulator_disable(struct regulator_dev *rdev)
static int _regulator_disable(struct regulator_dev *rdev,
		struct regulator_dev **supply_rdev_ptr)
{
	int ret = 0;

@@ -1376,8 +1384,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
		}

		/* decrease our supplies ref count and disable if required */
		if (rdev->supply)
			_regulator_disable(rdev->supply);
		*supply_rdev_ptr = rdev->supply;

		rdev->use_count = 0;
	} else if (rdev->use_count > 1) {
@@ -1407,17 +1414,29 @@ static int _regulator_disable(struct regulator_dev *rdev)
int regulator_disable(struct regulator *regulator)
{
	struct regulator_dev *rdev = regulator->rdev;
	struct regulator_dev *supply_rdev = NULL;
	int ret = 0;

	mutex_lock(&rdev->mutex);
	ret = _regulator_disable(rdev);
	ret = _regulator_disable(rdev, &supply_rdev);
	mutex_unlock(&rdev->mutex);

	/* decrease our supplies ref count and disable if required */
	while (supply_rdev != NULL) {
		rdev = supply_rdev;

		mutex_lock(&rdev->mutex);
		_regulator_disable(rdev, &supply_rdev);
		mutex_unlock(&rdev->mutex);
	}

	return ret;
}
EXPORT_SYMBOL_GPL(regulator_disable);

/* locks held by regulator_force_disable() */
static int _regulator_force_disable(struct regulator_dev *rdev)
static int _regulator_force_disable(struct regulator_dev *rdev,
		struct regulator_dev **supply_rdev_ptr)
{
	int ret = 0;

@@ -1436,8 +1455,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
	}

	/* decrease our supplies ref count and disable if required */
	if (rdev->supply)
		_regulator_disable(rdev->supply);
	*supply_rdev_ptr = rdev->supply;

	rdev->use_count = 0;
	return ret;
@@ -1454,12 +1472,17 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
 */
int regulator_force_disable(struct regulator *regulator)
{
	struct regulator_dev *supply_rdev = NULL;
	int ret;

	mutex_lock(&regulator->rdev->mutex);
	regulator->uA_load = 0;
	ret = _regulator_force_disable(regulator->rdev);
	ret = _regulator_force_disable(regulator->rdev, &supply_rdev);
	mutex_unlock(&regulator->rdev->mutex);

	if (supply_rdev)
		regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev)));

	return ret;
}
EXPORT_SYMBOL_GPL(regulator_force_disable);
@@ -2462,6 +2485,22 @@ void regulator_has_full_constraints(void)
}
EXPORT_SYMBOL_GPL(regulator_has_full_constraints);

/**
 * regulator_use_dummy_regulator - Provide a dummy regulator when none is found
 *
 * Calling this function will cause the regulator API to provide a
 * dummy regulator to consumers if no physical regulator is found,
 * allowing most consumers to proceed as though a regulator were
 * configured.  This allows systems such as those with software
 * controllable regulators for the CPU core only to be brought up more
 * readily.
 */
void regulator_use_dummy_regulator(void)
{
	board_wants_dummy_regulator = true;
}
EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator);

/**
 * rdev_get_drvdata - get rdev regulator driver data
 * @rdev: regulator
+0 −4
Original line number Diff line number Diff line
@@ -22,10 +22,6 @@ struct regulator_dev;

extern struct regulator_dev *dummy_regulator_rdev;

#ifdef CONFIG_REGULATOR_DUMMY
void __init regulator_dummy_init(void);
#else
static inline void regulator_dummy_init(void) { }
#endif

#endif
+660 −0
Original line number Diff line number Diff line
/*
 * Regulator driver for National Semiconductors LP3972 PMIC chip
 *
 * Based on lp3971.c
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#include <linux/bug.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/lp3972.h>
#include <linux/slab.h>

struct lp3972 {
	struct device *dev;
	struct mutex io_lock;
	struct i2c_client *i2c;
	int num_regulators;
	struct regulator_dev **rdev;
};

/* LP3972 Control Registers */
#define LP3972_SCR_REG		0x07
#define LP3972_OVER1_REG	0x10
#define LP3972_OVSR1_REG	0x11
#define LP3972_OVER2_REG	0x12
#define LP3972_OVSR2_REG	0x13
#define LP3972_VCC1_REG		0x20
#define LP3972_ADTV1_REG	0x23
#define LP3972_ADTV2_REG	0x24
#define LP3972_AVRC_REG		0x25
#define LP3972_CDTC1_REG	0x26
#define LP3972_CDTC2_REG	0x27
#define LP3972_SDTV1_REG	0x29
#define LP3972_SDTV2_REG	0x2A
#define LP3972_MDTV1_REG	0x32
#define LP3972_MDTV2_REG	0x33
#define LP3972_L2VCR_REG	0x39
#define LP3972_L34VCR_REG	0x3A
#define LP3972_SCR1_REG		0x80
#define LP3972_SCR2_REG		0x81
#define LP3972_OEN3_REG		0x82
#define LP3972_OSR3_REG		0x83
#define LP3972_LOER4_REG	0x84
#define LP3972_B2TV_REG		0x85
#define LP3972_B3TV_REG		0x86
#define LP3972_B32RC_REG	0x87
#define LP3972_ISRA_REG		0x88
#define LP3972_BCCR_REG		0x89
#define LP3972_II1RR_REG	0x8E
#define LP3972_II2RR_REG	0x8F

#define LP3972_SYS_CONTROL1_REG		LP3972_SCR1_REG
/* System control register 1 initial value,
 * bits 5, 6 and 7 are EPROM programmable */
#define SYS_CONTROL1_INIT_VAL		0x02
#define SYS_CONTROL1_INIT_MASK		0x1F

#define LP3972_VOL_CHANGE_REG		LP3972_VCC1_REG
#define LP3972_VOL_CHANGE_FLAG_GO	0x01
#define LP3972_VOL_CHANGE_FLAG_MASK	0x03

/* LDO output enable mask */
#define LP3972_OEN3_L1EN	BIT(0)
#define LP3972_OVER2_LDO2_EN	BIT(2)
#define LP3972_OVER2_LDO3_EN	BIT(3)
#define LP3972_OVER2_LDO4_EN	BIT(4)
#define LP3972_OVER1_S_EN	BIT(2)

static const int ldo1_voltage_map[] = {
	1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
	1900, 1925, 1950, 1975, 2000,
};

static const int ldo23_voltage_map[] = {
	1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
	2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
};

static const int ldo4_voltage_map[] = {
	1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
	1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
};

static const int ldo5_voltage_map[] = {
	   0,    0,    0,    0,    0,  850,  875,  900,
	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
};

static const int buck1_voltage_map[] = {
	 725,  750,  775,  800,  825,  850,  875,  900,
	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
};

static const int buck23_voltage_map[] = {
	   0,  800,  850,  900,  950, 1000, 1050, 1100,
	1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
	1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
	3000, 3300,
};

static const int *ldo_voltage_map[] = {
	ldo1_voltage_map,
	ldo23_voltage_map,
	ldo23_voltage_map,
	ldo4_voltage_map,
	ldo5_voltage_map,
};

static const int *buck_voltage_map[] = {
	buck1_voltage_map,
	buck23_voltage_map,
	buck23_voltage_map,
};

static const int ldo_output_enable_mask[] = {
	LP3972_OEN3_L1EN,
	LP3972_OVER2_LDO2_EN,
	LP3972_OVER2_LDO3_EN,
	LP3972_OVER2_LDO4_EN,
	LP3972_OVER1_S_EN,
};

static const int ldo_output_enable_addr[] = {
	LP3972_OEN3_REG,
	LP3972_OVER2_REG,
	LP3972_OVER2_REG,
	LP3972_OVER2_REG,
	LP3972_OVER1_REG,
};

static const int ldo_vol_ctl_addr[] = {
	LP3972_MDTV1_REG,
	LP3972_L2VCR_REG,
	LP3972_L34VCR_REG,
	LP3972_L34VCR_REG,
	LP3972_SDTV1_REG,
};

static const int buck_vol_enable_addr[] = {
	LP3972_OVER1_REG,
	LP3972_OEN3_REG,
	LP3972_OEN3_REG,
};

static const int buck_base_addr[] = {
	LP3972_ADTV1_REG,
	LP3972_B2TV_REG,
	LP3972_B3TV_REG,
};

#define LP3972_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x])
#define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
#define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x])

/*	LDO voltage control registers shift:
	LP3972_LDO1 -> 0, LP3972_LDO2 -> 4
	LP3972_LDO3 -> 0, LP3972_LDO4 -> 4
	LP3972_LDO5 -> 0
*/
#define LP3972_LDO_VOL_CONTR_SHIFT(x) (((x) & 1) << 2)
#define LP3972_LDO_VOL_CONTR_REG(x) (ldo_vol_ctl_addr[x])
#define LP3972_LDO_VOL_CHANGE_SHIFT(x) ((x) ? 4 : 6)

#define LP3972_LDO_VOL_MASK(x) (((x) % 4) ? 0x0f : 0x1f)
#define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00)
#define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c)

#define LP3972_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x])
#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
#define LP3972_BUCK_VOL_MASK 0x1f
#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00)
#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f)

static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count,
	u16 *dest)
{
	int ret;

	if (count != 1)
		return -EIO;
	ret = i2c_smbus_read_byte_data(i2c, reg);
	if (ret < 0)
		return ret;

	*dest = ret;
	return 0;
}

static int lp3972_i2c_write(struct i2c_client *i2c, char reg, int count,
	const u16 *src)
{
	if (count != 1)
		return -EIO;
	return i2c_smbus_write_byte_data(i2c, reg, *src);
}

static u8 lp3972_reg_read(struct lp3972 *lp3972, u8 reg)
{
	u16 val = 0;

	mutex_lock(&lp3972->io_lock);

	lp3972_i2c_read(lp3972->i2c, reg, 1, &val);

	dev_dbg(lp3972->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
		(unsigned)val & 0xff);

	mutex_unlock(&lp3972->io_lock);

	return val & 0xff;
}

static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val)
{
	u16 tmp;
	int ret;

	mutex_lock(&lp3972->io_lock);

	ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp);
	tmp = (tmp & ~mask) | val;
	if (ret == 0) {
		ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp);
		dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
			(unsigned)val & 0xff);
	}
	mutex_unlock(&lp3972->io_lock);

	return ret;
}

static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
{
	int ldo = rdev_get_id(dev) - LP3972_LDO1;
	return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index];
}

static int lp3972_ldo_is_enabled(struct regulator_dev *dev)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int ldo = rdev_get_id(dev) - LP3972_LDO1;
	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
	u16 val;

	val = lp3972_reg_read(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo));
	return !!(val & mask);
}

static int lp3972_ldo_enable(struct regulator_dev *dev)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int ldo = rdev_get_id(dev) - LP3972_LDO1;
	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);

	return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo),
				mask, mask);
}

static int lp3972_ldo_disable(struct regulator_dev *dev)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int ldo = rdev_get_id(dev) - LP3972_LDO1;
	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);

	return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo),
				mask, 0);
}

static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int ldo = rdev_get_id(dev) - LP3972_LDO1;
	u16 mask = LP3972_LDO_VOL_MASK(ldo);
	u16 val, reg;

	reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
	val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;

	return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val];
}

static int lp3972_ldo_set_voltage(struct regulator_dev *dev,
				  int min_uV, int max_uV)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int ldo = rdev_get_id(dev) - LP3972_LDO1;
	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
	const int *vol_map = LP3972_LDO_VOL_VALUE_MAP(ldo);
	u16 val;
	int shift, ret;

	if (min_vol < vol_map[LP3972_LDO_VOL_MIN_IDX(ldo)] ||
	    min_vol > vol_map[LP3972_LDO_VOL_MAX_IDX(ldo)])
		return -EINVAL;

	for (val = LP3972_LDO_VOL_MIN_IDX(ldo);
		val <= LP3972_LDO_VOL_MAX_IDX(ldo); val++)
		if (vol_map[val] >= min_vol)
			break;

	if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol)
		return -EINVAL;

	shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo);
	ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo),
		LP3972_LDO_VOL_MASK(ldo) << shift, val << shift);

	if (ret)
		return ret;

	/*
	 * LDO1 and LDO5 support voltage control by either target voltage1
	 * or target voltage2 register.
	 * We use target voltage1 register for LDO1 and LDO5 in this driver.
	 * We need to update voltage change control register(0x20) to enable
	 * LDO1 and LDO5 to change to their programmed target values.
	 */
	switch (ldo) {
	case LP3972_LDO1:
	case LP3972_LDO5:
		shift = LP3972_LDO_VOL_CHANGE_SHIFT(ldo);
		ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
			LP3972_VOL_CHANGE_FLAG_MASK << shift,
			LP3972_VOL_CHANGE_FLAG_GO << shift);
		if (ret)
			return ret;

		ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
			LP3972_VOL_CHANGE_FLAG_MASK << shift, 0);
		break;
	}

	return ret;
}

static struct regulator_ops lp3972_ldo_ops = {
	.list_voltage = lp3972_ldo_list_voltage,
	.is_enabled = lp3972_ldo_is_enabled,
	.enable = lp3972_ldo_enable,
	.disable = lp3972_ldo_disable,
	.get_voltage = lp3972_ldo_get_voltage,
	.set_voltage = lp3972_ldo_set_voltage,
};

static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
{
	int buck = rdev_get_id(dev) - LP3972_DCDC1;
	return 1000 * buck_voltage_map[buck][index];
}

static int lp3972_dcdc_is_enabled(struct regulator_dev *dev)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int buck = rdev_get_id(dev) - LP3972_DCDC1;
	u16 mask = 1 << (buck * 2);
	u16 val;

	val = lp3972_reg_read(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck));
	return !!(val & mask);
}

static int lp3972_dcdc_enable(struct regulator_dev *dev)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int buck = rdev_get_id(dev) - LP3972_DCDC1;
	u16 mask = 1 << (buck * 2);
	u16 val;

	val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck),
				mask, mask);
	return val;
}

static int lp3972_dcdc_disable(struct regulator_dev *dev)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int buck = rdev_get_id(dev) - LP3972_DCDC1;
	u16 mask = 1 << (buck * 2);
	u16 val;

	val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck),
				mask, 0);
	return val;
}

static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int buck = rdev_get_id(dev) - LP3972_DCDC1;
	u16 reg;
	int val;

	reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
	reg &= LP3972_BUCK_VOL_MASK;
	if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
		val = 1000 * buck_voltage_map[buck][reg];
	else {
		val = 0;
		dev_warn(&dev->dev, "chip reported incorrect voltage value."
				    " reg = %d\n", reg);
	}

	return val;
}

static int lp3972_dcdc_set_voltage(struct regulator_dev *dev,
				  int min_uV, int max_uV)
{
	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
	int buck = rdev_get_id(dev) - LP3972_DCDC1;
	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
	const int *vol_map = buck_voltage_map[buck];
	u16 val;
	int ret;

	if (min_vol < vol_map[LP3972_BUCK_VOL_MIN_IDX(buck)] ||
	    min_vol > vol_map[LP3972_BUCK_VOL_MAX_IDX(buck)])
		return -EINVAL;

	for (val = LP3972_BUCK_VOL_MIN_IDX(buck);
		val <= LP3972_BUCK_VOL_MAX_IDX(buck); val++)
		if (vol_map[val] >= min_vol)
			break;

	if (val > LP3972_BUCK_VOL_MAX_IDX(buck) ||
	    vol_map[val] > max_vol)
		return -EINVAL;

	ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck),
				LP3972_BUCK_VOL_MASK, val);
	if (ret)
		return ret;

	if (buck != 0)
		return ret;

	ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
		LP3972_VOL_CHANGE_FLAG_MASK, LP3972_VOL_CHANGE_FLAG_GO);
	if (ret)
		return ret;

	return lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
				LP3972_VOL_CHANGE_FLAG_MASK, 0);
}

static struct regulator_ops lp3972_dcdc_ops = {
	.list_voltage = lp3972_dcdc_list_voltage,
	.is_enabled = lp3972_dcdc_is_enabled,
	.enable = lp3972_dcdc_enable,
	.disable = lp3972_dcdc_disable,
	.get_voltage = lp3972_dcdc_get_voltage,
	.set_voltage = lp3972_dcdc_set_voltage,
};

static struct regulator_desc regulators[] = {
	{
		.name = "LDO1",
		.id = LP3972_LDO1,
		.ops = &lp3972_ldo_ops,
		.n_voltages = ARRAY_SIZE(ldo1_voltage_map),
		.type = REGULATOR_VOLTAGE,
		.owner = THIS_MODULE,
	},
	{
		.name = "LDO2",
		.id = LP3972_LDO2,
		.ops = &lp3972_ldo_ops,
		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
		.type = REGULATOR_VOLTAGE,
		.owner = THIS_MODULE,
	},
	{
		.name = "LDO3",
		.id = LP3972_LDO3,
		.ops = &lp3972_ldo_ops,
		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
		.type = REGULATOR_VOLTAGE,
		.owner = THIS_MODULE,
	},
	{
		.name = "LDO4",
		.id = LP3972_LDO4,
		.ops = &lp3972_ldo_ops,
		.n_voltages = ARRAY_SIZE(ldo4_voltage_map),
		.type = REGULATOR_VOLTAGE,
		.owner = THIS_MODULE,
	},
	{
		.name = "LDO5",
		.id = LP3972_LDO5,
		.ops = &lp3972_ldo_ops,
		.n_voltages = ARRAY_SIZE(ldo5_voltage_map),
		.type = REGULATOR_VOLTAGE,
		.owner = THIS_MODULE,
	},
	{
		.name = "DCDC1",
		.id = LP3972_DCDC1,
		.ops = &lp3972_dcdc_ops,
		.n_voltages = ARRAY_SIZE(buck1_voltage_map),
		.type = REGULATOR_VOLTAGE,
		.owner = THIS_MODULE,
	},
	{
		.name = "DCDC2",
		.id = LP3972_DCDC2,
		.ops = &lp3972_dcdc_ops,
		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
		.type = REGULATOR_VOLTAGE,
		.owner = THIS_MODULE,
	},
	{
		.name = "DCDC3",
		.id = LP3972_DCDC3,
		.ops = &lp3972_dcdc_ops,
		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
		.type = REGULATOR_VOLTAGE,
		.owner = THIS_MODULE,
	},
};

static int __devinit setup_regulators(struct lp3972 *lp3972,
	struct lp3972_platform_data *pdata)
{
	int i, err;

	lp3972->num_regulators = pdata->num_regulators;
	lp3972->rdev = kcalloc(pdata->num_regulators,
				sizeof(struct regulator_dev *), GFP_KERNEL);
	if (!lp3972->rdev) {
		err = -ENOMEM;
		goto err_nomem;
	}

	/* Instantiate the regulators */
	for (i = 0; i < pdata->num_regulators; i++) {
		struct lp3972_regulator_subdev *reg = &pdata->regulators[i];
		lp3972->rdev[i] = regulator_register(&regulators[reg->id],
					lp3972->dev, reg->initdata, lp3972);

		if (IS_ERR(lp3972->rdev[i])) {
			err = PTR_ERR(lp3972->rdev[i]);
			dev_err(lp3972->dev, "regulator init failed: %d\n",
				err);
			goto error;
		}
	}

	return 0;
error:
	while (--i >= 0)
		regulator_unregister(lp3972->rdev[i]);
	kfree(lp3972->rdev);
	lp3972->rdev = NULL;
err_nomem:
	return err;
}

static int __devinit lp3972_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	struct lp3972 *lp3972;
	struct lp3972_platform_data *pdata = i2c->dev.platform_data;
	int ret;
	u16 val;

	if (!pdata) {
		dev_dbg(&i2c->dev, "No platform init data supplied\n");
		return -ENODEV;
	}

	lp3972 = kzalloc(sizeof(struct lp3972), GFP_KERNEL);
	if (!lp3972)
		return -ENOMEM;

	lp3972->i2c = i2c;
	lp3972->dev = &i2c->dev;

	mutex_init(&lp3972->io_lock);

	/* Detect LP3972 */
	ret = lp3972_i2c_read(i2c, LP3972_SYS_CONTROL1_REG, 1, &val);
	if (ret == 0 &&
		(val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) {
		ret = -ENODEV;
		dev_err(&i2c->dev, "chip reported: val = 0x%x\n", val);
	}
	if (ret < 0) {
		dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret);
		goto err_detect;
	}

	ret = setup_regulators(lp3972, pdata);
	if (ret < 0)
		goto err_detect;

	i2c_set_clientdata(i2c, lp3972);
	return 0;

err_detect:
	kfree(lp3972);
	return ret;
}

static int __devexit lp3972_i2c_remove(struct i2c_client *i2c)
{
	struct lp3972 *lp3972 = i2c_get_clientdata(i2c);
	int i;

	for (i = 0; i < lp3972->num_regulators; i++)
		regulator_unregister(lp3972->rdev[i]);
	kfree(lp3972->rdev);
	kfree(lp3972);

	return 0;
}

static const struct i2c_device_id lp3972_i2c_id[] = {
	{ "lp3972", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id);

static struct i2c_driver lp3972_i2c_driver = {
	.driver = {
		.name = "lp3972",
		.owner = THIS_MODULE,
	},
	.probe    = lp3972_i2c_probe,
	.remove   = __devexit_p(lp3972_i2c_remove),
	.id_table = lp3972_i2c_id,
};

static int __init lp3972_module_init(void)
{
	return i2c_add_driver(&lp3972_i2c_driver);
}
subsys_initcall(lp3972_module_init);

static void __exit lp3972_module_exit(void)
{
	i2c_del_driver(&lp3972_i2c_driver);
}
module_exit(lp3972_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>");
MODULE_DESCRIPTION("LP3972 PMIC driver");
Loading