blob: 2b007e7568b21b72d51a47614e7498269cc14c18 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +03002/*
3 * ccs811.c - Support for AMS CCS811 VOC Sensor
4 *
5 * Copyright (C) 2017 Narcisa Vasile <narcisaanamaria12@gmail.com>
6 *
7 * Datasheet: ams.com/content/download/951091/2269479/CCS811_DS000459_3-00.pdf
8 *
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +03009 * IIO driver for AMS CCS811 (I2C address 0x5A/0x5B set by ADDR Low/High)
10 *
11 * TODO:
12 * 1. Make the drive mode selectable form userspace
13 * 2. Add support for interrupts
14 * 3. Adjust time to wait for data to be ready based on selected operation mode
15 * 4. Read error register and put the information in logs
16 */
17
18#include <linux/delay.h>
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +053019#include <linux/gpio/consumer.h>
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030020#include <linux/i2c.h>
21#include <linux/iio/iio.h>
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +030022#include <linux/iio/buffer.h>
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +030023#include <linux/iio/trigger.h>
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +030024#include <linux/iio/triggered_buffer.h>
25#include <linux/iio/trigger_consumer.h>
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030026#include <linux/module.h>
27
28#define CCS811_STATUS 0x00
29#define CCS811_MEAS_MODE 0x01
30#define CCS811_ALG_RESULT_DATA 0x02
31#define CCS811_RAW_DATA 0x03
32#define CCS811_HW_ID 0x20
Richard Laif0ef941a2018-02-13 22:36:57 +000033#define CCS811_HW_ID_VALUE 0x81
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030034#define CCS811_HW_VERSION 0x21
35#define CCS811_HW_VERSION_VALUE 0x10
36#define CCS811_HW_VERSION_MASK 0xF0
37#define CCS811_ERR 0xE0
38/* Used to transition from boot to application mode */
39#define CCS811_APP_START 0xF4
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +053040#define CCS811_SW_RESET 0xFF
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030041
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
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +030062#define CCS811_MEAS_MODE_INTERRUPT BIT(3)
63
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030064#define CCS811_VOLTAGE_MASK 0x3FF
65
66struct ccs811_reading {
67 __be16 co2;
68 __be16 voc;
69 u8 status;
70 u8 error;
Richard Lai4c73b802018-02-14 01:08:35 +000071 __be16 raw_data;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030072} __attribute__((__packed__));
73
74struct ccs811_data {
75 struct i2c_client *client;
76 struct mutex lock; /* Protect readings */
77 struct ccs811_reading buffer;
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +030078 struct iio_trigger *drdy_trig;
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +053079 struct gpio_desc *wakeup_gpio;
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +030080 bool drdy_trig_on;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030081};
82
83static const struct iio_chan_spec ccs811_channels[] = {
84 {
85 .type = IIO_CURRENT,
86 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +030087 BIT(IIO_CHAN_INFO_SCALE),
88 .scan_index = -1,
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030089 }, {
90 .type = IIO_VOLTAGE,
91 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +030092 BIT(IIO_CHAN_INFO_SCALE),
93 .scan_index = -1,
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +030094 }, {
95 .type = IIO_CONCENTRATION,
96 .channel2 = IIO_MOD_CO2,
97 .modified = 1,
98 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +030099 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 },
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300107 }, {
108 .type = IIO_CONCENTRATION,
109 .channel2 = IIO_MOD_VOC,
110 .modified = 1,
111 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +0300112 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 },
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300120 },
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +0300121 IIO_CHAN_SOFT_TIMESTAMP(2),
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300122};
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
Richard Laib91e1462018-02-17 16:28:24 +0000136 if ((ret & CCS811_STATUS_FW_MODE_APPLICATION))
137 return 0;
138
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300139 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
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +0530172static void ccs811_set_wakeup(struct ccs811_data *data, bool enable)
173{
174 if (!data->wakeup_gpio)
175 return;
176
177 gpiod_set_value(data->wakeup_gpio, enable);
178
179 if (enable)
180 usleep_range(50, 60);
181 else
182 usleep_range(20, 30);
183}
184
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300185static int ccs811_get_measurement(struct ccs811_data *data)
186{
187 int ret, tries = 11;
188
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +0530189 ccs811_set_wakeup(data, true);
190
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300191 /* Maximum waiting time: 1s, as measurements are made every second */
192 while (tries-- > 0) {
193 ret = i2c_smbus_read_byte_data(data->client, CCS811_STATUS);
194 if (ret < 0)
195 return ret;
196
197 if ((ret & CCS811_STATUS_DATA_READY) || tries == 0)
198 break;
199 msleep(100);
200 }
201 if (!(ret & CCS811_STATUS_DATA_READY))
202 return -EIO;
203
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +0530204 ret = i2c_smbus_read_i2c_block_data(data->client,
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300205 CCS811_ALG_RESULT_DATA, 8,
206 (char *)&data->buffer);
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +0530207 ccs811_set_wakeup(data, false);
208
209 return ret;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300210}
211
212static int ccs811_read_raw(struct iio_dev *indio_dev,
213 struct iio_chan_spec const *chan,
214 int *val, int *val2, long mask)
215{
216 struct ccs811_data *data = iio_priv(indio_dev);
217 int ret;
218
219 switch (mask) {
220 case IIO_CHAN_INFO_RAW:
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300221 ret = iio_device_claim_direct_mode(indio_dev);
222 if (ret)
223 return ret;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300224 mutex_lock(&data->lock);
225 ret = ccs811_get_measurement(data);
226 if (ret < 0) {
227 mutex_unlock(&data->lock);
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300228 iio_device_release_direct_mode(indio_dev);
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300229 return ret;
230 }
231
232 switch (chan->type) {
233 case IIO_VOLTAGE:
Richard Lai4c73b802018-02-14 01:08:35 +0000234 *val = be16_to_cpu(data->buffer.raw_data) &
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300235 CCS811_VOLTAGE_MASK;
236 ret = IIO_VAL_INT;
237 break;
238 case IIO_CURRENT:
Richard Lai4c73b802018-02-14 01:08:35 +0000239 *val = be16_to_cpu(data->buffer.raw_data) >> 10;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300240 ret = IIO_VAL_INT;
241 break;
242 case IIO_CONCENTRATION:
243 switch (chan->channel2) {
244 case IIO_MOD_CO2:
245 *val = be16_to_cpu(data->buffer.co2);
246 ret = IIO_VAL_INT;
247 break;
248 case IIO_MOD_VOC:
249 *val = be16_to_cpu(data->buffer.voc);
250 ret = IIO_VAL_INT;
251 break;
252 default:
253 ret = -EINVAL;
254 }
255 break;
256 default:
257 ret = -EINVAL;
258 }
259 mutex_unlock(&data->lock);
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300260 iio_device_release_direct_mode(indio_dev);
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300261
262 return ret;
263
264 case IIO_CHAN_INFO_SCALE:
265 switch (chan->type) {
266 case IIO_VOLTAGE:
267 *val = 1;
268 *val2 = 612903;
269 return IIO_VAL_INT_PLUS_MICRO;
270 case IIO_CURRENT:
271 *val = 0;
272 *val2 = 1000;
273 return IIO_VAL_INT_PLUS_MICRO;
274 case IIO_CONCENTRATION:
275 switch (chan->channel2) {
276 case IIO_MOD_CO2:
277 *val = 0;
Narcisa Ana Maria Vasile8f114ac2017-12-06 18:57:58 +0200278 *val2 = 100;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300279 return IIO_VAL_INT_PLUS_MICRO;
280 case IIO_MOD_VOC:
281 *val = 0;
Narcisa Ana Maria Vasile8f114ac2017-12-06 18:57:58 +0200282 *val2 = 100;
283 return IIO_VAL_INT_PLUS_NANO;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300284 default:
285 return -EINVAL;
286 }
287 default:
288 return -EINVAL;
289 }
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300290 default:
291 return -EINVAL;
292 }
293}
294
295static const struct iio_info ccs811_info = {
296 .read_raw = ccs811_read_raw,
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300297};
298
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300299static int ccs811_set_trigger_state(struct iio_trigger *trig,
300 bool state)
301{
302 struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
303 struct ccs811_data *data = iio_priv(indio_dev);
304 int ret;
305
306 ret = i2c_smbus_read_byte_data(data->client, CCS811_MEAS_MODE);
307 if (ret < 0)
308 return ret;
309
310 if (state)
311 ret |= CCS811_MEAS_MODE_INTERRUPT;
312 else
313 ret &= ~CCS811_MEAS_MODE_INTERRUPT;
314
315 data->drdy_trig_on = state;
316
317 return i2c_smbus_write_byte_data(data->client, CCS811_MEAS_MODE, ret);
318}
319
320static const struct iio_trigger_ops ccs811_trigger_ops = {
321 .set_trigger_state = ccs811_set_trigger_state,
322};
323
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +0300324static irqreturn_t ccs811_trigger_handler(int irq, void *p)
325{
326 struct iio_poll_func *pf = p;
327 struct iio_dev *indio_dev = pf->indio_dev;
328 struct ccs811_data *data = iio_priv(indio_dev);
329 struct i2c_client *client = data->client;
330 s16 buf[8]; /* s16 eCO2 + s16 TVOC + padding + 8 byte timestamp */
331 int ret;
332
333 ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA, 4,
334 (u8 *)&buf);
335 if (ret != 4) {
336 dev_err(&client->dev, "cannot read sensor data\n");
337 goto err;
338 }
339
340 iio_push_to_buffers_with_timestamp(indio_dev, buf,
341 iio_get_time_ns(indio_dev));
342
343err:
344 iio_trigger_notify_done(indio_dev->trig);
345
346 return IRQ_HANDLED;
347}
348
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300349static irqreturn_t ccs811_data_rdy_trigger_poll(int irq, void *private)
350{
351 struct iio_dev *indio_dev = private;
352 struct ccs811_data *data = iio_priv(indio_dev);
353
354 if (data->drdy_trig_on)
355 iio_trigger_poll(data->drdy_trig);
356
357 return IRQ_HANDLED;
358}
359
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +0530360static int ccs811_reset(struct i2c_client *client)
361{
362 struct gpio_desc *reset_gpio;
363 int ret;
364
365 reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
366 GPIOD_OUT_LOW);
367 if (IS_ERR(reset_gpio))
368 return PTR_ERR(reset_gpio);
369
370 /* Try to reset using nRESET pin if available else do SW reset */
371 if (reset_gpio) {
372 gpiod_set_value(reset_gpio, 1);
373 usleep_range(20, 30);
374 gpiod_set_value(reset_gpio, 0);
375 } else {
376 /*
377 * As per the datasheet, this sequence of values needs to be
378 * written to the SW_RESET register for triggering the soft
379 * reset in the device and placing it in boot mode.
380 */
381 static const u8 reset_seq[] = {
382 0x11, 0xE5, 0x72, 0x8A,
383 };
384
385 ret = i2c_smbus_write_i2c_block_data(client, CCS811_SW_RESET,
386 sizeof(reset_seq), reset_seq);
387 if (ret < 0) {
388 dev_err(&client->dev, "Failed to reset sensor\n");
389 return ret;
390 }
391 }
392
393 /* tSTART delay required after reset */
394 usleep_range(1000, 2000);
395
396 return 0;
397}
398
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300399static int ccs811_probe(struct i2c_client *client,
400 const struct i2c_device_id *id)
401{
402 struct iio_dev *indio_dev;
403 struct ccs811_data *data;
404 int ret;
405
406 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
407 | I2C_FUNC_SMBUS_BYTE_DATA
408 | I2C_FUNC_SMBUS_READ_I2C_BLOCK))
409 return -EOPNOTSUPP;
410
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300411 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
412 if (!indio_dev)
413 return -ENOMEM;
414
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300415 data = iio_priv(indio_dev);
416 i2c_set_clientdata(client, indio_dev);
417 data->client = client;
418
Manivannan Sadhasivamc6644f72020-04-15 00:19:29 +0530419 data->wakeup_gpio = devm_gpiod_get_optional(&client->dev, "wakeup",
420 GPIOD_OUT_HIGH);
421 if (IS_ERR(data->wakeup_gpio))
422 return PTR_ERR(data->wakeup_gpio);
423
424 ccs811_set_wakeup(data, true);
425
426 ret = ccs811_reset(client);
427 if (ret) {
428 ccs811_set_wakeup(data, false);
429 return ret;
430 }
431
432 /* Check hardware id (should be 0x81 for this family of devices) */
433 ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID);
434 if (ret < 0) {
435 ccs811_set_wakeup(data, false);
436 return ret;
437 }
438
439 if (ret != CCS811_HW_ID_VALUE) {
440 dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
441 ccs811_set_wakeup(data, false);
442 return -ENODEV;
443 }
444
445 ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION);
446 if (ret < 0) {
447 ccs811_set_wakeup(data, false);
448 return ret;
449 }
450
451 if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) {
452 dev_err(&client->dev, "no CCS811 sensor\n");
453 ccs811_set_wakeup(data, false);
454 return -ENODEV;
455 }
456
457 ret = ccs811_setup(client);
458 if (ret < 0) {
459 ccs811_set_wakeup(data, false);
460 return ret;
461 }
462
463 ccs811_set_wakeup(data, false);
464
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300465 mutex_init(&data->lock);
466
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300467 indio_dev->name = id->name;
468 indio_dev->info = &ccs811_info;
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300469 indio_dev->modes = INDIO_DIRECT_MODE;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300470
471 indio_dev->channels = ccs811_channels;
472 indio_dev->num_channels = ARRAY_SIZE(ccs811_channels);
473
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300474 if (client->irq > 0) {
475 ret = devm_request_threaded_irq(&client->dev, client->irq,
476 ccs811_data_rdy_trigger_poll,
477 NULL,
478 IRQF_TRIGGER_FALLING |
479 IRQF_ONESHOT,
480 "ccs811_irq", indio_dev);
481 if (ret) {
482 dev_err(&client->dev, "irq request error %d\n", -ret);
483 goto err_poweroff;
484 }
485
486 data->drdy_trig = devm_iio_trigger_alloc(&client->dev,
487 "%s-dev%d",
488 indio_dev->name,
489 indio_dev->id);
490 if (!data->drdy_trig) {
491 ret = -ENOMEM;
492 goto err_poweroff;
493 }
494
495 data->drdy_trig->dev.parent = &client->dev;
496 data->drdy_trig->ops = &ccs811_trigger_ops;
497 iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
498 indio_dev->trig = data->drdy_trig;
499 iio_trigger_get(indio_dev->trig);
500 ret = iio_trigger_register(data->drdy_trig);
501 if (ret)
502 goto err_poweroff;
503 }
504
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +0300505 ret = iio_triggered_buffer_setup(indio_dev, NULL,
506 ccs811_trigger_handler, NULL);
507
508 if (ret < 0) {
509 dev_err(&client->dev, "triggered buffer setup failed\n");
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300510 goto err_trigger_unregister;
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +0300511 }
512
513 ret = iio_device_register(indio_dev);
514 if (ret < 0) {
515 dev_err(&client->dev, "unable to register iio device\n");
516 goto err_buffer_cleanup;
517 }
518 return 0;
519
520err_buffer_cleanup:
521 iio_triggered_buffer_cleanup(indio_dev);
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300522err_trigger_unregister:
523 if (data->drdy_trig)
524 iio_trigger_unregister(data->drdy_trig);
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +0300525err_poweroff:
526 i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE, CCS811_MODE_IDLE);
527
528 return ret;
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300529}
530
531static int ccs811_remove(struct i2c_client *client)
532{
533 struct iio_dev *indio_dev = i2c_get_clientdata(client);
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300534 struct ccs811_data *data = iio_priv(indio_dev);
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300535
536 iio_device_unregister(indio_dev);
Narcisa Ana Maria Vasile283d2692017-08-17 14:34:29 +0300537 iio_triggered_buffer_cleanup(indio_dev);
Narcisa Ana Maria Vasilef1f065d2017-09-07 21:38:37 +0300538 if (data->drdy_trig)
539 iio_trigger_unregister(data->drdy_trig);
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300540
541 return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
542 CCS811_MODE_IDLE);
543}
544
545static const struct i2c_device_id ccs811_id[] = {
546 {"ccs811", 0},
547 { }
548};
549MODULE_DEVICE_TABLE(i2c, ccs811_id);
550
Manivannan Sadhasivam151e9172020-04-15 00:19:30 +0530551static const struct of_device_id ccs811_dt_ids[] = {
552 { .compatible = "ams,ccs811" },
553 { }
554};
555MODULE_DEVICE_TABLE(of, ccs811_dt_ids);
556
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300557static struct i2c_driver ccs811_driver = {
558 .driver = {
559 .name = "ccs811",
Manivannan Sadhasivam151e9172020-04-15 00:19:30 +0530560 .of_match_table = ccs811_dt_ids,
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +0300561 },
562 .probe = ccs811_probe,
563 .remove = ccs811_remove,
564 .id_table = ccs811_id,
565};
566module_i2c_driver(ccs811_driver);
567
568MODULE_AUTHOR("Narcisa Vasile <narcisaanamaria12@gmail.com>");
569MODULE_DESCRIPTION("CCS811 volatile organic compounds sensor");
570MODULE_LICENSE("GPL v2");