From: Andreas Klinger ak@it-klinger.de
commit 4043ecfb5fc4355a090111e14faf7945ff0fdbd5 upstream.
Fix bug in sampling function hx711_cycle() when interrupt occures while PD_SCK is high. If PD_SCK is high for at least 60 us power down mode of the sensor is entered which in turn leads to a wrong measurement.
Switch off interrupts during a PD_SCK high period and move query of DOUT to the latest point of time which is at the end of PD_SCK low period.
This bug exists in the driver since it's initial addition. The more interrupts on the system the higher is the probability that it happens.
Fixes: c3b2fdd0ea7e ("iio: adc: hx711: Add IIO driver for AVIA HX711") Signed-off-by: Andreas Klinger ak@it-klinger.de Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron Jonathan.Cameron@huawei.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/iio/adc/hx711.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
--- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -109,14 +109,14 @@ struct hx711_data {
static int hx711_cycle(struct hx711_data *hx711_data) { - int val; + unsigned long flags;
/* * if preempted for more then 60us while PD_SCK is high: * hx711 is going in reset * ==> measuring is false */ - preempt_disable(); + local_irq_save(flags); gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
/* @@ -126,7 +126,6 @@ static int hx711_cycle(struct hx711_data */ ndelay(hx711_data->data_ready_delay_ns);
- val = gpiod_get_value(hx711_data->gpiod_dout); /* * here we are not waiting for 0.2 us as suggested by the datasheet, * because the oscilloscope showed in a test scenario @@ -134,7 +133,7 @@ static int hx711_cycle(struct hx711_data * and 0.56 us for PD_SCK low on TI Sitara with 800 MHz */ gpiod_set_value(hx711_data->gpiod_pd_sck, 0); - preempt_enable(); + local_irq_restore(flags);
/* * make it a square wave for addressing cases with capacitance on @@ -142,7 +141,8 @@ static int hx711_cycle(struct hx711_data */ ndelay(hx711_data->data_ready_delay_ns);
- return val; + /* sample as late as possible */ + return gpiod_get_value(hx711_data->gpiod_dout); }
static int hx711_read(struct hx711_data *hx711_data)