diff options
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r-- | drivers/regulator/core.c | 79 |
1 files changed, 68 insertions, 11 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b60a4c9f8f16..c7bbe30010f7 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -19,10 +19,13 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/suspend.h> +#include <linux/delay.h> #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include "dummy.h" + #define REGULATOR_VERSION "0.5" static DEFINE_MUTEX(regulator_list_mutex); @@ -1084,6 +1087,13 @@ overflow_err: return NULL; } +static int _regulator_get_enable_time(struct regulator_dev *rdev) +{ + if (!rdev->desc->ops->enable_time) + return 0; + return rdev->desc->ops->enable_time(rdev); +} + /* Internal regulator request function */ static struct regulator *_regulator_get(struct device *dev, const char *id, int exclusive) @@ -1115,6 +1125,22 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, goto found; } } + +#ifdef CONFIG_REGULATOR_DUMMY + if (!devname) + devname = "deviceless"; + + /* If the board didn't flag that it was fully constrained then + * substitute in a dummy regulator so consumers can continue. + */ + if (!has_full_constraints) { + pr_warning("%s supply %s not found, using dummy regulator\n", + devname, id); + rdev = dummy_regulator_rdev; + goto found; + } +#endif + mutex_unlock(®ulator_list_mutex); return regulator; @@ -1251,7 +1277,7 @@ static int _regulator_can_change_status(struct regulator_dev *rdev) /* locks held by regulator_enable() */ static int _regulator_enable(struct regulator_dev *rdev) { - int ret; + int ret, delay; /* do we need to enable the supply regulator first */ if (rdev->supply) { @@ -1275,13 +1301,34 @@ static int _regulator_enable(struct regulator_dev *rdev) if (!_regulator_can_change_status(rdev)) return -EPERM; - if (rdev->desc->ops->enable) { - ret = rdev->desc->ops->enable(rdev); - if (ret < 0) - return ret; - } else { + if (!rdev->desc->ops->enable) return -EINVAL; + + /* Query before enabling in case configuration + * dependant. */ + ret = _regulator_get_enable_time(rdev); + if (ret >= 0) { + delay = ret; + } else { + printk(KERN_WARNING + "%s: enable_time() failed for %s: %d\n", + __func__, rdev_get_name(rdev), + ret); + delay = 0; } + + /* Allow the regulator to ramp; it would be useful + * to extend this for bulk operations so that the + * regulators can ramp together. */ + ret = rdev->desc->ops->enable(rdev); + if (ret < 0) + return ret; + + if (delay >= 1000) + mdelay(delay / 1000); + else if (delay) + udelay(delay); + } else if (ret < 0) { printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", __func__, rdev_get_name(rdev), ret); @@ -1341,6 +1388,9 @@ static int _regulator_disable(struct regulator_dev *rdev) __func__, rdev_get_name(rdev)); return ret; } + + _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, + NULL); } /* decrease our supplies ref count and disable if required */ @@ -1399,8 +1449,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev) return ret; } /* notify other consumers that power has been forced off */ - _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE, - NULL); + _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | + REGULATOR_EVENT_DISABLE, NULL); } /* decrease our supplies ref count and disable if required */ @@ -1434,9 +1484,9 @@ EXPORT_SYMBOL_GPL(regulator_force_disable); static int _regulator_is_enabled(struct regulator_dev *rdev) { - /* sanity check */ + /* If we don't know then assume that the regulator is always on */ if (!rdev->desc->ops->is_enabled) - return -EINVAL; + return 1; return rdev->desc->ops->is_enabled(rdev); } @@ -2451,8 +2501,15 @@ EXPORT_SYMBOL_GPL(regulator_get_init_drvdata); static int __init regulator_init(void) { + int ret; + printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION); - return class_register(®ulator_class); + + ret = class_register(®ulator_class); + + regulator_dummy_init(); + + return ret; } /* init early to allow our consumers to complete system booting */ |