Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0454bb7b authored by Michael Hennerich's avatar Michael Hennerich Committed by Greg Kroah-Hartman
Browse files

iio: dac: ad5593r: Fix i2c read protocol requirements



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: 56ca9db8 ("iio: dac: Add support for the AD5592R/AD5593R ADCs/DACs")
Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Signed-off-by: default avatarNuno 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: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 069c9992
Loading
Loading
Loading
Loading
+27 −19
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
#include <linux/of.h>
#include <linux/acpi.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)
@@ -22,6 +24,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);
@@ -40,13 +60,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)
@@ -60,25 +74,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;