* Re: [PATCH V5 0/6] OMAPDSS: Cleanup cpu_is checks
From: Tony Lindgren @ 2012-08-30 17:19 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: Chandrabhanu Mahapatra, paul, linux-omap, linux-fbdev
In-Reply-To: <1346312061.2327.27.camel@deskari>
Hi,
* Tomi Valkeinen <tomi.valkeinen@ti.com> [120830 00:35]:
> On Wed, 2012-08-29 at 17:20 -0700, Tony Lindgren wrote:
> >
> > Good to see this, we need this badly to avoid blocking
> > single zImage effort on omaps. Can you also please take
>
> What is the issue with single zImage? How do cpu_is_ check affect it?
The usage for that should only be limited to arch/arm/mach-omap2
so we can make cpu.h local as we can't include mach and plat
header files from the drivers with single zImage.
> I had a brief look at drivers/video/omap*. Here's a brief status. I
> don't really know much about the old fb driver (drivers/video/omap) so
> my comments may not be totally correct. And all fixing I do there is
> done in blind, I don't have any omap1 devices.
>
> I've left out the trivial cleanups from the list (i.e. file includes a
> header that it doesn't need), there were a bunch of those. I'll make a
> patch for these.
>
>
> $ git grep -E "<plat|<mach" drivers/video/omap*
> drivers/video/omap/lcd_ams_delta.c:#include <plat/board-ams-delta.h>
> * Needs to be moved
Yes, that should be either mach/board-ams-delta.h, or separate driver
specific headers in include/linux/platform_data. For omap1 we are not
planning common zImage support, so let's just make sure we're not
breaking anything there as people are still using it.
> * lcd_ams_delta uses also omap_write/read
Limiting omap_write/read to omap1 is OK for now, unless the fix
is trivial to do with ioremap + readw/writew.
> drivers/video/omap/lcd_inn1510.c:#include <plat/fpga.h>
> * No idea about this. Who wants to convert the fpga support? =)
I'll move it to mach/fpga.h as it's omap1 specifc.
> drivers/video/omap/lcd_mipid.c:#include <plat/lcd_mipid.h>
> * Needs to be moved
>
> drivers/video/omap/lcd_osk.c:#include <plat/mux.h>
> * Uses omap_cfg_reg(PWL). I don't know what this is...
I'll move plat/mux.h into mach for omap1. For omap2+, we have
a local mux.h and are moving to use device tree based pinctrl-single
driver.
> * lcd_osk.c uses omap_write/read
>
> drivers/video/omap/lcdc.c:#include <mach/lcdc.h>
> * Needs to be moved
This you can move to platform_data or mach for omap1?
> drivers/video/omap/lcdc.c:#include <plat/dma.h>
> * Uses arch/arm/mach-omap1/lcd_dma.c. Any idea about this? Will DMA
> engine support OMAP1's LCD DMA?
I think it should eventually as it can detect the device and could
automatically call those functions. Not sure if all options for
configuring it are available yet in dma engine.
> drivers/video/omap/omapfb_main.c:#include <plat/dma.h>
> * Uses DMA API to set DMA priority
>
> drivers/video/omap/sossi.c:#include <plat/dma.h>
> * Uses arch/arm/mach-omap1/lcd_dma.c
>
> drivers/video/omap2/dss/dss.c:#include <plat/cpu.h>
> * Uses cpu_is_* to find out the DSS version. dispc.c also uses cpu_is_*
> functions, but doesn't include plat/cpu.h. I know cpu_is_* checks should
> be removed, but is there some other file to include for the time being
> than plat/cpu.h?
We could make it mach/cpu.h for omap1, but ideally we would just
pass DSS_VERSION_XYZ type flag in platform data on omap1.
> drivers/video/omap2/dss/dss_features.c:#include <plat/cpu.h>
> * Uses cpu_is_* to find out the DSS version
Here too.
> drivers/video/omap2/omapfb/omapfb-ioctl.c:#include <plat/vrfb.h>
> drivers/video/omap2/omapfb/omapfb-ioctl.c:#include <plat/vram.h>
> drivers/video/omap2/omapfb/omapfb-main.c:#include <plat/vram.h>
> drivers/video/omap2/omapfb/omapfb-main.c:#include <plat/vrfb.h>
> drivers/video/omap2/omapfb/omapfb-sysfs.c:#include <plat/vrfb.h>
> drivers/video/omap2/vram.c:#include <plat/vram.h>
> drivers/video/omap2/vram.c:#include <plat/dma.h>
> drivers/video/omap2/vrfb.c:#include <plat/vrfb.h>
> drivers/video/omap2/vrfb.c:#include <plat/sdrc.h>
>
> Of these, I'm not sure how to handle.
These should eventually be in platform_data as driver specific headers.
> Grep shows that vram.c is only used by (the newer) omapfb, so it could
> be considered a part of that driver. It still needs to be built-in, as
> it needs to reserve memory early in the boot process (done with a call
> from arch/arm/plat-omap/common.c).
Hmm it sounds like omap_vram_reserve_sdram_memblock() should be in
plat-omap and just pass the pointer for later use for vram.c.
> Also board files can use a func call to define the amount of memory to
> allocate, but only rx51 seems to do this in the mainline.
>
> Anyway, I believe vram.c is going away when we start to use CMA.
OK cool.
> As for vrfb... I'm not really sure where it belongs. It is used by the
> newer omapfb and OMAP V4L2 driver. VRFB is a part of the OMAP's memory
> controller, so I'm not sure if it's really a normal driver.
Maybe just split it to platform code for the memblock stuff and pass
the necessary information to the driver in platform_data?
Regards,
Tony
^ permalink raw reply
* Re: [PATCH V5 0/6] OMAPDSS: Cleanup cpu_is checks
From: Tomi Valkeinen @ 2012-08-31 11:23 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Chandrabhanu Mahapatra, paul, linux-omap, linux-fbdev
In-Reply-To: <20120830171908.GQ1303@atomide.com>
[-- Attachment #1: Type: text/plain, Size: 3923 bytes --]
On Thu, 2012-08-30 at 10:19 -0700, Tony Lindgren wrote:
> Hi,
>
> * Tomi Valkeinen <tomi.valkeinen@ti.com> [120830 00:35]:
> > On Wed, 2012-08-29 at 17:20 -0700, Tony Lindgren wrote:
> > >
> > > Good to see this, we need this badly to avoid blocking
> > > single zImage effort on omaps. Can you also please take
> >
> > What is the issue with single zImage? How do cpu_is_ check affect it?
>
> The usage for that should only be limited to arch/arm/mach-omap2
> so we can make cpu.h local as we can't include mach and plat
> header files from the drivers with single zImage.
Ok.
> > $ git grep -E "<plat|<mach" drivers/video/omap*
> > drivers/video/omap/lcd_ams_delta.c:#include <plat/board-ams-delta.h>
> > * Needs to be moved
>
> Yes, that should be either mach/board-ams-delta.h, or separate driver
> specific headers in include/linux/platform_data. For omap1 we are not
> planning common zImage support, so let's just make sure we're not
> breaking anything there as people are still using it.
Hmm, so did I understand right, for omap1 stuff we can still include
from arch/arm/mach-omap1/include/mach?
If so, that makes things easier. I can manage the omap2+ stuff fine, but
I have no experience with omap1, nor do I have any omap1 devices. So I'd
rather keep the omap1 code as it is, in fear that I'd just break it
totally, and I'd rather spend my time on omap2+ code.
> > drivers/video/omap2/dss/dss.c:#include <plat/cpu.h>
> > * Uses cpu_is_* to find out the DSS version. dispc.c also uses cpu_is_*
> > functions, but doesn't include plat/cpu.h. I know cpu_is_* checks should
> > be removed, but is there some other file to include for the time being
> > than plat/cpu.h?
>
> We could make it mach/cpu.h for omap1, but ideally we would just
> pass DSS_VERSION_XYZ type flag in platform data on omap1.
Ok. The omap1 fb driver seems to contain a few cpu_is_omap15xx() checks,
nothing else.
> > drivers/video/omap2/dss/dss_features.c:#include <plat/cpu.h>
> > * Uses cpu_is_* to find out the DSS version
>
> Here too.
Yep, for omap2+ I'll create a version ID that we'll pass via plat data.
> > drivers/video/omap2/omapfb/omapfb-ioctl.c:#include <plat/vrfb.h>
> > drivers/video/omap2/omapfb/omapfb-ioctl.c:#include <plat/vram.h>
> > drivers/video/omap2/omapfb/omapfb-main.c:#include <plat/vram.h>
> > drivers/video/omap2/omapfb/omapfb-main.c:#include <plat/vrfb.h>
> > drivers/video/omap2/omapfb/omapfb-sysfs.c:#include <plat/vrfb.h>
> > drivers/video/omap2/vram.c:#include <plat/vram.h>
> > drivers/video/omap2/vram.c:#include <plat/dma.h>
> > drivers/video/omap2/vrfb.c:#include <plat/vrfb.h>
> > drivers/video/omap2/vrfb.c:#include <plat/sdrc.h>
> >
> > Of these, I'm not sure how to handle.
>
> These should eventually be in platform_data as driver specific headers.
>
> > Grep shows that vram.c is only used by (the newer) omapfb, so it could
> > be considered a part of that driver. It still needs to be built-in, as
> > it needs to reserve memory early in the boot process (done with a call
> > from arch/arm/plat-omap/common.c).
>
> Hmm it sounds like omap_vram_reserve_sdram_memblock() should be in
> plat-omap and just pass the pointer for later use for vram.c.
>
> > Also board files can use a func call to define the amount of memory to
> > allocate, but only rx51 seems to do this in the mainline.
> >
> > Anyway, I believe vram.c is going away when we start to use CMA.
>
> OK cool.
>
> > As for vrfb... I'm not really sure where it belongs. It is used by the
> > newer omapfb and OMAP V4L2 driver. VRFB is a part of the OMAP's memory
> > controller, so I'm not sure if it's really a normal driver.
>
> Maybe just split it to platform code for the memblock stuff and pass
> the necessary information to the driver in platform_data?
I'll try to figure out something for vrfb.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH v5 0/4] Runtime Interpreted Power Sequences
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
Arnd Bergmann
Cc: Leela Krishna Amudala, linux-tegra, linux-kernel, linux-fbdev,
devicetree-discuss, linux-pm, linux-doc, Alexandre Courbot
New revision taking (hopefully) all the feedback received from the previous
version into account. It's funny how a 30 lines patch to switch my backlight
turned into a 1500 lines patchset introducing a new framework. And in the end
my backlight switches just the same.
So anyway, the main updates are:
* Types of DT steps are now determined by a "type" property and not by the
presence of a specific property.
* Power sequences and their resources are now encapsulated into a "set"
structure. I was reluctant to this idea but have to admit now that it is way
cleaner.
* GPIO steps now refer the GPIO phandle directly in the DT instead of by name.
The GPIO framework does not work like regulator or PWM in that GPIOs cannot be
accessed by name, so it did not make sense anyway. And thanks to that we now
have perfect matching between the platform data members and the DT properties,
which makes everything more consistent.
* Moved the implementations of resources into their own file (directly included
from the main file) and added an "ops" structure to abstract them. This
clearly separates the framework from the resources implementations and should
make it easier to add new resources types.
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 | 117 ++++++
.../bindings/video/backlight/pwm-backlight.txt | 67 +++-
Documentation/power/power_seq.txt | 225 +++++++++++
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 | 81 ++++
drivers/power/power_seq/power_seq_pwm.c | 85 ++++
drivers/power/power_seq/power_seq_regulator.c | 86 ++++
drivers/video/backlight/Kconfig | 1 +
drivers/video/backlight/pwm_bl.c | 179 ++++++---
include/linux/power_seq.h | 174 ++++++++
include/linux/pwm_backlight.h | 15 +-
18 files changed, 1537 insertions(+), 56 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
^ permalink raw reply
* [PATCH v5 1/4] Runtime Interpreted Power Sequences
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
Arnd Bergmann
Cc: Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-pm-u79uwXL29TY76Z2rM5mHXA, linux-doc-u79uwXL29TY76Z2rM5mHXA,
Alexandre Courbot
In-Reply-To: <1346412846-17102-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
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 | 117 ++++++
Documentation/power/power_seq.txt | 225 +++++++++++
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 | 81 ++++
drivers/power/power_seq/power_seq_pwm.c | 85 ++++
drivers/power/power_seq/power_seq_regulator.c | 86 ++++
include/linux/power_seq.h | 174 ++++++++
12 files changed, 1270 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
diff --git a/Documentation/devicetree/bindings/power_seq/power_seq.txt b/Documentation/devicetree/bindings/power_seq/power_seq.txt
new file mode 100644
index 0000000..d3e3f6a
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_seq/power_seq.txt
@@ -0,0 +1,117 @@
+Runtime Interpreted Power Sequences
+=================+
+Power sequences are sequential descriptions of actions to be performed on
+power-related resources. Having these descriptions in a precise 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.
+
+In the device tree, power sequences are grouped into a set. The set is always
+declared as the "power-sequences" sub-node of the device node. Power sequences
+may reference resources declared by that device.
+
+Power Sequences Structure
+-------------------------
+Every device that makes use of power sequences must have a "power-sequences"
+sub-node. Power sequences are sub-nodes of this set node, and their node name
+indicates the id of the sequence.
+
+Every power sequence in turn contains its steps as sub-nodes of itself. Step
+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
+---------------------
+Step of a sequence describes 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_us: 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:
+ - number: phandle of the GPIO to use.
+ - enable / disable: one of these two empty properties must be present to
+ enable or disable the resource
+
+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_us = <10000>;
+ };
+ step2 {
+ type = "pwm";
+ id = "backlight";
+ enable;
+ };
+ step3 {
+ type = "gpio";
+ number = <&gpio 28 0>;
+ enable;
+ };
+ };
+
+ power-off {
+ step0 {
+ type = "gpio";
+ number = <&gpio 28 0>;
+ disable;
+ };
+ step1 {
+ type = "pwm";
+ id = "backlight";
+ disable;
+ };
+ step2 {
+ type = "delay";
+ delay_us = <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 in a way
+that makes them accessible by name.
+
+After the resources declaration, two sequences follow for powering the backlight
+on and off. Their names are specified by the pwm-backlight driver.
diff --git a/Documentation/power/power_seq.txt b/Documentation/power/power_seq.txt
new file mode 100644
index 0000000..48d1f6b
--- /dev/null
+++ b/Documentation/power/power_seq.txt
@@ -0,0 +1,225 @@
+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 to remove the callback mechanism and makes the kernel less
+board-dependant.
+
+What are Power Sequences?
+-------------------------
+Power sequences are a series of sequential steps during which an action is
+performed on a resource. The supported resources and actions operations are:
+- delay (just wait for a given number of microseconds)
+- GPIO (enable or disable)
+- regulator (enable or disable)
+- PWM (enable or disable)
+
+When a power sequence is run, each of its steps is executed sequentially until
+one step fails or the end of the sequence is reached.
+
+Power sequences are grouped in "sets" and declared per-device. Every sequence
+must be attributed a name that can be used to retrieve it from its set when it
+is needed.
+
+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 given device is an instance of platform_power_seq_set
+which points to instances of platform_power_seq. Every platform_power_seq is a
+single power sequence, and is itself composed of a variable length array of
+steps.
+
+A step is a union of all the step structures. Which one is to be used depends on
+the type of the step. Step structures are documented in the
+include/linux/power_seq.h file ; please refer to it for all details, but the
+following example will probably make it clear how power sequences should be
+defined. It defines two power sequences named "power_on" and "power_off". The
+"power_on" sequence enables a regulator called "power" (retrieved from the
+device using regulator_get()), waits for 10ms, and then enabled GPIO 110.
+"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_us = 10000,
+ },
+ },
+ {
+ .type = POWER_SEQ_GPIO,
+ .gpio = {
+ .number = 110,
+ .enable = true,
+ },
+ },
+ },
+};
+
+static struct platform_power_seq power_off_seq = {
+ .id = "power_off",
+ .num_steps = 3,
+ .steps = {
+ {
+ .type = POWER_SEQ_GPIO,
+ .gpio = {
+ .number = 110,
+ .enable = false,
+ },
+ },
+ {
+ .type = POWER_SEQ_DELAY,
+ .delay = {
+ .delay_us = 10000,
+ },
+ },
+ {
+ .type = POWER_SEQ_REGULATOR,
+ .regulator = {
+ .id = "power",
+ .enable = false,
+ },
+ },
+ },
+};
+
+static struct platform_power_seq_set power_sequences = {
+ .num_seqs = 2,
+ .seqs = {
+ &power_on_seq,
+ &power_off_seq,
+ },
+};
+
+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";
+ number = <&gpio 110 0>;
+ enable;
+ };
+ }
+ power-off {
+ step0 {
+ type = "gpio";
+ number = <&gpio 110 0>;
+ disable;
+ };
+ 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 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.
+
+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.
+
+Power sequences can then be retrieved by their name using power_seq_lookup:
+
+ struct power_seq *power_seq_lookup(struct power_seq_set *seqs,
+ const char *id);
+
+A power sequence can 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 occured.
+
+Sometimes, you may want to browse the list of resources allocated by a sequence,
+to for instance 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 of type struct power_seq_resource. This structure contains a
+"pdata" pointer that can be used to explore the platform data of this resource,
+as well as the resolved resource, if applicable.
+
+Finally, users of the device tree can build the platform data corresponding to
+the tree node using this function:
+
+ struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
+
+As the device tree syntax unambiguously states the name of the node containing
+the power sequences, it only needs a pointer to the device to work. The result
+can then be passed to devm_power_seq_set_build() in order to get a set of
+runnable sequences.
+
+devm_of_parse_power_seq_set allocates its memory using devm, but the platform
+data becomes unneeded after devm_power_seq_set_build() is called on it and can
+thus be freed. Be aware though that one allocation is performed for the set and
+for every sequence. The devm_power_seq_platform_data_free() function takes care
+of freeing the memory properly:
+
+ void devm_platform_power_seq_set_free(struct platform_power_seq_set *pseq);
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index fcc1bb0..5fdfd84 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -312,3 +312,4 @@ config AB8500_BATTERY_THERM_ON_BATCTRL
endif # POWER_SUPPLY
source "drivers/power/avs/Kconfig"
+source "drivers/power/power_seq/Kconfig"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index ee58afb..d3c893b 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -45,3 +45,4 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_POWER_AVS) += avs/
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
+obj-$(CONFIG_POWER_SEQ) += power_seq/
diff --git a/drivers/power/power_seq/Kconfig b/drivers/power/power_seq/Kconfig
new file mode 100644
index 0000000..3bff26e
--- /dev/null
+++ b/drivers/power/power_seq/Kconfig
@@ -0,0 +1,2 @@
+config POWER_SEQ
+ bool
diff --git a/drivers/power/power_seq/Makefile b/drivers/power/power_seq/Makefile
new file mode 100644
index 0000000..f77a359
--- /dev/null
+++ b/drivers/power/power_seq/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_POWER_SEQ) += power_seq.o
diff --git a/drivers/power/power_seq/power_seq.c b/drivers/power/power_seq/power_seq.c
new file mode 100644
index 0000000..e4d482c
--- /dev/null
+++ b/drivers/power/power_seq/power_seq.c
@@ -0,0 +1,446 @@
+/*
+ * power_seq.c - A simple power sequence interpreter for platform devices
+ * and device tree.
+ *
+ * Author: Alexandre Courbot <acourbot@nvidia.com>
+ *
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/power_seq.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+#include <linux/of.h>
+
+struct power_seq_set {
+ struct device *dev;
+ struct list_head resources;
+ struct list_head sequences;
+};
+
+struct power_seq_step {
+ /* Copy of the platform data */
+ struct platform_power_seq_step pdata;
+ /* Resolved resource */
+ struct power_seq_resource *resource;
+};
+
+struct power_seq {
+ /* Set this sequence belongs to */
+ struct power_seq_set *parent_set;
+ const char *id;
+ /* To thread into power_seqs structure */
+ struct list_head list;
+ unsigned int num_steps;
+ struct power_seq_step steps[];
+};
+
+#define power_seq_err(dev, seq, step_nbr, format, ...) \
+ dev_err(dev, "%s[%d]: " format, seq->id, step_nbr, ##__VA_ARGS__);
+
+/**
+ * struct power_seq_res_type - operators for power sequences resources
+ * @name: Name of the resource type. Set to null when a resource
+ * type support is not compiled in
+ * @need_resource: Whether a resource needs to be allocated when steps of
+ * this kind are met. If set to false, res_compare and
+ * res_alloc need not be set
+ * @of_parse: Parse a step for this kind of resource from a device
+ * tree node. The result of parsing must be written into
+ * step step_nbr of seq
+ * @step_run: Run a step for this kind of resource
+ * @res_compare: Return true if the resource used by both steps is the
+ * same, false otherwise
+ * @res_alloc: Resolve and allocate the resource passed from seq
+ * Return error code if the resource cannot be allocated
+ */
+struct power_seq_res_ops {
+ const char *name;
+ bool need_resource;
+ int (*of_parse)(struct device *dev, struct device_node *node,
+ struct platform_power_seq *seq, unsigned int step_nbr);
+ int (*step_run)(struct power_seq_step *step);
+ bool (*res_compare)(struct platform_power_seq_step *step1,
+ struct platform_power_seq_step *step2);
+ int (*res_alloc)(struct device *dev, struct power_seq_resource *seq);
+};
+
+static const struct power_seq_res_ops power_seq_types[POWER_SEQ_NUM_TYPES];
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_enable_properties(struct device *dev,
+ struct device_node *node,
+ struct platform_power_seq *seq,
+ unsigned int step_nbr,
+ bool *enable)
+{
+ if (of_find_property(node, "enable", NULL)) {
+ *enable = true;
+ } else if (of_find_property(node, "disable", NULL)) {
+ *enable = false;
+ } else {
+ power_seq_err(dev, seq, step_nbr,
+ "missing enable or disable property\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int of_power_seq_parse_step(struct device *dev, struct device_node *node,
+ struct platform_power_seq *seq,
+ unsigned int step_nbr)
+{
+ struct platform_power_seq_step *step = &seq->steps[step_nbr];
+ const char *type;
+ int i, err;
+
+ err = of_property_read_string(node, "type", &type);
+ if (err < 0) {
+ power_seq_err(dev, seq, step_nbr,
+ "cannot read type property\n");
+ return err;
+ }
+ 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);
+
+ return err;
+}
+
+static struct platform_power_seq *of_parse_power_seq(struct device *dev,
+ struct device_node *node)
+{
+ struct device_node *child = NULL;
+ struct platform_power_seq *pseq;
+ int num_steps, sz;
+ int err;
+
+ if (!node)
+ return ERR_PTR(-EINVAL);
+
+ num_steps = of_get_child_count(node);
+ sz = sizeof(*pseq) + sizeof(pseq->steps[0]) * num_steps;
+ pseq = devm_kzalloc(dev, sz, GFP_KERNEL);
+ if (!pseq)
+ return ERR_PTR(-ENOMEM);
+ pseq->num_steps = num_steps;
+ pseq->id = node->name;
+
+ for_each_child_of_node(node, child) {
+ unsigned int pos;
+
+ /* Check that the name's format is correct and within bounds */
+ if (strncmp("step", child->name, 4)) {
+ err = -EINVAL;
+ goto parse_error;
+ }
+
+ err = kstrtouint(child->name + 4, 10, &pos);
+ if (err < 0)
+ goto parse_error;
+
+ if (pos >= num_steps || pseq->steps[pos].type != 0) {
+ err = -EINVAL;
+ goto parse_error;
+ }
+
+ err = of_power_seq_parse_step(dev, child, pseq, pos);
+ if (err)
+ return ERR_PTR(err);
+ }
+
+ return pseq;
+
+parse_error:
+ dev_err(dev, "%s: invalid power step name %s!\n", pseq->id,
+ child->name);
+ return ERR_PTR(err);
+}
+
+/**
+ * of_parse_power_seq_set() - build platform data corresponding to a DT node
+ * @dev: Device on behalf of which the sequence is to be built
+ *
+ * Sequences must be contained into a subnode named "power-sequences" of the
+ * device root node.
+ *
+ * Memory for the platform sequence is allocated using devm_kzalloc on dev and
+ * can be freed by devm_kfree after power_seq_set_build returned. Beware that on
+ * top of the set itself, platform data for individual sequences should also be
+ * freed.
+ *
+ * Returns the built power sequence set on success, or an error code in case of
+ * failure.
+ */
+struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev)
+{
+ struct platform_power_seq_set *seqs;
+ struct device_node *root = dev->of_node;
+ struct device_node *seq;
+ int num_seqs, sz, i = 0;
+
+ if (!root)
+ return NULL;
+
+ root = of_find_node_by_name(root, "power-sequences");
+ if (!root)
+ return NULL;
+
+ 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)
+ return ERR_PTR(-ENOMEM);
+ seqs->num_seqs = num_seqs;
+
+ for_each_child_of_node(root, seq) {
+ struct platform_power_seq *pseq;
+
+ pseq = of_parse_power_seq(dev, seq);
+ if (IS_ERR(pseq))
+ return (void *)pseq;
+
+ seqs->seqs[i++] = pseq;
+ }
+
+ return seqs;
+}
+EXPORT_SYMBOL_GPL(devm_of_parse_power_seq_set);
+#endif /* CONFIG_OF */
+
+/**
+ * devm_platform_power_seq_set_free() - free data allocated by of_parse_power_seq_set
+ * @pseq: Platform data to free
+ *
+ * This function can be called *only* on data returned by of_parse_power_seq_set
+ * and *after* devm_power_seq_set_build has been called on it.
+ */
+void devm_platform_power_seq_set_free(struct device *dev,
+ struct platform_power_seq_set *pseq)
+{
+ int i;
+
+ for (i = 0; i < pseq->num_seqs; i++)
+ devm_kfree(dev, pseq->seqs[i]);
+
+ devm_kfree(dev, pseq);
+}
+EXPORT_SYMBOL_GPL(devm_platform_power_seq_set_free);
+
+static struct power_seq_resource *
+power_seq_find_resource(struct list_head *ress,
+ struct platform_power_seq_step *step)
+{
+ struct power_seq_resource *res;
+
+ list_for_each_entry(res, ress, list) {
+ struct platform_power_seq_step *pdata = res->pdata;
+
+ if (pdata->type != step->type)
+ continue;
+
+ if (power_seq_types[pdata->type].res_compare(pdata, step))
+ return res;
+ }
+
+ return NULL;
+}
+
+static struct power_seq *power_seq_build_one(struct device *dev,
+ struct power_seq_set *seqs,
+ struct platform_power_seq *pseq)
+{
+ struct power_seq *seq;
+ struct power_seq_resource *res;
+ int i, err;
+
+ seq = devm_kzalloc(dev, sizeof(*seq) + sizeof(seq->steps[0]) *
+ pseq->num_steps, GFP_KERNEL);
+ if (!seq)
+ return ERR_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++) {
+ struct platform_power_seq_step *pstep = &pseq->steps[i];
+ struct power_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);
+ return ERR_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)
+ return ERR_PTR(-ENOMEM);
+
+ res->pdata = &step->pdata;
+
+ err = power_seq_types[res->pdata->type].res_alloc(dev, res);
+ if (err < 0) {
+ power_seq_err(dev, seq, i,
+ "error building sequence\n");
+ return ERR_PTR(err);
+ }
+
+ list_add_tail(&res->list, &seqs->resources);
+ }
+ step->resource = res;
+ }
+
+ return seq;
+}
+
+/**
+ * power_seq_set_build() - build a set of runnable sequences from platform data
+ * @dev: Device that will use the power sequences. All resources will be
+ * devm-allocated against it
+ * @pseq: Platform data for the power sequences. It can be freed after
+ * this function returns
+ *
+ * All memory and resources (regulators, GPIOs, etc.) are allocated using devm
+ * functions.
+ *
+ * Returns the built sequence on success, an error code in case or failure.
+ */
+struct power_seq_set *devm_power_seq_set_build(struct device *dev,
+ struct platform_power_seq_set *pseq)
+{
+ struct power_seq_set *seqs;
+ int i;
+
+ seqs = devm_kzalloc(dev, sizeof(*seqs), GFP_KERNEL);
+
+ if (!seqs)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&seqs->resources);
+ INIT_LIST_HEAD(&seqs->sequences);
+ for (i = 0; i < pseq->num_seqs; i++) {
+ struct power_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);
+ }
+
+ return seqs;
+}
+EXPORT_SYMBOL_GPL(devm_power_seq_set_build);
+
+/**
+ * power_seq_lookup - Lookup a power sequence by name from a set
+ * @seqs: The set to look in
+ * @id: Name to look after
+ *
+ * Returns a matching power sequence if it exists, NULL if it does not.
+ */
+struct power_seq *power_seq_lookup(struct power_seq_set *seqs, const char *id)
+{
+ struct power_seq *seq;
+
+ list_for_each_entry(seq, &seqs->sequences, list) {
+ if (!strcmp(seq->id, id))
+ return seq;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(power_seq_lookup);
+
+/**
+ * power_seq_set_resources - return a list of all the resources used by a set
+ * @seqs: Power sequences set we are interested in getting the resources
+ *
+ * The returned list can be parsed using the power_seq_for_each_resource macro.
+ */
+struct list_head *power_seq_set_resources(struct power_seq_set *seqs)
+{
+ return &seqs->resources;
+}
+EXPORT_SYMBOL_GPL(power_seq_set_resources);
+
+/**
+ * power_seq_run() - run a power sequence
+ * @seq: The power sequence to run
+ *
+ * Returns 0 on success, error code in case of failure.
+ */
+int power_seq_run(struct power_seq *seq)
+{
+ unsigned int i;
+ int err;
+
+ if (!seq)
+ return 0;
+
+ for (i = 0; i < seq->num_steps; i++) {
+ unsigned int type = 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);
+ return err;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(power_seq_run);
+
+#include "power_seq_delay.c"
+#include "power_seq_regulator.c"
+#include "power_seq_pwm.c"
+#include "power_seq_gpio.c"
+
+static const struct power_seq_res_ops power_seq_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");
diff --git a/drivers/power/power_seq/power_seq_delay.c b/drivers/power/power_seq/power_seq_delay.c
new file mode 100644
index 0000000..072bf50
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_delay.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/delay.h>
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_delay(struct device *dev,
+ struct device_node *node,
+ struct platform_power_seq *seq,
+ unsigned int step_nbr)
+{
+ struct platform_power_seq_step *step = &seq->steps[step_nbr];
+ int err;
+
+ err = of_property_read_u32(node, "delay_us",
+ &step->delay.delay_us);
+ if (err < 0)
+ power_seq_err(dev, seq, step_nbr,
+ "error reading delay_us property\n");
+
+ return err;
+}
+#else
+#define of_power_seq_parse_delay NULL
+#endif
+
+static int power_seq_step_run_delay(struct power_seq_step *step)
+{
+ usleep_range(step->pdata.delay.delay_us,
+ step->pdata.delay.delay_us + 1000);
+
+ return 0;
+}
+
+#define POWER_SEQ_DELAY_TYPE { \
+ .name = "delay", \
+ .need_resource = false, \
+ .of_parse = of_power_seq_parse_delay, \
+ .step_run = power_seq_step_run_delay, \
+}
diff --git a/drivers/power/power_seq/power_seq_gpio.c b/drivers/power/power_seq/power_seq_gpio.c
new file mode 100644
index 0000000..2e9a49f
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_gpio.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#ifdef CONFIG_OF
+static int power_seq_of_parse_gpio(struct device *dev,
+ struct device_node *node,
+ struct platform_power_seq *seq,
+ unsigned int step_nbr)
+{
+ struct platform_power_seq_step *step = &seq->steps[step_nbr];
+ int gpio;
+ int err;
+
+ gpio = of_get_named_gpio(node, "number", 0);
+ if (gpio < 0) {
+ power_seq_err(dev, seq, step_nbr,
+ "error reading number property\n");
+ return gpio;
+ }
+ step->gpio.number = gpio;
+
+ err = of_power_seq_parse_enable_properties(dev, node, seq, step_nbr,
+ &step->gpio.enable);
+
+ return err;
+}
+#else
+#define of_power_seq_parse_gpio NULL
+#endif
+
+static bool power_seq_res_compare_gpio(struct platform_power_seq_step *step1,
+ struct platform_power_seq_step *step2)
+{
+ return step1->gpio.number = step2->gpio.number;
+}
+
+static int power_seq_res_alloc_gpio(struct device *dev,
+ struct power_seq_resource *res)
+{
+ int err;
+
+ err = devm_gpio_request_one(dev, res->pdata->gpio.number,
+ GPIOF_OUT_INIT_LOW, dev_name(dev));
+ if (err) {
+ dev_err(dev, "cannot get gpio %d\n", res->pdata->gpio.number);
+ return err;
+ }
+
+ return 0;
+}
+
+static int power_seq_step_run_gpio(struct power_seq_step *step)
+{
+ gpio_set_value_cansleep(step->pdata.gpio.number,
+ step->pdata.gpio.enable);
+
+ return 0;
+}
+
+#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, \
+}
diff --git a/drivers/power/power_seq/power_seq_pwm.c b/drivers/power/power_seq/power_seq_pwm.c
new file mode 100644
index 0000000..a80514f
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_pwm.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifdef CONFIG_PWM
+
+#include <linux/pwm.h>
+
+#ifdef CONFIG_OF
+static int power_seq_of_parse_pwm(struct device *dev,
+ struct device_node *node,
+ struct platform_power_seq *seq,
+ unsigned int step_nbr)
+{
+ struct platform_power_seq_step *step = &seq->steps[step_nbr];
+ int err;
+
+ err = of_property_read_string(node, "id",
+ &step->pwm.id);
+ if (err) {
+ power_seq_err(dev, seq, step_nbr,
+ "error reading id property\n");
+ return err;
+ }
+
+ err = of_power_seq_parse_enable_properties(dev, node, seq, step_nbr,
+ &step->pwm.enable);
+ return err;
+}
+#else
+#define of_power_seq_parse_pwm NULL
+#endif
+
+static bool power_seq_res_compare_pwm(struct platform_power_seq_step *step1,
+ struct platform_power_seq_step *step2)
+{
+ return (!strcmp(step1->pwm.id, step2->pwm.id));
+}
+
+static int power_seq_res_alloc_pwm(struct device *dev,
+ struct power_seq_resource *res)
+{
+ res->pwm = devm_pwm_get(dev, res->pdata->pwm.id);
+ if (IS_ERR(res->pwm)) {
+ dev_err(dev, "cannot get pwm \"%s\"\n", res->pdata->pwm.id);
+ return PTR_ERR(res->pwm);
+ }
+
+ return 0;
+}
+
+static int power_seq_step_run_pwm(struct power_seq_step *step)
+{
+ if (step->pdata.gpio.enable) {
+ return pwm_enable(step->resource->pwm);
+ } else {
+ pwm_disable(step->resource->pwm);
+ return 0;
+ }
+}
+
+#define POWER_SEQ_PWM_TYPE { \
+ .name = "pwm", \
+ .need_resource = true, \
+ .of_parse = power_seq_of_parse_pwm, \
+ .step_run = power_seq_step_run_pwm, \
+ .res_compare = power_seq_res_compare_pwm, \
+ .res_alloc = power_seq_res_alloc_pwm, \
+}
+
+#else
+
+#define POWER_SEQ_PWM_TYPE {}
+
+#endif
diff --git a/drivers/power/power_seq/power_seq_regulator.c b/drivers/power/power_seq/power_seq_regulator.c
new file mode 100644
index 0000000..915eac1
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_regulator.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifdef CONFIG_REGULATOR
+
+#include <linux/regulator/consumer.h>
+
+/* TODO change "which" */
+#ifdef CONFIG_OF
+static int power_seq_of_parse_regulator(struct device *dev,
+ struct device_node *node,
+ struct platform_power_seq *seq,
+ unsigned int step_nbr)
+{
+ struct platform_power_seq_step *step = &seq->steps[step_nbr];
+ int err;
+
+ err = of_property_read_string(node, "id",
+ &step->regulator.id);
+ if (err) {
+ power_seq_err(dev, seq, step_nbr,
+ "error reading id property\n");
+ return err;
+ }
+
+ err = of_power_seq_parse_enable_properties(dev, node, seq, step_nbr,
+ &step->regulator.enable);
+ return err;
+}
+#else
+#define of_power_seq_parse_regulator NULL
+#endif
+
+static bool
+power_seq_res_compare_regulator(struct platform_power_seq_step *step1,
+ struct platform_power_seq_step *step2)
+{
+ return (!strcmp(step1->regulator.id, step2->regulator.id));
+}
+
+static int power_seq_res_alloc_regulator(struct device *dev,
+ struct power_seq_resource *res)
+{
+ res->regulator = devm_regulator_get(dev, res->pdata->regulator.id);
+ if (IS_ERR(res->regulator)) {
+ dev_err(dev, "cannot get regulator \"%s\"\n",
+ res->pdata->regulator.id);
+ return PTR_ERR(res->regulator);
+ }
+
+ return 0;
+}
+
+static int power_seq_step_run_regulator(struct power_seq_step *step)
+{
+ if (step->pdata.regulator.enable)
+ return regulator_enable(step->resource->regulator);
+ else
+ return regulator_disable(step->resource->regulator);
+}
+
+#define POWER_SEQ_REGULATOR_TYPE { \
+ .name = "regulator", \
+ .need_resource = true, \
+ .of_parse = power_seq_of_parse_regulator, \
+ .step_run = power_seq_step_run_regulator, \
+ .res_compare = power_seq_res_compare_regulator, \
+ .res_alloc = power_seq_res_alloc_regulator, \
+}
+
+#else
+
+#define POWER_SEQ_REGULATOR_TYPE {}
+
+#endif
diff --git a/include/linux/power_seq.h b/include/linux/power_seq.h
new file mode 100644
index 0000000..78e8d77
--- /dev/null
+++ b/include/linux/power_seq.h
@@ -0,0 +1,174 @@
+/*
+ * power_seq.h
+ *
+ * Simple interpreter for defining power sequences as platform data or device
+ * tree properties.
+ *
+ * Power sequences are designed to replace the callbacks typically used in
+ * board-specific files that implement board-specific power sequences of devices
+ * such as backlights. A power sequence is an array of resources (which can a
+ * regulator, a GPIO, a PWM, ...) with an action to perform on it (enable or
+ * disable) and optional pre and post step delays. By having them interpreted
+ * instead of arbitrarily executed, it is possible to describe these in the
+ * device tree and thus remove board-specific code from the kernel.
+ *
+ * Author: Alexandre Courbot <acourbot@nvidia.com>
+ *
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __LINUX_POWER_SEQ_H
+#define __LINUX_POWER_SEQ_H
+
+#include <linux/types.h>
+
+struct device;
+struct regulator;
+struct pwm_device;
+struct device_node;
+
+/**
+ * The different kinds of resources that can be controlled during the sequences.
+ */
+enum power_seq_res_type {
+ POWER_SEQ_DELAY,
+ POWER_SEQ_REGULATOR,
+ POWER_SEQ_PWM,
+ POWER_SEQ_GPIO,
+ POWER_SEQ_NUM_TYPES,
+};
+
+/**
+ * struct platform_power_seq_delay_step - platform data for delay steps
+ * @delay_us: Amount of time to wait, in microseconds.
+ */
+struct platform_power_seq_delay_step {
+ unsigned int delay_us;
+};
+
+/**
+ * struct platform_power_seq_regulator_step - platform data for regulator steps
+ * @id: Name of the regulator to use. The regulator will be obtained
+ * using devm_regulator_get(dev, name)
+ * @enable: Whether to enable or disable the regulator during this step
+ */
+struct platform_power_seq_regulator_step {
+ const char *id;
+ bool enable;
+};
+
+/**
+ * struct platform_power_seq_pwm_step - platform data for PWM steps
+ * @id: Name of the pwm to use. The PWM will be obtained using
+ * devm_pwm_get(dev, name)
+ * @enable: Whether to enable or disable the PWM during this step
+ */
+struct platform_power_seq_pwm_step {
+ const char *id;
+ bool enable;
+};
+
+/**
+ * struct platform_power_seq_gpio_step - platform data for GPIO steps
+ * @number: Number of the GPIO to use. The GPIO will be obtained using
+ * devm_gpio_request_one(dev, number)
+ * @enable: Whether to enable or disable the GPIO during this step
+ */
+struct platform_power_seq_gpio_step {
+ int number;
+ bool enable;
+};
+
+/**
+ * struct platform_power_seq_step - platform data for power sequences steps
+ * @type: The type of this step. This decides which member of the union is
+ * valid for this step.
+ * @delay: Used if type = POWER_SEQ_DELAY
+ * @regulator: Used if type = POWER_SEQ_REGULATOR
+ * @pwm: Used if type = POWER_SEQ_PWN
+ * @gpio: Used if type = POWER_SEQ_GPIO
+ */
+struct platform_power_seq_step {
+ enum power_seq_res_type type;
+ union {
+ struct platform_power_seq_delay_step delay;
+ struct platform_power_seq_regulator_step regulator;
+ struct platform_power_seq_pwm_step pwm;
+ struct platform_power_seq_gpio_step gpio;
+ };
+};
+
+/**
+ * struct platform_power_seq - platform data for power sequences
+ * @id: Name through which this sequence is refered
+ * @num_steps: Number of steps in that sequence
+ * @steps: Array of num_steps steps describing the sequence
+ */
+struct platform_power_seq {
+ const char *id;
+ unsigned int num_steps;
+ struct platform_power_seq_step steps[];
+};
+
+/**
+ * struct platform_power_seq_set - platform data for sets of sequences
+ * @num_seqs: Number of sequences in this set
+ * @seqs: Array of pointers to individual sequences
+ */
+struct platform_power_seq_set {
+ unsigned int num_seqs;
+ struct platform_power_seq* seqs[];
+};
+
+/**
+ * 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
+ */
+struct power_seq_resource {
+ /* relevant for resolving the resource and knowing its type */
+ struct platform_power_seq_step *pdata;
+ /* resolved resource (if any) */
+ union {
+ struct regulator *regulator;
+ struct pwm_device *pwm;
+ };
+ struct list_head list;
+};
+#define power_seq_for_each_resource(pos, seqs) \
+ list_for_each_entry(pos, power_seq_set_resources(seqs), list)
+
+struct power_seq_resource;
+struct power_seq;
+struct power_seq_set;
+
+#ifdef CONFIG_OF
+struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
+#else
+inline struct platform_power_seq_set *of_parse_power_seq_set(struct device *dev)
+{
+ return NULL;
+}
+#endif
+void devm_platform_power_seq_set_free(struct device *dev,
+ struct platform_power_seq_set *pseq);
+
+struct power_seq_set *devm_power_seq_set_build(struct device *dev,
+ struct platform_power_seq_set *pseq);
+struct list_head *power_seq_set_resources(struct power_seq_set *seqs);
+struct power_seq *power_seq_lookup(struct power_seq_set *seqs, const char *id);
+int power_seq_run(struct power_seq *seq);
+
+#endif
--
1.7.12
^ permalink raw reply related
* [PATCH v5 2/4] pwm_backlight: use power sequences
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
Arnd Bergmann
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1346412846-17102-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Make use of the power sequences specified in the device tree or platform
data to control how the backlight is powered on and off.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
.../bindings/video/backlight/pwm-backlight.txt | 67 +++++++-
drivers/video/backlight/Kconfig | 1 +
drivers/video/backlight/pwm_bl.c | 179 +++++++++++++++------
include/linux/pwm_backlight.h | 15 +-
4 files changed, 208 insertions(+), 54 deletions(-)
diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
index 1e4fc72..873b993 100644
--- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
@@ -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
@@ -12,17 +13,73 @@ Required properties:
array defined by the "brightness-levels" property)
Optional properties:
- - pwm-names: a list of names for the PWM devices specified in the
- "pwms" property (see PWM binding[0])
+ - 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_us = <10000>;
+ };
+ step2 {
+ type = "pwm";
+ id = "backlight";
+ enable;
+ };
+ step3 {
+ type = "gpio";
+ number = <&gpio 28 0>;
+ enable;
+ };
+ };
+
+ power-off {
+ step0 {
+ type = "gpio";
+ number = <&gpio 28 0>;
+ disable;
+ };
+ step1 {
+ type = "pwm";
+ id = "backlight";
+ disable;
+ };
+ step2 {
+ type = "delay";
+ delay_us = <10000>;
+ };
+ step3 {
+ type = "regulator";
+ id = "power";
+ disable;
+ };
+ };
+ };
};
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index cf28276..6fb8aa3 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -246,6 +246,7 @@ config BACKLIGHT_CARILLO_RANCH
config BACKLIGHT_PWM
tristate "Generic PWM based Backlight Driver"
depends on PWM
+ select POWER_SEQ
help
If you have a LCD backlight adjustable by PWM, say Y to enable
this driver.
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 995f016..45d6edd 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -27,6 +27,12 @@ struct pwm_bl_data {
unsigned int period;
unsigned int lth_brightness;
unsigned int *levels;
+ bool enabled;
+ bool use_power_seqs;
+ struct power_seq *power_on_seq;
+ struct power_seq *power_off_seq;
+
+ /* Legacy callbacks */
int (*notify)(struct device *,
int brightness);
void (*notify_after)(struct device *,
@@ -35,6 +41,49 @@ struct pwm_bl_data {
void (*exit)(struct device *);
};
+static void pwm_backlight_on(struct backlight_device *bl)
+{
+ struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+ int ret;
+
+ if (pb->enabled)
+ return;
+
+ /* Legacy framework? */
+ if (!pb->use_power_seqs) {
+ pwm_config(pb->pwm, 0, pb->period);
+ pwm_disable(pb->pwm);
+ return;
+ }
+
+ ret = power_seq_run(pb->power_on_seq);
+ if (ret < 0)
+ dev_err(&bl->dev, "cannot run power on sequence\n");
+
+ pb->enabled = true;
+}
+
+static void pwm_backlight_off(struct backlight_device *bl)
+{
+ struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+ int ret;
+
+ if (!pb->enabled)
+ return;
+
+ /* Legacy framework? */
+ if (!pb->use_power_seqs) {
+ pwm_enable(pb->pwm);
+ return;
+ }
+
+ ret = power_seq_run(pb->power_off_seq);
+ if (ret < 0)
+ dev_err(&bl->dev, "cannot run power off sequence\n");
+
+ pb->enabled = false;
+}
+
static int pwm_backlight_update_status(struct backlight_device *bl)
{
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
@@ -51,8 +100,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
brightness = pb->notify(pb->dev, brightness);
if (brightness = 0) {
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
+ pwm_backlight_off(bl);
} else {
int duty_cycle;
@@ -66,7 +114,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
duty_cycle = pb->lth_brightness +
(duty_cycle * (pb->period - pb->lth_brightness) / max);
pwm_config(pb->pwm, duty_cycle, pb->period);
- pwm_enable(pb->pwm);
+ pwm_backlight_on(bl);
}
if (pb->notify_after)
@@ -145,11 +193,10 @@ static int pwm_backlight_parse_dt(struct device *dev,
data->max_brightness--;
}
- /*
- * TODO: Most users of this driver use a number of GPIOs to control
- * backlight power. Support for specifying these needs to be
- * added.
- */
+ /* parse power sequences and extract those we will use */
+ data->power_seqs = devm_of_parse_power_seq_set(dev);
+ if (IS_ERR(data->power_seqs))
+ return PTR_ERR(data->power_seqs);
return 0;
}
@@ -172,33 +219,96 @@ static int pwm_backlight_probe(struct platform_device *pdev)
{
struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
struct platform_pwm_backlight_data defdata;
+ struct power_seq_resource *res;
struct backlight_properties props;
struct backlight_device *bl;
struct pwm_bl_data *pb;
+ bool use_dt = false;
unsigned int max;
int ret;
+ pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
+ if (!pb) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ return -ENOMEM;
+ }
+
+ /* using new interface or 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) {
+ return ret;
+ } else if (ret < 0) {
dev_err(&pdev->dev, "failed to find platform data\n");
return ret;
}
-
data = &defdata;
+ use_dt = true;
+ }
+
+ /* using legacy interface? */
+ if (!data->power_seqs) {
+ 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");
+ return PTR_ERR(pb->pwm);
+ }
+ }
+
+ /*
+ * The DT case will set the pwm_period_ns field to 0 and store
+ * the period, parsed from the DT, in the PWM device. For the
+ * non-DT case, set the period from platform data.
+ */
+ if (data->pwm_period_ns > 0)
+ pwm_set_period(pb->pwm, data->pwm_period_ns);
+ } else {
+ /* build power sequences from platform data */
+ struct power_seq_set *seqs;
+
+ seqs = devm_power_seq_set_build(&pdev->dev, data->power_seqs);
+ if (IS_ERR(seqs))
+ return PTR_ERR(seqs);
+
+ if (use_dt)
+ devm_platform_power_seq_set_free(&pdev->dev,
+ data->power_seqs);
+
+ pb->power_on_seq = power_seq_lookup(seqs, "power-on");
+ pb->power_off_seq = power_seq_lookup(seqs, "power-off");
+
+ /* we must have exactly one PWM for this driver */
+ power_seq_for_each_resource(res, seqs) {
+ if (res->pdata->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;
+ }
+
+ pb->use_power_seqs = true;
}
if (data->init) {
ret = data->init(&pdev->dev);
if (ret < 0)
- return ret;
+ goto err;
}
- pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
- if (!pb) {
- dev_err(&pdev->dev, "no memory for state\n");
- ret = -ENOMEM;
- goto err_alloc;
+ /* from here we should have a PWM */
+ if (!pb->pwm) {
+ dev_err(&pdev->dev, "no PWM defined!\n");
+ return -EINVAL;
}
if (data->levels) {
@@ -213,28 +323,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);
- goto err_alloc;
- }
- }
-
- dev_dbg(&pdev->dev, "got pwm for backlight\n");
-
- /*
- * The DT case will set the pwm_period_ns field to 0 and store the
- * period, parsed from the DT, in the PWM device. For the non-DT case,
- * set the period from platform data.
- */
- if (data->pwm_period_ns > 0)
- pwm_set_period(pb->pwm, data->pwm_period_ns);
-
pb->period = pwm_get_period(pb->pwm);
pb->lth_brightness = data->lth_brightness * (pb->period / max);
@@ -246,18 +334,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);
- goto err_bl;
+ goto err;
}
bl->props.brightness = data->dft_brightness;
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
+
return 0;
-err_bl:
- pwm_put(pb->pwm);
-err_alloc:
+err:
if (data->exit)
data->exit(&pdev->dev);
return ret;
@@ -269,9 +356,8 @@ static int pwm_backlight_remove(struct platform_device *pdev)
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
backlight_device_unregister(bl);
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
- pwm_put(pb->pwm);
+ pwm_backlight_off(bl);
+
if (pb->exit)
pb->exit(&pdev->dev);
return 0;
@@ -285,8 +371,7 @@ static int pwm_backlight_suspend(struct device *dev)
if (pb->notify)
pb->notify(pb->dev, 0);
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
+ pwm_backlight_off(bl);
if (pb->notify_after)
pb->notify_after(pb->dev, 0);
return 0;
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 56f4a86..70d22f2 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -5,14 +5,25 @@
#define __LINUX_PWM_BACKLIGHT_H
#include <linux/backlight.h>
+#include <linux/power_seq.h>
struct platform_pwm_backlight_data {
- int pwm_id;
unsigned int max_brightness;
unsigned int dft_brightness;
unsigned int lth_brightness;
- unsigned int pwm_period_ns;
unsigned int *levels;
+ /*
+ * New interface using power sequences
+ */
+ struct platform_power_seq_set *power_seqs;
+ /*
+ * Legacy interface - use power sequences instead!
+ *
+ * pwm_id and pwm_period_ns need only be specified
+ * if get_pwm(dev, NULL) would return NULL.
+ */
+ int pwm_id;
+ unsigned int pwm_period_ns;
int (*init)(struct device *dev);
int (*notify)(struct device *dev, int brightness);
void (*notify_after)(struct device *dev, int brightness);
--
1.7.12
^ permalink raw reply related
* [PATCH v5 3/4] tegra: dt: add label to tegra20's PWM
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
Arnd Bergmann
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1346412846-17102-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
This is necessary to reference the PWM in board device trees.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
arch/arm/boot/dts/tegra20.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 405d167..67a6cd9 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -123,7 +123,7 @@
status = "disabled";
};
- pwm {
+ pwm: pwm {
compatible = "nvidia,tegra20-pwm";
reg = <0x7000a000 0x100>;
#pwm-cells = <2>;
--
1.7.12
^ permalink raw reply related
* [PATCH v5 4/4] tegra: ventana: add pwm backlight DT nodes
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
Arnd Bergmann
Cc: Leela Krishna Amudala, linux-tegra, linux-kernel, linux-fbdev,
devicetree-discuss, linux-pm, linux-doc, Alexandre Courbot
In-Reply-To: <1346412846-17102-1-git-send-email-acourbot@nvidia.com>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
arch/arm/boot/dts/tegra20-ventana.dts | 59 ++++++++++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index 4ec6b4c..025928d 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -467,6 +467,63 @@
bus-width = <8>;
};
+ backlight {
+ compatible = "pwm-backlight";
+ brightness-levels = <0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 255>;
+ default-brightness-level = <12>;
+
+ /* resources used by the power sequences */
+ pwms = <&pwm 2 5000000>;
+ pwm-names = "backlight";
+ power-supply = <&vdd_bl_reg>;
+
+ power-sequences {
+ power-on {
+ step0 {
+ type = "regulator";
+ id = "power";
+ enable;
+ };
+ step1 {
+ type = "delay";
+ delay_us = <10000>;
+ };
+ step2 {
+ type = "pwm";
+ id = "backlight";
+ enable;
+ };
+ step3 {
+ type = "gpio";
+ number = <&gpio 28 0>;
+ enable;
+ };
+ };
+
+ power-off {
+ step0 {
+ type = "gpio";
+ number = <&gpio 28 0>;
+ disable;
+ };
+ step1 {
+ type = "pwm";
+ id = "backlight";
+ disable;
+ };
+ step2 {
+ type = "delay";
+ delay_us = <10000>;
+ };
+ step3 {
+ type = "regulator";
+ id = "power";
+ disable;
+ };
+ };
+ };
+ };
+
regulators {
compatible = "simple-bus";
#address-cells = <1>;
@@ -510,7 +567,7 @@
enable-active-high;
};
- regulator@4 {
+ vdd_bl_reg: regulator@4 {
compatible = "regulator-fixed";
reg = <4>;
regulator-name = "vdd_bl";
--
1.7.12
^ permalink raw reply related
* [PATCH] video: s3c2410fb: Use pr_* and dev_* instead of printk
From: Sachin Kamat @ 2012-08-31 11:52 UTC (permalink / raw)
To: linux-fbdev
printk calls are replaced by pr_* and dev_* calls to silence
checkpatch warnings.
Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
---
drivers/video/s3c2410fb.c | 18 ++++++++++--------
1 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 77f34c6..a54e3f9 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -11,6 +11,8 @@
* Driver based on skeletonfb.c, sa1100fb.c and others.
*/
+#define pr_fmt(fmt) "s3c2410fb: " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
@@ -48,7 +50,7 @@ static int debug = 1;
static int debug;
#endif
-#define dprintk(msg...) if (debug) printk(KERN_DEBUG "s3c2410fb: " msg);
+#define dprintk(msg...) if (debug) pr_debug(msg);
/* useful functions */
@@ -598,11 +600,11 @@ static int s3c2410fb_debug_store(struct device *dev,
if (strnicmp(buf, "on", 2) = 0 ||
strnicmp(buf, "1", 1) = 0) {
debug = 1;
- printk(KERN_DEBUG "s3c2410fb: Debug On");
+ dev_dbg(dev, "s3c2410fb: Debug On");
} else if (strnicmp(buf, "off", 3) = 0 ||
strnicmp(buf, "0", 1) = 0) {
debug = 0;
- printk(KERN_DEBUG "s3c2410fb: Debug Off");
+ dev_dbg(dev, "s3c2410fb: Debug Off");
} else {
return -EINVAL;
}
@@ -921,7 +923,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
info->clk = clk_get(NULL, "lcd");
if (IS_ERR(info->clk)) {
- printk(KERN_ERR "failed to get lcd clock source\n");
+ dev_err(&pdev->dev, "failed to get lcd clock source\n");
ret = PTR_ERR(info->clk);
goto release_irq;
}
@@ -947,7 +949,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
/* Initialize video memory */
ret = s3c2410fb_map_video_memory(fbinfo);
if (ret) {
- printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
+ dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto release_clock;
}
@@ -970,7 +972,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
ret = register_framebuffer(fbinfo);
if (ret < 0) {
- printk(KERN_ERR "Failed to register framebuffer device: %d\n",
+ dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n",
ret);
goto free_cpufreq;
}
@@ -978,9 +980,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
/* create device files */
ret = device_create_file(&pdev->dev, &dev_attr_debug);
if (ret)
- printk(KERN_ERR "failed to add debug attribute\n");
+ dev_err(&pdev->dev, "failed to add debug attribute\n");
- printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ dev_info(&pdev->dev, "fb%d: %s frame buffer device\n",
fbinfo->node, fbinfo->fix.id);
return 0;
--
1.7.4.1
^ permalink raw reply related
* Re: [PATCH v2 02/23] OMAPDSS: outputs: Create and register output instances
From: Tomi Valkeinen @ 2012-08-31 11:57 UTC (permalink / raw)
To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346326845-16583-3-git-send-email-archit@ti.com>
[-- Attachment #1: Type: text/plain, Size: 2480 bytes --]
On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> Add output structs to output driver's private data. Register output instances by
> having an init function in the probes of the platform device drivers for
> different outputs. The *_init_output for each output registers the output and
> fill up the output's plaform device, type and id fields.
>
> In the probe of each interface driver, the output entities are initialized
> before the *_probe_pdata() functions intentionally. This is done to ensure that
> the output entity is prepared before the panels connected to the output are
> registered. We need the output entities to be ready because OMAPDSS will try
> to make connections between overlays, managers, outputs and devices during the
> panel's probe.
>
> Signed-off-by: Archit Taneja <archit@ti.com>
> ---
> drivers/video/omap2/dss/dpi.c | 15 +++++++++++++++
> drivers/video/omap2/dss/dsi.c | 18 ++++++++++++++++++
> drivers/video/omap2/dss/hdmi.c | 15 +++++++++++++++
> drivers/video/omap2/dss/rfbi.c | 17 +++++++++++++++++
> drivers/video/omap2/dss/sdi.c | 15 +++++++++++++++
> drivers/video/omap2/dss/venc.c | 15 +++++++++++++++
> 6 files changed, 95 insertions(+)
>
> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
> index 25fb895..9a7aee5 100644
> --- a/drivers/video/omap2/dss/dpi.c
> +++ b/drivers/video/omap2/dss/dpi.c
> @@ -45,6 +45,8 @@ static struct {
> struct omap_video_timings timings;
> struct dss_lcd_mgr_config mgr_config;
> int data_lines;
> +
> + struct omap_dss_output output;
> } dpi;
>
> static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
> @@ -410,10 +412,23 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
> }
> }
>
> +static void __init dpi_init_output(struct platform_device *pdev)
> +{
> + struct omap_dss_output *out = &dpi.output;
> +
> + dss_register_output(out);
> +
> + out->pdev = pdev;
> + out->id = OMAP_DSS_OUTPUT_DPI;
> + out->type = OMAP_DISPLAY_TYPE_DPI;
> +}
I think you should first initialize the output, and then register it.
Not the other way around.
I believe you need to implement unregister also. Normally unregister
won't be done, but the probe of an output driver can fail after the
output has been registered, and thus the output needs to be unregistered
at cleanup.
And it doesn't harm to unregister at the driver's remove.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2 03/23] OMAPDSS: output: Add set/unset device ops for omap_dss_output
From: Tomi Valkeinen @ 2012-08-31 12:03 UTC (permalink / raw)
To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346326845-16583-4-git-send-email-archit@ti.com>
[-- Attachment #1: Type: text/plain, Size: 3243 bytes --]
On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> An output entity represented by the struct omap_dss_output connects to a
> omap_dss_device entity. Add functions to set or unset an output's device. This
> is similar to how managers and devices were connected previously. An output can
> connect to a device without being connected to a manager. However, the output
> needs to eventually connect to a manager so that the connected panel can be
> enabled.
>
> Keep the omap_overlay_manager pointer in omap_dss_device for now to prevent
> breaking things. This will be removed later when outputs are supported
> completely.
>
> Signed-off-by: Archit Taneja <archit@ti.com>
> ---
> drivers/video/omap2/dss/output.c | 67 ++++++++++++++++++++++++++++++++++++++
> include/video/omapdss.h | 5 +++
> 2 files changed, 72 insertions(+)
>
> diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
> index 7d81be5..abc3aa2 100644
> --- a/drivers/video/omap2/dss/output.c
> +++ b/drivers/video/omap2/dss/output.c
> @@ -24,9 +24,76 @@
> #include "dss.h"
>
> static LIST_HEAD(output_list);
> +static DEFINE_MUTEX(output_lock);
> +
> +static int dss_output_set_device(struct omap_dss_output *out,
> + struct omap_dss_device *dssdev)
> +{
> + int r;
> +
> + mutex_lock(&output_lock);
> +
> + if (out->device) {
> + DSSERR("output already has device %s connected to it\n",
> + out->device->name);
> + r = -EINVAL;
> + goto err;
> + }
> +
> + if (out->type != dssdev->type) {
> + DSSERR("output type and display type don't match\n");
> + r = -EINVAL;
> + goto err;
> + }
> +
> + out->device = dssdev;
> + dssdev->output = out;
> +
> + mutex_unlock(&output_lock);
> +
> + return 0;
> +err:
> + mutex_unlock(&output_lock);
> +
> + return r;
> +}
> +
> +static int dss_output_unset_device(struct omap_dss_output *out)
> +{
> + int r;
> +
> + mutex_lock(&output_lock);
> +
> + if (!out->device) {
> + DSSERR("output doesn't have a device connected to it\n");
> + r = -EINVAL;
> + goto err;
> + }
> +
> + if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) {
> + DSSERR("device %s is not disabled, cannot unset device\n",
> + out->device->name);
> + r = -EINVAL;
> + goto err;
> + }
> +
> + out->device->output = NULL;
> + out->device = NULL;
> +
> + mutex_unlock(&output_lock);
> +
> + return 0;
> +err:
> + mutex_unlock(&output_lock);
> +
> + return r;
> +}
>
> void dss_register_output(struct omap_dss_output *out)
> {
> + out->set_device = &dss_output_set_device;
> + out->unset_device = &dss_output_unset_device;
> +
> list_add_tail(&out->list, &output_list);
> }
I don't think there's need for this indirection. We should use function
pointers only when the func pointer may lead to different functions.
Here we'll always have just one function, dss_output_set_device. We can
as well call the function directly.
I know we have similar func pointers for ovls/mgrs currently, but I
don't think they are good either. They are a relic from the time we
supported "virtual" overlays and managers, and thus could have different
implementations for the operations.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2 06/23] OMAP_VOUT: Remove manager->device references
From: Tomi Valkeinen @ 2012-08-31 12:11 UTC (permalink / raw)
To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev, Vaibhav Hiremath
In-Reply-To: <1346326845-16583-7-git-send-email-archit@ti.com>
[-- Attachment #1: Type: text/plain, Size: 700 bytes --]
On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> With the introduction of output entities, managers will now connect to outputs.
> Use the helper op for managers named get_device. This will abstract away the
> information on how to get the device from an overlay manager.
>
> Using the helper function will reduce the number of pointer dereferences a user
> of OMAPDSS needs to do and reduce risk of a NULL dereference.
Almost all the uses here seem to be getting the dssdev from an overlay.
Would it make sense to implement get_device for an ovl? That would
reduce all the ovl->manager ? ovl->manager->get_device(ovl->manager) :
NULL; code to ovl->get_device(ovl).
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2 02/23] OMAPDSS: outputs: Create and register output instances
From: Archit Taneja @ 2012-08-31 12:15 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: Archit Taneja, rob, linux-omap, linux-fbdev
In-Reply-To: <1346414265.18766.9.camel@lappyti>
On Friday 31 August 2012 05:27 PM, Tomi Valkeinen wrote:
> On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
>> Add output structs to output driver's private data. Register output instances by
>> having an init function in the probes of the platform device drivers for
>> different outputs. The *_init_output for each output registers the output and
>> fill up the output's plaform device, type and id fields.
>>
>> In the probe of each interface driver, the output entities are initialized
>> before the *_probe_pdata() functions intentionally. This is done to ensure that
>> the output entity is prepared before the panels connected to the output are
>> registered. We need the output entities to be ready because OMAPDSS will try
>> to make connections between overlays, managers, outputs and devices during the
>> panel's probe.
>>
>> Signed-off-by: Archit Taneja <archit@ti.com>
>> ---
>> drivers/video/omap2/dss/dpi.c | 15 +++++++++++++++
>> drivers/video/omap2/dss/dsi.c | 18 ++++++++++++++++++
>> drivers/video/omap2/dss/hdmi.c | 15 +++++++++++++++
>> drivers/video/omap2/dss/rfbi.c | 17 +++++++++++++++++
>> drivers/video/omap2/dss/sdi.c | 15 +++++++++++++++
>> drivers/video/omap2/dss/venc.c | 15 +++++++++++++++
>> 6 files changed, 95 insertions(+)
>>
>> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
>> index 25fb895..9a7aee5 100644
>> --- a/drivers/video/omap2/dss/dpi.c
>> +++ b/drivers/video/omap2/dss/dpi.c
>> @@ -45,6 +45,8 @@ static struct {
>> struct omap_video_timings timings;
>> struct dss_lcd_mgr_config mgr_config;
>> int data_lines;
>> +
>> + struct omap_dss_output output;
>> } dpi;
>>
>> static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
>> @@ -410,10 +412,23 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
>> }
>> }
>>
>> +static void __init dpi_init_output(struct platform_device *pdev)
>> +{
>> + struct omap_dss_output *out = &dpi.output;
>> +
>> + dss_register_output(out);
>> +
>> + out->pdev = pdev;
>> + out->id = OMAP_DSS_OUTPUT_DPI;
>> + out->type = OMAP_DISPLAY_TYPE_DPI;
>> +}
>
> I think you should first initialize the output, and then register it.
> Not the other way around.
Ok.
>
> I believe you need to implement unregister also. Normally unregister
> won't be done, but the probe of an output driver can fail after the
> output has been registered, and thus the output needs to be unregistered
> at cleanup.
Ah, right.
>
> And it doesn't harm to unregister at the driver's remove.
I'll fix these, thanks.
Archit
^ permalink raw reply
* Re: [PATCH v2 03/23] OMAPDSS: output: Add set/unset device ops for omap_dss_output
From: Tomi Valkeinen @ 2012-08-31 12:28 UTC (permalink / raw)
To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <5040ACE1.8080502@ti.com>
[-- Attachment #1: Type: text/plain, Size: 1008 bytes --]
On Fri, 2012-08-31 at 17:54 +0530, Archit Taneja wrote:
> On Friday 31 August 2012 05:33 PM, Tomi Valkeinen wrote:
> > I don't think there's need for this indirection. We should use function
> > pointers only when the func pointer may lead to different functions.
> > Here we'll always have just one function, dss_output_set_device. We can
> > as well call the function directly.
>
> Okay. I understand that. But in general, don't func pointers prevent us
> from exporting more symbols?
Yes. But I'm not sure if there's any real downside to exporting, as long
as the names are prefixed properly so that there are no name clashes.
> > I know we have similar func pointers for ovls/mgrs currently, but I
> > don't think they are good either. They are a relic from the time we
> > supported "virtual" overlays and managers, and thus could have different
> > implementations for the operations.
>
> Oh okay, I guess you mean the L4/sDMA updates for DSI command mode.
Yep.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2 03/23] OMAPDSS: output: Add set/unset device ops for omap_dss_output
From: Archit Taneja @ 2012-08-31 12:36 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346414621.18766.13.camel@lappyti>
On Friday 31 August 2012 05:33 PM, Tomi Valkeinen wrote:
> On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
>> An output entity represented by the struct omap_dss_output connects to a
>> omap_dss_device entity. Add functions to set or unset an output's device. This
>> is similar to how managers and devices were connected previously. An output can
>> connect to a device without being connected to a manager. However, the output
>> needs to eventually connect to a manager so that the connected panel can be
>> enabled.
>>
>> Keep the omap_overlay_manager pointer in omap_dss_device for now to prevent
>> breaking things. This will be removed later when outputs are supported
>> completely.
>>
>> Signed-off-by: Archit Taneja <archit@ti.com>
>> ---
>> drivers/video/omap2/dss/output.c | 67 ++++++++++++++++++++++++++++++++++++++
>> include/video/omapdss.h | 5 +++
>> 2 files changed, 72 insertions(+)
>>
>> diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
>> index 7d81be5..abc3aa2 100644
>> --- a/drivers/video/omap2/dss/output.c
>> +++ b/drivers/video/omap2/dss/output.c
>> @@ -24,9 +24,76 @@
>> #include "dss.h"
>>
>> static LIST_HEAD(output_list);
>> +static DEFINE_MUTEX(output_lock);
>> +
>> +static int dss_output_set_device(struct omap_dss_output *out,
>> + struct omap_dss_device *dssdev)
>> +{
>> + int r;
>> +
>> + mutex_lock(&output_lock);
>> +
>> + if (out->device) {
>> + DSSERR("output already has device %s connected to it\n",
>> + out->device->name);
>> + r = -EINVAL;
>> + goto err;
>> + }
>> +
>> + if (out->type != dssdev->type) {
>> + DSSERR("output type and display type don't match\n");
>> + r = -EINVAL;
>> + goto err;
>> + }
>> +
>> + out->device = dssdev;
>> + dssdev->output = out;
>> +
>> + mutex_unlock(&output_lock);
>> +
>> + return 0;
>> +err:
>> + mutex_unlock(&output_lock);
>> +
>> + return r;
>> +}
>> +
>> +static int dss_output_unset_device(struct omap_dss_output *out)
>> +{
>> + int r;
>> +
>> + mutex_lock(&output_lock);
>> +
>> + if (!out->device) {
>> + DSSERR("output doesn't have a device connected to it\n");
>> + r = -EINVAL;
>> + goto err;
>> + }
>> +
>> + if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) {
>> + DSSERR("device %s is not disabled, cannot unset device\n",
>> + out->device->name);
>> + r = -EINVAL;
>> + goto err;
>> + }
>> +
>> + out->device->output = NULL;
>> + out->device = NULL;
>> +
>> + mutex_unlock(&output_lock);
>> +
>> + return 0;
>> +err:
>> + mutex_unlock(&output_lock);
>> +
>> + return r;
>> +}
>>
>> void dss_register_output(struct omap_dss_output *out)
>> {
>> + out->set_device = &dss_output_set_device;
>> + out->unset_device = &dss_output_unset_device;
>> +
>> list_add_tail(&out->list, &output_list);
>> }
>
> I don't think there's need for this indirection. We should use function
> pointers only when the func pointer may lead to different functions.
> Here we'll always have just one function, dss_output_set_device. We can
> as well call the function directly.
Okay. I understand that. But in general, don't func pointers prevent us
from exporting more symbols?
>
> I know we have similar func pointers for ovls/mgrs currently, but I
> don't think they are good either. They are a relic from the time we
> supported "virtual" overlays and managers, and thus could have different
> implementations for the operations.
Oh okay, I guess you mean the L4/sDMA updates for DSI command mode.
Archit
^ permalink raw reply
* Re: [PATCH v2 06/23] OMAP_VOUT: Remove manager->device references
From: Archit Taneja @ 2012-08-31 12:46 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: rob, linux-omap, linux-fbdev, Vaibhav Hiremath
In-Reply-To: <1346415118.18766.15.camel@lappyti>
On Friday 31 August 2012 05:41 PM, Tomi Valkeinen wrote:
> On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
>> With the introduction of output entities, managers will now connect to outputs.
>> Use the helper op for managers named get_device. This will abstract away the
>> information on how to get the device from an overlay manager.
>>
>> Using the helper function will reduce the number of pointer dereferences a user
>> of OMAPDSS needs to do and reduce risk of a NULL dereference.
>
> Almost all the uses here seem to be getting the dssdev from an overlay.
> Would it make sense to implement get_device for an ovl? That would
> reduce all the ovl->manager ? ovl->manager->get_device(ovl->manager) :
> NULL; code to ovl->get_device(ovl).
That make sense.
We would still need mgr->get_device() though, as in some places, dss and
drm try to get the display from the manager.
Archit
^ permalink raw reply
* [PATCH] da8xx-fb: enable LCDC if FB is unblanked
From: Manjunathappa, Prakash @ 2012-08-31 13:12 UTC (permalink / raw)
To: linux-fbdev
Check for FB_BLANK_UNBLANK before enabling LCDC from PM resume
and DVFS. Without this, behavior in case of below used case is
not be not expected,
1) Issue FB_BLANK, LCDC disabled.
2) Do suspend/resume cycle or DVFS.
3) Do not expect LCDC to get enabled at this point.
Re-enabling of LCDC is done when FB_BLANK_UNBLANK is issued.
Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
---
Applies on top of fbdev-next of Florian Tobias Schandinat's tree.
drivers/video/da8xx-fb.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 761c8d1..1273354 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -962,7 +962,8 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
par->lcd_fck_rate = clk_get_rate(par->lcdc_clk);
lcd_disable_raster();
lcd_calc_clk_divider(par);
- lcd_enable_raster();
+ if (par->blank = FB_BLANK_UNBLANK)
+ lcd_enable_raster();
}
}
@@ -1486,10 +1487,12 @@ static int fb_resume(struct platform_device *dev)
console_lock();
clk_enable(par->lcdc_clk);
- lcd_enable_raster();
+ if (par->blank = FB_BLANK_UNBLANK) {
+ lcd_enable_raster();
- if (par->panel_power_ctrl)
- par->panel_power_ctrl(1);
+ if (par->panel_power_ctrl)
+ par->panel_power_ctrl(1);
+ }
fb_set_suspend(info, 0);
console_unlock();
--
1.7.1
^ permalink raw reply related
* [PATCH] video: mbxfb: Include linux/io.h instead of asm/io.h
From: Axel Lin @ 2012-08-31 13:39 UTC (permalink / raw)
To: Florian Tobias Schandinat
Cc: Arnd Bergmann, Mathieu Poirier, Damien Cassou, linux-fbdev,
linux-kernel
This fixes below build error:
CC [M] drivers/video/mbx/mbxfb.o
drivers/video/mbx/mbxfb.c: In function 'mbxfb_probe':
drivers/video/mbx/mbxfb.c:942:2: error: implicit declaration of function 'devm_ioremap_nocache' [-Werror=implicit-function-declaration]
drivers/video/mbx/mbxfb.c:942:22: warning: assignment makes pointer from integer without a cast [enabled by default]
drivers/video/mbx/mbxfb.c:952:21: warning: assignment makes pointer from integer without a cast [enabled by default]
cc1: some warnings being treated as errors
Signed-off-by: Axel Lin <axel.lin@gmail.com>
---
drivers/video/mbx/mbxfb.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
index 9229acf..6563e50 100644
--- a/drivers/video/mbx/mbxfb.c
+++ b/drivers/video/mbx/mbxfb.c
@@ -26,8 +26,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#include <video/mbxfb.h>
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v2 10/23] OMAPDSS: DPI: Pass omap_dss_output within the driver
From: Tomi Valkeinen @ 2012-08-31 13:48 UTC (permalink / raw)
To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346326845-16583-11-git-send-email-archit@ti.com>
[-- Attachment #1: Type: text/plain, Size: 2111 bytes --]
On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> When a panel driver calls a DPI function, it passes the omap_dss_device
> pointer, this pointer currently propagates within the DPI driver to configure
> the interface.
>
> Extract the omap_dss_output pointer from omap_dss_device received from the panel
> driver, pass the output pointer to DPI functions local to the driver to
> configure the interface, these functions no longer need omap_dss_device since
> the driver now maintains a copy of output parameters.
>
> Replace dssdev->manager references with out->manager references as only these
> will be valid later.
>
> With the addition of outputs. There is a possibility that an omap_dss_device
> isn't connected to an output, or a manager isn't connected to an output yet.
> Ensure that the DPI interface functions proceed only if the output is non NULL.
I agree with the direction of this and the similar patches for other
outputs, but I think we should leave these out for now, at least most of
the code here.
So ultimately we'll have the output drivers taking the omap_dss_output
as an argument, and we don't need dssdev anymore. But we can't do that
yet, and now that you mix both approaches I think the end result makes
the code a bit more confusing, and it would be changed again later when
dssdev can be removed.
What I mean is that, for example, display_enable takes dssdev as an
argument. Then you extract output from that, and pass output to some
other functions. Then these functions again extract dssdev from the
output.
This feels like extra churn that doesn't really help anything, and will
be changed later when the functions get output as an argument. So I
propose to keep passing dssdev around until we've removed the
dependencies to dssdev, and we (probably) get the output directly as an
argument to the functions. Then we can clean them up properly at one go.
The dssdev->manager parts still need to be changed to out->manager, of
course, but I think those are minority of the changes here and the
following patches.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2 10/23] OMAPDSS: DPI: Pass omap_dss_output within the driver
From: Archit Taneja @ 2012-08-31 13:59 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346420930.7508.9.camel@lappyti>
On Friday 31 August 2012 07:18 PM, Tomi Valkeinen wrote:
> On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
>> When a panel driver calls a DPI function, it passes the omap_dss_device
>> pointer, this pointer currently propagates within the DPI driver to configure
>> the interface.
>>
>> Extract the omap_dss_output pointer from omap_dss_device received from the panel
>> driver, pass the output pointer to DPI functions local to the driver to
>> configure the interface, these functions no longer need omap_dss_device since
>> the driver now maintains a copy of output parameters.
>>
>> Replace dssdev->manager references with out->manager references as only these
>> will be valid later.
>>
>> With the addition of outputs. There is a possibility that an omap_dss_device
>> isn't connected to an output, or a manager isn't connected to an output yet.
>> Ensure that the DPI interface functions proceed only if the output is non NULL.
>
> I agree with the direction of this and the similar patches for other
> outputs, but I think we should leave these out for now, at least most of
> the code here.
>
> So ultimately we'll have the output drivers taking the omap_dss_output
> as an argument, and we don't need dssdev anymore. But we can't do that
> yet, and now that you mix both approaches I think the end result makes
> the code a bit more confusing, and it would be changed again later when
> dssdev can be removed.
>
> What I mean is that, for example, display_enable takes dssdev as an
> argument. Then you extract output from that, and pass output to some
> other functions. Then these functions again extract dssdev from the
> output.
>
> This feels like extra churn that doesn't really help anything, and will
> be changed later when the functions get output as an argument. So I
> propose to keep passing dssdev around until we've removed the
> dependencies to dssdev, and we (probably) get the output directly as an
> argument to the functions. Then we can clean them up properly at one go.
>
> The dssdev->manager parts still need to be changed to out->manager, of
> course, but I think those are minority of the changes here and the
> following patches.
Ok. Yes, I guess if we start from here, we would need to do unnecessary
changes once we completely switch to outputs.
I'll change these output patches such that, only the dssdev->manager
references are fixed to dssdev->output->manager.
Archit
^ permalink raw reply
* Re: [PATCH v2 09/23] OMAPDSS: Create links between managers, outputs and devices
From: Tomi Valkeinen @ 2012-08-31 14:10 UTC (permalink / raw)
To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346326845-16583-10-git-send-email-archit@ti.com>
[-- Attachment #1: Type: text/plain, Size: 1924 bytes --]
On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> Links between DSS entities are made in dss_recheck_connections when a new panel
> is probed. Rewrite the code in dss_recheck_connections to link managers to
> outputs, and outputs to devices.
>
> The fields in omap_dss_device struct gives information on which output and
> manager to connect to. The desired manager and output pointers are retrieved and
> prepared(existing outputs/devices unset, if default display)) to form the
> desired links. The output is linked to the device, and then the manager to the
> output. If a probed device's required manager isn't free, the required output
> is still connected to the device so that it's easier to use the panel in the
> future.
I've been pondering this one, and I can't come to a conclusion. The
recheck_connections is just so ugly that I'd like to get rid of it =). I
guess this patch doesn't make it any more ugly, so we can include it in
the patch series.
And as I mentioned earlier, I think we should get rid of the
OMAP_DISPLAY_TYPE_* enum, as it's kinda extra now. But doing that would
require changing all board files. That's not out of the question, but I
think we should first make sure we know what we are doing with the board
files so we don't go back and forth there.
Just gathering my thoughts:
When we define a panel in DT/board file, we should also define the
output instance, because that's part of the hardware design. But there
are no hardcoded links between mgrs and outputs, so that doesn't belong
to the DT/board file. For example, omap4460's DSI1 can take input from
LCD1 or LCD2.
So who could/should make the decision which mgr to use... Well, I don't
know on what basis the decision can be made, but I still think omapdss
can't make good decisions on that, so probably the whole "chain" should
be configured in the omapfb/omapdrm level.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* RE: [PATCH] da8xx-fb: enable LCDC if FB is unblanked
From: Manjunathappa, Prakash @ 2012-08-31 14:15 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1346418020-31779-1-git-send-email-prakash.pm@ti.com>
Hi,
On Fri, Aug 31, 2012 at 18:30:20, Manjunathappa, Prakash wrote:
> Check for FB_BLANK_UNBLANK before enabling LCDC from PM resume
> and DVFS. Without this, behavior in case of below used case is
> not be not expected,
> 1) Issue FB_BLANK, LCDC disabled.
> 2) Do suspend/resume cycle or DVFS.
> 3) Do not expect LCDC to get enabled at this point.
>
> Re-enabling of LCDC is done when FB_BLANK_UNBLANK is issued.
I will reword this and send across next version.
>
> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
> ---
> Applies on top of fbdev-next of Florian Tobias Schandinat's tree.
>
> drivers/video/da8xx-fb.c | 11 +++++++----
> 1 files changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> index 761c8d1..1273354 100644
> --- a/drivers/video/da8xx-fb.c
> +++ b/drivers/video/da8xx-fb.c
> @@ -962,7 +962,8 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
> par->lcd_fck_rate = clk_get_rate(par->lcdc_clk);
> lcd_disable_raster();
> lcd_calc_clk_divider(par);
> - lcd_enable_raster();
> + if (par->blank = FB_BLANK_UNBLANK)
> + lcd_enable_raster();
> }
> }
>
> @@ -1486,10 +1487,12 @@ static int fb_resume(struct platform_device *dev)
>
> console_lock();
> clk_enable(par->lcdc_clk);
> - lcd_enable_raster();
> + if (par->blank = FB_BLANK_UNBLANK) {
> + lcd_enable_raster();
>
> - if (par->panel_power_ctrl)
> - par->panel_power_ctrl(1);
> + if (par->panel_power_ctrl)
> + par->panel_power_ctrl(1);
> + }
>
> fb_set_suspend(info, 0);
> console_unlock();
> --
> 1.7.1
>
>
^ permalink raw reply
* Re: [PATCH v2 15/23] OMAPDSS: RFBI: Add dssdev pointers as arguments to all exported functions
From: Tomi Valkeinen @ 2012-08-31 14:20 UTC (permalink / raw)
To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346326845-16583-16-git-send-email-archit@ti.com>
[-- Attachment #1: Type: text/plain, Size: 1474 bytes --]
On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> All functions of an interface driver used by a panel driver should have an
> omap_dss_device pointer as an argument. This may not be needed by some of the
> interfaces now as driver data is globally visible in them. The correct way
> to retrieve driver data is to extract the platform device from the output,
> and then extract the driver data from the platform device.
>
> Add dssdev arguments from functions used by panel drivers which currently miss
> it. This will come to use when the RFBI functions retrieve the driver data
> in the correct manner.
This and the similar patch for HDMI could probably also be left out for
now. Again I agree that this is correct direction, but this is not
really needed (right?) for output work or writeback. And we'll
eventually just change these parameters again.
The motivation for this patch was probably to have common format for the
output driver's functions, so that you can use func pointers in an ops
struct?
Let's delay that work until the common panel framework gets a bit more
solid.
Sorry if I'm saying "leave this patch out" for most of the patches =). I
just want to avoid extra churn, going back and forth with the code. The
most important things now are to get the output work in a state that WB
can be used, and on the other hand to remove the dssdev dependencies so
that at some point we can remove dssdev totally.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2 20/23] OMAPDSS: MANAGER: Update display sysfs store
From: Tomi Valkeinen @ 2012-08-31 14:30 UTC (permalink / raw)
To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346326845-16583-21-git-send-email-archit@ti.com>
[-- Attachment #1: Type: text/plain, Size: 3102 bytes --]
On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> The display sysfs attribute's store function needs to be changed with the
> introduction of outputs.
>
> Providing a manager to the display isn't enough to create a link now, the
> manager needs and output to connect to. A manager's display store file only
> has the information of the manager and the desired display, it is not aware
> of which output should the manager connect to.
>
> Because of this, a new constraint needs to be set up when setting a display via
> this sysfs file. The constraint is that the desired display should already be
> connected to an output before calling this sysfs function.
>
> This might break some existing user space stuff which uses sysfs directly. But
> in most cases dss_recheck_connections will connect displays to floating outputs.
> DSS sysfs files are being planned to be remove anyway, so it's not much of a
> harm.
>
> Signed-off-by: Archit Taneja <archit@ti.com>
> ---
> drivers/video/omap2/dss/manager.c | 25 ++++++++++++++++++++-----
> 1 file changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
> index fd39f66..d808ce2 100644
> --- a/drivers/video/omap2/dss/manager.c
> +++ b/drivers/video/omap2/dss/manager.c
> @@ -74,18 +74,33 @@ static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
> if (dssdev)
> DSSDBG("display %s found\n", dssdev->name);
>
> - if (mgr->get_device(mgr)) {
> - r = mgr->unset_device(mgr);
> + if (mgr->output) {
> + if (mgr->output->device) {
> + r = mgr->output->unset_device(mgr->output);
> + if (r) {
> + goto put_device;
> + DSSERR("failed to unset device from output\n");
> + }
> + }
> +
> + r = mgr->unset_output(mgr);
> if (r) {
> - DSSERR("failed to unset display\n");
> + DSSERR("failed to unset current output\n");
> goto put_device;
> }
> }
>
> if (dssdev) {
> - r = mgr->set_device(mgr, dssdev);
> + struct omap_dss_output *out = dssdev->output;
> +
> + if (!out) {
> + DSSERR("no output connected to device\n");
> + goto put_device;
> + }
> +
> + r = mgr->set_output(mgr, out);
> if (r) {
> - DSSERR("failed to set manager\n");
> + DSSERR("failed to set manager output\n");
> goto put_device;
> }
>
Hmm, I think this is a bit broken. If I read this right, the unlinking
removes both mgr-output link and the output-dssdev link. But the linking
part only sets up the mgr-output link.
So if there's a very simple configuration with one display, if you
unlink it via sysfs you can't link it back again.
The store function gets the mgr and the dssdev as arguments. I think
this could be changed so that the function would "guess" the needed
output. Well, not so much a guess, because a dssdev can only be
connected to one output, defined by the HW design. That is basically
what the recheck_connections does, we could use the same method here.
Then this sysfs file should work just like before.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH v2] da8xx-fb: enable LCDC if FB is unblanked
From: Manjunathappa, Prakash @ 2012-08-31 14:30 UTC (permalink / raw)
To: linux-fbdev
It is expected that LCDC to continue to be disabled after
resume if it is blanked before suspend. This is also true
for DVFS. But it is observed that LCDC being enabled after
suspend/resume cycle or DVFS.
Correcting it by having check for FB_BLANK_UNBLANK before
enabling.
Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
---
Applies on top of fbdev-next of Florian Tobias Schandinat's tree.
Since v1:
Re-written commit message.
drivers/video/da8xx-fb.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 761c8d1..1273354 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -962,7 +962,8 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
par->lcd_fck_rate = clk_get_rate(par->lcdc_clk);
lcd_disable_raster();
lcd_calc_clk_divider(par);
- lcd_enable_raster();
+ if (par->blank = FB_BLANK_UNBLANK)
+ lcd_enable_raster();
}
}
@@ -1486,10 +1487,12 @@ static int fb_resume(struct platform_device *dev)
console_lock();
clk_enable(par->lcdc_clk);
- lcd_enable_raster();
+ if (par->blank = FB_BLANK_UNBLANK) {
+ lcd_enable_raster();
- if (par->panel_power_ctrl)
- par->panel_power_ctrl(1);
+ if (par->panel_power_ctrl)
+ par->panel_power_ctrl(1);
+ }
fb_set_suspend(info, 0);
console_unlock();
--
1.7.1
^ permalink raw reply related
* Re: [PATCH v2 09/23] OMAPDSS: Create links between managers, outputs and devices
From: Archit Taneja @ 2012-08-31 14:36 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346422242.7508.18.camel@lappyti>
On Friday 31 August 2012 07:40 PM, Tomi Valkeinen wrote:
> On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
>> Links between DSS entities are made in dss_recheck_connections when a new panel
>> is probed. Rewrite the code in dss_recheck_connections to link managers to
>> outputs, and outputs to devices.
>>
>> The fields in omap_dss_device struct gives information on which output and
>> manager to connect to. The desired manager and output pointers are retrieved and
>> prepared(existing outputs/devices unset, if default display)) to form the
>> desired links. The output is linked to the device, and then the manager to the
>> output. If a probed device's required manager isn't free, the required output
>> is still connected to the device so that it's easier to use the panel in the
>> future.
>
> I've been pondering this one, and I can't come to a conclusion. The
> recheck_connections is just so ugly that I'd like to get rid of it =). I
> guess this patch doesn't make it any more ugly, so we can include it in
> the patch series.
>
> And as I mentioned earlier, I think we should get rid of the
> OMAP_DISPLAY_TYPE_* enum, as it's kinda extra now. But doing that would
> require changing all board files. That's not out of the question, but I
> think we should first make sure we know what we are doing with the board
> files so we don't go back and forth there.
Yes, I didn't remove it for the same reason.
>
> Just gathering my thoughts:
>
> When we define a panel in DT/board file, we should also define the
> output instance, because that's part of the hardware design. But there
It's a part of hardware design if the panel can't be detached. But yes,
even for detachable panels, we can assume that the panel would
eventually connect to that output.
> are no hardcoded links between mgrs and outputs, so that doesn't belong
> to the DT/board file. For example, omap4460's DSI1 can take input from
> LCD1 or LCD2.
Right, so we don't need an equivalent of the dssdev->channel field in DT
info. As you said, we need the output instance, is that why you were
sceptical about it being defined as an enum in previous patches?
Probably we could define output instances in DT as a pair of instance
number and instance type {number, type}. It would be sort of hard to
play around with those within OMAPDSS though.
>
> So who could/should make the decision which mgr to use... Well, I don't
> know on what basis the decision can be made, but I still think omapdss
> can't make good decisions on that, so probably the whole "chain" should
> be configured in the omapfb/omapdrm level.
Which manager to chose could be simply picking up the next free manager
which can connect to that output. omapfb/drm can take care of that.
Archit
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox