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: Matt Ranostay <mranostay@gmail.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
committed by
Jonathan Cameron
parent
4c3e2a4036
commit
93e87d73cc
@ -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_i2c_xfer(struct vz89x_data *data, u8 cmd)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
struct i2c_msg msg[2];
|
||||
int ret;
|
||||
u8 buf[3] = { cmd, 0, 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);
|
||||
|
||||
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(client);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->buffer[i] = ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vz89x_get_measurement(struct vz89x_data *data)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* sensor can only be polled once a second max per datasheet */
|
||||
if (!time_after(jiffies, data->last_update + HZ))
|
||||
return 0;
|
||||
|
||||
ret = i2c_smbus_write_word_data(data->client,
|
||||
VZ89X_REG_MEASUREMENT, 0);
|
||||
ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
|
||||
ret = i2c_smbus_read_byte(data->client);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->buffer[i] = 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;
|
||||
|
Reference in New Issue
Block a user