blob: 9f80cc18ef7fe6443cdcb5cf10a7fe9556534a6d [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * ccs811.c - Support for AMS CCS811 VOC Sensor
3 *
4 * Copyright (C) 2017 Narcisa Vasile <narcisaanamaria12@gmail.com>
5 *
6 * Datasheet: ams.com/content/download/951091/2269479/CCS811_DS000459_3-00.pdf
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * IIO driver for AMS CCS811 (I2C address 0x5A/0x5B set by ADDR Low/High)
13 *
14 * TODO:
15 * 1. Make the drive mode selectable form userspace
16 * 2. Add support for interrupts
17 * 3. Adjust time to wait for data to be ready based on selected operation mode
18 * 4. Read error register and put the information in logs
19 */
20
21#include <linux/delay.h>
22#include <linux/i2c.h>
23#include <linux/iio/iio.h>
24#include <linux/iio/buffer.h>
25#include <linux/iio/triggered_buffer.h>
26#include <linux/iio/trigger_consumer.h>
27#include <linux/module.h>
28
29#define CCS811_STATUS 0x00
30#define CCS811_MEAS_MODE 0x01
31#define CCS811_ALG_RESULT_DATA 0x02
32#define CCS811_RAW_DATA 0x03
33#define CCS811_HW_ID 0x20
34#define CCS881_HW_ID_VALUE 0x81
35#define CCS811_HW_VERSION 0x21
36#define CCS811_HW_VERSION_VALUE 0x10
37#define CCS811_HW_VERSION_MASK 0xF0
38#define CCS811_ERR 0xE0
39/* Used to transition from boot to application mode */
40#define CCS811_APP_START 0xF4
41
42/* Status register flags */
43#define CCS811_STATUS_ERROR BIT(0)
44#define CCS811_STATUS_DATA_READY BIT(3)
45#define CCS811_STATUS_APP_VALID_MASK BIT(4)
46#define CCS811_STATUS_APP_VALID_LOADED BIT(4)
47/*
48 * Value of FW_MODE bit of STATUS register describes the sensor's state:
49 * 0: Firmware is in boot mode, this allows new firmware to be loaded
50 * 1: Firmware is in application mode. CCS811 is ready to take ADC measurements
51 */
52#define CCS811_STATUS_FW_MODE_MASK BIT(7)
53#define CCS811_STATUS_FW_MODE_APPLICATION BIT(7)
54
55/* Measurement modes */
56#define CCS811_MODE_IDLE 0x00
57#define CCS811_MODE_IAQ_1SEC 0x10
58#define CCS811_MODE_IAQ_10SEC 0x20
59#define CCS811_MODE_IAQ_60SEC 0x30
60#define CCS811_MODE_RAW_DATA 0x40
61
62#define CCS811_VOLTAGE_MASK 0x3FF
63
64struct ccs811_reading {
65 __be16 co2;
66 __be16 voc;
67 u8 status;
68 u8 error;
69 __be16 resistance;
70} __attribute__((__packed__));
71
72struct ccs811_data {
73 struct i2c_client *client;
74 struct mutex lock; /* Protect readings */
75 struct ccs811_reading buffer;
76 /* Ensures correct alignment of timestamp if present */
77 struct {
78 s16 channels[2];
79 s64 ts __aligned(8);
80 } scan;
81};
82
83static const struct iio_chan_spec ccs811_channels[] = {
84 {
85 .type = IIO_CURRENT,
86 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
87 BIT(IIO_CHAN_INFO_SCALE),
88 .scan_index = -1,
89 }, {
90 .type = IIO_VOLTAGE,
91 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
92 BIT(IIO_CHAN_INFO_SCALE),
93 .scan_index = -1,
94 }, {
95 .type = IIO_CONCENTRATION,
96 .channel2 = IIO_MOD_CO2,
97 .modified = 1,
98 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
99 BIT(IIO_CHAN_INFO_SCALE),
100 .scan_index = 0,
101 .scan_type = {
102 .sign = 'u',
103 .realbits = 16,
104 .storagebits = 16,
105 .endianness = IIO_BE,
106 },
107 }, {
108 .type = IIO_CONCENTRATION,
109 .channel2 = IIO_MOD_VOC,
110 .modified = 1,
111 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
112 BIT(IIO_CHAN_INFO_SCALE),
113 .scan_index = 1,
114 .scan_type = {
115 .sign = 'u',
116 .realbits = 16,
117 .storagebits = 16,
118 .endianness = IIO_BE,
119 },
120 },
121 IIO_CHAN_SOFT_TIMESTAMP(2),
122};
123
124/*
125 * The CCS811 powers-up in boot mode. A setup write to CCS811_APP_START will
126 * transition the sensor to application mode.
127 */
128static int ccs811_start_sensor_application(struct i2c_client *client)
129{
130 int ret;
131
132 ret = i2c_smbus_read_byte_data(client, CCS811_STATUS);
133 if (ret < 0)
134 return ret;
135
136 if ((ret & CCS811_STATUS_FW_MODE_APPLICATION))
137 return 0;
138
139 if ((ret & CCS811_STATUS_APP_VALID_MASK) !=
140 CCS811_STATUS_APP_VALID_LOADED)
141 return -EIO;
142
143 ret = i2c_smbus_write_byte(client, CCS811_APP_START);
144 if (ret < 0)
145 return ret;
146
147 ret = i2c_smbus_read_byte_data(client, CCS811_STATUS);
148 if (ret < 0)
149 return ret;
150
151 if ((ret & CCS811_STATUS_FW_MODE_MASK) !=
152 CCS811_STATUS_FW_MODE_APPLICATION) {
153 dev_err(&client->dev, "Application failed to start. Sensor is still in boot mode.\n");
154 return -EIO;
155 }
156
157 return 0;
158}
159
160static int ccs811_setup(struct i2c_client *client)
161{
162 int ret;
163
164 ret = ccs811_start_sensor_application(client);
165 if (ret < 0)
166 return ret;
167
168 return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
169 CCS811_MODE_IAQ_1SEC);
170}
171
172static int ccs811_get_measurement(struct ccs811_data *data)
173{
174 int ret, tries = 11;
175
176 /* Maximum waiting time: 1s, as measurements are made every second */
177 while (tries-- > 0) {
178 ret = i2c_smbus_read_byte_data(data->client, CCS811_STATUS);
179 if (ret < 0)
180 return ret;
181
182 if ((ret & CCS811_STATUS_DATA_READY) || tries == 0)
183 break;
184 msleep(100);
185 }
186 if (!(ret & CCS811_STATUS_DATA_READY))
187 return -EIO;
188
189 return i2c_smbus_read_i2c_block_data(data->client,
190 CCS811_ALG_RESULT_DATA, 8,
191 (char *)&data->buffer);
192}
193
194static int ccs811_read_raw(struct iio_dev *indio_dev,
195 struct iio_chan_spec const *chan,
196 int *val, int *val2, long mask)
197{
198 struct ccs811_data *data = iio_priv(indio_dev);
199 int ret;
200
201 switch (mask) {
202 case IIO_CHAN_INFO_RAW:
203 mutex_lock(&data->lock);
204 ret = ccs811_get_measurement(data);
205 if (ret < 0) {
206 mutex_unlock(&data->lock);
207 return ret;
208 }
209
210 switch (chan->type) {
211 case IIO_VOLTAGE:
212 *val = be16_to_cpu(data->buffer.resistance) &
213 CCS811_VOLTAGE_MASK;
214 ret = IIO_VAL_INT;
215 break;
216 case IIO_CURRENT:
217 *val = be16_to_cpu(data->buffer.resistance) >> 10;
218 ret = IIO_VAL_INT;
219 break;
220 case IIO_CONCENTRATION:
221 switch (chan->channel2) {
222 case IIO_MOD_CO2:
223 *val = be16_to_cpu(data->buffer.co2);
224 ret = IIO_VAL_INT;
225 break;
226 case IIO_MOD_VOC:
227 *val = be16_to_cpu(data->buffer.voc);
228 ret = IIO_VAL_INT;
229 break;
230 default:
231 ret = -EINVAL;
232 }
233 break;
234 default:
235 ret = -EINVAL;
236 }
237 mutex_unlock(&data->lock);
238
239 return ret;
240
241 case IIO_CHAN_INFO_SCALE:
242 switch (chan->type) {
243 case IIO_VOLTAGE:
244 *val = 1;
245 *val2 = 612903;
246 return IIO_VAL_INT_PLUS_MICRO;
247 case IIO_CURRENT:
248 *val = 0;
249 *val2 = 1000;
250 return IIO_VAL_INT_PLUS_MICRO;
251 case IIO_CONCENTRATION:
252 switch (chan->channel2) {
253 case IIO_MOD_CO2:
254 *val = 0;
255 *val2 = 100;
256 return IIO_VAL_INT_PLUS_MICRO;
257 case IIO_MOD_VOC:
258 *val = 0;
259 *val2 = 100;
260 return IIO_VAL_INT_PLUS_NANO;
261 default:
262 return -EINVAL;
263 }
264 default:
265 return -EINVAL;
266 }
267 default:
268 return -EINVAL;
269 }
270}
271
272static const struct iio_info ccs811_info = {
273 .read_raw = ccs811_read_raw,
274 .driver_module = THIS_MODULE,
275};
276
277static irqreturn_t ccs811_trigger_handler(int irq, void *p)
278{
279 struct iio_poll_func *pf = p;
280 struct iio_dev *indio_dev = pf->indio_dev;
281 struct ccs811_data *data = iio_priv(indio_dev);
282 struct i2c_client *client = data->client;
283 int ret;
284
285 ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA,
286 sizeof(data->scan.channels),
287 (u8 *)data->scan.channels);
288 if (ret != 4) {
289 dev_err(&client->dev, "cannot read sensor data\n");
290 goto err;
291 }
292
293 iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
294 iio_get_time_ns(indio_dev));
295
296err:
297 iio_trigger_notify_done(indio_dev->trig);
298
299 return IRQ_HANDLED;
300}
301
302static int ccs811_probe(struct i2c_client *client,
303 const struct i2c_device_id *id)
304{
305 struct iio_dev *indio_dev;
306 struct ccs811_data *data;
307 int ret;
308
309 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
310 | I2C_FUNC_SMBUS_BYTE_DATA
311 | I2C_FUNC_SMBUS_READ_I2C_BLOCK))
312 return -EOPNOTSUPP;
313
314 /* Check hardware id (should be 0x81 for this family of devices) */
315 ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID);
316 if (ret < 0)
317 return ret;
318
319 if (ret != CCS881_HW_ID_VALUE) {
320 dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
321 return -ENODEV;
322 }
323
324 ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION);
325 if (ret < 0)
326 return ret;
327
328 if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) {
329 dev_err(&client->dev, "no CCS811 sensor\n");
330 return -ENODEV;
331 }
332
333 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
334 if (!indio_dev)
335 return -ENOMEM;
336
337 ret = ccs811_setup(client);
338 if (ret < 0)
339 return ret;
340
341 data = iio_priv(indio_dev);
342 i2c_set_clientdata(client, indio_dev);
343 data->client = client;
344
345 mutex_init(&data->lock);
346
347 indio_dev->dev.parent = &client->dev;
348 indio_dev->name = id->name;
349 indio_dev->info = &ccs811_info;
350
351 indio_dev->channels = ccs811_channels;
352 indio_dev->num_channels = ARRAY_SIZE(ccs811_channels);
353
354 ret = iio_triggered_buffer_setup(indio_dev, NULL,
355 ccs811_trigger_handler, NULL);
356
357 if (ret < 0) {
358 dev_err(&client->dev, "triggered buffer setup failed\n");
359 goto err_poweroff;
360 }
361
362 ret = iio_device_register(indio_dev);
363 if (ret < 0) {
364 dev_err(&client->dev, "unable to register iio device\n");
365 goto err_buffer_cleanup;
366 }
367 return 0;
368
369err_buffer_cleanup:
370 iio_triggered_buffer_cleanup(indio_dev);
371err_poweroff:
372 i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE, CCS811_MODE_IDLE);
373
374 return ret;
375}
376
377static int ccs811_remove(struct i2c_client *client)
378{
379 struct iio_dev *indio_dev = i2c_get_clientdata(client);
380
381 iio_device_unregister(indio_dev);
382 iio_triggered_buffer_cleanup(indio_dev);
383
384 return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
385 CCS811_MODE_IDLE);
386}
387
388static const struct i2c_device_id ccs811_id[] = {
389 {"ccs811", 0},
390 { }
391};
392MODULE_DEVICE_TABLE(i2c, ccs811_id);
393
394static struct i2c_driver ccs811_driver = {
395 .driver = {
396 .name = "ccs811",
397 },
398 .probe = ccs811_probe,
399 .remove = ccs811_remove,
400 .id_table = ccs811_id,
401};
402module_i2c_driver(ccs811_driver);
403
404MODULE_AUTHOR("Narcisa Vasile <narcisaanamaria12@gmail.com>");
405MODULE_DESCRIPTION("CCS811 volatile organic compounds sensor");
406MODULE_LICENSE("GPL v2");