Merge remote-tracking branches 'regulator/topic/supply', 'regulator/topic/tps6105x' and 'regulator/topic/tps65023' into regulator-next

This commit is contained in:
Mark Brown 2015-11-04 11:19:43 +00:00
commit 62e544b983
6 changed files with 372 additions and 325 deletions

View File

@ -0,0 +1,60 @@
TPS65023 family of regulators
Required properties:
- compatible: Must be one of the following.
"ti,tps65020",
"ti,tps65021",
"ti,tps65023",
- reg: I2C slave address
- regulators: list of regulators provided by this controller, must be named
after their hardware counterparts: VDCDC[1-3] and LDO[1-2]
- regulators: This is the list of child nodes that specify the regulator
initialization data for defined regulators. The definition for each of
these nodes is defined using the standard binding for regulators found at
Documentation/devicetree/bindings/regulator/regulator.txt.
Each regulator is defined using the standard binding for regulators.
Example:
tps65023@48 {
compatible = "ti,tps65023";
reg = <0x48>;
regulators {
VDCDC1 {
regulator-name = "vdd_mpu";
regulator-always-on;
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
VDCDC2 {
regulator-name = "vdd_core";
regulator-always-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
VDCDC3 {
regulator-name = "vdd_io";
regulator-always-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
LDO1 {
regulator-name = "vdd_usb18";
regulator-always-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
LDO2 {
regulator-name = "vdd_usb33";
regulator-always-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
};
};

View File

@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@ -25,73 +25,18 @@
#include <linux/mfd/core.h>
#include <linux/mfd/tps6105x.h>
int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value)
{
int ret;
ret = mutex_lock_interruptible(&tps6105x->lock);
if (ret)
return ret;
ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value);
mutex_unlock(&tps6105x->lock);
if (ret < 0)
return ret;
return 0;
}
EXPORT_SYMBOL(tps6105x_set);
int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf)
{
int ret;
ret = mutex_lock_interruptible(&tps6105x->lock);
if (ret)
return ret;
ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
mutex_unlock(&tps6105x->lock);
if (ret < 0)
return ret;
*buf = ret;
return 0;
}
EXPORT_SYMBOL(tps6105x_get);
/*
* Masks off the bits in the mask and sets the bits in the bitvalues
* parameter in one atomic operation
*/
int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
u8 bitmask, u8 bitvalues)
{
int ret;
u8 regval;
ret = mutex_lock_interruptible(&tps6105x->lock);
if (ret)
return ret;
ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
if (ret < 0)
goto fail;
regval = ret;
regval = (~bitmask & regval) | (bitmask & bitvalues);
ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval);
fail:
mutex_unlock(&tps6105x->lock);
if (ret < 0)
return ret;
return 0;
}
EXPORT_SYMBOL(tps6105x_mask_and_set);
static struct regmap_config tps6105x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = TPS6105X_REG_3,
};
static int tps6105x_startup(struct tps6105x *tps6105x)
{
int ret;
u8 regval;
unsigned int regval;
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
if (ret)
return ret;
switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
@ -145,11 +90,14 @@ static int tps6105x_probe(struct i2c_client *client,
if (!tps6105x)
return -ENOMEM;
tps6105x->regmap = devm_regmap_init_i2c(client, &tps6105x_regmap_config);
if (IS_ERR(tps6105x->regmap))
return PTR_ERR(tps6105x->regmap);
i2c_set_clientdata(client, tps6105x);
tps6105x->client = client;
pdata = dev_get_platdata(&client->dev);
tps6105x->pdata = pdata;
mutex_init(&tps6105x->lock);
ret = tps6105x_startup(tps6105x);
if (ret) {
@ -198,7 +146,7 @@ static int tps6105x_remove(struct i2c_client *client)
mfd_remove_devices(&client->dev);
/* Put chip in shutdown mode */
tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_MODE_MASK,
TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);

View File

@ -132,6 +132,45 @@ static bool have_full_constraints(void)
return has_full_constraints || of_have_populated_dt();
}
/**
* regulator_lock_supply - lock a regulator and its supplies
* @rdev: regulator source
*/
static void regulator_lock_supply(struct regulator_dev *rdev)
{
struct regulator *supply;
int i = 0;
while (1) {
mutex_lock_nested(&rdev->mutex, i++);
supply = rdev->supply;
if (!rdev->supply)
return;
rdev = supply->rdev;
}
}
/**
* regulator_unlock_supply - unlock a regulator and its supplies
* @rdev: regulator source
*/
static void regulator_unlock_supply(struct regulator_dev *rdev)
{
struct regulator *supply;
while (1) {
mutex_unlock(&rdev->mutex);
supply = rdev->supply;
if (!rdev->supply)
return;
rdev = supply->rdev;
}
}
/**
* of_get_regulator - get a regulator device node based on supply name
* @dev: Device pointer for the consumer (of regulator) device
@ -2364,6 +2403,40 @@ static int _regulator_is_enabled(struct regulator_dev *rdev)
return rdev->desc->ops->is_enabled(rdev);
}
static int _regulator_list_voltage(struct regulator *regulator,
unsigned selector, int lock)
{
struct regulator_dev *rdev = regulator->rdev;
const struct regulator_ops *ops = rdev->desc->ops;
int ret;
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
return rdev->desc->fixed_uV;
if (ops->list_voltage) {
if (selector >= rdev->desc->n_voltages)
return -EINVAL;
if (lock)
mutex_lock(&rdev->mutex);
ret = ops->list_voltage(rdev, selector);
if (lock)
mutex_unlock(&rdev->mutex);
} else if (rdev->supply) {
ret = _regulator_list_voltage(rdev->supply, selector, lock);
} else {
return -EINVAL;
}
if (ret > 0) {
if (ret < rdev->constraints->min_uV)
ret = 0;
else if (ret > rdev->constraints->max_uV)
ret = 0;
}
return ret;
}
/**
* regulator_is_enabled - is the regulator output enabled
* @regulator: regulator source
@ -2453,33 +2526,7 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages);
*/
int regulator_list_voltage(struct regulator *regulator, unsigned selector)
{
struct regulator_dev *rdev = regulator->rdev;
const struct regulator_ops *ops = rdev->desc->ops;
int ret;
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
return rdev->desc->fixed_uV;
if (ops->list_voltage) {
if (selector >= rdev->desc->n_voltages)
return -EINVAL;
mutex_lock(&rdev->mutex);
ret = ops->list_voltage(rdev, selector);
mutex_unlock(&rdev->mutex);
} else if (rdev->supply) {
ret = regulator_list_voltage(rdev->supply, selector);
} else {
return -EINVAL;
}
if (ret > 0) {
if (ret < rdev->constraints->min_uV)
ret = 0;
else if (ret > rdev->constraints->max_uV)
ret = 0;
}
return ret;
return _regulator_list_voltage(regulator, selector, 1);
}
EXPORT_SYMBOL_GPL(regulator_list_voltage);
@ -2614,6 +2661,23 @@ int regulator_is_supported_voltage(struct regulator *regulator,
}
EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
int max_uV)
{
const struct regulator_desc *desc = rdev->desc;
if (desc->ops->map_voltage)
return desc->ops->map_voltage(rdev, min_uV, max_uV);
if (desc->ops->list_voltage == regulator_list_voltage_linear)
return regulator_map_voltage_linear(rdev, min_uV, max_uV);
if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
}
static int _regulator_call_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV,
unsigned *selector)
@ -2702,23 +2766,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
}
} else if (rdev->desc->ops->set_voltage_sel) {
if (rdev->desc->ops->map_voltage) {
ret = rdev->desc->ops->map_voltage(rdev, min_uV,
max_uV);
} else {
if (rdev->desc->ops->list_voltage ==
regulator_list_voltage_linear)
ret = regulator_map_voltage_linear(rdev,
min_uV, max_uV);
else if (rdev->desc->ops->list_voltage ==
regulator_list_voltage_linear_range)
ret = regulator_map_voltage_linear_range(rdev,
min_uV, max_uV);
else
ret = regulator_map_voltage_iterate(rdev,
min_uV, max_uV);
}
ret = regulator_map_voltage(rdev, min_uV, max_uV);
if (ret >= 0) {
best_val = rdev->desc->ops->list_voltage(rdev, ret);
if (min_uV <= best_val && max_uV >= best_val) {
@ -2769,32 +2817,15 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
return ret;
}
/**
* regulator_set_voltage - set regulator output voltage
* @regulator: regulator source
* @min_uV: Minimum required voltage in uV
* @max_uV: Maximum acceptable voltage in uV
*
* Sets a voltage regulator to the desired output voltage. This can be set
* during any regulator state. IOW, regulator can be disabled or enabled.
*
* If the regulator is enabled then the voltage will change to the new value
* immediately otherwise if the regulator is disabled the regulator will
* output at the new voltage when enabled.
*
* NOTE: If the regulator is shared between several devices then the lowest
* request voltage that meets the system constraints will be used.
* Regulator system constraints must be set for this regulator before
* calling this function otherwise this call will fail.
*/
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
static int regulator_set_voltage_unlocked(struct regulator *regulator,
int min_uV, int max_uV)
{
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
int old_min_uV, old_max_uV;
int current_uV;
mutex_lock(&rdev->mutex);
int best_supply_uV = 0;
int supply_change_uV = 0;
/* If we're setting the same range as last time the change
* should be a noop (some cpufreq implementations use the same
@ -2838,17 +2869,95 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
if (ret < 0)
goto out2;
if (rdev->supply && (rdev->desc->min_dropout_uV ||
!rdev->desc->ops->get_voltage)) {
int current_supply_uV;
int selector;
selector = regulator_map_voltage(rdev, min_uV, max_uV);
if (selector < 0) {
ret = selector;
goto out2;
}
best_supply_uV = _regulator_list_voltage(regulator, selector, 0);
if (best_supply_uV < 0) {
ret = best_supply_uV;
goto out2;
}
best_supply_uV += rdev->desc->min_dropout_uV;
current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
if (current_supply_uV < 0) {
ret = current_supply_uV;
goto out2;
}
supply_change_uV = best_supply_uV - current_supply_uV;
}
if (supply_change_uV > 0) {
ret = regulator_set_voltage_unlocked(rdev->supply,
best_supply_uV, INT_MAX);
if (ret) {
dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n",
ret);
goto out2;
}
}
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
if (ret < 0)
goto out2;
if (supply_change_uV < 0) {
ret = regulator_set_voltage_unlocked(rdev->supply,
best_supply_uV, INT_MAX);
if (ret)
dev_warn(&rdev->dev, "Failed to decrease supply voltage: %d\n",
ret);
/* No need to fail here */
ret = 0;
}
out:
mutex_unlock(&rdev->mutex);
return ret;
out2:
regulator->min_uV = old_min_uV;
regulator->max_uV = old_max_uV;
mutex_unlock(&rdev->mutex);
return ret;
}
/**
* regulator_set_voltage - set regulator output voltage
* @regulator: regulator source
* @min_uV: Minimum required voltage in uV
* @max_uV: Maximum acceptable voltage in uV
*
* Sets a voltage regulator to the desired output voltage. This can be set
* during any regulator state. IOW, regulator can be disabled or enabled.
*
* If the regulator is enabled then the voltage will change to the new value
* immediately otherwise if the regulator is disabled the regulator will
* output at the new voltage when enabled.
*
* NOTE: If the regulator is shared between several devices then the lowest
* request voltage that meets the system constraints will be used.
* Regulator system constraints must be set for this regulator before
* calling this function otherwise this call will fail.
*/
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
{
int ret = 0;
regulator_lock_supply(regulator->rdev);
ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV);
regulator_unlock_supply(regulator->rdev);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage);
@ -3001,7 +3110,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
} else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) {
ret = rdev->desc->fixed_uV;
} else if (rdev->supply) {
ret = regulator_get_voltage(rdev->supply);
ret = _regulator_get_voltage(rdev->supply->rdev);
} else {
return -EINVAL;
}
@ -3024,11 +3133,11 @@ int regulator_get_voltage(struct regulator *regulator)
{
int ret;
mutex_lock(&regulator->rdev->mutex);
regulator_lock_supply(regulator->rdev);
ret = _regulator_get_voltage(regulator->rdev);
mutex_unlock(&regulator->rdev->mutex);
regulator_unlock_supply(regulator->rdev);
return ret;
}

View File

@ -14,7 +14,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/core.h>
@ -33,7 +33,7 @@ static int tps6105x_regulator_enable(struct regulator_dev *rdev)
int ret;
/* Activate voltage mode */
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_MODE_MASK,
TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
if (ret)
@ -48,7 +48,7 @@ static int tps6105x_regulator_disable(struct regulator_dev *rdev)
int ret;
/* Set into shutdown mode */
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_MODE_MASK,
TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
if (ret)
@ -60,10 +60,10 @@ static int tps6105x_regulator_disable(struct regulator_dev *rdev)
static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
u8 regval;
unsigned int regval;
int ret;
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
if (ret)
return ret;
regval &= TPS6105X_REG0_MODE_MASK;
@ -78,10 +78,10 @@ static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
u8 regval;
unsigned int regval;
int ret;
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
if (ret)
return ret;
@ -96,7 +96,7 @@ static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
int ret;
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_VOLTAGE_MASK,
selector << TPS6105X_REG0_VOLTAGE_SHIFT);
if (ret)

View File

@ -86,6 +86,42 @@
#define TPS65023_MAX_REG_ID TPS65023_LDO_2
#define TPS65023_REGULATOR_DCDC(_num, _t, _em) \
{ \
.name = "VDCDC"#_num, \
.of_match = of_match_ptr("VDCDC"#_num), \
.regulators_node = of_match_ptr("regulators"), \
.id = TPS65023_DCDC_##_num, \
.n_voltages = ARRAY_SIZE(_t), \
.ops = &tps65023_dcdc_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.volt_table = _t, \
.vsel_reg = TPS65023_REG_DEF_CORE, \
.vsel_mask = ARRAY_SIZE(_t) - 1, \
.enable_mask = _em, \
.enable_reg = TPS65023_REG_REG_CTRL, \
.apply_reg = TPS65023_REG_CON_CTRL2, \
.apply_bit = TPS65023_REG_CTRL2_GO, \
} \
#define TPS65023_REGULATOR_LDO(_num, _t, _vm) \
{ \
.name = "LDO"#_num, \
.of_match = of_match_ptr("LDO"#_num), \
.regulators_node = of_match_ptr("regulators"), \
.id = TPS65023_LDO_##_num, \
.n_voltages = ARRAY_SIZE(_t), \
.ops = &tps65023_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.volt_table = _t, \
.vsel_reg = TPS65023_REG_LDO_CTRL, \
.vsel_mask = _vm, \
.enable_mask = 1 << (_num), \
.enable_reg = TPS65023_REG_REG_CTRL, \
} \
/* Supported voltage values for regulators */
static const unsigned int VCORE_VSEL_table[] = {
800000, 825000, 850000, 875000,
@ -124,25 +160,16 @@ static const unsigned int TPS65023_LDO2_VSEL_table[] = {
2500000, 2800000, 3000000, 3300000,
};
/* Regulator specific details */
struct tps_info {
const char *name;
u8 table_len;
const unsigned int *table;
};
/* PMIC details */
struct tps_pmic {
struct regulator_desc desc[TPS65023_NUM_REGULATOR];
struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
const struct tps_info *info[TPS65023_NUM_REGULATOR];
const struct tps_driver_data *driver_data;
struct regmap *regmap;
u8 core_regulator;
};
/* Struct passed as driver data */
struct tps_driver_data {
const struct tps_info *info;
const struct regulator_desc *desc;
u8 core_regulator;
};
@ -154,7 +181,7 @@ static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev)
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL;
if (dcdc != tps->core_regulator)
if (dcdc != tps->driver_data->core_regulator)
return 0;
return regulator_get_voltage_sel_regmap(dev);
@ -166,7 +193,7 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
if (dcdc != tps->core_regulator)
if (dcdc != tps->driver_data->core_regulator)
return -EINVAL;
return regulator_set_voltage_sel_regmap(dev, selector);
@ -199,30 +226,60 @@ static const struct regmap_config tps65023_regmap_config = {
.val_bits = 8,
};
static const struct regulator_desc tps65020_regulators[] = {
TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20),
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10),
TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08),
TPS65023_REGULATOR_LDO(1, TPS65020_LDO_VSEL_table, 0x07),
TPS65023_REGULATOR_LDO(2, TPS65020_LDO_VSEL_table, 0x70),
};
static const struct regulator_desc tps65021_regulators[] = {
TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20),
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10),
TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08),
TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07),
TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70),
};
static const struct regulator_desc tps65023_regulators[] = {
TPS65023_REGULATOR_DCDC(1, VCORE_VSEL_table, 0x20),
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_3300000_VSEL_table, 0x10),
TPS65023_REGULATOR_DCDC(3, DCDC_FIXED_1800000_VSEL_table, 0x08),
TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07),
TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70),
};
static struct tps_driver_data tps65020_drv_data = {
.desc = tps65020_regulators,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65021_drv_data = {
.desc = tps65021_regulators,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65023_drv_data = {
.desc = tps65023_regulators,
.core_regulator = TPS65023_DCDC_1,
};
static int tps_65023_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct tps_driver_data *drv_data = (void *)id->driver_data;
const struct tps_info *info = drv_data->info;
struct regulator_init_data *init_data = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
struct tps_pmic *tps;
int i;
int error;
/**
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
init_data = dev_get_platdata(&client->dev);
if (!init_data)
return -EIO;
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
tps->driver_data = (struct tps_driver_data *)id->driver_data;
tps->regmap = devm_regmap_init_i2c(client, &tps65023_regmap_config);
if (IS_ERR(tps->regmap)) {
error = PTR_ERR(tps->regmap);
@ -232,58 +289,22 @@ static int tps_65023_probe(struct i2c_client *client,
}
/* common for all regulators */
tps->core_regulator = drv_data->core_regulator;
config.dev = &client->dev;
config.driver_data = tps;
config.regmap = tps->regmap;
for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
/* Store regulator specific information */
tps->info[i] = info;
tps->desc[i].name = info->name;
tps->desc[i].id = i;
tps->desc[i].n_voltages = info->table_len;
tps->desc[i].volt_table = info->table;
tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
&tps65023_ldo_ops : &tps65023_dcdc_ops);
tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE;
tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL;
switch (i) {
case TPS65023_LDO_1:
tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
tps->desc[i].vsel_mask = 0x07;
tps->desc[i].enable_mask = 1 << 1;
break;
case TPS65023_LDO_2:
tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
tps->desc[i].vsel_mask = 0x70;
tps->desc[i].enable_mask = 1 << 2;
break;
default: /* DCDCx */
tps->desc[i].enable_mask =
1 << (TPS65023_NUM_REGULATOR - i);
tps->desc[i].vsel_reg = TPS65023_REG_DEF_CORE;
tps->desc[i].vsel_mask = info->table_len - 1;
tps->desc[i].apply_reg = TPS65023_REG_CON_CTRL2;
tps->desc[i].apply_bit = TPS65023_REG_CTRL2_GO;
}
config.dev = &client->dev;
config.init_data = init_data;
config.driver_data = tps;
config.regmap = tps->regmap;
for (i = 0; i < TPS65023_NUM_REGULATOR; i++) {
if (init_data)
config.init_data = &init_data[i];
/* Register the regulators */
rdev = devm_regulator_register(&client->dev, &tps->desc[i],
&config);
if (IS_ERR(rdev)) {
tps->rdev[i] = devm_regulator_register(&client->dev,
&tps->driver_data->desc[i], &config);
if (IS_ERR(tps->rdev[i])) {
dev_err(&client->dev, "failed to register %s\n",
id->name);
return PTR_ERR(rdev);
return PTR_ERR(tps->rdev[i]);
}
/* Save regulator for cleanup */
tps->rdev[i] = rdev;
}
i2c_set_clientdata(client, tps);
@ -296,120 +317,33 @@ static int tps_65023_probe(struct i2c_client *client,
return 0;
}
static const struct tps_info tps65020_regs[] = {
{
.name = "VDCDC1",
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
.table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC2",
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
.table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "VDCDC3",
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "LDO1",
.table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table),
.table = TPS65020_LDO_VSEL_table,
},
{
.name = "LDO2",
.table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table),
.table = TPS65020_LDO_VSEL_table,
},
};
static const struct tps_info tps65021_regs[] = {
{
.name = "VDCDC1",
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
.table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC2",
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
.table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "VDCDC3",
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "LDO1",
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
.table = TPS65023_LDO1_VSEL_table,
},
{
.name = "LDO2",
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
.table = TPS65023_LDO2_VSEL_table,
},
};
static const struct tps_info tps65023_regs[] = {
{
.name = "VDCDC1",
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "VDCDC2",
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
.table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC3",
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
.table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "LDO1",
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
.table = TPS65023_LDO1_VSEL_table,
},
{
.name = "LDO2",
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
.table = TPS65023_LDO2_VSEL_table,
},
};
static struct tps_driver_data tps65020_drv_data = {
.info = tps65020_regs,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65021_drv_data = {
.info = tps65021_regs,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65023_drv_data = {
.info = tps65023_regs,
.core_regulator = TPS65023_DCDC_1,
static const struct of_device_id tps65023_of_match[] = {
{ .compatible = "ti,tps65020", .data = &tps65020_drv_data},
{ .compatible = "ti,tps65021", .data = &tps65021_drv_data},
{ .compatible = "ti,tps65023", .data = &tps65023_drv_data},
{},
};
MODULE_DEVICE_TABLE(of, tps65023_of_match);
static const struct i2c_device_id tps_65023_id[] = {
{.name = "tps65023",
.driver_data = (unsigned long) &tps65023_drv_data},
{.name = "tps65021",
.driver_data = (unsigned long) &tps65021_drv_data,},
{.name = "tps65020",
.driver_data = (unsigned long) &tps65020_drv_data},
{
.name = "tps65023",
.driver_data = (kernel_ulong_t)&tps65023_drv_data
}, {
.name = "tps65021",
.driver_data = (kernel_ulong_t)&tps65021_drv_data
}, {
.name = "tps65020",
.driver_data = (kernel_ulong_t)&tps65020_drv_data
},
{ },
};
MODULE_DEVICE_TABLE(i2c, tps_65023_id);
static struct i2c_driver tps_65023_i2c_driver = {
.driver = {
.name = "tps65023",
.of_match_table = of_match_ptr(tps65023_of_match),
},
.probe = tps_65023_probe,
.id_table = tps_65023_id,

View File

@ -10,6 +10,7 @@
#define MFD_TPS6105X_H
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/regulator/machine.h>
/*
@ -82,20 +83,15 @@ struct tps6105x_platform_data {
/**
* struct tps6105x - state holder for the TPS6105x drivers
* @mutex: mutex to serialize I2C accesses
* @i2c_client: corresponding I2C client
* @regulator: regulator device if used in voltage mode
* @regmap: used for i2c communcation on accessing registers
*/
struct tps6105x {
struct tps6105x_platform_data *pdata;
struct mutex lock;
struct i2c_client *client;
struct regulator_dev *regulator;
struct regmap *regmap;
};
extern int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value);
extern int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf);
extern int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
u8 bitmask, u8 bitvalues);
#endif