iio: adc: at91: disable adc channel interrupt in timeout case
commit 09c6bdee51183a575bf7546890c8c137a75a2b44 upstream. Having a brief look at at91_adc_read_raw() it is obvious that in the case of a timeout the setting of AT91_ADC_CHDR and AT91_ADC_IDR registers is omitted. If 2 different channels are queried we can end up with a situation where two interrupts are enabled, but only one interrupt is cleared in the interrupt handler. Resulting in a interrupt loop and a system hang. Signed-off-by: Georg Ottinger <g.ottinger@abatec.at> Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com> Cc: <Stable@vger.kernel.org> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
c69e21be54
commit
07921e3cb1
1 changed files with 17 additions and 11 deletions
|
@ -702,23 +702,29 @@ static int at91_adc_read_raw(struct iio_dev *idev,
|
||||||
ret = wait_event_interruptible_timeout(st->wq_data_avail,
|
ret = wait_event_interruptible_timeout(st->wq_data_avail,
|
||||||
st->done,
|
st->done,
|
||||||
msecs_to_jiffies(1000));
|
msecs_to_jiffies(1000));
|
||||||
if (ret == 0)
|
|
||||||
ret = -ETIMEDOUT;
|
|
||||||
if (ret < 0) {
|
|
||||||
mutex_unlock(&st->lock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
*val = st->last_value;
|
|
||||||
|
|
||||||
|
/* Disable interrupts, regardless if adc conversion was
|
||||||
|
* successful or not
|
||||||
|
*/
|
||||||
at91_adc_writel(st, AT91_ADC_CHDR,
|
at91_adc_writel(st, AT91_ADC_CHDR,
|
||||||
AT91_ADC_CH(chan->channel));
|
AT91_ADC_CH(chan->channel));
|
||||||
at91_adc_writel(st, AT91_ADC_IDR, BIT(chan->channel));
|
at91_adc_writel(st, AT91_ADC_IDR, BIT(chan->channel));
|
||||||
|
|
||||||
st->last_value = 0;
|
if (ret > 0) {
|
||||||
st->done = false;
|
/* a valid conversion took place */
|
||||||
|
*val = st->last_value;
|
||||||
|
st->last_value = 0;
|
||||||
|
st->done = false;
|
||||||
|
ret = IIO_VAL_INT;
|
||||||
|
} else if (ret == 0) {
|
||||||
|
/* conversion timeout */
|
||||||
|
dev_err(&idev->dev, "ADC Channel %d timeout.\n",
|
||||||
|
chan->channel);
|
||||||
|
ret = -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&st->lock);
|
mutex_unlock(&st->lock);
|
||||||
return IIO_VAL_INT;
|
return ret;
|
||||||
|
|
||||||
case IIO_CHAN_INFO_SCALE:
|
case IIO_CHAN_INFO_SCALE:
|
||||||
*val = st->vref_mv;
|
*val = st->vref_mv;
|
||||||
|
|
Loading…
Add table
Reference in a new issue