iio: adc: at91: disable adc channel interrupt in timeout case
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>
This commit is contained in:

committed by
Jonathan Cameron

parent
409a51e0a4
commit
09c6bdee51
@@ -704,23 +704,29 @@ static int at91_adc_read_raw(struct iio_dev *idev,
|
||||
ret = wait_event_interruptible_timeout(st->wq_data_avail,
|
||||
st->done,
|
||||
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_CH(chan->channel));
|
||||
at91_adc_writel(st, AT91_ADC_IDR, BIT(chan->channel));
|
||||
|
||||
st->last_value = 0;
|
||||
st->done = false;
|
||||
if (ret > 0) {
|
||||
/* 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);
|
||||
return IIO_VAL_INT;
|
||||
return ret;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = st->vref_mv;
|
||||
|
Reference in New Issue
Block a user