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

Commit 93e87d73 authored by Matt Ranostay's avatar Matt Ranostay Committed by Jonathan Cameron
Browse files

iio: chemical: vz89x: rework i2c transfer reading



Add an optimized i2c transfer reading function, and fallback
to racey smbus transfers if client->adapter doesn't support this.

Signed-off-by: default avatarMatt Ranostay <mranostay@gmail.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 4c3e2a40
Loading
Loading
Loading
Loading
+52 −14
Original line number Diff line number Diff line
@@ -34,8 +34,9 @@
struct vz89x_data {
	struct i2c_client *client;
	struct mutex lock;
	unsigned long last_update;
	int (*xfer)(struct vz89x_data *data, u8 cmd);

	unsigned long last_update;
	u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
};

@@ -100,27 +101,60 @@ static int vz89x_measurement_is_valid(struct vz89x_data *data)
	return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
}

static int vz89x_get_measurement(struct vz89x_data *data)
static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
{
	struct i2c_client *client = data->client;
	struct i2c_msg msg[2];
	int ret;
	int i;
	u8 buf[3] = { cmd, 0, 0};

	/* sensor can only be polled once a second max per datasheet */
	if (!time_after(jiffies, data->last_update + HZ))
		return 0;
	msg[0].addr = client->addr;
	msg[0].flags = client->flags;
	msg[0].len = 3;
	msg[0].buf  = (char *) &buf;

	msg[1].addr = client->addr;
	msg[1].flags = client->flags | I2C_M_RD;
	msg[1].len = VZ89X_REG_MEASUREMENT_SIZE;
	msg[1].buf = (char *) &data->buffer;

	ret = i2c_transfer(client->adapter, msg, 2);

	ret = i2c_smbus_write_word_data(data->client,
					VZ89X_REG_MEASUREMENT, 0);
	return (ret == 2) ? 0 : ret;
}

static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
{
	struct i2c_client *client = data->client;
	int ret;
	int i;

	ret = i2c_smbus_write_word_data(client, cmd, 0);
	if (ret < 0)
		return ret;

	for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
		ret = i2c_smbus_read_byte(data->client);
		ret = i2c_smbus_read_byte(client);
		if (ret < 0)
			return ret;
		data->buffer[i] = ret;
	}

	return 0;
}

static int vz89x_get_measurement(struct vz89x_data *data)
{
	int ret;

	/* sensor can only be polled once a second max per datasheet */
	if (!time_after(jiffies, data->last_update + HZ))
		return 0;

	ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
	if (ret < 0)
		return ret;

	ret = vz89x_measurement_is_valid(data);
	if (ret)
		return -EAGAIN;
@@ -204,15 +238,19 @@ static int vz89x_probe(struct i2c_client *client,
	struct iio_dev *indio_dev;
	struct vz89x_data *data;

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
				     I2C_FUNC_SMBUS_BYTE))
		return -ENODEV;

	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
	if (!indio_dev)
		return -ENOMEM;

	data = iio_priv(indio_dev);

	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
		data->xfer = vz89x_i2c_xfer;
	else if (i2c_check_functionality(client->adapter,
				I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
		data->xfer = vz89x_smbus_xfer;
	else
		return -ENOTSUPP;

	i2c_set_clientdata(client, indio_dev);
	data->client = client;
	data->last_update = jiffies - HZ;