Message ID | 1395996540-10999-2-git-send-email-LW@KARO-electronics.de |
---|---|
State | Superseded |
Headers | show |
On Fri, Mar 28, 2014 at 09:48:58AM +0100, 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. > > Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de> > --- > drivers/pwm/core.c | 46 ++++++++++++++++------------------------------ > 1 file changed, 16 insertions(+), 30 deletions(-) > diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c > index a804713..dc15543 100644 > --- a/drivers/pwm/core.c > +++ b/drivers/pwm/core.c > @@ -131,12 +131,12 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) > return 0; > } > > -struct pwm_device * > -of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) > +struct pwm_device *of_pwm_xlate(struct pwm_chip *pc, > + const struct of_phandle_args *args) > { > struct pwm_device *pwm; > > - if (pc->of_pwm_n_cells < 3) > + if (pc->of_pwm_n_cells < 2) > return ERR_PTR(-EINVAL); > > if (args->args[0] >= pc->npwm) > @@ -148,6 +148,9 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) > > pwm_set_period(pwm, args->args[1]); > > + if (pc->of_pwm_n_cells < 3) > + return pwm; > + > if (args->args[2] & PWM_POLARITY_INVERTED) > pwm_set_polarity(pwm, PWM_POLARITY_INVERSED); > else > @@ -155,27 +158,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) > > return pwm; > } > -EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); > > -static struct pwm_device * > -of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) > +struct pwm_device * > +of_pwm_xlate_with_flags(struct pwm_chip *pc, > + const struct of_phandle_args *args) > { > - struct pwm_device *pwm; > - > - if (pc->of_pwm_n_cells < 2) > - return ERR_PTR(-EINVAL); > - > - if (args->args[0] >= pc->npwm) > - return ERR_PTR(-EINVAL); > - > - pwm = pwm_request_from_chip(pc, args->args[0], NULL); > - if (IS_ERR(pwm)) > - return pwm; > - > - pwm_set_period(pwm, args->args[1]); > - > - return pwm; > + return of_pwm_xlate(pc, args); > } > +EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); > > static void of_pwmchip_add(struct pwm_chip *chip) > { > @@ -183,8 +173,11 @@ static void of_pwmchip_add(struct pwm_chip *chip) > return; > > if (!chip->of_xlate) { > - chip->of_xlate = of_pwm_simple_xlate; > - chip->of_pwm_n_cells = 2; > + chip->of_xlate = of_pwm_xlate; > + if (chip->ops->set_polarity) > + chip->of_pwm_n_cells = 3; > + else > + chip->of_pwm_n_cells = 2; I think the presence of the set_polarity callback shouldn't influence the number of cells the parser expects. As commented on 2/2 this doesn't actually mean the device actually support polarity inversion. Also, polarity inversion could still be done in software for hardware that doesn't support it. Sascha
On Wed, Apr 02, 2014 at 07:53:50AM +0200, Sascha Hauer wrote: > On Fri, Mar 28, 2014 at 09:48:58AM +0100, Lothar Waßmann wrote: [...] > > @@ -183,8 +173,11 @@ static void of_pwmchip_add(struct pwm_chip *chip) > > return; > > > > if (!chip->of_xlate) { > > - chip->of_xlate = of_pwm_simple_xlate; > > - chip->of_pwm_n_cells = 2; > > + chip->of_xlate = of_pwm_xlate; > > + if (chip->ops->set_polarity) > > + chip->of_pwm_n_cells = 3; > > + else > > + chip->of_pwm_n_cells = 2; > > I think the presence of the set_polarity callback shouldn't influence > the number of cells the parser expects. As commented on 2/2 this doesn't > actually mean the device actually support polarity inversion. How so? A driver should only implement .set_polarity() if it supports changing the polarity. That said, I agree that the presence of .set_polarity() shouldn't determine the number of cells. You could have any number of other flags set via the third cell. > Also, polarity inversion could still be done in software for hardware > that doesn't support it. No. You cannot emulate polarity inversion in software. Thierry
Hi, Thierry Reding wrote: > On Wed, Apr 02, 2014 at 07:53:50AM +0200, Sascha Hauer wrote: > > On Fri, Mar 28, 2014 at 09:48:58AM +0100, Lothar Waßmann wrote: > [...] > > > @@ -183,8 +173,11 @@ static void of_pwmchip_add(struct pwm_chip *chip) > > > return; > > > > > > if (!chip->of_xlate) { > > > - chip->of_xlate = of_pwm_simple_xlate; > > > - chip->of_pwm_n_cells = 2; > > > + chip->of_xlate = of_pwm_xlate; > > > + if (chip->ops->set_polarity) > > > + chip->of_pwm_n_cells = 3; > > > + else > > > + chip->of_pwm_n_cells = 2; > > > > I think the presence of the set_polarity callback shouldn't influence > > the number of cells the parser expects. As commented on 2/2 this doesn't > > actually mean the device actually support polarity inversion. > > How so? A driver should only implement .set_polarity() if it supports > changing the polarity. > > That said, I agree that the presence of .set_polarity() shouldn't > determine the number of cells. You could have any number of other flags > set via the third cell. > > > Also, polarity inversion could still be done in software for hardware > > that doesn't support it. > > No. You cannot emulate polarity inversion in software. > Why not? duty_ns = period_ns - duty_ns; Lothar Waßmann
On Mon, Apr 7, 2014 at 10:02 PM, Lothar Waßmann <LW@karo-electronics.de> wrote: > Thierry Reding wrote: >> No. You cannot emulate polarity inversion in software. >> > Why not? > > duty_ns = period_ns - duty_ns; Since I made the same mistake, I will pass along the pointer Thierry gave me. In include/linux/pwm.h the second difference for an inverted signal is described. /** * enum pwm_polarity - polarity of a PWM signal * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty- * cycle, followed by a low signal for the remainder of the pulse * period * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty- * cycle, followed by a high signal for the remainder of the pulse * period */ enum pwm_polarity { PWM_POLARITY_NORMAL, PWM_POLARITY_INVERSED, }; Of course, I suspect not all PWM hardware respects this definition of inverted output. Either way, hacking the duty in software certainly would get the high/low order wrong. -Tim -- 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
Hi, Tim Kryger wrote: > On Mon, Apr 7, 2014 at 10:02 PM, Lothar Waßmann <LW@karo-electronics.de>wrote: > > > > > > Thierry Reding wrote: > > > > > No. You cannot emulate polarity inversion in software. > > > > > Why not? > > > > duty_ns = period_ns - duty_ns; > > > > Since I made the same mistake, I will pass along the pointer Thierry gave > me. > > In include/linux/pwm.h the second difference for an inverted signal is > described. > > /** > * enum pwm_polarity - polarity of a PWM signal > * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty- > * cycle, followed by a low signal for the remainder of the pulse > * period > * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty- > * cycle, followed by a high signal for the remainder of the pulse > * period > */ > enum pwm_polarity { > PWM_POLARITY_NORMAL, > PWM_POLARITY_INVERSED, > }; > > Of course, I suspect not all PWM hardware respects this definition of > inverted output. > > Either way, hacking the duty in software certainly would get the high/low > order wrong. > OK. But for a periodic signal this doesn't make any difference. It's just a matter of where you set your reference point. Only if you program the PWM to create a single cycle you would see the difference. I wonder if this is a real life usecase though. Lothar Waßmann
On Tue, Apr 08, 2014 at 01:43:22PM -0700, Tim Kryger wrote: > On Mon, Apr 7, 2014 at 10:02 PM, Lothar Waßmann <LW@karo-electronics.de> wrote: > > Thierry Reding wrote: > > >> No. You cannot emulate polarity inversion in software. > >> > > Why not? > > > > duty_ns = period_ns - duty_ns; > > Since I made the same mistake, I will pass along the pointer Thierry gave me. > > In include/linux/pwm.h the second difference for an inverted signal is > described. > > /** > * enum pwm_polarity - polarity of a PWM signal > * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty- > * cycle, followed by a low signal for the remainder of the pulse > * period > * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty- > * cycle, followed by a high signal for the remainder of the pulse > * period > */ > enum pwm_polarity { > PWM_POLARITY_NORMAL, > PWM_POLARITY_INVERSED, > }; > > Of course, I suspect not all PWM hardware respects this definition of > inverted output. > > Either way, hacking the duty in software certainly would get the > high/low order wrong. This only relevant if you have some reference signal the PWM must be relative to, for example if you combine multiple PWMs for motor control. For PWMs used for backlight or beepers a signal inversion in software is perfectly fine. And I also think that it makes sense to put it once into the framework instead of bothering all consumer drivers with the inversion. Sascha
On Wed, Apr 09, 2014 at 08:04:50AM +0200, Lothar Waßmann wrote: > Hi, > > Tim Kryger wrote: > > On Mon, Apr 7, 2014 at 10:02 PM, Lothar Waßmann <LW@karo-electronics.de>wrote: > > > > > > > > > Thierry Reding wrote: > > > > > > > No. You cannot emulate polarity inversion in software. > > > > > > > Why not? > > > > > > duty_ns = period_ns - duty_ns; > > > > > > > Since I made the same mistake, I will pass along the pointer Thierry gave > > me. > > > > In include/linux/pwm.h the second difference for an inverted signal is > > described. > > > > /** > > * enum pwm_polarity - polarity of a PWM signal > > * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty- > > * cycle, followed by a low signal for the remainder of the pulse > > * period > > * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty- > > * cycle, followed by a high signal for the remainder of the pulse > > * period > > */ > > enum pwm_polarity { > > PWM_POLARITY_NORMAL, > > PWM_POLARITY_INVERSED, > > }; > > > > Of course, I suspect not all PWM hardware respects this definition of > > inverted output. > > > > Either way, hacking the duty in software certainly would get the high/low > > order wrong. > > > OK. But for a periodic signal this doesn't make any difference. It's > just a matter of where you set your reference point. > Only if you program the PWM to create a single cycle you would see the > difference. I wonder if this is a real life usecase though. It doesn't make a difference if all you're concerned about is the signal power (which happens to be the case for LED and backlight use-cases). Currently any in-kernel users only care about the signal power, but there's no guarantee that it will stay that way. Furthermore, PWM channels are exposed to userspace via sysfs, so code that we don't actually see may rely on this behaviour. Thierry
On Wed, Apr 09, 2014 at 08:12:09AM +0200, Sascha Hauer wrote: > On Tue, Apr 08, 2014 at 01:43:22PM -0700, Tim Kryger wrote: > > On Mon, Apr 7, 2014 at 10:02 PM, Lothar Waßmann <LW@karo-electronics.de> wrote: > > > Thierry Reding wrote: > > > > >> No. You cannot emulate polarity inversion in software. > > >> > > > Why not? > > > > > > duty_ns = period_ns - duty_ns; > > > > Since I made the same mistake, I will pass along the pointer Thierry gave me. > > > > In include/linux/pwm.h the second difference for an inverted signal is > > described. > > > > /** > > * enum pwm_polarity - polarity of a PWM signal > > * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty- > > * cycle, followed by a low signal for the remainder of the pulse > > * period > > * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty- > > * cycle, followed by a high signal for the remainder of the pulse > > * period > > */ > > enum pwm_polarity { > > PWM_POLARITY_NORMAL, > > PWM_POLARITY_INVERSED, > > }; > > > > Of course, I suspect not all PWM hardware respects this definition of > > inverted output. > > > > Either way, hacking the duty in software certainly would get the > > high/low order wrong. > > This only relevant if you have some reference signal the PWM must be > relative to, for example if you combine multiple PWMs for motor control. > For PWMs used for backlight or beepers a signal inversion in software is > perfectly fine. And I also think that it makes sense to put it once into > the framework instead of bothering all consumer drivers with the > inversion. The PWM framework itself doesn't have enough knowledge about what a PWM is being used for. Therefore it cannot determine whether emulating polarity inversion by reversing the duty cycle will be appropriate. Putting such functionality into the core will prevent PWM channels from being used for cases where the signal polarity does matter. Thierry
On Wed, Apr 09, 2014 at 09:22:50AM +0200, Thierry Reding wrote: > On Wed, Apr 09, 2014 at 08:12:09AM +0200, Sascha Hauer wrote: > > On Tue, Apr 08, 2014 at 01:43:22PM -0700, Tim Kryger wrote: > > > On Mon, Apr 7, 2014 at 10:02 PM, Lothar Waßmann <LW@karo-electronics.de> wrote: > > > > Thierry Reding wrote: > > > > > > >> No. You cannot emulate polarity inversion in software. > > > >> > > > > Why not? > > > > > > > > duty_ns = period_ns - duty_ns; > > > > > > Since I made the same mistake, I will pass along the pointer Thierry gave me. > > > > > > In include/linux/pwm.h the second difference for an inverted signal is > > > described. > > > > > > /** > > > * enum pwm_polarity - polarity of a PWM signal > > > * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty- > > > * cycle, followed by a low signal for the remainder of the pulse > > > * period > > > * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty- > > > * cycle, followed by a high signal for the remainder of the pulse > > > * period > > > */ > > > enum pwm_polarity { > > > PWM_POLARITY_NORMAL, > > > PWM_POLARITY_INVERSED, > > > }; > > > > > > Of course, I suspect not all PWM hardware respects this definition of > > > inverted output. > > > > > > Either way, hacking the duty in software certainly would get the > > > high/low order wrong. > > > > This only relevant if you have some reference signal the PWM must be > > relative to, for example if you combine multiple PWMs for motor control. > > For PWMs used for backlight or beepers a signal inversion in software is > > perfectly fine. And I also think that it makes sense to put it once into > > the framework instead of bothering all consumer drivers with the > > inversion. > > The PWM framework itself doesn't have enough knowledge about what a PWM > is being used for. Therefore it cannot determine whether emulating > polarity inversion by reversing the duty cycle will be appropriate. > > Putting such functionality into the core will prevent PWM channels from > being used for cases where the signal polarity does matter The PWM core is in no way prepared for handling such situations. Should we want to add support it a PWM_POLARITY_INVERSED flag would be the least of our problems. It could be renamed to PWM_POLARITY_INVERSED_ASYNC for the beeper/led drivers which do not need synchronization. Sascha
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index a804713..dc15543 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -131,12 +131,12 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) return 0; } -struct pwm_device * -of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) +struct pwm_device *of_pwm_xlate(struct pwm_chip *pc, + const struct of_phandle_args *args) { struct pwm_device *pwm; - if (pc->of_pwm_n_cells < 3) + if (pc->of_pwm_n_cells < 2) return ERR_PTR(-EINVAL); if (args->args[0] >= pc->npwm) @@ -148,6 +148,9 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) pwm_set_period(pwm, args->args[1]); + if (pc->of_pwm_n_cells < 3) + return pwm; + if (args->args[2] & PWM_POLARITY_INVERTED) pwm_set_polarity(pwm, PWM_POLARITY_INVERSED); else @@ -155,27 +158,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) return pwm; } -EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); -static struct pwm_device * -of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) +struct pwm_device * +of_pwm_xlate_with_flags(struct pwm_chip *pc, + const struct of_phandle_args *args) { - struct pwm_device *pwm; - - if (pc->of_pwm_n_cells < 2) - return ERR_PTR(-EINVAL); - - if (args->args[0] >= pc->npwm) - return ERR_PTR(-EINVAL); - - pwm = pwm_request_from_chip(pc, args->args[0], NULL); - if (IS_ERR(pwm)) - return pwm; - - pwm_set_period(pwm, args->args[1]); - - return pwm; + return of_pwm_xlate(pc, args); } +EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); static void of_pwmchip_add(struct pwm_chip *chip) { @@ -183,8 +173,11 @@ static void of_pwmchip_add(struct pwm_chip *chip) return; if (!chip->of_xlate) { - chip->of_xlate = of_pwm_simple_xlate; - chip->of_pwm_n_cells = 2; + chip->of_xlate = of_pwm_xlate; + if (chip->ops->set_polarity) + chip->of_pwm_n_cells = 3; + else + chip->of_pwm_n_cells = 2; } of_node_get(chip->dev->of_node); @@ -536,13 +529,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;
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. Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de> --- drivers/pwm/core.c | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-)