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:
Коммит
580287628c
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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(®ulators[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], ®_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
|
Загрузка…
Ссылка в новой задаче