aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-05-23 20:12:40 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2011-05-30 06:56:57 -0400
commitf21e0e81d81b649ad309cedc7226f1bed72982e0 (patch)
tree24fe19d6408b58a32c7f82df47f9e17fb76e1a5c /drivers/regulator
parent55922c9d1b84b89cb946c777fddccb3247e7df2c (diff)
regulator: Do bulk enables of regulators in parallel
In order to reduce the impact of ramp times rather than enabling the regulators for a device in series use async tasks to run the actual enables. This means that the delays which the enables implement can all run in parallel, though it does mean that the order in which the supplies come on may be unstable. For super bonus fun points if any of the regulators are shared between multiple supplies on the same device (as is rather likely) then this will test our locking. Note that in this case we only delay once for each physical regulator so the threads shouldn't block each other while delaying. It'd be even nicer if we could coalesce writes to a shared enable registers in PMICs but that's definitely future work, and it may also be useful and is certainly more achievable to optimise out the parallelism if none of the regulators implement ramp delays. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/core.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index d3e38790906e..7b38af90a012 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -20,6 +20,7 @@
20#include <linux/debugfs.h> 20#include <linux/debugfs.h>
21#include <linux/device.h> 21#include <linux/device.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/async.h>
23#include <linux/err.h> 24#include <linux/err.h>
24#include <linux/mutex.h> 25#include <linux/mutex.h>
25#include <linux/suspend.h> 26#include <linux/suspend.h>
@@ -2264,6 +2265,13 @@ err:
2264} 2265}
2265EXPORT_SYMBOL_GPL(regulator_bulk_get); 2266EXPORT_SYMBOL_GPL(regulator_bulk_get);
2266 2267
2268static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)
2269{
2270 struct regulator_bulk_data *bulk = data;
2271
2272 bulk->ret = regulator_enable(bulk->consumer);
2273}
2274
2267/** 2275/**
2268 * regulator_bulk_enable - enable multiple regulator consumers 2276 * regulator_bulk_enable - enable multiple regulator consumers
2269 * 2277 *
@@ -2279,21 +2287,33 @@ EXPORT_SYMBOL_GPL(regulator_bulk_get);
2279int regulator_bulk_enable(int num_consumers, 2287int regulator_bulk_enable(int num_consumers,
2280 struct regulator_bulk_data *consumers) 2288 struct regulator_bulk_data *consumers)
2281{ 2289{
2290 LIST_HEAD(async_domain);
2282 int i; 2291 int i;
2283 int ret; 2292 int ret = 0;
2293
2294 for (i = 0; i < num_consumers; i++)
2295 async_schedule_domain(regulator_bulk_enable_async,
2296 &consumers[i], &async_domain);
2297
2298 async_synchronize_full_domain(&async_domain);
2284 2299
2300 /* If any consumer failed we need to unwind any that succeeded */
2285 for (i = 0; i < num_consumers; i++) { 2301 for (i = 0; i < num_consumers; i++) {
2286 ret = regulator_enable(consumers[i].consumer); 2302 if (consumers[i].ret != 0) {
2287 if (ret != 0) 2303 ret = consumers[i].ret;
2288 goto err; 2304 goto err;
2305 }
2289 } 2306 }
2290 2307
2291 return 0; 2308 return 0;
2292 2309
2293err: 2310err:
2294 pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); 2311 for (i = 0; i < num_consumers; i++)
2295 for (--i; i >= 0; --i) 2312 if (consumers[i].ret == 0)
2296 regulator_disable(consumers[i].consumer); 2313 regulator_disable(consumers[i].consumer);
2314 else
2315 pr_err("Failed to enable %s: %d\n",
2316 consumers[i].supply, consumers[i].ret);
2297 2317
2298 return ret; 2318 return ret;
2299} 2319}