diff mbox

[PATCHv5,2/3] pwm: make the PWM_POLARITY flag in DTB optional

Message ID 20141009151605.GA8818@ulmo.nvidia.com
State Superseded
Headers show

Commit Message

Thierry Reding Oct. 9, 2014, 3:16 p.m. UTC
On Tue, Oct 07, 2014 at 03:55:33PM +0200, Lothar Waßmann wrote:
> Change the pwm chip driver registration, so that a chip driver that
> supports polarity inversion can still be used with DTBs that don't
> provide the 'PWM_POLARITY' flag.
> 
> This is done to provide polarity inversion support for the pwm-imx
> driver without having to modify all existing DTS files.

I don't like how this throws out the window the only sanity checking we
have in place for the #pwm-cells property.

As I understand it, the problem that you're trying to solve is one of
backwards-compatibility where existing device trees have #pwm-cells =
<2>, but the driver is extended to support flags as well.

In that case, can we not simply make of_pwm_xlate_with_flags() support
that case transparently? That is, if the driver sets .of_pwm_n_cells to
3, we can still support #pwm-cells = <2> and use the default (no) flags
instead.

Something like the below should do that (compile-tested only).

Thierry

Comments

Lothar Waßmann Oct. 10, 2014, 2:22 p.m. UTC | #1
This patch series adds support for polarity inversion to the pwm-imx
driver. The patches have been tested on i.MX6, i.MX53 and with the
ti-ehrpwm.c driver.

Changes wrt. v2:
- make the use of '#pwm-cells = <3>' optional, so that the change does
  not break existing DT blobs as suggested by Arnd Bergmann and Sascha
  Hauer.

Changes wrt. v3:
- implemented the approach suggested by Sascha Hauer 
- don't modify struct pwm_ops in the imx_pwm probe function

Changes wrt. v4:
- rebased onto current linux-next
- dropped cleanup patch which is not necessary any more
- resent with ACK from Shawn Guo and Reviewed-By tag from Sascha Hauer

Changes wrt. v5:
- don't remove of_pwm_n_cells to keep sanity checks for #pwm-cells as
  suggested by Thierry Reding

--
To unsubscribe from this list: send the line "unsubscribe linux-pwm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stefan Agner Sept. 8, 2016, 10:15 p.m. UTC | #2
Hi Lothar,

On 2014-10-10 07:22, Lothar Waßmann wrote:
> This patch series adds support for polarity inversion to the pwm-imx
> driver. The patches have been tested on i.MX6, i.MX53 and with the
> ti-ehrpwm.c driver.

Do you know what prevented this patchset from getting merged?

We are looking for Polarity support in PWM for too, this is especially
useful for backlight control.

--
Stefan

> 
> Changes wrt. v2:
> - make the use of '#pwm-cells = <3>' optional, so that the change does
>   not break existing DT blobs as suggested by Arnd Bergmann and Sascha
>   Hauer.
> 
> Changes wrt. v3:
> - implemented the approach suggested by Sascha Hauer 
> - don't modify struct pwm_ops in the imx_pwm probe function
> 
> Changes wrt. v4:
> - rebased onto current linux-next
> - dropped cleanup patch which is not necessary any more
> - resent with ACK from Shawn Guo and Reviewed-By tag from Sascha Hauer
> 
> Changes wrt. v5:
> - don't remove of_pwm_n_cells to keep sanity checks for #pwm-cells as
>   suggested by Thierry Reding
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
To unsubscribe from this list: send the line "unsubscribe linux-pwm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lothar Waßmann Sept. 9, 2016, 7:18 a.m. UTC | #3
Hi,

On Thu, 08 Sep 2016 15:15:57 -0700 Stefan Agner wrote:
> On 2014-10-10 07:22, Lothar Waßmann wrote:
> > This patch series adds support for polarity inversion to the pwm-imx
> > driver. The patches have been tested on i.MX6, i.MX53 and with the
> > ti-ehrpwm.c driver.
> 
> Do you know what prevented this patchset from getting merged?
> 
No idea.

> We are looking for Polarity support in PWM for too, this is especially
> useful for backlight control.
> 
Actually the PWM driver may be the wrong place to achieve this. When
the backlight driver sets the brightness to 0 to switch the backlight
off, it will disable the PWM. This will make the PWM pin go LOW and
thus turn the backlight to full brightness rather than off (unless there
is an additional GPIO that controls a backlight enable pin on the LCD).


Lothar Waßmann
--
To unsubscribe from this list: send the line "unsubscribe linux-pwm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alexandre Belloni Sept. 12, 2016, 12:45 p.m. UTC | #4
On 09/09/2016 at 09:18:57 +0200, Lothar Waßmann wrote :
> Hi,
> 
> On Thu, 08 Sep 2016 15:15:57 -0700 Stefan Agner wrote:
> > On 2014-10-10 07:22, Lothar Waßmann wrote:
> > > This patch series adds support for polarity inversion to the pwm-imx
> > > driver. The patches have been tested on i.MX6, i.MX53 and with the
> > > ti-ehrpwm.c driver.
> > 
> > Do you know what prevented this patchset from getting merged?
> > 
> No idea.
> 
> > We are looking for Polarity support in PWM for too, this is especially
> > useful for backlight control.
> > 
> Actually the PWM driver may be the wrong place to achieve this. When
> the backlight driver sets the brightness to 0 to switch the backlight
> off, it will disable the PWM. This will make the PWM pin go LOW and
> thus turn the backlight to full brightness rather than off (unless there
> is an additional GPIO that controls a backlight enable pin on the LCD).
> 

Isn't a properly designed PWM putting a high level on its pin when
disabled and configured with inversed polarity ?
If the HW is capable of it, the driver should be fixed.
Vladimir Zapolskiy Sept. 12, 2016, 1:54 p.m. UTC | #5
Hi Lothar,

On 09/09/2016 10:18 AM, Lothar Waßmann wrote:
> Hi,
>
> On Thu, 08 Sep 2016 15:15:57 -0700 Stefan Agner wrote:
>> On 2014-10-10 07:22, Lothar Waßmann wrote:
>>> This patch series adds support for polarity inversion to the pwm-imx
>>> driver. The patches have been tested on i.MX6, i.MX53 and with the
>>> ti-ehrpwm.c driver.
>>
>> Do you know what prevented this patchset from getting merged?
>>
> No idea.
>
>> We are looking for Polarity support in PWM for too, this is especially
>> useful for backlight control.
>>
> Actually the PWM driver may be the wrong place to achieve this. When
> the backlight driver sets the brightness to 0 to switch the backlight
> off, it will disable the PWM. This will make the PWM pin go LOW and
> thus turn the backlight to full brightness rather than off (unless there
> is an additional GPIO that controls a backlight enable pin on the LCD).
>

I've just realized that I had submitted practically the same change
(excluding iMX specifics) and about the same time in October 2014, but
my v1 is one and a half hours later than yours preceding v6 :)

Since I've subscribed to the linux-pwm right before sending my changes,
I don't have your changes in my mailbox. Would you mind to review my
v3 "pwm: support backward compatibility of DTB extending PWM args":

   http://lists.infradead.org/pipermail/linux-arm-kernel/2014-November/303833.html

then incorporate anything you find useful into your series and resend
v7? Or just resend the rebased v6 if nothing is found attracting?

In my turn I'll spend time to review the series and test it on iMX.

--
With best wishes,
Vladimir
--
To unsubscribe from this list: send the line "unsubscribe linux-pwm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uwe Kleine-König Sept. 12, 2016, 2:04 p.m. UTC | #6
Hello,

On Mon, Sep 12, 2016 at 02:45:53PM +0200, Alexandre Belloni wrote:
> Isn't a properly designed PWM putting a high level on its pin when
> disabled and configured with inversed polarity ?

it's not well defined. When trying several times over the years to
properly define and document it, I didn't manage to agree with Thierry
what is the right thing to define.

IMHO it would be sensible to make it explicitly undefined what happens
when a PMW is disabled. This would simplify drivers from

	pwm_config(mypwm, value, period);
	if (!value)
		pwm_disable(mypwm)
	else
		pwm_enable(led_dat->pwm);

to

	pwm_config(mypwm, value, period);

and let the pwm driver disable it's clock (or whatever) when value is 0
and there are energy saving benefits that don't hurt the expected
behaviour of the pin. So the hardware specific stuff is handled in the
hardware specific driver and usage in pwm-consumers is simplified.
Moreover this also simplifies some pwm drivers because they don't have
to catch in software the cases where the hardware differs from the
expectation[1].
Looking at drivers/leds/leds-pwm.c it doesn't ensure that each
pwm_enable is paired by an pwm_disable (e.g. on .remove). Is this a bug?
With my purposed semantics of .config and .disable this would be much
easier to fix.

Regarding your question: Yeah, maybe all properly designed PWMs behave
like you expect. But reality isn't only about properly designed
hardware, so I wouldn't expect all hardware to behave. The inverse
property might be software emulated and so on pwm_disable the pin might
become 0.

The obvious downside of my suggestion is that this is a change in what
most people expect (because it was "safe" to call pwm_enable before),
but the resulting code is simpler and cleaner.

Today it's a (maybe small) bug, when a pwm consumer calls pwm_config with
value=0 and doesn't disable it afterwards. IMHO that's a bug in the pwm
API that pwm_config with value=0 doesn't imply (the wanted effects of)
pwm_disable.

Best regards
Uwe

[1] This might even be impossible: Consider a PWM that gets 0 (or
high-z) on hw-disable independent of configured duty or inversion. The
driver now sees for an inverted pwm: pwm_config(this, 0, 100);
pwm_disable(this); The driver cannot know if it should continue to drive
the pin at 1, or if the pwm consumer stopped caring about the pwm and
disabling the hardware is OK.
Stefan Agner Sept. 12, 2016, 4:51 p.m. UTC | #7
Hi,

Thanks for that insight Uwe!

On 2016-09-12 07:04, Uwe Kleine-König wrote:
> Hello,
> 
> On Mon, Sep 12, 2016 at 02:45:53PM +0200, Alexandre Belloni wrote:
>> Isn't a properly designed PWM putting a high level on its pin when
>> disabled and configured with inversed polarity ?
> 
> it's not well defined. When trying several times over the years to
> properly define and document it, I didn't manage to agree with Thierry
> what is the right thing to define.
> 
> IMHO it would be sensible to make it explicitly undefined what happens
> when a PMW is disabled. This would simplify drivers from
> 
> 	pwm_config(mypwm, value, period);
> 	if (!value)
> 		pwm_disable(mypwm)
> 	else
> 		pwm_enable(led_dat->pwm);
> 
> to
> 
> 	pwm_config(mypwm, value, period);
> 
> and let the pwm driver disable it's clock (or whatever) when value is 0
> and there are energy saving benefits that don't hurt the expected
> behaviour of the pin. So the hardware specific stuff is handled in the
> hardware specific driver and usage in pwm-consumers is simplified.
> Moreover this also simplifies some pwm drivers because they don't have
> to catch in software the cases where the hardware differs from the
> expectation[1].

That sounds like a sane definition to me and what I would have expected
from the PWM framework. That the pin is not defined after pwm_disable is
totally understandable. It is usually a case which the board designer
anyway needs to take care of (e.g. what is the state right after power
on? If the designer cares about, he will put a pull-up/down in place).

And it seems also Sascha suggested that:
https://lkml.org/lkml/2013/1/4/139

I did not found where Thierry disagreed to that...?

> Looking at drivers/leds/leds-pwm.c it doesn't ensure that each
> pwm_enable is paired by an pwm_disable (e.g. on .remove). Is this a bug?
> With my purposed semantics of .config and .disable this would be much
> easier to fix.

That looks like a bug to me.

> 
> Regarding your question: Yeah, maybe all properly designed PWMs behave
> like you expect. But reality isn't only about properly designed
> hardware, so I wouldn't expect all hardware to behave. The inverse
> property might be software emulated and so on pwm_disable the pin might
> become 0.
> 
> The obvious downside of my suggestion is that this is a change in what
> most people expect (because it was "safe" to call pwm_enable before),
> but the resulting code is simpler and cleaner.
> 
> Today it's a (maybe small) bug, when a pwm consumer calls pwm_config with
> value=0 and doesn't disable it afterwards. IMHO that's a bug in the pwm
> API that pwm_config with value=0 doesn't imply (the wanted effects of)
> pwm_disable.

I don't quite get what you are saying here. What wanted effects of
pwm_disable would you like to move into pwm_config with value=0?

--
Stefan

> 
> Best regards
> Uwe
> 
> [1] This might even be impossible: Consider a PWM that gets 0 (or
> high-z) on hw-disable independent of configured duty or inversion. The
> driver now sees for an inverted pwm: pwm_config(this, 0, 100);
> pwm_disable(this); The driver cannot know if it should continue to drive
> the pin at 1, or if the pwm consumer stopped caring about the pwm and
> disabling the hardware is OK.
--
To unsubscribe from this list: send the line "unsubscribe linux-pwm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uwe Kleine-König Sept. 12, 2016, 8 p.m. UTC | #8
Hello Stefan,

On Mon, Sep 12, 2016 at 09:51:26AM -0700, Stefan Agner wrote:
> On 2016-09-12 07:04, Uwe Kleine-König wrote:
> > Hello,
> > 
> > On Mon, Sep 12, 2016 at 02:45:53PM +0200, Alexandre Belloni wrote:
> >> Isn't a properly designed PWM putting a high level on its pin when
> >> disabled and configured with inversed polarity ?
> > 
> > it's not well defined. When trying several times over the years to
> > properly define and document it, I didn't manage to agree with Thierry
> > what is the right thing to define.
> > 
> > IMHO it would be sensible to make it explicitly undefined what happens
> > when a PMW is disabled. This would simplify drivers from
> > 
> > 	pwm_config(mypwm, value, period);
> > 	if (!value)
> > 		pwm_disable(mypwm)
> > 	else
> > 		pwm_enable(led_dat->pwm);
> > 
> > to
> > 
> > 	pwm_config(mypwm, value, period);
> > 
> > and let the pwm driver disable it's clock (or whatever) when value is 0
> > and there are energy saving benefits that don't hurt the expected
> > behaviour of the pin. So the hardware specific stuff is handled in the
> > hardware specific driver and usage in pwm-consumers is simplified.
> > Moreover this also simplifies some pwm drivers because they don't have
> > to catch in software the cases where the hardware differs from the
> > expectation[1].
> 
> That sounds like a sane definition to me and what I would have expected
> from the PWM framework. That the pin is not defined after pwm_disable is
> totally understandable. It is usually a case which the board designer
> anyway needs to take care of (e.g. what is the state right after power
> on? If the designer cares about, he will put a pull-up/down in place).
> 
> And it seems also Sascha suggested that:
> https://lkml.org/lkml/2013/1/4/139

actually I talked to Sascha in private before ranting :-)

> I did not found where Thierry disagreed to that...?

Hmm, I used gmane links before, most of them are dead today. :-|
http://www.spinics.net/lists/linux-leds/msg03237.html is one example.

> > Today it's a (maybe small) bug, when a pwm consumer calls pwm_config with
> > value=0 and doesn't disable it afterwards. IMHO that's a bug in the pwm
> > API that pwm_config with value=0 doesn't imply (the wanted effects of)
> > pwm_disable.
> 
> I don't quite get what you are saying here. What wanted effects of
> pwm_disable would you like to move into pwm_config with value=0?

I want that the pwm driver disables its clock on pwm_config(mypwm, 0,
someperiod) such that the consumer doesn't need to call
pwm_disable(mypwm) to save power (assuming it's safe to do so, which
only the pwm provider knows).

Best regards
Uwe
Clemens Gruber Sept. 12, 2016, 9:12 p.m. UTC | #9
Hi Uwe,

On Mon, Sep 12, 2016 at 10:00:21PM +0200, Uwe Kleine-König wrote:
> I want that the pwm driver disables its clock on pwm_config(mypwm, 0,
> someperiod) such that the consumer doesn't need to call
> pwm_disable(mypwm) to save power (assuming it's safe to do so, which
> only the pwm provider knows).

I am not sure if this is such a good idea, because there are use cases
where you want to keep the PWM driver enabled the whole time but still
be able to change the duty cycle to 0 for some time without adding
unnecessary delays when changing the duty cycle back to something else.

We have an application where we control fluid valves in a beer
dispensing system through PWMs and these valves are pulsed with
different PWM duty cycles for a short time. In-between the duty cycle
is also 0. For example: Start at 0%, 100ms 90%, 200ms 70%, 300ms 0%,
100ms 90%, and so on..
There it is critical that the change from and to 0 duty cycle is not
delayed by disabling and reenabling the clock.
The oscillator (if there is one) should be up and running, only the duty
cycle should be 0 for a short time.

This would not be possible anymore with your API change, right?

Regards,
Clemens
--
To unsubscribe from this list: send the line "unsubscribe linux-pwm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uwe Kleine-König Sept. 13, 2016, 6:45 a.m. UTC | #10
Hello Clemens,

On Mon, Sep 12, 2016 at 11:12:54PM +0200, Clemens Gruber wrote:
> On Mon, Sep 12, 2016 at 10:00:21PM +0200, Uwe Kleine-König wrote:
> > I want that the pwm driver disables its clock on pwm_config(mypwm, 0,
> > someperiod) such that the consumer doesn't need to call
> > pwm_disable(mypwm) to save power (assuming it's safe to do so, which
> > only the pwm provider knows).
> 
> I am not sure if this is such a good idea, because there are use cases
> where you want to keep the PWM driver enabled the whole time but still
> be able to change the duty cycle to 0 for some time without adding
> unnecessary delays when changing the duty cycle back to something else.
> 
> We have an application where we control fluid valves in a beer
> dispensing system through PWMs and these valves are pulsed with
> different PWM duty cycles for a short time. In-between the duty cycle
> is also 0. For example: Start at 0%, 100ms 90%, 200ms 70%, 300ms 0%,
> 100ms 90%, and so on..
> There it is critical that the change from and to 0 duty cycle is not
> delayed by disabling and reenabling the clock.
> The oscillator (if there is one) should be up and running, only the duty
> cycle should be 0 for a short time.

I don't think it is sensible to map this requirement in the pwm api. The
trade-off between performance and power saving is common between all
types of devices and there are other mechanisms to handle this.

Also only some pwms are affected by this because disabling the clock
doesn't introduce a measurable overhead for all of them.

With write(2) there is also no way to define if the hard disk should
spin down after the request is completed. And this wouldn't make sense
for an ssd.

So yes, there would be no way to prohibit stopping the pwm with the pwm
API, but you could implement runtime pm for your device.

Best regards
Uwe
diff mbox

Patch

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 966497d10c6e..89a5e309b0a3 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -136,9 +136,14 @@  of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
 {
 	struct pwm_device *pwm;
 
+	/* check that the driver supports a third cell for flags */
 	if (pc->of_pwm_n_cells < 3)
 		return ERR_PTR(-EINVAL);
 
+	/* flags in the third cell are optional */
+	if (args->args_count < 2)
+		return ERR_PTR(-EINVAL);
+
 	if (args->args[0] >= pc->npwm)
 		return ERR_PTR(-EINVAL);
 
@@ -148,10 +153,12 @@  of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
 
 	pwm_set_period(pwm, args->args[1]);
 
-	if (args->args[2] & PWM_POLARITY_INVERTED)
-		pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
-	else
-		pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
+	if (args->args_count > 2) {
+		if (args->args[2] & PWM_POLARITY_INVERTED)
+			pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
+		else
+			pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
+	}
 
 	return pwm;
 }
@@ -162,9 +169,14 @@  of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
 {
 	struct pwm_device *pwm;
 
+	/* sanity check driver support */
 	if (pc->of_pwm_n_cells < 2)
 		return ERR_PTR(-EINVAL);
 
+	/* all cells are required */
+	if (args->args_count != pc->of_pwm_n_cells)
+		return ERR_PTR(-EINVAL);
+
 	if (args->args[0] >= pc->npwm)
 		return ERR_PTR(-EINVAL);
 
@@ -536,13 +548,6 @@  struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
 		goto put;
 	}
 
-	if (args.args_count != pc->of_pwm_n_cells) {
-		pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name,
-			 args.np->full_name);
-		pwm = ERR_PTR(-EINVAL);
-		goto put;
-	}
-
 	pwm = pc->of_xlate(pc, &args);
 	if (IS_ERR(pwm))
 		goto put;