diff options
Diffstat (limited to 'drivers/iio/chemical')
-rw-r--r-- | drivers/iio/chemical/Kconfig | 1 | ||||
-rw-r--r-- | drivers/iio/chemical/atlas-ph-sensor.c | 81 | ||||
-rw-r--r-- | drivers/iio/chemical/vz89x.c | 201 |
3 files changed, 224 insertions, 59 deletions
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index 4bcc025e8c8a..cea7f9857a1f 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig | |||
@@ -16,6 +16,7 @@ config ATLAS_PH_SENSOR | |||
16 | Atlas Scientific OEM SM sensors: | 16 | Atlas Scientific OEM SM sensors: |
17 | * pH SM sensor | 17 | * pH SM sensor |
18 | * EC SM sensor | 18 | * EC SM sensor |
19 | * ORP SM sensor | ||
19 | 20 | ||
20 | To compile this driver as module, choose M here: the | 21 | To compile this driver as module, choose M here: the |
21 | module will be called atlas-ph-sensor. | 22 | module will be called atlas-ph-sensor. |
diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index 407f141a1eee..bd321b305a0a 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c | |||
@@ -66,12 +66,17 @@ | |||
66 | #define ATLAS_REG_TDS_DATA 0x1c | 66 | #define ATLAS_REG_TDS_DATA 0x1c |
67 | #define ATLAS_REG_PSS_DATA 0x20 | 67 | #define ATLAS_REG_PSS_DATA 0x20 |
68 | 68 | ||
69 | #define ATLAS_REG_ORP_CALIB_STATUS 0x0d | ||
70 | #define ATLAS_REG_ORP_DATA 0x0e | ||
71 | |||
69 | #define ATLAS_PH_INT_TIME_IN_US 450000 | 72 | #define ATLAS_PH_INT_TIME_IN_US 450000 |
70 | #define ATLAS_EC_INT_TIME_IN_US 650000 | 73 | #define ATLAS_EC_INT_TIME_IN_US 650000 |
74 | #define ATLAS_ORP_INT_TIME_IN_US 450000 | ||
71 | 75 | ||
72 | enum { | 76 | enum { |
73 | ATLAS_PH_SM, | 77 | ATLAS_PH_SM, |
74 | ATLAS_EC_SM, | 78 | ATLAS_EC_SM, |
79 | ATLAS_ORP_SM, | ||
75 | }; | 80 | }; |
76 | 81 | ||
77 | struct atlas_data { | 82 | struct atlas_data { |
@@ -84,26 +89,10 @@ struct atlas_data { | |||
84 | __be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */ | 89 | __be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */ |
85 | }; | 90 | }; |
86 | 91 | ||
87 | static const struct regmap_range atlas_volatile_ranges[] = { | ||
88 | regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL), | ||
89 | regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4), | ||
90 | regmap_reg_range(ATLAS_REG_EC_DATA, ATLAS_REG_PSS_DATA + 4), | ||
91 | }; | ||
92 | |||
93 | static const struct regmap_access_table atlas_volatile_table = { | ||
94 | .yes_ranges = atlas_volatile_ranges, | ||
95 | .n_yes_ranges = ARRAY_SIZE(atlas_volatile_ranges), | ||
96 | }; | ||
97 | |||
98 | static const struct regmap_config atlas_regmap_config = { | 92 | static const struct regmap_config atlas_regmap_config = { |
99 | .name = ATLAS_REGMAP_NAME, | 93 | .name = ATLAS_REGMAP_NAME, |
100 | |||
101 | .reg_bits = 8, | 94 | .reg_bits = 8, |
102 | .val_bits = 8, | 95 | .val_bits = 8, |
103 | |||
104 | .volatile_table = &atlas_volatile_table, | ||
105 | .max_register = ATLAS_REG_PSS_DATA + 4, | ||
106 | .cache_type = REGCACHE_RBTREE, | ||
107 | }; | 96 | }; |
108 | 97 | ||
109 | static const struct iio_chan_spec atlas_ph_channels[] = { | 98 | static const struct iio_chan_spec atlas_ph_channels[] = { |
@@ -175,6 +164,23 @@ static const struct iio_chan_spec atlas_ec_channels[] = { | |||
175 | }, | 164 | }, |
176 | }; | 165 | }; |
177 | 166 | ||
167 | static const struct iio_chan_spec atlas_orp_channels[] = { | ||
168 | { | ||
169 | .type = IIO_VOLTAGE, | ||
170 | .address = ATLAS_REG_ORP_DATA, | ||
171 | .info_mask_separate = | ||
172 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), | ||
173 | .scan_index = 0, | ||
174 | .scan_type = { | ||
175 | .sign = 's', | ||
176 | .realbits = 32, | ||
177 | .storagebits = 32, | ||
178 | .endianness = IIO_BE, | ||
179 | }, | ||
180 | }, | ||
181 | IIO_CHAN_SOFT_TIMESTAMP(1), | ||
182 | }; | ||
183 | |||
178 | static int atlas_check_ph_calibration(struct atlas_data *data) | 184 | static int atlas_check_ph_calibration(struct atlas_data *data) |
179 | { | 185 | { |
180 | struct device *dev = &data->client->dev; | 186 | struct device *dev = &data->client->dev; |
@@ -240,6 +246,22 @@ static int atlas_check_ec_calibration(struct atlas_data *data) | |||
240 | return 0; | 246 | return 0; |
241 | } | 247 | } |
242 | 248 | ||
249 | static int atlas_check_orp_calibration(struct atlas_data *data) | ||
250 | { | ||
251 | struct device *dev = &data->client->dev; | ||
252 | int ret; | ||
253 | unsigned int val; | ||
254 | |||
255 | ret = regmap_read(data->regmap, ATLAS_REG_ORP_CALIB_STATUS, &val); | ||
256 | if (ret) | ||
257 | return ret; | ||
258 | |||
259 | if (!val) | ||
260 | dev_warn(dev, "device has not been calibrated\n"); | ||
261 | |||
262 | return 0; | ||
263 | }; | ||
264 | |||
243 | struct atlas_device { | 265 | struct atlas_device { |
244 | const struct iio_chan_spec *channels; | 266 | const struct iio_chan_spec *channels; |
245 | int num_channels; | 267 | int num_channels; |
@@ -264,7 +286,13 @@ static struct atlas_device atlas_devices[] = { | |||
264 | .calibration = &atlas_check_ec_calibration, | 286 | .calibration = &atlas_check_ec_calibration, |
265 | .delay = ATLAS_EC_INT_TIME_IN_US, | 287 | .delay = ATLAS_EC_INT_TIME_IN_US, |
266 | }, | 288 | }, |
267 | 289 | [ATLAS_ORP_SM] = { | |
290 | .channels = atlas_orp_channels, | ||
291 | .num_channels = 2, | ||
292 | .data_reg = ATLAS_REG_ORP_DATA, | ||
293 | .calibration = &atlas_check_orp_calibration, | ||
294 | .delay = ATLAS_ORP_INT_TIME_IN_US, | ||
295 | }, | ||
268 | }; | 296 | }; |
269 | 297 | ||
270 | static int atlas_set_powermode(struct atlas_data *data, int on) | 298 | static int atlas_set_powermode(struct atlas_data *data, int on) |
@@ -402,15 +430,14 @@ static int atlas_read_raw(struct iio_dev *indio_dev, | |||
402 | case IIO_PH: | 430 | case IIO_PH: |
403 | case IIO_CONCENTRATION: | 431 | case IIO_CONCENTRATION: |
404 | case IIO_ELECTRICALCONDUCTIVITY: | 432 | case IIO_ELECTRICALCONDUCTIVITY: |
405 | mutex_lock(&indio_dev->mlock); | 433 | case IIO_VOLTAGE: |
434 | ret = iio_device_claim_direct_mode(indio_dev); | ||
435 | if (ret) | ||
436 | return ret; | ||
406 | 437 | ||
407 | if (iio_buffer_enabled(indio_dev)) | 438 | ret = atlas_read_measurement(data, chan->address, ®); |
408 | ret = -EBUSY; | ||
409 | else | ||
410 | ret = atlas_read_measurement(data, | ||
411 | chan->address, ®); | ||
412 | 439 | ||
413 | mutex_unlock(&indio_dev->mlock); | 440 | iio_device_release_direct_mode(indio_dev); |
414 | break; | 441 | break; |
415 | default: | 442 | default: |
416 | ret = -EINVAL; | 443 | ret = -EINVAL; |
@@ -440,6 +467,10 @@ static int atlas_read_raw(struct iio_dev *indio_dev, | |||
440 | *val = 0; /* 0.000000001 */ | 467 | *val = 0; /* 0.000000001 */ |
441 | *val2 = 1000; | 468 | *val2 = 1000; |
442 | return IIO_VAL_INT_PLUS_NANO; | 469 | return IIO_VAL_INT_PLUS_NANO; |
470 | case IIO_VOLTAGE: | ||
471 | *val = 1; /* 0.1 */ | ||
472 | *val2 = 10; | ||
473 | break; | ||
443 | default: | 474 | default: |
444 | return -EINVAL; | 475 | return -EINVAL; |
445 | } | 476 | } |
@@ -475,6 +506,7 @@ static const struct iio_info atlas_info = { | |||
475 | static const struct i2c_device_id atlas_id[] = { | 506 | static const struct i2c_device_id atlas_id[] = { |
476 | { "atlas-ph-sm", ATLAS_PH_SM}, | 507 | { "atlas-ph-sm", ATLAS_PH_SM}, |
477 | { "atlas-ec-sm", ATLAS_EC_SM}, | 508 | { "atlas-ec-sm", ATLAS_EC_SM}, |
509 | { "atlas-orp-sm", ATLAS_ORP_SM}, | ||
478 | {} | 510 | {} |
479 | }; | 511 | }; |
480 | MODULE_DEVICE_TABLE(i2c, atlas_id); | 512 | MODULE_DEVICE_TABLE(i2c, atlas_id); |
@@ -482,6 +514,7 @@ MODULE_DEVICE_TABLE(i2c, atlas_id); | |||
482 | static const struct of_device_id atlas_dt_ids[] = { | 514 | static const struct of_device_id atlas_dt_ids[] = { |
483 | { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, }, | 515 | { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, }, |
484 | { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, }, | 516 | { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, }, |
517 | { .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, }, | ||
485 | { } | 518 | { } |
486 | }; | 519 | }; |
487 | MODULE_DEVICE_TABLE(of, atlas_dt_ids); | 520 | MODULE_DEVICE_TABLE(of, atlas_dt_ids); |
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 652649da500f..8e0e4415c161 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c | |||
@@ -19,25 +19,55 @@ | |||
19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
22 | 24 | ||
23 | #include <linux/iio/iio.h> | 25 | #include <linux/iio/iio.h> |
24 | #include <linux/iio/sysfs.h> | 26 | #include <linux/iio/sysfs.h> |
25 | 27 | ||
26 | #define VZ89X_REG_MEASUREMENT 0x09 | 28 | #define VZ89X_REG_MEASUREMENT 0x09 |
27 | #define VZ89X_REG_MEASUREMENT_SIZE 6 | 29 | #define VZ89X_REG_MEASUREMENT_RD_SIZE 6 |
30 | #define VZ89X_REG_MEASUREMENT_WR_SIZE 3 | ||
28 | 31 | ||
29 | #define VZ89X_VOC_CO2_IDX 0 | 32 | #define VZ89X_VOC_CO2_IDX 0 |
30 | #define VZ89X_VOC_SHORT_IDX 1 | 33 | #define VZ89X_VOC_SHORT_IDX 1 |
31 | #define VZ89X_VOC_TVOC_IDX 2 | 34 | #define VZ89X_VOC_TVOC_IDX 2 |
32 | #define VZ89X_VOC_RESISTANCE_IDX 3 | 35 | #define VZ89X_VOC_RESISTANCE_IDX 3 |
33 | 36 | ||
37 | #define VZ89TE_REG_MEASUREMENT 0x0c | ||
38 | #define VZ89TE_REG_MEASUREMENT_RD_SIZE 7 | ||
39 | #define VZ89TE_REG_MEASUREMENT_WR_SIZE 6 | ||
40 | |||
41 | #define VZ89TE_VOC_TVOC_IDX 0 | ||
42 | #define VZ89TE_VOC_CO2_IDX 1 | ||
43 | #define VZ89TE_VOC_RESISTANCE_IDX 2 | ||
44 | |||
45 | enum { | ||
46 | VZ89X, | ||
47 | VZ89TE, | ||
48 | }; | ||
49 | |||
50 | struct vz89x_chip_data; | ||
51 | |||
34 | struct vz89x_data { | 52 | struct vz89x_data { |
35 | struct i2c_client *client; | 53 | struct i2c_client *client; |
54 | const struct vz89x_chip_data *chip; | ||
36 | struct mutex lock; | 55 | struct mutex lock; |
37 | int (*xfer)(struct vz89x_data *data, u8 cmd); | 56 | int (*xfer)(struct vz89x_data *data, u8 cmd); |
38 | 57 | ||
58 | bool is_valid; | ||
39 | unsigned long last_update; | 59 | unsigned long last_update; |
40 | u8 buffer[VZ89X_REG_MEASUREMENT_SIZE]; | 60 | u8 buffer[VZ89TE_REG_MEASUREMENT_RD_SIZE]; |
61 | }; | ||
62 | |||
63 | struct vz89x_chip_data { | ||
64 | bool (*valid)(struct vz89x_data *data); | ||
65 | const struct iio_chan_spec *channels; | ||
66 | u8 num_channels; | ||
67 | |||
68 | u8 cmd; | ||
69 | u8 read_size; | ||
70 | u8 write_size; | ||
41 | }; | 71 | }; |
42 | 72 | ||
43 | static const struct iio_chan_spec vz89x_channels[] = { | 73 | static const struct iio_chan_spec vz89x_channels[] = { |
@@ -70,6 +100,40 @@ static const struct iio_chan_spec vz89x_channels[] = { | |||
70 | .info_mask_separate = | 100 | .info_mask_separate = |
71 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), | 101 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), |
72 | .address = VZ89X_VOC_RESISTANCE_IDX, | 102 | .address = VZ89X_VOC_RESISTANCE_IDX, |
103 | .scan_index = -1, | ||
104 | .scan_type = { | ||
105 | .endianness = IIO_LE, | ||
106 | }, | ||
107 | }, | ||
108 | }; | ||
109 | |||
110 | static const struct iio_chan_spec vz89te_channels[] = { | ||
111 | { | ||
112 | .type = IIO_CONCENTRATION, | ||
113 | .channel2 = IIO_MOD_VOC, | ||
114 | .modified = 1, | ||
115 | .info_mask_separate = | ||
116 | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW), | ||
117 | .address = VZ89TE_VOC_TVOC_IDX, | ||
118 | }, | ||
119 | |||
120 | { | ||
121 | .type = IIO_CONCENTRATION, | ||
122 | .channel2 = IIO_MOD_CO2, | ||
123 | .modified = 1, | ||
124 | .info_mask_separate = | ||
125 | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW), | ||
126 | .address = VZ89TE_VOC_CO2_IDX, | ||
127 | }, | ||
128 | { | ||
129 | .type = IIO_RESISTANCE, | ||
130 | .info_mask_separate = | ||
131 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), | ||
132 | .address = VZ89TE_VOC_RESISTANCE_IDX, | ||
133 | .scan_index = -1, | ||
134 | .scan_type = { | ||
135 | .endianness = IIO_BE, | ||
136 | }, | ||
73 | }, | 137 | }, |
74 | }; | 138 | }; |
75 | 139 | ||
@@ -93,29 +157,45 @@ static const struct attribute_group vz89x_attrs_group = { | |||
93 | * always zero, and by also confirming the VOC_short isn't zero. | 157 | * always zero, and by also confirming the VOC_short isn't zero. |
94 | */ | 158 | */ |
95 | 159 | ||
96 | static int vz89x_measurement_is_valid(struct vz89x_data *data) | 160 | static bool vz89x_measurement_is_valid(struct vz89x_data *data) |
97 | { | 161 | { |
98 | if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0) | 162 | if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0) |
99 | return 1; | 163 | return true; |
100 | 164 | ||
101 | return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0); | 165 | return !!(data->buffer[data->chip->read_size - 1] > 0); |
166 | } | ||
167 | |||
168 | /* VZ89TE device has a modified CRC-8 two complement check */ | ||
169 | static bool vz89te_measurement_is_valid(struct vz89x_data *data) | ||
170 | { | ||
171 | u8 crc = 0; | ||
172 | int i, sum = 0; | ||
173 | |||
174 | for (i = 0; i < (data->chip->read_size - 1); i++) { | ||
175 | sum = crc + data->buffer[i]; | ||
176 | crc = sum; | ||
177 | crc += sum / 256; | ||
178 | } | ||
179 | |||
180 | return !((0xff - crc) == data->buffer[data->chip->read_size - 1]); | ||
102 | } | 181 | } |
103 | 182 | ||
104 | static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd) | 183 | static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd) |
105 | { | 184 | { |
185 | const struct vz89x_chip_data *chip = data->chip; | ||
106 | struct i2c_client *client = data->client; | 186 | struct i2c_client *client = data->client; |
107 | struct i2c_msg msg[2]; | 187 | struct i2c_msg msg[2]; |
108 | int ret; | 188 | int ret; |
109 | u8 buf[3] = { cmd, 0, 0}; | 189 | u8 buf[6] = { cmd, 0, 0, 0, 0, 0xf3 }; |
110 | 190 | ||
111 | msg[0].addr = client->addr; | 191 | msg[0].addr = client->addr; |
112 | msg[0].flags = client->flags; | 192 | msg[0].flags = client->flags; |
113 | msg[0].len = 3; | 193 | msg[0].len = chip->write_size; |
114 | msg[0].buf = (char *) &buf; | 194 | msg[0].buf = (char *) &buf; |
115 | 195 | ||
116 | msg[1].addr = client->addr; | 196 | msg[1].addr = client->addr; |
117 | msg[1].flags = client->flags | I2C_M_RD; | 197 | msg[1].flags = client->flags | I2C_M_RD; |
118 | msg[1].len = VZ89X_REG_MEASUREMENT_SIZE; | 198 | msg[1].len = chip->read_size; |
119 | msg[1].buf = (char *) &data->buffer; | 199 | msg[1].buf = (char *) &data->buffer; |
120 | 200 | ||
121 | ret = i2c_transfer(client->adapter, msg, 2); | 201 | ret = i2c_transfer(client->adapter, msg, 2); |
@@ -133,7 +213,7 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd) | |||
133 | if (ret < 0) | 213 | if (ret < 0) |
134 | return ret; | 214 | return ret; |
135 | 215 | ||
136 | for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) { | 216 | for (i = 0; i < data->chip->read_size; i++) { |
137 | ret = i2c_smbus_read_byte(client); | 217 | ret = i2c_smbus_read_byte(client); |
138 | if (ret < 0) | 218 | if (ret < 0) |
139 | return ret; | 219 | return ret; |
@@ -145,30 +225,47 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd) | |||
145 | 225 | ||
146 | static int vz89x_get_measurement(struct vz89x_data *data) | 226 | static int vz89x_get_measurement(struct vz89x_data *data) |
147 | { | 227 | { |
228 | const struct vz89x_chip_data *chip = data->chip; | ||
148 | int ret; | 229 | int ret; |
149 | 230 | ||
150 | /* sensor can only be polled once a second max per datasheet */ | 231 | /* sensor can only be polled once a second max per datasheet */ |
151 | if (!time_after(jiffies, data->last_update + HZ)) | 232 | if (!time_after(jiffies, data->last_update + HZ)) |
152 | return 0; | 233 | return data->is_valid ? 0 : -EAGAIN; |
234 | |||
235 | data->is_valid = false; | ||
236 | data->last_update = jiffies; | ||
153 | 237 | ||
154 | ret = data->xfer(data, VZ89X_REG_MEASUREMENT); | 238 | ret = data->xfer(data, chip->cmd); |
155 | if (ret < 0) | 239 | if (ret < 0) |
156 | return ret; | 240 | return ret; |
157 | 241 | ||
158 | ret = vz89x_measurement_is_valid(data); | 242 | ret = chip->valid(data); |
159 | if (ret) | 243 | if (ret) |
160 | return -EAGAIN; | 244 | return -EAGAIN; |
161 | 245 | ||
162 | data->last_update = jiffies; | 246 | data->is_valid = true; |
163 | 247 | ||
164 | return 0; | 248 | return 0; |
165 | } | 249 | } |
166 | 250 | ||
167 | static int vz89x_get_resistance_reading(struct vz89x_data *data) | 251 | static int vz89x_get_resistance_reading(struct vz89x_data *data, |
252 | struct iio_chan_spec const *chan, | ||
253 | int *val) | ||
168 | { | 254 | { |
169 | u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX]; | 255 | u8 *tmp = (u8 *) &data->buffer[chan->address]; |
170 | 256 | ||
171 | return buf[0] | (buf[1] << 8); | 257 | switch (chan->scan_type.endianness) { |
258 | case IIO_LE: | ||
259 | *val = le32_to_cpup((__le32 *) tmp) & GENMASK(23, 0); | ||
260 | break; | ||
261 | case IIO_BE: | ||
262 | *val = be32_to_cpup((__be32 *) tmp) >> 8; | ||
263 | break; | ||
264 | default: | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | |||
268 | return 0; | ||
172 | } | 269 | } |
173 | 270 | ||
174 | static int vz89x_read_raw(struct iio_dev *indio_dev, | 271 | static int vz89x_read_raw(struct iio_dev *indio_dev, |
@@ -187,15 +284,15 @@ static int vz89x_read_raw(struct iio_dev *indio_dev, | |||
187 | if (ret) | 284 | if (ret) |
188 | return ret; | 285 | return ret; |
189 | 286 | ||
190 | switch (chan->address) { | 287 | switch (chan->type) { |
191 | case VZ89X_VOC_CO2_IDX: | 288 | case IIO_CONCENTRATION: |
192 | case VZ89X_VOC_SHORT_IDX: | ||
193 | case VZ89X_VOC_TVOC_IDX: | ||
194 | *val = data->buffer[chan->address]; | 289 | *val = data->buffer[chan->address]; |
195 | return IIO_VAL_INT; | 290 | return IIO_VAL_INT; |
196 | case VZ89X_VOC_RESISTANCE_IDX: | 291 | case IIO_RESISTANCE: |
197 | *val = vz89x_get_resistance_reading(data); | 292 | ret = vz89x_get_resistance_reading(data, chan, val); |
198 | return IIO_VAL_INT; | 293 | if (!ret) |
294 | return IIO_VAL_INT; | ||
295 | break; | ||
199 | default: | 296 | default: |
200 | return -EINVAL; | 297 | return -EINVAL; |
201 | } | 298 | } |
@@ -210,12 +307,12 @@ static int vz89x_read_raw(struct iio_dev *indio_dev, | |||
210 | } | 307 | } |
211 | break; | 308 | break; |
212 | case IIO_CHAN_INFO_OFFSET: | 309 | case IIO_CHAN_INFO_OFFSET: |
213 | switch (chan->address) { | 310 | switch (chan->channel2) { |
214 | case VZ89X_VOC_CO2_IDX: | 311 | case IIO_MOD_CO2: |
215 | *val = 44; | 312 | *val = 44; |
216 | *val2 = 250000; | 313 | *val2 = 250000; |
217 | return IIO_VAL_INT_PLUS_MICRO; | 314 | return IIO_VAL_INT_PLUS_MICRO; |
218 | case VZ89X_VOC_TVOC_IDX: | 315 | case IIO_MOD_VOC: |
219 | *val = -13; | 316 | *val = -13; |
220 | return IIO_VAL_INT; | 317 | return IIO_VAL_INT; |
221 | default: | 318 | default: |
@@ -232,11 +329,43 @@ static const struct iio_info vz89x_info = { | |||
232 | .driver_module = THIS_MODULE, | 329 | .driver_module = THIS_MODULE, |
233 | }; | 330 | }; |
234 | 331 | ||
332 | static const struct vz89x_chip_data vz89x_chips[] = { | ||
333 | { | ||
334 | .valid = vz89x_measurement_is_valid, | ||
335 | |||
336 | .cmd = VZ89X_REG_MEASUREMENT, | ||
337 | .read_size = VZ89X_REG_MEASUREMENT_RD_SIZE, | ||
338 | .write_size = VZ89X_REG_MEASUREMENT_WR_SIZE, | ||
339 | |||
340 | .channels = vz89x_channels, | ||
341 | .num_channels = ARRAY_SIZE(vz89x_channels), | ||
342 | }, | ||
343 | { | ||
344 | .valid = vz89te_measurement_is_valid, | ||
345 | |||
346 | .cmd = VZ89TE_REG_MEASUREMENT, | ||
347 | .read_size = VZ89TE_REG_MEASUREMENT_RD_SIZE, | ||
348 | .write_size = VZ89TE_REG_MEASUREMENT_WR_SIZE, | ||
349 | |||
350 | .channels = vz89te_channels, | ||
351 | .num_channels = ARRAY_SIZE(vz89te_channels), | ||
352 | }, | ||
353 | }; | ||
354 | |||
355 | static const struct of_device_id vz89x_dt_ids[] = { | ||
356 | { .compatible = "sgx,vz89x", .data = (void *) VZ89X }, | ||
357 | { .compatible = "sgx,vz89te", .data = (void *) VZ89TE }, | ||
358 | { } | ||
359 | }; | ||
360 | MODULE_DEVICE_TABLE(of, vz89x_dt_ids); | ||
361 | |||
235 | static int vz89x_probe(struct i2c_client *client, | 362 | static int vz89x_probe(struct i2c_client *client, |
236 | const struct i2c_device_id *id) | 363 | const struct i2c_device_id *id) |
237 | { | 364 | { |
238 | struct iio_dev *indio_dev; | 365 | struct iio_dev *indio_dev; |
239 | struct vz89x_data *data; | 366 | struct vz89x_data *data; |
367 | const struct of_device_id *of_id; | ||
368 | int chip_id; | ||
240 | 369 | ||
241 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | 370 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); |
242 | if (!indio_dev) | 371 | if (!indio_dev) |
@@ -251,8 +380,15 @@ static int vz89x_probe(struct i2c_client *client, | |||
251 | else | 380 | else |
252 | return -EOPNOTSUPP; | 381 | return -EOPNOTSUPP; |
253 | 382 | ||
383 | of_id = of_match_device(vz89x_dt_ids, &client->dev); | ||
384 | if (!of_id) | ||
385 | chip_id = id->driver_data; | ||
386 | else | ||
387 | chip_id = (unsigned long)of_id->data; | ||
388 | |||
254 | i2c_set_clientdata(client, indio_dev); | 389 | i2c_set_clientdata(client, indio_dev); |
255 | data->client = client; | 390 | data->client = client; |
391 | data->chip = &vz89x_chips[chip_id]; | ||
256 | data->last_update = jiffies - HZ; | 392 | data->last_update = jiffies - HZ; |
257 | mutex_init(&data->lock); | 393 | mutex_init(&data->lock); |
258 | 394 | ||
@@ -261,24 +397,19 @@ static int vz89x_probe(struct i2c_client *client, | |||
261 | indio_dev->name = dev_name(&client->dev); | 397 | indio_dev->name = dev_name(&client->dev); |
262 | indio_dev->modes = INDIO_DIRECT_MODE; | 398 | indio_dev->modes = INDIO_DIRECT_MODE; |
263 | 399 | ||
264 | indio_dev->channels = vz89x_channels; | 400 | indio_dev->channels = data->chip->channels; |
265 | indio_dev->num_channels = ARRAY_SIZE(vz89x_channels); | 401 | indio_dev->num_channels = data->chip->num_channels; |
266 | 402 | ||
267 | return devm_iio_device_register(&client->dev, indio_dev); | 403 | return devm_iio_device_register(&client->dev, indio_dev); |
268 | } | 404 | } |
269 | 405 | ||
270 | static const struct i2c_device_id vz89x_id[] = { | 406 | static const struct i2c_device_id vz89x_id[] = { |
271 | { "vz89x", 0 }, | 407 | { "vz89x", VZ89X }, |
408 | { "vz89te", VZ89TE }, | ||
272 | { } | 409 | { } |
273 | }; | 410 | }; |
274 | MODULE_DEVICE_TABLE(i2c, vz89x_id); | 411 | MODULE_DEVICE_TABLE(i2c, vz89x_id); |
275 | 412 | ||
276 | static const struct of_device_id vz89x_dt_ids[] = { | ||
277 | { .compatible = "sgx,vz89x" }, | ||
278 | { } | ||
279 | }; | ||
280 | MODULE_DEVICE_TABLE(of, vz89x_dt_ids); | ||
281 | |||
282 | static struct i2c_driver vz89x_driver = { | 413 | static struct i2c_driver vz89x_driver = { |
283 | .driver = { | 414 | .driver = { |
284 | .name = "vz89x", | 415 | .name = "vz89x", |