From 812460a927c1d0dc1fbdbec9aa07de1b04043d83 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 2 Nov 2008 03:55:10 +0100 Subject: [PATCH 01/16] regulator: struct device - replace bus_id with dev_name(), dev_set_name() This patch is part of a larger patch series which will remove the "char bus_id[20]" name string from struct device. The device name is managed in the kobject anyway, and without any size limitation, and just needlessly copied into "struct device". To set and read the device name dev_name(dev) and dev_set_name(dev) must be used. If your code uses static kobjects, which it shouldn't do, "const char *init_name" can be used to statically provide the name the registered device should have. At registration time, the init_name field is cleared, to enforce the use of dev_name(dev) to access the device name at a later time. We need to get rid of all occurrences of bus_id in the entire tree to be able to enable the new interface. Please apply this patch, and possibly convert any remaining remaining occurrences of bus_id. We want to submit a patch to -next, which will remove bus_id from "struct device", to find the remaining pieces to convert, and finally switch over to the new api, which will remove the 20 bytes array and does no longer have a size limitation. Thanks, Kay From: Kay Sievers Subject: regulator: struct device - replace bus_id with dev_name(), dev_set_name() Cc: Liam Girdwood Acked-by: Greg Kroah-Hartman Signed-Off-By: Kay Sievers Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 02a774424e8..9a644d41b81 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1779,8 +1779,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; rdev->dev.parent = dev; - snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id), - "regulator.%d", atomic_inc_return(®ulator_no) - 1); + dev_set_name(&rdev->dev, "regulator.%d", + atomic_inc_return(®ulator_no) - 1); ret = device_register(&rdev->dev); if (ret != 0) { kfree(rdev); From 412aec610559bdb602a0a21ce149ba8ffbb6f983 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 16 Nov 2008 11:44:46 -0800 Subject: [PATCH 02/16] regulator: enable/disable refcounting Make the framework treat enable/disable call pairs like the and frameworks do: they're refcounted, so that different parts of a driver don't need to put work into coordination that frameworks normally handle. It's a minor object code shrink. It also makes the regulator_is_disabled() kerneldoc say what it's actually returning: return value is not a refcount, and may report an error (e.g. I/O error from I2C). It also fixes some minor regulator_put() goofage: removing unlocked access to the enable state. (But still not making regulator put/get match the refcounting pattern they invoke.) Signed-off-by: David Brownell Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 71 ++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9a644d41b81..c2b7ec90103 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -79,7 +79,7 @@ struct regulator { int uA_load; int min_uV; int max_uV; - int enabled; /* client has called enabled */ + int enabled; /* count of client enables */ char *supply_name; struct device_attribute dev_attr; struct regulator_dev *rdev; @@ -963,16 +963,13 @@ void regulator_put(struct regulator *regulator) if (regulator == NULL || IS_ERR(regulator)) return; - if (regulator->enabled) { - printk(KERN_WARNING "Releasing supply %s while enabled\n", - regulator->supply_name); - WARN_ON(regulator->enabled); - regulator_disable(regulator); - } - mutex_lock(®ulator_list_mutex); rdev = regulator->rdev; + if (WARN(regulator->enabled, "Releasing supply %s while enabled\n", + regulator->supply_name)) + _regulator_disable(rdev); + /* remove any sysfs entries */ if (regulator->dev) { sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); @@ -1042,21 +1039,17 @@ static int _regulator_enable(struct regulator_dev *rdev) */ int regulator_enable(struct regulator *regulator) { - int ret; + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; - if (regulator->enabled) { - printk(KERN_CRIT "Regulator %s already enabled\n", - regulator->supply_name); - WARN_ON(regulator->enabled); - return 0; - } - - mutex_lock(®ulator->rdev->mutex); - regulator->enabled = 1; - ret = _regulator_enable(regulator->rdev); - if (ret != 0) - regulator->enabled = 0; - mutex_unlock(®ulator->rdev->mutex); + mutex_lock(&rdev->mutex); + if (regulator->enabled == 0) + ret = _regulator_enable(rdev); + else if (regulator->enabled < 0) + ret = -EIO; + if (ret == 0) + regulator->enabled++; + mutex_unlock(&rdev->mutex); return ret; } EXPORT_SYMBOL_GPL(regulator_enable); @@ -1108,19 +1101,21 @@ static int _regulator_disable(struct regulator_dev *rdev) */ int regulator_disable(struct regulator *regulator) { - int ret; + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; - if (!regulator->enabled) { - printk(KERN_ERR "%s: not in use by this consumer\n", - __func__); - return 0; - } - - mutex_lock(®ulator->rdev->mutex); - regulator->enabled = 0; - regulator->uA_load = 0; - ret = _regulator_disable(regulator->rdev); - mutex_unlock(®ulator->rdev->mutex); + mutex_lock(&rdev->mutex); + if (regulator->enabled == 1) { + ret = _regulator_disable(rdev); + if (ret == 0) + regulator->uA_load = 0; + } else if (WARN(regulator->enabled <= 0, + "unbalanced disables for supply %s\n", + regulator->supply_name)) + ret = -EIO; + if (ret == 0) + regulator->enabled--; + mutex_unlock(&rdev->mutex); return ret; } EXPORT_SYMBOL_GPL(regulator_disable); @@ -1196,7 +1191,13 @@ out: * regulator_is_enabled - is the regulator output enabled * @regulator: regulator source * - * Returns zero for disabled otherwise return number of enable requests. + * Returns positive if the regulator driver backing the source/client + * has requested that the device be enabled, zero if it hasn't, else a + * negative errno code. + * + * Note that the device backing this regulator handle can have multiple + * users, so it might be enabled even if regulator_enable() was never + * called for this particular source. */ int regulator_is_enabled(struct regulator *regulator) { From e573520b171095c106ffbbbf4f9cbed6d9bff576 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 16 Nov 2008 11:46:56 -0800 Subject: [PATCH 03/16] regulator: improved mode error checks Minor bugfixes in handling of regulator modes: - have the routine verifying regulator modes check against the set of legal modes (!); - have regulator_set_optimum_mode() verify the return value of regulator_ops.get_optimum_mode(), like drms_uA_update(); - one call to regulator_ops.set_mode() treated zero as a failure code; make this consistent with other callers. Both regulator_set_mode() and regulator_set_optimum_mode() now require valid_ops_mask to include REGULATOR_CHANGE_MODE; that seems like a bugfix too. Signed-off-by: David Brownell Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c2b7ec90103..686dfa99072 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -174,6 +174,16 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, /* operating mode constraint check */ static int regulator_check_mode(struct regulator_dev *rdev, int mode) { + switch (mode) { + case REGULATOR_MODE_FAST: + case REGULATOR_MODE_NORMAL: + case REGULATOR_MODE_IDLE: + case REGULATOR_MODE_STANDBY: + break; + default: + return -EINVAL; + } + if (!rdev->constraints) { printk(KERN_ERR "%s: no constraints for %s\n", __func__, rdev->desc->name); @@ -1494,7 +1504,8 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, output_uV, total_uA_load); - if (ret <= 0) { + ret = regulator_check_mode(rdev, mode); + if (ret < 0) { printk(KERN_ERR "%s: failed to get optimum mode for %s @" " %d uA %d -> %d uV\n", __func__, rdev->desc->name, total_uA_load, input_uV, output_uV); @@ -1502,7 +1513,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) } ret = rdev->desc->ops->set_mode(rdev, mode); - if (ret <= 0) { + if (ret < 0) { printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n", __func__, mode, rdev->desc->name); goto out; From 4fca9545d17b99cdb2774716b034c62a70151bcd Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 11 Nov 2008 17:38:53 -0800 Subject: [PATCH 04/16] regulator: code shrink (v2) Shrink regulator core by removing duplication in attribute printing and probe() cleanup paths. Saves about 340 bytes (object) on ARM. Signed-off-by: David Brownell Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 111 ++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 67 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 686dfa99072..5109f7d4809 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -267,12 +267,8 @@ static ssize_t regulator_name_show(struct device *dev, return sprintf(buf, "%s\n", name); } -static ssize_t regulator_opmode_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t regulator_print_opmode(char *buf, int mode) { - struct regulator_dev *rdev = dev_get_drvdata(dev); - int mode = _regulator_get_mode(rdev); - switch (mode) { case REGULATOR_MODE_FAST: return sprintf(buf, "fast\n"); @@ -286,12 +282,16 @@ static ssize_t regulator_opmode_show(struct device *dev, return sprintf(buf, "unknown\n"); } -static ssize_t regulator_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t regulator_opmode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - int state = _regulator_is_enabled(rdev); + return regulator_print_opmode(buf, _regulator_get_mode(rdev)); +} + +static ssize_t regulator_print_state(char *buf, int state) +{ if (state > 0) return sprintf(buf, "enabled\n"); else if (state == 0) @@ -300,6 +300,14 @@ static ssize_t regulator_state_show(struct device *dev, return sprintf(buf, "unknown\n"); } +static ssize_t regulator_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + + return regulator_print_state(buf, _regulator_is_enabled(rdev)); +} + static ssize_t regulator_min_uA_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -409,22 +417,6 @@ static ssize_t regulator_suspend_standby_uV_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); } -static ssize_t suspend_opmode_show(struct regulator_dev *rdev, - unsigned int mode, char *buf) -{ - 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_suspend_mem_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -432,8 +424,8 @@ static ssize_t regulator_suspend_mem_mode_show(struct device *dev, if (!rdev->constraints) return sprintf(buf, "not defined\n"); - return suspend_opmode_show(rdev, - rdev->constraints->state_mem.mode, buf); + return regulator_print_opmode(buf, + rdev->constraints->state_mem.mode); } static ssize_t regulator_suspend_disk_mode_show(struct device *dev, @@ -443,8 +435,8 @@ static ssize_t regulator_suspend_disk_mode_show(struct device *dev, if (!rdev->constraints) return sprintf(buf, "not defined\n"); - return suspend_opmode_show(rdev, - rdev->constraints->state_disk.mode, buf); + return regulator_print_opmode(buf, + rdev->constraints->state_disk.mode); } static ssize_t regulator_suspend_standby_mode_show(struct device *dev, @@ -454,8 +446,8 @@ static ssize_t regulator_suspend_standby_mode_show(struct device *dev, if (!rdev->constraints) return sprintf(buf, "not defined\n"); - return suspend_opmode_show(rdev, - rdev->constraints->state_standby.mode, buf); + return regulator_print_opmode(buf, + rdev->constraints->state_standby.mode); } static ssize_t regulator_suspend_mem_state_show(struct device *dev, @@ -466,10 +458,8 @@ static ssize_t regulator_suspend_mem_state_show(struct device *dev, if (!rdev->constraints) return sprintf(buf, "not defined\n"); - if (rdev->constraints->state_mem.enabled) - return sprintf(buf, "enabled\n"); - else - return sprintf(buf, "disabled\n"); + return regulator_print_state(buf, + rdev->constraints->state_mem.enabled); } static ssize_t regulator_suspend_disk_state_show(struct device *dev, @@ -480,10 +470,8 @@ static ssize_t regulator_suspend_disk_state_show(struct device *dev, if (!rdev->constraints) return sprintf(buf, "not defined\n"); - if (rdev->constraints->state_disk.enabled) - return sprintf(buf, "enabled\n"); - else - return sprintf(buf, "disabled\n"); + return regulator_print_state(buf, + rdev->constraints->state_disk.enabled); } static ssize_t regulator_suspend_standby_state_show(struct device *dev, @@ -494,10 +482,8 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev, if (!rdev->constraints) return sprintf(buf, "not defined\n"); - if (rdev->constraints->state_standby.enabled) - return sprintf(buf, "enabled\n"); - else - return sprintf(buf, "disabled\n"); + return regulator_print_state(buf, + rdev->constraints->state_standby.enabled); } static struct device_attribute regulator_dev_attrs[] = { @@ -1773,20 +1759,14 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, /* preform any regulator specific init */ if (init_data->regulator_init) { ret = init_data->regulator_init(rdev->reg_data); - if (ret < 0) { - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; - } + if (ret < 0) + goto clean; } /* set regulator constraints */ ret = set_machine_constraints(rdev, &init_data->constraints); - if (ret < 0) { - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; - } + if (ret < 0) + goto clean; /* register with sysfs */ rdev->dev.class = ®ulator_class; @@ -1794,11 +1774,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, dev_set_name(&rdev->dev, "regulator.%d", atomic_inc_return(®ulator_no) - 1); ret = device_register(&rdev->dev); - if (ret != 0) { - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; - } + if (ret != 0) + goto clean; dev_set_drvdata(&rdev->dev, rdev); @@ -1806,12 +1783,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (init_data->supply_regulator_dev) { ret = set_supply(rdev, dev_get_drvdata(init_data->supply_regulator_dev)); - if (ret < 0) { - device_unregister(&rdev->dev); - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; - } + if (ret < 0) + goto scrub; } /* add consumers devices */ @@ -1823,10 +1796,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, for (--i; i >= 0; i--) unset_consumer_device_supply(rdev, init_data->consumer_supplies[i].dev); - device_unregister(&rdev->dev); - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; + goto scrub; } } @@ -1834,6 +1804,13 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, out: mutex_unlock(®ulator_list_mutex); return rdev; + +scrub: + device_unregister(&rdev->dev); +clean: + kfree(rdev); + rdev = ERR_PTR(ret); + goto out; } EXPORT_SYMBOL_GPL(regulator_register); From 7ad68e2f970fd84d15ad67ce3216aed05f944a9c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 11 Nov 2008 17:39:02 -0800 Subject: [PATCH 05/16] regulator: sysfs attribute reduction (v2) Clean up the sysfs interface to regulators by only exposing the attributes that can be properly displayed. For example: when a particular regulator method is needed to display the value, only create that attribute when that method exists. This cleaned-up interface is much more comprehensible. Most regulators only support a subset of the possible methods, so often more than half the attributes would be meaningless. Many "not defined" values are no longer necessary. (But handling of out-of-range values still looks a bit iffy.) Documentation is updated to reflect that few of the attributes are *always* present, and to briefly explain why a regulator may not have a given attribute. This adds object code, about a dozen bytes more than was removed by the preceding patch, but saves a bunch of per-regulator data associated with the now-removed attributes. So there's a net reduction in memory footprint. Signed-off-by: David Brownell Signed-off-by: Liam Girdwood --- .../ABI/testing/sysfs-class-regulator | 136 ++++++------ drivers/regulator/core.c | 196 +++++++++++++----- 2 files changed, 208 insertions(+), 124 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator index 3731f6f29bc..873ef1fc156 100644 --- a/Documentation/ABI/testing/sysfs-class-regulator +++ b/Documentation/ABI/testing/sysfs-class-regulator @@ -3,8 +3,9 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called - state. This holds the regulator output state. + Some regulator directories will contain a field called + state. This reports the regulator enable status, for + regulators which can report that value. This will be one of the following strings: @@ -18,7 +19,8 @@ Description: 'disabled' means the regulator output is OFF and is not supplying power to the system.. - 'unknown' means software cannot determine the state. + 'unknown' means software cannot determine the state, or + the reported state is invalid. NOTE: this field can be used in conjunction with microvolts and microamps to determine regulator output levels. @@ -53,9 +55,10 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called microvolts. This holds the regulator output voltage setting - measured in microvolts (i.e. E-6 Volts). + measured in microvolts (i.e. E-6 Volts), for regulators + which can report that voltage. NOTE: This value should not be used to determine the regulator output voltage level as this value is the same regardless of @@ -67,9 +70,10 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called microamps. This holds the regulator output current limit - setting measured in microamps (i.e. E-6 Amps). + setting measured in microamps (i.e. E-6 Amps), for regulators + which can report that current. NOTE: This value should not be used to determine the regulator output current level as this value is the same regardless of @@ -81,8 +85,9 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called - opmode. This holds the regulator operating mode setting. + Some regulator directories will contain a field called + opmode. This holds the current regulator operating mode, + for regulators which can report it. The opmode value can be one of the following strings: @@ -92,7 +97,7 @@ Description: 'standby' 'unknown' - The modes are described in include/linux/regulator/regulator.h + The modes are described in include/linux/regulator/consumer.h NOTE: This value should not be used to determine the regulator output operating mode as this value is the same regardless of @@ -104,9 +109,10 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called min_microvolts. This holds the minimum safe working regulator - output voltage setting for this domain measured in microvolts. + output voltage setting for this domain measured in microvolts, + for regulators which support voltage constraints. NOTE: this will return the string 'constraint not defined' if the power domain has no min microvolts constraint defined by @@ -118,9 +124,10 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called max_microvolts. This holds the maximum safe working regulator - output voltage setting for this domain measured in microvolts. + output voltage setting for this domain measured in microvolts, + for regulators which support voltage constraints. NOTE: this will return the string 'constraint not defined' if the power domain has no max microvolts constraint defined by @@ -132,10 +139,10 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called min_microamps. This holds the minimum safe working regulator output current limit setting for this domain measured in - microamps. + microamps, for regulators which support current constraints. NOTE: this will return the string 'constraint not defined' if the power domain has no min microamps constraint defined by @@ -147,10 +154,10 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called max_microamps. This holds the maximum safe working regulator output current limit setting for this domain measured in - microamps. + microamps, for regulators which support current constraints. NOTE: this will return the string 'constraint not defined' if the power domain has no max microamps constraint defined by @@ -185,7 +192,7 @@ Date: April 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called requested_microamps. This holds the total requested load current in microamps for this regulator from all its consumer devices. @@ -204,125 +211,102 @@ Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_mem_microvolts. This holds the regulator output voltage setting for this domain measured in microvolts when - the system is suspended to memory. - - NOTE: this will return the string 'not defined' if - the power domain has no suspend to memory voltage defined by - platform code. + the system is suspended to memory, for voltage regulators + implementing suspend voltage configuration constraints. What: /sys/class/regulator/.../suspend_disk_microvolts Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_disk_microvolts. This holds the regulator output voltage setting for this domain measured in microvolts when - the system is suspended to disk. - - NOTE: this will return the string 'not defined' if - the power domain has no suspend to disk voltage defined by - platform code. + the system is suspended to disk, for voltage regulators + implementing suspend voltage configuration constraints. What: /sys/class/regulator/.../suspend_standby_microvolts Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_standby_microvolts. This holds the regulator output voltage setting for this domain measured in microvolts when - the system is suspended to standby. - - NOTE: this will return the string 'not defined' if - the power domain has no suspend to standby voltage defined by - platform code. + the system is suspended to standby, for voltage regulators + implementing suspend voltage configuration constraints. What: /sys/class/regulator/.../suspend_mem_mode Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_mem_mode. This holds the regulator operating mode setting for this domain when the system is suspended to - memory. - - NOTE: this will return the string 'not defined' if - the power domain has no suspend to memory mode defined by - platform code. + memory, for regulators implementing suspend mode + configuration constraints. What: /sys/class/regulator/.../suspend_disk_mode Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_disk_mode. This holds the regulator operating mode - setting for this domain when the system is suspended to disk. - - NOTE: this will return the string 'not defined' if - the power domain has no suspend to disk mode defined by - platform code. + setting for this domain when the system is suspended to disk, + for regulators implementing suspend mode configuration + constraints. What: /sys/class/regulator/.../suspend_standby_mode Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_standby_mode. This holds the regulator operating mode setting for this domain when the system is suspended to - standby. - - NOTE: this will return the string 'not defined' if - the power domain has no suspend to standby mode defined by - platform code. + standby, for regulators implementing suspend mode + configuration constraints. What: /sys/class/regulator/.../suspend_mem_state Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_mem_state. This holds the regulator operating state - when suspended to memory. + when suspended to memory, for regulators implementing suspend + configuration constraints. - This will be one of the following strings: - - 'enabled' - 'disabled' - 'not defined' + This will be one of the same strings reported by + the "state" attribute. What: /sys/class/regulator/.../suspend_disk_state Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_disk_state. This holds the regulator operating state - when suspended to disk. + when suspended to disk, for regulators implementing + suspend configuration constraints. - This will be one of the following strings: - - 'enabled' - 'disabled' - 'not defined' + This will be one of the same strings reported by + the "state" attribute. What: /sys/class/regulator/.../suspend_standby_state Date: May 2008 KernelVersion: 2.6.26 Contact: Liam Girdwood Description: - Each regulator directory will contain a field called + Some regulator directories will contain a field called suspend_standby_state. This holds the regulator operating - state when suspended to standby. + state when suspended to standby, for regulators implementing + suspend configuration constraints. - This will be one of the following strings: - - 'enabled' - 'disabled' - 'not defined' + This will be one of the same strings reported by + the "state" attribute. diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5109f7d4809..9a5ff97d158 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -242,6 +242,7 @@ static ssize_t regulator_uV_show(struct device *dev, return ret; } +static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL); static ssize_t regulator_uA_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -250,6 +251,7 @@ static ssize_t regulator_uA_show(struct device *dev, return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev)); } +static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL); static ssize_t regulator_name_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -289,6 +291,7 @@ static ssize_t regulator_opmode_show(struct device *dev, return regulator_print_opmode(buf, _regulator_get_mode(rdev)); } +static DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL); static ssize_t regulator_print_state(char *buf, int state) { @@ -307,6 +310,7 @@ static ssize_t regulator_state_show(struct device *dev, return regulator_print_state(buf, _regulator_is_enabled(rdev)); } +static DEVICE_ATTR(state, 0444, regulator_state_show, NULL); static ssize_t regulator_min_uA_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -318,6 +322,7 @@ static ssize_t regulator_min_uA_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->min_uA); } +static DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL); static ssize_t regulator_max_uA_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -329,6 +334,7 @@ static ssize_t regulator_max_uA_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->max_uA); } +static DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL); static ssize_t regulator_min_uV_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -340,6 +346,7 @@ static ssize_t regulator_min_uV_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->min_uV); } +static DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL); static ssize_t regulator_max_uV_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -351,6 +358,7 @@ static ssize_t regulator_max_uV_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->max_uV); } +static DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL); static ssize_t regulator_total_uA_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -365,6 +373,7 @@ static ssize_t regulator_total_uA_show(struct device *dev, mutex_unlock(&rdev->mutex); return sprintf(buf, "%d\n", uA); } +static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL); static ssize_t regulator_num_users_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -392,131 +401,106 @@ static ssize_t regulator_suspend_mem_uV_show(struct device *dev, { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV); } +static DEVICE_ATTR(suspend_mem_microvolts, 0444, + regulator_suspend_mem_uV_show, NULL); static ssize_t regulator_suspend_disk_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV); } +static DEVICE_ATTR(suspend_disk_microvolts, 0444, + regulator_suspend_disk_uV_show, NULL); static ssize_t regulator_suspend_standby_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); } +static DEVICE_ATTR(suspend_standby_microvolts, 0444, + regulator_suspend_standby_uV_show, NULL); static ssize_t regulator_suspend_mem_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return regulator_print_opmode(buf, rdev->constraints->state_mem.mode); } +static DEVICE_ATTR(suspend_mem_mode, 0444, + regulator_suspend_mem_mode_show, NULL); static ssize_t regulator_suspend_disk_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return regulator_print_opmode(buf, rdev->constraints->state_disk.mode); } +static DEVICE_ATTR(suspend_disk_mode, 0444, + regulator_suspend_disk_mode_show, NULL); static ssize_t regulator_suspend_standby_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return regulator_print_opmode(buf, rdev->constraints->state_standby.mode); } +static DEVICE_ATTR(suspend_standby_mode, 0444, + regulator_suspend_standby_mode_show, NULL); static ssize_t regulator_suspend_mem_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - return regulator_print_state(buf, rdev->constraints->state_mem.enabled); } +static DEVICE_ATTR(suspend_mem_state, 0444, + regulator_suspend_mem_state_show, NULL); static ssize_t regulator_suspend_disk_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - return regulator_print_state(buf, rdev->constraints->state_disk.enabled); } +static DEVICE_ATTR(suspend_disk_state, 0444, + regulator_suspend_disk_state_show, NULL); static ssize_t regulator_suspend_standby_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - return regulator_print_state(buf, rdev->constraints->state_standby.enabled); } +static DEVICE_ATTR(suspend_standby_state, 0444, + regulator_suspend_standby_state_show, NULL); + +/* + * These are the only attributes are present for all regulators. + * Other attributes are a function of regulator functionality. + */ static struct device_attribute regulator_dev_attrs[] = { __ATTR(name, 0444, regulator_name_show, NULL), - __ATTR(microvolts, 0444, regulator_uV_show, NULL), - __ATTR(microamps, 0444, regulator_uA_show, NULL), - __ATTR(opmode, 0444, regulator_opmode_show, NULL), - __ATTR(state, 0444, regulator_state_show, NULL), - __ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL), - __ATTR(min_microamps, 0444, regulator_min_uA_show, NULL), - __ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL), - __ATTR(max_microamps, 0444, regulator_max_uA_show, NULL), - __ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL), __ATTR(num_users, 0444, regulator_num_users_show, NULL), __ATTR(type, 0444, regulator_type_show, NULL), - __ATTR(suspend_mem_microvolts, 0444, - regulator_suspend_mem_uV_show, NULL), - __ATTR(suspend_disk_microvolts, 0444, - regulator_suspend_disk_uV_show, NULL), - __ATTR(suspend_standby_microvolts, 0444, - regulator_suspend_standby_uV_show, NULL), - __ATTR(suspend_mem_mode, 0444, - regulator_suspend_mem_mode_show, NULL), - __ATTR(suspend_disk_mode, 0444, - regulator_suspend_disk_mode_show, NULL), - __ATTR(suspend_standby_mode, 0444, - regulator_suspend_standby_mode_show, NULL), - __ATTR(suspend_mem_state, 0444, - regulator_suspend_mem_state_show, NULL), - __ATTR(suspend_disk_state, 0444, - regulator_suspend_disk_state_show, NULL), - __ATTR(suspend_standby_state, 0444, - regulator_suspend_standby_state_show, NULL), __ATTR_NULL, }; @@ -1711,6 +1695,117 @@ int regulator_notifier_call_chain(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_notifier_call_chain); +/* + * To avoid cluttering sysfs (and memory) with useless state, only + * create attributes that can be meaningfully displayed. + */ +static int add_regulator_attributes(struct regulator_dev *rdev) +{ + struct device *dev = &rdev->dev; + struct regulator_ops *ops = rdev->desc->ops; + int status = 0; + + /* some attributes need specific methods to be displayed */ + if (ops->get_voltage) { + status = device_create_file(dev, &dev_attr_microvolts); + if (status < 0) + return status; + } + if (ops->get_current_limit) { + status = device_create_file(dev, &dev_attr_microamps); + if (status < 0) + return status; + } + if (ops->get_mode) { + status = device_create_file(dev, &dev_attr_opmode); + if (status < 0) + return status; + } + if (ops->is_enabled) { + status = device_create_file(dev, &dev_attr_state); + if (status < 0) + return status; + } + + /* some attributes are type-specific */ + if (rdev->desc->type == REGULATOR_CURRENT) { + status = device_create_file(dev, &dev_attr_requested_microamps); + if (status < 0) + return status; + } + + /* all the other attributes exist to support constraints; + * don't show them if there are no constraints, or if the + * relevant supporting methods are missing. + */ + if (!rdev->constraints) + return status; + + /* constraints need specific supporting methods */ + if (ops->set_voltage) { + status = device_create_file(dev, &dev_attr_min_microvolts); + if (status < 0) + return status; + status = device_create_file(dev, &dev_attr_max_microvolts); + if (status < 0) + return status; + } + if (ops->set_current_limit) { + status = device_create_file(dev, &dev_attr_min_microamps); + if (status < 0) + return status; + status = device_create_file(dev, &dev_attr_max_microamps); + if (status < 0) + return status; + } + + /* suspend mode constraints need multiple supporting methods */ + if (!(ops->set_suspend_enable && ops->set_suspend_disable)) + return status; + + status = device_create_file(dev, &dev_attr_suspend_standby_state); + if (status < 0) + return status; + status = device_create_file(dev, &dev_attr_suspend_mem_state); + if (status < 0) + return status; + status = device_create_file(dev, &dev_attr_suspend_disk_state); + if (status < 0) + return status; + + if (ops->set_suspend_voltage) { + status = device_create_file(dev, + &dev_attr_suspend_standby_microvolts); + if (status < 0) + return status; + status = device_create_file(dev, + &dev_attr_suspend_mem_microvolts); + if (status < 0) + return status; + status = device_create_file(dev, + &dev_attr_suspend_disk_microvolts); + if (status < 0) + return status; + } + + if (ops->set_suspend_mode) { + status = device_create_file(dev, + &dev_attr_suspend_standby_mode); + if (status < 0) + return status; + status = device_create_file(dev, + &dev_attr_suspend_mem_mode); + if (status < 0) + return status; + status = device_create_file(dev, + &dev_attr_suspend_disk_mode); + if (status < 0) + return status; + } + + return status; +} + /** * regulator_register - register regulator * @regulator: regulator source @@ -1779,6 +1874,11 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, dev_set_drvdata(&rdev->dev, rdev); + /* add attributes supported by this regulator */ + ret = add_regulator_attributes(rdev); + if (ret < 0) + goto scrub; + /* set supply regulator if it exists */ if (init_data->supply_regulator_dev) { ret = set_supply(rdev, From 471d8d49a752a8ee3caf606dca83f7d7b99355f7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 24 Nov 2008 18:43:00 +0200 Subject: [PATCH 06/16] regulator: da903x: add '\n' to error messages Signed-off-by: Mike Rapoport Acked-by: Eric Miao Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 773b29cec8b..83101d68c12 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -102,7 +102,7 @@ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, uint8_t val, mask; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } @@ -172,7 +172,7 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, int ret; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } @@ -199,7 +199,7 @@ static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, int thresh; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } @@ -248,7 +248,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, int ret; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } @@ -273,7 +273,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, uint8_t val, mask; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } From 961869048b61c853a17f35b98be91c5630a73906 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 25 Nov 2008 10:19:52 +0200 Subject: [PATCH 07/16] regulator: da903x: make da903x_is_enabled return 0 or 1 Signed-off-by: Mike Rapoport Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 83101d68c12..fe77730a7ed 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -159,7 +159,7 @@ static int da903x_is_enabled(struct regulator_dev *rdev) if (ret) return ret; - return reg_val & (1 << info->enable_bit); + return !!(reg_val & (1 << info->enable_bit)); } /* DA9030 specific operations */ From 74f544c1fc0339acf6f66ff438b8543b1f9faf10 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 25 Nov 2008 14:53:53 +0200 Subject: [PATCH 08/16] regulator: move set_machine_constraints after regulator device initialization Calling set_machine_constraints before regulator device initialization causes crash when constraints have apply_uV set. Signed-off-by: Mike Rapoport Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9a5ff97d158..895f73887cf 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1858,11 +1858,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, goto clean; } - /* set regulator constraints */ - ret = set_machine_constraints(rdev, &init_data->constraints); - if (ret < 0) - goto clean; - /* register with sysfs */ rdev->dev.class = ®ulator_class; rdev->dev.parent = dev; @@ -1874,6 +1869,11 @@ 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 (ret < 0) + goto scrub; + /* add attributes supported by this regulator */ ret = add_regulator_attributes(rdev); if (ret < 0) From 9f4dab49e5351aead75d20f2d39acd0d6cf5f1c6 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 1 Dec 2008 21:50:13 -0800 Subject: [PATCH 09/16] regulator: init/link earlier Move regulator earlier in link sequence. The regulator core currently initializes as a core_initcall() to be available early ... but then it links way late, throwing away that benefit, so regulators available at e.g. subsys_initcall() are not available to subsystems which need to use them. Signed-off-by: David Brownell Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/Makefile b/drivers/Makefile index e121b66ef08..6326f4dbbda 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -18,6 +18,9 @@ obj-$(CONFIG_ARM_AMBA) += amba/ obj-$(CONFIG_XEN) += xen/ +# regulators early, since some subsystems rely on them to initialize +obj-$(CONFIG_REGULATOR) += regulator/ + # char/ comes before serial/ etc so that the VT console is the boot-time # default. obj-y += char/ @@ -101,5 +104,4 @@ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_VIRTIO) += virtio/ -obj-$(CONFIG_REGULATOR) += regulator/ obj-$(CONFIG_STAGING) += staging/ From 8dc5390d4f3fd8acc73773a56fea13544e7924dc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 31 Dec 2008 12:52:40 +0000 Subject: [PATCH 10/16] regulator: Remove extraneous kerneldoc annotations Some of the internal structures have no kerneldoc but the ** at the start of the comment marking them for documentation. Remove the annotation until some is added. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 895f73887cf..7ba9491a05c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -29,7 +29,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); -/** +/* * struct regulator_dev * * Voltage / Current regulator class device. One for each regulator. @@ -56,7 +56,7 @@ struct regulator_dev { void *reg_data; /* regulator_dev data */ }; -/** +/* * struct regulator_map * * Used to provide symbolic supply names to devices. From 69279fb9a95051971ac03e558c4d46e7ba84ab3a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 31 Dec 2008 12:52:41 +0000 Subject: [PATCH 11/16] regulator: Clean up kerneldoc warnings Remove kerneldoc warnings that don't relate to missing documentation, mostly by renaming parameters in the documentation to match their actual names. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 44 +++++++++++++++--------------- include/linux/regulator/consumer.h | 8 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7ba9491a05c..ea12c68c327 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -655,7 +655,7 @@ static void print_constraints(struct regulator_dev *rdev) /** * set_machine_constraints - sets regulator constraints - * @regulator: regulator source + * @rdev: regulator source * * Allows platform initialisation code to define and constrain * regulator circuits e.g. valid voltage/current ranges, etc. NOTE: @@ -730,8 +730,8 @@ out: /** * set_supply - set regulator supply regulator - * @regulator: regulator name - * @supply: supply regulator name + * @rdev: regulator name + * @supply_rdev: supply regulator name * * Called by platform initialisation code to set the supply regulator for this * regulator. This ensures that a regulators supply will also be enabled by the @@ -758,9 +758,9 @@ out: /** * set_consumer_device_supply: Bind a regulator to a symbolic supply - * @regulator: regulator source - * @dev: device the supply applies to - * @supply: symbolic name for supply + * @rdev: regulator source + * @consumer_dev: device the supply applies to + * @supply: symbolic name for supply * * Allows platform initialisation code to map physical regulator * sources to symbolic names for supplies for use by devices. Devices @@ -1013,9 +1013,8 @@ static int _regulator_enable(struct regulator_dev *rdev) * * Enable the regulator output at the predefined voltage or current value. * NOTE: the output value can be set by other drivers, boot loader or may be - * hardwired in the regulator. - * NOTE: calls to regulator_enable() must be balanced with calls to - * regulator_disable(). + * hardwired in the regulator. Calls to regulator_enable() must be balanced + * with calls to regulator_disable(). */ int regulator_enable(struct regulator *regulator) { @@ -1074,10 +1073,10 @@ static int _regulator_disable(struct regulator_dev *rdev) * @regulator: regulator source * * Disable the regulator output voltage or current. + * * NOTE: this will only disable the regulator output if no other consumer - * devices have it enabled. - * NOTE: calls to regulator_enable() must be balanced with calls to - * regulator_disable(). + * devices have it enabled. Calls to regulator_enable() must be balanced with + * calls to regulator_disable(). */ int regulator_disable(struct regulator *regulator) { @@ -1200,7 +1199,7 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled); * * NOTE: If the regulator is shared between several devices then the lowest * request voltage that meets the system constraints will be used. - * NOTE: Regulator system constraints must be set for this regulator before + * Regulator system constraints must be set for this regulator before * calling this function otherwise this call will fail. */ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) @@ -1498,7 +1497,7 @@ EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); /** * regulator_register_notifier - register regulator event notifier * @regulator: regulator source - * @notifier_block: notifier block + * @nb: notifier block * * Register notifier block to receive regulator events. */ @@ -1513,7 +1512,7 @@ EXPORT_SYMBOL_GPL(regulator_register_notifier); /** * regulator_unregister_notifier - unregister regulator event notifier * @regulator: regulator source - * @notifier_block: notifier block + * @nb: notifier block * * Unregister regulator event notifier block. */ @@ -1679,9 +1678,9 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free); /** * regulator_notifier_call_chain - call regulator event notifier - * @regulator: regulator source + * @rdev: regulator source * @event: notifier block - * @data: + * @data: callback-specific data. * * Called by regulator drivers to notify clients a regulator event has * occurred. We also notify regulator clients downstream. @@ -1808,8 +1807,9 @@ static int add_regulator_attributes(struct regulator_dev *rdev) /** * regulator_register - register regulator - * @regulator: regulator source - * @reg_data: private regulator data + * @regulator_desc: regulator to register + * @dev: struct device for the regulator + * @driver_data: private regulator data * * Called by regulator drivers to register a regulator. * Returns 0 on success. @@ -1916,7 +1916,7 @@ EXPORT_SYMBOL_GPL(regulator_register); /** * regulator_unregister - unregister regulator - * @regulator: regulator source + * @rdev: regulator to unregister * * Called by regulator drivers to unregister a regulator. */ @@ -1971,7 +1971,7 @@ EXPORT_SYMBOL_GPL(regulator_suspend_prepare); /** * rdev_get_drvdata - get rdev regulator driver data - * @regulator: regulator + * @rdev: regulator * * Get rdev regulator driver private data. This call can be used in the * regulator driver context. @@ -2008,7 +2008,7 @@ EXPORT_SYMBOL_GPL(regulator_set_drvdata); /** * regulator_get_id - get regulator ID - * @regulator: regulator + * @rdev: regulator */ int rdev_get_id(struct regulator_dev *rdev) { diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index afdc4558bb9..801bf77ff4e 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -104,10 +104,10 @@ struct regulator; /** * struct regulator_bulk_data - Data used for bulk regulator operations. * - * @supply The name of the supply. Initialised by the user before - * using the bulk regulator APIs. - * @consumer The regulator consumer for the supply. This will be managed - * by the bulk API. + * @supply: The name of the supply. Initialised by the user before + * using the bulk regulator APIs. + * @consumer: The regulator consumer for the supply. This will be managed + * by the bulk API. * * The regulator APIs provide a series of regulator_bulk_() API calls as * a convenience to consumers which require multiple supplies. This From c8e7e4640facbe99d10a6e262523b25be129b9b9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 31 Dec 2008 12:52:42 +0000 Subject: [PATCH 12/16] regulator: Add missing kerneldoc This is only the documentation that the kerneldoc system warns about. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 1 + include/linux/regulator/driver.h | 40 +++++++++++++++++++++++++++++- include/linux/regulator/machine.h | 41 +++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ea12c68c327..fda44009024 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -656,6 +656,7 @@ static void print_constraints(struct regulator_dev *rdev) /** * set_machine_constraints - sets regulator constraints * @rdev: regulator source + * @constraints: constraints to apply * * Allows platform initialisation code to define and constrain * regulator circuits e.g. valid voltage/current ranges, etc. NOTE: diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index e37d8056198..84c3737c2d2 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -24,7 +24,37 @@ struct regulator_init_data; /** * struct regulator_ops - regulator operations. * - * This struct describes regulator operations. + * This struct describes regulator operations which can be implemented by + * regulator chip drivers. + * + * @enable: Enable the regulator. + * @disable: Disable the regulator. + * @is_enabled: Return 1 if the reguator is enabled, 0 otherwise. + * + * @set_voltage: Set the voltage for the regulator within the range specified. + * The driver should select the voltage closest to min_uV. + * @get_voltage: Return the currently configured voltage for the regulator. + * + * @set_current: Set the current for the regulator within the range specified. + * The driver should select the current closest to min_uA. + * @get_current: Return the currently configured current for the regulator. + * + * @set_current_limit: Configure a limit for a current-limited regulator. + * @get_current_limit: Get the limit for a current-limited regulator. + * + * @set_mode: Set the operating mode for the regulator. + * @get_mode: Get the current operating mode for the regulator. + * @get_optimum_mode: Get the most efficient operating mode for the regulator + * when running with the specified parameters. + * + * @set_suspend_voltage: Set the voltage for the regulator when the system + * is suspended. + * @set_suspend_enable: Mark the regulator as enabled when the system is + * suspended. + * @set_suspend_disable: Mark the regulator as disabled when the system is + * suspended. + * @set_suspend_mode: Set the operating mode for the regulator when the + * system is suspended. */ struct regulator_ops { @@ -75,6 +105,14 @@ enum regulator_type { /** * struct regulator_desc - Regulator descriptor * + * Each regulator registered with the core is described with a structure of + * this type. + * + * @name: Identifying name for the regulator. + * @id: Numerical identifier for the regulator. + * @ops: Regulator operations table. + * @type: Indicates if the regulator is a voltage or current regulator. + * @owner: Module providing the regulator, used for refcounting. */ struct regulator_desc { const char *name; diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index c6d69331a81..3794773b23d 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -44,6 +44,10 @@ struct regulator; * struct regulator_state - regulator state during low power syatem states * * This describes a regulators state during a system wide low power state. + * + * @uV: Operating voltage during suspend. + * @mode: Operating mode during suspend. + * @enabled: Enabled during suspend. */ struct regulator_state { int uV; /* suspend voltage */ @@ -55,6 +59,30 @@ struct regulator_state { * struct regulation_constraints - regulator operating constraints. * * This struct describes regulator and board/machine specific constraints. + * + * @name: Descriptive name for the constraints, used for display purposes. + * + * @min_uV: Smallest voltage consumers may set. + * @max_uV: Largest voltage consumers may set. + * + * @min_uA: Smallest consumers consumers may set. + * @max_uA: Largest current consumers may set. + * + * @valid_modes_mask: Mask of modes which may be configured by consumers. + * @valid_ops_mask: Operations which may be performed by consumers. + * + * @always_on: Set if the regulator should never be disabled. + * @boot_on: Set if the regulator is enabled when the system is initially + * started. + * @apply_uV: Apply the voltage constraint when initialising. + * + * @input_uV: Input voltage for regulator when supplied by another regulator. + * + * @state_disk: State for regulator when system is suspended in disk mode. + * @state_mem: State for regulator when system is suspended in mem mode. + * @state_standby: State for regulator when system is suspended in standby + * mode. + * @initial_state: Suspend state to set by default. */ struct regulation_constraints { @@ -93,6 +121,9 @@ struct regulation_constraints { * struct regulator_consumer_supply - supply -> device mapping * * This maps a supply name to a device. + * + * @dev: Device structure for the consumer. + * @supply: Name for the supply. */ struct regulator_consumer_supply { struct device *dev; /* consumer */ @@ -103,6 +134,16 @@ struct regulator_consumer_supply { * struct regulator_init_data - regulator platform initialisation data. * * Initialisation constraints, our supply and consumers supplies. + * + * @supply_regulator_dev: Parent regulator (if any). + * + * @constraints: Constraints. These must be specified for the regulator to + * be usable. + * @num_consumer_supplies: Number of consumer device supplies. + * @consumer_supplies: Consumer device supply configuration. + * + * @regulator_init: Callback invoked when the regulator has been registered. + * @driver_data: Data passed to regulator_init. */ struct regulator_init_data { struct device *supply_regulator_dev; /* or NULL for LINE */ From cf7bbcdf4d267eff580cb7ce6cf4fe16a940a005 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 31 Dec 2008 12:52:43 +0000 Subject: [PATCH 13/16] regulator: Fix some kerneldoc rendering issues There are some minor textual changes in here as well, mostly to enable() and disable() but the primary goal of these changes is to fix misrenderings of the kerneldoc documentation for the regulator API. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fda44009024..7341c97cd91 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1012,10 +1012,12 @@ static int _regulator_enable(struct regulator_dev *rdev) * regulator_enable - enable regulator output * @regulator: regulator source * - * Enable the regulator output at the predefined voltage or current value. + * Request that the regulator be enabled with the regulator output at + * the predefined voltage or current value. Calls to regulator_enable() + * must be balanced with calls to regulator_disable(). + * * NOTE: the output value can be set by other drivers, boot loader or may be - * hardwired in the regulator. Calls to regulator_enable() must be balanced - * with calls to regulator_disable(). + * hardwired in the regulator. */ int regulator_enable(struct regulator *regulator) { @@ -1073,11 +1075,13 @@ static int _regulator_disable(struct regulator_dev *rdev) * regulator_disable - disable regulator output * @regulator: regulator source * - * Disable the regulator output voltage or current. + * Disable the regulator output voltage or current. Calls to + * regulator_enable() must be balanced with calls to + * regulator_disable(). * * NOTE: this will only disable the regulator output if no other consumer - * devices have it enabled. Calls to regulator_enable() must be balanced with - * calls to regulator_disable(). + * devices have it enabled, the regulator device supports disabling and + * machine constraints permit this operation. */ int regulator_disable(struct regulator *regulator) { @@ -1936,7 +1940,7 @@ void regulator_unregister(struct regulator_dev *rdev) EXPORT_SYMBOL_GPL(regulator_unregister); /** - * regulator_suspend_prepare: prepare regulators for system wide suspend + * regulator_suspend_prepare - prepare regulators for system wide suspend * @state: system suspend state * * Configure each regulator with it's suspend operating parameters for state. From 9fe5817f196054142b9a13ed78c73b76a29f2ea3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 31 Dec 2008 12:52:44 +0000 Subject: [PATCH 14/16] regulator: Add basic DocBook manual Add a basic DocBook manual for the regulator API. This is much more skeletal than the existing text documentation, the main benefit is to provide a skeleton for automatic generation of a manual based on the kerneldoc for the API. Since large portions of the text are lifted from the existing text format documentation written by Liam Girdwood much of the credit belongs to him. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- Documentation/DocBook/Makefile | 2 +- Documentation/DocBook/regulator.tmpl | 304 +++++++++++++++++++++++++++ 2 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 Documentation/DocBook/regulator.tmpl diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 0a08126d309..dc3154e4927 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -12,7 +12,7 @@ DOCBOOKS := z8530book.xml mcabook.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ - mac80211.xml debugobjects.xml sh.xml + mac80211.xml debugobjects.xml sh.xml regulator.xml ### # The build process is as follows (targets): diff --git a/Documentation/DocBook/regulator.tmpl b/Documentation/DocBook/regulator.tmpl new file mode 100644 index 00000000000..53f4f8d3b81 --- /dev/null +++ b/Documentation/DocBook/regulator.tmpl @@ -0,0 +1,304 @@ + + + + + + Voltage and current regulator API + + + + Liam + Girdwood + +
+ lrg@slimlogic.co.uk +
+
+
+ + Mark + Brown + + Wolfson Microelectronics +
+ broonie@opensource.wolfsonmicro.com +
+
+
+
+ + + 2007-2008 + Wolfson Microelectronics + + + 2008 + Liam Girdwood + + + + + This documentation 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. + + + + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + This framework is designed to provide a standard kernel + interface to control voltage and current regulators. + + + The intention is to allow systems to dynamically control + regulator power output in order to save power and prolong + battery life. This applies to both voltage regulators (where + voltage output is controllable) and current sinks (where current + limit is controllable). + + + Note that additional (and currently more complete) documentation + is available in the Linux kernel source under + Documentation/power/regulator. + + + + Glossary + + The regulator API uses a number of terms which may not be + familiar: + + + + + Regulator + + + Electronic device that supplies power to other devices. Most + regulators can enable and disable their output and some can also + control their output voltage or current. + + + + + + Consumer + + + Electronic device which consumes power provided by a regulator. + These may either be static, requiring only a fixed supply, or + dynamic, requiring active management of the regulator at + runtime. + + + + + + Power Domain + + + The electronic circuit supplied by a given regulator, including + the regulator and all consumer devices. The configuration of + the regulator is shared between all the components in the + circuit. + + + + + + Power Management Integrated Circuit + PMIC + + + An IC which contains numerous regulators and often also other + subsystems. In an embedded system the primary PMIC is often + equivalent to a combination of the PSU and southbridge in a + desktop system. + + + + + + + + + Consumer driver interface + + This offers a similar API to the kernel clock framework. + Consumer drivers use get and put operations to acquire and + release regulators. Functions are + provided to enable + and disable the + reguator and to get and set the runtime parameters of the + regulator. + + + When requesting regulators consumers use symbolic names for their + supplies, such as "Vcc", which are mapped into actual regulator + devices by the machine interface. + + + A stub version of this API is provided when the regulator + framework is not in use in order to minimise the need to use + ifdefs. + + + + Enabling and disabling + + The regulator API provides reference counted enabling and + disabling of regulators. Consumer devices use the regulator_enable + and regulator_disable + functions to enable and disable regulators. Calls + to the two functions must be balanced. + + + Note that since multiple consumers may be using a regulator and + machine constraints may not allow the regulator to be disabled + there is no guarantee that calling + regulator_disable will actually cause the + supply provided by the regulator to be disabled. Consumer + drivers should assume that the regulator may be enabled at all + times. + + + + + Configuration + + Some consumer devices may need to be able to dynamically + configure their supplies. For example, MMC drivers may need to + select the correct operating voltage for their cards. This may + be done while the regulator is enabled or disabled. + + + The regulator_set_voltage + and regulator_set_current_limit + functions provide the primary interface for this. + Both take ranges of voltages and currents, supporting drivers + that do not require a specific value (eg, CPU frequency scaling + normally permits the CPU to use a wider range of supply + voltages at lower frequencies but does not require that the + supply voltage be lowered). Where an exact value is required + both minimum and maximum values should be identical. + + + + + Callbacks + + Callbacks may also be registered + for events such as regulation failures. + + + + + + Regulator driver interface + + Drivers for regulator chips register the regulators + with the regulator core, providing operations structures to the + core. A notifier interface + allows error conditions to be reported to the core. + + + Registration should be triggered by explicit setup done by the + platform, supplying a struct + regulator_init_data for the regulator containing + constraint and + supply information. + + + + + Machine interface + + This interface provides a way to define how regulators are + connected to consumers on a given system and what the valid + operating parameters are for the system. + + + + Supplies + + Regulator supplies are specified using struct + regulator_consumer_supply. This is done at + driver registration + time as part of the machine constraints. + + + + + Constraints + + As well as definining the connections the machine interface + also provides constraints definining the operations that + clients are allowed to perform and the parameters that may be + set. This is required since generally regulator devices will + offer more flexibility than it is safe to use on a given + system, for example supporting higher supply voltages than the + consumers are rated for. + + + This is done at driver + registration time by providing a struct + regulation_constraints. + + + The constraints may also specify an initial configuration for the + regulator in the constraints, which is particularly useful for + use with static consumers. + + + + + + API reference + + Due to limitations of the kernel documentation framework and the + existing layout of the source code the entire regulator API is + documented here. + +!Iinclude/linux/regulator/consumer.h +!Iinclude/linux/regulator/machine.h +!Iinclude/linux/regulator/driver.h +!Edrivers/regulator/core.c + +
From 6001e13c5f708eb68c744a69df3c2c281156030d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Dec 2008 12:54:19 +0000 Subject: [PATCH 15/16] regulator: catch some registration errors Prevent registration of duplicate "struct regulator" names. They'd be unavailable, and clearly indicate something wrong. [Edited to remove check for NULL consumer device until we have a solution for things like cpufreq -- broonie] Signed-off-by: David Brownell Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7341c97cd91..f511a406fca 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -776,6 +776,20 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, if (supply == NULL) return -EINVAL; + list_for_each_entry(node, ®ulator_map_list, list) { + if (consumer_dev != node->dev) + continue; + 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->desc->name); + return -EBUSY; + } + node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL); if (node == NULL) return -ENOMEM; From 0ba4887c6329043d6cee5b5b477cfe50c2b57674 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 8 Jan 2009 11:50:23 -0800 Subject: [PATCH 16/16] regulator: fix kernel-doc warnings Fix kernel-doc warnings in regulator/driver.h: Warning(linux-next-20090108//include/linux/regulator/driver.h:95): Excess struct/union/enum/typedef member 'set_current' description in 'regulator_ops' Warning(linux-next-20090108//include/linux/regulator/driver.h:95): Excess struct/union/enum/typedef member 'get_current' description in 'regulator_ops' Warning(linux-next-20090108//include/linux/regulator/driver.h:124): No description found for parameter 'irq' Signed-off-by: Randy Dunlap cc: Liam Girdwood cc: Mark Brown Signed-off-by: Liam Girdwood --- include/linux/regulator/driver.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 84c3737c2d2..2dae05705f1 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -29,16 +29,12 @@ struct regulator_init_data; * * @enable: Enable the regulator. * @disable: Disable the regulator. - * @is_enabled: Return 1 if the reguator is enabled, 0 otherwise. + * @is_enabled: Return 1 if the regulator is enabled, 0 otherwise. * * @set_voltage: Set the voltage for the regulator within the range specified. * The driver should select the voltage closest to min_uV. * @get_voltage: Return the currently configured voltage for the regulator. * - * @set_current: Set the current for the regulator within the range specified. - * The driver should select the current closest to min_uA. - * @get_current: Return the currently configured current for the regulator. - * * @set_current_limit: Configure a limit for a current-limited regulator. * @get_current_limit: Get the limit for a current-limited regulator. * @@ -111,6 +107,7 @@ enum regulator_type { * @name: Identifying name for the regulator. * @id: Numerical identifier for the regulator. * @ops: Regulator operations table. + * @irq: Interrupt number for the regulator. * @type: Indicates if the regulator is a voltage or current regulator. * @owner: Module providing the regulator, used for refcounting. */