iio: dac: ad5593r: Fix i2c read protocol requirements
authorMichael Hennerich <michael.hennerich@analog.com>
Tue, 13 Sep 2022 07:34:12 +0000 (09:34 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Oct 2022 10:34:19 +0000 (12:34 +0200)
commit 558a25f903b4af6361b7fbeea08a6446a0745653 upstream.

For reliable operation across the full range of supported
interface rates, the AD5593R needs a STOP condition between
address write, and data read (like show in the datasheet Figure 40)
so in turn i2c_smbus_read_word_swapped cannot be used.

While at it, a simple helper was added to make the code simpler.

Fixes: 56ca9db862bf ("iio: dac: Add support for the AD5592R/AD5593R ADCs/DACs")
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
Cc: <Stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20220913073413.140475-2-nuno.sa@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/iio/dac/ad5593r.c

index 5b4df36..4cc855c 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 
+#include <asm/unaligned.h>
+
 #define AD5593R_MODE_CONF              (0 << 4)
 #define AD5593R_MODE_DAC_WRITE         (1 << 4)
 #define AD5593R_MODE_ADC_READBACK      (4 << 4)
 #define AD5593R_MODE_GPIO_READBACK     (6 << 4)
 #define AD5593R_MODE_REG_READBACK      (7 << 4)
 
+static int ad5593r_read_word(struct i2c_client *i2c, u8 reg, u16 *value)
+{
+       int ret;
+       u8 buf[2];
+
+       ret = i2c_smbus_write_byte(i2c, reg);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_master_recv(i2c, buf, sizeof(buf));
+       if (ret < 0)
+               return ret;
+
+       *value = get_unaligned_be16(buf);
+
+       return 0;
+}
+
 static int ad5593r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
 {
        struct i2c_client *i2c = to_i2c_client(st->dev);
@@ -38,13 +58,7 @@ static int ad5593r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value)
        if (val < 0)
                return (int) val;
 
-       val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_ADC_READBACK);
-       if (val < 0)
-               return (int) val;
-
-       *value = (u16) val;
-
-       return 0;
+       return ad5593r_read_word(i2c, AD5593R_MODE_ADC_READBACK, value);
 }
 
 static int ad5593r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
@@ -58,25 +72,19 @@ static int ad5593r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
 static int ad5593r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
 {
        struct i2c_client *i2c = to_i2c_client(st->dev);
-       s32 val;
-
-       val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_REG_READBACK | reg);
-       if (val < 0)
-               return (int) val;
 
-       *value = (u16) val;
-
-       return 0;
+       return ad5593r_read_word(i2c, AD5593R_MODE_REG_READBACK | reg, value);
 }
 
 static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
 {
        struct i2c_client *i2c = to_i2c_client(st->dev);
-       s32 val;
+       u16 val;
+       int ret;
 
-       val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_GPIO_READBACK);
-       if (val < 0)
-               return (int) val;
+       ret = ad5593r_read_word(i2c, AD5593R_MODE_GPIO_READBACK, &val);
+       if (ret)
+               return ret;
 
        *value = (u8) val;