Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6:
  regulator/max1586: fix V3 gain calculation integer overflow
  regulator/max1586: support increased V3 voltage range
  regulator: lp3971 - fix driver link error when built-in.
  LP3971 PMIC regulator driver (updated and combined version)
  regulator: remove driver_data direct access of struct device
  regulator: Set MODULE_ALIAS for regulator drivers
  regulator: Support list_voltage for fixed voltage regulator
  regulator: Move regulator drivers to subsys_initcall()
  regulator: build fix for powerpc - renamed show_state
  regulator: add userspace-consumer driver
  Maxim 1586 regulator driver
This commit is contained in:
Linus Torvalds 2009-06-15 09:27:37 -07:00
commit d3bf80bff1
14 changed files with 1236 additions and 8 deletions

View File

@ -47,6 +47,16 @@ config REGULATOR_VIRTUAL_CONSUMER
If unsure, say no.
config REGULATOR_USERSPACE_CONSUMER
tristate "Userspace regulator consumer support"
default n
help
There are some classes of devices that are controlled entirely
from user space. Usersapce consumer driver provides ability to
control power supplies for such devices.
If unsure, say no.
config REGULATOR_BQ24022
tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
default n
@ -56,6 +66,15 @@ config REGULATOR_BQ24022
charging select between 100 mA and 500 mA charging current
limit.
config REGULATOR_MAX1586
tristate "Maxim 1586/1587 voltage regulator"
depends on I2C
default n
help
This driver controls a Maxim 1586 or 1587 voltage output
regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TPS695x0 PMIC"
depends on TWL4030_CORE
@ -91,4 +110,11 @@ config REGULATOR_PCF50633
Say Y here to support the voltage regulators and convertors
on PCF50633
config REGULATOR_LP3971
tristate "National Semiconductors LP3971 PMIC regulator driver"
depends on I2C
help
Say Y here to support the voltage regulators and convertors
on National Semiconductors LP3971 PMIC
endif

View File

@ -6,8 +6,11 @@
obj-$(CONFIG_REGULATOR) += core.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_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o

View File

@ -504,7 +504,7 @@ static int __init da903x_regulator_init(void)
{
return platform_driver_register(&da903x_regulator_driver);
}
module_init(da903x_regulator_init);
subsys_initcall(da903x_regulator_init);
static void __exit da903x_regulator_exit(void)
{

View File

@ -44,10 +44,22 @@ static int fixed_voltage_get_voltage(struct regulator_dev *dev)
return data->microvolts;
}
static int fixed_voltage_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
if (selector != 0)
return -EINVAL;
return data->microvolts;
}
static struct regulator_ops fixed_voltage_ops = {
.is_enabled = fixed_voltage_is_enabled,
.enable = fixed_voltage_enable,
.get_voltage = fixed_voltage_get_voltage,
.list_voltage = fixed_voltage_list_voltage,
};
static int regulator_fixed_voltage_probe(struct platform_device *pdev)
@ -69,7 +81,8 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
}
drvdata->desc.type = REGULATOR_VOLTAGE;
drvdata->desc.owner = THIS_MODULE;
drvdata->desc.ops = &fixed_voltage_ops,
drvdata->desc.ops = &fixed_voltage_ops;
drvdata->desc.n_voltages = 1;
drvdata->microvolts = config->microvolts;
@ -117,7 +130,7 @@ static int __init regulator_fixed_voltage_init(void)
{
return platform_driver_register(&regulator_fixed_voltage_driver);
}
module_init(regulator_fixed_voltage_init);
subsys_initcall(regulator_fixed_voltage_init);
static void __exit regulator_fixed_voltage_exit(void)
{
@ -128,3 +141,4 @@ module_exit(regulator_fixed_voltage_exit);
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("Fixed voltage regulator");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:reg-fixed-voltage");

562
drivers/regulator/lp3971.c Normal file
View File

@ -0,0 +1,562 @@
/*
* Regulator driver for National Semiconductors LP3971 PMIC chip
*
* Copyright (C) 2009 Samsung Electronics
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
*
* Based on wm8350.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/lp3971.h>
struct lp3971 {
struct device *dev;
struct mutex io_lock;
struct i2c_client *i2c;
int num_regulators;
struct regulator_dev **rdev;
};
static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg);
static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val);
#define LP3971_SYS_CONTROL1_REG 0x07
/* System control register 1 initial value,
bits 4 and 5 are EPROM programmable */
#define SYS_CONTROL1_INIT_VAL 0x40
#define SYS_CONTROL1_INIT_MASK 0xCF
#define LP3971_BUCK_VOL_ENABLE_REG 0x10
#define LP3971_BUCK_VOL_CHANGE_REG 0x20
/* Voltage control registers shift:
LP3971_BUCK1 -> 0
LP3971_BUCK2 -> 4
LP3971_BUCK3 -> 6
*/
#define BUCK_VOL_CHANGE_SHIFT(x) (((1 << x) & ~0x01) << 1)
#define BUCK_VOL_CHANGE_FLAG_GO 0x01
#define BUCK_VOL_CHANGE_FLAG_TARGET 0x02
#define BUCK_VOL_CHANGE_FLAG_MASK 0x03
#define LP3971_BUCK1_BASE 0x23
#define LP3971_BUCK2_BASE 0x29
#define LP3971_BUCK3_BASE 0x32
const static int buck_base_addr[] = {
LP3971_BUCK1_BASE,
LP3971_BUCK2_BASE,
LP3971_BUCK3_BASE,
};
#define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
#define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
const static int buck_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,
};
#define BUCK_TARGET_VOL_MASK 0x3f
#define BUCK_TARGET_VOL_MIN_IDX 0x01
#define BUCK_TARGET_VOL_MAX_IDX 0x19
#define LP3971_BUCK_RAMP_REG(x) (buck_base_addr[x]+2)
#define LP3971_LDO_ENABLE_REG 0x12
#define LP3971_LDO_VOL_CONTR_BASE 0x39
/* Voltage control registers:
LP3971_LDO1 -> LP3971_LDO_VOL_CONTR_BASE + 0
LP3971_LDO2 -> LP3971_LDO_VOL_CONTR_BASE + 0
LP3971_LDO3 -> LP3971_LDO_VOL_CONTR_BASE + 1
LP3971_LDO4 -> LP3971_LDO_VOL_CONTR_BASE + 1
LP3971_LDO5 -> LP3971_LDO_VOL_CONTR_BASE + 2
*/
#define LP3971_LDO_VOL_CONTR_REG(x) (LP3971_LDO_VOL_CONTR_BASE + (x >> 1))
/* Voltage control registers shift:
LP3971_LDO1 -> 0, LP3971_LDO2 -> 4
LP3971_LDO3 -> 0, LP3971_LDO4 -> 4
LP3971_LDO5 -> 0
*/
#define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
#define LDO_VOL_CONTR_MASK 0x0f
const static int ldo45_voltage_map[] = {
1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
};
const static int ldo123_voltage_map[] = {
1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
};
const static int *ldo_voltage_map[] = {
ldo123_voltage_map, /* LDO1 */
ldo123_voltage_map, /* LDO2 */
ldo123_voltage_map, /* LDO3 */
ldo45_voltage_map, /* LDO4 */
ldo45_voltage_map, /* LDO5 */
};
#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)])
#define LDO_VOL_MIN_IDX 0x00
#define LDO_VOL_MAX_IDX 0x0f
static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
{
int ldo = rdev_get_id(dev) - LP3971_LDO1;
return 1000 * LDO_VOL_VALUE_MAP(ldo)[index];
}
static int lp3971_ldo_is_enabled(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3971_LDO1;
u16 mask = 1 << (1 + ldo);
u16 val;
val = lp3971_reg_read(lp3971, LP3971_LDO_ENABLE_REG);
return (val & mask) != 0;
}
static int lp3971_ldo_enable(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3971_LDO1;
u16 mask = 1 << (1 + ldo);
return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, mask);
}
static int lp3971_ldo_disable(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3971_LDO1;
u16 mask = 1 << (1 + ldo);
return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
}
static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3971_LDO1;
u16 val, reg;
reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
return 1000 * LDO_VOL_VALUE_MAP(ldo)[val];
}
static int lp3971_ldo_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3971_LDO1;
int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
const int *vol_map = LDO_VOL_VALUE_MAP(ldo);
u16 val;
if (min_vol < vol_map[LDO_VOL_MIN_IDX] ||
min_vol > vol_map[LDO_VOL_MAX_IDX])
return -EINVAL;
for (val = LDO_VOL_MIN_IDX; val <= LDO_VOL_MAX_IDX; val++)
if (vol_map[val] >= min_vol)
break;
if (vol_map[val] > max_vol)
return -EINVAL;
return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo),
LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), val);
}
static struct regulator_ops lp3971_ldo_ops = {
.list_voltage = lp3971_ldo_list_voltage,
.is_enabled = lp3971_ldo_is_enabled,
.enable = lp3971_ldo_enable,
.disable = lp3971_ldo_disable,
.get_voltage = lp3971_ldo_get_voltage,
.set_voltage = lp3971_ldo_set_voltage,
};
static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
{
return 1000 * buck_voltage_map[index];
}
static int lp3971_dcdc_is_enabled(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3971_DCDC1;
u16 mask = 1 << (buck * 2);
u16 val;
val = lp3971_reg_read(lp3971, LP3971_BUCK_VOL_ENABLE_REG);
return (val & mask) != 0;
}
static int lp3971_dcdc_enable(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3971_DCDC1;
u16 mask = 1 << (buck * 2);
return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, mask);
}
static int lp3971_dcdc_disable(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3971_DCDC1;
u16 mask = 1 << (buck * 2);
return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
}
static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3971_DCDC1;
u16 reg;
int val;
reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
reg &= BUCK_TARGET_VOL_MASK;
if (reg <= BUCK_TARGET_VOL_MAX_IDX)
val = 1000 * buck_voltage_map[reg];
else {
val = 0;
dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
}
return val;
}
static int lp3971_dcdc_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3971_DCDC1;
int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
const int *vol_map = buck_voltage_map;
u16 val;
int ret;
if (min_vol < vol_map[BUCK_TARGET_VOL_MIN_IDX] ||
min_vol > vol_map[BUCK_TARGET_VOL_MAX_IDX])
return -EINVAL;
for (val = BUCK_TARGET_VOL_MIN_IDX; val <= BUCK_TARGET_VOL_MAX_IDX;
val++)
if (vol_map[val] >= min_vol)
break;
if (vol_map[val] > max_vol)
return -EINVAL;
ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck),
BUCK_TARGET_VOL_MASK, val);
if (ret)
return ret;
ret = lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
BUCK_VOL_CHANGE_FLAG_GO << BUCK_VOL_CHANGE_SHIFT(buck));
if (ret)
return ret;
return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
0 << BUCK_VOL_CHANGE_SHIFT(buck));
}
static struct regulator_ops lp3971_dcdc_ops = {
.list_voltage = lp3971_dcdc_list_voltage,
.is_enabled = lp3971_dcdc_is_enabled,
.enable = lp3971_dcdc_enable,
.disable = lp3971_dcdc_disable,
.get_voltage = lp3971_dcdc_get_voltage,
.set_voltage = lp3971_dcdc_set_voltage,
};
static struct regulator_desc regulators[] = {
{
.name = "LDO1",
.id = LP3971_LDO1,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "LDO2",
.id = LP3971_LDO2,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "LDO3",
.id = LP3971_LDO3,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "LDO4",
.id = LP3971_LDO4,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "LDO5",
.id = LP3971_LDO5,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "DCDC1",
.id = LP3971_DCDC1,
.ops = &lp3971_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck_voltage_map),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "DCDC2",
.id = LP3971_DCDC2,
.ops = &lp3971_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck_voltage_map),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "DCDC3",
.id = LP3971_DCDC3,
.ops = &lp3971_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck_voltage_map),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
};
static int lp3971_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 || count != 1)
return -EIO;
*dest = ret;
return 0;
}
static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count,
const u16 *src)
{
int ret;
if (count != 1)
return -EIO;
ret = i2c_smbus_write_byte_data(i2c, reg, *src);
if (ret >= 0)
return 0;
return ret;
}
static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg)
{
u16 val = 0;
mutex_lock(&lp3971->io_lock);
lp3971_i2c_read(lp3971->i2c, reg, 1, &val);
dev_dbg(lp3971->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
(unsigned)val&0xff);
mutex_unlock(&lp3971->io_lock);
return val & 0xff;
}
static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)
{
u16 tmp;
int ret;
mutex_lock(&lp3971->io_lock);
ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp);
tmp = (tmp & ~mask) | val;
if (ret == 0) {
ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp);
dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
(unsigned)val&0xff);
}
mutex_unlock(&lp3971->io_lock);
return ret;
}
static int setup_regulators(struct lp3971 *lp3971,
struct lp3971_platform_data *pdata)
{
int i, err;
int num_regulators = pdata->num_regulators;
lp3971->num_regulators = num_regulators;
lp3971->rdev = kzalloc(sizeof(struct regulator_dev *) * num_regulators,
GFP_KERNEL);
/* Instantiate the regulators */
for (i = 0; i < num_regulators; i++) {
int id = pdata->regulators[i].id;
lp3971->rdev[i] = regulator_register(&regulators[id],
lp3971->dev, pdata->regulators[i].initdata, lp3971);
err = IS_ERR(lp3971->rdev[i]);
if (err) {
dev_err(lp3971->dev, "regulator init failed: %d\n",
err);
goto error;
}
}
return 0;
error:
for (i = 0; i < num_regulators; i++)
if (lp3971->rdev[i])
regulator_unregister(lp3971->rdev[i]);
kfree(lp3971->rdev);
lp3971->rdev = NULL;
return err;
}
static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct lp3971 *lp3971;
struct lp3971_platform_data *pdata = i2c->dev.platform_data;
int ret;
u16 val;
lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL);
if (lp3971 == NULL) {
ret = -ENOMEM;
goto err;
}
lp3971->i2c = i2c;
lp3971->dev = &i2c->dev;
i2c_set_clientdata(i2c, lp3971);
mutex_init(&lp3971->io_lock);
/* Detect LP3971 */
ret = lp3971_i2c_read(i2c, LP3971_SYS_CONTROL1_REG, 1, &val);
if (ret == 0 && (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL)
ret = -ENODEV;
if (ret < 0) {
dev_err(&i2c->dev, "failed to detect device\n");
goto err_detect;
}
if (pdata) {
ret = setup_regulators(lp3971, pdata);
if (ret < 0)
goto err_detect;
} else
dev_warn(lp3971->dev, "No platform init data supplied\n");
return 0;
err_detect:
i2c_set_clientdata(i2c, NULL);
kfree(lp3971);
err:
return ret;
}
static int __devexit lp3971_i2c_remove(struct i2c_client *i2c)
{
struct lp3971 *lp3971 = i2c_get_clientdata(i2c);
int i;
for (i = 0; i < lp3971->num_regulators; i++)
if (lp3971->rdev[i])
regulator_unregister(lp3971->rdev[i]);
kfree(lp3971->rdev);
i2c_set_clientdata(i2c, NULL);
kfree(lp3971);
return 0;
}
static const struct i2c_device_id lp3971_i2c_id[] = {
{ "lp3971", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id);
static struct i2c_driver lp3971_i2c_driver = {
.driver = {
.name = "LP3971",
.owner = THIS_MODULE,
},
.probe = lp3971_i2c_probe,
.remove = __devexit_p(lp3971_i2c_remove),
.id_table = lp3971_i2c_id,
};
static int __init lp3971_module_init(void)
{
int ret = -ENODEV;
ret = i2c_add_driver(&lp3971_i2c_driver);
if (ret != 0)
pr_err("Failed to register I2C driver: %d\n", ret);
return ret;
}
module_init(lp3971_module_init);
static void __exit lp3971_module_exit(void)
{
i2c_del_driver(&lp3971_i2c_driver);
}
module_exit(lp3971_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Szyprowski <m.szyprowski@samsung.com>");
MODULE_DESCRIPTION("LP3971 PMIC driver");

282
drivers/regulator/max1586.c Normal file
View File

@ -0,0 +1,282 @@
/*
* max1586.c -- Voltage and current regulation for the Maxim 1586
*
* Copyright (C) 2008 Robert Jarzmik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/max1586.h>
#define MAX1586_V3_MAX_VSEL 31
#define MAX1586_V6_MAX_VSEL 3
#define MAX1586_V3_MIN_UV 700000
#define MAX1586_V3_MAX_UV 1475000
#define MAX1586_V6_MIN_UV 0
#define MAX1586_V6_MAX_UV 3000000
#define I2C_V3_SELECT (0 << 5)
#define I2C_V6_SELECT (1 << 5)
struct max1586_data {
struct i2c_client *client;
/* min/max V3 voltage */
unsigned int min_uV;
unsigned int max_uV;
struct regulator_dev *rdev[0];
};
/*
* V3 voltage
* On I2C bus, sending a "x" byte to the max1586 means :
* set V3 to 0.700V + (x & 0x1f) * 0.025V
* This voltage can be increased by external resistors
* R24 and R25=100kOhm as described in the data sheet.
* The gain is approximately: 1 + R24/R25 + R24/185.5kOhm
*/
static int max1586_v3_calc_voltage(struct max1586_data *max1586,
unsigned selector)
{
unsigned range_uV = max1586->max_uV - max1586->min_uV;
return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL);
}
static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV)
{
struct max1586_data *max1586 = rdev_get_drvdata(rdev);
struct i2c_client *client = max1586->client;
unsigned range_uV = max1586->max_uV - max1586->min_uV;
unsigned selector;
u8 v3_prog;
if (min_uV > max1586->max_uV || max_uV < max1586->min_uV)
return -EINVAL;
if (min_uV < max1586->min_uV)
min_uV = max1586->min_uV;
selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL +
range_uV - 1) / range_uV;
if (max1586_v3_calc_voltage(max1586, selector) > max_uV)
return -EINVAL;
dev_dbg(&client->dev, "changing voltage v3 to %dmv\n",
max1586_v3_calc_voltage(max1586, selector) / 1000);
v3_prog = I2C_V3_SELECT | (u8) selector;
return i2c_smbus_write_byte(client, v3_prog);
}
static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector)
{
struct max1586_data *max1586 = rdev_get_drvdata(rdev);
if (selector > MAX1586_V3_MAX_VSEL)
return -EINVAL;
return max1586_v3_calc_voltage(max1586, selector);
}
/*
* V6 voltage
* On I2C bus, sending a "x" byte to the max1586 means :
* set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
* As regulator framework doesn't accept voltages to be 0V, we use 1uV.
*/
static int max1586_v6_calc_voltage(unsigned selector)
{
static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
return voltages_uv[selector];
}
static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV)
{
struct i2c_client *client = rdev_get_drvdata(rdev);
unsigned selector;
u8 v6_prog;
if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV)
return -EINVAL;
if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV)
return -EINVAL;
if (min_uV >= 3000000)
selector = 3;
if (min_uV < 3000000)
selector = 2;
if (min_uV < 2500000)
selector = 1;
if (min_uV < 1800000)
selector = 0;
if (max1586_v6_calc_voltage(selector) > max_uV)
return -EINVAL;
dev_dbg(&client->dev, "changing voltage v6 to %dmv\n",
max1586_v6_calc_voltage(selector) / 1000);
v6_prog = I2C_V6_SELECT | (u8) selector;
return i2c_smbus_write_byte(client, v6_prog);
}
static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector)
{
if (selector > MAX1586_V6_MAX_VSEL)
return -EINVAL;
return max1586_v6_calc_voltage(selector);
}
/*
* The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back
* the set up value.
*/
static struct regulator_ops max1586_v3_ops = {
.set_voltage = max1586_v3_set,
.list_voltage = max1586_v3_list,
};
static struct regulator_ops max1586_v6_ops = {
.set_voltage = max1586_v6_set,
.list_voltage = max1586_v6_list,
};
static struct regulator_desc max1586_reg[] = {
{
.name = "Output_V3",
.id = MAX1586_V3,
.ops = &max1586_v3_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = MAX1586_V3_MAX_VSEL + 1,
.owner = THIS_MODULE,
},
{
.name = "Output_V6",
.id = MAX1586_V6,
.ops = &max1586_v6_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = MAX1586_V6_MAX_VSEL + 1,
.owner = THIS_MODULE,
},
};
static int max1586_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
struct regulator_dev **rdev;
struct max1586_platform_data *pdata = client->dev.platform_data;
struct max1586_data *max1586;
int i, id, ret = -ENOMEM;
max1586 = kzalloc(sizeof(struct max1586_data) +
sizeof(struct regulator_dev *) * (MAX1586_V6 + 1),
GFP_KERNEL);
if (!max1586)
goto out;
max1586->client = client;
if (!pdata->v3_gain) {
ret = -EINVAL;
goto out_unmap;
}
max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000;
max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000;
rdev = max1586->rdev;
for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) {
id = pdata->subdevs[i].id;
if (!pdata->subdevs[i].platform_data)
continue;
if (id < MAX1586_V3 || id > MAX1586_V6) {
dev_err(&client->dev, "invalid regulator id %d\n", id);
goto err;
}
rdev[i] = regulator_register(&max1586_reg[id], &client->dev,
pdata->subdevs[i].platform_data,
max1586);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(&client->dev, "failed to register %s\n",
max1586_reg[id].name);
goto err;
}
}
i2c_set_clientdata(client, rdev);
dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n");
return 0;
err:
while (--i >= 0)
regulator_unregister(rdev[i]);
out_unmap:
kfree(max1586);
out:
return ret;
}
static int max1586_pmic_remove(struct i2c_client *client)
{
struct regulator_dev **rdev = i2c_get_clientdata(client);
int i;
for (i = 0; i <= MAX1586_V6; i++)
if (rdev[i])
regulator_unregister(rdev[i]);
kfree(rdev);
i2c_set_clientdata(client, NULL);
return 0;
}
static const struct i2c_device_id max1586_id[] = {
{ "max1586", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max1586_id);
static struct i2c_driver max1586_pmic_driver = {
.probe = max1586_pmic_probe,
.remove = max1586_pmic_remove,
.driver = {
.name = "max1586",
},
.id_table = max1586_id,
};
static int __init max1586_pmic_init(void)
{
return i2c_add_driver(&max1586_pmic_driver);
}
subsys_initcall(max1586_pmic_init);
static void __exit max1586_pmic_exit(void)
{
i2c_del_driver(&max1586_pmic_driver);
}
module_exit(max1586_pmic_exit);
/* Module information */
MODULE_DESCRIPTION("MAXIM 1586 voltage regulator driver");
MODULE_AUTHOR("Robert Jarzmik");
MODULE_LICENSE("GPL");

View File

@ -316,7 +316,7 @@ static int __init pcf50633_regulator_init(void)
{
return platform_driver_register(&pcf50633_regulator_driver);
}
module_init(pcf50633_regulator_init);
subsys_initcall(pcf50633_regulator_init);
static void __exit pcf50633_regulator_exit(void)
{

View File

@ -0,0 +1,200 @@
/*
* userspace-consumer.c
*
* Copyright 2009 CompuLab, Ltd.
*
* Author: Mike Rapoport <mike@compulab.co.il>
*
* Based of virtual consumer driver:
* Copyright 2008 Wolfson Microelectronics PLC.
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
*/
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/userspace-consumer.h>
struct userspace_consumer_data {
const char *name;
struct mutex lock;
bool enabled;
int num_supplies;
struct regulator_bulk_data *supplies;
};
static ssize_t reg_show_name(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct userspace_consumer_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", data->name);
}
static ssize_t reg_show_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct userspace_consumer_data *data = dev_get_drvdata(dev);
if (data->enabled)
return sprintf(buf, "enabled\n");
return sprintf(buf, "disabled\n");
}
static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct userspace_consumer_data *data = dev_get_drvdata(dev);
bool enabled;
int ret;
/*
* sysfs_streq() doesn't need the \n's, but we add them so the strings
* will be shared with show_state(), above.
*/
if (sysfs_streq(buf, "enabled\n") || sysfs_streq(buf, "1"))
enabled = true;
else if (sysfs_streq(buf, "disabled\n") || sysfs_streq(buf, "0"))
enabled = false;
else {
dev_err(dev, "Configuring invalid mode\n");
return count;
}
mutex_lock(&data->lock);
if (enabled != data->enabled) {
if (enabled)
ret = regulator_bulk_enable(data->num_supplies,
data->supplies);
else
ret = regulator_bulk_disable(data->num_supplies,
data->supplies);
if (ret == 0)
data->enabled = enabled;
else
dev_err(dev, "Failed to configure state: %d\n", ret);
}
mutex_unlock(&data->lock);
return count;
}
static DEVICE_ATTR(name, 0444, reg_show_name, NULL);
static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state);
static struct device_attribute *attributes[] = {
&dev_attr_name,
&dev_attr_state,
};
static int regulator_userspace_consumer_probe(struct platform_device *pdev)
{
struct regulator_userspace_consumer_data *pdata;
struct userspace_consumer_data *drvdata;
int ret, i;
pdata = pdev->dev.platform_data;
if (!pdata)
return -EINVAL;
drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL);
if (drvdata == NULL)
return -ENOMEM;
drvdata->name = pdata->name;
drvdata->num_supplies = pdata->num_supplies;
drvdata->supplies = pdata->supplies;
mutex_init(&drvdata->lock);
ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies,
drvdata->supplies);
if (ret) {
dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret);
goto err_alloc_supplies;
}
for (i = 0; i < ARRAY_SIZE(attributes); i++) {
ret = device_create_file(&pdev->dev, attributes[i]);
if (ret != 0)
goto err_create_attrs;
}
if (pdata->init_on)
ret = regulator_bulk_enable(drvdata->num_supplies,
drvdata->supplies);
drvdata->enabled = pdata->init_on;
if (ret) {
dev_err(&pdev->dev, "Failed to set initial state: %d\n", ret);
goto err_create_attrs;
}
platform_set_drvdata(pdev, drvdata);
return 0;
err_create_attrs:
for (i = 0; i < ARRAY_SIZE(attributes); i++)
device_remove_file(&pdev->dev, attributes[i]);
regulator_bulk_free(drvdata->num_supplies, drvdata->supplies);
err_alloc_supplies:
kfree(drvdata);
return ret;
}
static int regulator_userspace_consumer_remove(struct platform_device *pdev)
{
struct userspace_consumer_data *data = platform_get_drvdata(pdev);
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++)
device_remove_file(&pdev->dev, attributes[i]);
if (data->enabled)
regulator_bulk_disable(data->num_supplies, data->supplies);
regulator_bulk_free(data->num_supplies, data->supplies);
kfree(data);
return 0;
}
static struct platform_driver regulator_userspace_consumer_driver = {
.probe = regulator_userspace_consumer_probe,
.remove = regulator_userspace_consumer_remove,
.driver = {
.name = "reg-userspace-consumer",
},
};
static int __init regulator_userspace_consumer_init(void)
{
return platform_driver_register(&regulator_userspace_consumer_driver);
}
module_init(regulator_userspace_consumer_init);
static void __exit regulator_userspace_consumer_exit(void)
{
platform_driver_unregister(&regulator_userspace_consumer_driver);
}
module_exit(regulator_userspace_consumer_exit);
MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators");
MODULE_LICENSE("GPL");

View File

@ -347,3 +347,4 @@ module_exit(regulator_virtual_consumer_exit);
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("Virtual regulator consumer");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:reg-virt-consumer");

View File

@ -1570,3 +1570,4 @@ module_exit(wm8350_regulator_exit);
MODULE_AUTHOR("Liam Girdwood");
MODULE_DESCRIPTION("WM8350 voltage and current regulator driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm8350-regulator");

View File

@ -320,7 +320,7 @@ static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
pdev->dev.platform_data, pdev->dev.driver_data);
pdev->dev.platform_data, dev_get_drvdata(&pdev->dev));
if (IS_ERR(rdev))
return PTR_ERR(rdev);
@ -359,7 +359,7 @@ static struct platform_driver wm8400_regulator_driver = {
int wm8400_register_regulator(struct device *dev, int reg,
struct regulator_init_data *initdata)
{
struct wm8400 *wm8400 = dev->driver_data;
struct wm8400 *wm8400 = dev_get_drvdata(dev);
if (wm8400->regulators[reg].name)
return -EBUSY;
@ -369,8 +369,8 @@ int wm8400_register_regulator(struct device *dev, int reg,
wm8400->regulators[reg].name = "wm8400-regulator";
wm8400->regulators[reg].id = reg;
wm8400->regulators[reg].dev.parent = dev;
wm8400->regulators[reg].dev.driver_data = wm8400;
wm8400->regulators[reg].dev.platform_data = initdata;
dev_set_drvdata(&wm8400->regulators[reg].dev, wm8400);
return platform_device_register(&wm8400->regulators[reg]);
}
@ -380,7 +380,7 @@ static int __init wm8400_regulator_init(void)
{
return platform_driver_register(&wm8400_regulator_driver);
}
module_init(wm8400_regulator_init);
subsys_initcall(wm8400_regulator_init);
static void __exit wm8400_regulator_exit(void)
{

View File

@ -0,0 +1,51 @@
/*
* National Semiconductors LP3971 PMIC chip client interface
*
* Copyright (C) 2009 Samsung Electronics
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
*
* Based on wm8400.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __LINUX_REGULATOR_LP3971_H
#define __LINUX_REGULATOR_LP3971_H
#include <linux/regulator/machine.h>
#define LP3971_LDO1 0
#define LP3971_LDO2 1
#define LP3971_LDO3 2
#define LP3971_LDO4 3
#define LP3971_LDO5 4
#define LP3971_DCDC1 5
#define LP3971_DCDC2 6
#define LP3971_DCDC3 7
#define LP3971_NUM_REGULATORS 8
struct lp3971_regulator_subdev {
int id;
struct regulator_init_data *initdata;
};
struct lp3971_platform_data {
int num_regulators;
struct lp3971_regulator_subdev *regulators;
};
#endif

View File

@ -0,0 +1,63 @@
/*
* max1586.h -- Voltage regulation for the Maxim 1586
*
* Copyright (C) 2008 Robert Jarzmik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef REGULATOR_MAX1586
#define REGULATOR_MAX1586
#include <linux/regulator/machine.h>
#define MAX1586_V3 0
#define MAX1586_V6 1
/* precalculated values for v3_gain */
#define MAX1586_GAIN_NO_R24 1000000 /* 700000 .. 1475000 mV */
#define MAX1586_GAIN_R24_3k32 1051098 /* 735768 .. 1550369 mV */
#define MAX1586_GAIN_R24_5k11 1078648 /* 755053 .. 1591005 mV */
#define MAX1586_GAIN_R24_7k5 1115432 /* 780802 .. 1645262 mV */
/**
* max1586_subdev_data - regulator data
* @id: regulator Id (either MAX1586_V3 or MAX1586_V6)
* @name: regulator cute name (example for V3: "vcc_core")
* @platform_data: regulator init data (contraints, supplies, ...)
*/
struct max1586_subdev_data {
int id;
char *name;
struct regulator_init_data *platform_data;
};
/**
* max1586_platform_data - platform data for max1586
* @num_subdevs: number of regultors used (may be 1 or 2)
* @subdevs: regulator used
* At most, there will be a regulator for V3 and one for V6 voltages.
* @v3_gain: gain on the V3 voltage output multiplied by 1e6.
* This can be calculated as ((1 + R24/R25 + R24/185.5kOhm) * 1e6)
* for an external resistor configuration as described in the
* data sheet (R25=100kOhm).
*/
struct max1586_platform_data {
int num_subdevs;
struct max1586_subdev_data *subdevs;
int v3_gain;
};
#endif

View File

@ -0,0 +1,25 @@
#ifndef __REGULATOR_PLATFORM_CONSUMER_H_
#define __REGULATOR_PLATFORM_CONSUMER_H_
struct regulator_consumer_supply;
/**
* struct regulator_userspace_consumer_data - line consumer
* initialisation data.
*
* @name: Name for the consumer line
* @num_supplies: Number of supplies feeding the line
* @supplies: Supplies configuration.
* @init_on: Set if the regulators supplying the line should be
* enabled during initialisation
*/
struct regulator_userspace_consumer_data {
const char *name;
int num_supplies;
struct regulator_bulk_data *supplies;
bool init_on;
};
#endif /* __REGULATOR_PLATFORM_CONSUMER_H_ */