regulator: add support for changing control mode of regulator
[linux-2.6.git] / drivers / regulator / core.c
index b1fa25d..de6be43 100644 (file)
@@ -13,8 +13,6 @@
  *
  */
 
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/debugfs.h>
@@ -34,6 +32,9 @@
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/regulator.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
 
 #include "dummy.h"
 
@@ -54,9 +55,7 @@ static LIST_HEAD(regulator_map_list);
 static bool has_full_constraints;
 static bool board_wants_dummy_regulator;
 
-#ifdef CONFIG_DEBUG_FS
 static struct dentry *debugfs_root;
-#endif
 
 /*
  * struct regulator_map
@@ -84,13 +83,13 @@ struct regulator {
        char *supply_name;
        struct device_attribute dev_attr;
        struct regulator_dev *rdev;
-#ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs;
-#endif
 };
 
 static int _regulator_is_enabled(struct regulator_dev *rdev);
 static int _regulator_disable(struct regulator_dev *rdev);
+static int _regulator_enable(struct regulator_dev *rdev);
+static int _regulator_get_enable_time(struct regulator_dev *rdev);
 static int _regulator_get_voltage(struct regulator_dev *rdev);
 static int _regulator_get_current_limit(struct regulator_dev *rdev);
 static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
@@ -154,7 +153,7 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp
        regnode = of_parse_phandle(dev->of_node, prop_name, 0);
 
        if (!regnode) {
-               dev_warn(dev, "%s property in node %s references invalid phandle",
+               dev_dbg(dev, "Looking up %s property in node %s failed",
                                prop_name, dev->of_node->full_name);
                return NULL;
        }
@@ -296,6 +295,20 @@ static int regulator_check_drms(struct regulator_dev *rdev)
        return 0;
 }
 
+/* dynamic regulator control mode switching constraint check */
+static int regulator_check_control(struct regulator_dev *rdev)
+{
+       if (!rdev->constraints) {
+               rdev_err(rdev, "no constraints\n");
+               return -ENODEV;
+       }
+       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CONTROL)) {
+               rdev_err(rdev, "operation not allowed\n");
+               return -EPERM;
+       }
+       return 0;
+}
+
 static ssize_t device_requested_uA_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
@@ -308,6 +321,50 @@ static ssize_t device_requested_uA_show(struct device *dev,
        return sprintf(buf, "%d\n", regulator->uA_load);
 }
 
+static ssize_t regulator_uV_set(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
+       int ret;
+       int min_uV;
+       int max_uV = rdev->constraints->max_uV;
+       char *p = (char *)buf;
+
+       min_uV = memparse(p, &p);
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->set_voltage &&
+               !rdev->desc->ops->set_voltage_sel) {
+               rdev_err(rdev, "The operation is not supported\n");
+               goto out;
+       }
+
+       /* constraints check */
+       ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
+       if (ret < 0) {
+               rdev_err(rdev, "Voltage is out of range min:max= %d:%d\n",
+                       rdev->constraints->min_uV, rdev->constraints->max_uV);
+               goto out;
+       }
+
+       /* Consumer check */
+       ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
+       if (ret < 0) {
+               rdev_warn(rdev, "new voltage is out-range for some consumer\n");
+               rdev_warn(rdev, "min: max = %d:%d\n", min_uV, max_uV);
+       }
+
+       rdev_info(rdev, "Setting voltage min:max = %d:%d\n", min_uV, max_uV);
+       ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
+       if (ret < 0)
+               rdev_warn(rdev, "Can not set voltage %d:%d\n",  min_uV, max_uV);
+
+out:
+       mutex_unlock(&rdev->mutex);
+       return count;
+}
+
 static ssize_t regulator_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -320,7 +377,7 @@ static ssize_t regulator_uV_show(struct device *dev,
 
        return ret;
 }
-static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
+static DEVICE_ATTR(microvolts, 0644, regulator_uV_show, regulator_uV_set);
 
 static ssize_t regulator_uA_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
@@ -385,7 +442,65 @@ static ssize_t regulator_state_show(struct device *dev,
 
        return ret;
 }
-static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
+
+static ssize_t regulator_state_set(struct device *dev,
+                  struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
+       int ret;
+       bool enabled;
+
+       if ((*buf == 'E') || (*buf == 'e'))
+               enabled = true;
+       else if ((*buf == 'D') || (*buf == 'd'))
+               enabled = false;
+       else
+               return -EINVAL;
+
+       if ((_regulator_is_enabled(rdev) && enabled) ||
+               (!_regulator_is_enabled(rdev) && !enabled))
+               return count;
+
+       mutex_lock(&rdev->mutex);
+       if (enabled) {
+               int delay = 0;
+               if (!rdev->desc->ops->enable) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+               ret = _regulator_get_enable_time(rdev);
+               if (ret >= 0)
+                       delay = ret;
+               ret = rdev->desc->ops->enable(rdev);
+               if (ret < 0) {
+                       rdev_warn(rdev, "enable() failed: %d\n", ret);
+                       goto end;
+               }
+               if (delay >= 1000) {
+                       mdelay(delay / 1000);
+                       udelay(delay % 1000);
+               } else if (delay) {
+                       udelay(delay);
+               }
+       } else {
+               if (!rdev->desc->ops->disable) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+               ret = rdev->desc->ops->disable(rdev);
+               if (ret < 0) {
+                       rdev_warn(rdev, "disable() failed: %d\n", ret);
+                       goto end;
+               }
+       }
+
+end:
+       mutex_unlock(&rdev->mutex);
+       if (ret < 0)
+               return ret;
+       return count;
+}
+static DEVICE_ATTR(state, 0644, regulator_state_show, regulator_state_set);
 
 static ssize_t regulator_status_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
@@ -807,6 +922,11 @@ static void print_constraints(struct regulator_dev *rdev)
                count += sprintf(buf + count, "standby");
 
        rdev_info(rdev, "%s\n", buf);
+
+       if ((constraints->min_uV != constraints->max_uV) &&
+           !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE))
+               rdev_warn(rdev,
+                         "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n");
 }
 
 static int machine_constraints_voltage(struct regulator_dev *rdev,
@@ -996,7 +1116,6 @@ static int set_supply(struct regulator_dev *rdev,
 /**
  * set_consumer_device_supply - Bind a regulator to a symbolic supply
  * @rdev:         regulator source
- * @consumer_dev: device the supply applies to
  * @consumer_dev_name: dev_name() string for device supply applies to
  * @supply:       symbolic name for supply
  *
@@ -1004,22 +1123,14 @@ static int set_supply(struct regulator_dev *rdev,
  * sources to symbolic names for supplies for use by devices.  Devices
  * should use these symbolic names to request regulators, avoiding the
  * need to provide board-specific regulator names as platform data.
- *
- * Only one of consumer_dev and consumer_dev_name may be specified.
  */
 static int set_consumer_device_supply(struct regulator_dev *rdev,
-       struct device *consumer_dev, const char *consumer_dev_name,
-       const char *supply)
+                                     const char *consumer_dev_name,
+                                     const char *supply)
 {
        struct regulator_map *node;
        int has_dev;
 
-       if (consumer_dev && consumer_dev_name)
-               return -EINVAL;
-
-       if (!consumer_dev_name && consumer_dev)
-               consumer_dev_name = dev_name(consumer_dev);
-
        if (supply == NULL)
                return -EINVAL;
 
@@ -1039,11 +1150,12 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
                if (strcmp(node->supply, supply) != 0)
                        continue;
 
-               dev_dbg(consumer_dev, "%s/%s is '%s' supply; fail %s/%s\n",
-                       dev_name(&node->regulator->dev),
-                       node->regulator->desc->name,
-                       supply,
-                       dev_name(&rdev->dev), rdev_get_name(rdev));
+               pr_debug("%s: %s/%s is '%s' supply; fail %s/%s\n",
+                        consumer_dev_name,
+                        dev_name(&node->regulator->dev),
+                        node->regulator->desc->name,
+                        supply,
+                        dev_name(&rdev->dev), rdev_get_name(rdev));
                return -EBUSY;
        }
 
@@ -1142,12 +1254,10 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
                        goto attr_err;
        }
 
-#ifdef CONFIG_DEBUG_FS
        regulator->debugfs = debugfs_create_dir(regulator->supply_name,
                                                rdev->debugfs);
-       if (IS_ERR_OR_NULL(regulator->debugfs)) {
+       if (!regulator->debugfs) {
                rdev_warn(rdev, "Failed to create debugfs directory\n");
-               regulator->debugfs = NULL;
        } else {
                debugfs_create_u32("uA_load", 0444, regulator->debugfs,
                                   &regulator->uA_load);
@@ -1156,7 +1266,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
                debugfs_create_u32("max_uV", 0444, regulator->debugfs,
                                   &regulator->max_uV);
        }
-#endif
 
        mutex_unlock(&rdev->mutex);
        return regulator;
@@ -1210,7 +1319,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
 {
        struct regulator_dev *rdev;
        struct regulator_map *map;
-       struct regulator *regulator = ERR_PTR(-ENODEV);
+       struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
        const char *devname = NULL;
        int ret;
 
@@ -1320,6 +1429,40 @@ struct regulator *regulator_get(struct device *dev, const char *id)
 }
 EXPORT_SYMBOL_GPL(regulator_get);
 
+static void devm_regulator_release(struct device *dev, void *res)
+{
+       regulator_put(*(struct regulator **)res);
+}
+
+/**
+ * devm_regulator_get - Resource managed regulator_get()
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Managed regulator_get(). Regulators returned from this function are
+ * automatically regulator_put() on driver detach. See regulator_get() for more
+ * information.
+ */
+struct regulator *devm_regulator_get(struct device *dev, const char *id)
+{
+       struct regulator **ptr, *regulator;
+
+       ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       regulator = regulator_get(dev, id);
+       if (!IS_ERR(regulator)) {
+               *ptr = regulator;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return regulator;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get);
+
 /**
  * regulator_get_exclusive - obtain exclusive access to a regulator.
  * @dev: device for regulator "consumer"
@@ -1365,9 +1508,7 @@ void regulator_put(struct regulator *regulator)
        mutex_lock(&regulator_list_mutex);
        rdev = regulator->rdev;
 
-#ifdef CONFIG_DEBUG_FS
        debugfs_remove_recursive(regulator->debugfs);
-#endif
 
        /* remove any sysfs entries */
        if (regulator->dev) {
@@ -1387,6 +1528,37 @@ void regulator_put(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_put);
 
+static int devm_regulator_match(struct device *dev, void *res, void *data)
+{
+       struct regulator **r = res;
+       if (!r || !*r) {
+               WARN_ON(!r || !*r);
+               return 0;
+       }
+       return *r == data;
+}
+
+/**
+ * devm_regulator_put - Resource managed regulator_put()
+ * @regulator: regulator to free
+ *
+ * Deallocate a regulator allocated with devm_regulator_get(). Normally
+ * this function will not need to be called and the resource management
+ * code will ensure that the resource is freed.
+ */
+void devm_regulator_put(struct regulator *regulator)
+{
+       int rc;
+
+       rc = devres_destroy(regulator->dev, devm_regulator_release,
+                           devm_regulator_match, regulator);
+       if (rc == 0)
+               regulator_put(regulator);
+       else
+               WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_regulator_put);
+
 static int _regulator_can_change_status(struct regulator_dev *rdev)
 {
        if (!rdev->constraints)
@@ -1430,6 +1602,8 @@ static int _regulator_enable(struct regulator_dev *rdev)
                        }
 
                        trace_regulator_enable(rdev_get_name(rdev));
+                       _notifier_call_chain(
+                               rdev, REGULATOR_EVENT_PRE_ENABLE, NULL);
 
                        /* Allow the regulator to ramp; it would be useful
                         * to extend this for bulk operations so that the
@@ -1447,6 +1621,8 @@ static int _regulator_enable(struct regulator_dev *rdev)
                                udelay(delay);
                        }
 
+                       _notifier_call_chain(
+                               rdev, REGULATOR_EVENT_POST_ENABLE, NULL);
                        trace_regulator_enable_complete(rdev_get_name(rdev));
 
                } else if (ret < 0) {
@@ -1802,6 +1978,10 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
        max_uV += rdev->constraints->uV_offset;
 
        if (rdev->desc->ops->set_voltage) {
+               if (_regulator_is_enabled(rdev))
+                       _notifier_call_chain(rdev,
+                       REGULATOR_EVENT_OUT_PRECHANGE, (void *)min_uV);
+
                ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
                                                   &selector);
 
@@ -1842,11 +2022,19 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                        if (ret < 0)
                                return ret;
                        old_selector = ret;
-                       delay = rdev->desc->ops->set_voltage_time_sel(rdev,
+                       ret = rdev->desc->ops->set_voltage_time_sel(rdev,
                                                old_selector, selector);
+                       if (ret < 0)
+                               rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", ret);
+                       else
+                               delay = ret;
                }
 
                if (best_val != INT_MAX) {
+                       if (_regulator_is_enabled(rdev))
+                               _notifier_call_chain(rdev,
+                               REGULATOR_EVENT_OUT_PRECHANGE, (void *)best_val);
+
                        ret = rdev->desc->ops->set_voltage_sel(rdev, selector);
                        selector = best_val;
                } else {
@@ -1868,6 +2056,13 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
                                     NULL);
 
+       if (_regulator_is_enabled(rdev)) {
+               if (selector != -1)
+                       min_uV = selector;
+               _notifier_call_chain(rdev, REGULATOR_EVENT_OUT_POSTCHANGE,
+                                    (void *)min_uV);
+       }
+
        trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector);
 
        return ret;
@@ -2317,6 +2512,75 @@ out:
 EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
 
 /**
+ * regulator_set_control_mode - set regulator control mode
+ * @regulator: regulator source
+ * @mode: control mode - one of the REGULATOR_CONTROL_MODE constants
+ *
+ * Set regulator control mode to regulate the regulator output.
+ *
+ * NOTE: Regulator system constraints must be set for this regulator before
+ * calling this function otherwise this call will fail.
+ */
+int regulator_set_control_mode(struct regulator *regulator, unsigned int mode)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+       int ret;
+       int regulator_curr_mode;
+
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->set_control_mode) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* return if the same mode is requested */
+       if (rdev->desc->ops->get_control_mode) {
+               regulator_curr_mode = rdev->desc->ops->get_control_mode(rdev);
+               if (regulator_curr_mode == mode) {
+                       ret = 0;
+                       goto out;
+               }
+       }
+
+       /* constraints check */
+       ret = regulator_check_control(rdev);
+       if (ret < 0)
+               goto out;
+
+       ret = rdev->desc->ops->set_control_mode(rdev, mode);
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_control_mode);
+
+/**
+ * regulator_get_control_mode - get regulator control mode
+ * @regulator: regulator source
+ *
+ * Get the current regulator control mode.
+ */
+unsigned int regulator_get_control_mode(struct regulator *regulator)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+       int ret = -EINVAL;
+
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->get_control_mode)
+               goto out;
+
+       ret = rdev->desc->ops->get_control_mode(rdev);
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_get_control_mode);
+
+/**
  * regulator_register_notifier - register regulator event notifier
  * @regulator: regulator source
  * @nb: notifier block
@@ -2353,7 +2617,7 @@ static void _notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data)
 {
        /* call rdev chain first */
-       blocking_notifier_call_chain(&rdev->notifier, event, NULL);
+       blocking_notifier_call_chain(&rdev->notifier, event, data);
 }
 
 /**
@@ -2394,13 +2658,59 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
        return 0;
 
 err:
-       for (i = 0; i < num_consumers && consumers[i].consumer; i++)
+       while (--i >= 0)
                regulator_put(consumers[i].consumer);
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_bulk_get);
 
+/**
+ * devm_regulator_bulk_get - managed get multiple regulator consumers
+ *
+ * @dev:           Device to supply
+ * @num_consumers: Number of consumers to register
+ * @consumers:     Configuration of consumers; clients are stored here.
+ *
+ * @return 0 on success, an errno on failure.
+ *
+ * This helper function allows drivers to get several regulator
+ * consumers in one operation with management, the regulators will
+ * automatically be freed when the device is unbound.  If any of the
+ * regulators cannot be acquired then any regulators that were
+ * allocated will be freed before returning to the caller.
+ */
+int devm_regulator_bulk_get(struct device *dev, int num_consumers,
+                           struct regulator_bulk_data *consumers)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < num_consumers; i++)
+               consumers[i].consumer = NULL;
+
+       for (i = 0; i < num_consumers; i++) {
+               consumers[i].consumer = devm_regulator_get(dev,
+                                                          consumers[i].supply);
+               if (IS_ERR(consumers[i].consumer)) {
+                       ret = PTR_ERR(consumers[i].consumer);
+                       dev_err(dev, "Failed to get supply '%s': %d\n",
+                               consumers[i].supply, ret);
+                       consumers[i].consumer = NULL;
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       for (i = 0; i < num_consumers && consumers[i].consumer; i++)
+               devm_regulator_put(consumers[i].consumer);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_bulk_get);
+
 static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)
 {
        struct regulator_bulk_data *bulk = data;
@@ -2444,12 +2754,9 @@ int regulator_bulk_enable(int num_consumers,
        return 0;
 
 err:
-       for (i = 0; i < num_consumers; i++)
-               if (consumers[i].ret == 0)
-                       regulator_disable(consumers[i].consumer);
-               else
-                       pr_err("Failed to enable %s: %d\n",
-                              consumers[i].supply, consumers[i].ret);
+       pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret);
+       while (--i >= 0)
+               regulator_disable(consumers[i].consumer);
 
        return ret;
 }
@@ -2463,8 +2770,8 @@ EXPORT_SYMBOL_GPL(regulator_bulk_enable);
  * @return         0 on success, an errno on failure
  *
  * This convenience API allows consumers to disable multiple regulator
- * clients in a single API call.  If any consumers cannot be enabled
- * then any others that were disabled will be disabled again prior to
+ * clients in a single API call.  If any consumers cannot be disabled
+ * then any others that were disabled will be enabled again prior to
  * return.
  */
 int regulator_bulk_disable(int num_consumers,
@@ -2473,7 +2780,7 @@ int regulator_bulk_disable(int num_consumers,
        int i;
        int ret;
 
-       for (i = 0; i < num_consumers; i++) {
+       for (i = num_consumers - 1; i >= 0; --i) {
                ret = regulator_disable(consumers[i].consumer);
                if (ret != 0)
                        goto err;
@@ -2483,7 +2790,7 @@ int regulator_bulk_disable(int num_consumers,
 
 err:
        pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
-       for (--i; i >= 0; --i)
+       for (++i; i < num_consumers; ++i)
                regulator_enable(consumers[i].consumer);
 
        return ret;
@@ -2710,11 +3017,9 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
 
 static void rdev_init_debugfs(struct regulator_dev *rdev)
 {
-#ifdef CONFIG_DEBUG_FS
        rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root);
-       if (IS_ERR(rdev->debugfs) || !rdev->debugfs) {
+       if (!rdev->debugfs) {
                rdev_warn(rdev, "Failed to create debugfs directory\n");
-               rdev->debugfs = NULL;
                return;
        }
 
@@ -2722,7 +3027,6 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
                           &rdev->use_count);
        debugfs_create_u32("open_count", 0444, rdev->debugfs,
                           &rdev->open_count);
-#endif
 }
 
 /**
@@ -2731,7 +3035,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
  * @dev: struct device for the regulator
  * @init_data: platform provided init data, passed through by driver
  * @driver_data: private regulator data
- * @of_node: target open firmware device structure (may be NULL)
+ * @of_node: OpenFirmware node to parse for device tree bindings (may be
+ *           NULL).
  *
  * Called by regulator drivers to register a regulator.
  * Returns 0 on success.
@@ -2823,17 +3128,18 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
 
        if (init_data && init_data->supply_regulator)
                supply = init_data->supply_regulator;
+#if 0 /* Reenable when EPROBE_DEFER is pulled. */
        else if (regulator_desc->supply_name)
                supply = regulator_desc->supply_name;
+#endif
 
        if (supply) {
                struct regulator_dev *r;
 
                r = regulator_dev_lookup(dev, supply);
-
                if (!r) {
                        dev_err(dev, "Failed to find supply %s\n", supply);
-                       ret = -ENODEV;
+                       ret = -EPROBE_DEFER;
                        goto scrub;
                }
 
@@ -2854,7 +3160,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        if (init_data) {
                for (i = 0; i < init_data->num_consumer_supplies; i++) {
                        ret = set_consumer_device_supply(rdev,
-                               init_data->consumer_supplies[i].dev,
                                init_data->consumer_supplies[i].dev_name,
                                init_data->consumer_supplies[i].supply);
                        if (ret < 0) {
@@ -2876,6 +3181,8 @@ unset_supplies:
        unset_regulator_supplies(rdev);
 
 scrub:
+       if (rdev->supply)
+               regulator_put(rdev->supply);
        kfree(rdev->constraints);
        device_unregister(&rdev->dev);
        /* device core frees rdev */
@@ -2900,16 +3207,14 @@ void regulator_unregister(struct regulator_dev *rdev)
        if (rdev == NULL)
                return;
 
+       if (rdev->supply)
+               regulator_put(rdev->supply);
        mutex_lock(&regulator_list_mutex);
-#ifdef CONFIG_DEBUG_FS
        debugfs_remove_recursive(rdev->debugfs);
-#endif
        flush_work_sync(&rdev->disable_work.work);
        WARN_ON(rdev->open_count);
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
-       if (rdev->supply)
-               regulator_put(rdev->supply);
        kfree(rdev->constraints);
        device_unregister(&rdev->dev);
        mutex_unlock(&regulator_list_mutex);
@@ -3113,12 +3418,14 @@ static ssize_t supply_map_read_file(struct file *file, char __user *user_buf,
 
        return ret;
 }
+#endif
 
 static const struct file_operations supply_map_fops = {
+#ifdef CONFIG_DEBUG_FS
        .read = supply_map_read_file,
        .llseek = default_llseek,
-};
 #endif
+};
 
 static int __init regulator_init(void)
 {
@@ -3126,17 +3433,12 @@ static int __init regulator_init(void)
 
        ret = class_register(&regulator_class);
 
-#ifdef CONFIG_DEBUG_FS
        debugfs_root = debugfs_create_dir("regulator", NULL);
-       if (IS_ERR(debugfs_root) || !debugfs_root) {
+       if (!debugfs_root)
                pr_warn("regulator: Failed to create debugfs directory\n");
-               debugfs_root = NULL;
-       }
 
-       if (IS_ERR(debugfs_create_file("supply_map", 0444, debugfs_root,
-                                      NULL, &supply_map_fops)))
-               pr_warn("regulator: Failed to create supplies debugfs\n");
-#endif
+       debugfs_create_file("supply_map", 0444, debugfs_root, NULL,
+                           &supply_map_fops);
 
        regulator_dummy_init();
 
@@ -3205,4 +3507,59 @@ unlock:
 
        return 0;
 }
+
+#ifdef CONFIG_DEBUG_FS
+static int regulator_syncevent(struct file *file, const char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct regulator_dev *rdev;
+       char buffer[40];
+       int buf_size;
+
+       memset(buffer, 0, sizeof(buffer));
+       buf_size = min(count, (sizeof(buffer)-1));
+
+       if (copy_from_user(buffer, user_buf, buf_size))
+               return -EFAULT;
+
+       if (!strnicmp("all", buffer, 3)) {
+
+               mutex_lock(&regulator_list_mutex);
+
+               list_for_each_entry(rdev, &regulator_list, list) {
+                       mutex_lock(&rdev->mutex);
+
+                       if (_regulator_is_enabled(rdev))
+                               trace_regulator_enable(rdev_get_name(rdev));
+                       else
+                               trace_regulator_disable(rdev_get_name(rdev));
+
+                       trace_regulator_set_voltage(rdev_get_name(rdev),
+                               _regulator_get_voltage(rdev),
+                               _regulator_get_voltage(rdev));
+
+                       mutex_unlock(&rdev->mutex);
+               }
+       }
+
+       mutex_unlock(&regulator_list_mutex);
+
+       return count;
+}
+
+static const struct file_operations regulator_syncevent_fops = {
+       .write          = regulator_syncevent,
+};
+
+static int __init regulator_init_debugfs(void)
+{
+       debugfs_create_file("syncevent_regulators", S_IWUSR, NULL, NULL,
+                       &regulator_syncevent_fops);
+
+       return 0;
+}
+
+late_initcall(regulator_init_debugfs);
+#endif
+
 late_initcall(regulator_init_complete);