regulator: Remove ifdefs for debugfs code
[pandora-kernel.git] / drivers / regulator / core.c
index 938398f..603e39f 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>
@@ -25,6 +23,8 @@
 #include <linux/mutex.h>
 #include <linux/suspend.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
@@ -52,9 +52,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
@@ -82,9 +80,7 @@ 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);
@@ -132,6 +128,33 @@ static struct regulator *get_device_regulator(struct device *dev)
        return NULL;
 }
 
+/**
+ * of_get_regulator - get a regulator device node based on supply name
+ * @dev: Device pointer for the consumer (of regulator) device
+ * @supply: regulator supply name
+ *
+ * Extract the regulator device node corresponding to the supply name.
+ * retruns the device node corresponding to the regulator if found, else
+ * returns NULL.
+ */
+static struct device_node *of_get_regulator(struct device *dev, const char *supply)
+{
+       struct device_node *regnode = NULL;
+       char prop_name[32]; /* 32 is max size of property name */
+
+       dev_dbg(dev, "Looking up %s-supply from device tree\n", supply);
+
+       snprintf(prop_name, 32, "%s-supply", supply);
+       regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+       if (!regnode) {
+               dev_warn(dev, "%s property in node %s references invalid phandle",
+                               prop_name, dev->of_node->full_name);
+               return NULL;
+       }
+       return regnode;
+}
+
 /* Platform voltage constraint check */
 static int regulator_check_voltage(struct regulator_dev *rdev,
                                   int *min_uV, int *max_uV)
@@ -778,6 +801,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,
@@ -883,8 +911,12 @@ static int set_machine_constraints(struct regulator_dev *rdev,
        int ret = 0;
        struct regulator_ops *ops = rdev->desc->ops;
 
-       rdev->constraints = kmemdup(constraints, sizeof(*constraints),
-                                   GFP_KERNEL);
+       if (constraints)
+               rdev->constraints = kmemdup(constraints, sizeof(*constraints),
+                                           GFP_KERNEL);
+       else
+               rdev->constraints = kzalloc(sizeof(*constraints),
+                                           GFP_KERNEL);
        if (!rdev->constraints)
                return -ENOMEM;
 
@@ -893,7 +925,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                goto out;
 
        /* do we need to setup our suspend state */
-       if (constraints->initial_state) {
+       if (rdev->constraints->initial_state) {
                ret = suspend_prepare(rdev, rdev->constraints->initial_state);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set suspend state\n");
@@ -901,7 +933,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                }
        }
 
-       if (constraints->initial_mode) {
+       if (rdev->constraints->initial_mode) {
                if (!ops->set_mode) {
                        rdev_err(rdev, "no set_mode operation\n");
                        ret = -EINVAL;
@@ -952,9 +984,8 @@ static int set_supply(struct regulator_dev *rdev,
        rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev));
 
        rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY");
-       if (IS_ERR(rdev->supply)) {
-               err = PTR_ERR(rdev->supply);
-               rdev->supply = NULL;
+       if (rdev->supply == NULL) {
+               err = -ENOMEM;
                return err;
        }
 
@@ -1110,12 +1141,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);
@@ -1124,7 +1153,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;
@@ -1148,6 +1176,30 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev)
        return rdev->desc->ops->enable_time(rdev);
 }
 
+static struct regulator_dev *regulator_dev_lookup(struct device *dev,
+                                                        const char *supply)
+{
+       struct regulator_dev *r;
+       struct device_node *node;
+
+       /* first do a dt based lookup */
+       if (dev && dev->of_node) {
+               node = of_get_regulator(dev, supply);
+               if (node)
+                       list_for_each_entry(r, &regulator_list, list)
+                               if (r->dev.parent &&
+                                       node == r->dev.of_node)
+                                       return r;
+       }
+
+       /* if not found, try doing it non-dt way */
+       list_for_each_entry(r, &regulator_list, list)
+               if (strcmp(rdev_get_name(r), supply) == 0)
+                       return r;
+
+       return NULL;
+}
+
 /* Internal regulator request function */
 static struct regulator *_regulator_get(struct device *dev, const char *id,
                                        int exclusive)
@@ -1168,6 +1220,10 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
 
        mutex_lock(&regulator_list_mutex);
 
+       rdev = regulator_dev_lookup(dev, id);
+       if (rdev)
+               goto found;
+
        list_for_each_entry(map, &regulator_map_list, list) {
                /* If the mapping has a device set up it must match */
                if (map->dev_name &&
@@ -1221,6 +1277,7 @@ found:
        if (regulator == NULL) {
                regulator = ERR_PTR(-ENOMEM);
                module_put(rdev->owner);
+               goto out;
        }
 
        rdev->open_count++;
@@ -1304,9 +1361,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) {
@@ -1726,6 +1781,7 @@ int regulator_is_supported_voltage(struct regulator *regulator,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
 
 static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                                     int min_uV, int max_uV)
@@ -2332,7 +2388,7 @@ 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;
@@ -2382,12 +2438,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;
 }
@@ -2401,8 +2454,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,
@@ -2411,7 +2464,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;
@@ -2421,13 +2474,50 @@ 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;
 }
 EXPORT_SYMBOL_GPL(regulator_bulk_disable);
 
+/**
+ * regulator_bulk_force_disable - force disable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers:     Consumer data; clients are stored here.
+ * @return         0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to forcibly disable multiple regulator
+ * clients in a single API call.
+ * NOTE: This should be used for situations when device damage will
+ * likely occur if the regulators are not disabled (e.g. over temp).
+ * Although regulator_force_disable function call for some consumers can
+ * return error numbers, the function is called for all consumers.
+ */
+int regulator_bulk_force_disable(int num_consumers,
+                          struct regulator_bulk_data *consumers)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < num_consumers; i++)
+               consumers[i].ret =
+                           regulator_force_disable(consumers[i].consumer);
+
+       for (i = 0; i < num_consumers; i++) {
+               if (consumers[i].ret != 0) {
+                       ret = consumers[i].ret;
+                       goto out;
+               }
+       }
+
+       return 0;
+out:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_force_disable);
+
 /**
  * regulator_bulk_free - free multiple regulator consumers
  *
@@ -2503,7 +2593,8 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
        int                     status = 0;
 
        /* some attributes need specific methods to be displayed */
-       if (ops->get_voltage || ops->get_voltage_sel) {
+       if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
+           (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0)) {
                status = device_create_file(dev, &dev_attr_microvolts);
                if (status < 0)
                        return status;
@@ -2610,11 +2701,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;
        }
 
@@ -2622,7 +2711,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
 }
 
 /**
@@ -2637,11 +2725,13 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
  */
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        struct device *dev, const struct regulator_init_data *init_data,
-       void *driver_data)
+       void *driver_data, struct device_node *of_node)
 {
+       const struct regulation_constraints *constraints = NULL;
        static atomic_t regulator_no = ATOMIC_INIT(0);
        struct regulator_dev *rdev;
        int ret, i;
+       const char *supply = NULL;
 
        if (regulator_desc == NULL)
                return ERR_PTR(-EINVAL);
@@ -2653,9 +2743,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
            regulator_desc->type != REGULATOR_CURRENT)
                return ERR_PTR(-EINVAL);
 
-       if (!init_data)
-               return ERR_PTR(-EINVAL);
-
        /* Only one of each should be implemented */
        WARN_ON(regulator_desc->ops->get_voltage &&
                regulator_desc->ops->get_voltage_sel);
@@ -2688,7 +2775,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
 
        /* preform any regulator specific init */
-       if (init_data->regulator_init) {
+       if (init_data && init_data->regulator_init) {
                ret = init_data->regulator_init(rdev->reg_data);
                if (ret < 0)
                        goto clean;
@@ -2696,6 +2783,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
 
        /* register with sysfs */
        rdev->dev.class = &regulator_class;
+       rdev->dev.of_node = of_node;
        rdev->dev.parent = dev;
        dev_set_name(&rdev->dev, "regulator.%d",
                     atomic_inc_return(&regulator_no) - 1);
@@ -2708,7 +2796,10 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        dev_set_drvdata(&rdev->dev, rdev);
 
        /* set regulator constraints */
-       ret = set_machine_constraints(rdev, &init_data->constraints);
+       if (init_data)
+               constraints = &init_data->constraints;
+
+       ret = set_machine_constraints(rdev, constraints);
        if (ret < 0)
                goto scrub;
 
@@ -2717,21 +2808,18 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        if (ret < 0)
                goto scrub;
 
-       if (init_data->supply_regulator) {
+       if (init_data && init_data->supply_regulator)
+               supply = init_data->supply_regulator;
+       else if (regulator_desc->supply_name)
+               supply = regulator_desc->supply_name;
+
+       if (supply) {
                struct regulator_dev *r;
-               int found = 0;
 
-               list_for_each_entry(r, &regulator_list, list) {
-                       if (strcmp(rdev_get_name(r),
-                                  init_data->supply_regulator) == 0) {
-                               found = 1;
-                               break;
-                       }
-               }
+               r = regulator_dev_lookup(dev, supply);
 
-               if (!found) {
-                       dev_err(dev, "Failed to find supply %s\n",
-                               init_data->supply_regulator);
+               if (!r) {
+                       dev_err(dev, "Failed to find supply %s\n", supply);
                        ret = -ENODEV;
                        goto scrub;
                }
@@ -2739,18 +2827,28 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
                ret = set_supply(rdev, r);
                if (ret < 0)
                        goto scrub;
+
+               /* Enable supply if rail is enabled */
+               if (rdev->desc->ops->is_enabled &&
+                               rdev->desc->ops->is_enabled(rdev)) {
+                       ret = regulator_enable(rdev->supply);
+                       if (ret < 0)
+                               goto scrub;
+               }
        }
 
        /* add consumers devices */
-       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) {
-                       dev_err(dev, "Failed to set supply %s\n",
+       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);
-                       goto unset_supplies;
+                       if (ret < 0) {
+                               dev_err(dev, "Failed to set supply %s\n",
+                                       init_data->consumer_supplies[i].supply);
+                               goto unset_supplies;
+                       }
                }
        }
 
@@ -2790,9 +2888,7 @@ void regulator_unregister(struct regulator_dev *rdev)
                return;
 
        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);
@@ -3002,12 +3098,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)
 {
@@ -3015,17 +3113,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();