summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaura Lawrence <Laura.Lawrence@freescale.com>2008-01-25 01:05:10 -0600
committerDaniel Schaeffer <daniel.schaeffer@timesys.com>2008-08-25 15:20:36 -0400
commit973c485f7f3e8849bce29589aa23e27fc035953c (patch)
tree7759bcb625f5253755258ec9cca5bb385f9964ec
parentc1219fd957db3b7f789cb1a1ab6353cb34d31dc6 (diff)
ENGR00063257 Add Regulator API
Description: Generic interface to control voltage regulators at http://opensource.wolfsonmicro.com/node/8 AudioPlus project Signed-off-by: Rob Herring <ra7055@freescale.com>
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/regulator/Kconfig21
-rw-r--r--drivers/regulator/Makefile11
-rw-r--r--drivers/regulator/reg-core.c791
-rw-r--r--include/linux/regulator/regulator-drv.h107
-rw-r--r--include/linux/regulator/regulator-platform.h102
-rw-r--r--include/linux/regulator/regulator.h332
9 files changed, 1369 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 70f0b8600547..d7a0daca30e0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1002,6 +1002,8 @@ if ALIGNMENT_TRAP || !CPU_CP15_MMU
source "drivers/mtd/Kconfig"
endif
+source "drivers/regulator/Kconfig"
+
source "drivers/parport/Kconfig"
source "drivers/pnp/Kconfig"
diff --git a/drivers/Kconfig b/drivers/Kconfig
index f12108b84c9c..5604d59c65d8 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -86,6 +86,8 @@ source "drivers/edac/Kconfig"
source "drivers/rtc/Kconfig"
+source "drivers/regulator/Kconfig"
+
source "drivers/dma/Kconfig"
source "drivers/dca/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 48e670990615..343cf5230fe6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -92,5 +92,6 @@ obj-$(CONFIG_DCA) += dca/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
+obj-$(CONFIG_REGULATOR) += regulator/
obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_VIRTIO) += virtio/
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
new file mode 100644
index 000000000000..bec9a9421b40
--- /dev/null
+++ b/drivers/regulator/Kconfig
@@ -0,0 +1,21 @@
+menu "Voltage and Current regulators"
+
+config REGULATOR_API
+ bool
+
+config REGULATOR
+ tristate "Voltage and Current Regulator Support"
+ depends on EXPERIMENTAL
+ select REGULATOR_API
+ default n
+ help
+ Generic Voltage and Current Regulator support.
+
+config REGULATOR_DEBUG
+ bool "Regulator debug support"
+ depends on REGULATOR
+ help
+ Say yes here to enable debugging support.
+
+
+endmenu
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
new file mode 100644
index 000000000000..9cb2def48ba0
--- /dev/null
+++ b/drivers/regulator/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for regulator drivers.
+#
+
+obj-$(CONFIG_REGULATOR) += reg-core.o
+
+ifeq ($(CONFIG_REGULATOR_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+
+
diff --git a/drivers/regulator/reg-core.c b/drivers/regulator/reg-core.c
new file mode 100644
index 000000000000..1d68ad8fd88f
--- /dev/null
+++ b/drivers/regulator/reg-core.c
@@ -0,0 +1,791 @@
+/*
+ * regulator.c -- Voltage/Current Regulator framework.
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/regulator/regulator.h>
+#include <linux/regulator/regulator-drv.h>
+#include <linux/regulator/regulator-platform.h>
+
+static DEFINE_MUTEX(list_mutex);
+static LIST_HEAD(regulators);
+
+struct regulator_load {
+ struct device *dev;
+ struct list_head list;
+ int uA_load;
+ struct device_attribute dev_attr;
+};
+
+#define to_regulator(cd) \
+ container_of(cd, struct regulator, cdev)
+
+static struct regulator_load *get_regulator_load(struct device *dev)
+{
+ struct regulator_load *load = NULL;
+ struct regulator *regulator;
+
+ list_for_each_entry(regulator, &regulators, list) {
+ list_for_each_entry(load, &regulator->user_list, list) {
+ if (load->dev == dev)
+ return load;
+ }
+ }
+ return NULL;
+}
+
+#if 0
+static int constraint_check_state(struct regulator *regulator)
+{
+ if (!regulator->constraints)
+ return -ENODEV;
+ if (!regulator->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
+ return -EPERM;
+ return 0;
+}
+#endif
+
+static int constraint_check_voltage(struct regulator *regulator, int uV)
+{
+ if (!regulator->constraints)
+ return -ENODEV;
+ if (!regulator->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)
+ return -EPERM;
+ if (uV > regulator->constraints->max_uV ||
+ uV < regulator->constraints->min_uV)
+ return -EINVAL;
+ return 0;
+}
+
+static int constraint_check_current(struct regulator *regulator, int uA)
+{
+ if (!regulator->constraints)
+ return -ENODEV;
+ if (!regulator->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)
+ return -EPERM;
+ if (uA > regulator->constraints->max_uA ||
+ uA < regulator->constraints->min_uA)
+ return -EINVAL;
+ return 0;
+}
+
+static int constraint_check_mode(struct regulator *regulator, int mode)
+{
+ if (!regulator->constraints)
+ return -ENODEV;
+ if (!regulator->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)
+ return -EPERM;
+ if (!regulator->constraints->valid_modes_mask & mode)
+ return -EINVAL;
+ return 0;
+}
+
+static int constraint_check_drms(struct regulator *regulator)
+{
+ if (!regulator->constraints)
+ return -ENODEV;
+ if (!regulator->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)
+ return -EPERM;
+ return 0;
+}
+
+static ssize_t dev_load_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct regulator_load *load;
+
+ load = get_regulator_load(dev);
+ if (load == NULL)
+ return 0;
+
+ return sprintf(buf, "%d\n", load->uA_load);
+}
+
+static ssize_t regulator_uV_show(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+
+ return sprintf(buf, "%d\n", regulator_get_voltage(regulator));
+}
+
+static ssize_t regulator_uA_show(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+
+ return sprintf(buf, "%d\n", regulator_get_current(regulator));
+}
+
+static ssize_t regulator_mode_show(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+ int mode = regulator_get_mode(regulator);
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ return sprintf(buf, "fast\n");
+ case REGULATOR_MODE_NORMAL:
+ return sprintf(buf, "normal\n");
+ case REGULATOR_MODE_IDLE:
+ return sprintf(buf, "idle\n");
+ case REGULATOR_MODE_STANDBY:
+ return sprintf(buf, "standby\n");
+ }
+ return sprintf(buf, "unknown\n");
+}
+
+static ssize_t regulator_state_show(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+ int state = regulator_is_enabled(regulator);
+
+ if (state > 0)
+ return sprintf(buf, "enabled\n");
+ else if (state == 0)
+ return sprintf(buf, "disabled\n");
+ else
+ return sprintf(buf, "unknown\n");
+}
+
+static ssize_t
+regulator_constraint_uA_show(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+
+ if (!regulator->constraints)
+ return sprintf(buf, "no constraints\n");
+
+ return sprintf(buf, "%d %d\n", regulator->constraints->min_uA,
+ regulator->constraints->max_uA);
+}
+
+static ssize_t
+regulator_constraint_uV_show(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+
+ if (!regulator->constraints)
+ return sprintf(buf, "no constraints\n");
+
+ return sprintf(buf, "%d %d\n", regulator->constraints->min_uV,
+ regulator->constraints->max_uV);
+}
+
+static ssize_t
+regulator_constraint_modes_show(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+ int count = 0;
+
+ if (!regulator->constraints)
+ return sprintf(buf, "no constraints\n");
+
+ if (regulator->constraints->valid_modes_mask & REGULATOR_MODE_FAST)
+ count = sprintf(buf, "fast ");
+ if (regulator->constraints->valid_modes_mask & REGULATOR_MODE_NORMAL)
+ count += sprintf(buf + count, "normal ");
+ if (regulator->constraints->valid_modes_mask & REGULATOR_MODE_IDLE)
+ count += sprintf(buf + count, "idle ");
+ if (regulator->constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
+ count += sprintf(buf + count, "standby");
+ count += sprintf(buf + count, "\n");
+ return count;
+}
+
+static ssize_t regulator_total_dev_load(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+ struct regulator_load *load;
+ int uA = 0;
+
+ list_for_each_entry(load, &regulator->user_list, list) {
+ uA += load->uA_load;
+ }
+ return sprintf(buf, "%d\n", uA);
+}
+
+static ssize_t regulator_enabled_use_count(struct class_device *cdev, char *buf)
+{
+ struct regulator *regulator = to_regulator(cdev);
+ return sprintf(buf, "%d\n", regulator->use_count);
+}
+
+
+static struct class_device_attribute regulator_dev_attrs[] = {
+ __ATTR(uV, 0444, regulator_uV_show, NULL),
+ __ATTR(uA, 0444, regulator_uA_show, NULL),
+ __ATTR(mode, 0444, regulator_mode_show, NULL),
+ __ATTR(state, 0444, regulator_state_show, NULL),
+ __ATTR(uA_limits, 0444, regulator_constraint_uA_show, NULL),
+ __ATTR(uV_limits, 0444, regulator_constraint_uV_show, NULL),
+ __ATTR(valid_modes, 0444, regulator_constraint_modes_show, NULL),
+ __ATTR(total_uA_load, 0444, regulator_total_dev_load, NULL),
+ __ATTR(enabled_count, 0444, regulator_enabled_use_count, NULL),
+ __ATTR_NULL,
+};
+
+static void regulator_dev_release(struct class_device *class_dev) {}
+
+struct class regulator_class = {
+ .name = "regulator",
+ .release = regulator_dev_release,
+ .class_dev_attrs = regulator_dev_attrs,
+};
+
+static struct regulator_load *create_load_dev(struct regulator *regulator,
+ struct device *dev)
+{
+ struct regulator_load *load;
+ char buf[32];
+ int err;
+
+ load = kzalloc(sizeof(*load), GFP_KERNEL);
+ if (load == NULL)
+ return NULL;
+
+ sprintf(buf, "uA_load-%s", regulator->name);
+ list_add(&load->list, &regulator->user_list);
+ load->dev = dev;
+ load->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL);
+ load->dev_attr.attr.owner = THIS_MODULE;
+ load->dev_attr.attr.mode = 0444;
+ load->dev_attr.show = dev_load_show;
+ err = device_create_file(dev, &load->dev_attr);
+ if (err < 0) {
+ printk(KERN_WARNING "%s: could not add regulator load"
+ " sysfs\n", __func__);
+ goto err_out;
+ }
+ err = sysfs_create_link(&regulator->cdev.kobj, &dev->kobj,
+ dev->kobj.name);
+ if (err) {
+ printk
+ (KERN_WARNING "%s : could not add device link %s err %d\n",
+ __func__, dev->kobj.name, err);
+ goto err_out;
+ }
+ return load;
+err_out:
+ kfree(load->dev_attr.attr.name);
+ kfree(load);
+ return NULL;
+}
+
+struct regulator *regulator_get(struct device *dev, const char *id)
+{
+ struct regulator *r, *regulator = ERR_PTR(-ENOENT);
+ struct regulator_load *load = NULL;
+
+ if (id == NULL)
+ return regulator;
+
+ mutex_lock(&list_mutex);
+
+ list_for_each_entry(r, &regulators, list) {
+ if (strcmp(id, r->name) == 0 &&
+ try_module_get(r->owner)) {
+ regulator = r;
+ goto found;
+ }
+ }
+ printk
+ (KERN_WARNING "regulator: Unable to get requested regulator: %s\n",
+ id);
+ mutex_unlock(&list_mutex);
+ return regulator;
+found:
+ if (dev) {
+ load = create_load_dev(regulator, dev);
+ if (load == NULL) {
+ regulator = ERR_PTR(-ENOMEM);
+ module_put(regulator->owner);
+ }
+ }
+
+ mutex_unlock(&list_mutex);
+ return regulator;
+}
+EXPORT_SYMBOL_GPL(regulator_get);
+
+void regulator_put(struct regulator *regulator, struct device *dev)
+{
+ struct regulator_load *load, *l;
+
+ if (regulator == NULL || IS_ERR(regulator))
+ return;
+
+ if (!dev)
+ goto put;
+
+ sysfs_remove_link(&regulator->cdev.kobj, dev->kobj.name);
+ list_for_each_entry_safe(load, l, &regulator->user_list, list) {
+ device_remove_file(dev, &load->dev_attr);
+ list_del(&load->list);
+ kfree(load->dev_attr.attr.name);
+ kfree(load);
+ goto put;
+ }
+put:
+ module_put(regulator->owner);
+ mutex_unlock(&list_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_put);
+
+static int __regulator_disable(struct regulator *regulator);
+
+static int __regulator_enable(struct regulator *regulator)
+{
+ int ret = 0;
+
+ if (regulator->use_count == 0) {
+
+ if (regulator->parent) {
+ ret = __regulator_enable(regulator->parent);
+
+ if (ret < 0) {
+ __regulator_disable(regulator->parent);
+ goto out;
+ }
+ }
+
+ if (regulator->ops->enable) {
+ ret = regulator->ops->enable(regulator);
+ if (ret < 0) {
+ __regulator_disable(regulator);
+ goto out;
+ }
+ }
+ }
+ regulator->use_count++;
+out:
+ return ret;
+}
+
+int regulator_enable(struct regulator *regulator)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+ ret = __regulator_enable(regulator);
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_enable);
+
+static int __regulator_disable(struct regulator *regulator)
+{
+ int ret = 0;
+
+ if (regulator->use_count == 1) {
+
+ if (regulator->ops->disable) {
+ ret = regulator->ops->disable(regulator);
+ if (ret < 0)
+ goto out;
+ }
+ if (regulator->parent)
+ __regulator_disable(regulator->parent);
+ }
+ regulator->use_count--;
+out:
+ return ret;
+}
+
+int regulator_disable(struct regulator *regulator)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+ ret = __regulator_disable(regulator);
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_disable);
+
+int regulator_is_enabled(struct regulator *regulator)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+
+ /* sanity check */
+ if (!regulator->ops->is_enabled) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = regulator->ops->is_enabled(regulator);
+out:
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_is_enabled);
+
+int regulator_set_voltage(struct regulator *regulator, int uV)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+
+ /* sanity check */
+ if (!regulator->ops->set_voltage) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* constraints check */
+ ret = constraint_check_voltage(regulator, uV);
+ if (ret < 0)
+ goto out;
+
+ ret = regulator->ops->set_voltage(regulator, uV);
+out:
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage);
+
+int regulator_get_voltage(struct regulator *regulator)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+
+ /* sanity check */
+ if (!regulator->ops->get_voltage) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = regulator->ops->get_voltage(regulator);
+out:
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage);
+
+int regulator_set_current(struct regulator *regulator, int uA)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+
+ /* sanity check */
+ if (!regulator->ops->set_current) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* constraints check */
+ ret = constraint_check_current(regulator, uA);
+ if (ret < 0)
+ goto out;
+
+ ret = regulator->ops->set_current(regulator, uA);
+out:
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_current);
+
+int regulator_get_current(struct regulator *regulator)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+
+ /* sanity check */
+ if (!regulator->ops->get_current) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = regulator->ops->get_current(regulator);
+out:
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_get_current);
+
+int regulator_set_mode(struct regulator *regulator, unsigned int mode)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+
+ /* sanity check */
+ if (!regulator->ops->set_mode) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* constraints check */
+ ret = constraint_check_mode(regulator, mode);
+ if (ret < 0)
+ goto out;
+
+ ret = regulator->ops->set_mode(regulator, mode);
+out:
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_mode);
+
+unsigned int regulator_get_mode(struct regulator *regulator)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+
+ /* sanity check */
+ if (!regulator->ops->get_mode) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = regulator->ops->get_mode(regulator);
+out:
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_get_mode);
+
+unsigned int regulator_get_optimum_mode(struct regulator *regulator,
+ int input_uV, int output_uV, int load_uA)
+{
+ int ret;
+
+ mutex_lock(&regulator->mutex);
+
+ /* sanity check */
+ if (!regulator->ops->get_optimum_mode) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = regulator->ops->get_optimum_mode(regulator,
+ input_uV, output_uV, load_uA);
+out:
+ mutex_unlock(&regulator->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_get_optimum_mode);
+
+int regulator_register_client(struct regulator *regulator,
+ struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&regulator->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(regulator_register_client);
+
+int regulator_unregister_client(struct regulator *regulator,
+ struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&regulator->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(regulator_unregister_client);
+
+int regulator_notifier_call_chain(struct regulator *regulator,
+ unsigned long event, void *data)
+{
+ return blocking_notifier_call_chain(&regulator->notifier, event, data);
+}
+EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
+
+int regulator_register(struct regulator *regulator)
+{
+ static atomic_t regulator_no = ATOMIC_INIT(0);
+ int ret;
+
+ if (regulator == NULL || IS_ERR(regulator))
+ return -EINVAL;
+
+ if (regulator->name == NULL || regulator->ops == NULL)
+ return -EINVAL;
+
+ mutex_lock(&list_mutex);
+
+ mutex_init(&regulator->mutex);
+ regulator->parent = NULL;
+ INIT_LIST_HEAD(&regulator->user_list);
+ BLOCKING_INIT_NOTIFIER_HEAD(&regulator->notifier);
+
+ regulator->cdev.class = &regulator_class;
+ class_device_initialize(&regulator->cdev);
+ snprintf(regulator->cdev.class_id, sizeof(regulator->cdev.class_id),
+ "regulator-%ld-%s",
+ (unsigned long) atomic_inc_return(&regulator_no) - 1,
+ regulator->name);
+
+ ret = class_device_add(&regulator->cdev);
+ if (ret == 0)
+ list_add(&regulator->list, &regulators);
+ mutex_unlock(&list_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_register);
+
+void regulator_unregister(struct regulator *regulator)
+{
+ if (regulator == NULL || IS_ERR(regulator))
+ return;
+
+ mutex_lock(&list_mutex);
+ list_del(&regulator->list);
+ if (regulator->parent)
+ sysfs_remove_link(&regulator->cdev.kobj, "source");
+ class_device_unregister(&regulator->cdev);
+ mutex_unlock(&list_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_unregister);
+
+int regulator_set_platform_source(struct regulator *regulator,
+ struct regulator *parent)
+{
+ int err;
+
+ if (regulator == NULL || IS_ERR(regulator))
+ return -EINVAL;
+
+ if (parent == NULL || IS_ERR(parent))
+ return -EINVAL;
+
+ mutex_lock(&list_mutex);
+ regulator->parent = parent;
+ err = sysfs_create_link(&regulator->cdev.kobj, &parent->cdev.kobj,
+ "source");
+ if (err)
+ printk(KERN_WARNING "%s : could not add device link %s err %d\n",
+ __func__, parent->cdev.kobj.name, err);
+ mutex_unlock(&list_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(regulator_set_platform_source);
+
+struct regulator *regulator_get_platform_source(struct regulator *regulator)
+{
+ if (regulator == NULL || IS_ERR(regulator))
+ return ERR_PTR(-EINVAL);
+ return regulator->parent;
+}
+EXPORT_SYMBOL_GPL(regulator_get_platform_source);
+
+int regulator_set_platform_constraints(const char *regulator_name,
+ struct regulation_constraints *constraints)
+{
+ struct regulator *regulator;
+
+ if (regulator_name == NULL)
+ return -EINVAL;
+
+ mutex_lock(&list_mutex);
+ list_for_each_entry(regulator, &regulators, list) {
+ if (!strcmp(regulator_name, regulator->name)) {
+ mutex_lock(&regulator->mutex);
+ regulator->constraints = constraints;
+ mutex_unlock(&regulator->mutex);
+ mutex_unlock(&list_mutex);
+ return 0;
+ }
+ }
+ mutex_unlock(&list_mutex);
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(regulator_set_platform_constraints);
+
+static void load_change(struct regulator *regulator,
+ struct regulator_load *load, int uA)
+{
+ struct regulator_load *l;
+ int current_uA = 0, output_uV, input_uV, err;
+ unsigned int mode;
+
+ load->uA_load = uA;
+ err = constraint_check_drms(regulator);
+ if (err < 0 || !regulator->ops->get_optimum_mode ||
+ !regulator->ops->get_voltage || !regulator->ops->set_mode)
+ return;
+
+ /* get output voltage */
+ output_uV = regulator->ops->get_voltage(regulator);
+
+ /* get input voltage */
+ if (regulator->parent && regulator->parent->ops->get_voltage)
+ input_uV =
+ regulator->parent->ops->get_voltage(regulator->parent);
+ else
+ input_uV = regulator->constraints->input_uV;
+
+ /* calc total requested load */
+ list_for_each_entry(l, &regulator->user_list, list)
+ current_uA += l->uA_load;
+
+ mode = regulator->ops->get_optimum_mode(regulator, input_uV,
+ output_uV, current_uA);
+ err = constraint_check_mode(regulator, mode);
+ if (err < 0)
+ return;
+
+ regulator->ops->set_mode(regulator, mode);
+}
+
+void regulator_drms_notify_load(struct regulator *regulator,
+ struct device *dev, int uA)
+{
+ struct regulator_load *load;
+
+ mutex_lock(&regulator->mutex);
+ list_for_each_entry(load, &regulator->user_list, list) {
+ if (load->dev == dev) {
+ load_change(regulator, load, uA);
+ break;
+ }
+ }
+ mutex_unlock(&regulator->mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_drms_notify_load);
+
+void *regulator_get_drvdata(struct regulator *regulator)
+{
+ return regulator->reg_data;
+}
+EXPORT_SYMBOL_GPL(regulator_get_drvdata);
+
+void regulator_set_drvdata(struct regulator *regulator, void *data)
+{
+ regulator->reg_data = data;
+}
+EXPORT_SYMBOL_GPL(regulator_set_drvdata);
+
+static int __init regulator_init(void)
+{
+ return class_register(&regulator_class);
+}
+
+static void __exit regulator_exit(void)
+{
+ class_unregister(&regulator_class);
+}
+
+subsys_initcall(regulator_init);
+module_exit(regulator_exit);
+
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, \
+ www.wolfsonmicro.com ");
+MODULE_DESCRIPTION("Regulator Interface");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/regulator-drv.h b/include/linux/regulator/regulator-drv.h
new file mode 100644
index 000000000000..5235af9619fe
--- /dev/null
+++ b/include/linux/regulator/regulator-drv.h
@@ -0,0 +1,107 @@
+/*
+ * regulator-drv.h -- SoC Regulator support.
+ *
+ * Copyright (C) 2007 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Regulator Driver Interface.
+ */
+
+
+#ifndef __LINUX_REGULATOR_DRV_H_
+#define __LINUX_REGULATOR_DRV_H_
+
+#include <linux/device.h>
+#include <linux/regulator/regulator.h>
+
+struct regulator_constraints;
+
+/**
+ * struct regulator_ops - regulator operations.
+ *
+ * This struct describes regulator operations.
+ */
+struct regulator_ops {
+
+ /* get/set regulator voltage */
+ int (*set_voltage)(struct regulator *, int uV);
+ int (*get_voltage)(struct regulator *);
+
+ /* get/set regulator current */
+ int (*set_current)(struct regulator *, int uA);
+ int (*get_current)(struct regulator *);
+
+ /* enable/disable regulator */
+ int (*enable)(struct regulator *);
+ int (*disable)(struct regulator *);
+ int (*is_enabled)(struct regulator *);
+
+ /* get/set regulator mode (defined in regulator.h) */
+ int (*set_mode)(struct regulator *, unsigned int mode);
+ unsigned int (*get_mode)(struct regulator *);
+
+ /* get most efficient regulator mode for load */
+ unsigned int (*get_optimum_mode)(struct regulator *, int input_uV,
+ int output_uV, int load_uA);
+};
+
+/**
+ * struct regulator
+ *
+ * Voltage / Current regulator.
+ */
+struct regulator {
+ const char *name;
+ int id;
+ struct regulator_ops *ops;
+ struct regulation_constraints *constraints;
+ int use_count;
+
+ struct list_head list;
+ struct list_head user_list;
+ struct blocking_notifier_head notifier;
+ struct mutex mutex;
+ struct module *owner;
+ struct class_device cdev;
+
+ struct regulator *parent; /* for tree */
+
+ void *reg_data; /* regulator data */
+ void *vendor; /* regulator vendor extensions */
+};
+
+/**
+ * regulator_register - register regulator
+ * @regulator: regulator source
+ *
+ * Called by regulator drivers to register a regulator.
+ * Returns 0 on success.
+ */
+int regulator_register(struct regulator *regulator);
+
+/**
+ * regulator_unregister - unregister regulator
+ * @regulator: regulator source
+ *
+ * Called by regulator drivers to unregister a regulator.
+ */
+void regulator_unregister(struct regulator *regulator);
+
+/**
+ * regulator_notifier_call_chain - call regulator event notifier
+ * @regulator: regulator source
+ * @event: notifier block
+ * @data:
+ *
+ * Called by regulator drivers to notify clients a regulator event has
+ * occurred.
+ */
+int regulator_notifier_call_chain(struct regulator *regulator,
+ unsigned long event, void *data);
+
+#endif
diff --git a/include/linux/regulator/regulator-platform.h b/include/linux/regulator/regulator-platform.h
new file mode 100644
index 000000000000..7f57e035eb34
--- /dev/null
+++ b/include/linux/regulator/regulator-platform.h
@@ -0,0 +1,102 @@
+/*
+ * regulator-platform.h -- SoC Regulator support.
+ *
+ * Copyright (C) 2007 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Regulator Platform Interface.
+ */
+
+
+#ifndef __LINUX_REGULATOR_PLATFORM_H_
+#define __LINUX_REGULATOR_PLATFORM_H_
+
+#include <linux/regulator/regulator.h>
+
+struct regulator;
+
+/*
+ * Regulator operations.
+ *
+ * @VOLTAGE: Regulator output voltage can be changed by software on this
+ * board/machine.
+ * @CURRENT: Regulator output current can be changed by software on this
+ * board machine.
+ * @MODE: Regulator operating mode can be changed by software on this
+ * board machine.
+ * @STATUS: Regulator can be enabled and disabled.
+ * @DRMS: Dynamic Regulator Mode Switching is enabled for this regulator.
+ */
+
+#define REGULATOR_CHANGE_VOLTAGE 0x1
+#define REGULATOR_CHANGE_CURRENT 0x2
+#define REGULATOR_CHANGE_MODE 0x4
+#define REGULATOR_CHANGE_STATUS 0x8
+#define REGULATOR_CHANGE_DRMS 0x10
+
+/**
+ * struct regulation_constraints - regulator operating constraints.
+ *
+ * This struct describes regulator and board/machine specific constraints.
+ */
+struct regulation_constraints {
+
+ char *name;
+
+ /* voltage output range - for voltage control */
+ int min_uV;
+ int max_uV;
+
+ /* current output range - for current control */
+ int min_uA;
+ int max_uA;
+
+ /* valid regulator operating modes for this machine */
+ unsigned int valid_modes_mask;
+
+ /* valid operations for regulator on this machine */
+ unsigned int valid_ops_mask;
+
+ /* input voltage */
+ int input_uV;
+};
+
+/**
+ * regulator_set_platform_source - set regulator source regulator
+ * @regulator: regulator source
+ * @parent: source or parent regulator
+ *
+ * Called by platform initialisation code to set the source supply or "parent"
+ * regulator for this regulator.
+ */
+int regulator_set_platform_source(struct regulator *reg,
+ struct regulator *parent);
+
+/**
+ * regulator_get_platform_source - get regulator source regulator
+ * @regulator: regulator source
+ *
+ * Returns the regulator supply regulator or NULL if no supply regulator
+ * exists (i.e the regulator is supplied directly from USB, Line, Battery, etc)
+ */
+struct regulator *regulator_get_platform_source(struct regulator *regulator);
+
+
+/**
+ * regulator_set_platform_constraints - sets regulator constraints
+ * @regulator: regulator source
+ *
+ * Allows platform initialisation code to define and constrain regulator
+ * circuits e.g. valid voltage/current ranges, etc.
+ * NOTE: Constraints must be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current, set_mode.
+ */
+int regulator_set_platform_constraints(const char *regulator_name,
+ struct regulation_constraints *constraints);
+
+#endif
diff --git a/include/linux/regulator/regulator.h b/include/linux/regulator/regulator.h
new file mode 100644
index 000000000000..404b2472b11a
--- /dev/null
+++ b/include/linux/regulator/regulator.h
@@ -0,0 +1,332 @@
+/*
+ * regulator.h -- SoC Regulator support.
+ *
+ * Copyright (C) 2007 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Regulator Client Interface.
+ *
+ * A Power Management Regulator framework for SoC based devices.
+ * Features:-
+ * o Voltage and current level control.
+ * o Operating mode control.
+ * o Regulator status.
+ * o sysfs entries for showing client devices and status
+ *
+ * EXPERIMENTAL FEATURES:
+ * Dynamic Regulator operating Mode Switching (DRMS) - allows regulators
+ * to use most efficient operating mode depending upon voltage and load and
+ * is transparent to client drivers.
+ */
+
+
+#ifndef __LINUX_REGULATOR_H_
+#define __LINUX_REGULATOR_H_
+
+/*
+ * Regulator operating modes.
+ *
+ * Regulators can run in a variety of different operating modes depending
+ * output load. This allows further power saving though regulator efficiency.
+ *
+ * Most drivers will only care about NORMAL. The modes below are generic and
+ * will probably not match the naming convention of your regulator data sheet
+ * but should match the use cases in the datasheet.
+ *
+ * In order of power efficiency (least efficient at top).
+ *
+ * Mode Description
+ * FAST Regulator can handle fast changes in it's load.
+ * e.g. usefull in CPU voltage & frequency scaling where
+ * load can quickly increase with freqency increases.
+ *
+ * NORMAL Normal regulator power supply mode. Most drivers will
+ * use this mode.
+ *
+ * IDLE Regulator runs in a more efficient mode for light
+ * loads. Can be used for devices that have a low power
+ * requirement during periods of inactivity. This mode
+ * may be more noisy than NORMAL and may not be able
+ * to handle fast load switching.
+ *
+ * STANDBY Regulator runs in most efficient mode for very
+ * light loads. Can be used by devices when they are
+ * in a sleep/standby state. This mode may be more noisy
+ * than NORMAL and may not be able to handle fast load
+ * switching.
+ *
+ * NOTE: Most regulators will only support a subset of these modes. Some
+ * will only just support NORMAL.
+ */
+
+#define REGULATOR_MODE_FAST 0x1
+#define REGULATOR_MODE_NORMAL 0x2
+#define REGULATOR_MODE_IDLE 0x4
+#define REGULATOR_MODE_STANDBY 0x8
+
+/*
+ * Regulator notifier events.
+ *
+ * @UNDER_VOLTAGE: Regulator output is undervoltage.
+ * @OVER_CURRENT: Regulator output current is too high.
+ * @POWER_ON: Regulator power ON event.
+ * @POWER_OFF: Regulator power OFF event.
+ * @REGULATION_OUT: Regulator output is out of regulation.
+ * @FAIL: Regulator output has failed.
+ * @OVER_TEMP: Regulator over temp.
+ */
+
+#define REGULATOR_EVENT_UNDER_VOLTAGE 0x1
+#define REGULATOR_EVENT_OVER_CURRENT 0x2
+#define REGULATOR_EVENT_POWER_ON 0x4
+#define REGULATOR_EVENT_POWER_OFF 0x8
+#define REGULATOR_EVENT_REGULATION_OUT 0x10
+#define REGULATOR_EVENT_FAIL 0x20
+#define REGULATOR_EVENT_OVER_TEMP 0x40
+
+/*
+ * Convenience conversion.
+ * Here atm, maybe there is somewhere better for this.
+ */
+#define mV_to_uV(mV) (mV * 1000)
+#define uV_to_mV(uV) (uV / 1000)
+#define V_to_uV(V) (mV_to_uV(V * 1000))
+#define uV_to_V(uV) (uV_to_mV(uV) / 1000)
+
+struct regulator;
+
+#if defined(CONFIG_REGULATOR_API)
+
+/**
+ * regulator_get - lookup and obtain a reference to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: regulator ID
+ *
+ * Returns a struct regulator corresponding to the regulator producer, or
+ * valid IS_ERR() condition containing errno.
+ *
+ * Drivers must assume that the clock source is not enabled.
+ */
+struct regulator *regulator_get(struct device *dev, const char *id);
+
+/**
+ * regulator_put - "free" the regulator source
+ * @regulator: regulator source
+ * @dev: device
+ *
+ * Note: drivers must ensure that all regulator_enable calls made on this
+ * regulator source are balanced by regulator_disable calls prior to calling
+ * this function.
+ */
+void regulator_put(struct regulator *regulator, struct device *dev);
+
+/**
+ * regulator_enable - enable regulator output
+ * @regulator: regulator source
+ *
+ * Enable the regulator output at the predefined voltage or current value.
+ * Note: the output value can be set by other drivers, bootloader or may be
+ * hardwired in the regulator.
+ */
+int regulator_enable(struct regulator *regulator);
+
+/**
+ * regulator_disable - disable regulator output
+ * @regulator: regulator source
+ *
+ * Disable the regulator output voltage or current.
+ */
+int regulator_disable(struct regulator *regulator);
+
+/**
+ * regulator_is_enabled - is the regulator output enabled
+ * @regulator: regulator source
+ *
+ * Returns zero for disabled otherwise return number of enable requests.
+ */
+int regulator_is_enabled(struct regulator *regulator);
+
+/**
+ * regulator_set_voltage - set regulator output voltage
+ * @regulator: regulator source
+ * @uV: voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * during any regulator state. IOW, regulator can be disabled or enabled.
+ *
+ * If the regulator is enabled then the voltage will change to the new value
+ * immediately otherwise if the regulator is disabled the regulator will
+ * output at the new voltage when enabled.
+ */
+int regulator_set_voltage(struct regulator *regulator, int uV);
+
+/**
+ * regulator_get_voltage - get regulator output voltage
+ * @regulator: regulator source
+ *
+ * This returns the regulator voltage in uV.
+ *
+ * Note: If the regulator is disabled it will return the voltage value. This
+ * function should not be used to determine regulator state.
+ */
+int regulator_get_voltage(struct regulator *regulator);
+
+/**
+ * regulator_set_current - set regulator output current
+ * @regulator: regulator source
+ * @uV: voltage in uA
+ *
+ * Sets current regulator to the desired output current. This can be set during
+ * any regulator state. IOW, regulator can be disabled or enabled.
+ *
+ * If the regulator is enabled then the current will change to the new value
+ * immediately otherwise if the regulator is disabled the regulator will
+ * output at the new current when enabled.
+ */
+int regulator_set_current(struct regulator *regulator, int uA);
+
+/**
+ * regulator_get_current - get regulator output current
+ * @regulator: regulator source
+ *
+ * This returns the regulator current in uA.
+ *
+ * Note: If the regulator is disabled it will return the current value. This
+ * function should not be used to determine regulator state.
+ */
+int regulator_get_current(struct regulator *regulator);
+
+/**
+ * regulator_set_mode - set regulator operating mode
+ * @regulator: regulator source
+ * @mode: operating mode
+ *
+ * Set regulator operating mode to increase regulator efficiency or improve
+ * regulation performance.
+ */
+int regulator_set_mode(struct regulator *regulator, unsigned int mode);
+
+/**
+ * regulator_get_mode - set regulator operating mode
+ * @regulator: regulator source
+ *
+ * Get the current regulator operating mode.
+ */
+unsigned int regulator_get_mode(struct regulator *regulator);
+
+/**
+ * regulator_get_optimum_mode - get regulator optimum operating mode
+ * @regulator: regulator source
+ * @input_uV: input voltage
+ * @output_uV: output voltage
+ * @load_uV: load current
+ *
+ * Get the most efficient regulator operating mode for the given input
+ * and output voltages at a specific load..
+ */
+unsigned int regulator_get_optimum_mode(struct regulator *regulator,
+ int input_uV, int output_uV, int load_uA);
+
+/**
+ * regulator_register_client - register regulator event notifier
+ * @regulator: regulator source
+ * @notifier_block: notifier block
+ *
+ * Register notifier block to receive regulator events.
+ */
+int regulator_register_client(struct regulator *regulator,
+ struct notifier_block *nb);
+
+/**
+ * regulator_unregister_client - unregister regulator event notifier
+ * @regulator: regulator source
+ * @notifier_block: notifier block
+ *
+ * Unregister regulator event notifier block.
+ */
+int regulator_unregister_client(struct regulator *regulator,
+ struct notifier_block *nb);
+
+/**
+ * regulator_notify_load - notify regulator of device max load
+ * @regulator: regulator
+ * @dev: device
+ * @uA: load
+ *
+ * Notifies the regulator of new max device load. Can be used by DRMS to select
+ * the most efficient regulator operating mode.
+ *
+ * Client devices notify their supply regulator of the maximum power
+ * they will require when they change operational status and hence power
+ * state. Examples of operational state changes that can affect power
+ * consumption are :-
+ *
+ * o Device is opened / closed.
+ * o Device IO is about to begin or has just finished.
+ * o Device is idling in between work.
+ *
+ * The power tables in device datasheets would be used by the driver for
+ * the power consumption in each operational state. This information is
+ * also exported via sysfs to userspace.
+ *
+ * DRMS would then sum the total requested load on the regulator and change
+ * to the most efficient operating mode if platform constraints allow.
+ */
+void regulator_drms_notify_load(struct regulator *regulator,
+ struct device *dev, int uA);
+
+/**
+ * regulator_get_drvdata - get regulator driver data
+ * @regulator: regulator
+ */
+void *regulator_get_drvdata(struct regulator *regulator);
+
+/**
+ * regulator_set_drvdata - set regulator driver data
+ * @regulator: regulator
+ * @void: data
+ */
+void regulator_set_drvdata(struct regulator *regulator, void *data);
+
+#else
+
+/*
+ * Make sure client drivers will still build on systems with no software
+ * controllable voltage or current regulators.
+ */
+#define regulator_get(dev, id) ({ (void)(dev); (void)(id); NULL; })
+#define regulator_put(regulator, dev) \
+ do { (void)(regulator); (void)(dev); } while (0)
+#define regulator_enable(regulator) ({ (void)(regulator); 0; })
+#define regulator_disable(regulator) ({ (void)(regulator); 0; })
+#define regulator_is_enabled(regulator) ({ (void)(regulator); 1; })
+#define regulator_set_voltage(regulator, uV) \
+ ({ (void)(regulator); (void)(uV); 0; })
+#define regulator_get_voltage(regulator) ({ (void)(regulator); 0; })
+#define regulator_set_current(regulator, uA) \
+ ({ (void)(regulator); (void)(uA); 0; })
+#define regulator_get_current(regulator) ({ (void)(regulator); 0; })
+#define regulator_set_mode(regulator, mode) \
+ ({ (void)(regulator); (void)(mode); 0; })
+#define regulator_get_mode(regulator) ({ (void)(regulator); 0; })
+#define regulator_get_optimum_mode(regulator, input_uV, output_uV, load_uA) \
+ ({ (void)(regulator); (void)(input_uV); \
+ (void)(output_uV); (void)(load_uA); 0; })
+#define regulator_register_client(regulator, nb) \
+ ({ (void)(regulator); (void)(nb); 0; })
+#define regulator_unregister_client(regulator, nb) \
+ do { (void)(regulator); (void)(nb); } while (0)
+#define regulator_notify_load(regulator, dev, uA) \
+ do { (void)(regulator); (void)(dev); (void)(uA); } while (0)
+#define regulator_get_drvdata(regulator) ({ (void)(regulator); NULL; })
+#define regulator_set_drvdata(regulator, data) \
+ do { (void)(regulator); (void)(data); } while (0)
+
+#endif
+
+#endif