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: (22 commits)
  regulator: Remove default DEBUG define from TPS6586x
  regulator: tps6507x - add missing platform_set_drvdata in tps6507x_pmic_probe
  regulator: tps6586x - add regulator_unregister() in tps6586x_regulator_remove()
  mfd: max8998 - fix incorrect kfree(i2c) in i2c_driver probe callback handler
  regulator: lp3971 - remove unnecessary ret value checking in lp3971_i2c_write()
  regulator: max8660 - fix a memory leak in max8660_remove()
  regulator: max1586 - fix a memory leak in max1586_pmic_remove()
  regulator: Default GPIO controlled WM8994 regulators to disabled
  regulator: lp3971 - remove unnecessary ret value checking in lp3971_i2c_write()
  max8998: fix off-by-one value range checking
  regulator: tps6586x: fix millivolt return values and SM2 table
  regulator: tps6586x: add dependancy on MFD_TPS6585x
  regulator: add TPS6586X regulator driver
  regulator: MAX8998: set_voltage bugfix. ramp_up delay and min/max voltage
  regulator: add support for regulators on the ab8500 MFD
  ab8500-mfd: add regulator support to ab8500 mfd device
  tps65023: Allow registering similar TPS65021
  drivers: regulators: depend on MFD_MAX8998
  drivers: regulator: add Maxim 8998 driver
  ISL6271A voltage regulator support.
  ...
This commit is contained in:
Linus Torvalds 2010-08-12 10:01:30 -07:00
Родитель e83ddb3354 120be66328
Коммит 580287628c
21 изменённых файлов: 2431 добавлений и 22 удалений

Просмотреть файл

@ -293,6 +293,16 @@ config MFD_MAX8925
accessing the device, additional drivers must be enabled in order accessing the device, additional drivers must be enabled in order
to use the functionality of the device. to use the functionality of the device.
config MFD_MAX8998
bool "Maxim Semiconductor MAX8998 PMIC Support"
depends on I2C=y
select MFD_CORE
help
Say yes here to support for Maxim Semiconductor MAX8998. This is
a Power Management IC. This driver provies common support for
accessing the device, additional drivers must be enabled in order
to use the functionality of the device.
config MFD_WM8400 config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400" tristate "Support Wolfson Microelectronics WM8400"
select MFD_CORE select MFD_CORE

Просмотреть файл

@ -58,6 +58,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
obj-$(CONFIG_PMIC_DA903X) += da903x.o obj-$(CONFIG_PMIC_DA903X) += da903x.o
max8925-objs := max8925-core.o max8925-i2c.o max8925-objs := max8925-core.o max8925-i2c.o
obj-$(CONFIG_MFD_MAX8925) += max8925.o obj-$(CONFIG_MFD_MAX8925) += max8925.o
obj-$(CONFIG_MFD_MAX8998) += max8998.o
pcf50633-objs := pcf50633-core.o pcf50633-irq.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o

Просмотреть файл

@ -16,6 +16,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/ab8500.h> #include <linux/mfd/ab8500.h>
#include <linux/regulator/ab8500.h>
/* /*
* Interrupt register offsets * Interrupt register offsets
@ -352,6 +353,7 @@ static struct mfd_cell ab8500_devs[] = {
{ .name = "ab8500-audio", }, { .name = "ab8500-audio", },
{ .name = "ab8500-usb", }, { .name = "ab8500-usb", },
{ .name = "ab8500-pwm", }, { .name = "ab8500-pwm", },
{ .name = "ab8500-regulator", },
}; };
int __devinit ab8500_init(struct ab8500 *ab8500) int __devinit ab8500_init(struct ab8500 *ab8500)
@ -411,7 +413,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
goto out_removeirq; goto out_removeirq;
} }
ret = mfd_add_devices(ab8500->dev, -1, ab8500_devs, ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab8500_devs), NULL, ARRAY_SIZE(ab8500_devs), NULL,
ab8500->irq_base); ab8500->irq_base);
if (ret) if (ret)

158
drivers/mfd/max8998.c Normal file
Просмотреть файл

@ -0,0 +1,158 @@
/*
* max8698.c - mfd core driver for the Maxim 8998
*
* Copyright (C) 2009-2010 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
* Marek Szyprowski <m.szyprowski@samsung.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.
*
* 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/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max8998.h>
#include <linux/mfd/max8998-private.h>
static struct mfd_cell max8998_devs[] = {
{
.name = "max8998-pmic",
}
};
static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest)
{
struct i2c_client *client = max8998->i2c_client;
int ret;
mutex_lock(&max8998->iolock);
ret = i2c_smbus_read_byte_data(client, reg);
mutex_unlock(&max8998->iolock);
if (ret < 0)
return ret;
ret &= 0xff;
*dest = ret;
return 0;
}
static int max8998_i2c_device_write(struct max8998_dev *max8998, u8 reg, u8 value)
{
struct i2c_client *client = max8998->i2c_client;
int ret;
mutex_lock(&max8998->iolock);
ret = i2c_smbus_write_byte_data(client, reg, value);
mutex_unlock(&max8998->iolock);
return ret;
}
static int max8998_i2c_device_update(struct max8998_dev *max8998, u8 reg,
u8 val, u8 mask)
{
struct i2c_client *client = max8998->i2c_client;
int ret;
mutex_lock(&max8998->iolock);
ret = i2c_smbus_read_byte_data(client, reg);
if (ret >= 0) {
u8 old_val = ret & 0xff;
u8 new_val = (val & mask) | (old_val & (~mask));
ret = i2c_smbus_write_byte_data(client, reg, new_val);
if (ret >= 0)
ret = 0;
}
mutex_unlock(&max8998->iolock);
return ret;
}
static int max8998_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct max8998_dev *max8998;
int ret = 0;
max8998 = kzalloc(sizeof(struct max8998_dev), GFP_KERNEL);
if (max8998 == NULL)
return -ENOMEM;
i2c_set_clientdata(i2c, max8998);
max8998->dev = &i2c->dev;
max8998->i2c_client = i2c;
max8998->dev_read = max8998_i2c_device_read;
max8998->dev_write = max8998_i2c_device_write;
max8998->dev_update = max8998_i2c_device_update;
mutex_init(&max8998->iolock);
ret = mfd_add_devices(max8998->dev, -1,
max8998_devs, ARRAY_SIZE(max8998_devs),
NULL, 0);
if (ret < 0)
goto err;
return ret;
err:
mfd_remove_devices(max8998->dev);
kfree(max8998);
return ret;
}
static int max8998_i2c_remove(struct i2c_client *i2c)
{
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
mfd_remove_devices(max8998->dev);
kfree(max8998);
return 0;
}
static const struct i2c_device_id max8998_i2c_id[] = {
{ "max8998", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
static struct i2c_driver max8998_i2c_driver = {
.driver = {
.name = "max8998",
.owner = THIS_MODULE,
},
.probe = max8998_i2c_probe,
.remove = max8998_i2c_remove,
.id_table = max8998_i2c_id,
};
static int __init max8998_i2c_init(void)
{
return i2c_add_driver(&max8998_i2c_driver);
}
/* init early so consumer devices can complete system boot */
subsys_initcall(max8998_i2c_init);
static void __exit max8998_i2c_exit(void)
{
i2c_del_driver(&max8998_i2c_driver);
}
module_exit(max8998_i2c_exit);
MODULE_DESCRIPTION("MAXIM 8998 multi-function core driver");
MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
MODULE_LICENSE("GPL");

Просмотреть файл

@ -100,6 +100,14 @@ config REGULATOR_MAX8925
help help
Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC. Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC.
config REGULATOR_MAX8998
tristate "Maxim 8998 voltage regulator"
depends on MFD_MAX8998
help
This driver controls a Maxim 8998 voltage output regulator
via I2C bus. The provided regulator is suitable for S3C6410
and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
config REGULATOR_TWL4030 config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC" bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC"
depends on TWL4030_CORE depends on TWL4030_CORE
@ -201,5 +209,31 @@ config REGULATOR_88PM8607
help help
This driver supports 88PM8607 voltage regulator chips. This driver supports 88PM8607 voltage regulator chips.
config REGULATOR_ISL6271A
tristate "Intersil ISL6271A Power regulator"
depends on I2C
help
This driver supports ISL6271A voltage regulator chip.
config REGULATOR_AD5398
tristate "Analog Devices AD5398/AD5821 regulators"
depends on I2C
help
This driver supports AD5398 and AD5821 current regulator chips.
If building into module, its name is ad5398.ko.
config REGULATOR_AB8500
bool "ST-Ericsson AB8500 Power Regulators"
depends on AB8500_CORE
help
This driver supports the regulators found on the ST-Ericsson mixed
signal AB8500 PMIC
config REGULATOR_TPS6586X
tristate "TI TPS6586X Power regulators"
depends on MFD_TPS6586X
help
This driver supports TPS6586X voltage regulator chips.
endif endif

Просмотреть файл

@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
@ -16,12 +17,14 @@ obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
@ -31,5 +34,7 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG

427
drivers/regulator/ab8500.c Normal file
Просмотреть файл

@ -0,0 +1,427 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
*
* AB8500 peripheral regulators
*
* AB8500 supports the following regulators,
* LDOs - VAUDIO, VANAMIC2/2, VDIGMIC, VINTCORE12, VTVOUT,
* VAUX1/2/3, VANA
*
* for DB8500 cut 1.0 and previous versions of the silicon, all accesses
* to registers are through the DB8500 SPI. In cut 1.1 onwards, these
* accesses are through the DB8500 PRCMU I2C
*
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/mfd/ab8500.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>
/**
* struct ab8500_regulator_info - ab8500 regulator information
* @desc: regulator description
* @ab8500: ab8500 parent
* @regulator_dev: regulator device
* @max_uV: maximum voltage (for variable voltage supplies)
* @min_uV: minimum voltage (for variable voltage supplies)
* @fixed_uV: typical voltage (for fixed voltage supplies)
* @update_reg: register to control on/off
* @mask: mask to enable/disable regulator
* @enable: bits to enable the regulator in normal(high power) mode
* @voltage_reg: register to control regulator voltage
* @voltage_mask: mask to control regulator voltage
* @supported_voltages: supported voltage table
* @voltages_len: number of supported voltages for the regulator
*/
struct ab8500_regulator_info {
struct device *dev;
struct regulator_desc desc;
struct ab8500 *ab8500;
struct regulator_dev *regulator;
int max_uV;
int min_uV;
int fixed_uV;
int update_reg;
int mask;
int enable;
int voltage_reg;
int voltage_mask;
int const *supported_voltages;
int voltages_len;
};
/* voltage tables for the vauxn/vintcore supplies */
static const int ldo_vauxn_voltages[] = {
1100000,
1200000,
1300000,
1400000,
1500000,
1800000,
1850000,
1900000,
2500000,
2650000,
2700000,
2750000,
2800000,
2900000,
3000000,
3300000,
};
static const int ldo_vintcore_voltages[] = {
1200000,
1225000,
1250000,
1275000,
1300000,
1325000,
1350000,
};
static int ab8500_regulator_enable(struct regulator_dev *rdev)
{
int regulator_id, ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= AB8500_NUM_REGULATORS)
return -EINVAL;
ret = ab8500_set_bits(info->ab8500, info->update_reg,
info->mask, info->enable);
if (ret < 0)
dev_err(rdev_get_dev(rdev),
"couldn't set enable bits for regulator\n");
return ret;
}
static int ab8500_regulator_disable(struct regulator_dev *rdev)
{
int regulator_id, ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= AB8500_NUM_REGULATORS)
return -EINVAL;
ret = ab8500_set_bits(info->ab8500, info->update_reg,
info->mask, 0x0);
if (ret < 0)
dev_err(rdev_get_dev(rdev),
"couldn't set disable bits for regulator\n");
return ret;
}
static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
{
int regulator_id, ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= AB8500_NUM_REGULATORS)
return -EINVAL;
ret = ab8500_read(info->ab8500, info->update_reg);
if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"couldn't read 0x%x register\n", info->update_reg);
return ret;
}
if (ret & info->mask)
return true;
else
return false;
}
static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
{
int regulator_id;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= AB8500_NUM_REGULATORS)
return -EINVAL;
/* return the uV for the fixed regulators */
if (info->fixed_uV)
return info->fixed_uV;
if (selector > info->voltages_len)
return -EINVAL;
return info->supported_voltages[selector];
}
static int ab8500_regulator_get_voltage(struct regulator_dev *rdev)
{
int regulator_id, ret, val;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= AB8500_NUM_REGULATORS)
return -EINVAL;
ret = ab8500_read(info->ab8500, info->voltage_reg);
if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"couldn't read voltage reg for regulator\n");
return ret;
}
/* vintcore has a different layout */
val = ret & info->voltage_mask;
if (regulator_id == AB8500_LDO_INTCORE)
ret = info->supported_voltages[val >> 0x3];
else
ret = info->supported_voltages[val];
return ret;
}
static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
int i;
/* check the supported voltage */
for (i = 0; i < info->voltages_len; i++) {
if ((info->supported_voltages[i] >= min_uV) &&
(info->supported_voltages[i] <= max_uV))
return i;
}
return -EINVAL;
}
static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
int regulator_id, ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= AB8500_NUM_REGULATORS)
return -EINVAL;
/* get the appropriate voltages within the range */
ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"couldn't get best voltage for regulator\n");
return ret;
}
/* set the registers for the request */
ret = ab8500_set_bits(info->ab8500, info->voltage_reg,
info->voltage_mask, ret);
if (ret < 0)
dev_err(rdev_get_dev(rdev),
"couldn't set voltage reg for regulator\n");
return ret;
}
static struct regulator_ops ab8500_regulator_ops = {
.enable = ab8500_regulator_enable,
.disable = ab8500_regulator_disable,
.is_enabled = ab8500_regulator_is_enabled,
.get_voltage = ab8500_regulator_get_voltage,
.set_voltage = ab8500_regulator_set_voltage,
.list_voltage = ab8500_list_voltage,
};
static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
{
int regulator_id;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= AB8500_NUM_REGULATORS)
return -EINVAL;
return info->fixed_uV;
}
static struct regulator_ops ab8500_ldo_fixed_ops = {
.enable = ab8500_regulator_enable,
.disable = ab8500_regulator_disable,
.is_enabled = ab8500_regulator_is_enabled,
.get_voltage = ab8500_fixed_get_voltage,
.list_voltage = ab8500_list_voltage,
};
#define AB8500_LDO(_id, min, max, reg, reg_mask, reg_enable, \
volt_reg, volt_mask, voltages, \
len_volts) \
{ \
.desc = { \
.name = "LDO-" #_id, \
.ops = &ab8500_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = AB8500_LDO_##_id, \
.owner = THIS_MODULE, \
}, \
.min_uV = (min) * 1000, \
.max_uV = (max) * 1000, \
.update_reg = reg, \
.mask = reg_mask, \
.enable = reg_enable, \
.voltage_reg = volt_reg, \
.voltage_mask = volt_mask, \
.supported_voltages = voltages, \
.voltages_len = len_volts, \
.fixed_uV = 0, \
}
#define AB8500_FIXED_LDO(_id, fixed, reg, reg_mask, \
reg_enable) \
{ \
.desc = { \
.name = "LDO-" #_id, \
.ops = &ab8500_ldo_fixed_ops, \
.type = REGULATOR_VOLTAGE, \
.id = AB8500_LDO_##_id, \
.owner = THIS_MODULE, \
}, \
.fixed_uV = fixed * 1000, \
.update_reg = reg, \
.mask = reg_mask, \
.enable = reg_enable, \
}
static struct ab8500_regulator_info ab8500_regulator_info[] = {
/*
* Variable Voltage LDOs
* name, min uV, max uV, ctrl reg, reg mask, enable mask,
* volt ctrl reg, volt ctrl mask, volt table, num supported volts
*/
AB8500_LDO(AUX1, 1100, 3300, 0x0409, 0x3, 0x1, 0x041f, 0xf,
ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
AB8500_LDO(AUX2, 1100, 3300, 0x0409, 0xc, 0x4, 0x0420, 0xf,
ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
AB8500_LDO(AUX3, 1100, 3300, 0x040a, 0x3, 0x1, 0x0421, 0xf,
ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
AB8500_LDO(INTCORE, 1100, 3300, 0x0380, 0x4, 0x4, 0x0380, 0x38,
ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)),
/*
* Fixed Voltage LDOs
* name, o/p uV, ctrl reg, enable, disable
*/
AB8500_FIXED_LDO(TVOUT, 2000, 0x0380, 0x2, 0x2),
AB8500_FIXED_LDO(AUDIO, 2000, 0x0383, 0x2, 0x2),
AB8500_FIXED_LDO(ANAMIC1, 2050, 0x0383, 0x4, 0x4),
AB8500_FIXED_LDO(ANAMIC2, 2050, 0x0383, 0x8, 0x8),
AB8500_FIXED_LDO(DMIC, 1800, 0x0383, 0x10, 0x10),
AB8500_FIXED_LDO(ANA, 1200, 0x0383, 0xc, 0x4),
};
static inline struct ab8500_regulator_info *find_regulator_info(int id)
{
struct ab8500_regulator_info *info;
int i;
for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
info = &ab8500_regulator_info[i];
if (info->desc.id == id)
return info;
}
return NULL;
}
static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev);
int i, err;
if (!ab8500) {
dev_err(&pdev->dev, "null mfd parent\n");
return -EINVAL;
}
/* register all regulators */
for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
struct ab8500_regulator_info *info = NULL;
/* assign per-regulator data */
info = &ab8500_regulator_info[i];
info->dev = &pdev->dev;
info->ab8500 = ab8500;
info->regulator = regulator_register(&info->desc, &pdev->dev,
pdata->regulator[i], info);
if (IS_ERR(info->regulator)) {
err = PTR_ERR(info->regulator);
dev_err(&pdev->dev, "failed to register regulator %s\n",
info->desc.name);
/* when we fail, un-register all earlier regulators */
i--;
while (i > 0) {
info = &ab8500_regulator_info[i];
regulator_unregister(info->regulator);
i--;
}
return err;
}
}
return 0;
}
static __devexit int ab8500_regulator_remove(struct platform_device *pdev)
{
int i;
for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
struct ab8500_regulator_info *info = NULL;
info = &ab8500_regulator_info[i];
regulator_unregister(info->regulator);
}
return 0;
}
static struct platform_driver ab8500_regulator_driver = {
.probe = ab8500_regulator_probe,
.remove = __devexit_p(ab8500_regulator_remove),
.driver = {
.name = "ab8500-regulator",
.owner = THIS_MODULE,
},
};
static int __init ab8500_regulator_init(void)
{
int ret;
ret = platform_driver_register(&ab8500_regulator_driver);
if (ret != 0)
pr_err("Failed to register ab8500 regulator: %d\n", ret);
return ret;
}
subsys_initcall(ab8500_regulator_init);
static void __exit ab8500_regulator_exit(void)
{
platform_driver_unregister(&ab8500_regulator_driver);
}
module_exit(ab8500_regulator_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC");
MODULE_ALIAS("platform:ab8500-regulator");

288
drivers/regulator/ad5398.c Normal file
Просмотреть файл

@ -0,0 +1,288 @@
/*
* Voltage and current regulation for AD5398 and AD5821
*
* Copyright 2010 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#define AD5398_CURRENT_EN_MASK 0x8000
struct ad5398_chip_info {
struct i2c_client *client;
int min_uA;
int max_uA;
unsigned int current_level;
unsigned int current_mask;
unsigned int current_offset;
struct regulator_dev rdev;
};
static int ad5398_calc_current(struct ad5398_chip_info *chip,
unsigned selector)
{
unsigned range_uA = chip->max_uA - chip->min_uA;
return chip->min_uA + (selector * range_uA / chip->current_level);
}
static int ad5398_read_reg(struct i2c_client *client, unsigned short *data)
{
unsigned short val;
int ret;
ret = i2c_master_recv(client, (char *)&val, 2);
if (ret < 0) {
dev_err(&client->dev, "I2C read error\n");
return ret;
}
*data = be16_to_cpu(val);
return ret;
}
static int ad5398_write_reg(struct i2c_client *client, const unsigned short data)
{
unsigned short val;
int ret;
val = cpu_to_be16(data);
ret = i2c_master_send(client, (char *)&val, 2);
if (ret < 0)
dev_err(&client->dev, "I2C write error\n");
return ret;
}
static int ad5398_get_current_limit(struct regulator_dev *rdev)
{
struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
struct i2c_client *client = chip->client;
unsigned short data;
int ret;
ret = ad5398_read_reg(client, &data);
if (ret < 0)
return ret;
ret = (data & chip->current_mask) >> chip->current_offset;
return ad5398_calc_current(chip, ret);
}
static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
{
struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
struct i2c_client *client = chip->client;
unsigned range_uA = chip->max_uA - chip->min_uA;
unsigned selector;
unsigned short data;
int ret;
if (min_uA > chip->max_uA || min_uA < chip->min_uA)
return -EINVAL;
if (max_uA > chip->max_uA || max_uA < chip->min_uA)
return -EINVAL;
selector = ((min_uA - chip->min_uA) * chip->current_level +
range_uA - 1) / range_uA;
if (ad5398_calc_current(chip, selector) > max_uA)
return -EINVAL;
dev_dbg(&client->dev, "changing current %dmA\n",
ad5398_calc_current(chip, selector) / 1000);
/* read chip enable bit */
ret = ad5398_read_reg(client, &data);
if (ret < 0)
return ret;
/* prepare register data */
selector = (selector << chip->current_offset) & chip->current_mask;
data = (unsigned short)selector | (data & AD5398_CURRENT_EN_MASK);
/* write the new current value back as well as enable bit */
ret = ad5398_write_reg(client, data);
return ret;
}
static int ad5398_is_enabled(struct regulator_dev *rdev)
{
struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
struct i2c_client *client = chip->client;
unsigned short data;
int ret;
ret = ad5398_read_reg(client, &data);
if (ret < 0)
return ret;
if (data & AD5398_CURRENT_EN_MASK)
return 1;
else
return 0;
}
static int ad5398_enable(struct regulator_dev *rdev)
{
struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
struct i2c_client *client = chip->client;
unsigned short data;
int ret;
ret = ad5398_read_reg(client, &data);
if (ret < 0)
return ret;
if (data & AD5398_CURRENT_EN_MASK)
return 0;
data |= AD5398_CURRENT_EN_MASK;
ret = ad5398_write_reg(client, data);
return ret;
}
static int ad5398_disable(struct regulator_dev *rdev)
{
struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
struct i2c_client *client = chip->client;
unsigned short data;
int ret;
ret = ad5398_read_reg(client, &data);
if (ret < 0)
return ret;
if (!(data & AD5398_CURRENT_EN_MASK))
return 0;
data &= ~AD5398_CURRENT_EN_MASK;
ret = ad5398_write_reg(client, data);
return ret;
}
static struct regulator_ops ad5398_ops = {
.get_current_limit = ad5398_get_current_limit,
.set_current_limit = ad5398_set_current_limit,
.enable = ad5398_enable,
.disable = ad5398_disable,
.is_enabled = ad5398_is_enabled,
};
static struct regulator_desc ad5398_reg = {
.name = "isink",
.id = 0,
.ops = &ad5398_ops,
.type = REGULATOR_CURRENT,
.owner = THIS_MODULE,
};
struct ad5398_current_data_format {
int current_bits;
int current_offset;
int min_uA;
int max_uA;
};
static const struct ad5398_current_data_format df_10_4_120 = {10, 4, 0, 120000};
static const struct i2c_device_id ad5398_id[] = {
{ "ad5398", (kernel_ulong_t)&df_10_4_120 },
{ "ad5821", (kernel_ulong_t)&df_10_4_120 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5398_id);
static int __devinit ad5398_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regulator_dev *rdev;
struct regulator_init_data *init_data = client->dev.platform_data;
struct ad5398_chip_info *chip;
const struct ad5398_current_data_format *df =
(struct ad5398_current_data_format *)id->driver_data;
int ret;
if (!init_data)
return -EINVAL;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->client = client;
chip->min_uA = df->min_uA;
chip->max_uA = df->max_uA;
chip->current_level = 1 << df->current_bits;
chip->current_offset = df->current_offset;
chip->current_mask = (chip->current_level - 1) << chip->current_offset;
rdev = regulator_register(&ad5398_reg, &client->dev, init_data, chip);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
dev_err(&client->dev, "failed to register %s %s\n",
id->name, ad5398_reg.name);
goto err;
}
i2c_set_clientdata(client, chip);
dev_dbg(&client->dev, "%s regulator driver is registered.\n", id->name);
return 0;
err:
kfree(chip);
return ret;
}
static int __devexit ad5398_remove(struct i2c_client *client)
{
struct ad5398_chip_info *chip = i2c_get_clientdata(client);
regulator_unregister(&chip->rdev);
kfree(chip);
i2c_set_clientdata(client, NULL);
return 0;
}
static struct i2c_driver ad5398_driver = {
.probe = ad5398_probe,
.remove = __devexit_p(ad5398_remove),
.driver = {
.name = "ad5398",
},
.id_table = ad5398_id,
};
static int __init ad5398_init(void)
{
return i2c_add_driver(&ad5398_driver);
}
subsys_initcall(ad5398_init);
static void __exit ad5398_exit(void)
{
i2c_del_driver(&ad5398_driver);
}
module_exit(ad5398_exit);
MODULE_DESCRIPTION("AD5398 and AD5821 current regulator driver");
MODULE_AUTHOR("Sonic Zhang");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:ad5398-regulator");

Просмотреть файл

@ -0,0 +1,236 @@
/*
* isl6271a-regulator.c
*
* Support for Intersil ISL6271A voltage regulator
*
* Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
* whether express or implied; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/slab.h>
#define ISL6271A_VOLTAGE_MIN 850000
#define ISL6271A_VOLTAGE_MAX 1600000
#define ISL6271A_VOLTAGE_STEP 50000
/* PMIC details */
struct isl_pmic {
struct i2c_client *client;
struct regulator_dev *rdev[3];
struct mutex mtx;
};
static int isl6271a_get_voltage(struct regulator_dev *dev)
{
struct isl_pmic *pmic = rdev_get_drvdata(dev);
int idx, data;
mutex_lock(&pmic->mtx);
idx = i2c_smbus_read_byte(pmic->client);
if (idx < 0) {
dev_err(&pmic->client->dev, "Error getting voltage\n");
data = idx;
goto out;
}
/* Convert the data from chip to microvolts */
data = ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * (idx & 0xf));
out:
mutex_unlock(&pmic->mtx);
return data;
}
static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV)
{
struct isl_pmic *pmic = rdev_get_drvdata(dev);
int vsel, err, data;
if (minuV < ISL6271A_VOLTAGE_MIN || minuV > ISL6271A_VOLTAGE_MAX)
return -EINVAL;
if (maxuV < ISL6271A_VOLTAGE_MIN || maxuV > ISL6271A_VOLTAGE_MAX)
return -EINVAL;
/* Align to 50000 mV */
vsel = minuV - (minuV % ISL6271A_VOLTAGE_STEP);
/* If the result fell out of [minuV,maxuV] range, put it back */
if (vsel < minuV)
vsel += ISL6271A_VOLTAGE_STEP;
/* Convert the microvolts to data for the chip */
data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP;
mutex_lock(&pmic->mtx);
err = i2c_smbus_write_byte(pmic->client, data);
if (err < 0)
dev_err(&pmic->client->dev, "Error setting voltage\n");
mutex_unlock(&pmic->mtx);
return err;
}
static int isl6271a_list_voltage(struct regulator_dev *dev, unsigned selector)
{
return ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * selector);
}
static struct regulator_ops isl_core_ops = {
.get_voltage = isl6271a_get_voltage,
.set_voltage = isl6271a_set_voltage,
.list_voltage = isl6271a_list_voltage,
};
static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
{
int id = rdev_get_id(dev);
return (id == 1) ? 1100000 : 1300000;
}
static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector)
{
int id = rdev_get_id(dev);
return (id == 1) ? 1100000 : 1300000;
}
static struct regulator_ops isl_fixed_ops = {
.get_voltage = isl6271a_get_fixed_voltage,
.list_voltage = isl6271a_list_fixed_voltage,
};
static struct regulator_desc isl_rd[] = {
{
.name = "Core Buck",
.id = 0,
.n_voltages = 16,
.ops = &isl_core_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO1",
.id = 1,
.n_voltages = 1,
.ops = &isl_fixed_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO2",
.id = 2,
.n_voltages = 1,
.ops = &isl_fixed_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
};
static int __devinit isl6271a_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regulator_init_data *init_data = i2c->dev.platform_data;
struct isl_pmic *pmic;
int err, i;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
if (!init_data) {
dev_err(&i2c->dev, "no platform data supplied\n");
return -EIO;
}
pmic = kzalloc(sizeof(struct isl_pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
pmic->client = i2c;
mutex_init(&pmic->mtx);
for (i = 0; i < 3; i++) {
pmic->rdev[i] = regulator_register(&isl_rd[0], &i2c->dev,
init_data, pmic);
if (IS_ERR(pmic->rdev[i])) {
dev_err(&i2c->dev, "failed to register %s\n", id->name);
err = PTR_ERR(pmic->rdev);
goto error;
}
}
i2c_set_clientdata(i2c, pmic);
return 0;
error:
while (--i >= 0)
regulator_unregister(pmic->rdev[i]);
kfree(pmic);
return err;
}
static int __devexit isl6271a_remove(struct i2c_client *i2c)
{
struct isl_pmic *pmic = i2c_get_clientdata(i2c);
int i;
i2c_set_clientdata(i2c, NULL);
for (i = 0; i < 3; i++)
regulator_unregister(pmic->rdev[i]);
kfree(pmic);
return 0;
}
static const struct i2c_device_id isl6271a_id[] = {
{.name = "isl6271a", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, isl6271a_id);
static struct i2c_driver isl6271a_i2c_driver = {
.driver = {
.name = "isl6271a",
.owner = THIS_MODULE,
},
.probe = isl6271a_probe,
.remove = __devexit_p(isl6271a_remove),
.id_table = isl6271a_id,
};
static int __init isl6271a_init(void)
{
return i2c_add_driver(&isl6271a_i2c_driver);
}
static void __exit isl6271a_cleanup(void)
{
i2c_del_driver(&isl6271a_i2c_driver);
}
subsys_initcall(isl6271a_init);
module_exit(isl6271a_cleanup);
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
MODULE_DESCRIPTION("Intersil ISL6271A voltage regulator driver");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -377,7 +377,7 @@ static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
if (count != 1) if (count != 1)
return -EIO; return -EIO;
ret = i2c_smbus_read_byte_data(i2c, reg); ret = i2c_smbus_read_byte_data(i2c, reg);
if (ret < 0 || count != 1) if (ret < 0)
return -EIO; return -EIO;
*dest = ret; *dest = ret;
@ -387,15 +387,9 @@ static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count, static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count,
const u16 *src) const u16 *src)
{ {
int ret;
if (count != 1) if (count != 1)
return -EIO; return -EIO;
ret = i2c_smbus_write_byte_data(i2c, reg, *src); return 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) static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg)

Просмотреть файл

@ -223,7 +223,7 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client,
} }
} }
i2c_set_clientdata(client, rdev); i2c_set_clientdata(client, max1586);
dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n"); dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n");
return 0; return 0;
@ -238,13 +238,13 @@ out:
static int __devexit max1586_pmic_remove(struct i2c_client *client) static int __devexit max1586_pmic_remove(struct i2c_client *client)
{ {
struct regulator_dev **rdev = i2c_get_clientdata(client); struct max1586_data *max1586 = i2c_get_clientdata(client);
int i; int i;
for (i = 0; i <= MAX1586_V6; i++) for (i = 0; i <= MAX1586_V6; i++)
if (rdev[i]) if (max1586->rdev[i])
regulator_unregister(rdev[i]); regulator_unregister(max1586->rdev[i]);
kfree(rdev); kfree(max1586);
return 0; return 0;
} }

Просмотреть файл

@ -450,7 +450,7 @@ static int __devinit max8660_probe(struct i2c_client *client,
} }
} }
i2c_set_clientdata(client, rdev); i2c_set_clientdata(client, max8660);
dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n"); dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n");
return 0; return 0;
@ -465,13 +465,13 @@ out:
static int __devexit max8660_remove(struct i2c_client *client) static int __devexit max8660_remove(struct i2c_client *client)
{ {
struct regulator_dev **rdev = i2c_get_clientdata(client); struct max8660 *max8660 = i2c_get_clientdata(client);
int i; int i;
for (i = 0; i < MAX8660_V_END; i++) for (i = 0; i < MAX8660_V_END; i++)
if (rdev[i]) if (max8660->rdev[i])
regulator_unregister(rdev[i]); regulator_unregister(max8660->rdev[i]);
kfree(rdev); kfree(max8660);
return 0; return 0;
} }

635
drivers/regulator/max8998.c Normal file
Просмотреть файл

@ -0,0 +1,635 @@
/*
* max8998.c - Voltage regulator driver for the Maxim 8998
*
* Copyright (C) 2009-2010 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
* Marek Szyprowski <m.szyprowski@samsung.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.
*
* 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/init.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/max8998.h>
#include <linux/mfd/max8998-private.h>
struct max8998_data {
struct device *dev;
struct max8998_dev *iodev;
int num_regulators;
struct regulator_dev **rdev;
};
struct voltage_map_desc {
int min;
int max;
int step;
};
/* Voltage maps */
static const struct voltage_map_desc ldo23_voltage_map_desc = {
.min = 800, .step = 50, .max = 1300,
};
static const struct voltage_map_desc ldo456711_voltage_map_desc = {
.min = 1600, .step = 100, .max = 3600,
};
static const struct voltage_map_desc ldo8_voltage_map_desc = {
.min = 3000, .step = 100, .max = 3600,
};
static const struct voltage_map_desc ldo9_voltage_map_desc = {
.min = 2800, .step = 100, .max = 3100,
};
static const struct voltage_map_desc ldo10_voltage_map_desc = {
.min = 950, .step = 50, .max = 1300,
};
static const struct voltage_map_desc ldo1213_voltage_map_desc = {
.min = 800, .step = 100, .max = 3300,
};
static const struct voltage_map_desc ldo1415_voltage_map_desc = {
.min = 1200, .step = 100, .max = 3300,
};
static const struct voltage_map_desc ldo1617_voltage_map_desc = {
.min = 1600, .step = 100, .max = 3600,
};
static const struct voltage_map_desc buck12_voltage_map_desc = {
.min = 750, .step = 25, .max = 1525,
};
static const struct voltage_map_desc buck3_voltage_map_desc = {
.min = 1600, .step = 100, .max = 3600,
};
static const struct voltage_map_desc buck4_voltage_map_desc = {
.min = 800, .step = 100, .max = 2300,
};
static const struct voltage_map_desc *ldo_voltage_map[] = {
NULL,
NULL,
&ldo23_voltage_map_desc, /* LDO2 */
&ldo23_voltage_map_desc, /* LDO3 */
&ldo456711_voltage_map_desc, /* LDO4 */
&ldo456711_voltage_map_desc, /* LDO5 */
&ldo456711_voltage_map_desc, /* LDO6 */
&ldo456711_voltage_map_desc, /* LDO7 */
&ldo8_voltage_map_desc, /* LDO8 */
&ldo9_voltage_map_desc, /* LDO9 */
&ldo10_voltage_map_desc, /* LDO10 */
&ldo456711_voltage_map_desc, /* LDO11 */
&ldo1213_voltage_map_desc, /* LDO12 */
&ldo1213_voltage_map_desc, /* LDO13 */
&ldo1415_voltage_map_desc, /* LDO14 */
&ldo1415_voltage_map_desc, /* LDO15 */
&ldo1617_voltage_map_desc, /* LDO16 */
&ldo1617_voltage_map_desc, /* LDO17 */
&buck12_voltage_map_desc, /* BUCK1 */
&buck12_voltage_map_desc, /* BUCK2 */
&buck3_voltage_map_desc, /* BUCK3 */
&buck4_voltage_map_desc, /* BUCK4 */
};
static inline int max8998_get_ldo(struct regulator_dev *rdev)
{
return rdev_get_id(rdev);
}
static int max8998_list_voltage(struct regulator_dev *rdev,
unsigned int selector)
{
const struct voltage_map_desc *desc;
int ldo = max8998_get_ldo(rdev);
int val;
if (ldo >= ARRAY_SIZE(ldo_voltage_map))
return -EINVAL;
desc = ldo_voltage_map[ldo];
if (desc == NULL)
return -EINVAL;
val = desc->min + desc->step * selector;
if (val > desc->max)
return -EINVAL;
return val * 1000;
}
static int max8998_get_enable_register(struct regulator_dev *rdev,
int *reg, int *shift)
{
int ldo = max8998_get_ldo(rdev);
switch (ldo) {
case MAX8998_LDO2 ... MAX8998_LDO5:
*reg = MAX8998_REG_ONOFF1;
*shift = 3 - (ldo - MAX8998_LDO2);
break;
case MAX8998_LDO6 ... MAX8998_LDO13:
*reg = MAX8998_REG_ONOFF2;
*shift = 7 - (ldo - MAX8998_LDO6);
break;
case MAX8998_LDO14 ... MAX8998_LDO17:
*reg = MAX8998_REG_ONOFF3;
*shift = 7 - (ldo - MAX8998_LDO14);
break;
case MAX8998_BUCK1 ... MAX8998_BUCK4:
*reg = MAX8998_REG_ONOFF1;
*shift = 7 - (ldo - MAX8998_BUCK1);
break;
case MAX8998_EN32KHZ_AP ... MAX8998_ENVICHG:
*reg = MAX8998_REG_ONOFF4;
*shift = 7 - (ldo - MAX8998_EN32KHZ_AP);
break;
case MAX8998_ESAFEOUT1 ... MAX8998_ESAFEOUT2:
*reg = MAX8998_REG_CHGR2;
*shift = 7 - (ldo - MAX8998_ESAFEOUT1);
break;
default:
return -EINVAL;
}
return 0;
}
static int max8998_ldo_is_enabled(struct regulator_dev *rdev)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
int ret, reg, shift = 8;
u8 val;
ret = max8998_get_enable_register(rdev, &reg, &shift);
if (ret)
return ret;
ret = max8998_read_reg(max8998->iodev, reg, &val);
if (ret)
return ret;
return val & (1 << shift);
}
static int max8998_ldo_enable(struct regulator_dev *rdev)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
int reg, shift = 8, ret;
ret = max8998_get_enable_register(rdev, &reg, &shift);
if (ret)
return ret;
return max8998_update_reg(max8998->iodev, reg, 1<<shift, 1<<shift);
}
static int max8998_ldo_disable(struct regulator_dev *rdev)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
int reg, shift = 8, ret;
ret = max8998_get_enable_register(rdev, &reg, &shift);
if (ret)
return ret;
return max8998_update_reg(max8998->iodev, reg, 0, 1<<shift);
}
static int max8998_get_voltage_register(struct regulator_dev *rdev,
int *_reg, int *_shift, int *_mask)
{
int ldo = max8998_get_ldo(rdev);
int reg, shift = 0, mask = 0xff;
switch (ldo) {
case MAX8998_LDO2 ... MAX8998_LDO3:
reg = MAX8998_REG_LDO2_LDO3;
mask = 0xf;
if (ldo == MAX8998_LDO2)
shift = 4;
else
shift = 0;
break;
case MAX8998_LDO4 ... MAX8998_LDO7:
reg = MAX8998_REG_LDO4 + (ldo - MAX8998_LDO4);
break;
case MAX8998_LDO8 ... MAX8998_LDO9:
reg = MAX8998_REG_LDO8_LDO9;
mask = 0xf;
if (ldo == MAX8998_LDO8)
shift = 4;
else
shift = 0;
break;
case MAX8998_LDO10 ... MAX8998_LDO11:
reg = MAX8998_REG_LDO10_LDO11;
if (ldo == MAX8998_LDO10) {
shift = 5;
mask = 0x7;
} else {
shift = 0;
mask = 0x1f;
}
break;
case MAX8998_LDO12 ... MAX8998_LDO17:
reg = MAX8998_REG_LDO12 + (ldo - MAX8998_LDO12);
break;
case MAX8998_BUCK1:
reg = MAX8998_REG_BUCK1_DVSARM1;
break;
case MAX8998_BUCK2:
reg = MAX8998_REG_BUCK2_DVSINT1;
break;
case MAX8998_BUCK3:
reg = MAX8998_REG_BUCK3;
break;
case MAX8998_BUCK4:
reg = MAX8998_REG_BUCK4;
break;
default:
return -EINVAL;
}
*_reg = reg;
*_shift = shift;
*_mask = mask;
return 0;
}
static int max8998_get_voltage(struct regulator_dev *rdev)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
int reg, shift = 0, mask, ret;
u8 val;
ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
if (ret)
return ret;
ret = max8998_read_reg(max8998->iodev, reg, &val);
if (ret)
return ret;
val >>= shift;
val &= mask;
return max8998_list_voltage(rdev, val);
}
static int max8998_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
int previous_vol = 0;
const struct voltage_map_desc *desc;
int ldo = max8998_get_ldo(rdev);
int reg, shift = 0, mask, ret;
int i = 0;
u8 val;
bool en_ramp = false;
if (ldo >= ARRAY_SIZE(ldo_voltage_map))
return -EINVAL;
desc = ldo_voltage_map[ldo];
if (desc == NULL)
return -EINVAL;
if (max_vol < desc->min || min_vol > desc->max)
return -EINVAL;
while (desc->min + desc->step*i < min_vol &&
desc->min + desc->step*i < desc->max)
i++;
if (desc->min + desc->step*i > max_vol)
return -EINVAL;
ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
if (ret)
return ret;
/* wait for RAMP_UP_DELAY if rdev is BUCK1/2 and
* ENRAMP is ON */
if (ldo == MAX8998_BUCK1 || ldo == MAX8998_BUCK2) {
max8998_read_reg(max8998->iodev, MAX8998_REG_ONOFF4, &val);
if (val & (1 << 4)) {
en_ramp = true;
previous_vol = max8998_get_voltage(rdev);
}
}
ret = max8998_update_reg(max8998->iodev, reg, i<<shift, mask<<shift);
if (en_ramp == true) {
int difference = desc->min + desc->step*i - previous_vol/1000;
if (difference > 0)
udelay(difference / ((val & 0x0f) + 1));
}
return ret;
}
static struct regulator_ops max8998_ldo_ops = {
.list_voltage = max8998_list_voltage,
.is_enabled = max8998_ldo_is_enabled,
.enable = max8998_ldo_enable,
.disable = max8998_ldo_disable,
.get_voltage = max8998_get_voltage,
.set_voltage = max8998_set_voltage,
.set_suspend_enable = max8998_ldo_enable,
.set_suspend_disable = max8998_ldo_disable,
};
static struct regulator_ops max8998_buck_ops = {
.list_voltage = max8998_list_voltage,
.is_enabled = max8998_ldo_is_enabled,
.enable = max8998_ldo_enable,
.disable = max8998_ldo_disable,
.get_voltage = max8998_get_voltage,
.set_voltage = max8998_set_voltage,
.set_suspend_enable = max8998_ldo_enable,
.set_suspend_disable = max8998_ldo_disable,
};
static struct regulator_ops max8998_others_ops = {
.is_enabled = max8998_ldo_is_enabled,
.enable = max8998_ldo_enable,
.disable = max8998_ldo_disable,
.set_suspend_enable = max8998_ldo_enable,
.set_suspend_disable = max8998_ldo_disable,
};
static struct regulator_desc regulators[] = {
{
.name = "LDO2",
.id = MAX8998_LDO2,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO3",
.id = MAX8998_LDO3,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO4",
.id = MAX8998_LDO4,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO5",
.id = MAX8998_LDO5,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO6",
.id = MAX8998_LDO6,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO7",
.id = MAX8998_LDO7,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO8",
.id = MAX8998_LDO8,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO9",
.id = MAX8998_LDO9,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO10",
.id = MAX8998_LDO10,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO11",
.id = MAX8998_LDO11,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO12",
.id = MAX8998_LDO12,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO13",
.id = MAX8998_LDO13,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO14",
.id = MAX8998_LDO14,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO15",
.id = MAX8998_LDO15,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO16",
.id = MAX8998_LDO16,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "LDO17",
.id = MAX8998_LDO17,
.ops = &max8998_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "BUCK1",
.id = MAX8998_BUCK1,
.ops = &max8998_buck_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "BUCK2",
.id = MAX8998_BUCK2,
.ops = &max8998_buck_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "BUCK3",
.id = MAX8998_BUCK3,
.ops = &max8998_buck_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "BUCK4",
.id = MAX8998_BUCK4,
.ops = &max8998_buck_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "EN32KHz AP",
.id = MAX8998_EN32KHZ_AP,
.ops = &max8998_others_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "EN32KHz CP",
.id = MAX8998_EN32KHZ_CP,
.ops = &max8998_others_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "ENVICHG",
.id = MAX8998_ENVICHG,
.ops = &max8998_others_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "ESAFEOUT1",
.id = MAX8998_ESAFEOUT1,
.ops = &max8998_others_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
.name = "ESAFEOUT2",
.id = MAX8998_ESAFEOUT2,
.ops = &max8998_others_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}
};
static __devinit int max8998_pmic_probe(struct platform_device *pdev)
{
struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
struct regulator_dev **rdev;
struct max8998_data *max8998;
int i, ret, size;
if (!pdata) {
dev_err(pdev->dev.parent, "No platform init data supplied\n");
return -ENODEV;
}
max8998 = kzalloc(sizeof(struct max8998_data), GFP_KERNEL);
if (!max8998)
return -ENOMEM;
size = sizeof(struct regulator_dev *) * (pdata->num_regulators + 1);
max8998->rdev = kzalloc(size, GFP_KERNEL);
if (!max8998->rdev) {
kfree(max8998);
return -ENOMEM;
}
rdev = max8998->rdev;
max8998->iodev = iodev;
platform_set_drvdata(pdev, max8998);
for (i = 0; i < pdata->num_regulators; i++) {
const struct voltage_map_desc *desc;
int id = pdata->regulators[i].id;
int index = id - MAX8998_LDO2;
desc = ldo_voltage_map[id];
if (desc && regulators[index].ops != &max8998_others_ops) {
int count = (desc->max - desc->min) / desc->step + 1;
regulators[index].n_voltages = count;
}
rdev[i] = regulator_register(&regulators[index], max8998->dev,
pdata->regulators[i].initdata, max8998);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(max8998->dev, "regulator init failed\n");
rdev[i] = NULL;
goto err;
}
}
return 0;
err:
for (i = 0; i <= max8998->num_regulators; i++)
if (rdev[i])
regulator_unregister(rdev[i]);
kfree(max8998->rdev);
kfree(max8998);
return ret;
}
static int __devexit max8998_pmic_remove(struct platform_device *pdev)
{
struct max8998_data *max8998 = platform_get_drvdata(pdev);
struct regulator_dev **rdev = max8998->rdev;
int i;
for (i = 0; i <= max8998->num_regulators; i++)
if (rdev[i])
regulator_unregister(rdev[i]);
kfree(max8998->rdev);
kfree(max8998);
return 0;
}
static struct platform_driver max8998_pmic_driver = {
.driver = {
.name = "max8998-pmic",
.owner = THIS_MODULE,
},
.probe = max8998_pmic_probe,
.remove = __devexit_p(max8998_pmic_remove),
};
static int __init max8998_pmic_init(void)
{
return platform_driver_register(&max8998_pmic_driver);
}
subsys_initcall(max8998_pmic_init);
static void __exit max8998_pmic_cleanup(void)
{
platform_driver_unregister(&max8998_pmic_driver);
}
module_exit(max8998_pmic_cleanup);
MODULE_DESCRIPTION("MAXIM 8998 voltage regulator driver");
MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
MODULE_LICENSE("GPL");

Просмотреть файл

@ -585,6 +585,8 @@ static const struct tps_info tps65023_regs[] = {
static const struct i2c_device_id tps_65023_id[] = { static const struct i2c_device_id tps_65023_id[] = {
{.name = "tps65023", {.name = "tps65023",
.driver_data = (unsigned long) tps65023_regs,}, .driver_data = (unsigned long) tps65023_regs,},
{.name = "tps65021",
.driver_data = (unsigned long) tps65023_regs,},
{ }, { },
}; };

Просмотреть файл

@ -614,6 +614,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev)
} }
tps6507x_dev->pmic = tps; tps6507x_dev->pmic = tps;
platform_set_drvdata(pdev, tps6507x_dev);
return 0; return 0;

Просмотреть файл

@ -0,0 +1,396 @@
/*
* Regulator driver for TI TPS6586x
*
* Copyright (C) 2010 Compulab Ltd.
* Author: Mike Rapoport <mike@compulab.co.il>
*
* Based on da903x
* Copyright (C) 2006-2008 Marvell International Ltd.
* Copyright (C) 2008 Compulab Ltd.
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/tps6586x.h>
/* supply control and voltage setting */
#define TPS6586X_SUPPLYENA 0x10
#define TPS6586X_SUPPLYENB 0x11
#define TPS6586X_SUPPLYENC 0x12
#define TPS6586X_SUPPLYEND 0x13
#define TPS6586X_SUPPLYENE 0x14
#define TPS6586X_VCC1 0x20
#define TPS6586X_VCC2 0x21
#define TPS6586X_SM1V1 0x23
#define TPS6586X_SM1V2 0x24
#define TPS6586X_SM1SL 0x25
#define TPS6586X_SM0V1 0x26
#define TPS6586X_SM0V2 0x27
#define TPS6586X_SM0SL 0x28
#define TPS6586X_LDO2AV1 0x29
#define TPS6586X_LDO2AV2 0x2A
#define TPS6586X_LDO2BV1 0x2F
#define TPS6586X_LDO2BV2 0x30
#define TPS6586X_LDO4V1 0x32
#define TPS6586X_LDO4V2 0x33
/* converter settings */
#define TPS6586X_SUPPLYV1 0x41
#define TPS6586X_SUPPLYV2 0x42
#define TPS6586X_SUPPLYV3 0x43
#define TPS6586X_SUPPLYV4 0x44
#define TPS6586X_SUPPLYV5 0x45
#define TPS6586X_SUPPLYV6 0x46
#define TPS6586X_SMODE1 0x47
#define TPS6586X_SMODE2 0x48
struct tps6586x_regulator {
struct regulator_desc desc;
int volt_reg;
int volt_shift;
int volt_nbits;
int enable_bit[2];
int enable_reg[2];
int *voltages;
/* for DVM regulators */
int go_reg;
int go_bit;
};
static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
{
return rdev_get_dev(rdev)->parent->parent;
}
static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev,
unsigned selector)
{
struct tps6586x_regulator *info = rdev_get_drvdata(rdev);
return info->voltages[selector] * 1000;
}
static int __tps6586x_ldo_set_voltage(struct device *parent,
struct tps6586x_regulator *ri,
int min_uV, int max_uV)
{
int val, uV;
uint8_t mask;
for (val = 0; val < ri->desc.n_voltages; val++) {
uV = ri->voltages[val] * 1000;
/* LDO0 has minimal voltage 1.2 rather than 1.25 */
if (ri->desc.id == TPS6586X_ID_LDO_0 && val == 0)
uV -= 50 * 1000;
/* use the first in-range value */
if (min_uV <= uV && uV <= max_uV) {
val <<= ri->volt_shift;
mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
return tps6586x_update(parent, ri->volt_reg, val, mask);
}
}
return -EINVAL;
}
static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV);
}
static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
uint8_t val, mask;
int ret;
ret = tps6586x_read(parent, ri->volt_reg, &val);
if (ret)
return ret;
mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
val = (val & mask) >> ri->volt_shift;
if (val > ri->desc.n_voltages)
BUG();
return ri->voltages[val] * 1000;
}
static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
int ret;
ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV);
if (ret)
return ret;
return tps6586x_set_bits(parent, ri->go_reg, ri->go_bit);
}
static int tps6586x_regulator_enable(struct regulator_dev *rdev)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
return tps6586x_set_bits(parent, ri->enable_reg[0],
1 << ri->enable_bit[0]);
}
static int tps6586x_regulator_disable(struct regulator_dev *rdev)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
return tps6586x_clr_bits(parent, ri->enable_reg[0],
1 << ri->enable_bit[0]);
}
static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
uint8_t reg_val;
int ret;
ret = tps6586x_read(parent, ri->enable_reg[0], &reg_val);
if (ret)
return ret;
return !!(reg_val & (1 << ri->enable_bit[0]));
}
static struct regulator_ops tps6586x_regulator_ldo_ops = {
.list_voltage = tps6586x_ldo_list_voltage,
.get_voltage = tps6586x_ldo_get_voltage,
.set_voltage = tps6586x_ldo_set_voltage,
.is_enabled = tps6586x_regulator_is_enabled,
.enable = tps6586x_regulator_enable,
.disable = tps6586x_regulator_disable,
};
static struct regulator_ops tps6586x_regulator_dvm_ops = {
.list_voltage = tps6586x_ldo_list_voltage,
.get_voltage = tps6586x_ldo_get_voltage,
.set_voltage = tps6586x_dvm_set_voltage,
.is_enabled = tps6586x_regulator_is_enabled,
.enable = tps6586x_regulator_enable,
.disable = tps6586x_regulator_disable,
};
static int tps6586x_ldo_voltages[] = {
1250, 1500, 1800, 2500, 2700, 2850, 3100, 3300,
};
static int tps6586x_ldo4_voltages[] = {
1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
1900, 1925, 1950, 1975, 2000, 2025, 2050, 2075,
2100, 2125, 2150, 2175, 2200, 2225, 2250, 2275,
2300, 2325, 2350, 2375, 2400, 2425, 2450, 2475,
};
static int tps6586x_sm2_voltages[] = {
3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350,
3400, 3450, 3500, 3550, 3600, 3650, 3700, 3750,
3800, 3850, 3900, 3950, 4000, 4050, 4100, 4150,
4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550,
};
static int tps6586x_dvm_voltages[] = {
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,
};
#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
{ \
.desc = { \
.name = "REG-" #_id, \
.ops = &tps6586x_regulator_##_ops, \
.type = REGULATOR_VOLTAGE, \
.id = TPS6586X_ID_##_id, \
.n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages), \
.owner = THIS_MODULE, \
}, \
.volt_reg = TPS6586X_##vreg, \
.volt_shift = (shift), \
.volt_nbits = (nbits), \
.enable_reg[0] = TPS6586X_SUPPLY##ereg0, \
.enable_bit[0] = (ebit0), \
.enable_reg[1] = TPS6586X_SUPPLY##ereg1, \
.enable_bit[1] = (ebit1), \
.voltages = tps6586x_##vdata##_voltages, \
}
#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, 0, 0)
#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit)
static struct tps6586x_regulator tps6586x_regulator[] = {
TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0),
TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
TPS6586X_LDO(LDO_8, ldo, SUPPLYV1, 5, 3, ENC, 6, END, 6),
TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, ENE, 7, ENE, 7),
TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 1, END, 1),
TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6),
TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6),
TPS6586X_DVM(SM_0, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
TPS6586X_DVM(SM_1, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
};
/*
* TPS6586X has 2 enable bits that are OR'ed to determine the actual
* regulator state. Clearing one of this bits allows switching
* regulator on and of with single register write.
*/
static inline int tps6586x_regulator_preinit(struct device *parent,
struct tps6586x_regulator *ri)
{
uint8_t val1, val2;
int ret;
ret = tps6586x_read(parent, ri->enable_reg[0], &val1);
if (ret)
return ret;
ret = tps6586x_read(parent, ri->enable_reg[1], &val2);
if (ret)
return ret;
if (!(val2 & ri->enable_bit[1]))
return 0;
/*
* The regulator is on, but it's enabled with the bit we don't
* want to use, so we switch the enable bits
*/
if (!(val1 & ri->enable_bit[0])) {
ret = tps6586x_set_bits(parent, ri->enable_reg[0],
1 << ri->enable_bit[0]);
if (ret)
return ret;
}
return tps6586x_clr_bits(parent, ri->enable_reg[1],
1 << ri->enable_bit[1]);
}
static inline struct tps6586x_regulator *find_regulator_info(int id)
{
struct tps6586x_regulator *ri;
int i;
for (i = 0; i < ARRAY_SIZE(tps6586x_regulator); i++) {
ri = &tps6586x_regulator[i];
if (ri->desc.id == id)
return ri;
}
return NULL;
}
static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
{
struct tps6586x_regulator *ri = NULL;
struct regulator_dev *rdev;
int id = pdev->id;
int err;
dev_dbg(&pdev->dev, "Probing reulator %d\n", id);
ri = find_regulator_info(id);
if (ri == NULL) {
dev_err(&pdev->dev, "invalid regulator ID specified\n");
return -EINVAL;
}
err = tps6586x_regulator_preinit(pdev->dev.parent, ri);
if (err)
return err;
rdev = regulator_register(&ri->desc, &pdev->dev,
pdev->dev.platform_data, ri);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
return PTR_ERR(rdev);
}
platform_set_drvdata(pdev, rdev);
return 0;
}
static int __devexit tps6586x_regulator_remove(struct platform_device *pdev)
{
struct regulator_dev *rdev = platform_get_drvdata(pdev);
regulator_unregister(rdev);
return 0;
}
static struct platform_driver tps6586x_regulator_driver = {
.driver = {
.name = "tps6586x-regulator",
.owner = THIS_MODULE,
},
.probe = tps6586x_regulator_probe,
.remove = __devexit_p(tps6586x_regulator_remove),
};
static int __init tps6586x_regulator_init(void)
{
return platform_driver_register(&tps6586x_regulator_driver);
}
subsys_initcall(tps6586x_regulator_init);
static void __exit tps6586x_regulator_exit(void)
{
platform_driver_unregister(&tps6586x_regulator_driver);
}
module_exit(tps6586x_regulator_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
MODULE_DESCRIPTION("Regulator Driver for TI TPS6586X PMIC");
MODULE_ALIAS("platform:tps6586x-regulator");

Просмотреть файл

@ -219,8 +219,6 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
ldo->wm8994 = wm8994; ldo->wm8994 = wm8994;
ldo->is_enabled = true;
if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) { if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
ldo->enable = pdata->ldo[id].enable; ldo->enable = pdata->ldo[id].enable;
@ -237,7 +235,8 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
ret); ret);
goto err_gpio; goto err_gpio;
} }
} } else
ldo->is_enabled = true;
ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev, ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
pdata->ldo[id].init_data, ldo); pdata->ldo[id].init_data, ldo);

Просмотреть файл

@ -76,6 +76,8 @@
#define AB8500_NR_IRQS 104 #define AB8500_NR_IRQS 104
#define AB8500_NUM_IRQ_REGS 13 #define AB8500_NUM_IRQ_REGS 13
#define AB8500_NUM_REGULATORS 15
/** /**
* struct ab8500 - ab8500 internal structure * struct ab8500 - ab8500 internal structure
* @dev: parent device * @dev: parent device
@ -108,14 +110,18 @@ struct ab8500 {
u8 oldmask[AB8500_NUM_IRQ_REGS]; u8 oldmask[AB8500_NUM_IRQ_REGS];
}; };
struct regulator_init_data;
/** /**
* struct ab8500_platform_data - AB8500 platform data * struct ab8500_platform_data - AB8500 platform data
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @init: board-specific initialization after detection of ab8500 * @init: board-specific initialization after detection of ab8500
* @regulator: machine-specific constraints for regulators
*/ */
struct ab8500_platform_data { struct ab8500_platform_data {
int irq_base; int irq_base;
void (*init) (struct ab8500 *); void (*init) (struct ab8500 *);
struct regulator_init_data *regulator[AB8500_NUM_REGULATORS];
}; };
extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data); extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data);

Просмотреть файл

@ -0,0 +1,112 @@
/*
* max8698.h - Voltage regulator driver for the Maxim 8998
*
* Copyright (C) 2009-2010 Samsung Electrnoics
* Kyungmin Park <kyungmin.park@samsung.com>
* Marek Szyprowski <m.szyprowski@samsung.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.
*
* 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 __LINUX_MFD_MAX8998_PRIV_H
#define __LINUX_MFD_MAX8998_PRIV_H
/* MAX 8998 registers */
enum {
MAX8998_REG_IRQ1,
MAX8998_REG_IRQ2,
MAX8998_REG_IRQ3,
MAX8998_REG_IRQ4,
MAX8998_REG_IRQM1,
MAX8998_REG_IRQM2,
MAX8998_REG_IRQM3,
MAX8998_REG_IRQM4,
MAX8998_REG_STATUS1,
MAX8998_REG_STATUS2,
MAX8998_REG_STATUSM1,
MAX8998_REG_STATUSM2,
MAX8998_REG_CHGR1,
MAX8998_REG_CHGR2,
MAX8998_REG_LDO_ACTIVE_DISCHARGE1,
MAX8998_REG_LDO_ACTIVE_DISCHARGE2,
MAX8998_REG_BUCK_ACTIVE_DISCHARGE3,
MAX8998_REG_ONOFF1,
MAX8998_REG_ONOFF2,
MAX8998_REG_ONOFF3,
MAX8998_REG_ONOFF4,
MAX8998_REG_BUCK1_DVSARM1,
MAX8998_REG_BUCK1_DVSARM2,
MAX8998_REG_BUCK1_DVSARM3,
MAX8998_REG_BUCK1_DVSARM4,
MAX8998_REG_BUCK2_DVSINT1,
MAX8998_REG_BUCK2_DVSINT2,
MAX8998_REG_BUCK3,
MAX8998_REG_BUCK4,
MAX8998_REG_LDO2_LDO3,
MAX8998_REG_LDO4,
MAX8998_REG_LDO5,
MAX8998_REG_LDO6,
MAX8998_REG_LDO7,
MAX8998_REG_LDO8_LDO9,
MAX8998_REG_LDO10_LDO11,
MAX8998_REG_LDO12,
MAX8998_REG_LDO13,
MAX8998_REG_LDO14,
MAX8998_REG_LDO15,
MAX8998_REG_LDO16,
MAX8998_REG_LDO17,
MAX8998_REG_BKCHR,
MAX8998_REG_LBCNFG1,
MAX8998_REG_LBCNFG2,
};
/**
* struct max8998_dev - max8998 master device for sub-drivers
* @dev: master device of the chip (can be used to access platform data)
* @i2c_client: i2c client private data
* @dev_read(): chip register read function
* @dev_write(): chip register write function
* @dev_update(): chip register update function
* @iolock: mutex for serializing io access
*/
struct max8998_dev {
struct device *dev;
struct i2c_client *i2c_client;
int (*dev_read)(struct max8998_dev *max8998, u8 reg, u8 *dest);
int (*dev_write)(struct max8998_dev *max8998, u8 reg, u8 val);
int (*dev_update)(struct max8998_dev *max8998, u8 reg, u8 val, u8 mask);
struct mutex iolock;
};
static inline int max8998_read_reg(struct max8998_dev *max8998, u8 reg,
u8 *value)
{
return max8998->dev_read(max8998, reg, value);
}
static inline int max8998_write_reg(struct max8998_dev *max8998, u8 reg,
u8 value)
{
return max8998->dev_write(max8998, reg, value);
}
static inline int max8998_update_reg(struct max8998_dev *max8998, u8 reg,
u8 value, u8 mask)
{
return max8998->dev_update(max8998, reg, value, mask);
}
#endif /* __LINUX_MFD_MAX8998_PRIV_H */

Просмотреть файл

@ -0,0 +1,78 @@
/*
* max8698.h - Voltage regulator driver for the Maxim 8998
*
* Copyright (C) 2009-2010 Samsung Electrnoics
* Kyungmin Park <kyungmin.park@samsung.com>
* Marek Szyprowski <m.szyprowski@samsung.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.
*
* 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 __LINUX_MFD_MAX8998_H
#define __LINUX_MFD_MAX8998_H
#include <linux/regulator/machine.h>
/* MAX 8998 regulator ids */
enum {
MAX8998_LDO2 = 2,
MAX8998_LDO3,
MAX8998_LDO4,
MAX8998_LDO5,
MAX8998_LDO6,
MAX8998_LDO7,
MAX8998_LDO8,
MAX8998_LDO9,
MAX8998_LDO10,
MAX8998_LDO11,
MAX8998_LDO12,
MAX8998_LDO13,
MAX8998_LDO14,
MAX8998_LDO15,
MAX8998_LDO16,
MAX8998_LDO17,
MAX8998_BUCK1,
MAX8998_BUCK2,
MAX8998_BUCK3,
MAX8998_BUCK4,
MAX8998_EN32KHZ_AP,
MAX8998_EN32KHZ_CP,
MAX8998_ENVICHG,
MAX8998_ESAFEOUT1,
MAX8998_ESAFEOUT2,
};
/**
* max8998_regulator_data - regulator data
* @id: regulator id
* @initdata: regulator init data (contraints, supplies, ...)
*/
struct max8998_regulator_data {
int id;
struct regulator_init_data *initdata;
};
/**
* struct max8998_board - packages regulator init data
* @num_regulators: number of regultors used
* @regulators: array of defined regulators
*/
struct max8998_platform_data {
int num_regulators;
struct max8998_regulator_data *regulators;
};
#endif /* __LINUX_MFD_MAX8998_H */

Просмотреть файл

@ -0,0 +1,25 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
*
*/
#ifndef __LINUX_MFD_AB8500_REGULATOR_H
#define __LINUX_MFD_AB8500_REGULATOR_H
/* AB8500 regulators */
#define AB8500_LDO_AUX1 0
#define AB8500_LDO_AUX2 1
#define AB8500_LDO_AUX3 2
#define AB8500_LDO_INTCORE 3
#define AB8500_LDO_TVOUT 4
#define AB8500_LDO_AUDIO 5
#define AB8500_LDO_ANAMIC1 6
#define AB8500_LDO_ANAMIC2 7
#define AB8500_LDO_DMIC 8
#define AB8500_LDO_ANA 9
#endif