0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include <linux/delay.h>
0019 #include <linux/gpio/consumer.h>
0020 #include <linux/i2c.h>
0021 #include <linux/iio/iio.h>
0022 #include <linux/iio/buffer.h>
0023 #include <linux/iio/trigger.h>
0024 #include <linux/iio/triggered_buffer.h>
0025 #include <linux/iio/trigger_consumer.h>
0026 #include <linux/module.h>
0027
0028 #define CCS811_STATUS 0x00
0029 #define CCS811_MEAS_MODE 0x01
0030 #define CCS811_ALG_RESULT_DATA 0x02
0031 #define CCS811_RAW_DATA 0x03
0032 #define CCS811_HW_ID 0x20
0033 #define CCS811_HW_ID_VALUE 0x81
0034 #define CCS811_HW_VERSION 0x21
0035 #define CCS811_HW_VERSION_VALUE 0x10
0036 #define CCS811_HW_VERSION_MASK 0xF0
0037 #define CCS811_ERR 0xE0
0038
0039 #define CCS811_APP_START 0xF4
0040 #define CCS811_SW_RESET 0xFF
0041
0042
0043 #define CCS811_STATUS_ERROR BIT(0)
0044 #define CCS811_STATUS_DATA_READY BIT(3)
0045 #define CCS811_STATUS_APP_VALID_MASK BIT(4)
0046 #define CCS811_STATUS_APP_VALID_LOADED BIT(4)
0047
0048
0049
0050
0051
0052 #define CCS811_STATUS_FW_MODE_MASK BIT(7)
0053 #define CCS811_STATUS_FW_MODE_APPLICATION BIT(7)
0054
0055
0056 #define CCS811_MODE_IDLE 0x00
0057 #define CCS811_MODE_IAQ_1SEC 0x10
0058 #define CCS811_MODE_IAQ_10SEC 0x20
0059 #define CCS811_MODE_IAQ_60SEC 0x30
0060 #define CCS811_MODE_RAW_DATA 0x40
0061
0062 #define CCS811_MEAS_MODE_INTERRUPT BIT(3)
0063
0064 #define CCS811_VOLTAGE_MASK 0x3FF
0065
0066 struct ccs811_reading {
0067 __be16 co2;
0068 __be16 voc;
0069 u8 status;
0070 u8 error;
0071 __be16 raw_data;
0072 } __attribute__((__packed__));
0073
0074 struct ccs811_data {
0075 struct i2c_client *client;
0076 struct mutex lock;
0077 struct ccs811_reading buffer;
0078 struct iio_trigger *drdy_trig;
0079 struct gpio_desc *wakeup_gpio;
0080 bool drdy_trig_on;
0081
0082 struct {
0083 s16 channels[2];
0084 s64 ts __aligned(8);
0085 } scan;
0086 };
0087
0088 static const struct iio_chan_spec ccs811_channels[] = {
0089 {
0090 .type = IIO_CURRENT,
0091 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0092 BIT(IIO_CHAN_INFO_SCALE),
0093 .scan_index = -1,
0094 }, {
0095 .type = IIO_VOLTAGE,
0096 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0097 BIT(IIO_CHAN_INFO_SCALE),
0098 .scan_index = -1,
0099 }, {
0100 .type = IIO_CONCENTRATION,
0101 .channel2 = IIO_MOD_CO2,
0102 .modified = 1,
0103 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0104 BIT(IIO_CHAN_INFO_SCALE),
0105 .scan_index = 0,
0106 .scan_type = {
0107 .sign = 'u',
0108 .realbits = 16,
0109 .storagebits = 16,
0110 .endianness = IIO_BE,
0111 },
0112 }, {
0113 .type = IIO_CONCENTRATION,
0114 .channel2 = IIO_MOD_VOC,
0115 .modified = 1,
0116 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0117 BIT(IIO_CHAN_INFO_SCALE),
0118 .scan_index = 1,
0119 .scan_type = {
0120 .sign = 'u',
0121 .realbits = 16,
0122 .storagebits = 16,
0123 .endianness = IIO_BE,
0124 },
0125 },
0126 IIO_CHAN_SOFT_TIMESTAMP(2),
0127 };
0128
0129
0130
0131
0132
0133 static int ccs811_start_sensor_application(struct i2c_client *client)
0134 {
0135 int ret;
0136
0137 ret = i2c_smbus_read_byte_data(client, CCS811_STATUS);
0138 if (ret < 0)
0139 return ret;
0140
0141 if ((ret & CCS811_STATUS_FW_MODE_APPLICATION))
0142 return 0;
0143
0144 if ((ret & CCS811_STATUS_APP_VALID_MASK) !=
0145 CCS811_STATUS_APP_VALID_LOADED)
0146 return -EIO;
0147
0148 ret = i2c_smbus_write_byte(client, CCS811_APP_START);
0149 if (ret < 0)
0150 return ret;
0151
0152 ret = i2c_smbus_read_byte_data(client, CCS811_STATUS);
0153 if (ret < 0)
0154 return ret;
0155
0156 if ((ret & CCS811_STATUS_FW_MODE_MASK) !=
0157 CCS811_STATUS_FW_MODE_APPLICATION) {
0158 dev_err(&client->dev, "Application failed to start. Sensor is still in boot mode.\n");
0159 return -EIO;
0160 }
0161
0162 return 0;
0163 }
0164
0165 static int ccs811_setup(struct i2c_client *client)
0166 {
0167 int ret;
0168
0169 ret = ccs811_start_sensor_application(client);
0170 if (ret < 0)
0171 return ret;
0172
0173 return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
0174 CCS811_MODE_IAQ_1SEC);
0175 }
0176
0177 static void ccs811_set_wakeup(struct ccs811_data *data, bool enable)
0178 {
0179 if (!data->wakeup_gpio)
0180 return;
0181
0182 gpiod_set_value(data->wakeup_gpio, enable);
0183
0184 if (enable)
0185 usleep_range(50, 60);
0186 else
0187 usleep_range(20, 30);
0188 }
0189
0190 static int ccs811_get_measurement(struct ccs811_data *data)
0191 {
0192 int ret, tries = 11;
0193
0194 ccs811_set_wakeup(data, true);
0195
0196
0197 while (tries-- > 0) {
0198 ret = i2c_smbus_read_byte_data(data->client, CCS811_STATUS);
0199 if (ret < 0)
0200 return ret;
0201
0202 if ((ret & CCS811_STATUS_DATA_READY) || tries == 0)
0203 break;
0204 msleep(100);
0205 }
0206 if (!(ret & CCS811_STATUS_DATA_READY))
0207 return -EIO;
0208
0209 ret = i2c_smbus_read_i2c_block_data(data->client,
0210 CCS811_ALG_RESULT_DATA, 8,
0211 (char *)&data->buffer);
0212 ccs811_set_wakeup(data, false);
0213
0214 return ret;
0215 }
0216
0217 static int ccs811_read_raw(struct iio_dev *indio_dev,
0218 struct iio_chan_spec const *chan,
0219 int *val, int *val2, long mask)
0220 {
0221 struct ccs811_data *data = iio_priv(indio_dev);
0222 int ret;
0223
0224 switch (mask) {
0225 case IIO_CHAN_INFO_RAW:
0226 ret = iio_device_claim_direct_mode(indio_dev);
0227 if (ret)
0228 return ret;
0229 mutex_lock(&data->lock);
0230 ret = ccs811_get_measurement(data);
0231 if (ret < 0) {
0232 mutex_unlock(&data->lock);
0233 iio_device_release_direct_mode(indio_dev);
0234 return ret;
0235 }
0236
0237 switch (chan->type) {
0238 case IIO_VOLTAGE:
0239 *val = be16_to_cpu(data->buffer.raw_data) &
0240 CCS811_VOLTAGE_MASK;
0241 ret = IIO_VAL_INT;
0242 break;
0243 case IIO_CURRENT:
0244 *val = be16_to_cpu(data->buffer.raw_data) >> 10;
0245 ret = IIO_VAL_INT;
0246 break;
0247 case IIO_CONCENTRATION:
0248 switch (chan->channel2) {
0249 case IIO_MOD_CO2:
0250 *val = be16_to_cpu(data->buffer.co2);
0251 ret = IIO_VAL_INT;
0252 break;
0253 case IIO_MOD_VOC:
0254 *val = be16_to_cpu(data->buffer.voc);
0255 ret = IIO_VAL_INT;
0256 break;
0257 default:
0258 ret = -EINVAL;
0259 }
0260 break;
0261 default:
0262 ret = -EINVAL;
0263 }
0264 mutex_unlock(&data->lock);
0265 iio_device_release_direct_mode(indio_dev);
0266
0267 return ret;
0268
0269 case IIO_CHAN_INFO_SCALE:
0270 switch (chan->type) {
0271 case IIO_VOLTAGE:
0272 *val = 1;
0273 *val2 = 612903;
0274 return IIO_VAL_INT_PLUS_MICRO;
0275 case IIO_CURRENT:
0276 *val = 0;
0277 *val2 = 1000;
0278 return IIO_VAL_INT_PLUS_MICRO;
0279 case IIO_CONCENTRATION:
0280 switch (chan->channel2) {
0281 case IIO_MOD_CO2:
0282 *val = 0;
0283 *val2 = 100;
0284 return IIO_VAL_INT_PLUS_MICRO;
0285 case IIO_MOD_VOC:
0286 *val = 0;
0287 *val2 = 100;
0288 return IIO_VAL_INT_PLUS_NANO;
0289 default:
0290 return -EINVAL;
0291 }
0292 default:
0293 return -EINVAL;
0294 }
0295 default:
0296 return -EINVAL;
0297 }
0298 }
0299
0300 static const struct iio_info ccs811_info = {
0301 .read_raw = ccs811_read_raw,
0302 };
0303
0304 static int ccs811_set_trigger_state(struct iio_trigger *trig,
0305 bool state)
0306 {
0307 struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
0308 struct ccs811_data *data = iio_priv(indio_dev);
0309 int ret;
0310
0311 ret = i2c_smbus_read_byte_data(data->client, CCS811_MEAS_MODE);
0312 if (ret < 0)
0313 return ret;
0314
0315 if (state)
0316 ret |= CCS811_MEAS_MODE_INTERRUPT;
0317 else
0318 ret &= ~CCS811_MEAS_MODE_INTERRUPT;
0319
0320 data->drdy_trig_on = state;
0321
0322 return i2c_smbus_write_byte_data(data->client, CCS811_MEAS_MODE, ret);
0323 }
0324
0325 static const struct iio_trigger_ops ccs811_trigger_ops = {
0326 .set_trigger_state = ccs811_set_trigger_state,
0327 };
0328
0329 static irqreturn_t ccs811_trigger_handler(int irq, void *p)
0330 {
0331 struct iio_poll_func *pf = p;
0332 struct iio_dev *indio_dev = pf->indio_dev;
0333 struct ccs811_data *data = iio_priv(indio_dev);
0334 struct i2c_client *client = data->client;
0335 int ret;
0336
0337 ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA,
0338 sizeof(data->scan.channels),
0339 (u8 *)data->scan.channels);
0340 if (ret != 4) {
0341 dev_err(&client->dev, "cannot read sensor data\n");
0342 goto err;
0343 }
0344
0345 iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
0346 iio_get_time_ns(indio_dev));
0347
0348 err:
0349 iio_trigger_notify_done(indio_dev->trig);
0350
0351 return IRQ_HANDLED;
0352 }
0353
0354 static irqreturn_t ccs811_data_rdy_trigger_poll(int irq, void *private)
0355 {
0356 struct iio_dev *indio_dev = private;
0357 struct ccs811_data *data = iio_priv(indio_dev);
0358
0359 if (data->drdy_trig_on)
0360 iio_trigger_poll(data->drdy_trig);
0361
0362 return IRQ_HANDLED;
0363 }
0364
0365 static int ccs811_reset(struct i2c_client *client)
0366 {
0367 struct gpio_desc *reset_gpio;
0368 int ret;
0369
0370 reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
0371 GPIOD_OUT_LOW);
0372 if (IS_ERR(reset_gpio))
0373 return PTR_ERR(reset_gpio);
0374
0375
0376 if (reset_gpio) {
0377 gpiod_set_value(reset_gpio, 1);
0378 usleep_range(20, 30);
0379 gpiod_set_value(reset_gpio, 0);
0380 } else {
0381
0382
0383
0384
0385
0386 static const u8 reset_seq[] = {
0387 0x11, 0xE5, 0x72, 0x8A,
0388 };
0389
0390 ret = i2c_smbus_write_i2c_block_data(client, CCS811_SW_RESET,
0391 sizeof(reset_seq), reset_seq);
0392 if (ret < 0) {
0393 dev_err(&client->dev, "Failed to reset sensor\n");
0394 return ret;
0395 }
0396 }
0397
0398
0399 usleep_range(1000, 2000);
0400
0401 return 0;
0402 }
0403
0404 static int ccs811_probe(struct i2c_client *client,
0405 const struct i2c_device_id *id)
0406 {
0407 struct iio_dev *indio_dev;
0408 struct ccs811_data *data;
0409 int ret;
0410
0411 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
0412 | I2C_FUNC_SMBUS_BYTE_DATA
0413 | I2C_FUNC_SMBUS_READ_I2C_BLOCK))
0414 return -EOPNOTSUPP;
0415
0416 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0417 if (!indio_dev)
0418 return -ENOMEM;
0419
0420 data = iio_priv(indio_dev);
0421 i2c_set_clientdata(client, indio_dev);
0422 data->client = client;
0423
0424 data->wakeup_gpio = devm_gpiod_get_optional(&client->dev, "wakeup",
0425 GPIOD_OUT_HIGH);
0426 if (IS_ERR(data->wakeup_gpio))
0427 return PTR_ERR(data->wakeup_gpio);
0428
0429 ccs811_set_wakeup(data, true);
0430
0431 ret = ccs811_reset(client);
0432 if (ret) {
0433 ccs811_set_wakeup(data, false);
0434 return ret;
0435 }
0436
0437
0438 ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID);
0439 if (ret < 0) {
0440 ccs811_set_wakeup(data, false);
0441 return ret;
0442 }
0443
0444 if (ret != CCS811_HW_ID_VALUE) {
0445 dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
0446 ccs811_set_wakeup(data, false);
0447 return -ENODEV;
0448 }
0449
0450 ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION);
0451 if (ret < 0) {
0452 ccs811_set_wakeup(data, false);
0453 return ret;
0454 }
0455
0456 if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) {
0457 dev_err(&client->dev, "no CCS811 sensor\n");
0458 ccs811_set_wakeup(data, false);
0459 return -ENODEV;
0460 }
0461
0462 ret = ccs811_setup(client);
0463 if (ret < 0) {
0464 ccs811_set_wakeup(data, false);
0465 return ret;
0466 }
0467
0468 ccs811_set_wakeup(data, false);
0469
0470 mutex_init(&data->lock);
0471
0472 indio_dev->name = id->name;
0473 indio_dev->info = &ccs811_info;
0474 indio_dev->modes = INDIO_DIRECT_MODE;
0475
0476 indio_dev->channels = ccs811_channels;
0477 indio_dev->num_channels = ARRAY_SIZE(ccs811_channels);
0478
0479 if (client->irq > 0) {
0480 ret = devm_request_threaded_irq(&client->dev, client->irq,
0481 ccs811_data_rdy_trigger_poll,
0482 NULL,
0483 IRQF_TRIGGER_FALLING |
0484 IRQF_ONESHOT,
0485 "ccs811_irq", indio_dev);
0486 if (ret) {
0487 dev_err(&client->dev, "irq request error %d\n", -ret);
0488 goto err_poweroff;
0489 }
0490
0491 data->drdy_trig = devm_iio_trigger_alloc(&client->dev,
0492 "%s-dev%d",
0493 indio_dev->name,
0494 iio_device_id(indio_dev));
0495 if (!data->drdy_trig) {
0496 ret = -ENOMEM;
0497 goto err_poweroff;
0498 }
0499
0500 data->drdy_trig->ops = &ccs811_trigger_ops;
0501 iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
0502 ret = iio_trigger_register(data->drdy_trig);
0503 if (ret)
0504 goto err_poweroff;
0505
0506 indio_dev->trig = iio_trigger_get(data->drdy_trig);
0507 }
0508
0509 ret = iio_triggered_buffer_setup(indio_dev, NULL,
0510 ccs811_trigger_handler, NULL);
0511
0512 if (ret < 0) {
0513 dev_err(&client->dev, "triggered buffer setup failed\n");
0514 goto err_trigger_unregister;
0515 }
0516
0517 ret = iio_device_register(indio_dev);
0518 if (ret < 0) {
0519 dev_err(&client->dev, "unable to register iio device\n");
0520 goto err_buffer_cleanup;
0521 }
0522 return 0;
0523
0524 err_buffer_cleanup:
0525 iio_triggered_buffer_cleanup(indio_dev);
0526 err_trigger_unregister:
0527 if (data->drdy_trig)
0528 iio_trigger_unregister(data->drdy_trig);
0529 err_poweroff:
0530 i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE, CCS811_MODE_IDLE);
0531
0532 return ret;
0533 }
0534
0535 static int ccs811_remove(struct i2c_client *client)
0536 {
0537 struct iio_dev *indio_dev = i2c_get_clientdata(client);
0538 struct ccs811_data *data = iio_priv(indio_dev);
0539 int ret;
0540
0541 iio_device_unregister(indio_dev);
0542 iio_triggered_buffer_cleanup(indio_dev);
0543 if (data->drdy_trig)
0544 iio_trigger_unregister(data->drdy_trig);
0545
0546 ret = i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
0547 CCS811_MODE_IDLE);
0548 if (ret)
0549 dev_warn(&client->dev, "Failed to power down device (%pe)\n",
0550 ERR_PTR(ret));
0551
0552 return 0;
0553 }
0554
0555 static const struct i2c_device_id ccs811_id[] = {
0556 {"ccs811", 0},
0557 { }
0558 };
0559 MODULE_DEVICE_TABLE(i2c, ccs811_id);
0560
0561 static const struct of_device_id ccs811_dt_ids[] = {
0562 { .compatible = "ams,ccs811" },
0563 { }
0564 };
0565 MODULE_DEVICE_TABLE(of, ccs811_dt_ids);
0566
0567 static struct i2c_driver ccs811_driver = {
0568 .driver = {
0569 .name = "ccs811",
0570 .of_match_table = ccs811_dt_ids,
0571 },
0572 .probe = ccs811_probe,
0573 .remove = ccs811_remove,
0574 .id_table = ccs811_id,
0575 };
0576 module_i2c_driver(ccs811_driver);
0577
0578 MODULE_AUTHOR("Narcisa Vasile <narcisaanamaria12@gmail.com>");
0579 MODULE_DESCRIPTION("CCS811 volatile organic compounds sensor");
0580 MODULE_LICENSE("GPL v2");