linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
To: "Vokáč Michal" <Michal.Vokac@ysoft.com>
Cc: "Thierry Reding" <thierry.reding@gmail.com>,
	"Rob Herring" <robh+dt@kernel.org>,
	"Mark Rutland" <mark.rutland@arm.com>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"linux-pwm@vger.kernel.org" <linux-pwm@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"Lukasz Majewski" <l.majewski@majess.pl>,
	"Fabio Estevam" <fabio.estevam@nxp.com>,
	"Lothar Waßmann" <LW@karo-electronics.de>,
	kernel@pengutronix.de
Subject: Re: [RCF PATCH,v2,2/2] pwm: imx: Configure output to GPIO in disabled state
Date: Fri, 12 Oct 2018 10:57:24 +0200	[thread overview]
Message-ID: <20181012085720.GA9451@taurus.defre.kleine-koenig.org> (raw)
In-Reply-To: <1539163920-9442-3-git-send-email-michal.vokac@ysoft.com>

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

Hello,

On Wed, Oct 10, 2018 at 09:33:26AM +0000, Vokáč Michal wrote:
> Normally the PWM output is held LOW when PWM is disabled. This can cause
> problems when inverted PWM signal polarity is needed. With this behavior
> the connected circuit is fed by 100% duty cycle instead of being shut-off.
> 
> Allow users to define a "gpio" and a "pwm" pinctrl states. The pwm pinctrl
> state is then selected when PWM is enabled and the gpio pinctrl state is
> selected when PWM is disabled. Also add a new pwm-gpios GPIO that is used
> to drive the output in the gpio state.
> 
> If all the pinctrl states and the pwm-gpios are not correctly specified
> in DT the logic will work as before.
> 
> As an example, with this patch a PWM controlled backlight with inversed
> signal polarity can be used in full brightness range. Without this patch
> the backlight can not be turned off as brightness = 0 disables the PWM
> and that in turn set PWM output LOW, that is full brightness.
> 
> Output of the PWM with "default" pinctrl and with "pwm"+"gpio" pinctrl:
> 
> +--------------+------------+---------------+---------------------------+
> | After reset  | Bootloader | Linux pinctrl | User (sysfs, backlight..) |
> | 100k pull-up | (not used) |               |   enable    |   disable   |
> +--------------+------------+---------------+---------------------------+
>  ___________________________    default        _   _   _
>                             |_________________| |_| |_| |_|_____________
> 
>                                pwm + gpio
>  ___________________________________________   _   _   _   _____________
>                                             |_| |_| |_| |_|

I was made aware of this patch by Thierry while discussion about a patch
opportunity. I already pointed out some stuff I don't like about this
patch in the repective thread, but I repeat it here to have it at the
right place.

> Signed-off-by: Michal Vokáč <michal.vokac@ysoft.com>
> ---
> Changes in v2:
>  - Utilize the "pwm" and "gpio" pinctrl states.
>  - Use the pwm-gpios signal to drive the output in "gpio" pinctrl state.
>  - Select the right pinctrl state in probe. 
> 
>  drivers/pwm/pwm-imx.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
> index 6cd3b72..3502123 100644
> --- a/drivers/pwm/pwm-imx.c
> +++ b/drivers/pwm/pwm-imx.c
> @@ -10,11 +10,13 @@
>  #include <linux/clk.h>
>  #include <linux/delay.h>
>  #include <linux/err.h>
> +#include <linux/gpio/consumer.h>
>  #include <linux/io.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> +#include <linux/pinctrl/consumer.h>
>  #include <linux/platform_device.h>
>  #include <linux/pwm.h>
>  #include <linux/slab.h>
> @@ -92,10 +94,45 @@ struct imx_chip {
>  	void __iomem	*mmio_base;
>  
>  	struct pwm_chip	chip;
> +
> +	struct pinctrl *pinctrl;
> +	struct pinctrl_state *pinctrl_pins_gpio;
> +	struct pinctrl_state *pinctrl_pins_pwm;
> +	struct gpio_desc *pwm_gpiod;

The pinctrl framework already knows about "init" and "default". These
should be enough. i.e. "init" configures as gpio and "default" als pwm.

>  };
>  
> +
>  #define to_imx_chip(chip)	container_of(chip, struct imx_chip, chip)
>  
> +static int imx_pwm_init_pinctrl_info(struct imx_chip *imx_chip,
> +		struct platform_device *pdev)
> +{
> +	imx_chip->pinctrl = devm_pinctrl_get(&pdev->dev);
> +	if (!imx_chip->pinctrl || IS_ERR(imx_chip->pinctrl)) {
> +		dev_info(&pdev->dev, "can not get pinctrl\n");
> +		return PTR_ERR(imx_chip->pinctrl);
> +	}
> +
> +	imx_chip->pinctrl_pins_pwm = pinctrl_lookup_state(imx_chip->pinctrl,
> +			"pwm");
> +	imx_chip->pinctrl_pins_gpio = pinctrl_lookup_state(imx_chip->pinctrl,
> +			"gpio");
> +	imx_chip->pwm_gpiod = devm_gpiod_get_optional(&pdev->dev, "pwm",
> +			GPIOD_IN);
> +
> +	if (PTR_ERR(imx_chip->pwm_gpiod) == -EPROBE_DEFER) {

You must not use PTR_ERR on a value that might not contain an error
pointer.

> +		return -EPROBE_DEFER;
> +	} else if (IS_ERR(imx_chip->pwm_gpiod) ||
> +		   IS_ERR(imx_chip->pinctrl_pins_pwm) ||
> +		   IS_ERR(imx_chip->pinctrl_pins_gpio)) {

Would it be more correct to handle imx_chip->pinctrl_pins_pwm ==
ERR_PTR(-EPROBE_DEFER) similar to imx_chip->pwm_gpiod ==
ERR_PTR(-EPROBE_DEFER)?

> +		dev_dbg(&pdev->dev, "PWM pinctrl information incomplete\n");

I wouldn't call that "incomplete". It's incomplete for the gpio
switching trick, but enough in general.

> +		devm_pinctrl_put(imx_chip->pinctrl);
> +		imx_chip->pinctrl = NULL;
> +	}
> +
> +	return 0;
> +}
> +
>  static void imx_pwm_get_state(struct pwm_chip *chip,
>  		struct pwm_device *pwm, struct pwm_state *state)
>  {
> @@ -306,7 +343,31 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm,
>  					MX3_PWMCR_POUTC_INVERTED);
>  
>  		writel(cr, imx->mmio_base + MX3_PWMCR);
> +
> +		/*
> +		 * If we are in charge of pinctrl then switch output to
> +		 * the PWM signal.
> +		 */
> +		if (imx->pinctrl)
> +			pinctrl_select_state(imx->pinctrl,
> +					imx->pinctrl_pins_pwm);
>  	} else if (cstate.enabled) {
> +		/*
> +		 * PWM block will be disabled. Normally its output will be set
> +		 * low no matter what output polarity is configured. Lets use

s/Lets/Let's/

> +		 * pinctrl to switch the output pin to GPIO functon and keep
> +		 * the output at the same level as for duty-cycle = 0.

Is it obvious that using a GPIO is more efficient/better/worth the
complexity than just enabling the PWM with duty-cycle 0 and the right
polarity?

> +		 * First set the GPIO to the desired level, then switch the
> +		 * muxing and at last disable PWM. In that order we do not get
> +		 * unwanted logic level changes on the output.
> +		 */
> +		if (imx->pinctrl) {
> +			gpiod_set_value_cansleep(imx->pwm_gpiod, 0);

You must call gpiod_direction_output for this to have any effect.
There might be mechanisms in pincontrol that automatically mux the pin
if it's configured as gpio, I didn't follow the details though.

Also it should be possible to configure the GPIO as output immediatly.
If the pinmuxing is set to the PWM function this doesn't have a visible
side effect.

> +			pinctrl_select_state(imx->pinctrl,
> +					imx->pinctrl_pins_gpio);

Usually align function arguments to the opening (.

> +		}
> +
>  		writel(0, imx->mmio_base + MX3_PWMCR);
>  
>  		clk_disable_unprepare(imx->clk_per);
> @@ -354,6 +415,7 @@ static int imx_pwm_probe(struct platform_device *pdev)
>  	const struct of_device_id *of_id =
>  			of_match_device(imx_pwm_dt_ids, &pdev->dev);
>  	const struct imx_pwm_data *data;
> +	struct pwm_state cstate;
>  	struct imx_chip *imx;
>  	struct resource *r;
>  	int ret = 0;
> @@ -385,6 +447,10 @@ static int imx_pwm_probe(struct platform_device *pdev)
>  		imx->chip.of_pwm_n_cells = 3;
>  	}
>  
> +	ret = imx_pwm_init_pinctrl_info(imx, pdev);
> +	if (ret)
> +		return ret;
> +
>  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
>  	if (IS_ERR(imx->mmio_base))
> @@ -394,6 +460,26 @@ static int imx_pwm_probe(struct platform_device *pdev)
>  	if (ret < 0)
>  		return ret;
>  
> +	if (imx->pinctrl) {
> +		/*
> +		 * Update cstate after pwmchip_add() call as the core might
> +		 * call the get_state() function to read the PWM registers
> +		 * to get the actual HW state.
> +		 */
> +		pwm_get_state(imx->chip.pwms, &cstate);
> +		if (cstate.enabled) {
> +			dev_dbg(&pdev->dev,
> +				"PWM entered probe in enabled state\n");
> +			pinctrl_select_state(imx->pinctrl,
> +					imx->pinctrl_pins_pwm);
> +		} else {
> +			gpiod_set_value_cansleep(imx->pwm_gpiod, 0);
> +			pinctrl_select_state(imx->pinctrl,
> +					imx->pinctrl_pins_gpio);
> +
> +		}
> +	}
> +
>  	platform_set_drvdata(pdev, imx);
>  	return 0;
>  }

There is nothing in this patch that would prevent this code to live in a
place where other drivers could reuse this. (But attention, there are
dragons: Thierry already replied on my topic that his view is different
in this aspect compared to other maintainers though. His POV is that as
long as there is only a single driver known that has a problem this
should be handled in driver specific code.)

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

  reply	other threads:[~2018-10-12  9:04 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-10  9:33 [RCF PATCH v2 0/2] pwm: imx: Configure output to GPIO in disabled state Vokáč Michal
2018-10-10  9:33 ` [RCF PATCH v2 1/2] dt-bindings: pwm: imx: Allow switching PWM output between PWM and GPIO Vokáč Michal
2018-10-10 13:39   ` Thierry Reding
2018-10-29 15:52     ` Vokáč Michal
2018-10-10  9:33 ` [RCF PATCH v2 2/2] pwm: imx: Configure output to GPIO in disabled state Vokáč Michal
2018-10-12  8:57   ` Uwe Kleine-König [this message]
2018-10-12 15:04     ` [RCF PATCH,v2,2/2] " Vokáč Michal
2018-10-12 15:54       ` Thierry Reding
2018-10-12 16:08       ` Uwe Kleine-König
2018-10-14 20:24         ` Uwe Kleine-König
2018-10-15  8:45           ` Thierry Reding
2018-10-29 15:55             ` Vokáč Michal
2018-10-29 15:54         ` Vokáč Michal
2018-11-07  9:33           ` Uwe Kleine-König
2018-11-07 13:32             ` Vokáč Michal
2018-11-07 15:01               ` Uwe Kleine-König
2018-11-08 15:21                 ` Vokáč Michal
2018-11-08 19:18                   ` Uwe Kleine-König
2018-11-09 14:24                     ` Vokáč Michal
2018-11-09 16:55                       ` Uwe Kleine-König
2018-11-14  9:09                         ` Uwe Kleine-König
2018-11-14 11:34                         ` Thierry Reding
2018-11-14 21:51                           ` Uwe Kleine-König
2018-11-15 15:25                             ` Thierry Reding
2018-11-15 20:37                               ` Uwe Kleine-König
2018-11-16  7:34                                 ` Lothar Waßmann
2018-11-16  8:25                                   ` Uwe Kleine-König
2018-11-22 15:42                                     ` Vokáč Michal
2018-11-22 16:23                                       ` Uwe Kleine-König
2018-11-22 16:46                                         ` Vokáč Michal
2018-11-22 19:03                                           ` Uwe Kleine-König
2018-11-23 15:15                                             ` Vokáč Michal
2018-11-25 20:56                                               ` Uwe Kleine-König
2018-11-26  9:11                                                 ` Lothar Waßmann
2018-11-26  9:18                                                   ` Uwe Kleine-König
2018-11-26 10:03                                                     ` Lothar Waßmann
2018-11-26 11:51                                               ` Thierry Reding
2018-11-26 12:23                                                 ` Lothar Waßmann
2018-11-26 13:34                                                   ` Thierry Reding
2018-11-26 15:50                                                     ` Vokáč Michal
2018-11-16  9:51                                 ` Thierry Reding
2018-11-16 10:39                                   ` Uwe Kleine-König
2018-11-16 11:56                                     ` Lothar Waßmann
2018-11-18 11:30                                       ` Uwe Kleine-König
2018-11-16 12:24                                     ` Thierry Reding
2018-11-18 20:08                                       ` Uwe Kleine-König
2018-11-19  8:48                                         ` Uwe Kleine-König
2018-11-22 15:03                                         ` Thierry Reding
2018-11-22 16:17                                           ` Uwe Kleine-König
2018-11-20 13:14                                   ` Vokáč Michal
2018-11-20 16:54                                     ` Uwe Kleine-König
2018-11-22 14:23                                       ` Vokáč Michal
2018-11-19  7:44                             ` Linus Walleij
2018-11-19  8:32                               ` Uwe Kleine-König
2018-11-20  8:35                                 ` Linus Walleij
2018-11-20  9:16                                   ` Viresh Kumar
2018-11-20  9:53                                   ` Uwe Kleine-König
2018-11-14 11:14                   ` Thierry Reding
2018-10-12 16:00   ` [RCF PATCH v2 2/2] " Thierry Reding
2018-10-29 15:53     ` Vokáč Michal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181012085720.GA9451@taurus.defre.kleine-koenig.org \
    --to=u.kleine-koenig@pengutronix.de \
    --cc=LW@karo-electronics.de \
    --cc=Michal.Vokac@ysoft.com \
    --cc=devicetree@vger.kernel.org \
    --cc=fabio.estevam@nxp.com \
    --cc=kernel@pengutronix.de \
    --cc=l.majewski@majess.pl \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=robh+dt@kernel.org \
    --cc=thierry.reding@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).