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

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
Loading
Loading
Loading
Loading
+62 −18
Original line number Diff line number Diff line
@@ -19,25 +19,45 @@
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_device.h>

#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>

#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_SHORT_IDX		1
#define VZ89X_VOC_TVOC_IDX		2
#define VZ89X_VOC_RESISTANCE_IDX	3

enum {
	VZ89X,
};

struct vz89x_chip_data;

struct vz89x_data {
	struct i2c_client *client;
	const struct vz89x_chip_data *chip;
	struct mutex lock;
	int (*xfer)(struct vz89x_data *data, u8 cmd);

	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[] = {
@@ -93,16 +113,17 @@ static const struct attribute_group vz89x_attrs_group = {
 * 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)
		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)
{
	const struct vz89x_chip_data *chip = data->chip;
	struct i2c_client *client = data->client;
	struct i2c_msg msg[2];
	int ret;
@@ -110,12 +131,12 @@ static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)

	msg[0].addr = client->addr;
	msg[0].flags = client->flags;
	msg[0].len = 3;
	msg[0].len = chip->write_size;
	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].len = chip->read_size;
	msg[1].buf = (char *) &data->buffer;

	ret = i2c_transfer(client->adapter, msg, 2);
@@ -133,7 +154,7 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
	if (ret < 0)
		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);
		if (ret < 0)
			return ret;
@@ -145,17 +166,18 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)

static int vz89x_get_measurement(struct vz89x_data *data)
{
	const struct vz89x_chip_data *chip = data->chip;
	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);
	ret = data->xfer(data, chip->cmd);
	if (ret < 0)
		return ret;

	ret = vz89x_measurement_is_valid(data);
	ret = chip->valid(data);
	if (ret)
		return -EAGAIN;

@@ -232,11 +254,32 @@ static const struct iio_info vz89x_info = {
	.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,
		       const struct i2c_device_id *id)
{
	struct iio_dev *indio_dev;
	struct vz89x_data *data;
	const struct of_device_id *of_id;
	int chip_id;

	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
	if (!indio_dev)
@@ -251,8 +294,15 @@ static int vz89x_probe(struct i2c_client *client,
	else
		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);
	data->client = client;
	data->chip = &vz89x_chips[chip_id];
	data->last_update = jiffies - HZ;
	mutex_init(&data->lock);

@@ -261,24 +311,18 @@ static int vz89x_probe(struct i2c_client *client,
	indio_dev->name = dev_name(&client->dev);
	indio_dev->modes = INDIO_DIRECT_MODE;

	indio_dev->channels = vz89x_channels;
	indio_dev->num_channels = ARRAY_SIZE(vz89x_channels);
	indio_dev->channels = data->chip->channels;
	indio_dev->num_channels = data->chip->num_channels;

	return devm_iio_device_register(&client->dev, indio_dev);
}

static const struct i2c_device_id vz89x_id[] = {
	{ "vz89x", 0 },
	{ "vz89x", VZ89X },
	{ }
};
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 = {
	.driver = {
		.name	= "vz89x",