New revision of the power sequences, taking as usual the feedback that was
kindly provided about the last version.
I think now is a good time to discuss integrating this and to start looking for
a maintainer who would be willing to merge this into his/her tree (I am
especially thinking about the power framework maintainers, since this is where
the code is right now. The second patch in this series enables the pwm_backlight
driver to be used with the device tree, without relying on board-dependent
callbacks to support complex power sequences. We also plan to use power
sequences in other Tegra drivers, and other people have expressed interest in
this work during earlier reviews. See for instance
https://lists.ozlabs.org/pipermail/devicetree-discuss/2012-August/018532.html
and
https://lkml.org/lkml/2012/9/6/270
There is probably some more details to fix and improve, but the current shape
should be enough to know if we want this and where - therefore any sign from
a maintainer would be greatly appreciated!
Changes since v5:
* Removed pointers to platform data from resource structure for better code
clarity
* devm_power_seq_set_build() now automatically checks the DT if no platform
data is present, making it possible to remove the explicit DT parsing function
* Lots of fixes in the documentation which should be clearer now (thanks
Stephen!)
Alexandre Courbot (4):
Runtime Interpreted Power Sequences
pwm_backlight: use power sequences
tegra: dt: add label to tegra20's PWM
tegra: ventana: add pwm backlight DT nodes
.../devicetree/bindings/power_seq/power_seq.txt | 122 ++++++
.../bindings/video/backlight/pwm-backlight.txt | 65 ++-
Documentation/power/power_seq.txt | 215 ++++++++++
arch/arm/boot/dts/tegra20-ventana.dts | 59 ++-
arch/arm/boot/dts/tegra20.dtsi | 2 +-
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 | 446 +++++++++++++++++++++
drivers/power/power_seq/power_seq_delay.c | 51 +++
drivers/power/power_seq/power_seq_gpio.c | 91 +++++
drivers/power/power_seq/power_seq_pwm.c | 87 ++++
drivers/power/power_seq/power_seq_regulator.c | 87 ++++
drivers/video/backlight/Kconfig | 1 +
drivers/video/backlight/pwm_bl.c | 180 ++++++---
include/linux/power_seq.h | 172 ++++++++
include/linux/pwm_backlight.h | 15 +-
18 files changed, 1543 insertions(+), 55 deletions(-)
create mode 100644 Documentation/devicetree/bindings/power_seq/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.7.12
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>
---
.../bindings/video/backlight/pwm-backlight.txt | 65 +++++++-
drivers/video/backlight/Kconfig | 1 +
drivers/video/backlight/pwm_bl.c | 180 +++++++++++++++------
include/linux/pwm_backlight.h | 15 +-
4 files changed, 208 insertions(+), 53 deletions(-)
@@ -2,7 +2,8 @@ pwm-backlight bindings Required properties: - compatible: "pwm-backlight"- - pwms: OF device-tree PWM specification (see PWM binding[0])+ - pwms: OF device-tree PWM specification (see PWM binding[0]). Exactly one PWM+ must be specified - brightness-levels: Array of distinct brightness levels. Typically these are in the range from 0 to 255, but any range starting at 0 will do. The actual brightness level (PWM duty cycle) will be interpolated
@@ -16,17 +17,75 @@ Optional properties: "pwms" property (see PWM binding[0]) - low_threshold_brightness: brightness threshold low level. (get linear scales in brightness in low end of brightness levels)+ - pwm-names: name for the PWM device specified in the "pwms" property (see PWM+ binding[0]). Necessary if power sequences are used+ - 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_seq/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>;++ /* resources used by the 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;+ };+ };+ }; }; Example for brightness_threshold_level:
@@ -35,6 +41,52 @@ struct pwm_bl_data {void(*exit)(structdevice*);};+staticvoidpwm_backlight_on(structbacklight_device*bl)+{+structpwm_bl_data*pb=dev_get_drvdata(&bl->dev);+intret;++if(pb->enabled)+return;++if(pb->power_seqs){+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_config(pb->pwm,0,pb->period);+pwm_disable(pb->pwm);+}++pb->enabled=true;+}++staticvoidpwm_backlight_off(structbacklight_device*bl)+{+structpwm_bl_data*pb=dev_get_drvdata(&bl->dev);+intret;++if(!pb->enabled)+return;++if(pb->power_seqs){+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_enable(pb->pwm);+return;+}++pb->enabled=false;+}+staticintpwm_backlight_update_status(structbacklight_device*bl){structpwm_bl_data*pb=dev_get_drvdata(&bl->dev);
@@ -51,8 +103,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{intduty_cycle;
@@ -66,7 +117,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)
@@ -150,12 +201,6 @@ static int pwm_backlight_parse_dt(struct device *dev,data->lth_brightness=value;}-/*-*TODO:MostusersofthisdriveruseanumberofGPIOstocontrol-*backlightpower.Supportforspecifyingtheseneedstobe-*added.-*/-return0;}
@@ -177,33 +222,97 @@ static int pwm_backlight_probe(struct platform_device *pdev){structplatform_pwm_backlight_data*data=pdev->dev.platform_data;structplatform_pwm_backlight_datadefdata;+structpower_seq_resource*res;structbacklight_propertiesprops;structbacklight_device*bl;structpwm_bl_data*pb;unsignedintmax;intret;+pb=devm_kzalloc(&pdev->dev,sizeof(*pb),GFP_KERNEL);+if(!pb){+dev_err(&pdev->dev,"no memory for state\n");+return-ENOMEM;+}++/* using device tree? */if(!data){+/* build platform data from device tree */ret=pwm_backlight_parse_dt(&pdev->dev,&defdata);-if(ret<0){+if(ret=-EPROBE_DEFER){+returnret;+}elseif(ret<0){dev_err(&pdev->dev,"failed to find platform data\n");returnret;}-data=&defdata;}+/* using power sequences? */+pb->power_seqs=devm_power_seq_set_build(&pdev->dev,data->power_seqs);+if(pb->power_seqs){+structpower_seq_set*seqs=pb->power_seqs;++if(IS_ERR(seqs))+returnPTR_ERR(seqs);++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 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;+}+}+/* using legacy interface? */+else{+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");+returnPTR_ERR(pb->pwm);+}+}++/*+*TheDTcasewillsetthepwm_period_nsfieldto0andstore+*theperiod,parsedfromtheDT,inthePWMdevice.Forthe+*non-DTcase,settheperiodfromplatformdata.+*/+if(data->pwm_period_ns>0)+pwm_set_period(pb->pwm,data->pwm_period_ns);+}+if(data->init){ret=data->init(&pdev->dev);if(ret<0)-returnret;+gotoerr;}-pb=devm_kzalloc(&pdev->dev,sizeof(*pb),GFP_KERNEL);-if(!pb){-dev_err(&pdev->dev,"no memory for state\n");-ret=-ENOMEM;-gotoerr_alloc;+/* from here we should have a PWM */+if(!pb->pwm){+dev_err(&pdev->dev,"no PWM defined!\n");+return-EINVAL;}if(data->levels){
@@ -218,28 +327,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)pb->exit=data->exit;pb->dev=&pdev->dev;-pb->pwm=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);-gotoerr_alloc;-}-}--dev_dbg(&pdev->dev,"got pwm for backlight\n");--/*-*TheDTcasewillsetthepwm_period_nsfieldto0andstorethe-*period,parsedfromtheDT,inthePWMdevice.Forthenon-DTcase,-*settheperiodfromplatformdata.-*/-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);
@@ -251,18 +338,17 @@ static int pwm_backlight_probe(struct platform_device *pdev)if(IS_ERR(bl)){dev_err(&pdev->dev,"failed to register backlight\n");ret=PTR_ERR(bl);-gotoerr_bl;+gotoerr;}bl->props.brightness=data->dft_brightness;backlight_update_status(bl);platform_set_drvdata(pdev,bl);+return0;-err_bl:-pwm_put(pb->pwm);-err_alloc:+err:if(data->exit)data->exit(&pdev->dev);returnret;
@@ -274,9 +360,8 @@ static int pwm_backlight_remove(struct platform_device *pdev)structpwm_bl_data*pb=dev_get_drvdata(&bl->dev);backlight_device_unregister(bl);-pwm_config(pb->pwm,0,pb->period);-pwm_disable(pb->pwm);-pwm_put(pb->pwm);+pwm_backlight_off(bl);+if(pb->exit)pb->exit(&pdev->dev);return0;
@@ -290,8 +375,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);return0;
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-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>
---
.../devicetree/bindings/power_seq/power_seq.txt | 122 ++++++
Documentation/power/power_seq.txt | 215 ++++++++++
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 | 446 +++++++++++++++++++++
drivers/power/power_seq/power_seq_delay.c | 51 +++
drivers/power/power_seq/power_seq_gpio.c | 91 +++++
drivers/power/power_seq/power_seq_pwm.c | 87 ++++
drivers/power/power_seq/power_seq_regulator.c | 87 ++++
include/linux/power_seq.h | 172 ++++++++
12 files changed, 1276 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power_seq/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
@@ -0,0 +1,122 @@+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-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. Regulator is obtained by+ regulator_get(dev, id)+ - 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. PWM is obtained by pwm_get(dev, id)+ - 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 framework (for+instance, regulators and pwms are resolved by name using regulator_get() or+pwm_get()).++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_power_seq_set_build() with a NULL pseq+argument, their names can be passed to power_seq_lookup() to retrieve an actual+sequence.
@@ -0,0 +1,215 @@+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 very commonly use a GPIO+(abstracted to a regulator or not) to control the power supply of a backlight,+disabling it when the backlight is not used in order to save power. 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 reflect a power 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 a suite of sequential steps each 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, each of 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 correspond to 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 instances of platform_power_seq. Each platform_power_seq is a+single power sequence, and is itself made of a variable length array of steps.++A step is a union of all the platform step structures, which are defined and+documented in include/linux/power_seq.h. Which one is to be used depends on the+type of the step. This might sound complicated, but 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". The+"power-on" sequence enables a regulator named "power" (retrieved using+regulator_get()), waits for 10ms, and then set GPIO 110 to 1. "power-off" does+the opposite.++static struct platform_power_seq power_on_seq = {+ .id = "power-on",+ .num_steps = 3,+ .steps = {+ {+ .type = POWER_SEQ_REGULATOR,+ .regulator = {+ .id = "power",+ .enable = true,+ },+ },+ {+ .type = POWER_SEQ_DELAY,+ .delay = {+ .delay = 10000,+ },+ },+ {+ .type = POWER_SEQ_GPIO,+ .gpio = {+ .gpio = 110,+ .value = 1,+ },+ },+ },+};++static struct platform_power_seq power_off_seq = {+ .id = "power-off",+ .num_steps = 3,+ .steps = {+ {+ .type = POWER_SEQ_GPIO,+ .gpio = {+ .gpio = 110,+ .value = 0,+ },+ },+ {+ .type = POWER_SEQ_DELAY,+ .delay = {+ .delay = 10000,+ },+ },+ {+ .type = POWER_SEQ_REGULATOR,+ .regulator = {+ .id = "power",+ .enable = false,+ },+ },+ },+};++static struct platform_power_seq_set platform_power_sequences = {+ .num_seqs = 2,+ .seqs = {+ &power_on_seq,+ &power_off_seq,+ },+};++"platform_power_sequences" can then be passed to devm_power_seq_set_build() in+order to build the corresponding sequences 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:++power-supply = <&power_reg>;++power-sequences {+ power-on {+ step0 {+ type = "regulator";+ id = "power";+ enable;+ };+ step1 {+ type = "delay";+ delay = <10000>;+ };+ step2 {+ type = "gpio";+ gpio = <&gpio 110 0>;+ value = <1>;+ };+ }+ power-off {+ step0 {+ type = "gpio";+ gpio = <&gpio 110 0>;+ value = <0>;+ };+ step1 {+ type = "delay";+ delay = <10000>;+ };+ step2 {+ type = "regulator";+ id = "power";+ disable;+ };+ }+};++See Documentation/devicetree/bindings/power_seq/power_seq.txt for the complete+syntax of the DT bindings.++Usage by Drivers and Resources Management+-----------------------------------------+Power sequences make use of resources that must be properly allocated and+managed. The devm_power_seq_set_build() function builds a power sequence set+from platform data. It also takes care of resolving and allocating the resources+referenced by the sequence:++ struct power_seq_set *devm_power_seq_set_build(struct device *dev,+ struct platform_power_seq_set *pseq);++As its name states, all memory and resources are devm-allocated. The 'dev'+argument is the device in the name of which the resources are to be allocated.++If the pseq argument is NULL, then the power sequences are built from the device+tree data, if any.++On success, the function returns a devm allocated resolved sequences set for+which all the resources are allocated. In case of failure, an error code is+returned. If no set can be built because no platform data is passed and the+device tree node for the device contains no power sequence, the function returns+NULL.++Once the set is built, power sequences can be retrieved by their name using+power_seq_lookup:++ struct power_seq *power_seq_lookup(struct power_seq_set *seqs,+ const char *id);++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 by a sequence,+for instance to ensure that a resource of a given type is present. The+power_seq_set_resources() function returns a list head that can be used with+the power_seq_for_each_resource() macro to browse all the resources of a set:++ struct list_head *power_seq_set_resources(struct power_seq_set *seqs);+ 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.
@@ -0,0 +1,446 @@+/*+*power_seq.c-Asimplepowersequenceinterpreterforplatformdevices+*anddevicetree.+*+*Author:AlexandreCourbot<acourbot@nvidia.com>+*+*Copyright(c)2012NVIDIACorporation.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;version2oftheLicense.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,butWITHOUT+*ANYWARRANTY;withouteventheimpliedwarrantyofMERCHANTABILITYor+*FITNESSFORAPARTICULARPURPOSE.SeetheGNUGeneralPublicLicensefor+*moredetails.+*+*/++#include<linux/power_seq.h>+#include<linux/module.h>+#include<linux/err.h>+#include<linux/device.h>++#include<linux/of.h>++structpower_seq_set{+structdevice*dev;+structlist_headresources;+structlist_headsequences;+};++structpower_seq_step{+/* Copy of the platform data */+structplatform_power_seq_steppdata;+/* Resolved resource */+structpower_seq_resource*resource;+};++structpower_seq{+/* Set this sequence belongs to */+structpower_seq_set*parent_set;+constchar*id;+/* To thread into power_seqs structure */+structlist_headlist;+unsignedintnum_steps;+structpower_seq_stepsteps[];+};++#define power_seq_err(dev, seq, step_nbr, format, ...) \+dev_err(dev,"%s[%d]: "format,seq->id,step_nbr,##__VA_ARGS__);++/**+*structpower_seq_res_type-operatorsforpowersequencesresources+*@name:Nameoftheresourcetype.Settonullwhenaresource+*typesupportisnotcompiledin+*@need_resource:Whetheraresourceneedstobeallocatedwhenstepsof+*thiskindaremet.Ifsettofalse,res_compareand+*res_allocneednotbeset+*@of_parse:Parseastepforthiskindofresourcefromadevice+*treenode.Theresultofparsingmustbewritteninto+*stepstep_nbrofseq+*@step_run:Runastepforthiskindofresource+*@res_compare:Returntrueiftheresourceusedbytheresourceisthe+*sameastheonereferencedbythestep,falseotherwise.+*@res_alloc:Resolveandallocatetheresourceusedbypstepinto+*seq.Thememoryforseqisalreadyallocatedandits+*typememberisalreadysetwhenthisfunctioniscalled.+*Returnerrorcodeiftheresourcecannotbeallocated,0+*ifallocationwentsuccessfully.+*/+structpower_seq_res_ops{+constchar*name;+boolneed_resource;+int(*of_parse)(structdevice*dev,structdevice_node*node,+structplatform_power_seq*seq,unsignedintstep_nbr);+int(*step_run)(structpower_seq_step*step);+bool(*res_compare)(structpower_seq_resource*res,+structplatform_power_seq_step*step);+int(*res_alloc)(structdevice*dev,+structplatform_power_seq_step*pstep,+structpower_seq_resource*seq);+};++staticconststructpower_seq_res_opspower_seq_types[POWER_SEQ_NUM_TYPES];++#ifdef CONFIG_OF+staticintof_power_seq_parse_enable_properties(structdevice*dev,+structdevice_node*node,+structplatform_power_seq*seq,+unsignedintstep_nbr,+bool*enable)+{+if(of_find_property(node,"enable",NULL)){+*enable=true;+}elseif(of_find_property(node,"disable",NULL)){+*enable=false;+}else{+power_seq_err(dev,seq,step_nbr,+"missing enable or disable property\n");+return-EINVAL;+}++return0;+}++staticintof_power_seq_parse_step(structdevice*dev,structdevice_node*node,+structplatform_power_seq*seq,+unsignedintstep_nbr)+{+structplatform_power_seq_step*step=&seq->steps[step_nbr];+constchar*type;+inti,err;++err=of_property_read_string(node,"type",&type);+if(err<0){+power_seq_err(dev,seq,step_nbr,+"cannot read type property\n");+returnerr;+}+for(i=0;i<POWER_SEQ_NUM_TYPES;i++){+if(power_seq_types[i].name=NULL)+continue;+if(!strcmp(type,power_seq_types[i].name))+break;+}+if(i>=POWER_SEQ_NUM_TYPES){+power_seq_err(dev,seq,step_nbr,"unknown type %s\n",type);+return-EINVAL;+}+step->type=i;+err=power_seq_types[step->type].of_parse(dev,node,seq,step_nbr);++returnerr;+}++staticstructplatform_power_seq*of_parse_power_seq(structdevice*dev,+structdevice_node*node)+{+structdevice_node*child=NULL;+structplatform_power_seq*pseq;+intnum_steps,sz;+interr;++if(!node)+returnERR_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)+returnERR_PTR(-ENOMEM);+pseq->num_steps=num_steps;+pseq->id=node->name;++for_each_child_of_node(node,child){+unsignedintpos;++/* Check that the name's format is correct and within bounds */+if(strncmp("step",child->name,4)){+err=-EINVAL;+gotoparse_error;+}++err=kstrtouint(child->name+4,10,&pos);+if(err<0)+gotoparse_error;++if(pos>=num_steps||pseq->steps[pos].type!=0){+err=-EINVAL;+gotoparse_error;+}++err=of_power_seq_parse_step(dev,child,pseq,pos);+if(err)+returnERR_PTR(err);+}++returnpseq;++parse_error:+dev_err(dev,"%s: invalid power step name %s!\n",pseq->id,+child->name);+returnERR_PTR(err);+}++/*+*buildpowersequencesplatformdatafromadevicetreenode.+*+*Sequencesmustbecontainedintoasubnodenamed"power-sequences"ofthe+*devicerootnode.+*+*Memoryfortheplatformsequenceisallocatedusingdevm_kzallocondevand+*canbefreedbydevm_kfreeafterpower_seq_set_buildreturned.Bewarethaton+*topofthesetitself,platformdataforindividualsequencesshouldalsobe+*freed.+*+*Returnsthebuiltpowersequencesetonsuccess,oranerrorcodeincaseof+*failure.+*/+static+structplatform_power_seq_set*devm_of_parse_power_seq_set(structdevice*dev)+{+structplatform_power_seq_set*seqs;+structdevice_node*root=dev->of_node;+structdevice_node*seq;+intnum_seqs,sz,i=0;++if(!root)+returnNULL;++root=of_find_node_by_name(root,"power-sequences");+if(!root)+returnNULL;++num_seqs=of_get_child_count(root);+sz=sizeof(*seqs)+sizeof(seqs->seqs[0])*num_seqs;+seqs=devm_kzalloc(dev,sz,GFP_KERNEL);+if(!seqs)+returnERR_PTR(-ENOMEM);+seqs->num_seqs=num_seqs;++for_each_child_of_node(root,seq){+structplatform_power_seq*pseq;++pseq=of_parse_power_seq(dev,seq);+if(IS_ERR(pseq))+return(void*)pseq;++seqs->seqs[i++]=pseq;+}++returnseqs;+}+#endif /* CONFIG_OF */++staticstructpower_seq_resource*+power_seq_find_resource(structlist_head*ress,+structplatform_power_seq_step*step)+{+structpower_seq_resource*res;++list_for_each_entry(res,ress,list){+if(res->type!=step->type)+continue;++if(power_seq_types[res->type].res_compare(res,step))+returnres;+}++returnNULL;+}++staticstructpower_seq*power_seq_build_one(structdevice*dev,+structpower_seq_set*seqs,+structplatform_power_seq*pseq)+{+structpower_seq*seq;+structpower_seq_resource*res;+inti,err;++seq=devm_kzalloc(dev,sizeof(*seq)+sizeof(seq->steps[0])*+pseq->num_steps,GFP_KERNEL);+if(!seq)+returnERR_PTR(-ENOMEM);++INIT_LIST_HEAD(&seq->list);+seq->parent_set=seqs;+seq->num_steps=pseq->num_steps;+seq->id=pseq->id;++for(i=0;i<seq->num_steps;i++){+structplatform_power_seq_step*pstep=&pseq->steps[i];+structpower_seq_step*step=&seq->steps[i];++if(pstep->type>=POWER_SEQ_NUM_TYPES||+power_seq_types[pstep->type].name=NULL){+power_seq_err(dev,seq,i,+"invalid power sequence type %d!",+pstep->type);+returnERR_PTR(-EINVAL);+}++memcpy(&step->pdata,pstep,sizeof(step->pdata));++/* Steps without resource need not to continue */+if(!power_seq_types[pstep->type].need_resource)+continue;++/* create resource node if not referenced already */+res=power_seq_find_resource(&seqs->resources,pstep);+if(!res){+res=devm_kzalloc(dev,sizeof(*res),GFP_KERNEL);+if(!res)+returnERR_PTR(-ENOMEM);++res->type=step->pdata.type;++err=power_seq_types[res->type].res_alloc(dev,+&step->pdata,res);+if(err<0)+returnERR_PTR(err);++list_add_tail(&res->list,&seqs->resources);+}+step->resource=res;+}++returnseq;+}++/**+*power_seq_set_build()-buildasetofrunnablesequencesfromplatformdataordevicetree+*@dev:Devicethatwillusethepowersequences.Allresourceswillbe+*devm-allocatedagainstit+*@pseq:Platformdataforthepowersequences.Itcanbefreedafter+*thisfunctionreturns.Ifthisparameterisnull,power+*sequencesarelookedupinthedevicetree.+*+*Allmemoryandresources(regulators,GPIOs,etc.)areallocatedusingdevm+*functions.+*+*Returnsthebuiltsequenceonsuccess,anerrorcodeincaseorfailure,+*andNULLifneitherplatformdataordevicetreenodesaredefined.+*/+structpower_seq_set*devm_power_seq_set_build(structdevice*dev,+structplatform_power_seq_set*pseq)+{+structpower_seq_set*seqs;+inti;+booluse_dt=false;++if(!pseq){+use_dt=true;+pseq=devm_of_parse_power_seq_set(dev);+}++if(!pseq)+returnNULL;++seqs=devm_kzalloc(dev,sizeof(*seqs),GFP_KERNEL);++if(!seqs)+returnERR_PTR(-ENOMEM);++INIT_LIST_HEAD(&seqs->resources);+INIT_LIST_HEAD(&seqs->sequences);+for(i=0;i<pseq->num_seqs;i++){+structpower_seq*seq;++seq=power_seq_build_one(dev,seqs,pseq->seqs[i]);+if(IS_ERR(seq))+return(void*)seq;++list_add_tail(&seq->list,&seqs->sequences);+}++/* if we used the DT, free the temporarily built platform data */+if(use_dt){+for(i=0;i<pseq->num_seqs;i++)+devm_kfree(dev,pseq->seqs[i]);++devm_kfree(dev,pseq);+}++returnseqs;+}+EXPORT_SYMBOL_GPL(devm_power_seq_set_build);++/**+*power_seq_lookup-Lookupapowersequencebynamefromaset+*@seqs:Thesettolookin+*@id:Nametolookafter+*+*Returnsamatchingpowersequenceifitexists,NULLifitdoesnot.+*/+structpower_seq*power_seq_lookup(structpower_seq_set*seqs,constchar*id)+{+structpower_seq*seq;++list_for_each_entry(seq,&seqs->sequences,list){+if(!strcmp(seq->id,id))+returnseq;+}++returnNULL;+}+EXPORT_SYMBOL_GPL(power_seq_lookup);++/**+*power_seq_set_resources-returnalistofalltheresourcesusedbyaset+*@seqs:Powersequencessetweareinterestedingettingtheresources+*+*Thereturnedlistcanbeparsedusingthepower_seq_for_each_resourcemacro.+*/+structlist_head*power_seq_set_resources(structpower_seq_set*seqs)+{+return&seqs->resources;+}+EXPORT_SYMBOL_GPL(power_seq_set_resources);++/**+*power_seq_run()-runapowersequence+*@seq:Thepowersequencetorun+*+*Returns0onsuccess,errorcodeincaseoffailure.+*/+intpower_seq_run(structpower_seq*seq)+{+unsignedinti;+interr;++if(!seq)+return0;++for(i=0;i<seq->num_steps;i++){+unsignedinttype=seq->steps[i].pdata.type;++err=power_seq_types[type].step_run(&seq->steps[i]);+if(err){+power_seq_err(seq->parent_set->dev,seq,i,+"error %d while running power sequence step\n",+err);+returnerr;+}+}++return0;+}+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"++staticconststructpower_seq_res_opspower_seq_types[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");
@@ -0,0 +1,91 @@+/*+*Copyright(c)2012NVIDIACorporation.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;version2oftheLicense.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,butWITHOUT+*ANYWARRANTY;withouteventheimpliedwarrantyofMERCHANTABILITYor+*FITNESSFORAPARTICULARPURPOSE.SeetheGNUGeneralPublicLicensefor+*moredetails.+*+*/++#include<linux/gpio.h>+#include<linux/of_gpio.h>++#ifdef CONFIG_OF+staticintpower_seq_of_parse_gpio(structdevice*dev,+structdevice_node*node,+structplatform_power_seq*seq,+unsignedintstep_nbr)+{+structplatform_power_seq_step*step=&seq->steps[step_nbr];+intgpio;+interr;++gpio=of_get_named_gpio(node,"gpio",0);+if(gpio<0){+power_seq_err(dev,seq,step_nbr,+"error reading gpio property\n");+returngpio;+}+step->gpio.gpio=gpio;++err=of_property_read_u32(node,"value",&step->gpio.value);+if(err<0){+power_seq_err(dev,seq,step_nbr,+"error reading value property\n");+}elseif(step->gpio.value<0||step->gpio.value>1){+power_seq_err(dev,seq,step_nbr,+"value out of range (must be 0 or 1)\n");+err=-EINVAL;+}++returnerr;+}+#else+#define of_power_seq_parse_gpio NULL+#endif++staticboolpower_seq_res_compare_gpio(structpower_seq_resource*res,+structplatform_power_seq_step*step)+{+returnres->gpio.gpio=step->gpio.gpio;+}++staticintpower_seq_res_alloc_gpio(structdevice*dev,+structplatform_power_seq_step*pstep,+structpower_seq_resource*res)+{+interr;++err=devm_gpio_request_one(dev,pstep->gpio.gpio,+GPIOF_OUT_INIT_LOW,dev_name(dev));+if(err){+dev_err(dev,"cannot get gpio %d\n",pstep->gpio.gpio);+returnerr;+}++res->gpio.gpio=pstep->gpio.gpio;++return0;+}++staticintpower_seq_step_run_gpio(structpower_seq_step*step)+{+gpio_set_value_cansleep(step->resource->gpio.gpio,+step->pdata.gpio.value);++return0;+}++#define POWER_SEQ_GPIO_TYPE { \+.name="gpio",\+.need_resource=true,\+.of_parse=power_seq_of_parse_gpio,\+.step_run=power_seq_step_run_gpio,\+.res_compare=power_seq_res_compare_gpio,\+.res_alloc=power_seq_res_alloc_gpio,\+}
@@ -469,6 +469,63 @@bus-width=<8>;};+backlight{+compatible="pwm-backlight";+brightness-levels=<0163248648096112128144160176192208224240255>;+default-brightness-level=<12>;++/* resources used by the power sequences */+pwms=<&pwm25000000>;+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=<&gpio280>;+value=<1>;+};+};++power-off{+step0{+type="gpio";+gpio=<&gpio280>;+value=<0>;+};+step1{+type="pwm";+id="backlight";+disable;+};+step2{+type="delay";+delay=<10000>;+};+step3{+type="regulator";+id="power";+disable;+};+};+};+};+regulators{compatible="simple-bus";#address-cells=<1>;
Both patches 3 and 4 in the series,
Acked-by: Stephen Warren <redacted>
I will take those patches into the Tegra tree when (hopefully rather
than if) patches 1 and 2 are accepted.
From: Stephen Warren <hidden> Date: 2012-09-12 21:27:12
On 09/12/2012 03:57 AM, Alexandre Courbot wrote:
New revision of the power sequences, taking as usual the feedback that was
kindly provided about the last version.
I think now is a good time to discuss integrating this and to start looking for
a maintainer who would be willing to merge this into his/her tree (I am
especially thinking about the power framework maintainers, since this is where
the code is right now.
The other alternative is for you to maintain this going forward; I
believe that would be as simple as:
* Create a patch to add yourself to MAINTAINERS for the
drivers/power/power_seq/ directory.
* Get a kernel.org account, push this patch to a branch there, and add
the branch into linux-next.
* Send a pull request to Linus at the appropriate time.
* Ongoing: Accept any patches, perform any maintenance required, etc.
Does anyone see any issue with Alexandre doing this? Nobody else has
volunteered yet:-)
From: Anton Vorontsov <hidden> Date: 2012-09-12 21:36:37
On Wed, Sep 12, 2012 at 03:27:04PM -0600, Stephen Warren wrote:
On 09/12/2012 03:57 AM, Alexandre Courbot wrote:
quoted
New revision of the power sequences, taking as usual the feedback that was
kindly provided about the last version.
I think now is a good time to discuss integrating this and to start looking for
a maintainer who would be willing to merge this into his/her tree (I am
especially thinking about the power framework maintainers, since this is where
the code is right now.
The other alternative is for you to maintain this going forward; I
believe that would be as simple as:
* Create a patch to add yourself to MAINTAINERS for the
drivers/power/power_seq/ directory.
* Get a kernel.org account, push this patch to a branch there, and add
the branch into linux-next.
* Send a pull request to Linus at the appropriate time.
* Ongoing: Accept any patches, perform any maintenance required, etc.
Does anyone see any issue with Alexandre doing this? Nobody else has
volunteered yet:-)
From: Stephen Warren <hidden> Date: 2012-09-12 22:07:22
On 09/12/2012 03:57 AM, Alexandre Courbot wrote:
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-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>
+Sometimes, you may want to browse the list of resources allocated by a sequence,
+for instance to ensure that a resource of a given type is present. The
+power_seq_set_resources() function returns a list head that can be used with
+the power_seq_for_each_resource() macro to browse all the resources of a set:
+
+ struct list_head *power_seq_set_resources(struct power_seq_set *seqs);
I don't think you need to include that prototype here?
+ 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.
Hmm. The INIT_LOW part of that might be somewhat presumptive. I would
suggest simply requesting the GPIO here, and using
gpio_direction_output() in power_seq_step_run_gpio(), thus deferring the
decision of what value to set the GPIO to until a real sequence is
actually run.
+/**
+ * struct power_seq_resource - resource used by a power sequence set
+ * @pdata: Pointer to the platform data used to resolve this resource
+ * @regulator: Resolved regulator if of type POWER_SEQ_REGULATOR
+ * @pwm: Resolved PWM if of type POWER_SEQ_PWM
+ * @list: Used to link resources together
+ */
From: Stephen Warren <hidden> Date: 2012-09-12 22:15:40
On 09/12/2012 03:57 AM, 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>
From: Tomi Valkeinen <hidden> Date: 2012-09-13 05:45:50
On Wed, 2012-09-12 at 18:57 +0900, Alexandre Courbot wrote:
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.
The sequences are not board-specific, they are device (backlight, etc.)
specific. The sequences have been handled in board-specific hook
functions so far because there hasn't been proper drivers for the
devices.
If I were to take the same panel (and backlight) you have and install it
on my board, I would need the same power sequence.
Tomi
From: Tomi Valkeinen <hidden> Date: 2012-09-13 05:50:57
On Wed, 2012-09-12 at 18:57 +0900, Alexandre Courbot wrote:
New revision of the power sequences, taking as usual the feedback that was
kindly provided about the last version.
I think now is a good time to discuss integrating this and to start looking for
a maintainer who would be willing to merge this into his/her tree (I am
especially thinking about the power framework maintainers, since this is where
the code is right now. The second patch in this series enables the pwm_backlight
driver to be used with the device tree, without relying on board-dependent
callbacks to support complex power sequences. We also plan to use power
sequences in other Tegra drivers, and other people have expressed interest in
this work during earlier reviews. See for instance
https://lists.ozlabs.org/pipermail/devicetree-discuss/2012-August/018532.html
and
https://lkml.org/lkml/2012/9/6/270
There is probably some more details to fix and improve, but the current shape
should be enough to know if we want this and where - therefore any sign from
a maintainer would be greatly appreciated!
I want to reiterate my opinion that I think power sequences in DT data
is the wrong way to go. Powering sequences are device specific issues
and should be handled in the device driver. But I also think that power
sequences inside the drivers would probably be useful.
Tomi
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 05:51:45
On Thursday 13 September 2012 05:33:56 Anton Vorontsov wrote:
On Wed, Sep 12, 2012 at 03:27:04PM -0600, Stephen Warren wrote:
quoted
On 09/12/2012 03:57 AM, Alexandre Courbot wrote:
quoted
New revision of the power sequences, taking as usual the feedback that
was
kindly provided about the last version.
I think now is a good time to discuss integrating this and to start
looking for a maintainer who would be willing to merge this into
his/her tree (I am especially thinking about the power framework
maintainers, since this is where the code is right now.
The other alternative is for you to maintain this going forward; I
believe that would be as simple as:
* Create a patch to add yourself to MAINTAINERS for the
drivers/power/power_seq/ directory.
* Get a kernel.org account, push this patch to a branch there, and add
the branch into linux-next.
* Send a pull request to Linus at the appropriate time.
* Ongoing: Accept any patches, perform any maintenance required, etc.
Does anyone see any issue with Alexandre doing this? Nobody else has
volunteered yet:-)
Yup, looks like the best way.
I am fine this way too - it will just take some time for me to get ready as I
will need to get my GPG key signed by some kernel developers first (that's what
I forgot to do during the last LinuxCon!). I know a few here so it should not
be too hard to get them drunk and sign my key, but I don't expect to be ready
for the 3.7 merge window. Would anybody be concerned by this delay? By the
meantime I can also make a branch available somewhere.
Alex.
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 06:01:04
On Thursday 13 September 2012 06:07:13 Stephen Warren wrote:
On 09/12/2012 03:57 AM, Alexandre Courbot wrote:
quoted
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-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>
diff --git a/Documentation/power/power_seq.txt
b/Documentation/power/power_seq.txt
+Sometimes, you may want to browse the list of resources allocated by a
sequence, +for instance to ensure that a resource of a given type is
present. The +power_seq_set_resources() function returns a list head that
can be used with +the power_seq_for_each_resource() macro to browse all
the resources of a set: +
+ struct list_head *power_seq_set_resources(struct power_seq_set *seqs);
I don't think you need to include that prototype here?
Why not? I thought it was customary to include the prototypes in the
documentation, and this seems to be the right place for this function.
quoted
+ 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.
diff --git a/drivers/power/power_seq/Makefile
b/drivers/power/power_seq/Makefile new file mode 100644
index 0000000..f77a359
We could also go with something more dynamic and compile these files
separately, but that would require some registration mechanism which I don't
think is needed for such a simple feature.
Hmm. The INIT_LOW part of that might be somewhat presumptive. I would
suggest simply requesting the GPIO here, and using
gpio_direction_output() in power_seq_step_run_gpio(), thus deferring the
decision of what value to set the GPIO to until a real sequence is
actually run.
Totally, thanks. I don't even understand how it landed there in the first
place.
quoted
+/**
+ * struct power_seq_resource - resource used by a power sequence set
+ * @pdata: Pointer to the platform data used to resolve this resource
+ * @regulator: Resolved regulator if of type POWER_SEQ_REGULATOR
+ * @pwm: Resolved PWM if of type POWER_SEQ_PWM
+ * @list: Used to link resources together
+ */
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 06:06:39
On Thursday 13 September 2012 13:45:39 Tomi Valkeinen wrote:
* PGP Signed by an unknown key
On Wed, 2012-09-12 at 18:57 +0900, Alexandre Courbot wrote:
quoted
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.
The sequences are not board-specific, they are device (backlight, etc.)
specific. The sequences have been handled in board-specific hook
functions so far because there hasn't been proper drivers for the
devices.
If I were to take the same panel (and backlight) you have and install it
on my board, I would need the same power sequence.
You could also have power sequences that control a set of GPIOs for an
external interface (and would then be more board-specific), but you are right
that for most of the case power seqs apply to devices and this statement is
misleading. I will fix that in the commit message and wherever this might
appear.
Alex.
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 06:21:16
On Thursday 13 September 2012 13:50:47 Tomi Valkeinen wrote:
* PGP Signed by an unknown key
On Wed, 2012-09-12 at 18:57 +0900, Alexandre Courbot wrote:
quoted
New revision of the power sequences, taking as usual the feedback that
was
kindly provided about the last version.
I think now is a good time to discuss integrating this and to start
looking for a maintainer who would be willing to merge this into his/her
tree (I am especially thinking about the power framework maintainers,
since this is where the code is right now. The second patch in this
series enables the pwm_backlight driver to be used with the device tree,
without relying on board-dependent callbacks to support complex power
sequences. We also plan to use power sequences in other Tegra drivers,
and other people have expressed interest in this work during earlier
reviews. See for instance
https://lists.ozlabs.org/pipermail/devicetree-discuss/2012-
August/018532.html
quoted
and
https://lkml.org/lkml/2012/9/6/270
There is probably some more details to fix and improve, but the current
shape should be enough to know if we want this and where - therefore any
sign from a maintainer would be greatly appreciated!
I want to reiterate my opinion that I think power sequences in DT data
is the wrong way to go. Powering sequences are device specific issues
and should be handled in the device driver. But I also think that power
sequences inside the drivers would probably be useful.
I understand the logic behind handling powering sequences in the device
driver, but as we discussed for some classes of devices this might just not
scale. I don't know how many different panels (each with different powering
sequences) are relying on pwm_backlight, but the alternative of embedding
support for all of them into the kernel (and bloating the kernel image) or
having a 3 kilometers list in the kernel configuration to individually chose
which panel to support (which would be cumbersome and make the kernel less
portable across boards) does not look much appealing to me. With power
sequences encoded in the DT, we could have one .dtsi file per panel that would
be included from the board's .dts file - no bloat, no drivers explosion,
portability preserved.
DT support is actually the main point of power sequences, as outside of the DT
we can always work the old way and use callbacks. If we were to remove DT
support, I am not sure this work would still be worth being merged.
Alex.
From: Tomi Valkeinen <hidden> Date: 2012-09-13 06:23:08
On Thu, 2012-09-13 at 15:08 +0900, Alex Courbot wrote:
On Thursday 13 September 2012 13:45:39 Tomi Valkeinen wrote:
quoted
* PGP Signed by an unknown key
On Wed, 2012-09-12 at 18:57 +0900, Alexandre Courbot wrote:
quoted
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.
The sequences are not board-specific, they are device (backlight, etc.)
specific. The sequences have been handled in board-specific hook
functions so far because there hasn't been proper drivers for the
devices.
If I were to take the same panel (and backlight) you have and install it
on my board, I would need the same power sequence.
You could also have power sequences that control a set of GPIOs for an
external interface (and would then be more board-specific), but you are right
What do you mean with "external interface"?
But it's true that there can always be interesting board specific
hardware designs, and they truly are board specific. In my experience
these are quite rare, though, but perhaps not so rare that we wouldn't
need to care about them.
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
So I guess what I'm saying is that mostly these issues are device
specific, and when they are not, they may be rather complex/strange and
require c code.
Tomi
From: Mark Brown <hidden> Date: 2012-09-13 06:26:17
On Thu, Sep 13, 2012 at 03:23:06PM +0900, Alex Courbot wrote:
I understand the logic behind handling powering sequences in the device
driver, but as we discussed for some classes of devices this might just not
scale. I don't know how many different panels (each with different powering
It would be sensible to make sure that the framework is done in such a
way that drivers can use it - there will be drivers (perhaps not display
ones) that have a known power sequence and which could benefit from the
ability to use library code to implement it based on the user simply
supplying named resources.
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 06:34:35
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
* PGP Signed by an unknown key
On Thu, 2012-09-13 at 15:08 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 13:45:39 Tomi Valkeinen wrote:
quoted
quoted
Old Signed by an unknown key
On Wed, 2012-09-12 at 18:57 +0900, Alexandre Courbot wrote:
quoted
Some device drivers (panel backlights especially) need to follow
precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each
steps.
These sequences are board-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.
The sequences are not board-specific, they are device (backlight, etc.)
specific. The sequences have been handled in board-specific hook
functions so far because there hasn't been proper drivers for the
devices.
If I were to take the same panel (and backlight) you have and install
it
on my board, I would need the same power sequence.
You could also have power sequences that control a set of GPIOs for an
external interface (and would then be more board-specific), but you are
right
What do you mean with "external interface"?
Any crazy circuit design that would make the regular power sequence not usable
on a specific board. Sorry, I don't have any concrete example in mind, the
above is just speculation.
But it's true that there can always be interesting board specific
hardware designs, and they truly are board specific. In my experience
these are quite rare, though, but perhaps not so rare that we wouldn't
need to care about them.
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
So I guess what I'm saying is that mostly these issues are device
specific, and when they are not, they may be rather complex/strange and
require c code.
You're definitely right about the powering issue being a device issue 99% of
the time. For the rest I do not have enough insight to emit an opinion.
Alex.
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 06:40:20
On Thursday 13 September 2012 14:25:53 Mark Brown wrote:
On Thu, Sep 13, 2012 at 03:23:06PM +0900, Alex Courbot wrote:
quoted
I understand the logic behind handling powering sequences in the device
driver, but as we discussed for some classes of devices this might just
not
scale. I don't know how many different panels (each with different
powering
It would be sensible to make sure that the framework is done in such a
way that drivers can use it - there will be drivers (perhaps not display
ones) that have a known power sequence and which could benefit from the
ability to use library code to implement it based on the user simply
supplying named resources.
Not sure I understand what you mean, but things should be working this way
already - regulators and PWMs are acquired by name using the standard
regulator_get() and pwm_get() functions. GPIOs do not, AFAIK, have a way to be
referenced by name so their number is used instead.
Alex.
From: Tomi Valkeinen <hidden> Date: 2012-09-13 06:42:35
On Thu, 2012-09-13 at 15:23 +0900, Alex Courbot wrote:
On Thursday 13 September 2012 13:50:47 Tomi Valkeinen wrote:
quoted
I want to reiterate my opinion that I think power sequences in DT data
is the wrong way to go. Powering sequences are device specific issues
and should be handled in the device driver. But I also think that power
sequences inside the drivers would probably be useful.
I understand the logic behind handling powering sequences in the device
driver, but as we discussed for some classes of devices this might just not
scale. I don't know how many different panels (each with different powering
sequences) are relying on pwm_backlight, but the alternative of embedding
support for all of them into the kernel (and bloating the kernel image) or
having a 3 kilometers list in the kernel configuration to individually chose
which panel to support (which would be cumbersome and make the kernel less
portable across boards) does not look much appealing to me. With power
sequences encoded in the DT, we could have one .dtsi file per panel that would
be included from the board's .dts file - no bloat, no drivers explosion,
portability preserved.
Yes, I see that side of the argument also. And to be honest, I don't
know what kind of data is DT supposed to contain (or if there even is a
strict definition for that).
I have my opinion because I think that's how things should be: DT tells
us what devices there are and how they connect, and the driver handles
the rest. I may be a perfectionist, though, which is not good =).
As for the kernel bloat, it's a valid issue, but I wonder if it would be
an issue in practice. I don't know how many different supported devices
we'd have, and how many bytes the data for each device would consume.
I'm not even sure what amount of bytes would be acceptable.
But I'm guessing that we wouldn't have very many devices, and if the per
device data is made compact there wouldn't be that many bytes per
device. And with non-hotpluggable platform devices the unused device
data could be discarded after init.
Anyway, having the power sequences doesn't affect me if I don't use
them, so I have nothing against them =).
DT support is actually the main point of power sequences, as outside of the DT
we can always work the old way and use callbacks. If we were to remove DT
support, I am not sure this work would still be worth being merged.
We can't use board callbacks when running with a DT enabled kernel. What
I meant is that the driver could contain a power sequence for the device
(or multiple supported devices). So it'd essentially be the same as
getting the power sequence from the DT data.
But I haven't looked at the power sequence data structures, so I'm not
sure if they are geared for DT use. If so, they would probably need
tuning to be good for in-kernel use.
Tomi
From: Tomi Valkeinen <hidden> Date: 2012-09-13 06:48:23
On Thu, 2012-09-13 at 15:23 +0900, Alex Courbot wrote:
DT support is actually the main point of power sequences, as outside of the DT
we can always work the old way and use callbacks. If we were to remove DT
support, I am not sure this work would still be worth being merged.
Ah, I guess you meant hooks in the driver, not hooks to board files?
Yes, that would work, but if all the hooks do essentially the same
things with just minor modifications like sleep-time, it makes more
sense to have just one piece of code which gets the sequence as data.
Tomi
From: Tomi Valkeinen <hidden> Date: 2012-09-13 06:54:18
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
Tomi
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers and
thus adding board specific code to them is backwards.
Sascha
--
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 |
From: Tomi Valkeinen <hidden> Date: 2012-09-13 07:03:43
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers and
thus adding board specific code to them is backwards.
As was pointed out in earlier posts in this thread, these are almost
always device specific, not board specific.
Do you have examples of board specific power sequences or such?
Tomi
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 07:06:59
On Thursday 13 September 2012 14:54:09 Tomi Valkeinen wrote:
* PGP Signed by an unknown key
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit
anything,
so it may well be pwm, gpios and regulators are not enough for them.
For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like
to at least add regulator voltage setting, and maybe even support for
clocks and pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data.
I took care of that when naming the feature - it is not a "sequence" anymore
if you have conditionals. :P
Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I shall be satisfied the day the kernel is released as one big DT node along
with the 5KB interpreter that runs it.
Alex.
On Thu, Sep 13, 2012 at 10:03:27AM +0300, Tomi Valkeinen wrote:
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly.
These memory writes can be avoided when these registers are abstracted
as a regular gpio/regulator/pwm driver.
quoted
quoted
And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers and
thus adding board specific code to them is backwards.
As was pointed out in earlier posts in this thread, these are almost
always device specific, not board specific.
Do you have examples of board specific power sequences or such?
Sure, tons of. One board needs a gpio to be set high to enable backlight,
the next one to low, a regulator has to be enabled, and to avoid
flickering a certain timing has to be ensured. This is all highly board
specific.
Sascha
--
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 |
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 07:19:40
On Thursday 13 September 2012 15:03:27 Tomi Valkeinen wrote:
* PGP Signed by an unknown key
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit
anything,
so it may well be pwm, gpios and regulators are not enough for them.
For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would
like to
at least add regulator voltage setting, and maybe even
quoted
quoted
quoted
support for clocks and pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers and
thus adding board specific code to them is backwards.
As was pointed out in earlier posts in this thread, these are almost
always device specific, not board specific.
I think the confusion comes from the fact that in practice, people just wrote
their hooks into the board files instead of writing more "specialized" drivers
(which I agree would have been the correct way of doing). That is why hooks
like those of the pwm_backlight driver were "board specific code" to me too.
Alex.
From: Mark Brown <hidden> Date: 2012-09-13 07:19:50
On Thu, Sep 13, 2012 at 03:42:11PM +0900, Alex Courbot wrote:
On Thursday 13 September 2012 14:25:53 Mark Brown wrote:
quoted
It would be sensible to make sure that the framework is done in such a
way that drivers can use it - there will be drivers (perhaps not display
ones) that have a known power sequence and which could benefit from the
ability to use library code to implement it based on the user simply
supplying named resources.
Not sure I understand what you mean, but things should be working this way
already - regulators and PWMs are acquired by name using the standard
regulator_get() and pwm_get() functions. GPIOs do not, AFAIK, have a way to be
referenced by name so their number is used instead.
Right, but the sequencing for enabling them is currently open coded in
each driver.
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 07:24:44
On Thursday 13 September 2012 15:19:30 Mark Brown wrote:
On Thu, Sep 13, 2012 at 03:42:11PM +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:25:53 Mark Brown wrote:
quoted
It would be sensible to make sure that the framework is done in such a
way that drivers can use it - there will be drivers (perhaps not display
ones) that have a known power sequence and which could benefit from the
ability to use library code to implement it based on the user simply
supplying named resources.
Not sure I understand what you mean, but things should be working this way
already - regulators and PWMs are acquired by name using the standard
regulator_get() and pwm_get() functions. GPIOs do not, AFAIK, have a way
to be referenced by name so their number is used instead.
Right, but the sequencing for enabling them is currently open coded in
each driver.
Mmm then I'm afraid I don't see what you wanted to say initially - could you
elaborate?
Alex.
From: Tomi Valkeinen <hidden> Date: 2012-09-13 07:28:24
On Thu, 2012-09-13 at 09:18 +0200, Sascha Hauer wrote:
On Thu, Sep 13, 2012 at 10:03:27AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly.
These memory writes can be avoided when these registers are abstracted
as a regular gpio/regulator/pwm driver.
Only if they are gpios/regulators/pwms. Yes, I agree most of the
possible things to configure would be among those (or perhaps
pinmuxing). But there's always the odd one that's not one of those.
quoted
Do you have examples of board specific power sequences or such?
Sure, tons of. One board needs a gpio to be set high to enable backlight,
the next one to low, a regulator has to be enabled, and to avoid
flickering a certain timing has to be ensured. This is all highly board
specific.
Okay. In my experience these have always been device specific. In the
case of backlight, the backlight device requires one gpio to be set
high, other one low, etc.
Can you share a bit more what kind of HW configuration you have that
requires this? The backlight is not a single piece of HW added to the
board (or embedded into a panel module), but consists of multiple HW
blocks integrated in a custom way to the board?
Tomi
On Thu, Sep 13, 2012 at 10:03:27AM +0300, Tomi Valkeinen wrote:
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers and
thus adding board specific code to them is backwards.
As was pointed out in earlier posts in this thread, these are almost
always device specific, not board specific.
Do you have examples of board specific power sequences or such?
It is true that most (perhaps all) power sequences can be associated
with a specific device, but if we go and implement drivers for these
kinds of devices we will probably end up with loads of variations of
the same scheme.
Lets take display panels as an example. One of the devices that we build
has gone through two generations so far and both are slightly different
in how they control the panel backlight: one has an external backlight
controller, the other has the display controller built into the panel.
However, from the board's perspective the control of the backlight
doesn't change, because both devices get the same inputs (an enable pin
and a PWM) that map to the same pins on the SoC.
This may not be a very good example because the timing isn't relevant,
but the basic point is still valid: if we provide a driver for both
panel devices, the code will be exactly the same. So we end up having to
refactor to avoid code duplication and use the same driver for a number
of backlight/panel combinations. Which in itself isn't very bad, but it
also means that we'll probably get to see a large number of "generic"
drivers which aren't very generic after all.
Another problem, which also applies to the case of power-sequences, is
that often the panel and backlight are not the same device. So you could
have the same panel with any number of different backlight controllers
or vice-versa any number of different panels with the same backlight
controller.
Thierry
From: Mark Brown <hidden> Date: 2012-09-13 07:30:26
On Thu, Sep 13, 2012 at 04:26:34PM +0900, Alex Courbot wrote:
On Thursday 13 September 2012 15:19:30 Mark Brown wrote:
quoted
quoted
On Thursday 13 September 2012 14:25:53 Mark Brown wrote:
quoted
It would be sensible to make sure that the framework is done in such a
way that drivers can use it - there will be drivers (perhaps not display
ones) that have a known power sequence and which could benefit from the
ability to use library code to implement it based on the user simply
supplying named resources.
quoted
quoted
Not sure I understand what you mean, but things should be working this way
already - regulators and PWMs are acquired by name using the standard
regulator_get() and pwm_get() functions. GPIOs do not, AFAIK, have a way
to be referenced by name so their number is used instead.
quoted
Right, but the sequencing for enabling them is currently open coded in
each driver.
Mmm then I'm afraid I don't see what you wanted to say initially - could you
elaborate?
The driver knows the power sequence. Having to type the same sequence
into the DT or platform data for each board using the device wouuld be
retarded so we need the drivers to be able to give the sequence to the
library if they're going to be able to reuse it (which is a lot of what
Tomi is talking about).
On Thu, Sep 13, 2012 at 09:29:20AM +0200, Thierry Reding wrote:
On Thu, Sep 13, 2012 at 10:03:27AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers and
thus adding board specific code to them is backwards.
As was pointed out in earlier posts in this thread, these are almost
always device specific, not board specific.
Do you have examples of board specific power sequences or such?
It is true that most (perhaps all) power sequences can be associated
with a specific device, but if we go and implement drivers for these
kinds of devices we will probably end up with loads of variations of
the same scheme.
Lets take display panels as an example. One of the devices that we build
has gone through two generations so far and both are slightly different
in how they control the panel backlight: one has an external backlight
controller, the other has the display controller built into the panel.
However, from the board's perspective the control of the backlight
doesn't change, because both devices get the same inputs (an enable pin
and a PWM) that map to the same pins on the SoC.
This may not be a very good example because the timing isn't relevant,
but the basic point is still valid: if we provide a driver for both
panel devices, the code will be exactly the same. So we end up having to
refactor to avoid code duplication and use the same driver for a number
of backlight/panel combinations. Which in itself isn't very bad, but it
also means that we'll probably get to see a large number of "generic"
drivers which aren't very generic after all.
Another problem, which also applies to the case of power-sequences, is
that often the panel and backlight are not the same device.
Maybe that is the problem that needs to be addressed? They *are* not the
same device, still they are handled in a single platform callback (or
now power sequence). Maybe the amount of combinations dastrically go
down if we really make them two devices.
Most of our panels have:
- A regulator (or gpio) for turning them on
And the backlights have:
- A regulator (or gpio) for turning them on
- A PWM for controlling brightness.
The power sequence for the above is clear: Turn on the panel the panel,
wait until it stabilized and afterwards turn on the backlight.
Sascha
--
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 |
From: Tomi Valkeinen <hidden> Date: 2012-09-13 08:00:31
On Thu, 2012-09-13 at 09:29 +0200, Thierry Reding wrote:
On Thu, Sep 13, 2012 at 10:03:27AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit anything,
so it may well be pwm, gpios and regulators are not enough for them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like to
at least add regulator voltage setting, and maybe even support for clocks and
pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers and
thus adding board specific code to them is backwards.
As was pointed out in earlier posts in this thread, these are almost
always device specific, not board specific.
Do you have examples of board specific power sequences or such?
It is true that most (perhaps all) power sequences can be associated
with a specific device, but if we go and implement drivers for these
kinds of devices we will probably end up with loads of variations of
the same scheme.
Lets take display panels as an example. One of the devices that we build
has gone through two generations so far and both are slightly different
in how they control the panel backlight: one has an external backlight
controller, the other has the display controller built into the panel.
However, from the board's perspective the control of the backlight
doesn't change, because both devices get the same inputs (an enable pin
and a PWM) that map to the same pins on the SoC.
We had something a bit similar in Nokia. First versions had an
"independent" backlight controlled via pwm. Later versions had a
backlight that is controlled by the panel IP, so it was changed by
sending DSI commands to the panel.
This may not be a very good example because the timing isn't relevant,
but the basic point is still valid: if we provide a driver for both
panel devices, the code will be exactly the same. So we end up having to
refactor to avoid code duplication and use the same driver for a number
of backlight/panel combinations. Which in itself isn't very bad, but it
also means that we'll probably get to see a large number of "generic"
drivers which aren't very generic after all.
Another problem, which also applies to the case of power-sequences, is
that often the panel and backlight are not the same device. So you could
have the same panel with any number of different backlight controllers
or vice-versa any number of different panels with the same backlight
controller.
Yes, I think the backlight and the panel should be considered separate
devices. Just like, say, a touch screen and a panel may happen to be in
the same display module, a backlight and a panel can be in the same
display module. They are still separate, independent things, although
they are, of course, used together.
Tomi
From: Mark Brown <hidden> Date: 2012-09-13 08:10:22
On Wed, Sep 12, 2012 at 06:57:44PM +0900, Alexandre Courbot wrote:
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.
It does make me a little sad that the DT bindings need to specify the
number of steps but otherwise this looks good (modulo the minor comments
Stephen had as well):
Reviewed-by: Mark Brown <redacted>
I think regardless of the current discussion about some of the
applications (like pwm-backlight) there are going to be cases where this
is useful even if it ends up being more as library code for drivers than
as something that users work with directly.
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-09-13 08:19:33
On Thursday 13 September 2012 15:50:37 Sascha Hauer wrote:
On Thu, Sep 13, 2012 at 09:29:20AM +0200, Thierry Reding wrote:
quoted
On Thu, Sep 13, 2012 at 10:03:27AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit
anything,
so it may well be pwm, gpios and regulators are not enough for
them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I
would like to at least add regulator voltage setting, and maybe
even support for clocks and pinmux (but that might be out of
place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps
also
direct memory read/writes so you can twiddle registers directly. And
so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers
and
thus adding board specific code to them is backwards.
As was pointed out in earlier posts in this thread, these are almost
always device specific, not board specific.
Do you have examples of board specific power sequences or such?
It is true that most (perhaps all) power sequences can be associated
with a specific device, but if we go and implement drivers for these
kinds of devices we will probably end up with loads of variations of
the same scheme.
Lets take display panels as an example. One of the devices that we build
has gone through two generations so far and both are slightly different
in how they control the panel backlight: one has an external backlight
controller, the other has the display controller built into the panel.
However, from the board's perspective the control of the backlight
doesn't change, because both devices get the same inputs (an enable pin
and a PWM) that map to the same pins on the SoC.
This may not be a very good example because the timing isn't relevant,
but the basic point is still valid: if we provide a driver for both
panel devices, the code will be exactly the same. So we end up having to
refactor to avoid code duplication and use the same driver for a number
of backlight/panel combinations. Which in itself isn't very bad, but it
also means that we'll probably get to see a large number of "generic"
drivers which aren't very generic after all.
Another problem, which also applies to the case of power-sequences, is
that often the panel and backlight are not the same device.
Maybe that is the problem that needs to be addressed? They *are* not the
same device, still they are handled in a single platform callback (or
now power sequence). Maybe the amount of combinations dastrically go
down if we really make them two devices.
Most of our panels have:
- A regulator (or gpio) for turning them on
And the backlights have:
- A regulator (or gpio) for turning them on
- A PWM for controlling brightness.
The power sequence for the above is clear: Turn on the panel the panel,
wait until it stabilized and afterwards turn on the backlight.
Actually the sequence I submitted in this patchset only takes care of the
backlight device (the panel - or LCD - should have its own). The regulator
controls the power supply, the PWM the intensity, and on top of that it also
has an enable GPIO. These 3 resources are exclusively for the LED - the LCD
uses other ones. So as of now it seems that the LCD/backlight separation is
effective and the resources needed are not so uniform across backlights (not
even mentioning the delays).
The LCD's power sequence is even weirder - VDD must take at least 0.5ms for
going from 10% to 90% of its power, you must wait 400ms after switching it off
before switching it on again, and you should also transmit data for 200ms
before switching the backlight's LED on (using its own sequence). That last
point is interesting since it somehow makes the LCD and LED dependent on each
other - on an unrelated note, this might be something to consider in Laurent's
proposal for a panel framework.
Alex.
On Thu, Sep 13, 2012 at 05:21:10PM +0900, Alex Courbot wrote:
On Thursday 13 September 2012 15:50:37 Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:29:20AM +0200, Thierry Reding wrote:
quoted
On Thu, Sep 13, 2012 at 10:03:27AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 09:00 +0200, Sascha Hauer wrote:
quoted
On Thu, Sep 13, 2012 at 09:54:09AM +0300, Tomi Valkeinen wrote:
quoted
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit
anything,
so it may well be pwm, gpios and regulators are not enough for
them. For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I
would like to at least add regulator voltage setting, and maybe
even support for clocks and pinmux (but that might be out of
place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data. Perhaps
also
direct memory read/writes so you can twiddle registers directly. And
so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I have this concern aswell, that's why I'm sceptical about this patch
set. But what are the alternatives? Adding power code to the drivers
and
thus adding board specific code to them is backwards.
As was pointed out in earlier posts in this thread, these are almost
always device specific, not board specific.
Do you have examples of board specific power sequences or such?
It is true that most (perhaps all) power sequences can be associated
with a specific device, but if we go and implement drivers for these
kinds of devices we will probably end up with loads of variations of
the same scheme.
Lets take display panels as an example. One of the devices that we build
has gone through two generations so far and both are slightly different
in how they control the panel backlight: one has an external backlight
controller, the other has the display controller built into the panel.
However, from the board's perspective the control of the backlight
doesn't change, because both devices get the same inputs (an enable pin
and a PWM) that map to the same pins on the SoC.
This may not be a very good example because the timing isn't relevant,
but the basic point is still valid: if we provide a driver for both
panel devices, the code will be exactly the same. So we end up having to
refactor to avoid code duplication and use the same driver for a number
of backlight/panel combinations. Which in itself isn't very bad, but it
also means that we'll probably get to see a large number of "generic"
drivers which aren't very generic after all.
Another problem, which also applies to the case of power-sequences, is
that often the panel and backlight are not the same device.
Maybe that is the problem that needs to be addressed? They *are* not the
same device, still they are handled in a single platform callback (or
now power sequence). Maybe the amount of combinations dastrically go
down if we really make them two devices.
Most of our panels have:
- A regulator (or gpio) for turning them on
And the backlights have:
- A regulator (or gpio) for turning them on
- A PWM for controlling brightness.
The power sequence for the above is clear: Turn on the panel the panel,
wait until it stabilized and afterwards turn on the backlight.
Actually the sequence I submitted in this patchset only takes care of the
backlight device (the panel - or LCD - should have its own). The regulator
controls the power supply, the PWM the intensity, and on top of that it also
has an enable GPIO. These 3 resources are exclusively for the LED - the LCD
uses other ones. So as of now it seems that the LCD/backlight separation is
effective and the resources needed are not so uniform across backlights (not
even mentioning the delays).
The LCD's power sequence is even weirder - VDD must take at least 0.5ms for
going from 10% to 90% of its power, you must wait 400ms after switching it off
before switching it on again, and you should also transmit data for 200ms
before switching the backlight's LED on (using its own sequence). That last
point is interesting since it somehow makes the LCD and LED dependent on each
other - on an unrelated note, this might be something to consider in Laurent's
proposal for a panel framework.
Maybe this could be solved by adding a backlight resource type and
embedding a reference to the backlight within the panel's power
sequence?
Thierry
On Thu, Sep 13, 2012 at 11:00:18AM +0300, Tomi Valkeinen wrote:
Yes, I think the backlight and the panel should be considered separate
devices. Just like, say, a touch screen and a panel may happen to be in
the same display module, a backlight and a panel can be in the same
display module. They are still separate, independent things, although
they are, of course, used together.
Still, as Alex mentioned, there may be some dependency between the panel
and the backlight, so we may need to have some kind of connection. I
haven't had much time to look at the panel subsystem, but perhaps it
should provide for this.
I obviously don't know every panel and backlight combination out there,
but isn't the dependency more of a usability nature. What I mean is that
the panel will work even if you switch the backlight on immediately,
just that the panel might take some time to properly display data and
therefore the backlight should remain powered off so the user doesn't
see garbage. Or are there really any functional dependencies?
Thierry
From: Stephen Warren <hidden> Date: 2012-09-13 15:25:01
On 09/13/2012 01:29 AM, Mark Brown wrote:
On Thu, Sep 13, 2012 at 04:26:34PM +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 15:19:30 Mark Brown wrote:
quoted
quoted
On Thursday 13 September 2012 14:25:53 Mark Brown wrote:
quoted
It would be sensible to make sure that the framework is done in such a
way that drivers can use it - there will be drivers (perhaps not display
ones) that have a known power sequence and which could benefit from the
ability to use library code to implement it based on the user simply
supplying named resources.
quoted
quoted
quoted
Not sure I understand what you mean, but things should be working this way
already - regulators and PWMs are acquired by name using the standard
regulator_get() and pwm_get() functions. GPIOs do not, AFAIK, have a way
to be referenced by name so their number is used instead.
quoted
quoted
Right, but the sequencing for enabling them is currently open coded in
each driver.
quoted
Mmm then I'm afraid I don't see what you wanted to say initially - could you
elaborate?
The driver knows the power sequence. Having to type the same sequence
into the DT or platform data for each board using the device wouuld be
retarded so we need the drivers to be able to give the sequence to the
library if they're going to be able to reuse it (which is a lot of what
Tomi is talking about).
I believe that's trivial to implement. The relevant function is:
struct power_seq_set *devm_power_seq_set_build(struct device *dev,
struct platform_power_seq_set *pseq);
It's up to the driver whether pseq comes from platform data or is
hard-coded into the driver (or not provided at all, for the DT case).
So, the only change needed to convert a "hard-coded" driver to this API
is to convert the current custom data structure (or code) that describes
the sequence into a struct platform_power_seq_set.
From: Stephen Warren <hidden> Date: 2012-09-13 15:37:33
On 09/13/2012 01:08 AM, Alex Courbot wrote:
On Thursday 13 September 2012 14:54:09 Tomi Valkeinen wrote:
quoted
* PGP Signed by an unknown key
On Thu, 2012-09-13 at 15:36 +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 14:22:57 Tomi Valkeinen wrote:
quoted
However, I fear these board specific things may be quite a bit
anything,
so it may well be pwm, gpios and regulators are not enough for them.
For
example, there could be an FPGA on the board which requires some
configuration to accomplish the task at hand. It could be rather
difficult to handle it with a generic power sequence.
Right. Note that this framework is supposed to be extended - I would like
to at least add regulator voltage setting, and maybe even support for
clocks and pinmux (but that might be out of place).
Yes, that's one concern of mine... I already can imagine someone
suggesting adding conditionals to the power sequence data.
I took care of that when naming the feature - it is not a "sequence" anymore
if you have conditionals. :P
quoted
Perhaps also
direct memory read/writes so you can twiddle registers directly. And so
on. Where's the limit what it should contain? Can we soon write full
drivers with the DT data? =)
I shall be satisfied the day the kernel is released as one big DT node along
with the 5KB interpreter that runs it.
I know you're joking, but *cough* OpenFirmware *cough*, right?
From: Stephen Warren <hidden> Date: 2012-09-13 15:44:28
On 09/13/2012 12:02 AM, Alex Courbot wrote:
On Thursday 13 September 2012 06:07:13 Stephen Warren wrote:
quoted
On 09/12/2012 03:57 AM, Alexandre Courbot wrote:
quoted
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-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>
diff --git a/Documentation/power/power_seq.txt
b/Documentation/power/power_seq.txt
+Sometimes, you may want to browse the list of resources allocated by a
sequence, +for instance to ensure that a resource of a given type is
present. The +power_seq_set_resources() function returns a list head that
can be used with +the power_seq_for_each_resource() macro to browse all
the resources of a set: +
+ struct list_head *power_seq_set_resources(struct power_seq_set *seqs);
+ 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.
I don't think you need to include that [power_seq_set_resources] prototype
here?
Why not? I thought it was customary to include the prototypes in the
documentation, and this seems to be the right place for this function.
It's something used internally to the macro; what the user cares about
is which macro to use for the functionality you're describing, not any
prototypes needed by the internal implementation of the macro, which are
always provided by the appropriate header.
quoted
quoted
diff --git a/drivers/power/power_seq/power_seq.c
b/drivers/power/power_seq/power_seq.c
+struct power_seq_step {
+ /* Copy of the platform data */
+ struct platform_power_seq_step pdata;
I'd reword the comment to "Copy of the step", and name the field "step".
That would make a step within a step - doesn't pdata make it more explicit
what this member is for (containing the platform data for this step)?
Well, it's not always platform data; it could come from device tree.
Sorry for bike-shedding slightly, but how about just "data",
"step_data", "config", or "step_config"?
We could also go with something more dynamic and compile these files
separately, but that would require some registration mechanism which I don't
think is needed for such a simple feature.
Sure. There are already examples in the kernel of basically what you're
doing anyway, and it's not like it'd be hard to change this if we want
to do something different in the future too.
From: Mark Brown <hidden> Date: 2012-09-19 03:01:24
On Thu, Sep 13, 2012 at 09:24:53AM -0600, Stephen Warren wrote:
On 09/13/2012 01:29 AM, Mark Brown wrote:
quoted
The driver knows the power sequence. Having to type the same sequence
into the DT or platform data for each board using the device wouuld be
retarded so we need the drivers to be able to give the sequence to the
library if they're going to be able to reuse it (which is a lot of what
Tomi is talking about).
I believe that's trivial to implement. The relevant function is:
Right, that's what I'm saying - the code is mostly there now.
It's up to the driver whether pseq comes from platform data or is
hard-coded into the driver (or not provided at all, for the DT case).
So, the only change needed to convert a "hard-coded" driver to this API
is to convert the current custom data structure (or code) that describes
the sequence into a struct platform_power_seq_set.
The framework could still help by providing ways to avoid having to copy
the structure and fill in the blanks for GPIO numbers (and anything else
that is numbered rather than named) by hand.
From: Alex Courbot <acourbot@nvidia.com> Date: 2012-10-03 08:22:54
On 09/14/2012 12:24 AM, Stephen Warren wrote:
On 09/13/2012 01:29 AM, Mark Brown wrote:
quoted
On Thu, Sep 13, 2012 at 04:26:34PM +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 15:19:30 Mark Brown wrote:
quoted
quoted
On Thursday 13 September 2012 14:25:53 Mark Brown wrote:
quoted
It would be sensible to make sure that the framework is done in such a
way that drivers can use it - there will be drivers (perhaps not display
ones) that have a known power sequence and which could benefit from the
ability to use library code to implement it based on the user simply
supplying named resources.
quoted
quoted
quoted
Not sure I understand what you mean, but things should be working this way
already - regulators and PWMs are acquired by name using the standard
regulator_get() and pwm_get() functions. GPIOs do not, AFAIK, have a way
to be referenced by name so their number is used instead.
quoted
quoted
Right, but the sequencing for enabling them is currently open coded in
each driver.
quoted
Mmm then I'm afraid I don't see what you wanted to say initially - could you
elaborate?
The driver knows the power sequence. Having to type the same sequence
into the DT or platform data for each board using the device wouuld be
retarded so we need the drivers to be able to give the sequence to the
library if they're going to be able to reuse it (which is a lot of what
Tomi is talking about).
I believe that's trivial to implement. The relevant function is:
struct power_seq_set *devm_power_seq_set_build(struct device *dev,
struct platform_power_seq_set *pseq);
It's up to the driver whether pseq comes from platform data or is
hard-coded into the driver (or not provided at all, for the DT case).
So, the only change needed to convert a "hard-coded" driver to this API
is to convert the current custom data structure (or code) that describes
the sequence into a struct platform_power_seq_set.
If we go this way (which looks good IMO!), then maybe we should abandon
that "platform" denomination and merge platform_power_seq* structures
with the currently private power_seq*, and also replace the "building"
step with a resources acquisition one. Calling these structures
"platform" implies they are for platform data while they can be used to
perform more flexible things as Mark mentioned. Also making the resolved
resource visible would allow drivers to "patch" generic sequences with
the proper GPIO numbers at runtime. We would also avoid a few memory
copies and both design and usage would be simplified, at the cost of
having more things exposed. How does that sound?
Alex.
From: Stephen Warren <hidden> Date: 2012-10-03 15:30:21
On 10/03/2012 02:24 AM, Alex Courbot wrote:
On 09/14/2012 12:24 AM, Stephen Warren wrote:
quoted
On 09/13/2012 01:29 AM, Mark Brown wrote:
quoted
On Thu, Sep 13, 2012 at 04:26:34PM +0900, Alex Courbot wrote:
quoted
On Thursday 13 September 2012 15:19:30 Mark Brown wrote:
quoted
quoted
On Thursday 13 September 2012 14:25:53 Mark Brown wrote:
quoted
It would be sensible to make sure that the framework is done in
such a
way that drivers can use it - there will be drivers (perhaps not
display
ones) that have a known power sequence and which could benefit
from the
ability to use library code to implement it based on the user simply
supplying named resources.
quoted
quoted
quoted
Not sure I understand what you mean, but things should be working
this way
already - regulators and PWMs are acquired by name using the standard
regulator_get() and pwm_get() functions. GPIOs do not, AFAIK, have
a way
to be referenced by name so their number is used instead.
quoted
quoted
Right, but the sequencing for enabling them is currently open coded in
each driver.
quoted
Mmm then I'm afraid I don't see what you wanted to say initially -
could you
elaborate?
The driver knows the power sequence. Having to type the same sequence
into the DT or platform data for each board using the device wouuld be
retarded so we need the drivers to be able to give the sequence to the
library if they're going to be able to reuse it (which is a lot of what
Tomi is talking about).
I believe that's trivial to implement. The relevant function is:
struct power_seq_set *devm_power_seq_set_build(struct device *dev,
struct platform_power_seq_set *pseq);
It's up to the driver whether pseq comes from platform data or is
hard-coded into the driver (or not provided at all, for the DT case).
So, the only change needed to convert a "hard-coded" driver to this API
is to convert the current custom data structure (or code) that describes
the sequence into a struct platform_power_seq_set.
If we go this way (which looks good IMO!), then maybe we should abandon
that "platform" denomination and merge platform_power_seq* structures
with the currently private power_seq*, and also replace the "building"
step with a resources acquisition one. Calling these structures
"platform" implies they are for platform data while they can be used to
perform more flexible things as Mark mentioned.
That all seems reasonable.
Also making the resolved
resource visible would allow drivers to "patch" generic sequences with
the proper GPIO numbers at runtime.
That doesn't sound like a great idea to me, but we can simply avoid
doing this even though it's technically possible.
We would also avoid a few memory
copies and both design and usage would be simplified, at the cost of
having more things exposed. How does that sound?