From patchwork Sat Nov 24 22:14:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Duszynski X-Patchwork-Id: 10696581 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B436D13AD for ; Sat, 24 Nov 2018 22:14:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A3D86295E9 for ; Sat, 24 Nov 2018 22:14:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 965F629F58; Sat, 24 Nov 2018 22:14:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1C74A295E9 for ; Sat, 24 Nov 2018 22:14:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726552AbeKYJEE (ORCPT ); Sun, 25 Nov 2018 04:04:04 -0500 Received: from mail-lj1-f193.google.com ([209.85.208.193]:37965 "EHLO mail-lj1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726317AbeKYJEE (ORCPT ); Sun, 25 Nov 2018 04:04:04 -0500 Received: by mail-lj1-f193.google.com with SMTP id c19-v6so13357405lja.5; Sat, 24 Nov 2018 14:14:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yCtBduGV4B1E1QfmnGTbr9pPcIEi4Z8uiLxVSHUATEY=; b=uaX2cJ8jR89J/vIbthqKpO/SCmxkg17OzwEn6bIgahoPqUfE8pGRhdoZFjfBaZQdem g6dawmC5mXH3KoTmNj7KbIGSkJDlZvtFx+rWii4JmlZpwtProoIFydmsJO4y3UsQvxWt IxBAuSp5IXqHuMUh7a/1GhtvHugykSFDFBlPxKwUBn+cLdiGRqPE/AVl49X2pMVuJPL6 V2ycLS7/4XAAuPSxIEdT6USGnD9mQEF5plct6mraxF/iqhsY5AP6mTjE2Hu5xBAi4L4G q3K01o5WnT3x6o49fH0dw68ooHrK6WmIdoFMNkYlfNd8rgHYDVP7vHM2Pv6+OHyTlWL1 JCCw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=yCtBduGV4B1E1QfmnGTbr9pPcIEi4Z8uiLxVSHUATEY=; b=j1kZiO11Ypbg+Eat8LnFVNEF1CaMtdaPbzmVvXXUzobkCUgXmjaiidms2Vn+r2TLr+ PoQcGsX1YPPZoZFu6PlQiSNhjMSrJKQOliTwQIfJWDQTeEMbu9IncUJlS4dl+tzvD34H 8JLG+qmLTRZFPGgu91aVChTe0IWQNUP8Btx5q+gUwwb0RwT9nazE3DeeWy1rjgOA0Hgn Md8wQx+ORWgU0Ic6gYThXfuGNgzndwx84vns6/K+DrsCnd29SA5fOtr/UMJ55Eayd9OV v8uIDhftItAs8kWPnJFUn7hRIqFegx91DtHVeW6gcnuqVl+uXZ2mTYVVXo+tvfN81kps oILw== X-Gm-Message-State: AA+aEWaOO+6JWgF2h7GmCC3ZN3uMnmrAC/g1pO44q2Fmpy0HF2Bn9A6l OBOwUTRcAxMkFu9SZkdkmmhMgyX61HI= X-Google-Smtp-Source: AFSGD/VEFaUyMM9OcAkI6LFl3NP/CMa+QQk1y73CjWU8ycaM0imC6KQXtpI1wz5bb1ATvXLoLaSZPA== X-Received: by 2002:a2e:6503:: with SMTP id z3-v6mr12939024ljb.153.1543097675219; Sat, 24 Nov 2018 14:14:35 -0800 (PST) Received: from arch.domain.name (89-70-226-70.dynamic.chello.pl. [89.70.226.70]) by smtp.gmail.com with ESMTPSA id x16sm8369281lff.26.2018.11.24.14.14.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 24 Nov 2018 14:14:34 -0800 (PST) From: Tomasz Duszynski To: linux-iio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Tomasz Duszynski Subject: [PATCH 1/3] iio: add IIO_MASSCONCENTRATION channel type Date: Sat, 24 Nov 2018 23:14:13 +0100 Message-Id: <20181124221415.10081-2-tduszyns@gmail.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181124221415.10081-1-tduszyns@gmail.com> References: <20181124221415.10081-1-tduszyns@gmail.com> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Measuring particulate matter in ug / m3 (micro-grams per cubic meter) is de facto standard. Existing air quality sensors usually follow this convention and are capable of returning measurements using this unit. IIO currently does not offer suitable channel type for this type of measurements hence this patch adds this. In addition, two modifiers are introduced used for distinguishing between coarse (PM10) and fine particles (PM2p5) measurements, i.e IIO_MOD_PM10 and IIO_MOD_PM2p5. Signed-off-by: Tomasz Duszynski --- Documentation/ABI/testing/sysfs-bus-iio | 11 ++++++++++- drivers/iio/industrialio-core.c | 3 +++ include/uapi/linux/iio/types.h | 3 +++ tools/iio/iio_event_monitor.c | 6 ++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 8127a08e366d..ce0ed140660d 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1684,4 +1684,13 @@ KernelVersion: 4.18 Contact: linux-iio@vger.kernel.org Description: Raw (unscaled) phase difference reading from channel Y - that can be processed to radians. \ No newline at end of file + that can be processed to radians. + +What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm2p5_input +What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm2p5_input +What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm10_input +What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm10_input +KernelVersion: 4.21 +Contact: linux-iio@vger.kernel.org +Description: + Mass concentration reading of particulate matter in ug / m3. diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index a062cfddc5af..2a9ef600c1fb 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -87,6 +87,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_GRAVITY] = "gravity", [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", + [IIO_MASSCONCENTRATION] = "massconcentration", }; static const char * const iio_modifier_names[] = { @@ -127,6 +128,8 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_Q] = "q", [IIO_MOD_CO2] = "co2", [IIO_MOD_VOC] = "voc", + [IIO_MOD_PM2p5] = "pm2p5", + [IIO_MOD_PM10] = "pm10", }; /* relies on pairs of these shared then separate */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 92baabc103ac..465044b42af5 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -46,6 +46,7 @@ enum iio_chan_type { IIO_GRAVITY, IIO_POSITIONRELATIVE, IIO_PHASE, + IIO_MASSCONCENTRATION, }; enum iio_modifier { @@ -87,6 +88,8 @@ enum iio_modifier { IIO_MOD_VOC, IIO_MOD_LIGHT_UV, IIO_MOD_LIGHT_DUV, + IIO_MOD_PM2p5, + IIO_MOD_PM10, }; enum iio_event_type { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index ac2de6b7e89f..f0fcfeddba2b 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -60,6 +60,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_GRAVITY] = "gravity", [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", + [IIO_MASSCONCENTRATION] = "massconcentration", }; static const char * const iio_ev_type_text[] = { @@ -115,6 +116,8 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_Q] = "q", [IIO_MOD_CO2] = "co2", [IIO_MOD_VOC] = "voc", + [IIO_MOD_PM2p5] = "pm2p5", + [IIO_MOD_PM10] = "pm10", }; static bool event_is_known(struct iio_event_data *event) @@ -156,6 +159,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_GRAVITY: case IIO_POSITIONRELATIVE: case IIO_PHASE: + case IIO_MASSCONCENTRATION: break; default: return false; @@ -200,6 +204,8 @@ static bool event_is_known(struct iio_event_data *event) case IIO_MOD_Q: case IIO_MOD_CO2: case IIO_MOD_VOC: + case IIO_MOD_PM2p5: + case IIO_MOD_PM10: break; default: return false; From patchwork Sat Nov 24 22:14:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Duszynski X-Patchwork-Id: 10696577 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C9A9A13AD for ; Sat, 24 Nov 2018 22:14:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B7D0D295E9 for ; Sat, 24 Nov 2018 22:14:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AB5FD29F58; Sat, 24 Nov 2018 22:14:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7A791295E9 for ; Sat, 24 Nov 2018 22:14:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726620AbeKYJEG (ORCPT ); Sun, 25 Nov 2018 04:04:06 -0500 Received: from mail-lj1-f194.google.com ([209.85.208.194]:40175 "EHLO mail-lj1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726353AbeKYJEF (ORCPT ); Sun, 25 Nov 2018 04:04:05 -0500 Received: by mail-lj1-f194.google.com with SMTP id n18-v6so13356758lji.7; Sat, 24 Nov 2018 14:14:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3lASiJ+glt9uNF9n9xfrkuuBHN9E0fTN/Qr03Tfcz6w=; b=eAoEX2JZjUbIOpivdguDjnu27LFepsiIXh9o7xULUPvXEwuMR/2PRF0ltpM0idckYq KYMuk7XkPzKp4vuu3Bb308W/KoXS08kbpn1/MkT/CLEZ8onv0qPQCMPp+ZF8VHQ4w/qm b47p8c22kDRp40wvCOQosftab0PiqqVynHtTnwk7/g+51oXLCmMFqRE0FI6dvI6fEwha mxL73h/9ZnNuWsau8DG8SP4tLkPyYKOW9m7KcTHQJpjRFyMLouUdE5hz+6kKuyvGIEp1 b0Ob9HdjnN7i0qOZwFNonXvx6T2mfd37AfIf7T528gGEqpQM+ViVlIzdKU6fX9PKJ3G2 8C5A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3lASiJ+glt9uNF9n9xfrkuuBHN9E0fTN/Qr03Tfcz6w=; b=LBe6I/yjgUo75/F68KC2kM+iALWFOjBieXpK4c8PRo3uGspYP59m2umC9Lvnb+QxQ8 kDiC0FbABakZbQlXDsJiH+McJo/70LhigdI2eM+sZ6lDn9u+IiOkryN4O8TxvkdtLg40 brMqfIH7dklWDSa4SsiUaBrDIf/ka43gi0XtYr0VmeEK97+BlAm3GvRKy7vlUJdRlUyn 2gLgjvgKMisrUcumymwUCQFCj+7XSY3jZAG/qwdoEtxp5xfLgOENExiWjBJRwle8Y9/3 RI+u85h5kTV166W+jvJ3j+UGa9wXXBPZil+RwyZaAIIPpZ8mwvKOUFEZZA2Dp7NpaVt/ Y/CQ== X-Gm-Message-State: AA+aEWZ/1YXSQBs3Xh4wkL7U3mRD96dYimIGqQ0iepsURmoK73d9jCOz c3nmMmKZt/Y62T2fXFTkgjadxEqvA/I= X-Google-Smtp-Source: AFSGD/WcmJcgPVJ2TO4p4YA0dP3Ct4QFt17KoK+BGhpnmihVkad/FNYASYAeWSnfFmKKD/TzJNQ5Bg== X-Received: by 2002:a2e:9b15:: with SMTP id u21-v6mr3103124lji.29.1543097676205; Sat, 24 Nov 2018 14:14:36 -0800 (PST) Received: from arch.domain.name (89-70-226-70.dynamic.chello.pl. [89.70.226.70]) by smtp.gmail.com with ESMTPSA id x16sm8369281lff.26.2018.11.24.14.14.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 24 Nov 2018 14:14:35 -0800 (PST) From: Tomasz Duszynski To: linux-iio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Tomasz Duszynski Subject: [PATCH 2/3] iio: chemical: add support for Sensirion SPS30 sensor Date: Sat, 24 Nov 2018 23:14:14 +0100 Message-Id: <20181124221415.10081-3-tduszyns@gmail.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181124221415.10081-1-tduszyns@gmail.com> References: <20181124221415.10081-1-tduszyns@gmail.com> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for Sensirion SPS30 particulate matter sensor. Signed-off-by: Tomasz Duszynski Acked-by: Andreas Brauchli --- drivers/iio/chemical/Kconfig | 11 ++ drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/sps30.c | 359 ++++++++++++++++++++++++++++++++++ 3 files changed, 371 insertions(+) create mode 100644 drivers/iio/chemical/sps30.c diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index b8e005be4f87..40057ecf8130 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -61,6 +61,17 @@ config IAQCORE iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds) sensors +config SPS30 + tristate "SPS30 Particulate Matter sensor" + depends on I2C + select CRC8 + help + Say Y here to build support for the Sensirion SPS30 Particulate + Matter sensor. + + To compile this driver as a module, choose M here: the module will + be called sps30. + config VZ89X tristate "SGX Sensortech MiCS VZ89X VOC sensor" depends on I2C diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile index 2f4c4ba4d781..9f42f4252151 100644 --- a/drivers/iio/chemical/Makefile +++ b/drivers/iio/chemical/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_BME680_I2C) += bme680_i2c.o obj-$(CONFIG_BME680_SPI) += bme680_spi.o obj-$(CONFIG_CCS811) += ccs811.o obj-$(CONFIG_IAQCORE) += ams-iaq-core.o +obj-$(CONFIG_SPS30) += sps30.o obj-$(CONFIG_VZ89X) += vz89x.o diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c new file mode 100644 index 000000000000..bf802621ae7f --- /dev/null +++ b/drivers/iio/chemical/sps30.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sensirion SPS30 Particulate Matter sensor driver + * + * Copyright (c) Tomasz Duszynski + * + * I2C slave address: 0x69 + * + * TODO: + * - support for turning on fan cleaning + * - support for reading/setting auto cleaning interval + */ + +#define pr_fmt(fmt) "sps30: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPS30_CRC8_POLYNOMIAL 0x31 + +/* SPS30 commands */ +#define SPS30_START_MEAS 0x0010 +#define SPS30_STOP_MEAS 0x0104 +#define SPS30_RESET 0xd304 +#define SPS30_READ_DATA_READY_FLAG 0x0202 +#define SPS30_READ_DATA 0x0300 +#define SPS30_READ_SERIAL 0xD033 + +#define SPS30_CHAN(_index, _mod) { \ + .type = IIO_MASSCONCENTRATION, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## _mod, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 32, \ + .endianness = IIO_CPU, \ + }, \ +} + +enum { + PM1p0, /* just a placeholder */ + PM2p5, + PM4p0, /* just a placeholder */ + PM10, +}; + +struct sps30_state { + struct i2c_client *client; + /* guards against concurrent access to sensor registers */ + struct mutex lock; +}; + +DECLARE_CRC8_TABLE(sps30_crc8_table); + +static int sps30_write_then_read(struct sps30_state *state, u8 *buf, + int buf_size, u8 *data, int data_size) +{ + /* every two received data bytes are checksummed */ + u8 tmp[data_size + data_size / 2]; + int ret, i; + + /* + * Sensor does not support repeated start so instead of + * sending two i2c messages in a row we just send one by one. + */ + ret = i2c_master_send(state->client, buf, buf_size); + if (ret != buf_size) + return ret < 0 ? ret : -EIO; + + if (!data) + return 0; + + ret = i2c_master_recv(state->client, tmp, sizeof(tmp)); + if (ret != sizeof(tmp)) + return ret < 0 ? ret : -EIO; + + for (i = 0; i < sizeof(tmp); i += 3) { + u8 crc = crc8(sps30_crc8_table, &tmp[i], 2, CRC8_INIT_VALUE); + + if (crc != tmp[i + 2]) { + dev_err(&state->client->dev, + "data integrity check failed\n"); + return -EIO; + } + + *data++ = tmp[i]; + *data++ = tmp[i + 1]; + } + + return 0; +} + +static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size) +{ + /* depending on the command up to 3 bytes may be needed for argument */ + u8 buf[sizeof(cmd) + 3] = { cmd >> 8, cmd }; + + switch (cmd) { + case SPS30_START_MEAS: + buf[2] = 0x03; + buf[3] = 0x00; + buf[4] = 0xac; /* precomputed crc */ + return sps30_write_then_read(state, buf, 5, NULL, 0); + case SPS30_STOP_MEAS: + case SPS30_RESET: + return sps30_write_then_read(state, buf, 2, NULL, 0); + case SPS30_READ_DATA_READY_FLAG: + case SPS30_READ_DATA: + case SPS30_READ_SERIAL: + return sps30_write_then_read(state, buf, 2, data, size); + default: + return -EINVAL; + }; +} + +static int sps30_ieee754_to_int(const u8 *data) +{ + u32 val = ((u32)data[0] << 24) | ((u32)data[1] << 16) | + ((u32)data[2] << 8) | (u32)data[3], + mantissa = (val << 9) >> 9; + int exp = (val >> 23) - 127; + + if (!exp && !mantissa) + return 0; + + if (exp < 0) + return 0; + + return (1 << exp) + (mantissa >> (23 - exp)); +} + +static int sps30_do_meas(struct sps30_state *state, int *pm2p5, int *pm10) +{ + /* + * Internally sensor stores measurements in a following manner: + * + * PM1p0: upper two bytes, crc8, lower two bytes, crc8 + * PM2p5: upper two bytes, crc8, lower two bytes, crc8 + * PM4p0: upper two bytes, crc8, lower two bytes, crc8 + * PM10: upper two bytes, crc8, lower two bytes, crc8 + * + * What follows next are number concentration measurements and + * typical particle size measurement. + * + * Once data is read from sensor crc bytes are stripped off + * hence we need 16 bytes of buffer space. + */ + int ret, tries = 5; + u8 buf[16]; + + while (tries--) { + ret = sps30_do_cmd(state, SPS30_READ_DATA_READY_FLAG, buf, 2); + if (ret) + return -EIO; + + /* new measurements ready to be read */ + if (buf[1] == 1) + break; + + usleep_range(300000, 400000); + } + + if (!tries) + return -ETIMEDOUT; + + ret = sps30_do_cmd(state, SPS30_READ_DATA, buf, sizeof(buf)); + if (ret) + return ret; + + /* + * All measurements come in IEEE754 single precision floating point + * format but sensor itself is not precise enough (-+ 10% error) + * to take full advantage of it. Hence converting result to int + * to keep things simple. + */ + *pm2p5 = sps30_ieee754_to_int(&buf[PM2p5 * 4]); + *pm10 = sps30_ieee754_to_int(&buf[PM10 * 4]); + + return 0; +} + +static irqreturn_t sps30_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct sps30_state *state = iio_priv(indio_dev); + u32 buf[4]; /* PM2p5, PM10, timestamp */ + int ret; + + mutex_lock(&state->lock); + ret = sps30_do_meas(state, &buf[0], &buf[1]); + mutex_unlock(&state->lock); + if (ret < 0) + goto err; + + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int sps30_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct sps30_state *state = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_MASSCONCENTRATION: + mutex_lock(&state->lock); + switch (chan->channel2) { + case IIO_MOD_PM2p5: + ret = sps30_do_meas(state, val, val2); + break; + case IIO_MOD_PM10: + ret = sps30_do_meas(state, val2, val); + break; + default: + break; + } + mutex_unlock(&state->lock); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } +} + +static const struct iio_info sps30_info = { + .read_raw = sps30_read_raw, +}; + +static const struct iio_chan_spec sps30_channels[] = { + SPS30_CHAN(0, PM2p5), + SPS30_CHAN(1, PM10), + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + +static const unsigned long sps30_scan_masks[] = { 0x03, 0x00 }; + +static int sps30_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct sps30_state *state; + u8 buf[32] = { }; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EOPNOTSUPP; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*state)); + if (!indio_dev) + return -ENOMEM; + + state = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + state->client = client; + indio_dev->dev.parent = &client->dev; + indio_dev->info = &sps30_info; + indio_dev->name = client->name; + indio_dev->channels = sps30_channels; + indio_dev->num_channels = ARRAY_SIZE(sps30_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->available_scan_masks = sps30_scan_masks; + + mutex_init(&state->lock); + crc8_populate_msb(sps30_crc8_table, SPS30_CRC8_POLYNOMIAL); + + /* + * Power-on-reset causes sensor to produce some glitch on i2c bus + * and some controllers end up in error state. Recover simply + * by placing something on the bus. + */ + ret = sps30_do_cmd(state, SPS30_RESET, NULL, 0); + if (ret) { + dev_err(&client->dev, "failed to reset device\n"); + return ret; + } + usleep_range(2500000, 3500000); + sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0); + + ret = sps30_do_cmd(state, SPS30_READ_SERIAL, buf, sizeof(buf)); + if (ret) { + dev_err(&client->dev, "failed to read serial number\n"); + return ret; + } + dev_info(&client->dev, "serial number: %s\n", buf); + + ret = sps30_do_cmd(state, SPS30_START_MEAS, NULL, 0); + if (ret) { + dev_err(&client->dev, "failed to start measurement\n"); + return ret; + } + + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, + sps30_trigger_handler, NULL); + if (ret) + return ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static int sps30_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct sps30_state *state = iio_priv(indio_dev); + + sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0); + + return 0; +} + +static const struct i2c_device_id sps30_id[] = { + { "sps30" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sps30_id); + +static const struct of_device_id sps30_of_match[] = { + { .compatible = "sensirion,sps30" }, + { } +}; +MODULE_DEVICE_TABLE(of, sps30_of_match); + +static struct i2c_driver sps30_driver = { + .driver = { + .name = "sps30", + .of_match_table = sps30_of_match, + }, + .id_table = sps30_id, + .probe_new = sps30_probe, + .remove = sps30_remove, +}; +module_i2c_driver(sps30_driver); + +MODULE_AUTHOR("Tomasz Duszynski "); +MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor driver"); +MODULE_LICENSE("GPL v2"); From patchwork Sat Nov 24 22:14:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Duszynski X-Patchwork-Id: 10696579 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A7B8913AD for ; Sat, 24 Nov 2018 22:14:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 98DF5295E9 for ; Sat, 24 Nov 2018 22:14:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8C33C29F58; Sat, 24 Nov 2018 22:14:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6A40D295E9 for ; Sat, 24 Nov 2018 22:14:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726622AbeKYJEH (ORCPT ); Sun, 25 Nov 2018 04:04:07 -0500 Received: from mail-lf1-f67.google.com ([209.85.167.67]:45066 "EHLO mail-lf1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726275AbeKYJEG (ORCPT ); Sun, 25 Nov 2018 04:04:06 -0500 Received: by mail-lf1-f67.google.com with SMTP id b20so10886742lfa.12; Sat, 24 Nov 2018 14:14:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DInuEKdbNHvaSBbjubOXmw0RPlkgMluOKS1WEsr6y5c=; b=P+HbEDD7S3tijmzF5mUDpL6PzzMVdhR7Sgv3RYIrG9pek+X434r375IqMvaioHTMTV sdXjQmrv7B3TsdMAFOjFrIAnNleGbXgHurxMNj9vNrXd5EqdzF7m5BkWEll17xehDTeV v1tNr9Rf0GiaCIv2gWcEjax+f8dJTr6kl2xUPRhDgofOW097/LTomZDOzny8ri0E16OB HDGkkTTUkffqInPsMCHHoHBctNZy/l8vk08GRMbKBenXZj/nN6a2+woQPRBoIjZYhHC4 QFVXb6ZIWSzqgpRczWbQ3w8VMi+eXojx5tm758OennOcnZyIhGXSQohn+48w+mDcKOj+ nOPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DInuEKdbNHvaSBbjubOXmw0RPlkgMluOKS1WEsr6y5c=; b=FqPMPV8EzRxmCQu1djl4QuqNc6SwETif0d+/Ga+ny/jc5sirzBF5BNytnQSF5o18mk A54lLE3Zqp4FnTyAIosdkzBOnH6kSAeunPqIGaDtox8ZmLmLN8VTTZPS2ZiQe3D4aVZi N1A5j/zvw7wFho0C3YvKfpIPnxep0DdGI33/trRrZaVXIE/Q4Oe1m2AGWElKI72XbUFs tYgYT43K7QH+LfqCBjEm/B5vlBkYX9bVb5ziTZZh2ghS2VPqjZIWvn30FsbzUfALhECo +gmibfx2jayA5dvdeJz1otGSy3b8T1eQF1LKTYZEoLW03PU0LDj8f/76TfCotYN9NOXz /gPQ== X-Gm-Message-State: AGRZ1gKwWjfK4Af4avU0CdHgZnYueFC2/OjnCFBmSadunw2yhAakpAsp gQ7NGqlxiKRGH8OxpUwujx9s00abfxI= X-Google-Smtp-Source: AJdET5cFwAqQZTtwVJDczTXMUaN9HUW9hV+rtncawVZp+Zeha7BY74DUBO3UQel2gM6naN6C8VWw6g== X-Received: by 2002:a19:d287:: with SMTP id j129mr13160029lfg.26.1543097677576; Sat, 24 Nov 2018 14:14:37 -0800 (PST) Received: from arch.domain.name (89-70-226-70.dynamic.chello.pl. [89.70.226.70]) by smtp.gmail.com with ESMTPSA id x16sm8369281lff.26.2018.11.24.14.14.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 24 Nov 2018 14:14:36 -0800 (PST) From: Tomasz Duszynski To: linux-iio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Tomasz Duszynski Subject: [PATCH 3/3] iio: chemical: sps30: add device tree support Date: Sat, 24 Nov 2018 23:14:15 +0100 Message-Id: <20181124221415.10081-4-tduszyns@gmail.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181124221415.10081-1-tduszyns@gmail.com> References: <20181124221415.10081-1-tduszyns@gmail.com> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add device tree support for Sensirion SPS30 particulate matter sensor. Signed-off-by: Tomasz Duszynski --- .../bindings/iio/chemical/sensirion,sps30.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt diff --git a/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt b/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt new file mode 100644 index 000000000000..6eee2709b5b6 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt @@ -0,0 +1,12 @@ +* Sensirion SPS30 particulate matter sensor + +Required properties: +- compatible: must be "sensirion,sps30" +- reg: the I2C address of the sensor + +Example: + +sps30@69 { + compatible = "sensirion,sps30"; + reg = <0x69>; +};