Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH] backlight: Add of_find_backlight_by_node() function
From: Thierry Reding @ 2012-11-16 20:56 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Jingoo Han, 'Richard Purdie',
	'Florian Tobias Schandinat', linux-fbdev,
	devicetree-discuss, linux-kernel
In-Reply-To: <001201cdc30f$65a17be0$30e473a0$%han@samsung.com>

[-- Attachment #1: Type: text/plain, Size: 1802 bytes --]

On Thu, Nov 15, 2012 at 05:58:35PM +0900, Jingoo Han wrote:
> On Thursday, November 15, 2012 3:52 PM Thierry Reding wrote
> > On Thu, Nov 15, 2012 at 10:30:11AM +0900, Jingoo Han wrote:
> > > On Friday, November 09, 2012 11:05 PM Thierry Reding wrote
> > > >
> > > > This function finds the struct backlight_device for a given device tree
> > > > node. A dummy function is provided so that it safely compiles out if OF
> > > > support is disabled.
> > > >
> > > > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> > >
> > > CC'ed Andrew Morton
> > 
> > Yes, the backlight subsystem isn't very well maintained, so I should
> > have added Andrew in the first place. Thanks.
> > 
> > >
> > > Hi Thierry Reding,
> > >
> > > The patch itself looks good.
> > > Could you explain when this API is used?
> > > Thank you.
> > 
> > I use this for the upcoming Tegra DRM driver in order to hook up the
> > backlight with the DRM driver via DT to allow switching off the
> > backlight when the corresponding DRM output is switched of using DPMS.
> > Basically what you have is something like this in the device tree:
> > 
> > 	display {
> > 		...
> > 
> > 		backlight = <&backlight>;
> > 
> > 		...
> > 	}
> > 
> > Then you call something along these lines:
> > 
> > 	np = of_parse_phandle(display, "backlight", 0);
> > 	if (np) {
> > 		backlight = of_find_backlight_by_node(np);
> > 		of_node_put(np);
> > 	}
> > 
> > And then use the standard backlight API on the returned pointer.
> 
> OK, I see how this API can be called.
> AS you mentioned, it will allow Tegra DRM driver to use
> the backlight driver.
> 
> Acked-by: Jingoo Han <jg1.han@samsung.com>

Andrew,

any chance we could still get this in for the 3.8 merge window?

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v8 3/3] Take maintainership of power sequences
From: Stephen Warren @ 2012-11-16 17:09 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Alexandre Courbot, linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Mark Brown,
	Stephen Warren, linux-pm-u79uwXL29TY76Z2rM5mHXA,
	Leela Krishna Amudala, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Zhang, Rob Herring, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Anton Vorontsov, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	David Woodhouse
In-Reply-To: <1353047903-14363-4-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

On 11/15/2012 11:38 PM, Alexandre Courbot wrote:
> Add entry for power sequences into MAINTAINERS with all the needed
> contact and SCM info.

Acked-by: Stephen Warren <swarren@nvidia.com>

> diff --git a/MAINTAINERS b/MAINTAINERS

> +POWER SEQUENCES
> +M:	Alexandre Courbot <acourbot@nvidia.com>
> +S:	Maintained

Given you're presumably working on this on NVIDIA's time, perhaps make
that "Supported" not "Maintained"?

^ permalink raw reply

* Re: [PATCH v8 0/3] Runtime Interpreted Power Sequences
From: Stephen Warren @ 2012-11-16 17:08 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Alexandre Courbot, linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Mark Brown,
	Stephen Warren, linux-pm-u79uwXL29TY76Z2rM5mHXA,
	Leela Krishna Amudala, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Zhang, Rob Herring, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Anton Vorontsov, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	David Woodhouse
In-Reply-To: <1353047903-14363-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

On 11/15/2012 11:38 PM, Alexandre Courbot wrote:
> Hopefully the final series before the feature gets merged. Anton Vorontsov
> kindly accepted to take it into his tree, so this series is mostly a call for
> acks, tests and reviews notices before the merge window for 3.8 opens. If you
> are interested in seeing this feature, please add your name.
> 
> This series also adds an entry for the subsystem into MAINTAINERS, setting me as
> the person in charge.

The series,
Tested-by: Stephen Warren <swarren@nvidia.com>

On Ventana.


^ permalink raw reply

* RE: [RFC] fbdev: arm has __raw I/O accessors, use them in fb.h
From: H Hartley Sweeten @ 2012-11-16 16:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1353057364-21214-1-git-send-email-archit@ti.com>

On Friday, November 16, 2012 2:16 AM, Archit Taneja wrote:
>
> This removes the sparse warnings on arm platforms:
>
> warning: cast removes address space of expression
>
> Signed-off-by: Archit Taneja <archit@ti.com>

I submitted the same patch around early March 2012. So FWIW:

Reviewed-by: H Hartley Sweeten <hsweeten@visionengravers.com>

Regards,
Hartley

^ permalink raw reply

* Williams
From: willims gebrel @ 2012-11-16 12:59 UTC (permalink / raw)
  To: linux-fbdev


My Dear,

 

I'm happy to inform you about my success in getting those funds transferred under the cooperation of my new partner from Canada based business man; presently I'm in Bahamas for investment projects with my own share of the total sum. Meanwhile, I didn't forget your past efforts and attempts to assist me in transferring those funds despite that it failed us somehow.

 

Now contact my patina personal adviser in Togo, his name is HON REV.PETER SMITH of church embassy ministry Togo, E-mail: fortbendlawlegal@gmail.com

 

Ask him to send you the official Draft check of $500.000.00 or by cash which I gave him as order to kept for your compensation for all the past efforts and attempts to assist me in this matter before. I appreciated your collective efforts at that time, so feel free and get in touch with my patina adviser HON.REV. PETER SMITH and instruct him where to send the amount to you. Please do let me know immediately you receive it so that we can share the joy after all the sufferings at that time.

 

in the moment, I am very busy here In Bahamas because of the investment projects which myself and the new partner are having at hand without confrontations, finally, remember that I had forwarded instruction to the REV.PETER SMITH on your behalf to send you the check or by cash as my patina deposited to him on your name before he left to Canada where he based.

 

So feel free to get in touch with HON REV.PETER SMITH he will send the amount to you without any delay.

 

With best regards,

Williams

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Anton Vorontsov @ 2012-11-16 12:25 UTC (permalink / raw)
  To: Alex Courbot
  Cc: Stephen Warren, Thierry Reding, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org,
	devicetree-discuss@lists.ozlabs.org, linux-pm@vger.kernel.org,
	Alexandre Courbot
In-Reply-To: <50A60AF6.9080509@nvidia.com>

On Fri, Nov 16, 2012 at 06:44:22PM +0900, Alex Courbot wrote:
> On 11/16/2012 04:26 PM, Anton Vorontsov wrote:
> >>+#include "power_seq_delay.c"
> >>+#include "power_seq_regulator.c"
> >>+#include "power_seq_pwm.c"
> >>+#include "power_seq_gpio.c"
> >
> >This is odd, although I remember you already explained why you have to
> >include the .c files, instead of linking them separately. But I forgot the
> >reason. :) I think this deserves a comment in the code.
> 
> This is because of the table right after these includes:
> 
> static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
> 	[POWER_SEQ_DELAY] = POWER_SEQ_DELAY_TYPE,
> 	[POWER_SEQ_REGULATOR] = POWER_SEQ_REGULATOR_TYPE,
> 	[POWER_SEQ_PWM] = POWER_SEQ_PWM_TYPE,
> 	[POWER_SEQ_GPIO] = POWER_SEQ_GPIO_TYPE,
> };
> 
> The POWER_SEQ_*_TYPE macros are defined in the C files. It's the
> simplest way to initialize this table, and the code inside these C
> files is short and simple enough that I thought I would be forgiven.
> :)

I think in the header file you could just write

extern ..... power_seq_delay_type;
#ifndef ...
#define power_seq_delay_type NULL
#endif

And then, in the .c file:

static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
	[POWER_SEQ_DELAY] = power_seq_delay_type,
	...
};

And then you can stop including the .c files directly, and link them
instead.

> At first everything was in power_seq.c and it was fine, then I
> thought it would be better to move resource support code into their
> own filesm and now everybody is asking. :P
> 
> But yeah, maybe it would be even better to not stop halfway and use
> dynamic linking.
> 
> Comment added for the time being. ;)
> 
> >>+static int of_power_seq_parse_step(struct device *dev,
> >>+				   struct device_node *node,
> >>+				   struct power_seq *seq,
> >>+				   unsigned int step_nbr,
> >>+				   struct list_head *resources)
> >>+{
> >>+	struct power_seq_step *step = &seq->steps[step_nbr];
> >>+	struct power_seq_resource res, *res2;
> >>+	const char *type;
> >>+	int i, err;
> >
> >nit: one variable declaration per line.
> 
> Fair enough - but is that a convention? checkpatch.pl was happy with these.

It's not a rule, although there is a small passage about it in CodingStyle
file when it describes commenting style. Though, some folks choose to
ignore this suggestion quite frequently, especially if variables have no
comments.

Often, the multiple declarations per line are used to hide ugly functions
w/ tons of variables, or just to confuse the reader for the fun of it.

There are exceptions, of course. E.g.

	int i, j, k; /* Our iterators. */

Is perfectly fine.

But
	int i, err;

At least to me seems weird, this stuff is logically disjunct.

Only human can truly differentiate when the stuff "looks better" together
or apart, so that's why checkpatch doesn't complain. Personally, I use
this rule of thumb: when in doubt, use just one declaration per line, it
is always OK. :)

Thanks,
Anton.

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Mark Rutland @ 2012-11-16 10:35 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, rob.herring@calxeda.com, Mark Brown,
	David Woodhouse, Arnd Bergmann, Alexandre Courbot,
	linux-fbdev@vger.kernel.org, linux-pm@vger.kernel.org,
	Leela Krishna Amudala, devicetree-discuss@lists.ozlabs.org,
	linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org
In-Reply-To: <1353047903-14363-2-git-send-email-acourbot@nvidia.com>

On Fri, Nov 16, 2012 at 06:38:21AM +0000, Alexandre Courbot wrote:
> Some device drivers (e.g. panel or backlights) need to follow precise
> sequences for powering on and off, involving GPIOs, regulators, PWMs
> with a precise powering order and delays to respect between steps.
> These sequences are device-specific, and do not belong to a particular
> driver - therefore they have been performed by board-specific hook
> functions to far.
> 
> With the advent of the device tree and of ARM kernels that are not
> board-tied, we cannot rely on these board-specific hooks anymore but
> need a way to implement these sequences in a portable manner. This patch
> introduces a simple interpreter that can execute such power sequences
> encoded either as platform data or within the device tree.

Given there are several ARM platforms that may have an interest in this, please
consider posting this to the ARM mailing list:
linux-arm-kernel@lists.infradead.org.

> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> ---
>  .../devicetree/bindings/power/power_seq.txt        | 121 +++++++
>  Documentation/power/power_seq.txt                  | 253 ++++++++++++++
>  drivers/power/Kconfig                              |   1 +
>  drivers/power/Makefile                             |   1 +
>  drivers/power/power_seq/Kconfig                    |   2 +
>  drivers/power/power_seq/Makefile                   |   1 +
>  drivers/power/power_seq/power_seq.c                | 376 +++++++++++++++++++++
>  drivers/power/power_seq/power_seq_delay.c          |  65 ++++
>  drivers/power/power_seq/power_seq_gpio.c           |  94 ++++++
>  drivers/power/power_seq/power_seq_pwm.c            |  82 +++++
>  drivers/power/power_seq/power_seq_regulator.c      |  83 +++++
>  include/linux/power_seq.h                          | 203 +++++++++++
>  12 files changed, 1282 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/power_seq.txt
>  create mode 100644 Documentation/power/power_seq.txt
>  create mode 100644 drivers/power/power_seq/Kconfig
>  create mode 100644 drivers/power/power_seq/Makefile
>  create mode 100644 drivers/power/power_seq/power_seq.c
>  create mode 100644 drivers/power/power_seq/power_seq_delay.c
>  create mode 100644 drivers/power/power_seq/power_seq_gpio.c
>  create mode 100644 drivers/power/power_seq/power_seq_pwm.c
>  create mode 100644 drivers/power/power_seq/power_seq_regulator.c
>  create mode 100644 include/linux/power_seq.h
> 
> diff --git a/Documentation/devicetree/bindings/power/power_seq.txt b/Documentation/devicetree/bindings/power/power_seq.txt
> new file mode 100644
> index 0000000..7880a6c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/power_seq.txt
> @@ -0,0 +1,121 @@
> +Runtime Interpreted Power Sequences
> +=================> +
> +Power sequences are sequential descriptions of actions to be performed on
> +power-related resources. Having these descriptions in a well-defined data format
> +allows us to take much of the board- or device- specific power control code out
> +of the kernel and place it into the device tree instead, making kernels less
> +board-dependant.
> +
> +A device typically makes use of multiple power sequences, for different purposes
> +such as powering on and off. All the power sequences of a given device are
> +grouped into a set. In the device tree, this set is a sub-node of the device
> +node named "power-sequences".
> +
> +Power Sequences Structure
> +-------------------------
> +Every device that makes use of power sequences must have a "power-sequences"
> +node into which individual power sequences are declared as sub-nodes. The name
> +of the node becomes the name of the sequence within the power sequences
> +framework.
> +
> +Similarly, each power sequence declares its steps as sub-nodes of itself. Steps
> +must be named sequentially, with the first step named step0, the second step1,
> +etc. Failure to follow this rule will result in a parsing error.

Could we not encode the step number in the unit-address? i.e. step@N rather than
stepN.

If we ever add additional (non step) data to sequences it might make it easier
to filter, as we only reserve one name rather than a class of names.

> +
> +Power Sequences Steps
> +---------------------
> +Steps of a sequence describe an action to be performed on a resource. They
> +always include a "type" property which indicates what kind of resource this
> +step works on. Depending on the resource type, additional properties are defined
> +to control the action to be performed.
> +
> +"delay" type required properties:
> +  - delay: delay to wait (in microseconds)
> +
> +"regulator" type required properties:
> +  - id: name of the regulator to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"pwm" type required properties:
> +  - id: name of the PWM to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"gpio" type required properties:
> +  - gpio: phandle of the GPIO to use.
> +  - value: value this GPIO should take. Must be 0 or 1.

Is there any reason for id to be a name rather than a phandle? It seems
inconsistent with the gpio case.

I also see from the example below that the gpio property is not just a phandle,
as it has the gpio-specifier appended. Is there a better way of describing this
format in the documentation?

> +Example
> +-------
> +Here are example sequences declared within a backlight device that use all the
> +supported resources types:
> +
> +       backlight {
> +               compatible = "pwm-backlight";
> +               ...
> +
> +               /* resources used by the power sequences */
> +               pwms = <&pwm 2 5000000>;
> +               pwm-names = "backlight";
> +               power-supply = <&backlight_reg>;
> +
> +               power-sequences {
> +                       power-on {
> +                               step0 {
> +                                       type = "regulator";
> +                                       id = "power";
> +                                       enable;
> +                               };
> +                               step1 {
> +                                       type = "delay";
> +                                       delay = <10000>;
> +                               };
> +                               step2 {
> +                                       type = "pwm";
> +                                       id = "backlight";
> +                                       enable;
> +                               };
> +                               step3 {
> +                                       type = "gpio";
> +                                       gpio = <&gpio 28 0>;
> +                                       value = <1>;
> +                               };
> +                       };
> +
> +                       power-off {
> +                               step0 {
> +                                       type = "gpio";
> +                                       gpio = <&gpio 28 0>;
> +                                       value = <0>;
> +                               };
> +                               step1 {
> +                                       type = "pwm";
> +                                       id = "backlight";
> +                                       disable;
> +                               };
> +                               step2 {
> +                                       type = "delay";
> +                                       delay = <10000>;
> +                               };
> +                               step3 {
> +                                       type = "regulator";
> +                                       id = "power";
> +                                       disable;
> +                               };
> +                       };
> +               };
> +       };
 
Thanks,
Mark


^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Alex Courbot @ 2012-11-16  9:44 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: Stephen Warren, Thierry Reding, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org,
	devicetree-discuss@lists.ozlabs.org, linux-pm@vger.kernel.org,
	Alexandre Courbot
In-Reply-To: <20121116072642.GA22291@lizard>

On 11/16/2012 04:26 PM, Anton Vorontsov wrote:
>> +#include "power_seq_delay.c"
>> +#include "power_seq_regulator.c"
>> +#include "power_seq_pwm.c"
>> +#include "power_seq_gpio.c"
>
> This is odd, although I remember you already explained why you have to
> include the .c files, instead of linking them separately. But I forgot the
> reason. :) I think this deserves a comment in the code.

This is because of the table right after these includes:

static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
	[POWER_SEQ_DELAY] = POWER_SEQ_DELAY_TYPE,
	[POWER_SEQ_REGULATOR] = POWER_SEQ_REGULATOR_TYPE,
	[POWER_SEQ_PWM] = POWER_SEQ_PWM_TYPE,
	[POWER_SEQ_GPIO] = POWER_SEQ_GPIO_TYPE,
};

The POWER_SEQ_*_TYPE macros are defined in the C files. It's the 
simplest way to initialize this table, and the code inside these C files 
is short and simple enough that I thought I would be forgiven. :)

At first everything was in power_seq.c and it was fine, then I thought 
it would be better to move resource support code into their own filesm 
and now everybody is asking. :P

But yeah, maybe it would be even better to not stop halfway and use 
dynamic linking.

Comment added for the time being. ;)

>> +static int of_power_seq_parse_step(struct device *dev,
>> +				   struct device_node *node,
>> +				   struct power_seq *seq,
>> +				   unsigned int step_nbr,
>> +				   struct list_head *resources)
>> +{
>> +	struct power_seq_step *step = &seq->steps[step_nbr];
>> +	struct power_seq_resource res, *res2;
>> +	const char *type;
>> +	int i, err;
>
> nit: one variable declaration per line.

Fair enough - but is that a convention? checkpatch.pl was happy with these.

Thanks,
Alex.



^ permalink raw reply

* Re: [PATCH v8 2/3] pwm_backlight: use power sequences
From: Anton Vorontsov @ 2012-11-16  9:39 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Alexandre Courbot, Stephen Warren, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Alexandre Courbot
In-Reply-To: <20121116084958.GB20785-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>

On Fri, Nov 16, 2012 at 09:49:58AM +0100, Thierry Reding wrote:
> On Fri, Nov 16, 2012 at 03:38:22PM +0900, Alexandre Courbot wrote:
> > Make use of the power sequences specified in the device tree or platform
> > data to control how the backlight is powered on and off.
> > 
> > Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> > Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
> 
> Anton,
> 
> I would normally take pwm-backlight patches through the PWM tree, but
> since this patch depends on the first in this series, I think it would
> be easier if you took it through your tree along with the rest of the
> series. If that's okay with you:
> 
> Acked-by: Thierry Reding <thierry.reding@avionic-design.de>

Sure, I'll take it. Thank you!

^ permalink raw reply

* Re: [RFC] fbdev: arm has __raw I/O accessors, use them in fb.h
From: Tomi Valkeinen @ 2012-11-16  9:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1353057364-21214-1-git-send-email-archit@ti.com>

[-- Attachment #1: Type: text/plain, Size: 1192 bytes --]

On 2012-11-16 11:16, Archit Taneja wrote:
> This removes the sparse warnings on arm platforms:
> 
> warning: cast removes address space of expression
> 
> Signed-off-by: Archit Taneja <archit@ti.com>
> ---
>  include/linux/fb.h |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/linux/fb.h b/include/linux/fb.h
> index c7a9571..7fce1e1 100644
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -548,7 +548,7 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
>  #define fb_memcpy_fromfb sbus_memcpy_fromio
>  #define fb_memcpy_tofb sbus_memcpy_toio
>  
> -#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__) || defined(__bfin__)
> +#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__) || defined(__bfin__) || defined(__arm__)
>  
>  #define fb_readb __raw_readb
>  #define fb_readw __raw_readw

Looks good and works for me:

Acked-by: Tomi Valkeinen <tomi.valkeinen@ti.com>

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 897 bytes --]

^ permalink raw reply

* [RFC] fbdev: arm has __raw I/O accessors, use them in fb.h
From: Archit Taneja @ 2012-11-16  9:28 UTC (permalink / raw)
  To: linux-arm-kernel

This removes the sparse warnings on arm platforms:

warning: cast removes address space of expression

Signed-off-by: Archit Taneja <archit@ti.com>
---
 include/linux/fb.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/fb.h b/include/linux/fb.h
index c7a9571..7fce1e1 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -548,7 +548,7 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
 #define fb_memcpy_fromfb sbus_memcpy_fromio
 #define fb_memcpy_tofb sbus_memcpy_toio
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__) || defined(__bfin__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__) || defined(__bfin__) || defined(__arm__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH 0/5] OMAPFB: use dma_alloc instead of omap's vram
From: Tomi Valkeinen @ 2012-11-16  9:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121112225037.GU6801@atomide.com>

[-- Attachment #1: Type: text/plain, Size: 1826 bytes --]

Hi Tony,

On 2012-11-13 00:50, Tony Lindgren wrote:
> * Tomi Valkeinen <tomi.valkeinen@ti.com> [121112 02:27]:
>> Hi,
>>
>> This series changes omapfb to use standard dma_alloc funcs instead of omap
>> specific vram allocator. This let's us remove the omap vram allocator, making
>> omapfb platform independent.
>>
>> However, note that using standard dma funcs causes the following downsides:
>>
>> 1) dma_alloc_attrs doesn't let us allocate at certain physical address.
>> However, this should not be a problem as this feature of vram allocator
>> is only used when reserving the framebuffer that was initialized by the
>> bootloader, and we don't currently support "passing" a framebuffer from
>> the bootloader to the kernel anyway.
>>
>> 2) dma_alloc_attrs, as of now, always ioremaps the allocated area, and
>> we don't need the ioremap when using VRFB. This patch uses
>> DMA_ATTR_NO_KERNEL_MAPPING for the allocation, but the flag is currently
>> not operational.
>>
>> 3) OMAPFB_GET_VRAM_INFO ioctl cannot return real values anymore. I
>> changed the ioctl to return 64M for all the values, which, I hope, the
>> applications will interpret as "there's enough vram".
>>
>> 4) "vram" kernel parameter to define how much ram to reserve for video use no
>> longer works. The user needs to enable CMA and use "cma" parameter.
> 
> Great, thanks for fixing these. Could you please queue these into
> a separate branch against v3.7-rc5 that I can also merge into
> omap-for-v3.8/cleanup-headers-prepare-multiplatform-v3?

Should we enable CMA by default in omap2plus_defconfig? And perhaps on
omap1 also?

I have to say I don't know the details of the dma allocation, but afaik
there are no drawbacks with CMA. Although it is still marked
EXPERIMENTAL in the kconfig...

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 897 bytes --]

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Srinivas KANDAGATLA @ 2012-11-16  9:04 UTC (permalink / raw)
  To: Alex Courbot
  Cc: Alexandre Courbot,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Mark Brown,
	Stephen Warren, linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Leela Krishna Amudala,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	Mark Zhang, Rob Herring,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Anton Vorontsov,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	David Woodhouse
In-Reply-To: <4423025.WvVzNKlS3r@percival>

On 16/11/12 08:31, Alex Courbot wrote:
> Hi Srinivas,
>
> On Friday 16 November 2012 15:58:29 Srinivas KANDAGATLA wrote:
>> Hi Alex,
>> I am looking forward for this feature to be mainlined,
> *cough* Ack *cough* :)
:-)
>> but I have
>> comment on the way the types are tied up to power seq infrastructure.
>> I know your use case are limited to using type "delay", "pwm" and "gpio"
>> and "regulator", However there are instances where the devices can be
>> powered up or reset by writing to special registers or sysconfs or
>> something else.
>> So My suggestion would be to make these type register them selfs
>> dynamically with the power_seq infrastructure so that in future this can
>> be extended to other types as-well.
>> This trivial change can make a lot of difference for the future chips
>> which do thing bit differently.
>> ST Microelectronics chips fit it in these category and I guess other
>> Vendors have this similar chips.
> The current implementation is (purposedly) minimal and will certainly be 
> extended. There are other aspects of regulators for instance that should also 
> be controllable (voltage comes to mind). And I am totally open to supporting 
> new kinds of resources as usage broadens. For this first version I just wanted 
> to introduce the feature and minimize the impact should anything (DT 
> bindings?) need to change.
Ok I agree. I was thinking more of to fit few things specific to our
chip via power-seqs.
>
> I am a little bit skeptical about the purpose of directly accessing registers 
> (or any part of the address space) from power sequences. It should at least be 
> possible to involve some kind of abstraction. Not necessarily one of the 
> currently supported types - but at least something.
Yes, There is a level of abstraction (aka sysconf) in our case.. again
it is not mainlined yet.
>
> The reason is that I'd like to try and avoid direct references to resources 
> within sequences as much as possible to make them reusable. If your system has 
> two identical devices, you should not need to duplicate their sequences just 
> to change a register range from the few steps that make use of it. If you can 
> do the same job with, say, a regulator, you can just give it a name, get it at 
> runtime using regulator_get() and define it outside of the sequence, in our 
> device node.
>
> Of course there might be scenarios where you really need to access a register 
> and there is no way to do otherwise, in this case I am open to discussion. But 
> before resorting to this I'd like to make that the existing abstraction cannot 
> cover the case already.
yep.

thanks,
srini
>
> Alex.
>
>


^ permalink raw reply

* Re: [PATCH v10 1/6] video: add display_timing and videomode
From: Steffen Trumtrar @ 2012-11-16  8:53 UTC (permalink / raw)
  To: Grant Likely
  Cc: Laurent Pinchart, devicetree-discuss, linux-fbdev, dri-devel,
	Tomi Valkeinen, kernel, Guennady Liakhovetski, linux-media
In-Reply-To: <20121115180359.1E6F33E197F@localhost>

Hi Grant,

On Thu, Nov 15, 2012 at 06:03:59PM +0000, Grant Likely wrote:
> On Thu, 15 Nov 2012 17:00:57 +0100, Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> > Hi Grant,
> > 
> > On Thursday 15 November 2012 15:47:53 Grant Likely wrote:
> > > On Thu, 15 Nov 2012 10:23:52 +0100, Steffen Trumtrar wrote:
> > > > Add display_timing structure and the according helper functions. This
> > > > allows the description of a display via its supported timing parameters.
> > > > 
> > > > Every timing parameter can be specified as a single value or a range
> > > > <min typ max>.
> > > > 
> > > > Also, add helper functions to convert from display timings to a generic
> > > > videomode structure. This videomode can then be converted to the
> > > > corresponding subsystem mode representation (e.g. fb_videomode).
> > > > 
> > > > Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
> > > 
> > > Hmmm... here's my thoughts as an outside reviewer. Correct me if I'm
> > > making an incorrect assumption.
> > > 
> > > It looks to me that the purpose of this entire series is to decode video
> > > timings from the device tree and (eventually) provide the data in the
> > > form 'struct videomode'. Correct?
> > > 

For the time being it is straight from devicetree via struct videomode
to struct drm_display_mode or fb_videomode. Correct.

> > > If so, then it looks over engineered. Creating new infrastructure to
> > > allocate, maintain, and free a new 'struct display_timings' doesn't make
> > > any sense when it is an intermediary data format that will never be used
> > > by drivers.
> > > 
> > > Can the DT parsing code instead return a table of struct videomode?
> > > 

See below.

> > > But, wait... struct videomode is also a new structure. So it looks like
> > > this series creates two new intermediary data structures;
> > > display_timings and videomode. And at least as far as I can see in this
> > > series struct fb_videomode is the only user.

struct drm_display_mode is also a user in this series see 5/6 and 6/6.

> > 
> > struct videomode is supposed to slowly replace the various video mode 
> > structures we currently have in the kernel (struct drm_mode_modeinfo, struct 
> > fb_videomode and struct v4l2_bt_timings), at least where possible (userspace 
> > APIs can't be broken). This will make it possible to reuse code across the 
> > DRM, FB and V4L2 subsystems, such as the EDID parser or HDMI encoder drivers. 
> > This rationale might not be clearly explained in the commit message, but 
> > having a shared video mode structure is pretty important.
>

That.

> Okay that make sense. What about struct display_timings?
> 

The reason for defining an intermediary step is because of the different things
that are described:
- struct display_timing describes the signal ranges a display supports
- struct display_timings describes all timing settings of a display
- struct videomode describes one single mode generated from that settings

It is possible to generate multiple struct videomodes from one
struct display_timing based on the circumstances. And that is a task for the
driver using the display_timing infos. This means drivers are supposed to use
struct display_timings if they need to generate a struct videomode from the
timing ranges of one entry.
This is just the first step in that direction.
I hope this makes the need for struct display_timings a little clearer.
The other solution would be the one Laurent suggested and pass multiple values
around. Which in my opinion doesn't make it better, more practical or cleaner.


Regards,
Steffen

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* Re: [PATCH v8 2/3] pwm_backlight: use power sequences
From: Thierry Reding @ 2012-11-16  8:49 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Anton Vorontsov, Stephen Warren, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Alexandre Courbot
In-Reply-To: <1353047903-14363-3-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 772 bytes --]

On Fri, Nov 16, 2012 at 03:38:22PM +0900, Alexandre Courbot wrote:
> Make use of the power sequences specified in the device tree or platform
> data to control how the backlight is powered on and off.
> 
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>

Anton,

I would normally take pwm-backlight patches through the PWM tree, but
since this patch depends on the first in this series, I think it would
be easier if you took it through your tree along with the rest of the
series. If that's okay with you:

Acked-by: Thierry Reding <thierry.reding@avionic-design.de>

Otherwise just let me know and I'm sure we can coordinate to take this
in via the two trees separately.

Thanks,
Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v8 0/3] Runtime Interpreted Power Sequences
From: Thierry Reding @ 2012-11-16  8:44 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Anton Vorontsov, Stephen Warren, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Alexandre Courbot
In-Reply-To: <1353047903-14363-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 2691 bytes --]

On Fri, Nov 16, 2012 at 03:38:20PM +0900, Alexandre Courbot wrote:
> Hopefully the final series before the feature gets merged. Anton Vorontsov
> kindly accepted to take it into his tree, so this series is mostly a call for
> acks, tests and reviews notices before the merge window for 3.8 opens. If you
> are interested in seeing this feature, please add your name.
> 
> This series also adds an entry for the subsystem into MAINTAINERS, setting me as
> the person in charge.
> 
> Changes from v7:
> - fix bug reported by Tony Prisk
> - add MAINTAINERS entry
> 
> Alexandre Courbot (3):
>   Runtime Interpreted Power Sequences
>   pwm_backlight: use power sequences
>   Take maintainership of power sequences
> 
>  .../devicetree/bindings/power/power_seq.txt        | 121 +++++++
>  .../bindings/video/backlight/pwm-backlight.txt     |  63 +++-
>  Documentation/power/power_seq.txt                  | 253 ++++++++++++++
>  MAINTAINERS                                        |  10 +
>  drivers/power/Kconfig                              |   1 +
>  drivers/power/Makefile                             |   1 +
>  drivers/power/power_seq/Kconfig                    |   2 +
>  drivers/power/power_seq/Makefile                   |   1 +
>  drivers/power/power_seq/power_seq.c                | 376 +++++++++++++++++++++
>  drivers/power/power_seq/power_seq_delay.c          |  65 ++++
>  drivers/power/power_seq/power_seq_gpio.c           |  94 ++++++
>  drivers/power/power_seq/power_seq_pwm.c            |  82 +++++
>  drivers/power/power_seq/power_seq_regulator.c      |  83 +++++
>  drivers/video/backlight/Kconfig                    |   1 +
>  drivers/video/backlight/pwm_bl.c                   | 160 +++++++--
>  include/linux/power_seq.h                          | 203 +++++++++++
>  include/linux/pwm_backlight.h                      |  18 +-
>  17 files changed, 1494 insertions(+), 40 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/power/power_seq.txt
>  create mode 100644 Documentation/power/power_seq.txt
>  create mode 100644 drivers/power/power_seq/Kconfig
>  create mode 100644 drivers/power/power_seq/Makefile
>  create mode 100644 drivers/power/power_seq/power_seq.c
>  create mode 100644 drivers/power/power_seq/power_seq_delay.c
>  create mode 100644 drivers/power/power_seq/power_seq_gpio.c
>  create mode 100644 drivers/power/power_seq/power_seq_pwm.c
>  create mode 100644 drivers/power/power_seq/power_seq_regulator.c
>  create mode 100644 include/linux/power_seq.h

The series,

Tested-by: Thierry Reding <thierry.reding@avionic-design.de>
Acked-by: Thierry Reding <thierry.reding@avionic-design.de>

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Alex Courbot @ 2012-11-16  8:31 UTC (permalink / raw)
  To: srinivas.kandagatla-qxv4g6HH51o@public.gmane.org
  Cc: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann, Alexandre Courbot,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Leela Krishna Amudala,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <50A5F225.6000200-qxv4g6HH51o@public.gmane.org>

Hi Srinivas,

On Friday 16 November 2012 15:58:29 Srinivas KANDAGATLA wrote:
> Hi Alex,
> I am looking forward for this feature to be mainlined,

*cough* Ack *cough* :)

> but I have
> comment on the way the types are tied up to power seq infrastructure.
> I know your use case are limited to using type "delay", "pwm" and "gpio"
> and "regulator", However there are instances where the devices can be
> powered up or reset by writing to special registers or sysconfs or
> something else.
> So My suggestion would be to make these type register them selfs
> dynamically with the power_seq infrastructure so that in future this can
> be extended to other types as-well.
> This trivial change can make a lot of difference for the future chips
> which do thing bit differently.
> ST Microelectronics chips fit it in these category and I guess other
> Vendors have this similar chips.

The current implementation is (purposedly) minimal and will certainly be 
extended. There are other aspects of regulators for instance that should also 
be controllable (voltage comes to mind). And I am totally open to supporting 
new kinds of resources as usage broadens. For this first version I just wanted 
to introduce the feature and minimize the impact should anything (DT 
bindings?) need to change.

I am a little bit skeptical about the purpose of directly accessing registers 
(or any part of the address space) from power sequences. It should at least be 
possible to involve some kind of abstraction. Not necessarily one of the 
currently supported types - but at least something.

The reason is that I'd like to try and avoid direct references to resources 
within sequences as much as possible to make them reusable. If your system has 
two identical devices, you should not need to duplicate their sequences just 
to change a register range from the few steps that make use of it. If you can 
do the same job with, say, a regulator, you can just give it a name, get it at 
runtime using regulator_get() and define it outside of the sequence, in our 
device node.

Of course there might be scenarios where you really need to access a register 
and there is no way to do otherwise, in this case I am open to discussion. But 
before resorting to this I'd like to make that the existing abstraction cannot 
cover the case already.

Alex.


^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Srinivas KANDAGATLA @ 2012-11-16  7:58 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann, Alexandre Courbot, linux-fbdev, linux-pm,
	Leela Krishna Amudala, devicetree-discuss, linux-kernel,
	linux-tegra
In-Reply-To: <1353047903-14363-2-git-send-email-acourbot@nvidia.com>

Hi Alex,
I am looking forward for this feature to be mainlined, but I have
comment on the way the types are tied up to power seq infrastructure.
I know your use case are limited to using type "delay", "pwm" and "gpio"
and "regulator", However there are instances where the devices can be
powered up or reset by writing to special registers or sysconfs or
something else.
So My suggestion would be to make these type register them selfs
dynamically with the power_seq infrastructure so that in future this can
be extended to other types as-well.
This trivial change can make a lot of difference for the future chips
which do thing bit differently.
ST Microelectronics chips fit it in these category and I guess other
Vendors have this similar chips.

What do you think?


Thanks,
srini

On 16/11/12 06:38, Alexandre Courbot wrote:
> Some device drivers (e.g. panel or backlights) need to follow precise
> sequences for powering on and off, involving GPIOs, regulators, PWMs
> with a precise powering order and delays to respect between steps.
> These sequences are device-specific, and do not belong to a particular
> driver - therefore they have been performed by board-specific hook
> functions to far.
>
> With the advent of the device tree and of ARM kernels that are not
> board-tied, we cannot rely on these board-specific hooks anymore but
> need a way to implement these sequences in a portable manner. This patch
> introduces a simple interpreter that can execute such power sequences
> encoded either as platform data or within the device tree.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> ---
>  .../devicetree/bindings/power/power_seq.txt        | 121 +++++++
>  Documentation/power/power_seq.txt                  | 253 ++++++++++++++
>  drivers/power/Kconfig                              |   1 +
>  drivers/power/Makefile                             |   1 +
>  drivers/power/power_seq/Kconfig                    |   2 +
>  drivers/power/power_seq/Makefile                   |   1 +
>  drivers/power/power_seq/power_seq.c                | 376 +++++++++++++++++++++
>  drivers/power/power_seq/power_seq_delay.c          |  65 ++++
>  drivers/power/power_seq/power_seq_gpio.c           |  94 ++++++
>  drivers/power/power_seq/power_seq_pwm.c            |  82 +++++
>  drivers/power/power_seq/power_seq_regulator.c      |  83 +++++
>  include/linux/power_seq.h                          | 203 +++++++++++
>  12 files changed, 1282 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/power_seq.txt
>  create mode 100644 Documentation/power/power_seq.txt
>  create mode 100644 drivers/power/power_seq/Kconfig
>  create mode 100644 drivers/power/power_seq/Makefile
>  create mode 100644 drivers/power/power_seq/power_seq.c
>  create mode 100644 drivers/power/power_seq/power_seq_delay.c
>  create mode 100644 drivers/power/power_seq/power_seq_gpio.c
>  create mode 100644 drivers/power/power_seq/power_seq_pwm.c
>  create mode 100644 drivers/power/power_seq/power_seq_regulator.c
>  create mode 100644 include/linux/power_seq.h
>
> diff --git a/Documentation/devicetree/bindings/power/power_seq.txt b/Documentation/devicetree/bindings/power/power_seq.txt
> new file mode 100644
> index 0000000..7880a6c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/power_seq.txt
> @@ -0,0 +1,121 @@
> +Runtime Interpreted Power Sequences
> +=================> +
> +Power sequences are sequential descriptions of actions to be performed on
> +power-related resources. Having these descriptions in a well-defined data format
> +allows us to take much of the board- or device- specific power control code out
> +of the kernel and place it into the device tree instead, making kernels less
> +board-dependant.
> +
> +A device typically makes use of multiple power sequences, for different purposes
> +such as powering on and off. All the power sequences of a given device are
> +grouped into a set. In the device tree, this set is a sub-node of the device
> +node named "power-sequences".
> +
> +Power Sequences Structure
> +-------------------------
> +Every device that makes use of power sequences must have a "power-sequences"
> +node into which individual power sequences are declared as sub-nodes. The name
> +of the node becomes the name of the sequence within the power sequences
> +framework.
> +
> +Similarly, each power sequence declares its steps as sub-nodes of itself. Steps
> +must be named sequentially, with the first step named step0, the second step1,
> +etc. Failure to follow this rule will result in a parsing error.
> +
> +Power Sequences Steps
> +---------------------
> +Steps of a sequence describe an action to be performed on a resource. They
> +always include a "type" property which indicates what kind of resource this
> +step works on. Depending on the resource type, additional properties are defined
> +to control the action to be performed.
> +
> +"delay" type required properties:
> +  - delay: delay to wait (in microseconds)
> +
> +"regulator" type required properties:
> +  - id: name of the regulator to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"pwm" type required properties:
> +  - id: name of the PWM to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"gpio" type required properties:
> +  - gpio: phandle of the GPIO to use.
> +  - value: value this GPIO should take. Must be 0 or 1.
> +
> +Example
> +-------
> +Here are example sequences declared within a backlight device that use all the
> +supported resources types:
> +
> +	backlight {
> +		compatible = "pwm-backlight";
> +		...
> +
> +		/* resources used by the power sequences */
> +		pwms = <&pwm 2 5000000>;
> +		pwm-names = "backlight";
> +		power-supply = <&backlight_reg>;
> +
> +		power-sequences {
> +			power-on {
> +				step0 {
> +					type = "regulator";
> +					id = "power";
> +					enable;
> +				};
> +				step1 {
> +					type = "delay";
> +					delay = <10000>;
> +				};
> +				step2 {
> +					type = "pwm";
> +					id = "backlight";
> +					enable;
> +				};
> +				step3 {
> +					type = "gpio";
> +					gpio = <&gpio 28 0>;
> +					value = <1>;
> +				};
> +			};
> +
> +			power-off {
> +				step0 {
> +					type = "gpio";
> +					gpio = <&gpio 28 0>;
> +					value = <0>;
> +				};
> +				step1 {
> +					type = "pwm";
> +					id = "backlight";
> +					disable;
> +				};
> +				step2 {
> +					type = "delay";
> +					delay = <10000>;
> +				};
> +				step3 {
> +					type = "regulator";
> +					id = "power";
> +					disable;
> +				};
> +			};
> +		};
> +	};
> +
> +The first part lists the PWM and regulator resources used by the sequences.
> +These resources will be requested on behalf of the backlight device when the
> +sequences are built and are declared according to their own bindings (for
> +instance, regulators and pwms are resolved by name - note though that name
> +declaration is done differently by the two frameworks).
> +
> +After the resources declaration, two sequences follow for powering the backlight
> +on and off. Their names are specified by the pwm-backlight device bindings. Once
> +the sequences are built by calling devm_of_parse_power_seq_set() on the
> +backlight device, they can be added to a set using
> +power_seq_set_add_sequences().
> diff --git a/Documentation/power/power_seq.txt b/Documentation/power/power_seq.txt
> new file mode 100644
> index 0000000..8be0570
> --- /dev/null
> +++ b/Documentation/power/power_seq.txt
> @@ -0,0 +1,253 @@
> +Runtime Interpreted Power Sequences
> +=================> +
> +Problem
> +-------
> +Very commonly, boards need the help of out-of-driver code to turn some of their
> +devices on and off. For instance, SoC boards might use a GPIO (abstracted to a
> +regulator or not) to control the power supply of a backlight. The GPIO that
> +should be used, however, as well as the exact power sequence that may also
> +involve other resources, is board-dependent and thus unknown to the driver.
> +
> +This was previously addressed by having hooks in the device's platform data that
> +are called whenever the state of the device might need a power status change.
> +This approach, however, introduces board-dependant code into the kernel and is
> +not compatible with the device tree.
> +
> +The Runtime Interpreted Power Sequences (or power sequences for short) aim at
> +turning this code into platform data or device tree nodes. Power sequences are
> +described using a simple format and run by a lightweight interpreter whenever
> +needed. This allows device drivers to work without power callbacks and makes the
> +kernel less board-dependant.
> +
> +What are Power Sequences?
> +-------------------------
> +A power sequence is an array of sequential steps describing an action to be
> +performed on a resource. The supported resources and actions operations are:
> +- delay (just wait for a given number of microseconds)
> +- GPIO (set to 0 or 1)
> +- regulator (enable or disable)
> +- PWM (enable or disable)
> +
> +When a power sequence is run, its steps is executed one after the other until
> +one step fails or the end of the sequence is reached.
> +
> +Power sequences are named, and grouped into "sets" which contain all the
> +sequences of a device as well as the resources they use.
> +
> +Power sequences can be declared as platform data or in the device tree.
> +
> +Platform Data Format
> +--------------------
> +All relevant data structures for declaring power sequences are located in
> +include/linux/power_seq.h.
> +
> +The platform data for a device may include an instance of platform_power_seq_set
> +which references all the power sequences used for a device. The power sequences
> +reference resources in their steps, and setup the union member that corresponds
> +to the resource's type. Resources, similarly, have a union which relevant member
> +depends on their type.
> +
> +Note that the only "platform data" per se here is platform_power_seq_set. Other
> +structures (power_seq and power_seq_resource) will be used at runtime and thus
> +*must* survive initialization, so do not declare them with the __initdata
> +attribute.
> +
> +The following example should make it clear how the platform data for power
> +sequences is defined. It declares two power sequences named "power-on" and
> +"power-off" for a backlight device. The "power-on" sequence enables the "power"
> +regulator of the device, waits for 10ms, and then enables PWM "backlight" and
> +set GPIO 28 to 1. "power-off" does the opposite.
> +
> +struct power_seq_resource reg_res = {
> +	.type = POWER_SEQ_REGULATOR,
> +	.regulator.id = "power",
> +};
> +
> +struct power_seq_resource gpio_res = {
> +	.type = POWER_SEQ_GPIO,
> +	.gpio.gpio = 28,
> +};
> +
> +struct power_seq_resource pwm_res = {
> +	.type = POWER_SEQ_PWM,
> +	.pwm.id = "backlight",
> +};
> +
> +struct power_seq_resource delay_res = {
> +	.type = POWER_SEQ_DELAY,
> +};
> +
> +struct power_seq power_on_seq = {
> +	.id = "power-on",
> +	.num_steps = 4,
> +	.steps = {
> +		{
> +			.resource = &reg_res,
> +			.regulator.enable = true,
> +		}, {
> +			.resource = &delay_res,
> +			.delay.delay = 10000,
> +		}, {
> +			.resource = &pwm_res,
> +			.pwm.enable = true,
> +		}, {
> +			.resource = &gpio_res,
> +			.gpio.value = 1,
> +		},
> +	},
> +};
> +
> +struct power_seq power_off_seq = {
> +	.id = "power-off",
> +	.num_steps = 4,
> +	.steps = {
> +		{
> +			.resource = &gpio_res,
> +			.gpio.value = 0,
> +		}, {
> +			.resource = &pwm_res,
> +			.pwm.enable = false,
> +		}, {
> +			.resource = &delay_res,
> +			.delay.delay = 10000,
> +		}, {
> +			.resource = &reg_res,
> +			.regulator.enable = false,
> +		},
> +	},
> +};
> +
> +struct platform_power_seq_set backlight_power_seqs __initdata = {
> +	.num_seqs = 2,
> +	.seqs = {
> +		&power_on_seq,
> +		&power_off_seq,
> +	},
> +};
> +
> +"backlight_power_seqs" can then be passed to power_seq_set_add_sequences() in
> +order to add the sequences to a set and allocate all the necessary resources.
> +More on this later in this document.
> +
> +Device Tree
> +-----------
> +Power sequences can also be encoded as device tree nodes. The following
> +properties and nodes are equivalent to the platform data defined previously:
> +
> +pwms = <&pwm 2 5000000>;
> +pwm-names = "backlight";
> +power-supply = <&vdd_bl_reg>;
> +
> +power-sequences {
> +	power-on {
> +		step0 {
> +			type = "regulator";
> +			id = "power";
> +			enable;
> +		};
> +		step1 {
> +			type = "delay";
> +			delay = <10000>;
> +		};
> +		step2 {
> +			type = "pwm";
> +			id = "backlight";
> +			enable;
> +		};
> +		step3 {
> +			type = "gpio";
> +			gpio = <&gpio 28 0>;
> +			value = <1>;
> +		};
> +	};
> +
> +	power-off {
> +		step0 {
> +			type = "gpio";
> +			gpio = <&gpio 28 0>;
> +			value = <0>;
> +		};
> +		step1 {
> +			type = "pwm";
> +			id = "backlight";
> +			disable;
> +		};
> +		step2 {
> +			type = "delay";
> +			delay = <10000>;
> +		};
> +		step3 {
> +			type = "regulator";
> +			id = "power";
> +			disable;
> +		};
> +	};
> +};
> +
> +See Documentation/devicetree/bindings/power/power_seq.txt for the complete
> +syntax of the DT bindings.
> +
> +Use by Drivers and Resources Management
> +---------------------------------------
> +Power sequences make use of resources that must be properly allocated and
> +managed. The power_seq_set structure manages the sequences and resources for a
> +particular device. A driver willing to use power sequences will thus declare one
> +instance of power_seq_set per device and initialize it at probe time:
> +
> +struct my_device_data {
> +	struct device *dev;
> +	...
> +	struct power_set_set power_seqs;
> +	...
> +};
> +
> +power_seq_set_init(&my_device->power_seqs, my_device->dev);
> +
> +The power_seq_set_add_sequence() and power_seq_set_add_sequences() functions are
> +then used to add one or several sequences to a set. These functions will also
> +allocate all the resources used by the sequence(s) and make sure they are ready
> +to be run. All resources are allocated through devm and will thus be freed when
> +the set's device is removed.
> +
> +  int power_seq_set_add_sequence(struct power_seq_set *set,
> +			         struct power_seq *seq);
> +  int power_seq_set_add_sequences(struct power_seq_set *set,
> +				  struct platform_power_seq_set *seqs);
> +
> +Power sequences added to a set can then be resolved by their name using
> +power_seq_lookup():
> +
> +  struct power_seq *power_seq_lookup(struct power_seq_set *seqs,
> +				     const char *id);
> +
> +power_seq_lookup() returns a ready-to-run pointer to the power sequence which
> +name matches the id parameter.
> +
> +A retrieved power sequence can then be executed by power_seq_run:
> +
> +  int power_seq_run(struct power_seq *seq);
> +
> +It returns 0 if the sequence has successfully been run, or an error code if a
> +problem occurred.
> +
> +Sometimes, you may want to browse the list of resources allocated for the
> +sequences of a device, for instance to ensure that a resource of a given type is
> +present. The power_seq_for_each_resource() macro does this:
> +
> +  power_seq_for_each_resource(pos, seqs)
> +
> +Here "pos" will be a pointer to a struct power_seq_resource. This structure
> +contains the type of the resource, the information used for identifying it, and
> +the resolved resource itself.
> +
> +Finally, users of the device tree can obtain a platform_power_seq_set structure
> +built from the device's node using devm_of_parse_power_seq_set:
> +
> +  struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
> +
> +The power sequences must be declared under a "power-sequences" node directly
> +declared under the device's node. Detailed syntax contained in Documentation/devicetree/bindings/power/power_seq.txt. As the function name
> +states, all memory is allocated through devm. The returned
> +platform_power_seq_set can be freed after being added to a set, but the
> +sequences themselves must be preserved until they are freed by devm.
> \ No newline at end of file
> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
> index 49a8939..f20d449 100644
> --- a/drivers/power/Kconfig
> +++ b/drivers/power/Kconfig
> @@ -338,3 +338,4 @@ config AB8500_BATTERY_THERM_ON_BATCTRL
>  endif # POWER_SUPPLY
>  
>  source "drivers/power/avs/Kconfig"
> +source "drivers/power/power_seq/Kconfig"
> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
> index b949cf8..883ad4d 100644
> --- a/drivers/power/Makefile
> +++ b/drivers/power/Makefile
> @@ -49,3 +49,4 @@ obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
>  obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
>  obj-$(CONFIG_POWER_AVS)		+= avs/
>  obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
> +obj-$(CONFIG_POWER_SEQ)		+= power_seq/
> diff --git a/drivers/power/power_seq/Kconfig b/drivers/power/power_seq/Kconfig
> new file mode 100644
> index 0000000..3bff26e
> --- /dev/null
> +++ b/drivers/power/power_seq/Kconfig
> @@ -0,0 +1,2 @@
> +config POWER_SEQ
> +	bool
> diff --git a/drivers/power/power_seq/Makefile b/drivers/power/power_seq/Makefile
> new file mode 100644
> index 0000000..f77a359
> --- /dev/null
> +++ b/drivers/power/power_seq/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_POWER_SEQ)		+= power_seq.o
> diff --git a/drivers/power/power_seq/power_seq.c b/drivers/power/power_seq/power_seq.c
> new file mode 100644
> index 0000000..255b1a0
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq.c
> @@ -0,0 +1,376 @@
> +/*
> + * power_seq.c - power sequence interpreter for platform devices and device tree
> + *
> + * Author: Alexandre Courbot <acourbot@nvidia.com>
> + *
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * 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.
> + *
> + */
> +
> +#include <linux/power_seq.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/device.h>
> +
> +#include <linux/of.h>
> +
> +#define power_seq_err(seq, step_nbr, format, ...)			\
> +	dev_err(seq->set->dev, "%s[%d]: " format, seq->id, step_nbr,	\
> +	##__VA_ARGS__);
> +
> +/**
> + * struct power_seq_res_ops - operators for power sequences resources
> + * @name:		Name of the resource type. Set to null when a resource
> + *			type support is not compiled in
> + * @of_parse:		Parse a step for this kind of resource from a device
> + *			tree node. The result of parsing must be written into
> + *			step step_nbr of seq
> + * @step_run:		Run a step for this kind of resource
> + * @res_compare:	Return true if the resource used by the resource is the
> + *			same as the one referenced by the step, false otherwise.
> + * @res_alloc:		Resolve and allocate a resource. Return error code if
> + *			the resource cannot be allocated, 0 otherwise
> + */
> +struct power_seq_res_ops {
> +	const char *name;
> +	int (*of_parse)(struct device_node *node, struct power_seq *seq,
> +			unsigned int step_nbr, struct power_seq_resource *res);
> +	int (*step_run)(struct power_seq_step *step);
> +	bool (*res_compare)(struct power_seq_resource *res,
> +			    struct power_seq_resource *res2);
> +	int (*res_alloc)(struct device *dev,
> +			 struct power_seq_resource *res);
> +};
> +
> +static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES];
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_enable_properties(struct device_node *node,
> +						struct power_seq *seq,
> +						unsigned int step_nbr,
> +						bool *enable)
> +{
> +	if (of_find_property(node, "enable", NULL)) {
> +		*enable = true;
> +	} else if (of_find_property(node, "disable", NULL)) {
> +		*enable = false;
> +	} else {
> +		power_seq_err(seq, step_nbr,
> +			      "missing enable or disable property\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int of_power_seq_parse_step(struct device *dev,
> +				   struct device_node *node,
> +				   struct power_seq *seq,
> +				   unsigned int step_nbr,
> +				   struct list_head *resources)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	struct power_seq_resource res, *res2;
> +	const char *type;
> +	int i, err;
> +
> +	err = of_property_read_string(node, "type", &type);
> +	if (err < 0) {
> +		power_seq_err(seq, step_nbr, "cannot read type property\n");
> +		return err;
> +	}
> +	for (i = 0; i < POWER_SEQ_NUM_TYPES; i++) {
> +		if (power_seq_ops[i].name = NULL)
> +			continue;
> +		if (!strcmp(type, power_seq_ops[i].name))
> +			break;
> +	}
> +	if (i >= POWER_SEQ_NUM_TYPES) {
> +		power_seq_err(seq, step_nbr, "unknown type %s\n", type);
> +		return -EINVAL;
> +	}
> +	memset(&res, 0, sizeof(res));
> +	res.type = i;
> +	err = power_seq_ops[res.type].of_parse(node, seq, step_nbr, &res);
> +	if (err < 0)
> +		return err;
> +
> +	/* Use the same instance of the resource if met before */
> +	list_for_each_entry(res2, resources, list) {
> +		if (res.type = res2->type &&
> +		    power_seq_ops[res.type].res_compare(&res, res2))
> +			break;
> +	}
> +	/* Resource never met before, create it */
> +	if (&res2->list = resources) {
> +		res2 = devm_kzalloc(dev, sizeof(*res2), GFP_KERNEL);
> +		if (!res2)
> +			return -ENOMEM;
> +		memcpy(res2, &res, sizeof(res));
> +		list_add_tail(&res2->list, resources);
> +	}
> +	step->resource = res2;
> +
> +	return 0;
> +}
> +
> +static struct power_seq *of_parse_power_seq(struct device *dev,
> +					    struct device_node *node,
> +					    struct list_head *resources)
> +{
> +	struct device_node *child = NULL;
> +	struct power_seq *pseq;
> +	int num_steps, sz;
> +	int err;
> +
> +	if (!node)
> +		return ERR_PTR(-EINVAL);
> +
> +	num_steps = of_get_child_count(node);
> +	sz = sizeof(*pseq) + sizeof(pseq->steps[0]) * num_steps;
> +	pseq = devm_kzalloc(dev, sz, GFP_KERNEL);
> +	if (!pseq)
> +		return ERR_PTR(-ENOMEM);
> +	pseq->id = node->name;
> +	pseq->num_steps = num_steps;
> +
> +	for_each_child_of_node(node, child) {
> +		unsigned int pos;
> +
> +		/* Check that the name's format is correct and within bounds */
> +		if (strncmp("step", child->name, 4)) {
> +			err = -EINVAL;
> +			goto parse_error;
> +		}
> +
> +		err = kstrtouint(child->name + 4, 10, &pos);
> +		if (err < 0)
> +			goto parse_error;
> +
> +		/* Invalid step index or step already parsed? */
> +		if (pos >= num_steps || pseq->steps[pos].resource != NULL) {
> +			err = -EINVAL;
> +			goto parse_error;
> +		}
> +
> +		err = of_power_seq_parse_step(dev, child, pseq, pos, resources);
> +		if (err)
> +			return ERR_PTR(err);
> +	}
> +
> +	return pseq;
> +
> +parse_error:
> +	dev_err(dev, "%s: invalid power step name %s!\n", pseq->id,
> +		child->name);
> +	return ERR_PTR(err);
> +}
> +
> +/**
> + * devm_of_parse_power_seq_set - build a power_seq_set from the device tree
> + * @dev:	Device to parse the power sequences of
> + *
> + * Sequences must be contained into a subnode named "power-sequences" of the
> + * device root node.
> + *
> + * Memory for the sequence is allocated using devm_kzalloc on dev. The returned
> + * platform_power_seq_set can be freed by devm_kfree after the sequences have
> + * been added, but the sequences themselves must be preserved.
> + *
> + * Returns the built set on success, or an error code in case of failure.
> + */
> +struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev)
> +{
> +	struct platform_power_seq_set *set;
> +	struct device_node *root = dev->of_node;
> +	struct device_node *seq;
> +	struct list_head resources;
> +	int n, sz;
> +
> +	if (!root)
> +		return NULL;
> +
> +	root = of_find_node_by_name(root, "power-sequences");
> +	if (!root)
> +		return NULL;
> +
> +	n = of_get_child_count(root);
> +	sz = sizeof(*set) + sizeof(struct power_seq *) * n;
> +	set = devm_kzalloc(dev, sz, GFP_KERNEL);
> +	if (!set)
> +		return ERR_PTR(-ENOMEM);
> +	set->num_seqs = n;
> +
> +	n = 0;
> +	INIT_LIST_HEAD(&resources);
> +	for_each_child_of_node(root, seq) {
> +		struct power_seq *pseq;
> +
> +		pseq = of_parse_power_seq(dev, seq, &resources);
> +		if (IS_ERR(pseq))
> +			return (void *)pseq;
> +
> +		set->seqs[n++] = pseq;
> +	}
> +
> +	return set;
> +}
> +EXPORT_SYMBOL_GPL(devm_of_parse_power_seq_set);
> +#endif /* CONFIG_OF */
> +
> +/**
> + * power_seq_set_init - initialize a power_seq_set
> + * @set:	Set to initialize
> + * @dev:	Device this set is going to belong to
> + */
> +void power_seq_set_init(struct power_seq_set *set, struct device *dev)
> +{
> +	set->dev = dev;
> +	INIT_LIST_HEAD(&set->resources);
> +	INIT_LIST_HEAD(&set->seqs);
> +}
> +EXPORT_SYMBOL_GPL(power_seq_set_init);
> +
> +/**
> + * power_seq_add_sequence - add a power sequence to a set
> + * @set:	Set to add the sequence to
> + * @seq:	Sequence to add
> + *
> + * This step will check that all the resources used by the sequence are
> + * allocated. If they are not, an attempt to allocate them is made. This
> + * operation can fail and and return an error code.
> + *
> + * Returns 0 on success, error code if a resource initialization failed.
> + */
> +int power_seq_add_sequence(struct power_seq_set *set, struct power_seq *seq)
> +{
> +	struct power_seq_resource *res;
> +	int i, err;
> +
> +	for (i = 0; i < seq->num_steps; i++) {
> +		struct power_seq_step *step = &seq->steps[i];
> +		struct power_seq_resource *step_res = step->resource;
> +		list_for_each_entry(res, &set->resources, list) {
> +			if (res = step_res)
> +				break;
> +		}
> +		/* resource not allocated yet, allocate and add it */
> +		if (&res->list = &set->resources) {
> +			err = power_seq_ops[step_res->type].res_alloc(set->dev,
> +								      step_res);
> +			if (err)
> +				return err;
> +			list_add_tail(&step->resource->list, &set->resources);
> +		}
> +	}
> +
> +	list_add_tail(&seq->list, &set->seqs);
> +	seq->set = set;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(power_seq_add_sequence);
> +
> +/**
> + * power_seq_add_sequences - add power sequences defined as platform data
> + * @set:	Set to add the sequences to
> + * @seqs:	Sequences to add
> + *
> + * See power_seq_add_sequence for more details.
> + *
> + * Returns 0 on success, error code if a resource initialization failed.
> + */
> +int power_seq_set_add_sequences(struct power_seq_set *set,
> +				struct platform_power_seq_set *seqs)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < seqs->num_seqs; i++) {
> +		ret = power_seq_add_sequence(set, seqs->seqs[i]);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(power_seq_set_add_sequences);
> +
> +/**
> + * power_seq_lookup - Lookup a power sequence by name from a set
> + * @seqs:	The set to look in
> + * @id:		Name to look after
> + *
> + * Returns a matching power sequence if it exists, NULL if it does not.
> + */
> +struct power_seq *power_seq_lookup(struct power_seq_set *set, const char *id)
> +{
> +	struct power_seq *seq;
> +
> +	list_for_each_entry(seq, &set->seqs, list) {
> +		if (!strcmp(seq->id, id))
> +			return seq;
> +	}
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(power_seq_lookup);
> +
> +/**
> + * power_seq_run() - run a power sequence
> + * @seq:	The power sequence to run
> + *
> + * Returns 0 on success, error code in case of failure.
> + */
> +int power_seq_run(struct power_seq *seq)
> +{
> +	unsigned int i;
> +	int err;
> +
> +	if (!seq)
> +		return 0;
> +
> +	if (!seq->set) {
> +		pr_err("cannot run a sequence not added to a set");
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < seq->num_steps; i++) {
> +		unsigned int type = seq->steps[i].resource->type;
> +
> +		err = power_seq_ops[type].step_run(&seq->steps[i]);
> +		if (err) {
> +			power_seq_err(seq, i,
> +				"error %d while running power sequence step\n",
> +				err);
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(power_seq_run);
> +
> +#include "power_seq_delay.c"
> +#include "power_seq_regulator.c"
> +#include "power_seq_pwm.c"
> +#include "power_seq_gpio.c"
> +
> +static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
> +	[POWER_SEQ_DELAY] = POWER_SEQ_DELAY_TYPE,
> +	[POWER_SEQ_REGULATOR] = POWER_SEQ_REGULATOR_TYPE,
> +	[POWER_SEQ_PWM] = POWER_SEQ_PWM_TYPE,
> +	[POWER_SEQ_GPIO] = POWER_SEQ_GPIO_TYPE,
> +};
> +
> +MODULE_AUTHOR("Alexandre Courbot <acourbot@nvidia.com>");
> +MODULE_DESCRIPTION("Runtime Interpreted Power Sequences");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/power/power_seq/power_seq_delay.c b/drivers/power/power_seq/power_seq_delay.c
> new file mode 100644
> index 0000000..5bb0a46
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq_delay.c
> @@ -0,0 +1,65 @@
> +/*
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * 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.
> + *
> + */
> +
> +#include <linux/delay.h>
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_delay(struct device_node *node,
> +				    struct power_seq *seq,
> +				    unsigned int step_nbr,
> +				    struct power_seq_resource *res)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	int err;
> +
> +	err = of_property_read_u32(node, "delay",
> +				   &step->delay.delay);
> +	if (err < 0)
> +		power_seq_err(seq, step_nbr, "error reading delay property\n");
> +
> +	return err;
> +}
> +#else
> +#define of_power_seq_parse_delay NULL
> +#endif
> +
> +static bool power_seq_res_compare_delay(struct power_seq_resource *res,
> +					struct power_seq_resource *res2)
> +{
> +	/* Delay resources are just here to hold the type of steps, so they are
> +	 * all equivalent. */
> +	return true;
> +}
> +
> +static int power_seq_res_alloc_delay(struct device *dev,
> +				     struct power_seq_resource *res)
> +{
> +	return 0;
> +}
> +
> +static int power_seq_step_run_delay(struct power_seq_step *step)
> +{
> +	usleep_range(step->delay.delay,
> +		     step->delay.delay + 1000);
> +
> +	return 0;
> +}
> +
> +#define POWER_SEQ_DELAY_TYPE {				\
> +	.name = "delay",				\
> +	.of_parse = of_power_seq_parse_delay,		\
> +	.step_run = power_seq_step_run_delay,		\
> +	.res_compare = power_seq_res_compare_delay,	\
> +	.res_alloc = power_seq_res_alloc_delay,		\
> +}
> diff --git a/drivers/power/power_seq/power_seq_gpio.c b/drivers/power/power_seq/power_seq_gpio.c
> new file mode 100644
> index 0000000..028a4cc
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq_gpio.c
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * 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.
> + *
> + */
> +
> +#include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_gpio(struct device_node *node,
> +				   struct power_seq *seq,
> +				   unsigned int step_nbr,
> +				   struct power_seq_resource *res)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	int gpio;
> +	int err;
> +
> +	gpio = of_get_named_gpio(node, "gpio", 0);
> +	if (gpio < 0) {
> +		power_seq_err(seq, step_nbr, "error reading gpio property\n");
> +		return gpio;
> +	}
> +	res->gpio.gpio = gpio;
> +
> +	err = of_property_read_u32(node, "value", &step->gpio.value);
> +	if (err < 0) {
> +		power_seq_err(seq, step_nbr, "error reading value property\n");
> +	} else if (step->gpio.value < 0 || step->gpio.value > 1) {
> +		power_seq_err(seq, step_nbr,
> +			      "value out of range (must be 0 or 1)\n");
> +		err = -EINVAL;
> +	}
> +
> +	return err;
> +}
> +#else
> +#define of_power_seq_parse_gpio NULL
> +#endif
> +
> +static bool power_seq_res_compare_gpio(struct power_seq_resource *res,
> +				       struct power_seq_resource *res2)
> +{
> +	return res->gpio.gpio = res2->gpio.gpio;
> +}
> +
> +static int power_seq_res_alloc_gpio(struct device *dev,
> +				    struct power_seq_resource *res)
> +{
> +	int err;
> +
> +	err = devm_gpio_request(dev, res->gpio.gpio, dev_name(dev));
> +	if (err) {
> +		dev_err(dev, "cannot get gpio %d\n", res->gpio.gpio);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int power_seq_step_run_gpio(struct power_seq_step *step)
> +{
> +	struct power_seq_resource *res = step->resource;
> +
> +	/* set the GPIO direction at first use */
> +	if (!res->gpio.is_set) {
> +		int err = gpio_direction_output(res->gpio.gpio,
> +						step->gpio.value);
> +		if (err)
> +			return err;
> +		res->gpio.is_set = true;
> +	} else {
> +		gpio_set_value_cansleep(res->gpio.gpio, step->gpio.value);
> +	}
> +
> +	return 0;
> +}
> +
> +#define POWER_SEQ_GPIO_TYPE {					\
> +	.name = "gpio",					\
> +	.of_parse = of_power_seq_parse_gpio,		\
> +	.step_run = power_seq_step_run_gpio,		\
> +	.res_compare = power_seq_res_compare_gpio,	\
> +	.res_alloc = power_seq_res_alloc_gpio,		\
> +}
> diff --git a/drivers/power/power_seq/power_seq_pwm.c b/drivers/power/power_seq/power_seq_pwm.c
> new file mode 100644
> index 0000000..e61acdd
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq_pwm.c
> @@ -0,0 +1,82 @@
> +/*
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * 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.
> + *
> + */
> +
> +#ifdef CONFIG_PWM
> +
> +#include <linux/pwm.h>
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_pwm(struct device_node *node,
> +				  struct power_seq *seq,
> +				  unsigned int step_nbr,
> +				  struct power_seq_resource *res)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	int err;
> +
> +	err = of_property_read_string(node, "id", &res->pwm.id);
> +	if (err) {
> +		power_seq_err(seq, step_nbr, "error reading id property\n");
> +		return err;
> +	}
> +
> +	err = of_power_seq_parse_enable_properties(node, seq, step_nbr,
> +						   &step->pwm.enable);
> +	return err;
> +}
> +#else
> +#define of_power_seq_parse_pwm NULL
> +#endif
> +
> +static bool power_seq_res_compare_pwm(struct power_seq_resource *res,
> +				      struct power_seq_resource *res2)
> +{
> +	return !strcmp(res->pwm.id, res2->pwm.id);
> +}
> +
> +static int power_seq_res_alloc_pwm(struct device *dev,
> +				   struct power_seq_resource *res)
> +{
> +	res->pwm.pwm = devm_pwm_get(dev, res->pwm.id);
> +	if (IS_ERR(res->pwm.pwm)) {
> +		dev_err(dev, "cannot get pwm \"%s\"\n", res->pwm.id);
> +		return PTR_ERR(res->pwm.pwm);
> +	}
> +
> +	return 0;
> +}
> +
> +static int power_seq_step_run_pwm(struct power_seq_step *step)
> +{
> +	if (step->pwm.enable) {
> +		return pwm_enable(step->resource->pwm.pwm);
> +	} else {
> +		pwm_disable(step->resource->pwm.pwm);
> +		return 0;
> +	}
> +}
> +
> +#define POWER_SEQ_PWM_TYPE {				\
> +	.name = "pwm",					\
> +	.of_parse = of_power_seq_parse_pwm,		\
> +	.step_run = power_seq_step_run_pwm,		\
> +	.res_compare = power_seq_res_compare_pwm,	\
> +	.res_alloc = power_seq_res_alloc_pwm,		\
> +}
> +
> +#else
> +
> +#define POWER_SEQ_PWM_TYPE {}
> +
> +#endif
> diff --git a/drivers/power/power_seq/power_seq_regulator.c b/drivers/power/power_seq/power_seq_regulator.c
> new file mode 100644
> index 0000000..2025155
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq_regulator.c
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * 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.
> + *
> + */
> +
> +#ifdef CONFIG_REGULATOR
> +
> +#include <linux/regulator/consumer.h>
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_regulator(struct device_node *node,
> +					struct power_seq *seq,
> +					unsigned int step_nbr,
> +					struct power_seq_resource *res)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	int err;
> +
> +	err = of_property_read_string(node, "id",
> +				      &res->regulator.id);
> +	if (err) {
> +		power_seq_err(seq, step_nbr, "error reading id property\n");
> +		return err;
> +	}
> +
> +	err = of_power_seq_parse_enable_properties(node, seq, step_nbr,
> +						   &step->regulator.enable);
> +	return err;
> +}
> +#else
> +#define of_power_seq_parse_regulator NULL
> +#endif
> +
> +static bool
> +power_seq_res_compare_regulator(struct power_seq_resource *res,
> +				struct power_seq_resource *res2)
> +{
> +	return !strcmp(res->regulator.id, res2->regulator.id);
> +}
> +
> +static int power_seq_res_alloc_regulator(struct device *dev,
> +					 struct power_seq_resource *res)
> +{
> +	res->regulator.regulator = devm_regulator_get(dev, res->regulator.id);
> +	if (IS_ERR(res->regulator.regulator)) {
> +		dev_err(dev, "cannot get regulator \"%s\"\n",
> +			res->regulator.id);
> +		return PTR_ERR(res->regulator.regulator);
> +	}
> +
> +	return 0;
> +}
> +
> +static int power_seq_step_run_regulator(struct power_seq_step *step)
> +{
> +	if (step->regulator.enable)
> +		return regulator_enable(step->resource->regulator.regulator);
> +	else
> +		return regulator_disable(step->resource->regulator.regulator);
> +}
> +
> +#define POWER_SEQ_REGULATOR_TYPE {			\
> +	.name = "regulator",				\
> +	.of_parse = of_power_seq_parse_regulator,	\
> +	.step_run = power_seq_step_run_regulator,	\
> +	.res_compare = power_seq_res_compare_regulator,	\
> +	.res_alloc = power_seq_res_alloc_regulator,	\
> +}
> +
> +#else
> +
> +#define POWER_SEQ_REGULATOR_TYPE {}
> +
> +#endif
> diff --git a/include/linux/power_seq.h b/include/linux/power_seq.h
> new file mode 100644
> index 0000000..21b95b6
> --- /dev/null
> +++ b/include/linux/power_seq.h
> @@ -0,0 +1,203 @@
> +/*
> + * power_seq.h
> + *
> + * Simple interpreter for power sequences defined as platform data or device
> + * tree properties.
> + *
> + * Power sequences are designed to replace the callbacks typically used in
> + * board-specific files that implement board- or device- specific power
> + * sequences (such as those of backlights). A power sequence is an array of
> + * steps referencing resources (regulators, GPIOs, PWMs, ...) with an action to
> + * perform on them. By having the power sequences interpreted, it becomes
> + * possible to describe them in the device tree and thus to remove
> + * board-specific files from the kernel.
> + *
> + * See Documentation/power/power_seqs.txt for detailed information.
> + *
> + * Author: Alexandre Courbot <acourbot@nvidia.com>
> + *
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __LINUX_POWER_SEQ_H
> +#define __LINUX_POWER_SEQ_H
> +
> +#include <linux/types.h>
> +#include <linux/list.h>
> +
> +struct device;
> +struct regulator;
> +struct pwm_device;
> +
> +/**
> + * The different kinds of resources that can be controlled by the sequences
> + */
> +enum power_seq_res_type {
> +	POWER_SEQ_DELAY,
> +	POWER_SEQ_REGULATOR,
> +	POWER_SEQ_PWM,
> +	POWER_SEQ_GPIO,
> +	POWER_SEQ_NUM_TYPES,
> +};
> +
> +/**
> + * struct power_seq_regulator_resource
> + * @id:		name of the regulator
> + * @regulator:	resolved regulator. Written during resource resolution.
> + */
> +struct power_seq_regulator_resource {
> +	const char *id;
> +	struct regulator *regulator;
> +};
> +
> +/**
> + * struct power_seq_pwm_resource
> + * @id:		name of the PWM
> + * @regulator:	resolved PWM. Written during resource resolution.
> + */
> +struct power_seq_pwm_resource {
> +	const char *id;
> +	struct pwm_device *pwm;
> +};
> +
> +/**
> + * struct power_seq_gpio_resource
> + * @gpio:	number of the GPIO
> + * @is_set:	track GPIO state to set its direction at first use
> + */
> +struct power_seq_gpio_resource {
> +	int gpio;
> +	bool is_set;
> +};
> +
> +/**
> + * struct power_seq_resource - resource used by power sequences
> + * @type:	type of the resource. This decides which member of the union is
> + *		used for this resource
> + * @list:	link resources together in power_seq_set
> + * @regulator:	used if @type = POWER_SEQ_REGULATOR
> + * @pwm:	used if @type = POWER_SEQ_PWM
> + * @gpio:	used if @type = POWER_SEQ_GPIO
> + */
> +struct power_seq_resource {
> +	enum power_seq_res_type type;
> +	struct list_head list;
> +	union {
> +		struct power_seq_regulator_resource regulator;
> +		struct power_seq_pwm_resource pwm;
> +		struct power_seq_gpio_resource gpio;
> +	};
> +};
> +#define power_seq_for_each_resource(pos, set)			\
> +	list_for_each_entry(pos, &(set)->resources, list)
> +
> +/**
> + * struct power_seq_delay_step - action data for delay steps
> + * @delay:	amount of time to wait, in microseconds
> + */
> +struct power_seq_delay_step {
> +	unsigned int delay;
> +};
> +
> +/**
> + * struct power_seq_regulator_step - platform data for regulator steps
> + * @enable:	whether to enable or disable the regulator during this step
> + */
> +struct power_seq_regulator_step {
> +	bool enable;
> +};
> +
> +/**
> + * struct power_seq_pwm_step - action data for PWM steps
> + * @enable:	whether to enable or disable the PWM during this step
> + */
> +struct power_seq_pwm_step {
> +	bool enable;
> +};
> +
> +/**
> + * struct power_seq_gpio_step - action data for GPIO steps
> + * @enable:	whether to enable or disable the GPIO during this step
> + */
> +struct power_seq_gpio_step {
> +	int value;
> +};
> +
> +/**
> + * struct power_seq_step - data for power sequences steps
> + * @resource:	resource used by this step
> + * @delay:	used if resource->type = POWER_SEQ_DELAY
> + * @regulator:	used if resource->type = POWER_SEQ_REGULATOR
> + * @pwm:	used if resource->type = POWER_SEQ_PWN
> + * @gpio:	used if resource->type = POWER_SEQ_GPIO
> + */
> +struct power_seq_step {
> +	struct power_seq_resource *resource;
> +	union {
> +		struct power_seq_delay_step delay;
> +		struct power_seq_regulator_step regulator;
> +		struct power_seq_pwm_step pwm;
> +		struct power_seq_gpio_step gpio;
> +	};
> +};
> +
> +struct power_seq_set;
> +
> +/**
> + * struct power_seq - single power sequence
> + * @id:		name of this sequence
> + * @list:	link sequences together in power_seq_set. Leave as-is
> + * @set:	set this sequence belongs to. Written when added to a set
> + * @num_steps:	number of steps in the sequence
> + * @steps:	array of steps that make the sequence
> + */
> +struct power_seq {
> +	const char *id;
> +	struct list_head list;
> +	struct power_seq_set *set;
> +	unsigned int num_steps;
> +	struct power_seq_step steps[];
> +};
> +
> +/**
> + * struct power_seq_set - power sequences and resources used by a device
> + * @dev:	device this set belongs to
> + * @resources:	list of resources used by power sequences
> + * @seqs:	list of power sequences
> + */
> +struct power_seq_set {
> +	struct device *dev;
> +	struct list_head resources;
> +	struct list_head seqs;
> +};
> +
> +/**
> + * struct platform_power_seq_set - define power sequences as platform data
> + * @num_seqs:	number of sequences defined
> + * @seqs:	array of num_seqs power sequences
> + */
> +struct platform_power_seq_set {
> +	unsigned int num_seqs;
> +	struct power_seq *seqs[];
> +};
> +
> +struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
> +void power_seq_set_init(struct power_seq_set *set, struct device *dev);
> +int power_seq_set_add_sequence(struct power_seq_set *set,
> +			       struct power_seq *seq);
> +int power_seq_set_add_sequences(struct power_seq_set *set,
> +				struct platform_power_seq_set *seqs);
> +struct power_seq *power_seq_lookup(struct power_seq_set *seqs, const char *id);
> +int power_seq_run(struct power_seq *seq);
> +
> +#endif


^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Anton Vorontsov @ 2012-11-16  7:26 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Stephen Warren, Thierry Reding, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra, linux-kernel, linux-fbdev,
	devicetree-discuss, linux-pm, Alexandre Courbot
In-Reply-To: <1353047903-14363-2-git-send-email-acourbot@nvidia.com>

Hi Alexandre,

The code looks neat, thanks for you work!

Just a couple of comments...

On Fri, Nov 16, 2012 at 03:38:21PM +0900, Alexandre Courbot wrote:
[...]
> +
> +#include "power_seq_delay.c"
> +#include "power_seq_regulator.c"
> +#include "power_seq_pwm.c"
> +#include "power_seq_gpio.c"

This is odd, although I remember you already explained why you have to
include the .c files, instead of linking them separately. But I forgot the
reason. :) I think this deserves a comment in the code.

> +static int of_power_seq_parse_step(struct device *dev,
> +				   struct device_node *node,
> +				   struct power_seq *seq,
> +				   unsigned int step_nbr,
> +				   struct list_head *resources)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	struct power_seq_resource res, *res2;
> +	const char *type;
> +	int i, err;

nit: one variable declaration per line.

Thanks,
Anton.

^ permalink raw reply

* Re: [PATCH 00/32] OMAPDSS: create compat layer
From: Archit Taneja @ 2012-11-16  7:17 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Rob Clark, linux-omap, linux-fbdev
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>

On Thursday 15 November 2012 09:28 PM, Tomi Valkeinen wrote:
> Hi,
>
> This series is about improving omapdss API for omapdrm.
>
> We have two separate, exclusive, users of omapdss: 1) omapfb + omap_vout and 2)
> omapdrm. Because omapfb and omap_vout are independent drivers, we've built
> layers in omapdss to manage the two simultaneous callers. These layers are not
> needed for omapdrm, as omapdrm is the sole user of omapdss, and these layers in
> fact only create trouble for omapdrm.
>
> The simple option to improve omapdrm situation would be to copy the omapdss
> code for omapdrm. We are trying to avoid this, as omapdss and the panel drivers
> are quite a lot of code together, and most of the code would be used without
> change.
>
> Thus this series helps the situation by moving the omapdss code required by
> omapfb + omap_vout to separate files, creating a distinct layer used only by
> omapfb + omap_vout. We call this layer "compat layer". This compat layer then
> uses the core omapdss driver to operate the hardware. omapdrm will use the core
> omapdss directly, without any layers in between.
>
> After this series, omapfb, omap_vout and omapdrm can all be compiled at the
> same time. Obviously omapdrm and omapfb+omap_vout cannot be run at the same
> time (the first one to start will "win"), so compiling them at the same time is
> only sensible as modules for testing purposes. Normal users should only compile
> one of those.
>
> This series does not make omapdrm use the core omapdss API, that will happen in
> a separate series for omapdrm.
>
> The series is based on current omapdss master, and can also be found from:
> git://gitorious.org/linux-omap-dss2/linux.git work/apply-test-9

Series looks fine to me. Will test it out.

Archit

>
>   Tomi
>
> Tomi Valkeinen (32):
>    OMAPDSS: remove declarations for non-existing functions
>    OMAPDSS: DPI: fix crash with dpi_verify_dsi_pll()
>    OMAPDSS: don't WARN if there's no DSI device
>    OMAPDSS: DISPC: add no_framedone_tv feat
>    OMAPDSS: DISPC: use get_framedone_irq in disable_digit_out
>    OMAPDSS: DISPC: Remove blocking code from dispc_wb_enable()
>    OMAPDSS: cleanup WB enable/is_enabled functions
>    OMAPDSS: DISPC: use WARN_ON() in dispc_mgr_go
>    OMAPDSS: DISPC: pclk & lclk rates for writeback
>    OMAPDSS: DISPC: pass pclk to calc_core_clk()
>    OMAPDSS: DISPC: pass pclk & lclk to check_horiz_timing_omap3
>    OMAPDSS: DISPC: pass pclk & lclk to calc_scaling
>    OMAPDSS: DISPC: pass pclk & lclk to dispc_ovl_calc_scaling
>    OMAPDSS: create display-sysfs.c
>    OMAPDSS: add dss_get_core_pdev()
>    OMAPDSS: add omapdss_compat_init()
>    OMAPDSS: move ovl & ovl-mgr init to apply.c
>    OMAPDSS: move ovl-mgr function setup to apply.c
>    OMAPDSS: move ovl function setup to apply.c
>    OMAPDSS: add manager ops
>    OMAPDSS: manage framedone irq with mgr ops
>    OMAPDSS: move blocking mgr enable/disable to compat layer
>    OMAPDSS: move omap_dispc_wait_for_irq_interruptible_timeout to
>      dispc-compat.c
>    OMAPDSS: move irq handling to dispc-compat
>    OMAPDSS: DISPC: add dispc_ovl_check()
>    OMAPDSS: DPI: use dispc's check_timings
>    OMAPDSS: move display sysfs init to compat layer
>    OMAPDSS: separate compat files in the Makefile
>    OMAPDSS: export dss_mgr_ops functions
>    OMAPDSS: export dss_feat functions
>    OMAPDSS: export dispc functions
>    OMAPDSS: use omapdss_compat_init() in other drivers
>
>   drivers/media/platform/omap/omap_vout.c  |   17 +-
>   drivers/staging/omapdrm/omap_drv.c       |   11 +
>   drivers/video/omap2/dss/Makefile         |    6 +-
>   drivers/video/omap2/dss/apply.c          |  245 ++++++++-
>   drivers/video/omap2/dss/core.c           |   13 +-
>   drivers/video/omap2/dss/dispc-compat.c   |  667 +++++++++++++++++++++++
>   drivers/video/omap2/dss/dispc-compat.h   |   30 ++
>   drivers/video/omap2/dss/dispc.c          |  863 +++++-------------------------
>   drivers/video/omap2/dss/display-sysfs.c  |  321 +++++++++++
>   drivers/video/omap2/dss/display.c        |  285 +---------
>   drivers/video/omap2/dss/dpi.c            |    4 +-
>   drivers/video/omap2/dss/dsi.c            |   26 +-
>   drivers/video/omap2/dss/dss.h            |   75 +--
>   drivers/video/omap2/dss/dss_features.c   |    5 +
>   drivers/video/omap2/dss/dss_features.h   |    4 -
>   drivers/video/omap2/dss/manager.c        |   39 --
>   drivers/video/omap2/dss/output.c         |   65 +++
>   drivers/video/omap2/dss/overlay.c        |   17 -
>   drivers/video/omap2/dss/rfbi.c           |   12 +-
>   drivers/video/omap2/omapfb/omapfb-main.c |    6 +
>   include/video/omapdss.h                  |   80 ++-
>   21 files changed, 1582 insertions(+), 1209 deletions(-)
>   create mode 100644 drivers/video/omap2/dss/dispc-compat.c
>   create mode 100644 drivers/video/omap2/dss/dispc-compat.h
>   create mode 100644 drivers/video/omap2/dss/display-sysfs.c
>


^ permalink raw reply

* Re: [PATCH 0/5] OMAPFB: use dma_alloc instead of omap's vram
From: Tomi Valkeinen @ 2012-11-16  7:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121112225037.GU6801@atomide.com>

[-- Attachment #1: Type: text/plain, Size: 1828 bytes --]

On 2012-11-13 00:50, Tony Lindgren wrote:
> * Tomi Valkeinen <tomi.valkeinen@ti.com> [121112 02:27]:
>> Hi,
>>
>> This series changes omapfb to use standard dma_alloc funcs instead of omap
>> specific vram allocator. This let's us remove the omap vram allocator, making
>> omapfb platform independent.
>>
>> However, note that using standard dma funcs causes the following downsides:
>>
>> 1) dma_alloc_attrs doesn't let us allocate at certain physical address.
>> However, this should not be a problem as this feature of vram allocator
>> is only used when reserving the framebuffer that was initialized by the
>> bootloader, and we don't currently support "passing" a framebuffer from
>> the bootloader to the kernel anyway.
>>
>> 2) dma_alloc_attrs, as of now, always ioremaps the allocated area, and
>> we don't need the ioremap when using VRFB. This patch uses
>> DMA_ATTR_NO_KERNEL_MAPPING for the allocation, but the flag is currently
>> not operational.
>>
>> 3) OMAPFB_GET_VRAM_INFO ioctl cannot return real values anymore. I
>> changed the ioctl to return 64M for all the values, which, I hope, the
>> applications will interpret as "there's enough vram".
>>
>> 4) "vram" kernel parameter to define how much ram to reserve for video use no
>> longer works. The user needs to enable CMA and use "cma" parameter.
> 
> Great, thanks for fixing these. Could you please queue these into
> a separate branch against v3.7-rc5 that I can also merge into
> omap-for-v3.8/cleanup-headers-prepare-multiplatform-v3?
> 
> Feel free to add my Acked-by: Tony Lindgren <tony@atomide.com> to the
> arch/arm/*omap*/* parts.

I added your acks, and pushed:

git://gitorious.org/linux-omap-dss2/linux.git 3.8/vram-conversion

It's based on -rc4 as my other branches are based on that.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 897 bytes --]

^ permalink raw reply

* [PATCH v8 3/3] Take maintainership of power sequences
From: Alexandre Courbot @ 2012-11-16  6:38 UTC (permalink / raw)
  To: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann
  Cc: Leela Krishna Amudala, linux-tegra, linux-kernel, linux-fbdev,
	devicetree-discuss, linux-pm, Alexandre Courbot,
	Alexandre Courbot
In-Reply-To: <1353047903-14363-1-git-send-email-acourbot@nvidia.com>

Add entry for power sequences into MAINTAINERS with all the needed
contact and SCM info.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 59203e7..c86a93b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5696,6 +5696,16 @@ F:	fs/timerfd.c
 F:	include/linux/timer*
 F:	kernel/*timer*
 
+POWER SEQUENCES
+M:	Alexandre Courbot <acourbot@nvidia.com>
+S:	Maintained
+W:	https://github.com/Gnurou/linux-power-seqs
+T:	git https://github.com/Gnurou/linux-power-seqs.git
+F:	Documentation/devicetree/bindings/power/power_seq.txt
+F:	Documentation/power/power_seq.txt
+F:	include/linux/power_seq.h
+F:	drivers/power/power_seq/
+
 POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
 M:	Anton Vorontsov <cbou@mail.ru>
 M:	David Woodhouse <dwmw2@infradead.org>
-- 
1.8.0


^ permalink raw reply related

* [PATCH v8 2/3] pwm_backlight: use power sequences
From: Alexandre Courbot @ 2012-11-16  6:38 UTC (permalink / raw)
  To: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann
  Cc: Alexandre Courbot, linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Leela Krishna Amudala,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1353047903-14363-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Make use of the power sequences specified in the device tree or platform
data to control how the backlight is powered on and off.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
---
 .../bindings/video/backlight/pwm-backlight.txt     |  63 +++++++-
 drivers/video/backlight/Kconfig                    |   1 +
 drivers/video/backlight/pwm_bl.c                   | 160 ++++++++++++++++-----
 include/linux/pwm_backlight.h                      |  18 ++-
 4 files changed, 202 insertions(+), 40 deletions(-)

diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
index 1e4fc72..b20e98e 100644
--- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
@@ -13,16 +13,73 @@ Required properties:
 
 Optional properties:
   - pwm-names: a list of names for the PWM devices specified in the
-               "pwms" property (see PWM binding[0])
+      "pwms" property (see PWM binding[0]).
+  - power-sequences: Power sequences (see Power sequences[1]) used to bring the
+      backlight on and off. If this property is present, then two power
+      sequences named "power-on" and "power-off" must be defined to control how
+      the backlight is to be powered on and off. These sequences must reference
+      the PWM specified in the pwms property by its name, and can also reference
+      other resources supported by the power sequences mechanism
 
 [0]: Documentation/devicetree/bindings/pwm/pwm.txt
+[1]: Documentation/devicetree/bindings/power/power_seq.txt
 
 Example:
 
 	backlight {
 		compatible = "pwm-backlight";
-		pwms = <&pwm 0 5000000>;
-
 		brightness-levels = <0 4 8 16 32 64 128 255>;
 		default-brightness-level = <6>;
+		low-threshold-brightness = <50>;
+
+		/* resources used by the power sequences */
+		pwms = <&pwm 0 5000000>;
+		pwm-names = "backlight";
+		power-supply = <&backlight_reg>;
+
+		power-sequences {
+			power-on {
+				step0 {
+					type = "regulator";
+					id = "power";
+					enable;
+				};
+				step1 {
+					type = "delay";
+					delay = <10000>;
+				};
+				step2 {
+					type = "pwm";
+					id = "backlight";
+					enable;
+				};
+				step3 {
+					type = "gpio";
+					gpio = <&gpio 28 0>;
+					value = <1>;
+				};
+			};
+
+			power-off {
+				step0 {
+					type = "gpio";
+					gpio = <&gpio 28 0>;
+					value = <0>;
+				};
+				step1 {
+					type = "pwm";
+					id = "backlight";
+					disable;
+				};
+				step2 {
+					type = "delay";
+					delay = <10000>;
+				};
+				step3 {
+					type = "regulator";
+					id = "power";
+					disable;
+				};
+			};
+		};
 	};
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 765a945..a6b0640 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -240,6 +240,7 @@ config BACKLIGHT_CARILLO_RANCH
 config BACKLIGHT_PWM
 	tristate "Generic PWM based Backlight Driver"
 	depends on PWM
+	select POWER_SEQ
 	help
 	  If you have a LCD backlight adjustable by PWM, say Y to enable
 	  this driver.
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 069983c..cfc0780 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -27,6 +27,12 @@ struct pwm_bl_data {
 	unsigned int		period;
 	unsigned int		lth_brightness;
 	unsigned int		*levels;
+	bool			enabled;
+	struct power_seq_set	power_seqs;
+	struct power_seq	*power_on_seq;
+	struct power_seq	*power_off_seq;
+
+	/* Legacy callbacks */
 	int			(*notify)(struct device *,
 					  int brightness);
 	void			(*notify_after)(struct device *,
@@ -35,6 +41,51 @@ struct pwm_bl_data {
 	void			(*exit)(struct device *);
 };
 
+static void pwm_backlight_on(struct backlight_device *bl)
+{
+	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+	int ret;
+
+	if (pb->enabled)
+		return;
+
+	if (pb->power_on_seq) {
+		ret = power_seq_run(pb->power_on_seq);
+		if (ret < 0) {
+			dev_err(&bl->dev, "cannot run power on sequence\n");
+			return;
+		}
+	} else {
+		/* legacy framework */
+		pwm_enable(pb->pwm);
+	}
+
+	pb->enabled = true;
+}
+
+static void pwm_backlight_off(struct backlight_device *bl)
+{
+	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+	int ret;
+
+	if (!pb->enabled)
+		return;
+
+	if (pb->power_off_seq) {
+		ret = power_seq_run(pb->power_off_seq);
+		if (ret < 0) {
+			dev_err(&bl->dev, "cannot run power off sequence\n");
+			return;
+		}
+	} else {
+		/* legacy framework */
+		pwm_config(pb->pwm, 0, pb->period);
+		pwm_disable(pb->pwm);
+	}
+
+	pb->enabled = false;
+}
+
 static int pwm_backlight_update_status(struct backlight_device *bl)
 {
 	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
@@ -51,8 +102,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
 		brightness = pb->notify(pb->dev, brightness);
 
 	if (brightness = 0) {
-		pwm_config(pb->pwm, 0, pb->period);
-		pwm_disable(pb->pwm);
+		pwm_backlight_off(bl);
 	} else {
 		int duty_cycle;
 
@@ -66,7 +116,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
 		duty_cycle = pb->lth_brightness +
 		     (duty_cycle * (pb->period - pb->lth_brightness) / max);
 		pwm_config(pb->pwm, duty_cycle, pb->period);
-		pwm_enable(pb->pwm);
+		pwm_backlight_on(bl);
 	}
 
 	if (pb->notify_after)
@@ -145,11 +195,10 @@ static int pwm_backlight_parse_dt(struct device *dev,
 		data->max_brightness--;
 	}
 
-	/*
-	 * TODO: Most users of this driver use a number of GPIOs to control
-	 *       backlight power. Support for specifying these needs to be
-	 *       added.
-	 */
+	/* read power sequences */
+	data->power_seqs = devm_of_parse_power_seq_set(dev);
+	if (IS_ERR(data->power_seqs))
+		return PTR_ERR(data->power_seqs);
 
 	return 0;
 }
@@ -172,6 +221,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 {
 	struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
 	struct platform_pwm_backlight_data defdata;
+	struct power_seq_resource *res;
 	struct backlight_properties props;
 	struct backlight_device *bl;
 	struct pwm_bl_data *pb;
@@ -180,7 +230,9 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
 	if (!data) {
 		ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
-		if (ret < 0) {
+		if (ret = -EPROBE_DEFER) {
+			return ret;
+		} else if (ret < 0) {
 			dev_err(&pdev->dev, "failed to find platform data\n");
 			return ret;
 		}
@@ -201,6 +253,68 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 		goto err_alloc;
 	}
 
+	if (data->power_seqs) {
+		/* use power sequences */
+		struct power_seq_set *seqs = &pb->power_seqs;
+
+		power_seq_set_init(seqs, &pdev->dev);
+		power_seq_set_add_sequences(seqs, data->power_seqs);
+
+		/* Check that the required sequences are here */
+		pb->power_on_seq = power_seq_lookup(seqs, "power-on");
+		if (!pb->power_on_seq) {
+			dev_err(&pdev->dev, "missing power-on sequence\n");
+			return -EINVAL;
+		}
+		pb->power_off_seq = power_seq_lookup(seqs, "power-off");
+		if (!pb->power_off_seq) {
+			dev_err(&pdev->dev, "missing power-off sequence\n");
+			return -EINVAL;
+		}
+
+		/* we must have exactly one PWM resource for this driver */
+		power_seq_for_each_resource(res, seqs) {
+			if (res->type != POWER_SEQ_PWM)
+				continue;
+			if (pb->pwm) {
+				dev_err(&pdev->dev, "more than one PWM used\n");
+				return -EINVAL;
+			}
+			/* keep the pwm at hand */
+			pb->pwm = res->pwm.pwm;
+		}
+		/* from here we should have a PWM */
+		if (!pb->pwm) {
+			dev_err(&pdev->dev, "no PWM defined!\n");
+			return -EINVAL;
+		}
+	} else {
+		/* use legacy interface */
+		pb->pwm = devm_pwm_get(&pdev->dev, NULL);
+		if (IS_ERR(pb->pwm)) {
+			dev_err(&pdev->dev,
+				"unable to request PWM, trying legacy API\n");
+
+			pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
+			if (IS_ERR(pb->pwm)) {
+				dev_err(&pdev->dev,
+					"unable to request legacy PWM\n");
+				ret = PTR_ERR(pb->pwm);
+				goto err_alloc;
+			}
+		}
+
+		dev_dbg(&pdev->dev, "got pwm for backlight\n");
+
+		/*
+		* The DT case will set the pwm_period_ns field to 0 and store
+		* the period, parsed from the DT, in the PWM device. For the
+		* non-DT case, set the period from platform data.
+		*/
+		if (data->pwm_period_ns > 0)
+			pwm_set_period(pb->pwm, data->pwm_period_ns);
+	}
+
 	if (data->levels) {
 		max = data->levels[data->max_brightness];
 		pb->levels = data->levels;
@@ -213,28 +327,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	pb->exit = data->exit;
 	pb->dev = &pdev->dev;
 
-	pb->pwm = devm_pwm_get(&pdev->dev, NULL);
-	if (IS_ERR(pb->pwm)) {
-		dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
-
-		pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
-		if (IS_ERR(pb->pwm)) {
-			dev_err(&pdev->dev, "unable to request legacy PWM\n");
-			ret = PTR_ERR(pb->pwm);
-			goto err_alloc;
-		}
-	}
-
-	dev_dbg(&pdev->dev, "got pwm for backlight\n");
-
-	/*
-	 * The DT case will set the pwm_period_ns field to 0 and store the
-	 * period, parsed from the DT, in the PWM device. For the non-DT case,
-	 * set the period from platform data.
-	 */
-	if (data->pwm_period_ns > 0)
-		pwm_set_period(pb->pwm, data->pwm_period_ns);
-
 	pb->period = pwm_get_period(pb->pwm);
 	pb->lth_brightness = data->lth_brightness * (pb->period / max);
 
@@ -267,8 +359,7 @@ static int pwm_backlight_remove(struct platform_device *pdev)
 	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 
 	backlight_device_unregister(bl);
-	pwm_config(pb->pwm, 0, pb->period);
-	pwm_disable(pb->pwm);
+	pwm_backlight_off(bl);
 	if (pb->exit)
 		pb->exit(&pdev->dev);
 	return 0;
@@ -282,8 +373,7 @@ static int pwm_backlight_suspend(struct device *dev)
 
 	if (pb->notify)
 		pb->notify(pb->dev, 0);
-	pwm_config(pb->pwm, 0, pb->period);
-	pwm_disable(pb->pwm);
+	pwm_backlight_off(bl);
 	if (pb->notify_after)
 		pb->notify_after(pb->dev, 0);
 	return 0;
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 56f4a86..0dcec1d 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -5,14 +5,28 @@
 #define __LINUX_PWM_BACKLIGHT_H
 
 #include <linux/backlight.h>
+#include <linux/power_seq.h>
 
 struct platform_pwm_backlight_data {
-	int pwm_id;
 	unsigned int max_brightness;
 	unsigned int dft_brightness;
 	unsigned int lth_brightness;
-	unsigned int pwm_period_ns;
 	unsigned int *levels;
+	/*
+	 * New interface using power sequences. Must include exactly
+	 * two power sequences named 'power-on' and 'power-off'. If NULL,
+	 * the legacy interface is used.
+	 */
+	struct platform_power_seq_set *power_seqs;
+
+	/*
+	 * Legacy interface - use power sequences instead!
+	 *
+	 * pwm_id and pwm_period_ns need only be specified
+	 * if get_pwm(dev, NULL) would return NULL.
+	 */
+	int pwm_id;
+	unsigned int pwm_period_ns;
 	int (*init)(struct device *dev);
 	int (*notify)(struct device *dev, int brightness);
 	void (*notify_after)(struct device *dev, int brightness);
-- 
1.8.0


^ permalink raw reply related

* [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Alexandre Courbot @ 2012-11-16  6:38 UTC (permalink / raw)
  To: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann
  Cc: Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Alexandre Courbot,
	Alexandre Courbot
In-Reply-To: <1353047903-14363-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Some device drivers (e.g. panel or backlights) need to follow precise
sequences for powering on and off, involving GPIOs, regulators, PWMs
with a precise powering order and delays to respect between steps.
These sequences are device-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.

With the advent of the device tree and of ARM kernels that are not
board-tied, we cannot rely on these board-specific hooks anymore but
need a way to implement these sequences in a portable manner. This patch
introduces a simple interpreter that can execute such power sequences
encoded either as platform data or within the device tree.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 .../devicetree/bindings/power/power_seq.txt        | 121 +++++++
 Documentation/power/power_seq.txt                  | 253 ++++++++++++++
 drivers/power/Kconfig                              |   1 +
 drivers/power/Makefile                             |   1 +
 drivers/power/power_seq/Kconfig                    |   2 +
 drivers/power/power_seq/Makefile                   |   1 +
 drivers/power/power_seq/power_seq.c                | 376 +++++++++++++++++++++
 drivers/power/power_seq/power_seq_delay.c          |  65 ++++
 drivers/power/power_seq/power_seq_gpio.c           |  94 ++++++
 drivers/power/power_seq/power_seq_pwm.c            |  82 +++++
 drivers/power/power_seq/power_seq_regulator.c      |  83 +++++
 include/linux/power_seq.h                          | 203 +++++++++++
 12 files changed, 1282 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/power_seq.txt
 create mode 100644 Documentation/power/power_seq.txt
 create mode 100644 drivers/power/power_seq/Kconfig
 create mode 100644 drivers/power/power_seq/Makefile
 create mode 100644 drivers/power/power_seq/power_seq.c
 create mode 100644 drivers/power/power_seq/power_seq_delay.c
 create mode 100644 drivers/power/power_seq/power_seq_gpio.c
 create mode 100644 drivers/power/power_seq/power_seq_pwm.c
 create mode 100644 drivers/power/power_seq/power_seq_regulator.c
 create mode 100644 include/linux/power_seq.h

diff --git a/Documentation/devicetree/bindings/power/power_seq.txt b/Documentation/devicetree/bindings/power/power_seq.txt
new file mode 100644
index 0000000..7880a6c
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/power_seq.txt
@@ -0,0 +1,121 @@
+Runtime Interpreted Power Sequences
+=================+
+Power sequences are sequential descriptions of actions to be performed on
+power-related resources. Having these descriptions in a well-defined data format
+allows us to take much of the board- or device- specific power control code out
+of the kernel and place it into the device tree instead, making kernels less
+board-dependant.
+
+A device typically makes use of multiple power sequences, for different purposes
+such as powering on and off. All the power sequences of a given device are
+grouped into a set. In the device tree, this set is a sub-node of the device
+node named "power-sequences".
+
+Power Sequences Structure
+-------------------------
+Every device that makes use of power sequences must have a "power-sequences"
+node into which individual power sequences are declared as sub-nodes. The name
+of the node becomes the name of the sequence within the power sequences
+framework.
+
+Similarly, each power sequence declares its steps as sub-nodes of itself. Steps
+must be named sequentially, with the first step named step0, the second step1,
+etc. Failure to follow this rule will result in a parsing error.
+
+Power Sequences Steps
+---------------------
+Steps of a sequence describe an action to be performed on a resource. They
+always include a "type" property which indicates what kind of resource this
+step works on. Depending on the resource type, additional properties are defined
+to control the action to be performed.
+
+"delay" type required properties:
+  - delay: delay to wait (in microseconds)
+
+"regulator" type required properties:
+  - id: name of the regulator to use.
+  - enable / disable: one of these two empty properties must be present to
+                      enable or disable the resource
+
+"pwm" type required properties:
+  - id: name of the PWM to use.
+  - enable / disable: one of these two empty properties must be present to
+                      enable or disable the resource
+
+"gpio" type required properties:
+  - gpio: phandle of the GPIO to use.
+  - value: value this GPIO should take. Must be 0 or 1.
+
+Example
+-------
+Here are example sequences declared within a backlight device that use all the
+supported resources types:
+
+	backlight {
+		compatible = "pwm-backlight";
+		...
+
+		/* resources used by the power sequences */
+		pwms = <&pwm 2 5000000>;
+		pwm-names = "backlight";
+		power-supply = <&backlight_reg>;
+
+		power-sequences {
+			power-on {
+				step0 {
+					type = "regulator";
+					id = "power";
+					enable;
+				};
+				step1 {
+					type = "delay";
+					delay = <10000>;
+				};
+				step2 {
+					type = "pwm";
+					id = "backlight";
+					enable;
+				};
+				step3 {
+					type = "gpio";
+					gpio = <&gpio 28 0>;
+					value = <1>;
+				};
+			};
+
+			power-off {
+				step0 {
+					type = "gpio";
+					gpio = <&gpio 28 0>;
+					value = <0>;
+				};
+				step1 {
+					type = "pwm";
+					id = "backlight";
+					disable;
+				};
+				step2 {
+					type = "delay";
+					delay = <10000>;
+				};
+				step3 {
+					type = "regulator";
+					id = "power";
+					disable;
+				};
+			};
+		};
+	};
+
+The first part lists the PWM and regulator resources used by the sequences.
+These resources will be requested on behalf of the backlight device when the
+sequences are built and are declared according to their own bindings (for
+instance, regulators and pwms are resolved by name - note though that name
+declaration is done differently by the two frameworks).
+
+After the resources declaration, two sequences follow for powering the backlight
+on and off. Their names are specified by the pwm-backlight device bindings. Once
+the sequences are built by calling devm_of_parse_power_seq_set() on the
+backlight device, they can be added to a set using
+power_seq_set_add_sequences().
diff --git a/Documentation/power/power_seq.txt b/Documentation/power/power_seq.txt
new file mode 100644
index 0000000..8be0570
--- /dev/null
+++ b/Documentation/power/power_seq.txt
@@ -0,0 +1,253 @@
+Runtime Interpreted Power Sequences
+=================+
+Problem
+-------
+Very commonly, boards need the help of out-of-driver code to turn some of their
+devices on and off. For instance, SoC boards might use a GPIO (abstracted to a
+regulator or not) to control the power supply of a backlight. The GPIO that
+should be used, however, as well as the exact power sequence that may also
+involve other resources, is board-dependent and thus unknown to the driver.
+
+This was previously addressed by having hooks in the device's platform data that
+are called whenever the state of the device might need a power status change.
+This approach, however, introduces board-dependant code into the kernel and is
+not compatible with the device tree.
+
+The Runtime Interpreted Power Sequences (or power sequences for short) aim at
+turning this code into platform data or device tree nodes. Power sequences are
+described using a simple format and run by a lightweight interpreter whenever
+needed. This allows device drivers to work without power callbacks and makes the
+kernel less board-dependant.
+
+What are Power Sequences?
+-------------------------
+A power sequence is an array of sequential steps describing an action to be
+performed on a resource. The supported resources and actions operations are:
+- delay (just wait for a given number of microseconds)
+- GPIO (set to 0 or 1)
+- regulator (enable or disable)
+- PWM (enable or disable)
+
+When a power sequence is run, its steps is executed one after the other until
+one step fails or the end of the sequence is reached.
+
+Power sequences are named, and grouped into "sets" which contain all the
+sequences of a device as well as the resources they use.
+
+Power sequences can be declared as platform data or in the device tree.
+
+Platform Data Format
+--------------------
+All relevant data structures for declaring power sequences are located in
+include/linux/power_seq.h.
+
+The platform data for a device may include an instance of platform_power_seq_set
+which references all the power sequences used for a device. The power sequences
+reference resources in their steps, and setup the union member that corresponds
+to the resource's type. Resources, similarly, have a union which relevant member
+depends on their type.
+
+Note that the only "platform data" per se here is platform_power_seq_set. Other
+structures (power_seq and power_seq_resource) will be used at runtime and thus
+*must* survive initialization, so do not declare them with the __initdata
+attribute.
+
+The following example should make it clear how the platform data for power
+sequences is defined. It declares two power sequences named "power-on" and
+"power-off" for a backlight device. The "power-on" sequence enables the "power"
+regulator of the device, waits for 10ms, and then enables PWM "backlight" and
+set GPIO 28 to 1. "power-off" does the opposite.
+
+struct power_seq_resource reg_res = {
+	.type = POWER_SEQ_REGULATOR,
+	.regulator.id = "power",
+};
+
+struct power_seq_resource gpio_res = {
+	.type = POWER_SEQ_GPIO,
+	.gpio.gpio = 28,
+};
+
+struct power_seq_resource pwm_res = {
+	.type = POWER_SEQ_PWM,
+	.pwm.id = "backlight",
+};
+
+struct power_seq_resource delay_res = {
+	.type = POWER_SEQ_DELAY,
+};
+
+struct power_seq power_on_seq = {
+	.id = "power-on",
+	.num_steps = 4,
+	.steps = {
+		{
+			.resource = &reg_res,
+			.regulator.enable = true,
+		}, {
+			.resource = &delay_res,
+			.delay.delay = 10000,
+		}, {
+			.resource = &pwm_res,
+			.pwm.enable = true,
+		}, {
+			.resource = &gpio_res,
+			.gpio.value = 1,
+		},
+	},
+};
+
+struct power_seq power_off_seq = {
+	.id = "power-off",
+	.num_steps = 4,
+	.steps = {
+		{
+			.resource = &gpio_res,
+			.gpio.value = 0,
+		}, {
+			.resource = &pwm_res,
+			.pwm.enable = false,
+		}, {
+			.resource = &delay_res,
+			.delay.delay = 10000,
+		}, {
+			.resource = &reg_res,
+			.regulator.enable = false,
+		},
+	},
+};
+
+struct platform_power_seq_set backlight_power_seqs __initdata = {
+	.num_seqs = 2,
+	.seqs = {
+		&power_on_seq,
+		&power_off_seq,
+	},
+};
+
+"backlight_power_seqs" can then be passed to power_seq_set_add_sequences() in
+order to add the sequences to a set and allocate all the necessary resources.
+More on this later in this document.
+
+Device Tree
+-----------
+Power sequences can also be encoded as device tree nodes. The following
+properties and nodes are equivalent to the platform data defined previously:
+
+pwms = <&pwm 2 5000000>;
+pwm-names = "backlight";
+power-supply = <&vdd_bl_reg>;
+
+power-sequences {
+	power-on {
+		step0 {
+			type = "regulator";
+			id = "power";
+			enable;
+		};
+		step1 {
+			type = "delay";
+			delay = <10000>;
+		};
+		step2 {
+			type = "pwm";
+			id = "backlight";
+			enable;
+		};
+		step3 {
+			type = "gpio";
+			gpio = <&gpio 28 0>;
+			value = <1>;
+		};
+	};
+
+	power-off {
+		step0 {
+			type = "gpio";
+			gpio = <&gpio 28 0>;
+			value = <0>;
+		};
+		step1 {
+			type = "pwm";
+			id = "backlight";
+			disable;
+		};
+		step2 {
+			type = "delay";
+			delay = <10000>;
+		};
+		step3 {
+			type = "regulator";
+			id = "power";
+			disable;
+		};
+	};
+};
+
+See Documentation/devicetree/bindings/power/power_seq.txt for the complete
+syntax of the DT bindings.
+
+Use by Drivers and Resources Management
+---------------------------------------
+Power sequences make use of resources that must be properly allocated and
+managed. The power_seq_set structure manages the sequences and resources for a
+particular device. A driver willing to use power sequences will thus declare one
+instance of power_seq_set per device and initialize it at probe time:
+
+struct my_device_data {
+	struct device *dev;
+	...
+	struct power_set_set power_seqs;
+	...
+};
+
+power_seq_set_init(&my_device->power_seqs, my_device->dev);
+
+The power_seq_set_add_sequence() and power_seq_set_add_sequences() functions are
+then used to add one or several sequences to a set. These functions will also
+allocate all the resources used by the sequence(s) and make sure they are ready
+to be run. All resources are allocated through devm and will thus be freed when
+the set's device is removed.
+
+  int power_seq_set_add_sequence(struct power_seq_set *set,
+			         struct power_seq *seq);
+  int power_seq_set_add_sequences(struct power_seq_set *set,
+				  struct platform_power_seq_set *seqs);
+
+Power sequences added to a set can then be resolved by their name using
+power_seq_lookup():
+
+  struct power_seq *power_seq_lookup(struct power_seq_set *seqs,
+				     const char *id);
+
+power_seq_lookup() returns a ready-to-run pointer to the power sequence which
+name matches the id parameter.
+
+A retrieved power sequence can then be executed by power_seq_run:
+
+  int power_seq_run(struct power_seq *seq);
+
+It returns 0 if the sequence has successfully been run, or an error code if a
+problem occurred.
+
+Sometimes, you may want to browse the list of resources allocated for the
+sequences of a device, for instance to ensure that a resource of a given type is
+present. The power_seq_for_each_resource() macro does this:
+
+  power_seq_for_each_resource(pos, seqs)
+
+Here "pos" will be a pointer to a struct power_seq_resource. This structure
+contains the type of the resource, the information used for identifying it, and
+the resolved resource itself.
+
+Finally, users of the device tree can obtain a platform_power_seq_set structure
+built from the device's node using devm_of_parse_power_seq_set:
+
+  struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
+
+The power sequences must be declared under a "power-sequences" node directly
+declared under the device's node. Detailed syntax contained in Documentation/devicetree/bindings/power/power_seq.txt. As the function name
+states, all memory is allocated through devm. The returned
+platform_power_seq_set can be freed after being added to a set, but the
+sequences themselves must be preserved until they are freed by devm.
\ No newline at end of file
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 49a8939..f20d449 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -338,3 +338,4 @@ config AB8500_BATTERY_THERM_ON_BATCTRL
 endif # POWER_SUPPLY
 
 source "drivers/power/avs/Kconfig"
+source "drivers/power/power_seq/Kconfig"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index b949cf8..883ad4d 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -49,3 +49,4 @@ obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_POWER_AVS)		+= avs/
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
+obj-$(CONFIG_POWER_SEQ)		+= power_seq/
diff --git a/drivers/power/power_seq/Kconfig b/drivers/power/power_seq/Kconfig
new file mode 100644
index 0000000..3bff26e
--- /dev/null
+++ b/drivers/power/power_seq/Kconfig
@@ -0,0 +1,2 @@
+config POWER_SEQ
+	bool
diff --git a/drivers/power/power_seq/Makefile b/drivers/power/power_seq/Makefile
new file mode 100644
index 0000000..f77a359
--- /dev/null
+++ b/drivers/power/power_seq/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_POWER_SEQ)		+= power_seq.o
diff --git a/drivers/power/power_seq/power_seq.c b/drivers/power/power_seq/power_seq.c
new file mode 100644
index 0000000..255b1a0
--- /dev/null
+++ b/drivers/power/power_seq/power_seq.c
@@ -0,0 +1,376 @@
+/*
+ * power_seq.c - power sequence interpreter for platform devices and device tree
+ *
+ * Author: Alexandre Courbot <acourbot@nvidia.com>
+ *
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/power_seq.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+#include <linux/of.h>
+
+#define power_seq_err(seq, step_nbr, format, ...)			\
+	dev_err(seq->set->dev, "%s[%d]: " format, seq->id, step_nbr,	\
+	##__VA_ARGS__);
+
+/**
+ * struct power_seq_res_ops - operators for power sequences resources
+ * @name:		Name of the resource type. Set to null when a resource
+ *			type support is not compiled in
+ * @of_parse:		Parse a step for this kind of resource from a device
+ *			tree node. The result of parsing must be written into
+ *			step step_nbr of seq
+ * @step_run:		Run a step for this kind of resource
+ * @res_compare:	Return true if the resource used by the resource is the
+ *			same as the one referenced by the step, false otherwise.
+ * @res_alloc:		Resolve and allocate a resource. Return error code if
+ *			the resource cannot be allocated, 0 otherwise
+ */
+struct power_seq_res_ops {
+	const char *name;
+	int (*of_parse)(struct device_node *node, struct power_seq *seq,
+			unsigned int step_nbr, struct power_seq_resource *res);
+	int (*step_run)(struct power_seq_step *step);
+	bool (*res_compare)(struct power_seq_resource *res,
+			    struct power_seq_resource *res2);
+	int (*res_alloc)(struct device *dev,
+			 struct power_seq_resource *res);
+};
+
+static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES];
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_enable_properties(struct device_node *node,
+						struct power_seq *seq,
+						unsigned int step_nbr,
+						bool *enable)
+{
+	if (of_find_property(node, "enable", NULL)) {
+		*enable = true;
+	} else if (of_find_property(node, "disable", NULL)) {
+		*enable = false;
+	} else {
+		power_seq_err(seq, step_nbr,
+			      "missing enable or disable property\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int of_power_seq_parse_step(struct device *dev,
+				   struct device_node *node,
+				   struct power_seq *seq,
+				   unsigned int step_nbr,
+				   struct list_head *resources)
+{
+	struct power_seq_step *step = &seq->steps[step_nbr];
+	struct power_seq_resource res, *res2;
+	const char *type;
+	int i, err;
+
+	err = of_property_read_string(node, "type", &type);
+	if (err < 0) {
+		power_seq_err(seq, step_nbr, "cannot read type property\n");
+		return err;
+	}
+	for (i = 0; i < POWER_SEQ_NUM_TYPES; i++) {
+		if (power_seq_ops[i].name = NULL)
+			continue;
+		if (!strcmp(type, power_seq_ops[i].name))
+			break;
+	}
+	if (i >= POWER_SEQ_NUM_TYPES) {
+		power_seq_err(seq, step_nbr, "unknown type %s\n", type);
+		return -EINVAL;
+	}
+	memset(&res, 0, sizeof(res));
+	res.type = i;
+	err = power_seq_ops[res.type].of_parse(node, seq, step_nbr, &res);
+	if (err < 0)
+		return err;
+
+	/* Use the same instance of the resource if met before */
+	list_for_each_entry(res2, resources, list) {
+		if (res.type = res2->type &&
+		    power_seq_ops[res.type].res_compare(&res, res2))
+			break;
+	}
+	/* Resource never met before, create it */
+	if (&res2->list = resources) {
+		res2 = devm_kzalloc(dev, sizeof(*res2), GFP_KERNEL);
+		if (!res2)
+			return -ENOMEM;
+		memcpy(res2, &res, sizeof(res));
+		list_add_tail(&res2->list, resources);
+	}
+	step->resource = res2;
+
+	return 0;
+}
+
+static struct power_seq *of_parse_power_seq(struct device *dev,
+					    struct device_node *node,
+					    struct list_head *resources)
+{
+	struct device_node *child = NULL;
+	struct power_seq *pseq;
+	int num_steps, sz;
+	int err;
+
+	if (!node)
+		return ERR_PTR(-EINVAL);
+
+	num_steps = of_get_child_count(node);
+	sz = sizeof(*pseq) + sizeof(pseq->steps[0]) * num_steps;
+	pseq = devm_kzalloc(dev, sz, GFP_KERNEL);
+	if (!pseq)
+		return ERR_PTR(-ENOMEM);
+	pseq->id = node->name;
+	pseq->num_steps = num_steps;
+
+	for_each_child_of_node(node, child) {
+		unsigned int pos;
+
+		/* Check that the name's format is correct and within bounds */
+		if (strncmp("step", child->name, 4)) {
+			err = -EINVAL;
+			goto parse_error;
+		}
+
+		err = kstrtouint(child->name + 4, 10, &pos);
+		if (err < 0)
+			goto parse_error;
+
+		/* Invalid step index or step already parsed? */
+		if (pos >= num_steps || pseq->steps[pos].resource != NULL) {
+			err = -EINVAL;
+			goto parse_error;
+		}
+
+		err = of_power_seq_parse_step(dev, child, pseq, pos, resources);
+		if (err)
+			return ERR_PTR(err);
+	}
+
+	return pseq;
+
+parse_error:
+	dev_err(dev, "%s: invalid power step name %s!\n", pseq->id,
+		child->name);
+	return ERR_PTR(err);
+}
+
+/**
+ * devm_of_parse_power_seq_set - build a power_seq_set from the device tree
+ * @dev:	Device to parse the power sequences of
+ *
+ * Sequences must be contained into a subnode named "power-sequences" of the
+ * device root node.
+ *
+ * Memory for the sequence is allocated using devm_kzalloc on dev. The returned
+ * platform_power_seq_set can be freed by devm_kfree after the sequences have
+ * been added, but the sequences themselves must be preserved.
+ *
+ * Returns the built set on success, or an error code in case of failure.
+ */
+struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev)
+{
+	struct platform_power_seq_set *set;
+	struct device_node *root = dev->of_node;
+	struct device_node *seq;
+	struct list_head resources;
+	int n, sz;
+
+	if (!root)
+		return NULL;
+
+	root = of_find_node_by_name(root, "power-sequences");
+	if (!root)
+		return NULL;
+
+	n = of_get_child_count(root);
+	sz = sizeof(*set) + sizeof(struct power_seq *) * n;
+	set = devm_kzalloc(dev, sz, GFP_KERNEL);
+	if (!set)
+		return ERR_PTR(-ENOMEM);
+	set->num_seqs = n;
+
+	n = 0;
+	INIT_LIST_HEAD(&resources);
+	for_each_child_of_node(root, seq) {
+		struct power_seq *pseq;
+
+		pseq = of_parse_power_seq(dev, seq, &resources);
+		if (IS_ERR(pseq))
+			return (void *)pseq;
+
+		set->seqs[n++] = pseq;
+	}
+
+	return set;
+}
+EXPORT_SYMBOL_GPL(devm_of_parse_power_seq_set);
+#endif /* CONFIG_OF */
+
+/**
+ * power_seq_set_init - initialize a power_seq_set
+ * @set:	Set to initialize
+ * @dev:	Device this set is going to belong to
+ */
+void power_seq_set_init(struct power_seq_set *set, struct device *dev)
+{
+	set->dev = dev;
+	INIT_LIST_HEAD(&set->resources);
+	INIT_LIST_HEAD(&set->seqs);
+}
+EXPORT_SYMBOL_GPL(power_seq_set_init);
+
+/**
+ * power_seq_add_sequence - add a power sequence to a set
+ * @set:	Set to add the sequence to
+ * @seq:	Sequence to add
+ *
+ * This step will check that all the resources used by the sequence are
+ * allocated. If they are not, an attempt to allocate them is made. This
+ * operation can fail and and return an error code.
+ *
+ * Returns 0 on success, error code if a resource initialization failed.
+ */
+int power_seq_add_sequence(struct power_seq_set *set, struct power_seq *seq)
+{
+	struct power_seq_resource *res;
+	int i, err;
+
+	for (i = 0; i < seq->num_steps; i++) {
+		struct power_seq_step *step = &seq->steps[i];
+		struct power_seq_resource *step_res = step->resource;
+		list_for_each_entry(res, &set->resources, list) {
+			if (res = step_res)
+				break;
+		}
+		/* resource not allocated yet, allocate and add it */
+		if (&res->list = &set->resources) {
+			err = power_seq_ops[step_res->type].res_alloc(set->dev,
+								      step_res);
+			if (err)
+				return err;
+			list_add_tail(&step->resource->list, &set->resources);
+		}
+	}
+
+	list_add_tail(&seq->list, &set->seqs);
+	seq->set = set;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(power_seq_add_sequence);
+
+/**
+ * power_seq_add_sequences - add power sequences defined as platform data
+ * @set:	Set to add the sequences to
+ * @seqs:	Sequences to add
+ *
+ * See power_seq_add_sequence for more details.
+ *
+ * Returns 0 on success, error code if a resource initialization failed.
+ */
+int power_seq_set_add_sequences(struct power_seq_set *set,
+				struct platform_power_seq_set *seqs)
+{
+	int i, ret;
+
+	for (i = 0; i < seqs->num_seqs; i++) {
+		ret = power_seq_add_sequence(set, seqs->seqs[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(power_seq_set_add_sequences);
+
+/**
+ * power_seq_lookup - Lookup a power sequence by name from a set
+ * @seqs:	The set to look in
+ * @id:		Name to look after
+ *
+ * Returns a matching power sequence if it exists, NULL if it does not.
+ */
+struct power_seq *power_seq_lookup(struct power_seq_set *set, const char *id)
+{
+	struct power_seq *seq;
+
+	list_for_each_entry(seq, &set->seqs, list) {
+		if (!strcmp(seq->id, id))
+			return seq;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(power_seq_lookup);
+
+/**
+ * power_seq_run() - run a power sequence
+ * @seq:	The power sequence to run
+ *
+ * Returns 0 on success, error code in case of failure.
+ */
+int power_seq_run(struct power_seq *seq)
+{
+	unsigned int i;
+	int err;
+
+	if (!seq)
+		return 0;
+
+	if (!seq->set) {
+		pr_err("cannot run a sequence not added to a set");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < seq->num_steps; i++) {
+		unsigned int type = seq->steps[i].resource->type;
+
+		err = power_seq_ops[type].step_run(&seq->steps[i]);
+		if (err) {
+			power_seq_err(seq, i,
+				"error %d while running power sequence step\n",
+				err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(power_seq_run);
+
+#include "power_seq_delay.c"
+#include "power_seq_regulator.c"
+#include "power_seq_pwm.c"
+#include "power_seq_gpio.c"
+
+static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
+	[POWER_SEQ_DELAY] = POWER_SEQ_DELAY_TYPE,
+	[POWER_SEQ_REGULATOR] = POWER_SEQ_REGULATOR_TYPE,
+	[POWER_SEQ_PWM] = POWER_SEQ_PWM_TYPE,
+	[POWER_SEQ_GPIO] = POWER_SEQ_GPIO_TYPE,
+};
+
+MODULE_AUTHOR("Alexandre Courbot <acourbot@nvidia.com>");
+MODULE_DESCRIPTION("Runtime Interpreted Power Sequences");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/power_seq/power_seq_delay.c b/drivers/power/power_seq/power_seq_delay.c
new file mode 100644
index 0000000..5bb0a46
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_delay.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_delay(struct device_node *node,
+				    struct power_seq *seq,
+				    unsigned int step_nbr,
+				    struct power_seq_resource *res)
+{
+	struct power_seq_step *step = &seq->steps[step_nbr];
+	int err;
+
+	err = of_property_read_u32(node, "delay",
+				   &step->delay.delay);
+	if (err < 0)
+		power_seq_err(seq, step_nbr, "error reading delay property\n");
+
+	return err;
+}
+#else
+#define of_power_seq_parse_delay NULL
+#endif
+
+static bool power_seq_res_compare_delay(struct power_seq_resource *res,
+					struct power_seq_resource *res2)
+{
+	/* Delay resources are just here to hold the type of steps, so they are
+	 * all equivalent. */
+	return true;
+}
+
+static int power_seq_res_alloc_delay(struct device *dev,
+				     struct power_seq_resource *res)
+{
+	return 0;
+}
+
+static int power_seq_step_run_delay(struct power_seq_step *step)
+{
+	usleep_range(step->delay.delay,
+		     step->delay.delay + 1000);
+
+	return 0;
+}
+
+#define POWER_SEQ_DELAY_TYPE {				\
+	.name = "delay",				\
+	.of_parse = of_power_seq_parse_delay,		\
+	.step_run = power_seq_step_run_delay,		\
+	.res_compare = power_seq_res_compare_delay,	\
+	.res_alloc = power_seq_res_alloc_delay,		\
+}
diff --git a/drivers/power/power_seq/power_seq_gpio.c b/drivers/power/power_seq/power_seq_gpio.c
new file mode 100644
index 0000000..028a4cc
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_gpio.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_gpio(struct device_node *node,
+				   struct power_seq *seq,
+				   unsigned int step_nbr,
+				   struct power_seq_resource *res)
+{
+	struct power_seq_step *step = &seq->steps[step_nbr];
+	int gpio;
+	int err;
+
+	gpio = of_get_named_gpio(node, "gpio", 0);
+	if (gpio < 0) {
+		power_seq_err(seq, step_nbr, "error reading gpio property\n");
+		return gpio;
+	}
+	res->gpio.gpio = gpio;
+
+	err = of_property_read_u32(node, "value", &step->gpio.value);
+	if (err < 0) {
+		power_seq_err(seq, step_nbr, "error reading value property\n");
+	} else if (step->gpio.value < 0 || step->gpio.value > 1) {
+		power_seq_err(seq, step_nbr,
+			      "value out of range (must be 0 or 1)\n");
+		err = -EINVAL;
+	}
+
+	return err;
+}
+#else
+#define of_power_seq_parse_gpio NULL
+#endif
+
+static bool power_seq_res_compare_gpio(struct power_seq_resource *res,
+				       struct power_seq_resource *res2)
+{
+	return res->gpio.gpio = res2->gpio.gpio;
+}
+
+static int power_seq_res_alloc_gpio(struct device *dev,
+				    struct power_seq_resource *res)
+{
+	int err;
+
+	err = devm_gpio_request(dev, res->gpio.gpio, dev_name(dev));
+	if (err) {
+		dev_err(dev, "cannot get gpio %d\n", res->gpio.gpio);
+		return err;
+	}
+
+	return 0;
+}
+
+static int power_seq_step_run_gpio(struct power_seq_step *step)
+{
+	struct power_seq_resource *res = step->resource;
+
+	/* set the GPIO direction at first use */
+	if (!res->gpio.is_set) {
+		int err = gpio_direction_output(res->gpio.gpio,
+						step->gpio.value);
+		if (err)
+			return err;
+		res->gpio.is_set = true;
+	} else {
+		gpio_set_value_cansleep(res->gpio.gpio, step->gpio.value);
+	}
+
+	return 0;
+}
+
+#define POWER_SEQ_GPIO_TYPE {					\
+	.name = "gpio",					\
+	.of_parse = of_power_seq_parse_gpio,		\
+	.step_run = power_seq_step_run_gpio,		\
+	.res_compare = power_seq_res_compare_gpio,	\
+	.res_alloc = power_seq_res_alloc_gpio,		\
+}
diff --git a/drivers/power/power_seq/power_seq_pwm.c b/drivers/power/power_seq/power_seq_pwm.c
new file mode 100644
index 0000000..e61acdd
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_pwm.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
+#ifdef CONFIG_PWM
+
+#include <linux/pwm.h>
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_pwm(struct device_node *node,
+				  struct power_seq *seq,
+				  unsigned int step_nbr,
+				  struct power_seq_resource *res)
+{
+	struct power_seq_step *step = &seq->steps[step_nbr];
+	int err;
+
+	err = of_property_read_string(node, "id", &res->pwm.id);
+	if (err) {
+		power_seq_err(seq, step_nbr, "error reading id property\n");
+		return err;
+	}
+
+	err = of_power_seq_parse_enable_properties(node, seq, step_nbr,
+						   &step->pwm.enable);
+	return err;
+}
+#else
+#define of_power_seq_parse_pwm NULL
+#endif
+
+static bool power_seq_res_compare_pwm(struct power_seq_resource *res,
+				      struct power_seq_resource *res2)
+{
+	return !strcmp(res->pwm.id, res2->pwm.id);
+}
+
+static int power_seq_res_alloc_pwm(struct device *dev,
+				   struct power_seq_resource *res)
+{
+	res->pwm.pwm = devm_pwm_get(dev, res->pwm.id);
+	if (IS_ERR(res->pwm.pwm)) {
+		dev_err(dev, "cannot get pwm \"%s\"\n", res->pwm.id);
+		return PTR_ERR(res->pwm.pwm);
+	}
+
+	return 0;
+}
+
+static int power_seq_step_run_pwm(struct power_seq_step *step)
+{
+	if (step->pwm.enable) {
+		return pwm_enable(step->resource->pwm.pwm);
+	} else {
+		pwm_disable(step->resource->pwm.pwm);
+		return 0;
+	}
+}
+
+#define POWER_SEQ_PWM_TYPE {				\
+	.name = "pwm",					\
+	.of_parse = of_power_seq_parse_pwm,		\
+	.step_run = power_seq_step_run_pwm,		\
+	.res_compare = power_seq_res_compare_pwm,	\
+	.res_alloc = power_seq_res_alloc_pwm,		\
+}
+
+#else
+
+#define POWER_SEQ_PWM_TYPE {}
+
+#endif
diff --git a/drivers/power/power_seq/power_seq_regulator.c b/drivers/power/power_seq/power_seq_regulator.c
new file mode 100644
index 0000000..2025155
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_regulator.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
+#ifdef CONFIG_REGULATOR
+
+#include <linux/regulator/consumer.h>
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_regulator(struct device_node *node,
+					struct power_seq *seq,
+					unsigned int step_nbr,
+					struct power_seq_resource *res)
+{
+	struct power_seq_step *step = &seq->steps[step_nbr];
+	int err;
+
+	err = of_property_read_string(node, "id",
+				      &res->regulator.id);
+	if (err) {
+		power_seq_err(seq, step_nbr, "error reading id property\n");
+		return err;
+	}
+
+	err = of_power_seq_parse_enable_properties(node, seq, step_nbr,
+						   &step->regulator.enable);
+	return err;
+}
+#else
+#define of_power_seq_parse_regulator NULL
+#endif
+
+static bool
+power_seq_res_compare_regulator(struct power_seq_resource *res,
+				struct power_seq_resource *res2)
+{
+	return !strcmp(res->regulator.id, res2->regulator.id);
+}
+
+static int power_seq_res_alloc_regulator(struct device *dev,
+					 struct power_seq_resource *res)
+{
+	res->regulator.regulator = devm_regulator_get(dev, res->regulator.id);
+	if (IS_ERR(res->regulator.regulator)) {
+		dev_err(dev, "cannot get regulator \"%s\"\n",
+			res->regulator.id);
+		return PTR_ERR(res->regulator.regulator);
+	}
+
+	return 0;
+}
+
+static int power_seq_step_run_regulator(struct power_seq_step *step)
+{
+	if (step->regulator.enable)
+		return regulator_enable(step->resource->regulator.regulator);
+	else
+		return regulator_disable(step->resource->regulator.regulator);
+}
+
+#define POWER_SEQ_REGULATOR_TYPE {			\
+	.name = "regulator",				\
+	.of_parse = of_power_seq_parse_regulator,	\
+	.step_run = power_seq_step_run_regulator,	\
+	.res_compare = power_seq_res_compare_regulator,	\
+	.res_alloc = power_seq_res_alloc_regulator,	\
+}
+
+#else
+
+#define POWER_SEQ_REGULATOR_TYPE {}
+
+#endif
diff --git a/include/linux/power_seq.h b/include/linux/power_seq.h
new file mode 100644
index 0000000..21b95b6
--- /dev/null
+++ b/include/linux/power_seq.h
@@ -0,0 +1,203 @@
+/*
+ * power_seq.h
+ *
+ * Simple interpreter for power sequences defined as platform data or device
+ * tree properties.
+ *
+ * Power sequences are designed to replace the callbacks typically used in
+ * board-specific files that implement board- or device- specific power
+ * sequences (such as those of backlights). A power sequence is an array of
+ * steps referencing resources (regulators, GPIOs, PWMs, ...) with an action to
+ * perform on them. By having the power sequences interpreted, it becomes
+ * possible to describe them in the device tree and thus to remove
+ * board-specific files from the kernel.
+ *
+ * See Documentation/power/power_seqs.txt for detailed information.
+ *
+ * Author: Alexandre Courbot <acourbot@nvidia.com>
+ *
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_POWER_SEQ_H
+#define __LINUX_POWER_SEQ_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct device;
+struct regulator;
+struct pwm_device;
+
+/**
+ * The different kinds of resources that can be controlled by the sequences
+ */
+enum power_seq_res_type {
+	POWER_SEQ_DELAY,
+	POWER_SEQ_REGULATOR,
+	POWER_SEQ_PWM,
+	POWER_SEQ_GPIO,
+	POWER_SEQ_NUM_TYPES,
+};
+
+/**
+ * struct power_seq_regulator_resource
+ * @id:		name of the regulator
+ * @regulator:	resolved regulator. Written during resource resolution.
+ */
+struct power_seq_regulator_resource {
+	const char *id;
+	struct regulator *regulator;
+};
+
+/**
+ * struct power_seq_pwm_resource
+ * @id:		name of the PWM
+ * @regulator:	resolved PWM. Written during resource resolution.
+ */
+struct power_seq_pwm_resource {
+	const char *id;
+	struct pwm_device *pwm;
+};
+
+/**
+ * struct power_seq_gpio_resource
+ * @gpio:	number of the GPIO
+ * @is_set:	track GPIO state to set its direction at first use
+ */
+struct power_seq_gpio_resource {
+	int gpio;
+	bool is_set;
+};
+
+/**
+ * struct power_seq_resource - resource used by power sequences
+ * @type:	type of the resource. This decides which member of the union is
+ *		used for this resource
+ * @list:	link resources together in power_seq_set
+ * @regulator:	used if @type = POWER_SEQ_REGULATOR
+ * @pwm:	used if @type = POWER_SEQ_PWM
+ * @gpio:	used if @type = POWER_SEQ_GPIO
+ */
+struct power_seq_resource {
+	enum power_seq_res_type type;
+	struct list_head list;
+	union {
+		struct power_seq_regulator_resource regulator;
+		struct power_seq_pwm_resource pwm;
+		struct power_seq_gpio_resource gpio;
+	};
+};
+#define power_seq_for_each_resource(pos, set)			\
+	list_for_each_entry(pos, &(set)->resources, list)
+
+/**
+ * struct power_seq_delay_step - action data for delay steps
+ * @delay:	amount of time to wait, in microseconds
+ */
+struct power_seq_delay_step {
+	unsigned int delay;
+};
+
+/**
+ * struct power_seq_regulator_step - platform data for regulator steps
+ * @enable:	whether to enable or disable the regulator during this step
+ */
+struct power_seq_regulator_step {
+	bool enable;
+};
+
+/**
+ * struct power_seq_pwm_step - action data for PWM steps
+ * @enable:	whether to enable or disable the PWM during this step
+ */
+struct power_seq_pwm_step {
+	bool enable;
+};
+
+/**
+ * struct power_seq_gpio_step - action data for GPIO steps
+ * @enable:	whether to enable or disable the GPIO during this step
+ */
+struct power_seq_gpio_step {
+	int value;
+};
+
+/**
+ * struct power_seq_step - data for power sequences steps
+ * @resource:	resource used by this step
+ * @delay:	used if resource->type = POWER_SEQ_DELAY
+ * @regulator:	used if resource->type = POWER_SEQ_REGULATOR
+ * @pwm:	used if resource->type = POWER_SEQ_PWN
+ * @gpio:	used if resource->type = POWER_SEQ_GPIO
+ */
+struct power_seq_step {
+	struct power_seq_resource *resource;
+	union {
+		struct power_seq_delay_step delay;
+		struct power_seq_regulator_step regulator;
+		struct power_seq_pwm_step pwm;
+		struct power_seq_gpio_step gpio;
+	};
+};
+
+struct power_seq_set;
+
+/**
+ * struct power_seq - single power sequence
+ * @id:		name of this sequence
+ * @list:	link sequences together in power_seq_set. Leave as-is
+ * @set:	set this sequence belongs to. Written when added to a set
+ * @num_steps:	number of steps in the sequence
+ * @steps:	array of steps that make the sequence
+ */
+struct power_seq {
+	const char *id;
+	struct list_head list;
+	struct power_seq_set *set;
+	unsigned int num_steps;
+	struct power_seq_step steps[];
+};
+
+/**
+ * struct power_seq_set - power sequences and resources used by a device
+ * @dev:	device this set belongs to
+ * @resources:	list of resources used by power sequences
+ * @seqs:	list of power sequences
+ */
+struct power_seq_set {
+	struct device *dev;
+	struct list_head resources;
+	struct list_head seqs;
+};
+
+/**
+ * struct platform_power_seq_set - define power sequences as platform data
+ * @num_seqs:	number of sequences defined
+ * @seqs:	array of num_seqs power sequences
+ */
+struct platform_power_seq_set {
+	unsigned int num_seqs;
+	struct power_seq *seqs[];
+};
+
+struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
+void power_seq_set_init(struct power_seq_set *set, struct device *dev);
+int power_seq_set_add_sequence(struct power_seq_set *set,
+			       struct power_seq *seq);
+int power_seq_set_add_sequences(struct power_seq_set *set,
+				struct platform_power_seq_set *seqs);
+struct power_seq *power_seq_lookup(struct power_seq_set *seqs, const char *id);
+int power_seq_run(struct power_seq *seq);
+
+#endif
-- 
1.8.0


^ permalink raw reply related

* [PATCH v8 0/3] Runtime Interpreted Power Sequences
From: Alexandre Courbot @ 2012-11-16  6:38 UTC (permalink / raw)
  To: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann
  Cc: Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Alexandre Courbot,
	Alexandre Courbot

Hopefully the final series before the feature gets merged. Anton Vorontsov
kindly accepted to take it into his tree, so this series is mostly a call for
acks, tests and reviews notices before the merge window for 3.8 opens. If you
are interested in seeing this feature, please add your name.

This series also adds an entry for the subsystem into MAINTAINERS, setting me as
the person in charge.

Changes from v7:
- fix bug reported by Tony Prisk
- add MAINTAINERS entry

Alexandre Courbot (3):
  Runtime Interpreted Power Sequences
  pwm_backlight: use power sequences
  Take maintainership of power sequences

 .../devicetree/bindings/power/power_seq.txt        | 121 +++++++
 .../bindings/video/backlight/pwm-backlight.txt     |  63 +++-
 Documentation/power/power_seq.txt                  | 253 ++++++++++++++
 MAINTAINERS                                        |  10 +
 drivers/power/Kconfig                              |   1 +
 drivers/power/Makefile                             |   1 +
 drivers/power/power_seq/Kconfig                    |   2 +
 drivers/power/power_seq/Makefile                   |   1 +
 drivers/power/power_seq/power_seq.c                | 376 +++++++++++++++++++++
 drivers/power/power_seq/power_seq_delay.c          |  65 ++++
 drivers/power/power_seq/power_seq_gpio.c           |  94 ++++++
 drivers/power/power_seq/power_seq_pwm.c            |  82 +++++
 drivers/power/power_seq/power_seq_regulator.c      |  83 +++++
 drivers/video/backlight/Kconfig                    |   1 +
 drivers/video/backlight/pwm_bl.c                   | 160 +++++++--
 include/linux/power_seq.h                          | 203 +++++++++++
 include/linux/pwm_backlight.h                      |  18 +-
 17 files changed, 1494 insertions(+), 40 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power/power_seq.txt
 create mode 100644 Documentation/power/power_seq.txt
 create mode 100644 drivers/power/power_seq/Kconfig
 create mode 100644 drivers/power/power_seq/Makefile
 create mode 100644 drivers/power/power_seq/power_seq.c
 create mode 100644 drivers/power/power_seq/power_seq_delay.c
 create mode 100644 drivers/power/power_seq/power_seq_gpio.c
 create mode 100644 drivers/power/power_seq/power_seq_pwm.c
 create mode 100644 drivers/power/power_seq/power_seq_regulator.c
 create mode 100644 include/linux/power_seq.h

-- 
1.8.0


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox