linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] iio: adc: ad7768-1: disable IRQ autoenable
@ 2025-07-18  1:33 Jonathan Santos
  2025-07-18  9:18 ` Nuno Sá
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Santos @ 2025-07-18  1:33 UTC (permalink / raw)
  To: linux-iio, linux-kernel
  Cc: Jonathan Santos, lars, Michael.Hennerich, jic23, dlechner,
	nuno.sa, andy, jonath4nns

The device continuously converts data while powered up, generating
interrupts in the background. Configure the IRQ to be enabled and
disabled manually as needed to avoid unnecessary CPU load.

Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
 drivers/iio/adc/ad7768-1.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index a2e061f0cb08..3eea03c004c3 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -395,8 +395,10 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
 	if (ret < 0)
 		return ret;
 
+	enable_irq(st->spi->irq);
 	ret = wait_for_completion_timeout(&st->completion,
 					  msecs_to_jiffies(1000));
+	disable_irq(st->spi->irq);
 	if (!ret)
 		return -ETIMEDOUT;
 
@@ -1130,7 +1132,21 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
 	.predisable = &ad7768_buffer_predisable,
 };
 
+static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct ad7768_state *st = iio_priv(indio_dev);
+
+	if (enable)
+		enable_irq(st->spi->irq);
+	else
+		disable_irq(st->spi->irq);
+
+	return 0;
+}
+
 static const struct iio_trigger_ops ad7768_trigger_ops = {
+	.set_trigger_state = ad7768_set_trigger_state,
 	.validate_device = iio_trigger_validate_own_device,
 };
 
@@ -1417,7 +1433,7 @@ static int ad7768_probe(struct spi_device *spi)
 
 	ret = devm_request_irq(&spi->dev, spi->irq,
 			       &ad7768_interrupt,
-			       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			       IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
 			       indio_dev->name, indio_dev);
 	if (ret)
 		return ret;

base-commit: 0a686b9c4f847dc21346df8e56d5b119918fefef
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] iio: adc: ad7768-1: disable IRQ autoenable
  2025-07-18  1:33 [PATCH] iio: adc: ad7768-1: disable IRQ autoenable Jonathan Santos
@ 2025-07-18  9:18 ` Nuno Sá
  2025-07-19 12:08   ` Jonathan Cameron
  0 siblings, 1 reply; 5+ messages in thread
From: Nuno Sá @ 2025-07-18  9:18 UTC (permalink / raw)
  To: Jonathan Santos
  Cc: linux-iio, linux-kernel, lars, Michael.Hennerich, jic23, dlechner,
	nuno.sa, andy, jonath4nns

On Thu, Jul 17, 2025 at 10:33:07PM -0300, Jonathan Santos wrote:
> The device continuously converts data while powered up, generating
> interrupts in the background. Configure the IRQ to be enabled and
> disabled manually as needed to avoid unnecessary CPU load.
> 
> Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> ---

LGTM,

Reviewed-by: Nuno Sá <nuno.sa@analog.com>

>  drivers/iio/adc/ad7768-1.c | 18 +++++++++++++++++-
>  1 file changed, 17 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
> index a2e061f0cb08..3eea03c004c3 100644
> --- a/drivers/iio/adc/ad7768-1.c
> +++ b/drivers/iio/adc/ad7768-1.c
> @@ -395,8 +395,10 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
>  	if (ret < 0)
>  		return ret;
>  
> +	enable_irq(st->spi->irq);
>  	ret = wait_for_completion_timeout(&st->completion,
>  					  msecs_to_jiffies(1000));
> +	disable_irq(st->spi->irq);
>  	if (!ret)
>  		return -ETIMEDOUT;
>  
> @@ -1130,7 +1132,21 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
>  	.predisable = &ad7768_buffer_predisable,
>  };
>  
> +static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable)
> +{
> +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> +	struct ad7768_state *st = iio_priv(indio_dev);
> +
> +	if (enable)
> +		enable_irq(st->spi->irq);
> +	else
> +		disable_irq(st->spi->irq);
> +
> +	return 0;
> +}
> +
>  static const struct iio_trigger_ops ad7768_trigger_ops = {
> +	.set_trigger_state = ad7768_set_trigger_state,
>  	.validate_device = iio_trigger_validate_own_device,
>  };
>  
> @@ -1417,7 +1433,7 @@ static int ad7768_probe(struct spi_device *spi)
>  
>  	ret = devm_request_irq(&spi->dev, spi->irq,
>  			       &ad7768_interrupt,
> -			       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +			       IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
>  			       indio_dev->name, indio_dev);
>  	if (ret)
>  		return ret;
> 
> base-commit: 0a686b9c4f847dc21346df8e56d5b119918fefef
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] iio: adc: ad7768-1: disable IRQ autoenable
  2025-07-18  9:18 ` Nuno Sá
@ 2025-07-19 12:08   ` Jonathan Cameron
  2025-07-25 20:01     ` Jonathan Santos
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Cameron @ 2025-07-19 12:08 UTC (permalink / raw)
  To: Nuno Sá
  Cc: Jonathan Santos, linux-iio, linux-kernel, lars, Michael.Hennerich,
	dlechner, nuno.sa, andy, jonath4nns

On Fri, 18 Jul 2025 10:18:56 +0100
Nuno Sá <noname.nuno@gmail.com> wrote:

> On Thu, Jul 17, 2025 at 10:33:07PM -0300, Jonathan Santos wrote:
> > The device continuously converts data while powered up, generating
> > interrupts in the background. Configure the IRQ to be enabled and
> > disabled manually as needed to avoid unnecessary CPU load.

This generates interrupts continuously even when in oneshot mode?

> > 
> > Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> > ---  
> 
> LGTM,
> 
> Reviewed-by: Nuno Sá <nuno.sa@analog.com>
> 
> >  drivers/iio/adc/ad7768-1.c | 18 +++++++++++++++++-
> >  1 file changed, 17 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
> > index a2e061f0cb08..3eea03c004c3 100644
> > --- a/drivers/iio/adc/ad7768-1.c
> > +++ b/drivers/iio/adc/ad7768-1.c
> > @@ -395,8 +395,10 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
> >  	if (ret < 0)
> >  		return ret;
> >  
> > +	enable_irq(st->spi->irq);

Looks racey to me in a number of ways.

Before this patch:
In continuous mode, reinit_completion called then interrupt before we enter
 oneshot mode. What was captured? 

After this patch
Oneshot mode starts - hardware interrupt happens but enable_irq() is not set
so we miss it - or do we get another pulse later?

I'm not sure how to solve this as a device generating a stream of garbage
interrupts is near impossible to deal with.

I'm not following the datasheet description of this features vs the code 
though. It refers to oneshot mode requiring a pulse on sync in which I can't
find.

> >  	ret = wait_for_completion_timeout(&st->completion,
> >  					  msecs_to_jiffies(1000));
> > +	disable_irq(st->spi->irq);
> >  	if (!ret)
> >  		return -ETIMEDOUT;
> >  
> > @@ -1130,7 +1132,21 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
> >  	.predisable = &ad7768_buffer_predisable,
> >  };
> >  
> > +static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable)
> > +{
> > +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> > +	struct ad7768_state *st = iio_priv(indio_dev);
> > +
> > +	if (enable)
> > +		enable_irq(st->spi->irq);
> > +	else
> > +		disable_irq(st->spi->irq);
> > +
> > +	return 0;
> > +}
> > +
> >  static const struct iio_trigger_ops ad7768_trigger_ops = {
> > +	.set_trigger_state = ad7768_set_trigger_state,
> >  	.validate_device = iio_trigger_validate_own_device,
> >  };
> >  
> > @@ -1417,7 +1433,7 @@ static int ad7768_probe(struct spi_device *spi)
> >  
> >  	ret = devm_request_irq(&spi->dev, spi->irq,
> >  			       &ad7768_interrupt,
> > -			       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> > +			       IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,

Why drop oneshot?

> >  			       indio_dev->name, indio_dev);
> >  	if (ret)
> >  		return ret;
> > 
> > base-commit: 0a686b9c4f847dc21346df8e56d5b119918fefef
> > -- 
> > 2.34.1
> >   
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] iio: adc: ad7768-1: disable IRQ autoenable
  2025-07-19 12:08   ` Jonathan Cameron
@ 2025-07-25 20:01     ` Jonathan Santos
  2025-07-27 15:38       ` Jonathan Cameron
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Santos @ 2025-07-25 20:01 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Nuno Sá, Jonathan Santos, linux-iio, linux-kernel, lars,
	Michael.Hennerich, dlechner, nuno.sa, andy

On 07/19, Jonathan Cameron wrote:
> On Fri, 18 Jul 2025 10:18:56 +0100
> Nuno Sá <noname.nuno@gmail.com> wrote:
> 
> > On Thu, Jul 17, 2025 at 10:33:07PM -0300, Jonathan Santos wrote:
> > > The device continuously converts data while powered up, generating
> > > interrupts in the background. Configure the IRQ to be enabled and
> > > disabled manually as needed to avoid unnecessary CPU load.
> 
> This generates interrupts continuously even when in oneshot mode?
> 

No, but oneshot mode is only enabled for a brief moment when reading the raw data. The rest of the time it stays in continuous conversion mode because datasheet says it is necessary to make configuration changes.

> > > 
> > > Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> > > ---  
> > 
> > LGTM,
> > 
> > Reviewed-by: Nuno Sá <nuno.sa@analog.com>
> > 
> > >  drivers/iio/adc/ad7768-1.c | 18 +++++++++++++++++-
> > >  1 file changed, 17 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
> > > index a2e061f0cb08..3eea03c004c3 100644
> > > --- a/drivers/iio/adc/ad7768-1.c
> > > +++ b/drivers/iio/adc/ad7768-1.c
> > > @@ -395,8 +395,10 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
> > >  	if (ret < 0)
> > >  		return ret;
> > >  
> > > +	enable_irq(st->spi->irq);
> 
> Looks racey to me in a number of ways.
> 
> Before this patch:
> In continuous mode, reinit_completion called then interrupt before we enter
>  oneshot mode. What was captured? 
> 
> After this patch
> Oneshot mode starts - hardware interrupt happens but enable_irq() is not set
> so we miss it - or do we get another pulse later?
> 

After some debugging, i think the device gets the last interrupt before
getting into oneshot mode because I don't see any DRDY later. it should have a sync_in pulse after to
update the data value, as you said.

> I'm not sure how to solve this as a device generating a stream of garbage
> interrupts is near impossible to deal with.
> 
> I'm not following the datasheet description of this features vs the code 
> though. It refers to oneshot mode requiring a pulse on sync in which I can't
> find.
> 

If we made something like this wouldn't sufice?

...
	reinit_completion(&st->completion);

	ret = ad7768_set_mode(st, AD7768_ONE_SHOT);
	if (ret < 0)
		return ret;

	enable_irq(st->spi->irq);
	ad7768_send_sync_pulse(st);

	ret = wait_for_completion_timeout(&st->completion,
					  msecs_to_jiffies(1000));
	disable_irq(st->spi->irq);
	if (!ret)
		return -ETIMEDOUT;
...


> > >  	ret = wait_for_completion_timeout(&st->completion,
> > >  					  msecs_to_jiffies(1000));
> > > +	disable_irq(st->spi->irq);
> > >  	if (!ret)
> > >  		return -ETIMEDOUT;
> > >  
> > > @@ -1130,7 +1132,21 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
> > >  	.predisable = &ad7768_buffer_predisable,
> > >  };
> > >  
> > > +static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable)
> > > +{
> > > +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> > > +	struct ad7768_state *st = iio_priv(indio_dev);
> > > +
> > > +	if (enable)
> > > +		enable_irq(st->spi->irq);
> > > +	else
> > > +		disable_irq(st->spi->irq);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  static const struct iio_trigger_ops ad7768_trigger_ops = {
> > > +	.set_trigger_state = ad7768_set_trigger_state,
> > >  	.validate_device = iio_trigger_validate_own_device,
> > >  };
> > >  
> > > @@ -1417,7 +1433,7 @@ static int ad7768_probe(struct spi_device *spi)
> > >  
> > >  	ret = devm_request_irq(&spi->dev, spi->irq,
> > >  			       &ad7768_interrupt,
> > > -			       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> > > +			       IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
> 
> Why drop oneshot?
> 
> > >  			       indio_dev->name, indio_dev);
> > >  	if (ret)
> > >  		return ret;
> > > 
> > > base-commit: 0a686b9c4f847dc21346df8e56d5b119918fefef
> > > -- 
> > > 2.34.1
> > >   
> > 
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] iio: adc: ad7768-1: disable IRQ autoenable
  2025-07-25 20:01     ` Jonathan Santos
@ 2025-07-27 15:38       ` Jonathan Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Cameron @ 2025-07-27 15:38 UTC (permalink / raw)
  To: Jonathan Santos
  Cc: 20250719130844.7559e322, Nuno Sá, Jonathan Santos, linux-iio,
	linux-kernel, lars, Michael.Hennerich, dlechner, nuno.sa, andy,
	Uwe Kleine-König

On Fri, 25 Jul 2025 17:01:24 -0300
Jonathan Santos <jonath4nns@gmail.com> wrote:

> On 07/19, Jonathan Cameron wrote:
> > On Fri, 18 Jul 2025 10:18:56 +0100
> > Nuno Sá <noname.nuno@gmail.com> wrote:
> >   
> > > On Thu, Jul 17, 2025 at 10:33:07PM -0300, Jonathan Santos wrote:  
> > > > The device continuously converts data while powered up, generating
> > > > interrupts in the background. Configure the IRQ to be enabled and
> > > > disabled manually as needed to avoid unnecessary CPU load.  
> > 
> > This generates interrupts continuously even when in oneshot mode?
> >   
> 
> No, but oneshot mode is only enabled for a brief moment when reading the raw data. The rest of the time it stays in continuous conversion mode because datasheet says it is necessary to make configuration changes.

Hmm.  So if we want to suppress interrupts we would need to switch out of 
continuous mode.  That might be helpful, though with the sync in pulse
in the mix we might not need it.  There are complications though.

> 
> > > > 
> > > > Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> > > > ---    
> > > 
> > > LGTM,
> > > 
> > > Reviewed-by: Nuno Sá <nuno.sa@analog.com>
> > >   
> > > >  drivers/iio/adc/ad7768-1.c | 18 +++++++++++++++++-
> > > >  1 file changed, 17 insertions(+), 1 deletion(-)
> > > > 
> > > > diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
> > > > index a2e061f0cb08..3eea03c004c3 100644
> > > > --- a/drivers/iio/adc/ad7768-1.c
> > > > +++ b/drivers/iio/adc/ad7768-1.c
> > > > @@ -395,8 +395,10 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
> > > >  	if (ret < 0)
> > > >  		return ret;
> > > >  
> > > > +	enable_irq(st->spi->irq);  
> > 
> > Looks racey to me in a number of ways.
> > 
> > Before this patch:
> > In continuous mode, reinit_completion called then interrupt before we enter
> >  oneshot mode. What was captured? 
> > 
> > After this patch
> > Oneshot mode starts - hardware interrupt happens but enable_irq() is not set
> > so we miss it - or do we get another pulse later?
> >   
> 
> After some debugging, i think the device gets the last interrupt before
> getting into oneshot mode because I don't see any DRDY later. it should have a sync_in pulse after to
> update the data value, as you said.
> 
> > I'm not sure how to solve this as a device generating a stream of garbage
> > interrupts is near impossible to deal with.
> > 
> > I'm not following the datasheet description of this features vs the code 
> > though. It refers to oneshot mode requiring a pulse on sync in which I can't
> > find.
> >   
> 
> If we made something like this wouldn't sufice?

Yes. I think that looks fine but it is relying on particular behavior
of the interrupt controller.

> 
> ...
> 	reinit_completion(&st->completion);
> 
> 	ret = ad7768_set_mode(st, AD7768_ONE_SHOT);
> 	if (ret < 0)
> 		return ret;
> 
> 	enable_irq(st->spi->irq);

In some interrupt controllers, IIRC interrupts are annoyingly queued
when disable_irq() has been called, so when you next enable_irq() you
may immediately get one. If it happens, should happen very fast though
I'm not 100% sure it will happen before we return to here which makes
dealing with that race hard.

Do we have a way to check the interrupt was due to the sync pulse?
If not maybe we need a flag that we set here - but that will race
with a slow response to a previously queued interrupt. Maybe that case
doesn't actually exist though - I'm not sure we got that far with
analysizing the guarantees. 

+CC Uwe who I think was dealing with this a while back with the
ad_sigma_delta library and might remember it a clearer than me.

https://lore.kernel.org/all/io53lznz3qp3jd5rohqsjhosnmdzd6d44sdbwu5jcfrs3rz2a2@orquwgflrtyc/
was the main thread in which Thomas Gleixner replied.

Jonathan


> 	ad7768_send_sync_pulse(st);
> 
> 	ret = wait_for_completion_timeout(&st->completion,
> 					  msecs_to_jiffies(1000));
> 	disable_irq(st->spi->irq);
> 	if (!ret)
> 		return -ETIMEDOUT;
> ...
> 
> 
> > > >  	ret = wait_for_completion_timeout(&st->completion,
> > > >  					  msecs_to_jiffies(1000));
> > > > +	disable_irq(st->spi->irq);
> > > >  	if (!ret)
> > > >  		return -ETIMEDOUT;
> > > >  
> > > > @@ -1130,7 +1132,21 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
> > > >  	.predisable = &ad7768_buffer_predisable,
> > > >  };
> > > >  
> > > > +static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable)
> > > > +{
> > > > +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> > > > +	struct ad7768_state *st = iio_priv(indio_dev);
> > > > +
> > > > +	if (enable)
> > > > +		enable_irq(st->spi->irq);
> > > > +	else
> > > > +		disable_irq(st->spi->irq);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > >  static const struct iio_trigger_ops ad7768_trigger_ops = {
> > > > +	.set_trigger_state = ad7768_set_trigger_state,
> > > >  	.validate_device = iio_trigger_validate_own_device,
> > > >  };
> > > >  
> > > > @@ -1417,7 +1433,7 @@ static int ad7768_probe(struct spi_device *spi)
> > > >  
> > > >  	ret = devm_request_irq(&spi->dev, spi->irq,
> > > >  			       &ad7768_interrupt,
> > > > -			       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> > > > +			       IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,  
> > 
> > Why drop oneshot?
> >   
> > > >  			       indio_dev->name, indio_dev);
> > > >  	if (ret)
> > > >  		return ret;
> > > > 
> > > > base-commit: 0a686b9c4f847dc21346df8e56d5b119918fefef
> > > > -- 
> > > > 2.34.1
> > > >     
> > >   
> >   
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-07-27 15:38 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-18  1:33 [PATCH] iio: adc: ad7768-1: disable IRQ autoenable Jonathan Santos
2025-07-18  9:18 ` Nuno Sá
2025-07-19 12:08   ` Jonathan Cameron
2025-07-25 20:01     ` Jonathan Santos
2025-07-27 15:38       ` Jonathan Cameron

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).