From 00c877c69ba315d6c565a4df51c71b11e82cdeb8 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 18 Sep 2013 18:18:02 +0530 Subject: regulator: core: add support for configuring turn-on time through constraints The turn-on time of the regulator depends on the regulator device's electrical characteristics. Sometimes regulator turn-on time also depends on the capacitive load on the given platform and it can be more than the datasheet value. The driver provides the enable-time as per datasheet. Add support for configure the enable ramp time through regulator constraints so that regulator core can take this value for enable time for that regulator. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 2bd8f09..e2c7f1e 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -14,6 +14,11 @@ Optional properties: - regulator-ramp-delay: ramp delay for regulator(in uV/uS) For hardwares which support disabling ramp rate, it should be explicitly intialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay. +- regulator-enable-ramp-delay: The time taken, in microseconds, for the supply + rail to reach the target voltage, plus/minus whatever tolerance the board + design requires. This property describes the total system ramp time + required due to the combination of internal ramping of the regulator itself, + and board design issues such as trace capacitance and load on the supply. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a01b8b3..5217c19 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1186,6 +1186,8 @@ overflow_err: static int _regulator_get_enable_time(struct regulator_dev *rdev) { + if (rdev->constraints && rdev->constraints->enable_time) + return rdev->constraints->enable_time; if (!rdev->desc->ops->enable_time) return rdev->desc->enable_time; return rdev->desc->ops->enable_time(rdev); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 7827384..ea4f36f 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -23,6 +23,8 @@ static void of_get_regulation_constraints(struct device_node *np, const __be32 *min_uA, *max_uA, *ramp_delay; struct property *prop; struct regulation_constraints *constraints = &(*init_data)->constraints; + int ret; + u32 pval; constraints->name = of_get_property(np, "regulator-name", NULL); @@ -73,6 +75,10 @@ static void of_get_regulation_constraints(struct device_node *np, else constraints->ramp_disable = true; } + + ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval); + if (!ret) + constraints->enable_time = pval; } /** diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 999b20c..8108751 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -95,6 +95,7 @@ struct regulator_state { * @initial_state: Suspend state to set by default. * @initial_mode: Mode to set at startup. * @ramp_delay: Time to settle down after voltage change (unit: uV/us) + * @enable_time: Turn-on time of the rails (unit: microseconds) */ struct regulation_constraints { @@ -129,6 +130,7 @@ struct regulation_constraints { unsigned int initial_mode; unsigned int ramp_delay; + unsigned int enable_time; /* constraint flags */ unsigned always_on:1; /* regulator never off when system is on */ -- cgit v0.10.2 From f8c1700dd7d2ce9b2238b20d364317b2968ac76b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 20 Sep 2013 13:13:02 +0530 Subject: regulator: core: set current constraints while setting machine constraints Machine constraints is configured during regulator register. If current constraints are provided through machine constraints then it is observed that sometime the current configured on rail is out of range what machine constraint has. Set the current constraints when setting machine constraints to make sure that rail's current is within the range of given machine constraints. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5217c19..66ae12d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -923,6 +923,36 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, return 0; } +static int machine_constraints_current(struct regulator_dev *rdev, + struct regulation_constraints *constraints) +{ + struct regulator_ops *ops = rdev->desc->ops; + int ret; + + if (!constraints->min_uA && !constraints->max_uA) + return 0; + + if (constraints->min_uA > constraints->max_uA) { + rdev_err(rdev, "Invalid current constraints\n"); + return -EINVAL; + } + + if (!ops->set_current_limit || !ops->get_current_limit) { + rdev_warn(rdev, "Operation of current configuration missing\n"); + return 0; + } + + /* Set regulator current in constraints range */ + ret = ops->set_current_limit(rdev, constraints->min_uA, + constraints->max_uA); + if (ret < 0) { + rdev_err(rdev, "Failed to set current constraint, %d\n", ret); + return ret; + } + + return 0; +} + /** * set_machine_constraints - sets regulator constraints * @rdev: regulator source @@ -953,6 +983,10 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (ret != 0) goto out; + ret = machine_constraints_current(rdev, rdev->constraints); + if (ret != 0) + goto out; + /* do we need to setup our suspend state */ if (rdev->constraints->initial_state) { ret = suspend_prepare(rdev, rdev->constraints->initial_state); -- cgit v0.10.2 From 043c998f95036e7fc796b240ab5ba49a8de36df3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 20 Sep 2013 12:32:18 +0100 Subject: regulator: core: Fix return code for invalid parameters We should be returning an error, a repeated call will never succeed. Signed-off-by: Mark Brown diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 66ae12d..ad15424 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1288,7 +1288,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, if (id == NULL) { pr_err("get() with no identifier\n"); - return regulator; + return ERR_PTR(-EINVAL); } if (dev) -- cgit v0.10.2 From 5df529d440aa4f0e67be9af3718e7edf05db7d02 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 20 Sep 2013 13:51:56 +0200 Subject: regulator: core: Reduce busy-wait looping Keep busy-wait looping to a minimum while waiting for a regulator to ramp-up to the target voltage. This follows the guidelines set forth in Documentation/timers/timers-howto.txt and assumes that regulators are never enabled in atomic context. Signed-off-by: Thierry Reding Signed-off-by: Mark Brown diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ad15424..5075ed1 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1740,11 +1740,39 @@ static int _regulator_do_enable(struct regulator_dev *rdev) * together. */ trace_regulator_enable_delay(rdev_get_name(rdev)); - if (delay >= 1000) { - mdelay(delay / 1000); - udelay(delay % 1000); - } else if (delay) { - udelay(delay); + /* + * Delay for the requested amount of time as per the guidelines in: + * + * Documentation/timers/timers-howto.txt + * + * The assumption here is that regulators will never be enabled in + * atomic context and therefore sleeping functions can be used. + */ + if (delay) { + unsigned int ms = delay / 1000; + unsigned int us = delay % 1000; + + if (ms > 0) { + /* + * For small enough values, handle super-millisecond + * delays in the usleep_range() call below. + */ + if (ms < 20) + us += ms * 1000; + else + msleep(ms); + } + + /* + * Give the scheduler some room to coalesce with any other + * wakeup sources. For delays shorter than 10 us, don't even + * bother setting up high-resolution timers and just busy- + * loop. + */ + if (us >= 10) + usleep_range(us, us + 100); + else + udelay(us); } trace_regulator_enable_complete(rdev_get_name(rdev)); -- cgit v0.10.2