Commit 8376882f authored by Matt Ranostay's avatar Matt Ranostay Committed by Jonathan Cameron

iio: chemical: vz89x: abstract chip configuration

Abstract chip configuration data to allow supporting multiple variants
of the VZ89 chemical sensor line.
Signed-off-by: default avatarMatt Ranostay <mranostay@gmail.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 8c9e7b1b
...@@ -19,25 +19,45 @@ ...@@ -19,25 +19,45 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#define VZ89X_REG_MEASUREMENT 0x09 #define VZ89X_REG_MEASUREMENT 0x09
#define VZ89X_REG_MEASUREMENT_SIZE 6 #define VZ89X_REG_MEASUREMENT_RD_SIZE 6
#define VZ89X_REG_MEASUREMENT_WR_SIZE 3
#define VZ89X_VOC_CO2_IDX 0 #define VZ89X_VOC_CO2_IDX 0
#define VZ89X_VOC_SHORT_IDX 1 #define VZ89X_VOC_SHORT_IDX 1
#define VZ89X_VOC_TVOC_IDX 2 #define VZ89X_VOC_TVOC_IDX 2
#define VZ89X_VOC_RESISTANCE_IDX 3 #define VZ89X_VOC_RESISTANCE_IDX 3
enum {
VZ89X,
};
struct vz89x_chip_data;
struct vz89x_data { struct vz89x_data {
struct i2c_client *client; struct i2c_client *client;
const struct vz89x_chip_data *chip;
struct mutex lock; struct mutex lock;
int (*xfer)(struct vz89x_data *data, u8 cmd); int (*xfer)(struct vz89x_data *data, u8 cmd);
unsigned long last_update; unsigned long last_update;
u8 buffer[VZ89X_REG_MEASUREMENT_SIZE]; u8 buffer[VZ89X_REG_MEASUREMENT_RD_SIZE];
};
struct vz89x_chip_data {
bool (*valid)(struct vz89x_data *data);
const struct iio_chan_spec *channels;
u8 num_channels;
u8 cmd;
u8 read_size;
u8 write_size;
}; };
static const struct iio_chan_spec vz89x_channels[] = { static const struct iio_chan_spec vz89x_channels[] = {
...@@ -93,16 +113,17 @@ static const struct attribute_group vz89x_attrs_group = { ...@@ -93,16 +113,17 @@ static const struct attribute_group vz89x_attrs_group = {
* always zero, and by also confirming the VOC_short isn't zero. * always zero, and by also confirming the VOC_short isn't zero.
*/ */
static int vz89x_measurement_is_valid(struct vz89x_data *data) static bool vz89x_measurement_is_valid(struct vz89x_data *data)
{ {
if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0) if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0)
return 1; return 1;
return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0); return !!(data->buffer[data->chip->read_size - 1] > 0);
} }
static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd) static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
{ {
const struct vz89x_chip_data *chip = data->chip;
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
struct i2c_msg msg[2]; struct i2c_msg msg[2];
int ret; int ret;
...@@ -110,12 +131,12 @@ static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd) ...@@ -110,12 +131,12 @@ static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
msg[0].addr = client->addr; msg[0].addr = client->addr;
msg[0].flags = client->flags; msg[0].flags = client->flags;
msg[0].len = 3; msg[0].len = chip->write_size;
msg[0].buf = (char *) &buf; msg[0].buf = (char *) &buf;
msg[1].addr = client->addr; msg[1].addr = client->addr;
msg[1].flags = client->flags | I2C_M_RD; msg[1].flags = client->flags | I2C_M_RD;
msg[1].len = VZ89X_REG_MEASUREMENT_SIZE; msg[1].len = chip->read_size;
msg[1].buf = (char *) &data->buffer; msg[1].buf = (char *) &data->buffer;
ret = i2c_transfer(client->adapter, msg, 2); ret = i2c_transfer(client->adapter, msg, 2);
...@@ -133,7 +154,7 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd) ...@@ -133,7 +154,7 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
if (ret < 0) if (ret < 0)
return ret; return ret;
for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) { for (i = 0; i < data->chip->read_size; i++) {
ret = i2c_smbus_read_byte(client); ret = i2c_smbus_read_byte(client);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -145,17 +166,18 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd) ...@@ -145,17 +166,18 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
static int vz89x_get_measurement(struct vz89x_data *data) static int vz89x_get_measurement(struct vz89x_data *data)
{ {
const struct vz89x_chip_data *chip = data->chip;
int ret; int ret;
/* sensor can only be polled once a second max per datasheet */ /* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ)) if (!time_after(jiffies, data->last_update + HZ))
return 0; return 0;
ret = data->xfer(data, VZ89X_REG_MEASUREMENT); ret = data->xfer(data, chip->cmd);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = vz89x_measurement_is_valid(data); ret = chip->valid(data);
if (ret) if (ret)
return -EAGAIN; return -EAGAIN;
...@@ -232,11 +254,32 @@ static const struct iio_info vz89x_info = { ...@@ -232,11 +254,32 @@ static const struct iio_info vz89x_info = {
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static const struct vz89x_chip_data vz89x_chips[] = {
{
.valid = vz89x_measurement_is_valid,
.cmd = VZ89X_REG_MEASUREMENT,
.read_size = VZ89X_REG_MEASUREMENT_RD_SIZE,
.write_size = VZ89X_REG_MEASUREMENT_WR_SIZE,
.channels = vz89x_channels,
.num_channels = ARRAY_SIZE(vz89x_channels),
},
};
static const struct of_device_id vz89x_dt_ids[] = {
{ .compatible = "sgx,vz89x", .data = (void *) VZ89X },
{ }
};
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
static int vz89x_probe(struct i2c_client *client, static int vz89x_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
struct vz89x_data *data; struct vz89x_data *data;
const struct of_device_id *of_id;
int chip_id;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) if (!indio_dev)
...@@ -251,8 +294,15 @@ static int vz89x_probe(struct i2c_client *client, ...@@ -251,8 +294,15 @@ static int vz89x_probe(struct i2c_client *client,
else else
return -EOPNOTSUPP; return -EOPNOTSUPP;
of_id = of_match_device(vz89x_dt_ids, &client->dev);
if (!of_id)
chip_id = id->driver_data;
else
chip_id = (unsigned long)of_id->data;
i2c_set_clientdata(client, indio_dev); i2c_set_clientdata(client, indio_dev);
data->client = client; data->client = client;
data->chip = &vz89x_chips[chip_id];
data->last_update = jiffies - HZ; data->last_update = jiffies - HZ;
mutex_init(&data->lock); mutex_init(&data->lock);
...@@ -261,24 +311,18 @@ static int vz89x_probe(struct i2c_client *client, ...@@ -261,24 +311,18 @@ static int vz89x_probe(struct i2c_client *client,
indio_dev->name = dev_name(&client->dev); indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vz89x_channels; indio_dev->channels = data->chip->channels;
indio_dev->num_channels = ARRAY_SIZE(vz89x_channels); indio_dev->num_channels = data->chip->num_channels;
return devm_iio_device_register(&client->dev, indio_dev); return devm_iio_device_register(&client->dev, indio_dev);
} }
static const struct i2c_device_id vz89x_id[] = { static const struct i2c_device_id vz89x_id[] = {
{ "vz89x", 0 }, { "vz89x", VZ89X },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, vz89x_id); MODULE_DEVICE_TABLE(i2c, vz89x_id);
static const struct of_device_id vz89x_dt_ids[] = {
{ .compatible = "sgx,vz89x" },
{ }
};
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
static struct i2c_driver vz89x_driver = { static struct i2c_driver vz89x_driver = {
.driver = { .driver = {
.name = "vz89x", .name = "vz89x",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment