[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250425221214.50255-1-surajsonawane0215@gmail.com>
Date: Sat, 26 Apr 2025 03:42:14 +0530
From: surajsonawane0215@...il.com
To: jic23@...nel.org
Cc: lars@...afoo.de,
surajsonawane0215@...il.com,
linux-kernel@...r.kernel.org,
linux-iio@...r.kernel.org
Subject: [PATCH 2/2] iio: chemical: Add driver for Sharp GP2Y1010AU0F dust sensor
From: Suraj Sonawane <surajsonawane0215@...il.com>
Implement support for the Sharp GP2Y1010AU0F optical dust sensor which
measures particulate matter concentration using infrared scattering. The
sensor requires precise 280us LED pulses with ADC sampling at 200us after
LED activation.
The driver provides:
- Raw voltage readings through IIO interface
- Hardware-agnostic operation via GPIO and IIO ADC interfaces
- Power management through regulator framework
- Device Tree binding support
Device operation:
1. Activate IR LED for 280us
2. Wait 40us after LED activation
3. Sample analog output at 200us (peak sensitivity)
4. Convert voltage to dust density via calibration parameters
Tested on BeagleBone Black with:
- P8_12 (GPIO_44) for LED control
- P9_39 (AIN0) for analog output
Datasheet:
https://global.sharp/products/device/lineup/data/pdf/datasheet/gp2y1010au_appl_e.pdf
Signed-off-by: Suraj Sonawane <surajsonawane0215@...il.com>
---
MAINTAINERS | 7 ++
drivers/iio/chemical/Kconfig | 12 +++
drivers/iio/chemical/Makefile | 1 +
drivers/iio/chemical/gp2y1010.c | 183 ++++++++++++++++++++++++++++++++
4 files changed, 203 insertions(+)
create mode 100644 drivers/iio/chemical/gp2y1010.c
diff --git a/MAINTAINERS b/MAINTAINERS
index f31aeb6b4..54e0f67e0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21974,6 +21974,13 @@ F: drivers/iio/chemical/sps30.c
F: drivers/iio/chemical/sps30_i2c.c
F: drivers/iio/chemical/sps30_serial.c
+SHARP GP2Y1010AU0F DUST SENSOR DRIVER
+M: Suraj Sonawane <surajsonawane0215@...il.com>
+L: linux-iio@...r.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/chemical/sharp,gp2y1010au0f.yaml
+F: drivers/iio/chemical/gp2y1010.c
+
SERIAL DEVICE BUS
M: Rob Herring <robh@...nel.org>
L: linux-serial@...r.kernel.org
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index 330fe0af9..119c6e6d8 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -100,6 +100,18 @@ config ENS160_SPI
tristate
select REGMAP_SPI
+config GP2Y1010AU0F
+ tristate "Sharp GP2Y1010AU0F optical dust sensor"
+ depends on IIO
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say Y here to build support for Sharp GP2Y1010AU0F optical dust sensor
+ that measures particulate matter concentration in air.
+
+ To compile this driver as a module, choose M here: the module will be
+ called gp2y1010au0f.
+
config IAQCORE
tristate "AMS iAQ-Core VOC sensors"
depends on I2C
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index 4866db06b..296bbc0d0 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_ENS160) += ens160_core.o
obj-$(CONFIG_ENS160_I2C) += ens160_i2c.o
obj-$(CONFIG_ENS160_SPI) += ens160_spi.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
+obj-$(CONFIG_GP2Y1010AU0F) += gp2y1010.o
obj-$(CONFIG_PMS7003) += pms7003.o
obj-$(CONFIG_SCD30_CORE) += scd30_core.o
obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o
diff --git a/drivers/iio/chemical/gp2y1010.c b/drivers/iio/chemical/gp2y1010.c
new file mode 100644
index 000000000..19c09e0e3
--- /dev/null
+++ b/drivers/iio/chemical/gp2y1010.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Suraj Sonawane <surajsonawane0215@...il.com>
+ *
+ * Sharp GP2Y1010AU0F Dust Sensor Driver
+ *
+ * Datasheet:
+ * https://global.sharp/products/device/lineup/data/pdf/datasheet/gp2y1010au_appl_e.pdf
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+
+#define GP2Y1010_LED_PULSE_US 280 /* LED on-time (280us) */
+#define GP2Y1010_SAMPLE_DELAY_US 40 /* Wait 40us after LED on */
+#define GP2Y1010_MEASUREMENT_US 200 /* Measure 200us after LED on */
+
+struct gp2y1010_data {
+ struct gpio_desc *led_gpio;
+ struct iio_dev *indio_dev;
+ struct iio_channel *adc_chan;
+ struct regulator *vdd;
+ int v_clean; /* Calibration: voltage in clean air (mV) */
+};
+
+static int gp2y1010_power_on(struct gp2y1010_data *data)
+{
+ int ret;
+
+ ret = regulator_enable(data->vdd);
+ if (ret) {
+ dev_err(&data->indio_dev->dev, "Failed to enable vdd regulator\n");
+ return ret;
+ }
+
+ udelay(100); /* Short delay for regulator stability */
+ return 0;
+}
+
+static void gp2y1010_power_off(struct gp2y1010_data *data)
+{
+ regulator_disable(data->vdd);
+}
+
+static int gp2y1010_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct gp2y1010_data *data = iio_priv(indio_dev);
+ int ret, voltage_mv;
+
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ /* Turn on LED */
+ gpiod_set_value(data->led_gpio, 1);
+
+ /* Wait 40us (datasheet: delay after LED on) */
+ udelay(GP2Y1010_SAMPLE_DELAY_US);
+
+ /* Read ADC at 200us (peak sensitivity) */
+ udelay(GP2Y1010_MEASUREMENT_US - GP2Y1010_SAMPLE_DELAY_US);
+ ret = iio_read_channel_processed(data->adc_chan, &voltage_mv);
+ if (ret < 0) {
+ gpiod_set_value(data->led_gpio, 0);
+ return ret;
+ }
+
+ /* Turn off LED (total pulse width = 280us) */
+ gpiod_set_value(data->led_gpio, 0);
+
+ /* Store raw voltage (for debugging) */
+ *val = voltage_mv;
+
+ return IIO_VAL_INT;
+}
+
+static const struct iio_info gp2y1010_info = {
+ .read_raw = gp2y1010_read_raw,
+};
+
+static const struct iio_chan_spec gp2y1010_channels[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .extend_name = "dust",
+ },
+};
+
+static int gp2y1010_probe(struct platform_device *pdev)
+{
+ struct gp2y1010_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->indio_dev = indio_dev;
+ data->v_clean = 900; /* Default calibration (adjust per sensor) */
+
+ /* Get LED GPIO */
+ data->led_gpio = devm_gpiod_get(&pdev->dev, "led", GPIOD_OUT_LOW);
+ if (IS_ERR(data->led_gpio))
+ return dev_err_probe(&pdev->dev, PTR_ERR(data->led_gpio),
+ "Failed to get LED GPIO\n");
+
+ /* Get regulator */
+ data->vdd = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(data->vdd))
+ return dev_err_probe(&pdev->dev, PTR_ERR(data->vdd),
+ "Failed to get regulator\n");
+
+ /* Power on sensor */
+ ret = gp2y1010_power_on(data);
+ if (ret)
+ return ret;
+
+ /* Get ADC channel */
+ data->adc_chan = devm_iio_channel_get(&pdev->dev, "dust");
+ if (IS_ERR(data->adc_chan)) {
+ gp2y1010_power_off(data);
+ return dev_err_probe(&pdev->dev, PTR_ERR(data->adc_chan),
+ "Failed to get ADC channel\n");
+ }
+
+ /* Setup IIO device */
+ indio_dev->name = "gp2y1010";
+ indio_dev->info = &gp2y1010_info;
+ indio_dev->channels = gp2y1010_channels;
+ indio_dev->num_channels = ARRAY_SIZE(gp2y1010_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_iio_device_register(&pdev->dev, indio_dev);
+ if (ret) {
+ gp2y1010_power_off(data);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void gp2y1010_remove(struct platform_device *pdev)
+{
+ struct gp2y1010_data *data = platform_get_drvdata(pdev);
+
+ gp2y1010_power_off(data);
+}
+
+static const struct of_device_id gp2y1010_of_match[] = {
+ { .compatible = "sharp,gp2y1010au0f", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, gp2y1010_of_match);
+
+static struct platform_driver gp2y1010_driver = {
+ .driver = {
+ .name = "gp2y1010",
+ .of_match_table = gp2y1010_of_match,
+ },
+ .probe = gp2y1010_probe,
+ .remove = gp2y1010_remove,
+};
+
+module_platform_driver(gp2y1010_driver);
+
+MODULE_AUTHOR("Suraj Sonawane <surajsonawane0215@...il.com>");
+MODULE_DESCRIPTION("Sharp GP2Y1010AU0F Dust Sensor Driver");
+MODULE_LICENSE("GPL");
--
2.34.1
Powered by blists - more mailing lists