devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Nuno Sá" <noname.nuno@gmail.com>
To: "Guillaume Stols" <gstols@baylibre.com>,
	"Uwe Kleine-König" <ukleinek@kernel.org>,
	"Lars-Peter Clausen" <lars@metafoo.de>,
	"Michael Hennerich" <Michael.Hennerich@analog.com>,
	"Jonathan Cameron" <jic23@kernel.org>,
	"Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	"Jonathan Corbet" <corbet@lwn.net>
Cc: linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org,
	 linux-fbdev@vger.kernel.org, linux-iio@vger.kernel.org,
	 devicetree@vger.kernel.org, linux-doc@vger.kernel.org,
	aardelean@baylibre.com,  dlechner@baylibre.com,
	jstephan@baylibre.com,
	Jonathan Cameron <Jonathan.Cameron@huawei.com>
Subject: Re: [PATCH v4 4/8] iio: adc: ad7606: Add PWM support for conversion trigger
Date: Wed, 09 Oct 2024 16:29:33 +0200	[thread overview]
Message-ID: <5860310e0413038ac477b9e191c3d15029487628.camel@gmail.com> (raw)
In-Reply-To: <20241009-ad7606_add_iio_backend_support-v4-4-6971a8c0f1d5@baylibre.com>

On Wed, 2024-10-09 at 09:19 +0000, Guillaume Stols wrote:
> Until now, the conversion were triggered by setting high the GPIO
> connected to the convst pin. This commit gives the possibility to
> connect the convst pin to a PWM.
> Connecting a PWM allows to have a better control on the samplerate,
> but it must be handled with care, as it is completely decorrelated of
> the driver's busy pin handling.
> Hence it is not recommended to be used "as is" but must be exploited
> in conjunction with IIO backend, and for now only a mock functionality
> is enabled, i.e PWM never swings, but is used as a GPIO, i.e duty_cycle
> == period equals high state, duty_cycle == 0 equals low state.
> 
> This mock functionality will be disabled after the IIO backend usecase
> is introduced.
> 
> Signed-off-by: Guillaume Stols <gstols@baylibre.com>
> ---

Hi Guillaume,

Looks overall good, just some minor stuff

>  drivers/iio/adc/ad7606.c | 143 +++++++++++++++++++++++++++++++++++++++++++----
>  drivers/iio/adc/ad7606.h |   2 +
>  2 files changed, 135 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
> index 71362eafe838..5b276d087ec3 100644
> --- a/drivers/iio/adc/ad7606.c
> +++ b/drivers/iio/adc/ad7606.c
> @@ -13,10 +13,12 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/property.h>
> +#include <linux/pwm.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/sched.h>
>  #include <linux/slab.h>
>  #include <linux/sysfs.h>
> +#include <linux/units.h>
>  #include <linux/util_macros.h>
>  
>  #include <linux/iio/buffer.h>
> @@ -299,6 +301,82 @@ static int ad7606_reg_access(struct iio_dev *indio_dev,
>  	}
>  }
>  
> +static int ad7606_pwm_set_high(struct ad7606_state *st)
> +{
> +	struct pwm_state cnvst_pwm_state;
> +	int ret;
> +
> +	if (!st->cnvst_pwm)
> +		return -EINVAL;
> +

Maybe consider doing the check before calling the API (for the cases that need it)?
It seems at least that in a couple of cases you actually already know that the PWM
must be here (since you check for the gpio presence)...

> +	pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
> +	cnvst_pwm_state.enabled = true;
> +	cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period;
> +
> +	ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
> +	/* sleep 2 µS to let finish the current pulse */
> +	fsleep(2);
> +
> +	return ret;
> +}
> +
> +static int ad7606_pwm_set_low(struct ad7606_state *st)
> +{
> +	struct pwm_state cnvst_pwm_state;
> +	int ret;
> +
> +	if (!st->cnvst_pwm)
> +		return -EINVAL;
> +

Same deal...

> +	pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
> +	cnvst_pwm_state.enabled = true;
> +	cnvst_pwm_state.duty_cycle = 0;
> +
> +	ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
> +	/* sleep 2 µS to let finish the current pulse */
> +	fsleep(2);
> +
> +	return ret;
> +}
> +
> +static bool ad7606_pwm_is_swinging(struct ad7606_state *st)
> +{
> +	struct pwm_state cnvst_pwm_state;
> +
> +	if (!st->cnvst_pwm)
> +		return false;
> +

This one also seems to be redundant? ad7606_set_sampling_freq() should be only called
from a context where the PWM exists right?

> +	pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
> +
> +	return cnvst_pwm_state.duty_cycle != cnvst_pwm_state.period &&
> +	       cnvst_pwm_state.duty_cycle != 0;
> +}
> +
> +static int ad7606_set_sampling_freq(struct ad7606_state *st, unsigned long freq)
> +{
> +	struct pwm_state cnvst_pwm_state;
> +	bool is_swinging = ad7606_pwm_is_swinging(st);
> +	bool is_high;
> +
> +	if (freq == 0)
> +		return -EINVAL;
> +
> +	/* Retrieve the previous state. */
> +	pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
> +	is_high = cnvst_pwm_state.duty_cycle == cnvst_pwm_state.period;
> +
> +	cnvst_pwm_state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, freq);
> +	cnvst_pwm_state.polarity = PWM_POLARITY_NORMAL;
> +	if (is_high)
> +		cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period;
> +	else if (is_swinging)
> +		cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2;
> +	else
> +		cnvst_pwm_state.duty_cycle = 0;
> +
> +	return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
> +}
> +
>  static int ad7606_read_samples(struct ad7606_state *st)
>  {
>  	unsigned int num = st->chip_info->num_channels - 1;
> @@ -325,6 +403,7 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p)
>  	iio_trigger_notify_done(indio_dev->trig);
>  	/* The rising edge of the CONVST signal starts a new conversion. */
>  	gpiod_set_value(st->gpio_convst, 1);
> +	ad7606_pwm_set_high(st);
>  
>  	return IRQ_HANDLED;
>  }
> @@ -337,7 +416,13 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev,
> unsigned int ch,
>  	const struct iio_chan_spec *chan;
>  	int ret;
>  
> -	gpiod_set_value(st->gpio_convst, 1);
> +	if (st->gpio_convst) {
> +		gpiod_set_value(st->gpio_convst, 1);
> +	} else {
> +		ret = ad7606_pwm_set_high(st);
> +		if (ret < 0)
> +			return ret;
> +	}
>  	ret = wait_for_completion_timeout(&st->completion,
>  					  msecs_to_jiffies(1000));
>  	if (!ret) {
> @@ -363,6 +448,11 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev,
> unsigned int ch,
>  	}
>  
>  error_ret:
> +	if (!st->gpio_convst) {
> +		ret = ad7606_pwm_set_low(st);
> +		if (ret < 0)
> +			return ret;
> +	}
>  	gpiod_set_value(st->gpio_convst, 0);
>  
>  	return ret;
> @@ -662,8 +752,9 @@ static int ad7606_request_gpios(struct ad7606_state *st)
>  {
>  	struct device *dev = st->dev;
>  
> -	st->gpio_convst = devm_gpiod_get(dev, "adi,conversion-start",
> -					 GPIOD_OUT_LOW);
> +	st->gpio_convst = devm_gpiod_get_optional(dev, "adi,conversion-start",
> +						  GPIOD_OUT_LOW);
> +
>  	if (IS_ERR(st->gpio_convst))
>  		return PTR_ERR(st->gpio_convst);
>  
> @@ -708,6 +799,7 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
>  
>  	if (iio_buffer_enabled(indio_dev)) {
>  		gpiod_set_value(st->gpio_convst, 0);
> +		ad7606_pwm_set_low(st);
>  		iio_trigger_poll_nested(st->trig);
>  	} else {
>  		complete(&st->completion);
> @@ -732,6 +824,7 @@ static int ad7606_buffer_postenable(struct iio_dev *indio_dev)
>  	struct ad7606_state *st = iio_priv(indio_dev);
>  
>  	gpiod_set_value(st->gpio_convst, 1);
> +	ad7606_pwm_set_high(st);

error handling?
>  
>  	return 0;
>  }
> @@ -741,6 +834,7 @@ static int ad7606_buffer_predisable(struct iio_dev *indio_dev)
>  	struct ad7606_state *st = iio_priv(indio_dev);
>  
>  	gpiod_set_value(st->gpio_convst, 0);
> +	ad7606_pwm_set_low(st);
> 

error handling?

>  	return 0;
>  }
> @@ -874,6 +968,11 @@ static int ad7606_chan_scales_setup(struct iio_dev *indio_dev)
>  	return 0;
>  }
>  
> +static void ad7606_pwm_disable(void *data)
> +{
> +	pwm_disable(data);
> +}
> +
>  int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
>  		 const char *name, unsigned int id,
>  		 const struct ad7606_bus_ops *bops)
> @@ -950,6 +1049,31 @@ int ad7606_probe(struct device *dev, int irq, void __iomem
> *base_address,
>  	if (ret)
>  		return ret;
>  
> +	/* If convst pin is not defined, setup PWM. */
> +	if (!st->gpio_convst) {
> +		st->cnvst_pwm = devm_pwm_get(dev, NULL);
> +		if (IS_ERR(st->cnvst_pwm))
> +			return PTR_ERR(st->cnvst_pwm);
> +
> +		/* The PWM is initialized at 1MHz to have a fast enough GPIO
> emulation. */
> +		ret = ad7606_set_sampling_freq(st, 1 * MEGA);
> +		if (ret)
> +			return ret;
> +
> +		ret = ad7606_pwm_set_low(st);
> +		if (ret)
> +			return ret;
> +
> +		/*
> +		 * PWM is not disabled when sampling stops, but instead its duty
> cycle is set
> +		 * to 0% to be sure we have a "low" state. After we unload the
> driver, let's
> +		 * disable the PWM.
> +		 */
> +		ret = devm_add_action_or_reset(dev, ad7606_pwm_disable,
> +					       st->cnvst_pwm);
> +		if (ret)
> +			return ret;
> +	}
>  	st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
>  					  indio_dev->name,
>  					  iio_device_id(indio_dev));
> @@ -963,6 +1087,12 @@ int ad7606_probe(struct device *dev, int irq, void __iomem
> *base_address,
>  		return ret;
>  
>  	indio_dev->trig = iio_trigger_get(st->trig);
> +	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
> +					      &iio_pollfunc_store_time,
> +					      &ad7606_trigger_handler,
> +					      &ad7606_buffer_ops);
> +	if (ret)
> +		return ret;
> 

The above change seems unrelated?

- Nuno Sá


  reply	other threads:[~2024-10-09 14:29 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-09  9:19 [PATCH v4 0/8] Add iio backend compatibility for ad7606 Guillaume Stols
2024-10-09  9:19 ` [PATCH v4 1/8] dt-bindings: iio: adc: ad7606: Remove spi-cpha from required Guillaume Stols
2024-10-09  9:19 ` [PATCH v4 2/8] dt-bindings: iio: adc: ad7606: Add iio backend bindings Guillaume Stols
2024-10-09  9:19 ` [PATCH v4 3/8] Documentation: iio: Document ad7606 driver Guillaume Stols
2024-10-09  9:19 ` [PATCH v4 4/8] iio: adc: ad7606: Add PWM support for conversion trigger Guillaume Stols
2024-10-09 14:29   ` Nuno Sá [this message]
2024-10-09  9:19 ` [PATCH v4 5/8] iio: adc: ad7606: Add compatibility to fw_nodes Guillaume Stols
2024-10-09 14:39   ` Nuno Sá
2024-10-09 14:53     ` Guillaume Stols
2024-10-09 14:59       ` Nuno Sá
2024-10-09  9:19 ` [PATCH v4 6/8] iio: adc: ad7606: Introduce num_adc_channels Guillaume Stols
2024-10-09 14:40   ` Nuno Sá
2024-10-09  9:19 ` [PATCH v4 7/8] iio: adc: ad7606: Add iio-backend support Guillaume Stols
2024-10-09 14:55   ` Nuno Sá
2024-10-09  9:19 ` [PATCH v4 8/8] iio: adc: ad7606: Disable PWM usage for non backend version Guillaume Stols
2024-10-09 14:45   ` Nuno Sá
2024-10-12 12:48     ` Jonathan Cameron

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=5860310e0413038ac477b9e191c3d15029487628.camel@gmail.com \
    --to=noname.nuno@gmail.com \
    --cc=Jonathan.Cameron@huawei.com \
    --cc=Michael.Hennerich@analog.com \
    --cc=aardelean@baylibre.com \
    --cc=conor+dt@kernel.org \
    --cc=corbet@lwn.net \
    --cc=devicetree@vger.kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=gstols@baylibre.com \
    --cc=jic23@kernel.org \
    --cc=jstephan@baylibre.com \
    --cc=krzk+dt@kernel.org \
    --cc=lars@metafoo.de \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=rafael@kernel.org \
    --cc=robh@kernel.org \
    --cc=ukleinek@kernel.org \
    /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).