iio: chemical: add driver for dsm501/ppd42ns particle sensors
PATCH 2/4 iio: chemical: add driver for dsm501/ppd42ns particle sensors
This patch adds support for dsm501 and ppd42ns particle sensors.
Both sensors work on the same principle. Heater (resistor) heats up air in sensor chamber which induces upward flow. Particles convect up through a light beam provided by internal infra-red LED. Light scattered by particles is picked by photodiode and internal electronics outputs PWM signal.
Measuring low time occupancy of the signal during 30s measurement period particles number in cubic meter can be computed.
--- drivers/iio/chemical/Kconfig | 10 ++ drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/dsm501.c | 231 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 drivers/iio/chemical/dsm501.c
drivers/iio/chemical/Kconfig +10 -0
@@ -21,6 +21,16 @@ config ATLAS_PH_SENSOR To compile this driver as module, choose M here: the module will be called atlas-ph-sensor. +config DSM501 + tristate "Samyoung DSM501 particle sensor" + depends on GPIOLIB + help + Say yes here to build support for the Samyoung DSM501 + particle sensor. + + To compile this driver as a module, choose M here: the module + will be called dsm501. + config IAQCORE tristate "AMS iAQ-Core VOC sensors" depends on I2C
drivers/iio/chemical/Makefile +1 -0
@@ -4,5 +4,6 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-ph-sensor.o +obj-$(CONFIG_DSM501) += dsm501.o obj-$(CONFIG_IAQCORE) += ams-iaq-core.o obj-$(CONFIG_VZ89X) += vz89x.o
drivers/iio/chemical/dsm501.c new file +231 -0
231 lines not on this page · raw message
Signature · 1 line
2.11.1
Quoted 2 lines
This patch adds support for dsm501 and ppd42ns particle sensors.
quick comments below
Quoted 79 lines
Both sensors work on the same principle. Heater (resistor) heats up air in sensor chamber which induces upward flow. Particles convect up through a light beam provided by internal infra-red LED. Light scattered by particles is picked by photodiode and internal electronics outputs PWM signal.
Measuring low time occupancy of the signal during 30s measurement period particles number in cubic meter can be computed.
Signed-off-by Tomasz Duszynski <[email protected]>--- drivers/iio/chemical/Kconfig | 10 ++ drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/dsm501.c | 231 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 drivers/iio/chemical/dsm501.cdrivers/iio/chemical/Kconfig +10
-0@@ -21,6 +21,16 @@ config ATLAS_PH_SENSOR To compile this driver as module, choose M here: the module will be called atlas-ph-sensor. +config DSM501 + tristate "Samyoung DSM501 particle sensor" + depends on GPIOLIB + help + Say yes here to build support for the Samyoung DSM501 + particle sensor. + + To compile this driver as a module, choose M here: the module + will be called dsm501. + config IAQCORE tristate "AMS iAQ-Core VOC sensors" depends on I2Cdrivers/iio/chemical/Makefile +1
-0@@ -4,5 +4,6 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-ph-sensor.o +obj-$(CONFIG_DSM501) += dsm501.o obj-$(CONFIG_IAQCORE) += ams-iaq-core.o obj-$(CONFIG_VZ89X) += vz89x.odrivers/iio/chemical/dsm501.c new file +24
-0@@ -0,0 +1,231 @@ +/* +* Samyoung DSM501 particle sensor driver +* +* Copyright (C) 2017 Tomasz Duszynski <[email protected]> +* +* Datasheets: +* http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf +* http://wiki.timelab.org/images/f/f9/PPD42NS.pdf +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h>
drivers/iio/chemical/dsm501.c line 34
Quoted 10 lines
drivers/iio/chemical/dsm501.c new file +10
-0+#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/timekeeping.h> + +#define DSM501_DRV_NAME "dsm501" +#define DSM501_IRQ_NAME "dsm501_irq"
replace tab by space
Quoted 16 lines
drivers/iio/chemical/dsm501.c new file +16
-0+ +#define DSM501_DEFAULT_MEASUREMENT_TIME 30/* seconds */ + +struct dsm501_data { +ktime_t ts; +ktime_t low_time; +ktime_t meas_time; + +int irq; +struct gpio_desc *gpio; + +struct mutex lock; + +int (*number_concentration)(struct dsm501_data *data); +}; +
drivers/iio/chemical/dsm501.c line 60
Quoted 10 lines
drivers/iio/chemical/dsm501.c new file +10
-0+/* +* Series of data points in Fig. 8-3 (Low Ratio vs Particle) +* can be approximated by following polynomials: +* +* p(r) = 0 (undefined) for r < 4 +* p(r) = 2353564.2r - 4373814.7 for 4 <= r < 20 +* p(r) = 4788112.4r - 53581390 for r >= 20 +* +* Note: Result is in pcs/m3. To convert to pcs/0.01cf multiply +* by 0.0002831685.
is cf needed?
Quoted 46 lines
drivers/iio/chemical/dsm501.c new file +46
-0+*/ +static int dsm501_number_concentartion (struct dsm501_data *data) +{ +s64 retval =0 , r =div64_s64 (ktime_to_ns (data->low_time) *100 , +ktime_to_ns (data->meas_time)); + +if (r >=4 && r <20 ) + retval =23535642 * r -43738147 ; +else if (r >=20 ) + retval =47881124 * r -535813900 ; + +return div_s64 (retval,10 ); +} + +/* +* Series of data points in Fig. 2 (Lo Pulse Occupancy Time vs Concentration) +* can be approximated by following polynomial: +* +* p(r) = 3844.2r^3 - 16201.3r^2 + 1848746.1r + 52497.2 +* +* Note: Result is in pcs/m3. To convert to pcs/0.01cf multiply +* by 0.0002831685. +*/ +static int ppd42ns_number_concentration (struct dsm501_data *data) +{ +s64 retval, r3, r2, r =div64_s64 (ktime_to_ns (data->low_time) *100 , +ktime_to_ns (data->meas_time)); + + r2 = r * r; + r3 = r2 * r; + + retval =38442 * r3; + retval -=162013 * r2; + retval +=18487461 * r; + retval +=524972 ; + +return div_s64 (retval,10 ); +} + +static irqreturn_t dsm501_irq (int irq,void *dev_id) +{ +struct dsm501_data *data =iio_priv (dev_id); +int val =gpiod_get_value (data->gpio); +ktime_t dt, ts =ktime_get (); + +if (ktime_to_ns (data->ts) ==0 ) {
drivers/iio/chemical/dsm501.c line 116
Quoted 10 lines
drivers/iio/chemical/dsm501.c new file +10
-0+ data->ts = ts; + data->low_time =ktime_set (0 ,0 ); + } + +if (val) { + dt =ktime_sub (ts, data->ts); + data->low_time =ktime_add (data->low_time, dt); + }else { + data->ts = ts; + }
{} needed?
Quoted 11 lines
drivers/iio/chemical/dsm501.c new file +11
-0+ +return IRQ_HANDLED ; +} + +static int dsm501_read_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan,int *val, +int *val2,long mask) +{ +struct dsm501_data *data =iio_priv (indio_dev); +struct device *dev = indio_dev->dev.parent; +unsigned long irqflags =IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING ;
drivers/iio/chemical/dsm501.c line 137
Quoted 10 lines
drivers/iio/chemical/dsm501.c new file +10
-0+int ret; + + +switch (mask) { +case IIO_CHAN_INFO_PROCESSED : +mutex_lock (&data->lock); + data->ts =ktime_set (0 ,0 ); + + ret =devm_request_irq (dev, data->irq, dsm501_irq, irqflags, +DSM501_IRQ_NAME , indio_dev);
why devm_()? if the irq is explicitly freed below? requesting the irq for every measurement seems weird even if it only happens every 30s
Quoted 63 lines
drivers/iio/chemical/dsm501.c new file +63
-0+if (ret) { +dev_err (dev,"Failed to request interrupt %d\n" , data->irq); +mutex_unlock (&data->lock); +return ret; + } + +msleep_interruptible (ktime_to_ms (data->meas_time)); +devm_free_irq (dev, data->irq, indio_dev); + + *val = data->number_concentration (data); +mutex_unlock (&data->lock); + +return IIO_VAL_INT ; +default : +return -EINVAL ; + } +} + +static const struct iio_info dsm501_info = { + .driver_module =THIS_MODULE , + .read_raw = dsm501_read_raw, +}; + +static const struct iio_chan_spec dsm501_channels[] = { + { + .type =IIO_NUMBERCONCENTRATION , + .info_mask_separate =BIT (IIO_CHAN_INFO_PROCESSED ), + }, +}; + +static int dsm501_probe (struct platform_device *pdev) +{ +struct dsm501_data *data; +struct iio_dev *indio_dev; +struct device *dev = &pdev->dev; + + indio_dev =devm_iio_device_alloc (&pdev->dev,sizeof (*data)); +if (!indio_dev) +return -ENOMEM ; + + data =iio_priv (indio_dev); +platform_set_drvdata (pdev, indio_dev); + + data->gpio =devm_gpiod_get_index (dev,NULL ,0 ,GPIOD_IN ); +if (IS_ERR (data->gpio)) { +dev_err (dev,"Failed to get GPIO\n" ); +return PTR_ERR (data->gpio); + } + + data->irq =gpiod_to_irq (data->gpio); +if (data->irq <0 ) { +dev_err (dev,"GPIO has no interrupt\n" ); +return data->irq; + } + + data->meas_time =ktime_set (DSM501_DEFAULT_MEASUREMENT_TIME ,0 ); + data->number_concentration =of_device_get_match_data (dev); +mutex_init (&data->lock); + + indio_dev->name =DSM501_DRV_NAME ; + indio_dev->dev.parent = dev; + indio_dev->info = &dsm501_info; + indio_dev->modes =INDIO_DIRECT_MODE ;
drivers/iio/chemical/dsm501.c line 210
Quoted 10 lines
drivers/iio/chemical/dsm501.c new file +10
-0+ indio_dev->channels = dsm501_channels; + indio_dev->num_channels =ARRAY_SIZE (dsm501_channels); + +return devm_iio_device_register (&pdev->dev, indio_dev); +} + +static const struct of_device_id dsm501_id[] = { + { + .compatible ="samyoung,dsm501" , + .data = dsm501_number_concentartion,
type: concentration
Quoted 22 lines
drivers/iio/chemical/dsm501.c new file +21
-0+ }, + { + .compatible = "shinyei,ppd42ns", + .data = ppd42ns_number_concentration, + }, + { } +}; +MODULE_DEVICE_TABLE (of, dsm501_id); + +static struct platform_driver dsm501_driver = { + .driver = { + .name =DSM501_DRV_NAME , + .of_match_table =of_match_ptr (dsm501_id) + }, + .probe = dsm501_probe +}; +module_platform_driver (dsm501_driver); + +MODULE_AUTHOR ("Tomasz Duszynski <[email protected]>" ); +MODULE_DESCRIPTION ("Samyoung DSM501 particle sensor driver" ); +MODULE_LICENSE ("GPL v2" );
Signature · 2 lines
Peter Meerwald-Stadler +43-664-2444418 (mobile)
Thanks for review!
Quoted 88 lines · Peter Meerwald-Stadler
Quoted 2 lines
This patch adds support for dsm501 and ppd42ns particle sensors.
quick comments below
GQuoted 83 lines
Both sensors work on the same principle. Heater (resistor) heats up air in sensor chamber which induces upward flow. Particles convect up through a light beam provided by internal infra-red LED. Light scattered by particles is picked by photodiode and internal electronics outputs PWM signal.
Measuring low time occupancy of the signal during 30s measurement period particles number in cubic meter can be computed.
Signed-off-by Tomasz Duszynski <[email protected]>--- drivers/iio/chemical/Kconfig | 10 ++ drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/dsm501.c | 231 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 drivers/iio/chemical/dsm501.cdrivers/iio/chemical/Kconfig +10
-0@@ -21,6 +21,16 @@ config ATLAS_PH_SENSOR To compile this driver as module, choose M here: the module will be called atlas-ph-sensor. +config DSM501 + tristate "Samyoung DSM501 particle sensor" + depends on GPIOLIB + help + Say yes here to build support for the Samyoung DSM501 + particle sensor. + + To compile this driver as a module, choose M here: the module + will be called dsm501. + config IAQCORE tristate "AMS iAQ-Core VOC sensors" depends on I2Cdrivers/iio/chemical/Makefile +1
-0@@ -4,5 +4,6 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-ph-sensor.o +obj-$(CONFIG_DSM501) += dsm501.o obj-$(CONFIG_IAQCORE) += ams-iaq-core.o obj-$(CONFIG_VZ89X) += vz89x.odrivers/iio/chemical/dsm501.c new file +28
-0@@ -0,0 +1,231 @@ +/* +* Samyoung DSM501 particle sensor driver +* +* Copyright (C) 2017 Tomasz Duszynski <[email protected]> +* +* Datasheets: +* http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf +* http://wiki.timelab.org/images/f/f9/PPD42NS.pdf +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mutex.h>
Quoted 8 lines
drivers/iio/chemical/dsm501.c line 34
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/timekeeping.h> + +#define DSM501_DRV_NAME "dsm501" +#define DSM501_IRQ_NAME "dsm501_irq"replace tab by space
Ack.
Quoted 21 lines
Quoted 21 lines
drivers/iio/chemical/dsm501.c new file +20
-0+ +#define DSM501_DEFAULT_MEASUREMENT_TIME 30/* seconds */ + +struct dsm501_data { +ktime_t ts; +ktime_t low_time; +ktime_t meas_time; + +int irq; +struct gpio_desc *gpio; + +struct mutex lock; + +int (*number_concentration)(struct dsm501_data *data); +}; + +/* +* Series of data points in Fig. 8-3 (Low Ratio vs Particle) +* can be approximated by following polynomials: +*
Quoted 8 lines
drivers/iio/chemical/dsm501.c line 60
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+* p(r) = 0 (undefined) for r < 4 +* p(r) = 2353564.2r - 4373814.7 for 4 <= r < 20 +* p(r) = 4788112.4r - 53581390 for r >= 20 +* +* Note: Result is in pcs/m3. To convert to pcs/0.01cf multiply +* by 0.0002831685. is cf needed?
No. I've put that sidenote so that others looking at figures in datahseets won't scratch their heads why units here are pcs/m3 and pcs/0.01cf there. Anyway I am happy to drop that part.
Quoted 51 lines
Quoted 51 lines
drivers/iio/chemical/dsm501.c new file +50
-0+*/ +static int dsm501_number_concentartion (struct dsm501_data *data) +{ +s64 retval =0 , r =div64_s64 (ktime_to_ns (data->low_time) *100 , +ktime_to_ns (data->meas_time)); + +if (r >=4 && r <20 ) + retval =23535642 * r -43738147 ; +else if (r >=20 ) + retval =47881124 * r -535813900 ; + +return div_s64 (retval,10 ); +} + +/* +* Series of data points in Fig. 2 (Lo Pulse Occupancy Time vs Concentration) +* can be approximated by following polynomial: +* +* p(r) = 3844.2r^3 - 16201.3r^2 + 1848746.1r + 52497.2 +* +* Note: Result is in pcs/m3. To convert to pcs/0.01cf multiply +* by 0.0002831685. +*/ +static int ppd42ns_number_concentration (struct dsm501_data *data) +{ +s64 retval, r3, r2, r =div64_s64 (ktime_to_ns (data->low_time) *100 , +ktime_to_ns (data->meas_time)); + + r2 = r * r; + r3 = r2 * r; + + retval =38442 * r3; + retval -=162013 * r2; + retval +=18487461 * r; + retval +=524972 ; + +return div_s64 (retval,10 ); +} + +static irqreturn_t dsm501_irq (int irq,void *dev_id) +{ +struct dsm501_data *data =iio_priv (dev_id); +int val =gpiod_get_value (data->gpio); +ktime_t dt, ts =ktime_get (); + +if (ktime_to_ns (data->ts) ==0 ) { + data->ts = ts; + data->low_time =ktime_set (0 ,0 ); + } +
Quoted 8 lines
drivers/iio/chemical/dsm501.c line 116
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+if (val) { + dt =ktime_sub (ts, data->ts); + data->low_time =ktime_add (data->low_time, dt); + }else { + data->ts = ts; + }{} needed?
According to CodingStyle yes. {} could be dropped if there was single statement under if (val) { ...
Quoted 18 lines
Quoted 18 lines
drivers/iio/chemical/dsm501.c new file +17
-0+ +return IRQ_HANDLED ; +} + +static int dsm501_read_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan,int *val, +int *val2,long mask) +{ +struct dsm501_data *data =iio_priv (indio_dev); +struct device *dev = indio_dev->dev.parent; +unsigned long irqflags =IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING ; +int ret; + + +switch (mask) { +case IIO_CHAN_INFO_PROCESSED : +mutex_lock (&data->lock);
Quoted 8 lines
drivers/iio/chemical/dsm501.c line 137
Quoted 4 lines
drivers/iio/chemical/dsm501.c new file +4
-0+ data->ts =ktime_set (0 ,0 ); + + ret =devm_request_irq (dev, data->irq, dsm501_irq, irqflags, +DSM501_IRQ_NAME , indio_dev);why
devm_()? if the irq is explicitly freed below? requesting the irq for every measurement seems weird even if it only happens every 30s
Ack.
Quoted 68 lines
Quoted 68 lines
drivers/iio/chemical/dsm501.c new file +67
-0+if (ret) { +dev_err (dev,"Failed to request interrupt %d\n" , data->irq); +mutex_unlock (&data->lock); +return ret; + } + +msleep_interruptible (ktime_to_ms (data->meas_time)); +devm_free_irq (dev, data->irq, indio_dev); + + *val = data->number_concentration (data); +mutex_unlock (&data->lock); + +return IIO_VAL_INT ; +default : +return -EINVAL ; + } +} + +static const struct iio_info dsm501_info = { + .driver_module =THIS_MODULE , + .read_raw = dsm501_read_raw, +}; + +static const struct iio_chan_spec dsm501_channels[] = { + { + .type =IIO_NUMBERCONCENTRATION , + .info_mask_separate =BIT (IIO_CHAN_INFO_PROCESSED ), + }, +}; + +static int dsm501_probe (struct platform_device *pdev) +{ +struct dsm501_data *data; +struct iio_dev *indio_dev; +struct device *dev = &pdev->dev; + + indio_dev =devm_iio_device_alloc (&pdev->dev,sizeof (*data)); +if (!indio_dev) +return -ENOMEM ; + + data =iio_priv (indio_dev); +platform_set_drvdata (pdev, indio_dev); + + data->gpio =devm_gpiod_get_index (dev,NULL ,0 ,GPIOD_IN ); +if (IS_ERR (data->gpio)) { +dev_err (dev,"Failed to get GPIO\n" ); +return PTR_ERR (data->gpio); + } + + data->irq =gpiod_to_irq (data->gpio); +if (data->irq <0 ) { +dev_err (dev,"GPIO has no interrupt\n" ); +return data->irq; + } + + data->meas_time =ktime_set (DSM501_DEFAULT_MEASUREMENT_TIME ,0 ); + data->number_concentration =of_device_get_match_data (dev); +mutex_init (&data->lock); + + indio_dev->name =DSM501_DRV_NAME ; + indio_dev->dev.parent = dev; + indio_dev->info = &dsm501_info; + indio_dev->modes =INDIO_DIRECT_MODE ; + indio_dev->channels = dsm501_channels; + indio_dev->num_channels =ARRAY_SIZE (dsm501_channels); + +return devm_iio_device_register (&pdev->dev, indio_dev);
Quoted 8 lines
drivers/iio/chemical/dsm501.c line 210
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+} + +static const struct of_device_id dsm501_id[] = { + { + .compatible ="samyoung,dsm501" , + .data = dsm501_number_concentartion,type: concentration
Are you refering to function naming here? *_number_concentration was named after returned physical quantity.
Quoted 28 lines
Quoted 13 lines
drivers/iio/chemical/dsm501.c new file +11
-0+ }, + { + .compatible = "shinyei,ppd42ns", + .data = ppd42ns_number_concentration, + }, + { } +}; +MODULE_DEVICE_TABLE (of, dsm501_id); + +static struct platform_driver dsm501_driver = { + .driver = {drivers/iio/chemical/dsm501.c line 231
Quoted 10 lines
drivers/iio/chemical/dsm501.c new file +10
-0+ .name = DSM501_DRV_NAME, + .of_match_table =of_match_ptr (dsm501_id) + }, + .probe = dsm501_probe +}; +module_platform_driver (dsm501_driver); + +MODULE_AUTHOR ("Tomasz Duszynski <[email protected]>" ); +MODULE_DESCRIPTION ("Samyoung DSM501 particle sensor driver" ); +MODULE_LICENSE ("GPL v2" );--
Peter Meerwald-Stadler
+43-664-2444418 (mobile)
Quoted 13 lines · Tomasz Duszynski
=20
Thanks for review!
=20Quoted 8 lines · Peter Meerwald-Stadler
=20
Quoted 1 line
This patch adds support for dsm501 and ppd42ns particle sensors.
=20
quick comments below
GQuoted 2 lines
Both sensors work on the same principle. Heater (resistor) heats up air in sensor chamber which induces upward flow. Particles convect up throug=
h
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
a light beam provided by internal infra-red LED. Light scattered by particles is picked by photodiode and internal electronics outputs PWM signal.
=20
Measuring low time occupancy of the signal during 30s measurement period=particles number in cubic meter can be computed.
=20
This a SI unit?
Also this maybe could be better off in drivers/iio/light... as much I like t=
o have other people in drivers/iio/chemical =F0=9F=98=80
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Signed-off-by Tomasz Duszynski <[email protected]>---
drivers/iio/chemical/Kconfig | 10 ++ drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/dsm501.c | 231 ++++++++++++++++++++++++++++++++++++=
++++++
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
3 files changed, 242 insertions(+)create mode 100644
drivers/iio/chemical/dsm501.c
=20drivers/iio/chemical/Kconfig= renamed from drivers/iio/chemical/Kconfig +0
-0index
cea7f9857a1f..986d612aa77f100644drivers/iio/chemical/Kconfig +0
-0@@ -21,6 +21,16 @@ config ATLAS_PH_SENSOR To compile this driver as module, choose M here: the module will be called atlas-ph-sensor.=20
drivers/iio/chemical/Kconfig +6
-0+config DSM501 + tristate "Samyoung DSM501 particle sensor" + depends on GPIOLIB + help + Say yes here to build support for the Samyoung DSM501 + particle sensor.
Quoted 8 lines
Quoted 8 lines
drivers/iio/chemical/Makefi=
Quoted 8 lines
drivers/iio/chemical/Kconfig +4
-0+ + To compile this driver as a module, choose M here: the module + will be called dsm501. +config IAQCORE
tristate "AMS iAQ-Core VOC sensors"
depends on I2Cdrivers/iio/chemical/Makefi= renamed from drivers/iio/chemical/Makefile +0
-0
le
Quoted 11 lines
Quoted 11 lines
drivers/iio/chemical/dsm501=
Quoted 11 lines
index
b02202b41289..76f50ff8ba7d100644drivers/iio/chemical/Makefile +0
-0@@ -4,5 +4,6 @@=20
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ATLAS_PH_SENSOR) +=3D atlas-ph-sensor.o
+obj-$(CONFIG_DSM501) +=3D dsm501.o
obj-$(CONFIG_IAQCORE) +=3D ams-iaq-core.o
obj-$(CONFIG_VZ89X) +=3D vz89x.odrivers/iio/chemical/dsm501= renamed from drivers/iio/chemical/dsm501.c +0
-0
.c
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
new file mode 100644
index 000000000000..013f6b3bfd48drivers/iio/chemical/dsm501.c new file +0
-0
Quoted 8 lines
Quoted 8 lines
drivers/iio/chemical/dsm501.c line 7
Quoted 8 lines
drivers/iio/chemical/dsm501.c new file +7
-0@@ -0,0 +1,231 @@ +/* +* Samyoung DSM501 particle sensor driver +* +* Copyright (C) 2017 Tomasz Duszynski <[email protected]> +* +* Datasheets: +* http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pd=
f
Quoted 61 lines
Quoted 23 lines
Quoted 23 lines
drivers/iio/chemical/dsm501.c new file +21
-0+* http://wiki.timelab.org/images/f/f9/PPD42NS.pdf +* +* This program is free software; you can redistribute it and/or modify= +* it under the terms of the GNU General Public License as published by= +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mutex.h> Quoted 8 lines
drivers/iio/chemical/dsm501.c line 34
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/timekeeping.h> + +#define DSM501_DRV_NAME "dsm501" +#define DSM501_IRQ_NAME "dsm501_irq"=20
replace tab by spaceAck.
Quoted 21 lines
=20
Quoted 20 lines
drivers/iio/chemical/dsm501.c new file +20
-0+ +#define DSM501_DEFAULT_MEASUREMENT_TIME 30/* seconds */ + +struct dsm501_data { +ktime_t ts; +ktime_t low_time; +ktime_t meas_time; + +int irq; +struct gpio_desc *gpio; + +struct mutex lock; + +int (*number_concentration)(struct dsm501_data *data); +}; + +/* +* Series of data points in Fig. 8-3 (Low Ratio vs Particle) +* can be approximated by following polynomials: +* Quoted 8 lines
Quoted 6 lines
+ * p(r) =3D 0 (undefined) for r < 4
+ * p(r) =3D 2353564.2r - 4373814.7 for 4 <=3D r < 20
+ * p(r) =3D 4788112.4r - 53581390 for r >=3D 20
+ *
+ * Note: Result is in pcs/m3. To convert to pcs/0.01cf multiply
+ * by 0.0002831685.=20
is cf needed?
Quoted 8 lines
No. I've put that sidenote so that others looking at figures in datahseets won't scratch their heads why units here are pcs/m3 and pcs/0.01cf there. Anyway I am happy to drop that part.
Quoted 5 lines
=20
drivers/iio/chemical/dsm501.c
Quoted 4 lines
+ */
drivers/iio/chemical/dsm501.c new file +3
-0+static int dsm501_number_concentartion (struct dsm501_data *data) +{ + s64 retval =3D 0, r =3D div64_s64(ktime_to_ns(data->low_time) * 100=
,
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/iio/chemical/dsm501.c new file +4
-0+ ktime_to_ns(data->meas_time)); + + if (r >=3D 4 && r < 20) + retval =3D 23535642 * r - 43738147;
Quoted 8 lines
Quoted 8 lines
drivers/iio/chemical/dsm501.c
Quoted 8 lines
drivers/iio/chemical/dsm501.c new file +8
-0+ else if (r >=3D 20) + retval =3D 47881124 * r - 535813900; + +return div_s64 (retval,10 ); +} + +/* +* Series of data points in Fig. 2 (Lo Pulse Occupancy Time vs Concentr=
ation)
Quoted 10 lines
Quoted 10 lines
drivers/iio/chemical/dsm501.c
Quoted 10 lines
+ * can be approximated by following polynomial:
+ *
+ * p(r) =3D 3844.2r^3 - 16201.3r^2 + 1848746.1r + 52497.2
+ *
+ * Note: Result is in pcs/m3. To convert to pcs/0.01cf multiply
+ * by 0.0002831685.
+ */drivers/iio/chemical/dsm501.c new file +3
-0+static int ppd42ns_number_concentration (struct dsm501_data *data) +{ + s64 retval, r3, r2, r =3D div64_s64(ktime_to_ns(data->low_time) * 1=
00,
Quoted 35 lines
Quoted 24 lines
Quoted 24 lines
drivers/iio/chemical/dsm501.c new file +24
-0+ ktime_to_ns(data->meas_time)); + + r2 =3D r * r; + r3 =3D r2 * r; + + retval =3D 38442 * r3; + retval -=3D 162013 * r2; + retval +=3D 18487461 * r; + retval +=3D 524972; + +return div_s64 (retval,10 ); +} + +static irqreturn_t dsm501_irq (int irq,void *dev_id) +{ + struct dsm501_data *data =3D iio_priv(dev_id); + int val =3D gpiod_get_value(data->gpio); + ktime_t dt, ts =3D ktime_get(); + + if (ktime_to_ns(data->ts) =3D=3D 0) { + data->ts =3D ts; + data->low_time =3D ktime_set(0, 0); + } +Quoted 8 lines
drivers/iio/chemical/dsm501.c line 116
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+if (val) { + dt =3D ktime_sub(ts, data->ts); + data->low_time =3D ktime_add(data->low_time, dt); + }else { + data->ts =3D ts; + }=20
{} needed?According to CodingStyle yes. {} could be dropped if there was single statement under if (val) { ...
Quoted 1 line
=20
Quoted 11 lines
Quoted 11 lines
drivers/iio/chemical/dsm501.c
Quoted 11 lines
drivers/iio/chemical/dsm501.c new file +11
-0+ +return IRQ_HANDLED ; +} + +static int dsm501_read_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan,int *val, +int *val2,long mask) +{ + struct dsm501_data *data =3D iio_priv(indio_dev); + struct device *dev =3D indio_dev->dev.parent; + unsigned long irqflags =3D IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLI=
NG;
Quoted 14 lines
Quoted 6 lines
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+int ret; + + +switch (mask) { +case IIO_CHAN_INFO_PROCESSED : +mutex_lock (&data->lock);Quoted 8 lines
drivers/iio/chemical/dsm501.c line 137
Quoted 4 lines
drivers/iio/chemical/dsm501.c new file +4
-0+ data->ts =3D ktime_set(0, 0); + + ret =3D devm_request_irq(dev, data->irq, dsm501_irq, irqflags, +DSM501_IRQ_NAME , indio_dev);=20
whydevm_()? if the irq is explicitly freed below? requesting the irq for every measurement seems weird even if it only happens every 30s
Quoted 4 lines
Ack.
Quoted 3 lines
=20
Quoted 2 lines
drivers/iio/chemical/dsm501.c new file +2
-0+if (ret) { + dev_err(dev, "Failed to request interrupt %d\n", data->irq)=
;
Quoted 73 lines
Quoted 65 lines
Quoted 65 lines
drivers/iio/chemical/dsm501.c new file +65
-0+mutex_unlock (&data->lock); +return ret; + } + +msleep_interruptible (ktime_to_ms (data->meas_time)); +devm_free_irq (dev, data->irq, indio_dev); + + *val =3D data->number_concentration(data); +mutex_unlock (&data->lock); + +return IIO_VAL_INT ; +default : +return -EINVAL ; + } +} + +static const struct iio_info dsm501_info =3D { + .driver_module =3D THIS_MODULE, + .read_raw =3D dsm501_read_raw, +}; + +static const struct iio_chan_spec dsm501_channels[] =3D { + { + .type =3D IIO_NUMBERCONCENTRATION, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_PROCESSED), + }, +}; + +static int dsm501_probe (struct platform_device *pdev) +{ +struct dsm501_data *data; +struct iio_dev *indio_dev; +struct device *dev =3D &pdev->dev; + + indio_dev =3D devm_iio_device_alloc(&pdev->dev, sizeof(*data)); +if (!indio_dev) +return -ENOMEM ; + + data =3D iio_priv(indio_dev); +platform_set_drvdata (pdev, indio_dev); + + data->gpio =3D devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN); +if (IS_ERR (data->gpio)) { +dev_err (dev,"Failed to get GPIO\n" ); +return PTR_ERR (data->gpio); + } + + data->irq =3D gpiod_to_irq(data->gpio); +if (data->irq <0 ) { +dev_err (dev,"GPIO has no interrupt\n" ); +return data->irq; + } + + data->meas_time =3D ktime_set(DSM501_DEFAULT_MEASUREMENT_TIME, 0); + data->number_concentration =3D of_device_get_match_data(dev); +mutex_init (&data->lock); + + indio_dev->name =3D DSM501_DRV_NAME; + indio_dev->dev.parent =3D dev; + indio_dev->info =3D &dsm501_info; + indio_dev->modes =3D INDIO_DIRECT_MODE; + indio_dev->channels =3D dsm501_channels; + indio_dev->num_channels =3D ARRAY_SIZE(dsm501_channels); + +return devm_iio_device_register (&pdev->dev, indio_dev);Quoted 8 lines
drivers/iio/chemical/dsm501.c
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+} + +static const struct of_device_id dsm501_id[] =3D { + { + .compatible =3D "samyoung,dsm501", + .data =3D dsm501_number_concentartion,=20
type: concentration
Quoted 1 line
Are you refering to function naming here?
*_number_concentrationwas name=
d
Quoted 33 lines
after returned physical quantity.
Quoted 20 lines
=20
Quoted 19 lines
drivers/iio/chemical/dsm501.c new file +19
-0+ }, + { + .compatible =3D "shinyei,ppd42ns", + .data =3D ppd42ns_number_concentration, + }, + { } +}; +MODULE_DEVICE_TABLE (of, dsm501_id); + +static struct platform_driver dsm501_driver =3D { + .driver =3D { + .name =3D DSM501_DRV_NAME, + .of_match_table =3D of_match_ptr(dsm501_id) + }, + .probe =3D dsm501_probe +}; +module_platform_driver (dsm501_driver); + +MODULE_AUTHOR ("Tomasz Duszynski <[email protected]>" );Quoted 8 lines
Quoted 3 lines
drivers/iio/chemical/dsm501.c new file +2
-0+MODULE_DESCRIPTION ("Samyoung DSM501 particle sensor driver" ); +MODULE_LICENSE ("GPL v2" );=20
=20
--
=20
Peter Meerwald-Stadler
+43-664-2444418 (mobile)--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Jonathan Cameron
maintainerQuoted 17 lines · Matt Ranostay
Quoted 17 lines · Tomasz Duszynski
Thanks for review!
Quoted 12 lines · Peter Meerwald-Stadler
Quoted 2 lines
This patch adds support for dsm501 and ppd42ns particle sensors.
quick comments below
GQuoted 6 lines
Both sensors work on the same principle. Heater (resistor) heats up air in sensor chamber which induces upward flow. Particles convect up through a light beam provided by internal infra-red LED. Light scattered by particles is picked by photodiode and internal electronics outputs PWM signal.
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Measuring low time occupancy of the signal during 30s measurement period particles number in cubic meter can be computed.
This a SI unit?
Also this maybe could be better off in
drivers/iio/light... as much I like to have other people indrivers/iio/chemical😀
Hmm. It's an odd one certainly. Bit like the pulse sensors that also use something derived from light in a non trivial way.
I'm not sure, but my gut feeling is to go with use case and short of having a new particle sensing category I think chemical is probably just about the best place for this one
Anyhow, interesting device. Another one where it sort of feels like it ought to be tied to dedicated pulse counter hardware but I guess it's slow enough that this works.
Jonathan
Quoted 318 lines
Quoted 307 lines
Quoted 74 lines
Quoted 74 lines
Signed-off-by Tomasz Duszynski <[email protected]>---
drivers/iio/chemical/Kconfig | 10 ++ drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/dsm501.c | 231 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+)create mode 100644
drivers/iio/chemical/dsm501.cdrivers/iio/chemical/Kconfig +10
-0@@ -21,6 +21,16 @@ config ATLAS_PH_SENSOR To compile this driver as module, choose M here: the module will be called atlas-ph-sensor. +config DSM501 + tristate "Samyoung DSM501 particle sensor" + depends on GPIOLIB + help + Say yes here to build support for the Samyoung DSM501 + particle sensor. + + To compile this driver as a module, choose M here: the module + will be called dsm501. +config IAQCORE
tristate "AMS iAQ-Core VOC sensors"
depends on I2Cdrivers/iio/chemical/Makefile +0
-0@@ -4,5 +4,6 @@ # When adding new entries keep the list in alphabetical orderobj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-ph-sensor.o
+obj-$(CONFIG_DSM501) += dsm501.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
obj-$(CONFIG_VZ89X) += vz89x.odrivers/iio/chemical/dsm501.c new file +28
-0@@ -0,0 +1,231 @@ +/* +* Samyoung DSM501 particle sensor driver +* +* Copyright (C) 2017 Tomasz Duszynski <[email protected]> +* +* Datasheets: +* http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf +* http://wiki.timelab.org/images/f/f9/PPD42NS.pdf +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mutex.h> Quoted 8 lines
drivers/iio/chemical/dsm501.c line 34
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/timekeeping.h> + +#define DSM501_DRV_NAME "dsm501" +#define DSM501_IRQ_NAME "dsm501_irq"replace tab by space
Ack.
Quoted 21 lines
Quoted 21 lines
drivers/iio/chemical/dsm501.c new file +20
-0+ +#define DSM501_DEFAULT_MEASUREMENT_TIME 30/* seconds */ + +struct dsm501_data { +ktime_t ts; +ktime_t low_time; +ktime_t meas_time; + +int irq; +struct gpio_desc *gpio; + +struct mutex lock; + +int (*number_concentration)(struct dsm501_data *data); +}; + +/* +* Series of data points in Fig. 8-3 (Low Ratio vs Particle) +* can be approximated by following polynomials: +* Quoted 8 lines
drivers/iio/chemical/dsm501.c line 60
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+* p(r) = 0 (undefined) for r < 4 +* p(r) = 2353564.2r - 4373814.7 for 4 <= r < 20 +* p(r) = 4788112.4r - 53581390 for r >= 20 +* +* Note: Result is in pcs/m3. To convert to pcs/0.01cf multiply +* by 0.0002831685. is cf needed?
No. I've put that sidenote so that others looking at figures in datahseets won't scratch their heads why units here are pcs/m3 and pcs/0.01cf there. Anyway I am happy to drop that part.
Quoted 51 lines
Quoted 51 lines
drivers/iio/chemical/dsm501.c new file +50
-0+*/ +static int dsm501_number_concentartion (struct dsm501_data *data) +{ +s64 retval =0 , r =div64_s64 (ktime_to_ns (data->low_time) *100 , +ktime_to_ns (data->meas_time)); + +if (r >=4 && r <20 ) + retval =23535642 * r -43738147 ; +else if (r >=20 ) + retval =47881124 * r -535813900 ; + +return div_s64 (retval,10 ); +} + +/* +* Series of data points in Fig. 2 (Lo Pulse Occupancy Time vs Concentration) +* can be approximated by following polynomial: +* +* p(r) = 3844.2r^3 - 16201.3r^2 + 1848746.1r + 52497.2 +* +* Note: Result is in pcs/m3. To convert to pcs/0.01cf multiply +* by 0.0002831685. +*/ +static int ppd42ns_number_concentration (struct dsm501_data *data) +{ +s64 retval, r3, r2, r =div64_s64 (ktime_to_ns (data->low_time) *100 , +ktime_to_ns (data->meas_time)); + + r2 = r * r; + r3 = r2 * r; + + retval =38442 * r3; + retval -=162013 * r2; + retval +=18487461 * r; + retval +=524972 ; + +return div_s64 (retval,10 ); +} + +static irqreturn_t dsm501_irq (int irq,void *dev_id) +{ +struct dsm501_data *data =iio_priv (dev_id); +int val =gpiod_get_value (data->gpio); +ktime_t dt, ts =ktime_get (); + +if (ktime_to_ns (data->ts) ==0 ) { + data->ts = ts; + data->low_time =ktime_set (0 ,0 ); + } +Quoted 8 lines
drivers/iio/chemical/dsm501.c line 116
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+if (val) { + dt =ktime_sub (ts, data->ts); + data->low_time =ktime_add (data->low_time, dt); + }else { + data->ts = ts; + }{} needed?
According to CodingStyle yes. {} could be dropped if there was single statement under if (val) { ...
Quoted 18 lines
Quoted 18 lines
drivers/iio/chemical/dsm501.c new file +17
-0+ +return IRQ_HANDLED ; +} + +static int dsm501_read_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan,int *val, +int *val2,long mask) +{ +struct dsm501_data *data =iio_priv (indio_dev); +struct device *dev = indio_dev->dev.parent; +unsigned long irqflags =IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING ; +int ret; + + +switch (mask) { +case IIO_CHAN_INFO_PROCESSED : +mutex_lock (&data->lock);Quoted 8 lines
drivers/iio/chemical/dsm501.c line 137
Quoted 4 lines
drivers/iio/chemical/dsm501.c new file +4
-0+ data->ts =ktime_set (0 ,0 ); + + ret =devm_request_irq (dev, data->irq, dsm501_irq, irqflags, +DSM501_IRQ_NAME , indio_dev);why
devm_()? if the irq is explicitly freed below? requesting the irq for every measurement seems weird even if it only happens every 30sAck.
Quoted 68 lines
Quoted 68 lines
drivers/iio/chemical/dsm501.c new file +67
-0+if (ret) { +dev_err (dev,"Failed to request interrupt %d\n" , data->irq); +mutex_unlock (&data->lock); +return ret; + } + +msleep_interruptible (ktime_to_ms (data->meas_time)); +devm_free_irq (dev, data->irq, indio_dev); + + *val = data->number_concentration (data); +mutex_unlock (&data->lock); + +return IIO_VAL_INT ; +default : +return -EINVAL ; + } +} + +static const struct iio_info dsm501_info = { + .driver_module =THIS_MODULE , + .read_raw = dsm501_read_raw, +}; + +static const struct iio_chan_spec dsm501_channels[] = { + { + .type =IIO_NUMBERCONCENTRATION , + .info_mask_separate =BIT (IIO_CHAN_INFO_PROCESSED ), + }, +}; + +static int dsm501_probe (struct platform_device *pdev) +{ +struct dsm501_data *data; +struct iio_dev *indio_dev; +struct device *dev = &pdev->dev; + + indio_dev =devm_iio_device_alloc (&pdev->dev,sizeof (*data)); +if (!indio_dev) +return -ENOMEM ; + + data =iio_priv (indio_dev); +platform_set_drvdata (pdev, indio_dev); + + data->gpio =devm_gpiod_get_index (dev,NULL ,0 ,GPIOD_IN ); +if (IS_ERR (data->gpio)) { +dev_err (dev,"Failed to get GPIO\n" ); +return PTR_ERR (data->gpio); + } + + data->irq =gpiod_to_irq (data->gpio); +if (data->irq <0 ) { +dev_err (dev,"GPIO has no interrupt\n" ); +return data->irq; + } + + data->meas_time =ktime_set (DSM501_DEFAULT_MEASUREMENT_TIME ,0 ); + data->number_concentration =of_device_get_match_data (dev); +mutex_init (&data->lock); + + indio_dev->name =DSM501_DRV_NAME ; + indio_dev->dev.parent = dev; + indio_dev->info = &dsm501_info; + indio_dev->modes =INDIO_DIRECT_MODE ; + indio_dev->channels = dsm501_channels; + indio_dev->num_channels =ARRAY_SIZE (dsm501_channels); + +return devm_iio_device_register (&pdev->dev, indio_dev);Quoted 8 lines
drivers/iio/chemical/dsm501.c line 210
Quoted 6 lines
drivers/iio/chemical/dsm501.c new file +6
-0+} + +static const struct of_device_id dsm501_id[] = { + { + .compatible ="samyoung,dsm501" , + .data = dsm501_number_concentartion,type: concentration
Are you refering to function naming here?
*_number_concentrationwas named after returned physical quantity.Quoted 26 lines
Quoted 13 lines
drivers/iio/chemical/dsm501.c new file +11
-0+ }, + { + .compatible = "shinyei,ppd42ns", + .data = ppd42ns_number_concentration, + }, + { } +}; +MODULE_DEVICE_TABLE (of, dsm501_id); + +static struct platform_driver dsm501_driver = { + .driver = {drivers/iio/chemical/dsm501.c line 231
Quoted 10 lines
drivers/iio/chemical/dsm501.c new file +10
-0+ .name = DSM501_DRV_NAME, + .of_match_table =of_match_ptr (dsm501_id) + }, + .probe = dsm501_probe +}; +module_platform_driver (dsm501_driver); + +MODULE_AUTHOR ("Tomasz Duszynski <[email protected]>" ); +MODULE_DESCRIPTION ("Samyoung DSM501 particle sensor driver" ); +MODULE_LICENSE ("GPL v2" );--
Quoted 6 lines
Quoted 2 lines
Peter Meerwald-Stadler
+43-664-2444418 (mobile)--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html