linux/drivers/iio/chemical/sps30.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Sensirion SPS30 particulate matter sensor driver
   4 *
   5 * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
   6 */
   7
   8#include <linux/crc8.h>
   9#include <linux/delay.h>
  10#include <linux/i2c.h>
  11#include <linux/iio/buffer.h>
  12#include <linux/iio/iio.h>
  13#include <linux/iio/sysfs.h>
  14#include <linux/iio/trigger_consumer.h>
  15#include <linux/iio/triggered_buffer.h>
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18
  19#include "sps30.h"
  20
  21/* sensor measures reliably up to 3000 ug / m3 */
  22#define SPS30_MAX_PM 3000
  23/* minimum and maximum self cleaning periods in seconds */
  24#define SPS30_AUTO_CLEANING_PERIOD_MIN 0
  25#define SPS30_AUTO_CLEANING_PERIOD_MAX 604800
  26
  27enum {
  28        PM1,
  29        PM2P5,
  30        PM4,
  31        PM10,
  32};
  33
  34enum {
  35        RESET,
  36        MEASURING,
  37};
  38
  39static s32 sps30_float_to_int_clamped(__be32 *fp)
  40{
  41        int val = be32_to_cpup(fp);
  42        int mantissa = val & GENMASK(22, 0);
  43        /* this is fine since passed float is always non-negative */
  44        int exp = val >> 23;
  45        int fraction, shift;
  46
  47        /* special case 0 */
  48        if (!exp && !mantissa)
  49                return 0;
  50
  51        exp -= 127;
  52        if (exp < 0) {
  53                /* return values ranging from 1 to 99 */
  54                return ((((1 << 23) + mantissa) * 100) >> 23) >> (-exp);
  55        }
  56
  57        /* return values ranging from 100 to 300000 */
  58        shift = 23 - exp;
  59        val = (1 << exp) + (mantissa >> shift);
  60        if (val >= SPS30_MAX_PM)
  61                return SPS30_MAX_PM * 100;
  62
  63        fraction = mantissa & GENMASK(shift - 1, 0);
  64
  65        return val * 100 + ((fraction * 100) >> shift);
  66}
  67
  68static int sps30_do_meas(struct sps30_state *state, s32 *data, int size)
  69{
  70        int i, ret;
  71
  72        if (state->state == RESET) {
  73                ret = state->ops->start_meas(state);
  74                if (ret)
  75                        return ret;
  76
  77                state->state = MEASURING;
  78        }
  79
  80        ret = state->ops->read_meas(state, (__be32 *)data, size);
  81        if (ret)
  82                return ret;
  83
  84        for (i = 0; i < size; i++)
  85                data[i] = sps30_float_to_int_clamped((__be32 *)&data[i]);
  86
  87        return 0;
  88}
  89
  90static int sps30_do_reset(struct sps30_state *state)
  91{
  92        int ret;
  93
  94        ret = state->ops->reset(state);
  95        if (ret)
  96                return ret;
  97
  98        state->state = RESET;
  99
 100        return 0;
 101}
 102
 103static irqreturn_t sps30_trigger_handler(int irq, void *p)
 104{
 105        struct iio_poll_func *pf = p;
 106        struct iio_dev *indio_dev = pf->indio_dev;
 107        struct sps30_state *state = iio_priv(indio_dev);
 108        int ret;
 109        struct {
 110                s32 data[4]; /* PM1, PM2P5, PM4, PM10 */
 111                s64 ts;
 112        } scan;
 113
 114        mutex_lock(&state->lock);
 115        ret = sps30_do_meas(state, scan.data, ARRAY_SIZE(scan.data));
 116        mutex_unlock(&state->lock);
 117        if (ret)
 118                goto err;
 119
 120        iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 121                                           iio_get_time_ns(indio_dev));
 122err:
 123        iio_trigger_notify_done(indio_dev->trig);
 124
 125        return IRQ_HANDLED;
 126}
 127
 128static int sps30_read_raw(struct iio_dev *indio_dev,
 129                          struct iio_chan_spec const *chan,
 130                          int *val, int *val2, long mask)
 131{
 132        struct sps30_state *state = iio_priv(indio_dev);
 133        int data[4], ret = -EINVAL;
 134
 135        switch (mask) {
 136        case IIO_CHAN_INFO_PROCESSED:
 137                switch (chan->type) {
 138                case IIO_MASSCONCENTRATION:
 139                        mutex_lock(&state->lock);
 140                        /* read up to the number of bytes actually needed */
 141                        switch (chan->channel2) {
 142                        case IIO_MOD_PM1:
 143                                ret = sps30_do_meas(state, data, 1);
 144                                break;
 145                        case IIO_MOD_PM2P5:
 146                                ret = sps30_do_meas(state, data, 2);
 147                                break;
 148                        case IIO_MOD_PM4:
 149                                ret = sps30_do_meas(state, data, 3);
 150                                break;
 151                        case IIO_MOD_PM10:
 152                                ret = sps30_do_meas(state, data, 4);
 153                                break;
 154                        }
 155                        mutex_unlock(&state->lock);
 156                        if (ret)
 157                                return ret;
 158
 159                        *val = data[chan->address] / 100;
 160                        *val2 = (data[chan->address] % 100) * 10000;
 161
 162                        return IIO_VAL_INT_PLUS_MICRO;
 163                default:
 164                        return -EINVAL;
 165                }
 166        case IIO_CHAN_INFO_SCALE:
 167                switch (chan->type) {
 168                case IIO_MASSCONCENTRATION:
 169                        switch (chan->channel2) {
 170                        case IIO_MOD_PM1:
 171                        case IIO_MOD_PM2P5:
 172                        case IIO_MOD_PM4:
 173                        case IIO_MOD_PM10:
 174                                *val = 0;
 175                                *val2 = 10000;
 176
 177                                return IIO_VAL_INT_PLUS_MICRO;
 178                        default:
 179                                return -EINVAL;
 180                        }
 181                default:
 182                        return -EINVAL;
 183                }
 184        }
 185
 186        return -EINVAL;
 187}
 188
 189static ssize_t start_cleaning_store(struct device *dev,
 190                                    struct device_attribute *attr,
 191                                    const char *buf, size_t len)
 192{
 193        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 194        struct sps30_state *state = iio_priv(indio_dev);
 195        int val, ret;
 196
 197        if (kstrtoint(buf, 0, &val) || val != 1)
 198                return -EINVAL;
 199
 200        mutex_lock(&state->lock);
 201        ret = state->ops->clean_fan(state);
 202        mutex_unlock(&state->lock);
 203        if (ret)
 204                return ret;
 205
 206        return len;
 207}
 208
 209static ssize_t cleaning_period_show(struct device *dev,
 210                                    struct device_attribute *attr,
 211                                    char *buf)
 212{
 213        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 214        struct sps30_state *state = iio_priv(indio_dev);
 215        __be32 val;
 216        int ret;
 217
 218        mutex_lock(&state->lock);
 219        ret = state->ops->read_cleaning_period(state, &val);
 220        mutex_unlock(&state->lock);
 221        if (ret)
 222                return ret;
 223
 224        return sprintf(buf, "%d\n", be32_to_cpu(val));
 225}
 226
 227static ssize_t cleaning_period_store(struct device *dev, struct device_attribute *attr,
 228                                     const char *buf, size_t len)
 229{
 230        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 231        struct sps30_state *state = iio_priv(indio_dev);
 232        int val, ret;
 233
 234        if (kstrtoint(buf, 0, &val))
 235                return -EINVAL;
 236
 237        if ((val < SPS30_AUTO_CLEANING_PERIOD_MIN) ||
 238            (val > SPS30_AUTO_CLEANING_PERIOD_MAX))
 239                return -EINVAL;
 240
 241        mutex_lock(&state->lock);
 242        ret = state->ops->write_cleaning_period(state, cpu_to_be32(val));
 243        if (ret) {
 244                mutex_unlock(&state->lock);
 245                return ret;
 246        }
 247
 248        msleep(20);
 249
 250        /*
 251         * sensor requires reset in order to return up to date self cleaning
 252         * period
 253         */
 254        ret = sps30_do_reset(state);
 255        if (ret)
 256                dev_warn(dev,
 257                         "period changed but reads will return the old value\n");
 258
 259        mutex_unlock(&state->lock);
 260
 261        return len;
 262}
 263
 264static ssize_t cleaning_period_available_show(struct device *dev,
 265                                              struct device_attribute *attr,
 266                                              char *buf)
 267{
 268        return sysfs_emit(buf, "[%d %d %d]\n",
 269                          SPS30_AUTO_CLEANING_PERIOD_MIN, 1,
 270                          SPS30_AUTO_CLEANING_PERIOD_MAX);
 271}
 272
 273static IIO_DEVICE_ATTR_WO(start_cleaning, 0);
 274static IIO_DEVICE_ATTR_RW(cleaning_period, 0);
 275static IIO_DEVICE_ATTR_RO(cleaning_period_available, 0);
 276
 277static struct attribute *sps30_attrs[] = {
 278        &iio_dev_attr_start_cleaning.dev_attr.attr,
 279        &iio_dev_attr_cleaning_period.dev_attr.attr,
 280        &iio_dev_attr_cleaning_period_available.dev_attr.attr,
 281        NULL
 282};
 283
 284static const struct attribute_group sps30_attr_group = {
 285        .attrs = sps30_attrs,
 286};
 287
 288static const struct iio_info sps30_info = {
 289        .attrs = &sps30_attr_group,
 290        .read_raw = sps30_read_raw,
 291};
 292
 293#define SPS30_CHAN(_index, _mod) { \
 294        .type = IIO_MASSCONCENTRATION, \
 295        .modified = 1, \
 296        .channel2 = IIO_MOD_ ## _mod, \
 297        .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
 298        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
 299        .address = _mod, \
 300        .scan_index = _index, \
 301        .scan_type = { \
 302                .sign = 'u', \
 303                .realbits = 19, \
 304                .storagebits = 32, \
 305                .endianness = IIO_CPU, \
 306        }, \
 307}
 308
 309static const struct iio_chan_spec sps30_channels[] = {
 310        SPS30_CHAN(0, PM1),
 311        SPS30_CHAN(1, PM2P5),
 312        SPS30_CHAN(2, PM4),
 313        SPS30_CHAN(3, PM10),
 314        IIO_CHAN_SOFT_TIMESTAMP(4),
 315};
 316
 317static void sps30_devm_stop_meas(void *data)
 318{
 319        struct sps30_state *state = data;
 320
 321        if (state->state == MEASURING)
 322                state->ops->stop_meas(state);
 323}
 324
 325static const unsigned long sps30_scan_masks[] = { 0x0f, 0x00 };
 326
 327int sps30_probe(struct device *dev, const char *name, void *priv, const struct sps30_ops *ops)
 328{
 329        struct iio_dev *indio_dev;
 330        struct sps30_state *state;
 331        int ret;
 332
 333        indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
 334        if (!indio_dev)
 335                return -ENOMEM;
 336
 337        dev_set_drvdata(dev, indio_dev);
 338
 339        state = iio_priv(indio_dev);
 340        state->dev = dev;
 341        state->priv = priv;
 342        state->ops = ops;
 343        mutex_init(&state->lock);
 344
 345        indio_dev->info = &sps30_info;
 346        indio_dev->name = name;
 347        indio_dev->channels = sps30_channels;
 348        indio_dev->num_channels = ARRAY_SIZE(sps30_channels);
 349        indio_dev->modes = INDIO_DIRECT_MODE;
 350        indio_dev->available_scan_masks = sps30_scan_masks;
 351
 352        ret = sps30_do_reset(state);
 353        if (ret) {
 354                dev_err(dev, "failed to reset device\n");
 355                return ret;
 356        }
 357
 358        ret = state->ops->show_info(state);
 359        if (ret) {
 360                dev_err(dev, "failed to read device info\n");
 361                return ret;
 362        }
 363
 364        ret = devm_add_action_or_reset(dev, sps30_devm_stop_meas, state);
 365        if (ret)
 366                return ret;
 367
 368        ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
 369                                              sps30_trigger_handler, NULL);
 370        if (ret)
 371                return ret;
 372
 373        return devm_iio_device_register(dev, indio_dev);
 374}
 375EXPORT_SYMBOL_GPL(sps30_probe);
 376
 377MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
 378MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor driver");
 379MODULE_LICENSE("GPL v2");
 380