All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.