blob: 8dbb5eddeb1f3098be9e82c40b9c5892f720da9a [file] [log] [blame]
Narcisa Ana Maria Vasilea94c24a2017-07-17 22:28:03 +03001/*
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/module.h>
25
26#define CCS811_STATUS 0x00
27#define CCS811_MEAS_MODE 0x01
28#define CCS811_ALG_RESULT_DATA 0x02
29#define CCS811_RAW_DATA 0x03
30#define CCS811_HW_ID 0x20
31#define CCS881_HW_ID_VALUE 0x81
32#define CCS811_HW_VERSION 0x21
33#define CCS811_HW_VERSION_VALUE 0x10
34#define CCS811_HW_VERSION_MASK 0xF0
35#define CCS811_ERR 0xE0
36/* Used to transition from boot to application mode */
37#define CCS811_APP_START 0xF4
38
39/* Status register flags */
40#define CCS811_STATUS_ERROR BIT(0)
41#define CCS811_STATUS_DATA_READY BIT(3)
42#define CCS811_STATUS_APP_VALID_MASK BIT(4)
43#define CCS811_STATUS_APP_VALID_LOADED BIT(4)
44/*
45 * Value of FW_MODE bit of STATUS register describes the sensor's state:
46 * 0: Firmware is in boot mode, this allows new firmware to be loaded
47 * 1: Firmware is in application mode. CCS811 is ready to take ADC measurements
48 */
49#define CCS811_STATUS_FW_MODE_MASK BIT(7)
50#define CCS811_STATUS_FW_MODE_APPLICATION BIT(7)
51
52/* Measurement modes */
53#define CCS811_MODE_IDLE 0x00
54#define CCS811_MODE_IAQ_1SEC 0x10
55#define CCS811_MODE_IAQ_10SEC 0x20
56#define CCS811_MODE_IAQ_60SEC 0x30
57#define CCS811_MODE_RAW_DATA 0x40
58
59#define CCS811_VOLTAGE_MASK 0x3FF
60
61struct ccs811_reading {
62 __be16 co2;
63 __be16 voc;
64 u8 status;
65 u8 error;
66 __be16 resistance;
67} __attribute__((__packed__));
68
69struct ccs811_data {
70 struct i2c_client *client;
71 struct mutex lock; /* Protect readings */
72 struct ccs811_reading buffer;
73};
74
75static const struct iio_chan_spec ccs811_channels[] = {
76 {
77 .type = IIO_CURRENT,
78 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
79 BIT(IIO_CHAN_INFO_SCALE)
80 }, {
81 .type = IIO_VOLTAGE,
82 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
83 BIT(IIO_CHAN_INFO_SCALE)
84 }, {
85 .type = IIO_CONCENTRATION,
86 .channel2 = IIO_MOD_CO2,
87 .modified = 1,
88 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
89 BIT(IIO_CHAN_INFO_OFFSET) |
90 BIT(IIO_CHAN_INFO_SCALE)
91 }, {
92 .type = IIO_CONCENTRATION,
93 .channel2 = IIO_MOD_VOC,
94 .modified = 1,
95 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
96 BIT(IIO_CHAN_INFO_SCALE)
97 },
98};
99
100/*
101 * The CCS811 powers-up in boot mode. A setup write to CCS811_APP_START will
102 * transition the sensor to application mode.
103 */
104static int ccs811_start_sensor_application(struct i2c_client *client)
105{
106 int ret;
107
108 ret = i2c_smbus_read_byte_data(client, CCS811_STATUS);
109 if (ret < 0)
110 return ret;
111
112 if ((ret & CCS811_STATUS_APP_VALID_MASK) !=
113 CCS811_STATUS_APP_VALID_LOADED)
114 return -EIO;
115
116 ret = i2c_smbus_write_byte(client, CCS811_APP_START);
117 if (ret < 0)
118 return ret;
119
120 ret = i2c_smbus_read_byte_data(client, CCS811_STATUS);
121 if (ret < 0)
122 return ret;
123
124 if ((ret & CCS811_STATUS_FW_MODE_MASK) !=
125 CCS811_STATUS_FW_MODE_APPLICATION) {
126 dev_err(&client->dev, "Application failed to start. Sensor is still in boot mode.\n");
127 return -EIO;
128 }
129
130 return 0;
131}
132
133static int ccs811_setup(struct i2c_client *client)
134{
135 int ret;
136
137 ret = ccs811_start_sensor_application(client);
138 if (ret < 0)
139 return ret;
140
141 return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
142 CCS811_MODE_IAQ_1SEC);
143}
144
145static int ccs811_get_measurement(struct ccs811_data *data)
146{
147 int ret, tries = 11;
148
149 /* Maximum waiting time: 1s, as measurements are made every second */
150 while (tries-- > 0) {
151 ret = i2c_smbus_read_byte_data(data->client, CCS811_STATUS);
152 if (ret < 0)
153 return ret;
154
155 if ((ret & CCS811_STATUS_DATA_READY) || tries == 0)
156 break;
157 msleep(100);
158 }
159 if (!(ret & CCS811_STATUS_DATA_READY))
160 return -EIO;
161
162 return i2c_smbus_read_i2c_block_data(data->client,
163 CCS811_ALG_RESULT_DATA, 8,
164 (char *)&data->buffer);
165}
166
167static int ccs811_read_raw(struct iio_dev *indio_dev,
168 struct iio_chan_spec const *chan,
169 int *val, int *val2, long mask)
170{
171 struct ccs811_data *data = iio_priv(indio_dev);
172 int ret;
173
174 switch (mask) {
175 case IIO_CHAN_INFO_RAW:
176 mutex_lock(&data->lock);
177 ret = ccs811_get_measurement(data);
178 if (ret < 0) {
179 mutex_unlock(&data->lock);
180 return ret;
181 }
182
183 switch (chan->type) {
184 case IIO_VOLTAGE:
185 *val = be16_to_cpu(data->buffer.resistance) &
186 CCS811_VOLTAGE_MASK;
187 ret = IIO_VAL_INT;
188 break;
189 case IIO_CURRENT:
190 *val = be16_to_cpu(data->buffer.resistance) >> 10;
191 ret = IIO_VAL_INT;
192 break;
193 case IIO_CONCENTRATION:
194 switch (chan->channel2) {
195 case IIO_MOD_CO2:
196 *val = be16_to_cpu(data->buffer.co2);
197 ret = IIO_VAL_INT;
198 break;
199 case IIO_MOD_VOC:
200 *val = be16_to_cpu(data->buffer.voc);
201 ret = IIO_VAL_INT;
202 break;
203 default:
204 ret = -EINVAL;
205 }
206 break;
207 default:
208 ret = -EINVAL;
209 }
210 mutex_unlock(&data->lock);
211
212 return ret;
213
214 case IIO_CHAN_INFO_SCALE:
215 switch (chan->type) {
216 case IIO_VOLTAGE:
217 *val = 1;
218 *val2 = 612903;
219 return IIO_VAL_INT_PLUS_MICRO;
220 case IIO_CURRENT:
221 *val = 0;
222 *val2 = 1000;
223 return IIO_VAL_INT_PLUS_MICRO;
224 case IIO_CONCENTRATION:
225 switch (chan->channel2) {
226 case IIO_MOD_CO2:
227 *val = 0;
228 *val2 = 12834;
229 return IIO_VAL_INT_PLUS_MICRO;
230 case IIO_MOD_VOC:
231 *val = 0;
232 *val2 = 84246;
233 return IIO_VAL_INT_PLUS_MICRO;
234 default:
235 return -EINVAL;
236 }
237 default:
238 return -EINVAL;
239 }
240 case IIO_CHAN_INFO_OFFSET:
241 if (!(chan->type == IIO_CONCENTRATION &&
242 chan->channel2 == IIO_MOD_CO2))
243 return -EINVAL;
244 *val = -400;
245 return IIO_VAL_INT;
246 default:
247 return -EINVAL;
248 }
249}
250
251static const struct iio_info ccs811_info = {
252 .read_raw = ccs811_read_raw,
253 .driver_module = THIS_MODULE,
254};
255
256static int ccs811_probe(struct i2c_client *client,
257 const struct i2c_device_id *id)
258{
259 struct iio_dev *indio_dev;
260 struct ccs811_data *data;
261 int ret;
262
263 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
264 | I2C_FUNC_SMBUS_BYTE_DATA
265 | I2C_FUNC_SMBUS_READ_I2C_BLOCK))
266 return -EOPNOTSUPP;
267
268 /* Check hardware id (should be 0x81 for this family of devices) */
269 ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID);
270 if (ret < 0)
271 return ret;
272
273 if (ret != CCS881_HW_ID_VALUE) {
274 dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
275 return -ENODEV;
276 }
277
278 ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION);
279 if (ret < 0)
280 return ret;
281
282 if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) {
283 dev_err(&client->dev, "no CCS811 sensor\n");
284 return -ENODEV;
285 }
286
287 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
288 if (!indio_dev)
289 return -ENOMEM;
290
291 ret = ccs811_setup(client);
292 if (ret < 0)
293 return ret;
294
295 data = iio_priv(indio_dev);
296 i2c_set_clientdata(client, indio_dev);
297 data->client = client;
298
299 mutex_init(&data->lock);
300
301 indio_dev->dev.parent = &client->dev;
302 indio_dev->name = id->name;
303 indio_dev->info = &ccs811_info;
304
305 indio_dev->channels = ccs811_channels;
306 indio_dev->num_channels = ARRAY_SIZE(ccs811_channels);
307
308 return iio_device_register(indio_dev);
309}
310
311static int ccs811_remove(struct i2c_client *client)
312{
313 struct iio_dev *indio_dev = i2c_get_clientdata(client);
314
315 iio_device_unregister(indio_dev);
316
317 return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
318 CCS811_MODE_IDLE);
319}
320
321static const struct i2c_device_id ccs811_id[] = {
322 {"ccs811", 0},
323 { }
324};
325MODULE_DEVICE_TABLE(i2c, ccs811_id);
326
327static struct i2c_driver ccs811_driver = {
328 .driver = {
329 .name = "ccs811",
330 },
331 .probe = ccs811_probe,
332 .remove = ccs811_remove,
333 .id_table = ccs811_id,
334};
335module_i2c_driver(ccs811_driver);
336
337MODULE_AUTHOR("Narcisa Vasile <narcisaanamaria12@gmail.com>");
338MODULE_DESCRIPTION("CCS811 volatile organic compounds sensor");
339MODULE_LICENSE("GPL v2");