| From 558a25f903b4af6361b7fbeea08a6446a0745653 Mon Sep 17 00:00:00 2001 |
| From: Michael Hennerich <michael.hennerich@analog.com> |
| Date: Tue, 13 Sep 2022 09:34:12 +0200 |
| Subject: iio: dac: ad5593r: Fix i2c read protocol requirements |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Michael Hennerich <michael.hennerich@analog.com> |
| |
| 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 | 46 +++++++++++++++++++++++++++------------------- |
| 1 file changed, 27 insertions(+), 19 deletions(-) |
| |
| --- a/drivers/iio/dac/ad5593r.c |
| +++ b/drivers/iio/dac/ad5593r.c |
| @@ -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) |
| @@ -20,6 +22,24 @@ |
| #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 ad559 |
| 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 ad55 |
| 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; |
| |