summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-02 13:51:23 +0000
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-02 13:51:23 +0000
commitfb87ef1a123fa85bca1b6ac693a65752a7d0c718 (patch)
treec70dc30c026f06f5d782e9bad141caa35e12e061
parent62aa2b537c6f5957afd98e29f96897419ed5ebab (diff)
parent20a14b84f8d62ba9ad7acad1d67a2ffa3c06468b (diff)
downloadlinux-fb87ef1a123fa85bca1b6ac693a65752a7d0c718.tar.gz
linux-fb87ef1a123fa85bca1b6ac693a65752a7d0c718.tar.bz2
linux-fb87ef1a123fa85bca1b6ac693a65752a7d0c718.zip
Merge branch 'regulator-drivers' into regulator-supply
-rw-r--r--drivers/regulator/Kconfig31
-rw-r--r--drivers/regulator/Makefile5
-rw-r--r--drivers/regulator/db8500-prcmu.c118
-rw-r--r--drivers/regulator/dbx500-prcmu.c241
-rw-r--r--drivers/regulator/dbx500-prcmu.h63
-rw-r--r--drivers/regulator/max8997.c8
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c2
-rw-r--r--drivers/regulator/s5m8767.c832
-rw-r--r--drivers/regulator/tps62360-regulator.c472
-rw-r--r--drivers/regulator/tps65217-regulator.c493
-rw-r--r--drivers/regulator/tps65910-regulator.c280
-rw-r--r--drivers/regulator/wm8350-regulator.c4
-rw-r--r--include/linux/mfd/tps65910.h8
-rw-r--r--include/linux/regulator/tps62360.h57
14 files changed, 2492 insertions, 122 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 7a61b17ddd04..376824b865a4 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -136,6 +136,14 @@ config REGULATOR_MAX8998
via I2C bus. The provided regulator is suitable for S3C6410
and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
+config REGULATOR_S5M8767
+ tristate "Samsung S5M8767A voltage regulator"
+ depends on MFD_S5M_CORE
+ help
+ This driver supports a Samsung S5M8767A voltage output regulator
+ via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
+ supports DVS mode with 8bits of output voltage control.
+
config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
depends on TWL4030_CORE
@@ -267,6 +275,15 @@ config REGULATOR_TPS6507X
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
+config REGULATOR_TPS65217
+ tristate "TI TPS65217 Power regulators"
+ depends on MFD_TPS65217
+ help
+ This driver supports TPS65217 voltage regulator chips. TPS65217
+ provides three step-down converters and four general-purpose LDO
+ voltage regulators. It supports software based voltage control
+ for different voltage domains
+
config REGULATOR_TPS65912
tristate "TI TPS65912 Power regulator"
depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
@@ -299,9 +316,13 @@ config REGULATOR_AB8500
This driver supports the regulators found on the ST-Ericsson mixed
signal AB8500 PMIC
+config REGULATOR_DBX500_PRCMU
+ bool
+
config REGULATOR_DB8500_PRCMU
bool "ST-Ericsson DB8500 Voltage Domain Regulators"
depends on MFD_DB8500_PRCMU
+ select REGULATOR_DBX500_PRCMU
help
This driver supports the voltage domain regulators controlled by the
DB8500 PRCMU
@@ -328,6 +349,16 @@ config REGULATOR_TPS65910
help
This driver supports TPS65910 voltage regulator chips.
+config REGULATOR_TPS62360
+ tristate "TI TPS62360 Power Regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports TPS62360 voltage regulator chip. This
+ regulator is meant for processor core supply. This chip is
+ high-frequency synchronous step down dc-dc converter optimized
+ for battery-powered portable applications.
+
config REGULATOR_AAT2870
tristate "AnalogicTech AAT2870 Regulators"
depends on MFD_AAT2870_CORE
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 503bac87715e..4cbf8c55f8a9 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -40,13 +40,18 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
+obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
+obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
+obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
index 515443fcd26b..4bd25e75efa0 100644
--- a/drivers/regulator/db8500-prcmu.c
+++ b/drivers/regulator/db8500-prcmu.c
@@ -18,74 +18,11 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/module.h>
-
-/*
- * power state reference count
- */
-static int power_state_active_cnt; /* will initialize to zero */
-static DEFINE_SPINLOCK(power_state_active_lock);
-
-static void power_state_active_enable(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&power_state_active_lock, flags);
- power_state_active_cnt++;
- spin_unlock_irqrestore(&power_state_active_lock, flags);
-}
-
-static int power_state_active_disable(void)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&power_state_active_lock, flags);
- if (power_state_active_cnt <= 0) {
- pr_err("power state: unbalanced enable/disable calls\n");
- ret = -EINVAL;
- goto out;
- }
-
- power_state_active_cnt--;
-out:
- spin_unlock_irqrestore(&power_state_active_lock, flags);
- return ret;
-}
-
-/*
- * Exported interface for CPUIdle only. This function is called when interrupts
- * are turned off. Hence, no locking.
- */
-int power_state_active_is_enabled(void)
-{
- return (power_state_active_cnt > 0);
-}
-
-/**
- * struct db8500_regulator_info - db8500 regulator information
- * @dev: device pointer
- * @desc: regulator description
- * @rdev: regulator device pointer
- * @is_enabled: status of the regulator
- * @epod_id: id for EPOD (power domain)
- * @is_ramret: RAM retention switch for EPOD (power domain)
- * @operating_point: operating point (only for vape, to be removed)
- *
- */
-struct db8500_regulator_info {
- struct device *dev;
- struct regulator_desc desc;
- struct regulator_dev *rdev;
- bool is_enabled;
- u16 epod_id;
- bool is_ramret;
- bool exclude_from_power_state;
- unsigned int operating_point;
-};
+#include "dbx500-prcmu.h"
static int db8500_regulator_enable(struct regulator_dev *rdev)
{
- struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
if (info == NULL)
return -EINVAL;
@@ -93,16 +30,18 @@ static int db8500_regulator_enable(struct regulator_dev *rdev)
dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
info->desc.name);
- info->is_enabled = true;
- if (!info->exclude_from_power_state)
- power_state_active_enable();
+ if (!info->is_enabled) {
+ info->is_enabled = true;
+ if (!info->exclude_from_power_state)
+ power_state_active_enable();
+ }
return 0;
}
static int db8500_regulator_disable(struct regulator_dev *rdev)
{
- struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
int ret = 0;
if (info == NULL)
@@ -111,16 +50,18 @@ static int db8500_regulator_disable(struct regulator_dev *rdev)
dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
info->desc.name);
- info->is_enabled = false;
- if (!info->exclude_from_power_state)
- ret = power_state_active_disable();
+ if (info->is_enabled) {
+ info->is_enabled = false;
+ if (!info->exclude_from_power_state)
+ ret = power_state_active_disable();
+ }
return ret;
}
static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
{
- struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
if (info == NULL)
return -EINVAL;
@@ -197,7 +138,7 @@ static int disable_epod(u16 epod_id, bool ramret)
*/
static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
{
- struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
if (info == NULL)
@@ -221,7 +162,7 @@ out:
static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
{
- struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
if (info == NULL)
@@ -245,7 +186,7 @@ out:
static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
{
- struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
if (info == NULL)
return -EINVAL;
@@ -266,8 +207,8 @@ static struct regulator_ops db8500_regulator_switch_ops = {
/*
* Regulator information
*/
-static struct db8500_regulator_info
-db8500_regulator_info[DB8500_NUM_REGULATORS] = {
+static struct dbx500_regulator_info
+dbx500_regulator_info[DB8500_NUM_REGULATORS] = {
[DB8500_REGULATOR_VAPE] = {
.desc = {
.name = "db8500-vape",
@@ -476,12 +417,12 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev)
int i, err;
/* register all regulators */
- for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
- struct db8500_regulator_info *info;
+ for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
+ struct dbx500_regulator_info *info;
struct regulator_init_data *init_data = &db8500_init_data[i];
/* assign per-regulator data */
- info = &db8500_regulator_info[i];
+ info = &dbx500_regulator_info[i];
info->dev = &pdev->dev;
/* register with the regulator framework */
@@ -494,7 +435,7 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev)
/* if failing, unregister all earlier regulators */
while (--i >= 0) {
- info = &db8500_regulator_info[i];
+ info = &dbx500_regulator_info[i];
regulator_unregister(info->rdev);
}
return err;
@@ -503,17 +444,22 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev)
dev_dbg(rdev_get_dev(info->rdev),
"regulator-%s-probed\n", info->desc.name);
}
+ err = ux500_regulator_debug_init(pdev,
+ dbx500_regulator_info,
+ ARRAY_SIZE(dbx500_regulator_info));
- return 0;
+ return err;
}
static int __exit db8500_regulator_remove(struct platform_device *pdev)
{
int i;
- for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
- struct db8500_regulator_info *info;
- info = &db8500_regulator_info[i];
+ ux500_regulator_debug_exit();
+
+ for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
+ struct dbx500_regulator_info *info;
+ info = &dbx500_regulator_info[i];
dev_vdbg(rdev_get_dev(info->rdev),
"regulator-%s-remove\n", info->desc.name);
diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c
new file mode 100644
index 000000000000..f2e5ecdc5864
--- /dev/null
+++ b/drivers/regulator/dbx500-prcmu.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * UX500 common part of Power domain regulators
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+
+#include "dbx500-prcmu.h"
+
+/*
+ * power state reference count
+ */
+static int power_state_active_cnt; /* will initialize to zero */
+static DEFINE_SPINLOCK(power_state_active_lock);
+
+int power_state_active_get(void)
+{
+ unsigned long flags;
+ int cnt;
+
+ spin_lock_irqsave(&power_state_active_lock, flags);
+ cnt = power_state_active_cnt;
+ spin_unlock_irqrestore(&power_state_active_lock, flags);
+
+ return cnt;
+}
+
+void power_state_active_enable(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&power_state_active_lock, flags);
+ power_state_active_cnt++;
+ spin_unlock_irqrestore(&power_state_active_lock, flags);
+}
+
+int power_state_active_disable(void)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&power_state_active_lock, flags);
+ if (power_state_active_cnt <= 0) {
+ pr_err("power state: unbalanced enable/disable calls\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ power_state_active_cnt--;
+out:
+ spin_unlock_irqrestore(&power_state_active_lock, flags);
+ return ret;
+}
+
+#ifdef CONFIG_REGULATOR_DEBUG
+
+static struct ux500_regulator_debug {
+ struct dentry *dir;
+ struct dentry *status_file;
+ struct dentry *power_state_cnt_file;
+ struct dbx500_regulator_info *regulator_array;
+ int num_regulators;
+ u8 *state_before_suspend;
+ u8 *state_after_suspend;
+} rdebug;
+
+void ux500_regulator_suspend_debug(void)
+{
+ int i;
+ for (i = 0; i < rdebug.num_regulators; i++)
+ rdebug.state_before_suspend[i] =
+ rdebug.regulator_array[i].is_enabled;
+}
+
+void ux500_regulator_resume_debug(void)
+{
+ int i;
+ for (i = 0; i < rdebug.num_regulators; i++)
+ rdebug.state_after_suspend[i] =
+ rdebug.regulator_array[i].is_enabled;
+}
+
+static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
+{
+ struct device *dev = s->private;
+ int err;
+
+ /* print power state count */
+ err = seq_printf(s, "ux500-regulator power state count: %i\n",
+ power_state_active_get());
+ if (err < 0)
+ dev_err(dev, "seq_printf overflow\n");
+
+ return 0;
+}
+
+static int ux500_regulator_power_state_cnt_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ux500_regulator_power_state_cnt_print,
+ inode->i_private);
+}
+
+static const struct file_operations ux500_regulator_power_state_cnt_fops = {
+ .open = ux500_regulator_power_state_cnt_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ux500_regulator_status_print(struct seq_file *s, void *p)
+{
+ struct device *dev = s->private;
+ int err;
+ int i;
+
+ /* print dump header */
+ err = seq_printf(s, "ux500-regulator status:\n");
+ if (err < 0)
+ dev_err(dev, "seq_printf overflow\n");
+
+ err = seq_printf(s, "%31s : %8s : %8s\n", "current",
+ "before", "after");
+ if (err < 0)
+ dev_err(dev, "seq_printf overflow\n");
+
+ for (i = 0; i < rdebug.num_regulators; i++) {
+ struct dbx500_regulator_info *info;
+ /* Access per-regulator data */
+ info = &rdebug.regulator_array[i];
+
+ /* print status */
+ err = seq_printf(s, "%20s : %8s : %8s : %8s\n", info->desc.name,
+ info->is_enabled ? "enabled" : "disabled",
+ rdebug.state_before_suspend[i] ? "enabled" : "disabled",
+ rdebug.state_after_suspend[i] ? "enabled" : "disabled");
+ if (err < 0)
+ dev_err(dev, "seq_printf overflow\n");
+ }
+
+ return 0;
+}
+
+static int ux500_regulator_status_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ux500_regulator_status_print,
+ inode->i_private);
+}
+
+static const struct file_operations ux500_regulator_status_fops = {
+ .open = ux500_regulator_status_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+int __attribute__((weak)) dbx500_regulator_testcase(
+ struct dbx500_regulator_info *regulator_info,
+ int num_regulators)
+{
+ return 0;
+}
+
+int __devinit
+ux500_regulator_debug_init(struct platform_device *pdev,
+ struct dbx500_regulator_info *regulator_info,
+ int num_regulators)
+{
+ /* create directory */
+ rdebug.dir = debugfs_create_dir("ux500-regulator", NULL);
+ if (!rdebug.dir)
+ goto exit_no_debugfs;
+
+ /* create "status" file */
+ rdebug.status_file = debugfs_create_file("status",
+ S_IRUGO, rdebug.dir, &pdev->dev,
+ &ux500_regulator_status_fops);
+ if (!rdebug.status_file)
+ goto exit_destroy_dir;
+
+ /* create "power-state-count" file */
+ rdebug.power_state_cnt_file = debugfs_create_file("power-state-count",
+ S_IRUGO, rdebug.dir, &pdev->dev,
+ &ux500_regulator_power_state_cnt_fops);
+ if (!rdebug.power_state_cnt_file)
+ goto exit_destroy_status;
+
+ rdebug.regulator_array = regulator_info;
+ rdebug.num_regulators = num_regulators;
+
+ rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
+ if (!rdebug.state_before_suspend) {
+ dev_err(&pdev->dev,
+ "could not allocate memory for saving state\n");
+ goto exit_destroy_power_state;
+ }
+
+ rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
+ if (!rdebug.state_after_suspend) {
+ dev_err(&pdev->dev,
+ "could not allocate memory for saving state\n");
+ goto exit_free;
+ }
+
+ dbx500_regulator_testcase(regulator_info, num_regulators);
+ return 0;
+
+exit_free:
+ kfree(rdebug.state_before_suspend);
+exit_destroy_power_state:
+ debugfs_remove(rdebug.power_state_cnt_file);
+exit_destroy_status:
+ debugfs_remove(rdebug.status_file);
+exit_destroy_dir:
+ debugfs_remove(rdebug.dir);
+exit_no_debugfs:
+ dev_err(&pdev->dev, "failed to create debugfs entries.\n");
+ return -ENOMEM;
+}
+
+int __devexit ux500_regulator_debug_exit(void)
+{
+ debugfs_remove_recursive(rdebug.dir);
+ kfree(rdebug.state_after_suspend);
+ kfree(rdebug.state_before_suspend);
+
+ return 0;
+}
+#endif
diff --git a/drivers/regulator/dbx500-prcmu.h b/drivers/regulator/dbx500-prcmu.h
new file mode 100644
index 000000000000..e763883a44f4
--- /dev/null
+++ b/drivers/regulator/dbx500-prcmu.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson,
+ * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License Terms: GNU General Public License v2
+ *
+ */
+
+#ifndef DBX500_REGULATOR_H
+#define DBX500_REGULATOR_H
+
+#include <linux/platform_device.h>
+
+/**
+ * struct dbx500_regulator_info - dbx500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @rdev: regulator device pointer
+ * @is_enabled: status of the regulator
+ * @epod_id: id for EPOD (power domain)
+ * @is_ramret: RAM retention switch for EPOD (power domain)
+ * @operating_point: operating point (only for vape, to be removed)
+ *
+ */
+struct dbx500_regulator_info {
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ bool is_enabled;
+ u16 epod_id;
+ bool is_ramret;
+ bool exclude_from_power_state;
+ unsigned int operating_point;
+};
+
+void power_state_active_enable(void);
+int power_state_active_disable(void);
+
+
+#ifdef CONFIG_REGULATOR_DEBUG
+int ux500_regulator_debug_init(struct platform_device *pdev,
+ struct dbx500_regulator_info *regulator_info,
+ int num_regulators);
+
+int ux500_regulator_debug_exit(void);
+#else
+
+static inline int ux500_regulator_debug_init(struct platform_device *pdev,
+ struct dbx500_regulator_info *regulator_info,
+ int num_regulators)
+{
+ return 0;
+}
+
+static inline int ux500_regulator_debug_exit(void)
+{
+ return 0;
+}
+
+#endif
+#endif
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index d26e8646277b..bb7cd9df9487 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -908,13 +908,13 @@ static struct regulator_desc regulators[] = {
},
regulator_desc_buck(7),
{
- .name = "EN32KHz AP",
+ .name = "EN32KHz_AP",
.id = MAX8997_EN32KHZ_AP,
.ops = &max8997_fixedvolt_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
- .name = "EN32KHz CP",
+ .name = "EN32KHz_CP",
.id = MAX8997_EN32KHZ_CP,
.ops = &max8997_fixedvolt_ops,
.type = REGULATOR_VOLTAGE,
@@ -938,7 +938,7 @@ static struct regulator_desc regulators[] = {
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
}, {
- .name = "CHARGER CV",
+ .name = "CHARGER_CV",
.id = MAX8997_CHARGER_CV,
.ops = &max8997_fixedstate_ops,
.type = REGULATOR_VOLTAGE,
@@ -950,7 +950,7 @@ static struct regulator_desc regulators[] = {
.type = REGULATOR_CURRENT,
.owner = THIS_MODULE,
}, {
- .name = "CHARGER TOPOFF",
+ .name = "CHARGER_TOPOFF",
.id = MAX8997_CHARGER_TOPOFF,
.ops = &max8997_charger_fixedstate_ops,
.type = REGULATOR_CURRENT,
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index 80ecafef1bc3..62dcd0a432bb 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -254,6 +254,7 @@ int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
return num;
}
+EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt);
struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt(
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
@@ -291,6 +292,7 @@ struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt(
return data;
}
+EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt);
#endif
MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
new file mode 100644
index 000000000000..5b00e5ac70cd
--- /dev/null
+++ b/drivers/regulator/s5m8767.c
@@ -0,0 +1,832 @@
+/*
+ * s5m8767.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ * http://www.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.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/s5m87xx/s5m-core.h>
+#include <linux/mfd/s5m87xx/s5m-pmic.h>
+
+struct s5m8767_info {
+ struct device *dev;
+ struct s5m87xx_dev *iodev;
+ int num_regulators;
+ struct regulator_dev **rdev;
+
+ int ramp_delay;
+ bool buck2_ramp;
+ bool buck3_ramp;
+ bool buck4_ramp;
+
+ bool buck2_gpiodvs;
+ bool buck3_gpiodvs;
+ bool buck4_gpiodvs;
+ u8 buck2_vol[8];
+ u8 buck3_vol[8];
+ u8 buck4_vol[8];
+ int buck_gpios[3];
+ int buck_gpioindex;
+};
+
+struct s5m_voltage_desc {
+ int max;
+ int min;
+ int step;
+};
+
+static const struct s5m_voltage_desc buck_voltage_val1 = {
+ .max = 2225000,
+ .min = 650000,
+ .step = 6250,
+};
+
+static const struct s5m_voltage_desc buck_voltage_val2 = {
+ .max = 1600000,
+ .min = 600000,
+ .step = 6250,
+};
+
+static const struct s5m_voltage_desc buck_voltage_val3 = {
+ .max = 3000000,
+ .min = 750000,
+ .step = 12500,
+};
+
+static const struct s5m_voltage_desc ldo_voltage_val1 = {
+ .max = 3950000,
+ .min = 800000,
+ .step = 50000,
+};
+
+static const struct s5m_voltage_desc ldo_voltage_val2 = {
+ .max = 2375000,
+ .min = 800000,
+ .step = 25000,
+};
+
+static const struct s5m_voltage_desc *reg_voltage_map[] = {
+ [S5M8767_LDO1] = &ldo_voltage_val2,
+ [S5M8767_LDO2] = &ldo_voltage_val2,
+ [S5M8767_LDO3] = &ldo_voltage_val1,
+ [S5M8767_LDO4] = &ldo_voltage_val1,
+ [S5M8767_LDO5] = &ldo_voltage_val1,
+ [S5M8767_LDO6] = &ldo_voltage_val2,
+ [S5M8767_LDO7] = &ldo_voltage_val2,
+ [S5M8767_LDO8] = &ldo_voltage_val2,
+ [S5M8767_LDO9] = &ldo_voltage_val1,
+ [S5M8767_LDO10] = &ldo_voltage_val1,
+ [S5M8767_LDO11] = &ldo_voltage_val1,
+ [S5M8767_LDO12] = &ldo_voltage_val1,
+ [S5M8767_LDO13] = &ldo_voltage_val1,
+ [S5M8767_LDO14] = &ldo_voltage_val1,
+ [S5M8767_LDO15] = &ldo_voltage_val2,
+ [S5M8767_LDO16] = &ldo_voltage_val1,
+ [S5M8767_LDO17] = &ldo_voltage_val1,
+ [S5M8767_LDO18] = &ldo_voltage_val1,
+ [S5M8767_LDO19] = &ldo_voltage_val1,
+ [S5M8767_LDO20] = &ldo_voltage_val1,
+ [S5M8767_LDO21] = &ldo_voltage_val1,
+ [S5M8767_LDO22] = &ldo_voltage_val1,
+ [S5M8767_LDO23] = &ldo_voltage_val1,
+ [S5M8767_LDO24] = &ldo_voltage_val1,
+ [S5M8767_LDO25] = &ldo_voltage_val1,
+ [S5M8767_LDO26] = &ldo_voltage_val1,
+ [S5M8767_LDO27] = &ldo_voltage_val1,
+ [S5M8767_LDO28] = &ldo_voltage_val1,
+ [S5M8767_BUCK1] = &buck_voltage_val1,
+ [S5M8767_BUCK2] = &buck_voltage_val2,
+ [S5M8767_BUCK3] = &buck_voltage_val2,
+ [S5M8767_BUCK4] = &buck_voltage_val2,
+ [S5M8767_BUCK5] = &buck_voltage_val1,
+ [S5M8767_BUCK6] = &buck_voltage_val1,
+ [S5M8767_BUCK7] = NULL,
+ [S5M8767_BUCK8] = NULL,
+ [S5M8767_BUCK9] = &buck_voltage_val3,
+};
+
+static int s5m8767_list_voltage(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ const struct s5m_voltage_desc *desc;
+ int reg_id = rdev_get_id(rdev);
+ int val;
+
+ if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0)
+ return -EINVAL;
+
+ desc = reg_voltage_map[reg_id];
+ if (desc == NULL)
+ return -EINVAL;
+
+ val = desc->min + desc->step * selector;
+ if (val > desc->max)
+ return -EINVAL;
+
+ return val;
+}
+
+static int s5m8767_get_register(struct regulator_dev *rdev, int *reg)
+{
+ int reg_id = rdev_get_id(rdev);
+
+ switch (reg_id) {
+ case S5M8767_LDO1 ... S5M8767_LDO2:
+ *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
+ break;
+ case S5M8767_LDO3 ... S5M8767_LDO28:
+ *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
+ break;
+ case S5M8767_BUCK1:
+ *reg = S5M8767_REG_BUCK1CTRL1;
+ break;
+ case S5M8767_BUCK2 ... S5M8767_BUCK4:
+ *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9;
+ break;
+ case S5M8767_BUCK5:
+ *reg = S5M8767_REG_BUCK5CTRL1;
+ break;
+ case S5M8767_BUCK6 ... S5M8767_BUCK9:
+ *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+ int ret, reg;
+ int mask = 0xc0, pattern = 0xc0;
+ u8 val;
+
+ ret = s5m8767_get_register(rdev, &reg);
+ if (ret == -EINVAL)
+ return 1;
+ else if (ret)
+ return ret;
+
+ ret = s5m_reg_read(s5m8767->iodev, reg, &val);
+ if (ret)
+ return ret;
+
+ return (val & mask) == pattern;
+}
+
+static int s5m8767_reg_enable(struct regulator_dev *rdev)
+{
+ struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+ int ret, reg;
+ int mask = 0xc0, pattern = 0xc0;
+
+ ret = s5m8767_get_register(rdev, &reg);
+ if (ret)
+ return ret;
+
+ return s5m_reg_update(s5m8767->iodev, reg, pattern, mask);
+}
+
+static int s5m8767_reg_disable(struct regulator_dev *rdev)
+{
+ struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+ int ret, reg;
+ int mask = 0xc0, pattern = 0xc0;
+
+ ret = s5m8767_get_register(rdev, &reg);
+ if (ret)
+ return ret;
+
+ return s5m_reg_update(s5m8767->iodev, reg, ~pattern, mask);
+}
+
+static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
+{
+ int reg_id = rdev_get_id(rdev);
+ int reg;
+
+ switch (reg_id) {
+ case S5M8767_LDO1 ... S5M8767_LDO2:
+ reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
+ break;
+ case S5M8767_LDO3 ... S5M8767_LDO28:
+ reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
+ break;
+ case S5M8767_BUCK1:
+ reg = S5M8767_REG_BUCK1CTRL2;
+ break;
+ case S5M8767_BUCK2:
+ reg = S5M8767_REG_BUCK2DVS1;
+ break;
+ case S5M8767_BUCK3:
+ reg = S5M8767_REG_BUCK3DVS1;
+ break;
+ case S5M8767_BUCK4:
+ reg = S5M8767_REG_BUCK4DVS1;
+ break;
+ case S5M8767_BUCK5:
+ reg = S5M8767_REG_BUCK5CTRL2;
+ break;
+ case S5M8767_BUCK6 ... S5M8767_BUCK9:
+ reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *_reg = reg;
+
+ return 0;
+}
+
+static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+ int reg, mask = 0xff, ret;
+ int reg_id = rdev_get_id(rdev);
+ u8 val;
+
+ ret = s5m8767_get_voltage_register(rdev, &reg);
+ if (ret)
+ return ret;
+
+ switch (reg_id) {
+ case S5M8767_LDO1 ... S5M8767_LDO28:
+ mask = 0x3f;
+ break;
+ case S5M8767_BUCK2:
+ if (s5m8767->buck2_gpiodvs)
+ reg += s5m8767->buck_gpioindex;
+ break;
+ case S5M8767_BUCK3:
+ if (s5m8767->buck3_gpiodvs)
+ reg += s5m8767->buck_gpioindex;
+ break;
+ case S5M8767_BUCK4:
+ if (s5m8767->buck4_gpiodvs)
+ reg += s5m8767->buck_gpioindex;
+ break;
+ }
+
+ ret = s5m_reg_read(s5m8767->iodev, reg, &val);
+ if (ret)
+ return ret;
+
+ val &= mask;
+
+ return val;
+}
+
+static inline int s5m8767_convert_voltage(
+ const struct s5m_voltage_desc *desc,
+ int min_vol, int max_vol)
+{
+ int out_vol = 0;
+
+ if (desc == NULL)
+ return -EINVAL;
+
+ if (max_vol < desc->min || min_vol > desc->max)
+ return -EINVAL;
+
+ out_vol = (min_vol - desc->min) / desc->step;
+
+ if (desc->min + desc->step * out_vol > max_vol)
+ return -EINVAL;
+
+ return out_vol;
+}
+
+static int s5m8767_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+ int min_vol = min_uV, max_vol = max_uV;