Devicetree
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Add Sharp GP2AP070S Proximity Driver and enable it in Galaxy J6 (j6lte)
@ 2026-07-30 19:31 Kaustabh Chakraborty
  2026-07-30 19:31 ` [PATCH v2 1/3] dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor Kaustabh Chakraborty
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 19:31 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kaustabh Chakraborty, Peter Griffin, Alim Akhtar
  Cc: linux-iio, devicetree, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

Sharp GP2AP070S is a promixity sensor (NOT an ambient light sensor) in
mobile devices. This sensor chip is found in mobile devices, including
(but perhaps not limited to) Samsung Galaxy J6 (codename: j6lte).

To the best of my knowledge, there's no public documentation available
for this device. [1] is a downstream kernel implementation, which has
been the single source for developing this driver. Some bits have also
been stolen from existing GP2AP* drivers available in iio/light.

The last patch in this series touches the device tree sources to add the
light sensor node in j6lte. This needs to be accepted into next only
when the former patches are in next.

[1] https://github.com/Exynos7870/android_kernel_samsung_universal7870/blob/lineage-16.0/drivers/sensors/gp2ap070s.c

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
Changes in v2:
- Reshuffle and add missing header inclusions (Joshua Crofts)
- Add missing regulators in driver and dt-schema
  (Joshua Crofts, Jonathan Cameron)
- Rename and rearrange register addresses, masks and values (Jonathan Cameron)
- Use regmap_get_device() for carrying dev pointer (Jonathan Cameron)
- Use FIELD_GET() instead of !! (Jonathan Cameron)
- Drop unused i2c_set_clientdata() (Jonathan Cameron)
- Use fsleep() instead of usleep_range() (Jonathan Cameron)
- Check if proximity-near-level is available before reading its value
  (Jonathan Cameron)
- Drop redundant dev_err_probe() from devm_request_threaded_irq()
  (Joshua Crofts)
- Use mutex guards for guarding concurrent read/write calls (Sashiko)
- Add reset chip action on removal (Sashiko)
- Ensure input value in iio_write_event_value() is 16-bit (Sashiko)
- Use regmap_bulk_*() instead of regmap_raw_*() (Jonathan Cameron)
- Hint volatile registers for regmap (Jonathan Cameron)
- Link to v1: https://patch.msgid.link/20260723-gp2ap070s-v1-0-b8ca3a4c10dd@disroot.org

---
Kaustabh Chakraborty (3):
      dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor
      iio: proximity: add driver for Sharp GP2AP070S proximity sensor
      arm64: dts: exynos7870-j6lte: add Sharp GP2AP070S proximity sensor

 .../bindings/iio/proximity/sharp,gp2ap070s.yaml    |  59 +++
 arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts    |  55 ++-
 drivers/iio/proximity/Kconfig                      |  11 +
 drivers/iio/proximity/Makefile                     |   1 +
 drivers/iio/proximity/gp2ap070s.c                  | 502 +++++++++++++++++++++
 5 files changed, 626 insertions(+), 2 deletions(-)
---
base-commit: 290aaf24a551d5a0dce037e3fab30820f9113a10
change-id: 20260723-gp2ap070s-f7e0120970a5

Best regards,
--  
Kaustabh Chakraborty <kauschluss@disroot.org>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/3] dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor
  2026-07-30 19:31 [PATCH v2 0/3] Add Sharp GP2AP070S Proximity Driver and enable it in Galaxy J6 (j6lte) Kaustabh Chakraborty
@ 2026-07-30 19:31 ` Kaustabh Chakraborty
  2026-07-30 19:38   ` sashiko-bot
  2026-07-30 19:31 ` [PATCH v2 2/3] iio: proximity: add driver for " Kaustabh Chakraborty
  2026-07-30 19:31 ` [PATCH v2 3/3] arm64: dts: exynos7870-j6lte: add " Kaustabh Chakraborty
  2 siblings, 1 reply; 8+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 19:31 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kaustabh Chakraborty, Peter Griffin, Alim Akhtar
  Cc: linux-iio, devicetree, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

The GP2AP070S is a proximity sensor designed and manufactured by Sharp
Corporation. Unlike the other GP2AP* schemas, this is strictly a
proximity sensor and NOT an ambient light sensor.

For power supplies, it expects two voltage supplies, one for core and
other for driving the infrared LED which is used to measure proximity
distance.

This chip has been used in production mobile devices such as the Samsung
Galaxy J6.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 .../bindings/iio/proximity/sharp,gp2ap070s.yaml    | 59 ++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/proximity/sharp,gp2ap070s.yaml b/Documentation/devicetree/bindings/iio/proximity/sharp,gp2ap070s.yaml
new file mode 100644
index 000000000000..bcae68303b3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/proximity/sharp,gp2ap070s.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/proximity/sharp,gp2ap070s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sharp GP2AP070S Proximity sensor
+
+maintainers:
+  - Kaustabh Chakraborty <kauschluss@disroot.org>
+
+allOf:
+  - $ref: ../common.yaml#
+
+properties:
+  compatible:
+    const: sharp,gp2ap070s
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vdd-supply:
+    description: Voltage supply for the internal circuitry
+
+  vled-supply:
+    description: Voltage supply for the IR LED
+
+  proximity-near-level: true
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      proximity@39 {
+        compatible = "sharp,gp2ap070s";
+        reg = <0x39>;
+        interrupt-parent = <&gpio>;
+        interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
+        vdd-supply = <&vdd_supply>;
+        vled-supply = <&vled_supply>;
+        proximity-near-level = <500>;
+      };
+    };
+
+...

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/3] iio: proximity: add driver for Sharp GP2AP070S proximity sensor
  2026-07-30 19:31 [PATCH v2 0/3] Add Sharp GP2AP070S Proximity Driver and enable it in Galaxy J6 (j6lte) Kaustabh Chakraborty
  2026-07-30 19:31 ` [PATCH v2 1/3] dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor Kaustabh Chakraborty
@ 2026-07-30 19:31 ` Kaustabh Chakraborty
  2026-07-30 19:36   ` Kaustabh Chakraborty
                     ` (2 more replies)
  2026-07-30 19:31 ` [PATCH v2 3/3] arm64: dts: exynos7870-j6lte: add " Kaustabh Chakraborty
  2 siblings, 3 replies; 8+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 19:31 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kaustabh Chakraborty, Peter Griffin, Alim Akhtar
  Cc: linux-iio, devicetree, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

The GP2AP070S is a proximity sensor designed and manufactured by Sharp
Corporation. This sensor is used in mobile devices, including, but not
limited to - the Samsung Galaxy J6.

The driver has been adopted from Samsung's downstream kernel
implementation [1]. Due to the lack of public documentation about the
schematics of this device. The downstream driver acts as the secondary
source of information. Driver clarity has also been improved with the
help of the GP2AP* drivers in iio/light.

Link: https://github.com/Exynos7870/android_kernel_samsung_universal7870/blob/lineage-16.0/drivers/sensors/gp2ap070s.c [1]
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 drivers/iio/proximity/Kconfig     |  11 +
 drivers/iio/proximity/Makefile    |   1 +
 drivers/iio/proximity/gp2ap070s.c | 502 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 514 insertions(+)

diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index bb77fad2a1b3..3f30ebfc21bc 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -41,6 +41,17 @@ config D3323AA
 	  To compile this driver as a module, choose M here: the module will be
 	  called d3323aa.
 
+config GP2AP070S
+	tristate "Sharp GP2AP070S proximity sensor"
+	select REGMAP_I2C
+	depends on I2C
+	help
+	  Say Y here to build a driver for the Sharp GP2AP070S proximity
+	  sensor.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called gp2ap070s.
+
 config HX9023S
 	tristate "TYHX HX9023S SAR sensor"
 	select IIO_BUFFER
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index 4352833dd8a4..627ffb04acb2 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -7,6 +7,7 @@
 obj-$(CONFIG_AS3935)		+= as3935.o
 obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o
 obj-$(CONFIG_D3323AA)		+= d3323aa.o
+obj-$(CONFIG_GP2AP070S)		+= gp2ap070s.o
 obj-$(CONFIG_HX9023S)		+= hx9023s.o
 obj-$(CONFIG_IRSD200)		+= irsd200.o
 obj-$(CONFIG_ISL29501)		+= isl29501.o
diff --git a/drivers/iio/proximity/gp2ap070s.c b/drivers/iio/proximity/gp2ap070s.c
new file mode 100644
index 000000000000..9625f53d956e
--- /dev/null
+++ b/drivers/iio/proximity/gp2ap070s.c
@@ -0,0 +1,502 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IIO driver for Sharp GP2AP070S proximity sensor.
+ *
+ * Copyright (C) 2026 Kaustabh Chakraborty <kauschluss@disroot.org>
+ */
+
+#include <linux/i2c.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#define GP2AP070S_REG_COM1		0x80
+#define GP2AP070S_REG_COM2		0x81
+#define GP2AP070S_REG_COM3		0x82
+#define GP2AP070S_REG_COM4		0x83
+#define GP2AP070S_REG_PS1		0x85
+#define GP2AP070S_REG_PS2		0x86
+#define GP2AP070S_REG_PS3		0x87
+#define GP2AP070S_REG_PS_THD_LO_LE16	0x88
+#define GP2AP070S_REG_PS_THD_HI_LE16	0x8a
+#define GP2AP070S_REG_OS_D0_LE16	0x8c
+#define GP2AP070S_REG_D0_LE16		0x90
+
+/* GP2AP070S_REG_COM1 */
+#define GP2AP070S_VAL_COM1_WKUP		BIT(7)
+#define GP2AP070S_VAL_COM1_EN		BIT(5)
+
+/* GP2AP070S_REG_COM3 */
+#define GP2AP070S_VAL_COM3_INT_PULSE	BIT(1)
+
+/* GP2AP070S_REG_COM4 */
+#define GP2AP070S_VAL_COM1_BLINK	GENMASK(2, 0)	/* LED Blink Interval */
+
+#define GP2AP070S_VAL_COM1_BLINK_0ms	0
+#define GP2AP070S_VAL_COM1_BLINK_2ms	1
+#define GP2AP070S_VAL_COM1_BLINK_8ms	2
+#define GP2AP070S_VAL_COM1_BLINK_33ms	3
+#define GP2AP070S_VAL_COM1_BLINK_66ms	4
+#define GP2AP070S_VAL_COM1_BLINK_131ms	5
+#define GP2AP070S_VAL_COM1_BLINK_262ms	6
+#define GP2AP070S_VAL_COM1_BLINK_524ms	7
+
+/* GP2AP070S_REG_PS1 */
+#define GP2AP070S_VAL_PS1_RESOL		GENMASK(5, 4)	/* Resolution */
+
+#define GP2AP070S_VAL_PS1_RESOL_14ms	0
+#define GP2AP070S_VAL_PS1_RESOL_12ms	1
+#define GP2AP070S_VAL_PS1_RESOL_10ms	2
+#define GP2AP070S_VAL_PS1_RESOL_8ms	3
+
+/* GP2AP070S_REG_PS2 */
+#define GP2AP070S_VAL_PS2_IOUT		GENMASK(6, 4)	/* Current Output */
+#define GP2AP070S_VAL_PS2_SUM32		BIT(2)
+
+#define GP2AP070S_VAL_PS2_IOUT_0mA	0
+#define GP2AP070S_VAL_PS2_IOUT_24mA	1
+#define GP2AP070S_VAL_PS2_IOUT_89mA	2
+#define GP2AP070S_VAL_PS2_IOUT_130mA	3
+#define GP2AP070S_VAL_PS2_IOUT_190mA	4
+
+/* GP2AP070S_REG_PS3 */
+#define GP2AP070S_VAL_PS3_PRST		GENMASK(6, 4)	/* Repeating Measurements */
+
+struct gp2ap070s_drvdata {
+	struct device *dev;
+	struct regmap *regmap;
+	struct regulator_bulk_data *regulators;
+	u32 near_level;
+};
+
+static const struct regmap_config gp2ap070s_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static const char *const gp2ap070s_regulator_names[] = {
+	"vdd",
+	"vled",
+};
+
+static ssize_t gp2ap070s_iio_read_near_level(struct iio_dev *indio_dev,
+					     uintptr_t priv,
+					     const struct iio_chan_spec *chan,
+					     char *buf)
+{
+	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
+
+	return sprintf(buf, "%u\n", drvdata->near_level);
+}
+
+static const struct iio_chan_spec_ext_info gp2ap070s_iio_chan_spec_ext_info[] = {
+	{
+		.name = "nearlevel",
+		.shared = IIO_SEPARATE,
+		.read = gp2ap070s_iio_read_near_level,
+	},
+	{ /* sentinel */ }
+};
+
+static const struct iio_event_spec gp2ap070s_iio_event_spec[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	},
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	},
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+	},
+};
+
+static const struct iio_chan_spec gp2ap070s_iio_chan_spec[] = {
+	{
+		.type = IIO_PROXIMITY,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.ext_info = gp2ap070s_iio_chan_spec_ext_info,
+		.event_spec = gp2ap070s_iio_event_spec,
+		.num_event_specs = ARRAY_SIZE(gp2ap070s_iio_event_spec),
+	},
+};
+
+static int gp2ap070s_iio_read_raw(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan, int *val,
+				  int *val2, long mask)
+{
+	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
+	__le16 value;
+	int ret;
+
+	ret = regmap_raw_read(drvdata->regmap, GP2AP070S_REG_D0_LE16, &value,
+			      sizeof(value));
+	if (ret)
+		return ret;
+
+	*val = le16_to_cpu(value);
+	return IIO_VAL_INT;
+}
+
+static int gp2ap070s_iio_read_event_value(struct iio_dev *indio_dev,
+					  const struct iio_chan_spec *chan,
+					  enum iio_event_type type,
+					  enum iio_event_direction dir,
+					  enum iio_event_info info, int *val,
+					  int *val2)
+{
+	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
+	__le16 value;
+	int ret;
+
+	if (type != IIO_EV_TYPE_THRESH || info != IIO_EV_INFO_VALUE)
+		return -EINVAL;
+
+	switch (dir) {
+	case IIO_EV_DIR_RISING:
+		ret = regmap_raw_read(drvdata->regmap,
+				      GP2AP070S_REG_PS_THD_HI_LE16, &value,
+				      sizeof(value));
+		if (ret)
+			return ret;
+
+		*val = le16_to_cpu(value);
+		return IIO_VAL_INT;
+	case IIO_EV_DIR_FALLING:
+		ret = regmap_raw_read(drvdata->regmap,
+				      GP2AP070S_REG_PS_THD_LO_LE16, &value,
+				      sizeof(value));
+		if (ret)
+			return ret;
+
+		*val = le16_to_cpu(value);
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int gp2ap070s_iio_write_event_value(struct iio_dev *indio_dev,
+					   const struct iio_chan_spec *chan,
+					   enum iio_event_type type,
+					   enum iio_event_direction dir,
+					   enum iio_event_info info, int val,
+					   int val2)
+{
+	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
+	__le16 value;
+	u16 threshold_other;
+	int ret;
+
+	if (type != IIO_EV_TYPE_THRESH || info != IIO_EV_INFO_VALUE)
+		return -EINVAL;
+
+	switch (dir) {
+	case IIO_EV_DIR_RISING:
+		ret = regmap_raw_read(drvdata->regmap,
+				      GP2AP070S_REG_PS_THD_LO_LE16, &value,
+				      sizeof(value));
+		if (ret)
+			return ret;
+
+		/* Ensure lo_threshold < hi_threshold */
+		threshold_other = le16_to_cpu(value);
+		if (threshold_other >= val)
+			return -EINVAL;
+
+		value = cpu_to_le16((u16)val);
+		ret = regmap_raw_write(drvdata->regmap,
+				       GP2AP070S_REG_PS_THD_HI_LE16, &value,
+				       sizeof(value));
+		if (ret)
+			return ret;
+
+		return IIO_VAL_INT;
+	case IIO_EV_DIR_FALLING:
+		ret = regmap_raw_read(drvdata->regmap,
+				      GP2AP070S_REG_PS_THD_HI_LE16, &value,
+				      sizeof(value));
+		if (ret)
+			return ret;
+
+		/* Ensure hi_threshold > lo_threshold */
+		threshold_other = le16_to_cpu(value);
+		if (threshold_other <= val)
+			return -EINVAL;
+
+		value = cpu_to_le16((u16)val);
+		ret = regmap_raw_write(drvdata->regmap,
+				       GP2AP070S_REG_PS_THD_LO_LE16, &value,
+				       sizeof(value));
+		if (ret)
+			return ret;
+
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int gp2ap070s_read_event_config(struct iio_dev *indio_dev,
+				       const struct iio_chan_spec *chan,
+				       enum iio_event_type type,
+				       enum iio_event_direction dir)
+{
+	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
+	unsigned int value;
+	int ret;
+
+	if (type != IIO_EV_TYPE_THRESH)
+		return -EINVAL;
+
+	switch (dir) {
+	case IIO_EV_DIR_EITHER:
+		ret = regmap_read(drvdata->regmap, GP2AP070S_REG_COM3, &value);
+		if (ret)
+			return ret;
+
+		return !!(value & GP2AP070S_VAL_COM3_INT_PULSE);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int gp2ap070s_write_event_config(struct iio_dev *indio_dev,
+					const struct iio_chan_spec *chan,
+					enum iio_event_type type,
+					enum iio_event_direction dir,
+					bool state)
+{
+	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
+	int ret;
+
+	if (type != IIO_EV_TYPE_THRESH)
+		return -EINVAL;
+
+	switch (dir) {
+	case IIO_EV_DIR_EITHER:
+		if (state)
+			ret = regmap_set_bits(drvdata->regmap,
+					      GP2AP070S_REG_COM3,
+					      GP2AP070S_VAL_COM3_INT_PULSE);
+		else
+			ret = regmap_clear_bits(drvdata->regmap,
+						GP2AP070S_REG_COM3,
+						GP2AP070S_VAL_COM3_INT_PULSE);
+		if (ret)
+			return ret;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct iio_info gp2ap070s_iio_info = {
+	.read_raw = gp2ap070s_iio_read_raw,
+	.read_event_value = gp2ap070s_iio_read_event_value,
+	.write_event_value = gp2ap070s_iio_write_event_value,
+	.read_event_config = gp2ap070s_read_event_config,
+	.write_event_config = gp2ap070s_write_event_config,
+};
+
+static irqreturn_t gp2ap070s_irq_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
+	struct device *dev = drvdata->dev;
+	u16 threshold_lo, threshold_hi, distance;
+	__le16 value;
+	int ret;
+
+	ret = regmap_raw_read(drvdata->regmap, GP2AP070S_REG_PS_THD_LO_LE16,
+			      &value, sizeof(value));
+	if (ret) {
+		dev_err(dev, "Failed to read low threshold value (%d)\n", ret);
+		return IRQ_HANDLED;
+	}
+
+	threshold_lo = __le16_to_cpu(value);
+
+	ret = regmap_raw_read(drvdata->regmap, GP2AP070S_REG_PS_THD_HI_LE16,
+			      &value, sizeof(value));
+	if (ret) {
+		dev_err(dev, "Failed to read high threshold value (%d)\n", ret);
+		return IRQ_HANDLED;
+	}
+
+	threshold_hi = __le16_to_cpu(value);
+
+	ret = regmap_raw_read(drvdata->regmap, GP2AP070S_REG_D0_LE16, &value,
+			      sizeof(value));
+	if (ret) {
+		dev_err(dev, "Failed to read proximity distance (%d)\n", ret);
+		return IRQ_HANDLED;
+	}
+
+	distance = __le16_to_cpu(value);
+
+	if (distance >= threshold_hi) {
+		iio_push_event(indio_dev,
+			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+						    IIO_EV_TYPE_THRESH,
+						    IIO_EV_DIR_RISING),
+			       iio_get_time_ns(indio_dev));
+	} else if (distance <= threshold_lo) {
+		iio_push_event(indio_dev,
+			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+						    IIO_EV_TYPE_THRESH,
+						    IIO_EV_DIR_FALLING),
+			       iio_get_time_ns(indio_dev));
+	} else {
+		/*
+		 * If none match, then it's stuck in the threshold band gap.
+		 * The hardware generally does not issue interrupts here.
+		 */
+		WARN_ONCE(true, "spurious interrupt issued in proximity threshold gap\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int gp2ap070s_probe_hw_register(struct gp2ap070s_drvdata *drvdata)
+{
+	struct device *dev = drvdata->dev;
+	int ret;
+
+	ret = regmap_clear_bits(drvdata->regmap, GP2AP070S_REG_COM1, ~0);
+	if (ret)
+		return dev_err_probe(drvdata->dev, ret, "Failed to reset sensor\n");
+
+	ret = regmap_clear_bits(drvdata->regmap, GP2AP070S_REG_COM2, ~0);
+	if (ret)
+		return dev_err_probe(drvdata->dev, ret, "Failed to unmask interrupts\n");
+
+	ret = regmap_set_bits(drvdata->regmap, GP2AP070S_REG_COM3,
+			      GP2AP070S_VAL_COM3_INT_PULSE);
+	if (ret)
+		return dev_err_probe(drvdata->dev, ret, "Failed to enable interrupt\n");
+
+	ret = regmap_write_bits(drvdata->regmap, GP2AP070S_REG_COM4,
+				GP2AP070S_VAL_COM1_BLINK,
+				FIELD_PREP_CONST(GP2AP070S_VAL_COM1_BLINK,
+						 GP2AP070S_VAL_COM1_BLINK_33ms));
+	if (ret)
+		return dev_err_probe(drvdata->dev, ret, "Failed to set LED blink timing\n");
+
+	ret = regmap_write_bits(drvdata->regmap, GP2AP070S_REG_PS1,
+				GP2AP070S_VAL_PS1_RESOL,
+				FIELD_PREP_CONST(GP2AP070S_VAL_PS1_RESOL,
+						 GP2AP070S_VAL_PS1_RESOL_10ms));
+	if (ret)
+		return dev_err_probe(drvdata->dev, ret, "Failed to set resolution\n");
+
+	ret = regmap_write_bits(drvdata->regmap, GP2AP070S_REG_PS2,
+				GP2AP070S_VAL_PS2_IOUT | GP2AP070S_VAL_PS2_SUM32,
+				FIELD_PREP_CONST(GP2AP070S_VAL_PS2_IOUT,
+						 GP2AP070S_VAL_PS2_IOUT_89mA) |
+				GP2AP070S_VAL_PS2_SUM32);
+	if (ret)
+		return dev_err_probe(drvdata->dev, ret, "Failed to set current output\n");
+
+	ret = regmap_write_bits(drvdata->regmap, GP2AP070S_REG_PS3,
+				GP2AP070S_VAL_PS3_PRST,
+				FIELD_PREP_CONST(GP2AP070S_VAL_PS3_PRST, 3));
+	if (ret)
+		return dev_err_probe(drvdata->dev, ret, "Failed to set measurement repetitions\n");
+
+	ret = regmap_set_bits(drvdata->regmap, GP2AP070S_REG_COM1,
+			      GP2AP070S_VAL_COM1_WKUP | GP2AP070S_VAL_COM1_EN);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable sensor\n");
+
+	return 0;
+}
+
+static int gp2ap070s_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct iio_dev *indio_dev;
+	struct gp2ap070s_drvdata *drvdata;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*drvdata));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	drvdata = iio_priv(indio_dev);
+	i2c_set_clientdata(client, drvdata);
+
+	drvdata->dev = dev;
+	drvdata->regmap = devm_regmap_init_i2c(client, &gp2ap070s_regmap_config);
+	if (IS_ERR(drvdata->regmap))
+		return dev_err_probe(dev, PTR_ERR(drvdata->regmap), "Failed to create regmap\n");
+
+	ret = devm_regulator_bulk_get_enable(dev,
+					     ARRAY_SIZE(gp2ap070s_regulator_names),
+					     gp2ap070s_regulator_names);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to get and enable regulators");
+
+	usleep_range(10000, 11000);
+
+	indio_dev->name = "gp2ap070s";
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = gp2ap070s_iio_chan_spec;
+	indio_dev->num_channels = ARRAY_SIZE(gp2ap070s_iio_chan_spec);
+	indio_dev->info = &gp2ap070s_iio_info;
+
+	device_property_read_u32(&client->dev, "proximity-near-level",
+				 &drvdata->near_level);
+
+	ret = gp2ap070s_probe_hw_register(drvdata);
+	if (ret)
+		return ret;
+
+	ret = devm_request_threaded_irq(dev, client->irq, NULL,
+					gp2ap070s_irq_handler, IRQF_ONESHOT,
+					"gp2ap070s-irq", indio_dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to request IRQ");
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct of_device_id gp2ap070s_of_device_id[] = {
+	{ .compatible = "sharp,gp2ap070s" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, gp2ap070s_of_device_id);
+
+static const struct i2c_device_id gp2ap070s_i2c_device_id[] = {
+	{ .name = "gp2ap070s" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, gp2ap070s_i2c_device_id);
+
+static struct i2c_driver gp2ap070s_i2c_driver = {
+	.driver = {
+		.name = "gp2ap070s",
+		.of_match_table = gp2ap070s_of_device_id,
+	},
+	.probe = gp2ap070s_probe,
+	.id_table = gp2ap070s_i2c_device_id,
+};
+module_i2c_driver(gp2ap070s_i2c_driver);
+
+MODULE_AUTHOR("Kaustabh Chakraborty <kauschluss@disroot.org>");
+MODULE_DESCRIPTION("Sharp GP2AP070S Proximity Sensor");
+MODULE_LICENSE("GPL");

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/3] arm64: dts: exynos7870-j6lte: add Sharp GP2AP070S proximity sensor
  2026-07-30 19:31 [PATCH v2 0/3] Add Sharp GP2AP070S Proximity Driver and enable it in Galaxy J6 (j6lte) Kaustabh Chakraborty
  2026-07-30 19:31 ` [PATCH v2 1/3] dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor Kaustabh Chakraborty
  2026-07-30 19:31 ` [PATCH v2 2/3] iio: proximity: add driver for " Kaustabh Chakraborty
@ 2026-07-30 19:31 ` Kaustabh Chakraborty
  2 siblings, 0 replies; 8+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 19:31 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kaustabh Chakraborty, Peter Griffin, Alim Akhtar
  Cc: linux-iio, devicetree, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

The Sharp GP2AP070S is a proximity sensor, which is connected to a
GPIO-driven I2C line. Define the devicetree node for the sensor.

The sensor requires two voltage supplies, one of which is from the
primary regulator bank of the device, while the other one is controlled
by the GPIO. Add a regulator wrapping over the concerned GPIO so as to
feed it to the sensor node.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts | 55 ++++++++++++++++++++++++-
 1 file changed, 53 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts b/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
index de30d0970336..dd493138fed6 100644
--- a/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
+++ b/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
@@ -73,6 +73,35 @@ key-volup {
 		};
 	};
 
+	i2c-proximity {
+		compatible = "i2c-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c_proxm_bus>;
+
+		sda-gpios = <&gpf4 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		scl-gpios = <&gpf4 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+
+		i2c-gpio,delay-us = <2>;
+
+		proximity@39 {
+			compatible = "sharp,gp2ap070s";
+			reg = <0x39>;
+			interrupt-parent = <&gpa0>;
+			interrupts = <5 IRQ_TYPE_EDGE_BOTH>;
+
+			pinctrl-names = "default";
+			pinctrl-0 = <&proxm_irq>;
+
+			vdd-supply = <&vdd_fixed_proxm>;
+			vled-supply = <&vdd_ldo33>;
+
+			proximity-near-level = <500>;
+		};
+	};
+
 	memory@40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0x3d800000>,
@@ -94,6 +123,16 @@ vdd_fixed_mmc2: regulator-fixed-mmc2 {
 		enable-active-high;
 	};
 
+	/* proximity: vdd */
+	vdd_fixed_proxm: regulator-fixed-proxm {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_fixed_proxm";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		gpio = <&gpd2 3 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <1>;
@@ -354,13 +393,12 @@ vdd_ldo32: ldo32 {
 				regulator-ramp-delay = <12000>;
 			};
 
+			/* proximity: vled */
 			vdd_ldo33: ldo33 {
 				regulator-name = "vdd_ldo33";
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-ramp-delay = <12000>;
-				regulator-boot-on;
-				regulator-always-on;
 			};
 
 			/* touchscreen: vdd */
@@ -556,6 +594,13 @@ pmic_irq: pmic-irq-pins {
 		samsung,pin-drv = <EXYNOS5433_PIN_DRV_FAST_SR4>;
 	};
 
+	proxm_irq: proxm-irq-pins {
+		samsung,pins = "gpa0-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_EINT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS5433_PIN_DRV_FAST_SR1>;
+	};
+
 	touch_irq: touch-irq-pins {
 		samsung,pins = "gpa0-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_EINT>;
@@ -579,6 +624,12 @@ bt_enable: bt-enable-pins {
 		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
 	};
 
+	i2c_proxm_bus: i2c-proxm-bus-pins {
+		samsung,pins = "gpf4-3", "gpf4-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+	};
+
 	wlan_enable: wlan-enable-pins {
 		samsung,pins = "gpd3-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/3] iio: proximity: add driver for Sharp GP2AP070S proximity sensor
  2026-07-30 19:31 ` [PATCH v2 2/3] iio: proximity: add driver for " Kaustabh Chakraborty
@ 2026-07-30 19:36   ` Kaustabh Chakraborty
  2026-07-30 19:43   ` sashiko-bot
  2026-07-30 19:54   ` Uwe Kleine-König
  2 siblings, 0 replies; 8+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 19:36 UTC (permalink / raw)
  To: Kaustabh Chakraborty, Jonathan Cameron, David Lechner,
	Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Peter Griffin, Alim Akhtar
  Cc: linux-iio, devicetree, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

On 2026-07-31 01:01 +05:30, Kaustabh Chakraborty wrote:
> The GP2AP070S is a proximity sensor designed and manufactured by Sharp
> Corporation. This sensor is used in mobile devices, including, but not
> limited to - the Samsung Galaxy J6.
>
> The driver has been adopted from Samsung's downstream kernel
> implementation [1]. Due to the lack of public documentation about the
> schematics of this device. The downstream driver acts as the secondary
> source of information. Driver clarity has also been improved with the
> help of the GP2AP* drivers in iio/light.
>
> Link: https://github.com/Exynos7870/android_kernel_samsung_universal7870/blob/lineage-16.0/drivers/sensors/gp2ap070s.c [1]
> Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>

This is stale. I'm sending v3 right away.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/3] dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor
  2026-07-30 19:31 ` [PATCH v2 1/3] dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor Kaustabh Chakraborty
@ 2026-07-30 19:38   ` sashiko-bot
  0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-07-30 19:38 UTC (permalink / raw)
  To: Kaustabh Chakraborty; +Cc: robh, conor+dt, devicetree

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The hardware voltage supplies (`vdd-supply` and `vled-supply`) are not marked as required, despite the commit message stating the hardware explicitly expects them.
--

--- Patch [1]: [PATCH v2 1/3] dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor ---
commit 96d4a5f0f4aeeedf39b25cab70844620180ba231
Author: Kaustabh Chakraborty <kauschluss@disroot.org>

dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor

This commit introduces the device tree bindings for the Sharp GP2AP070S
proximity sensor. It defines properties for the voltage supplies expected
for the core and infrared LED, as well as the interrupt configuration.

> diff --git a/Documentation/devicetree/bindings/iio/proximity/sharp,gp2ap070s.yaml b/Documentation/devicetree/bindings/iio/proximity/sharp,gp2ap070s.yaml
> new file mode 100644
> index 0000000000000..bcae68303b3f0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/proximity/sharp,gp2ap070s.yaml
[ ... ]
> +  vdd-supply:
> +    description: Voltage supply for the internal circuitry
> +
> +  vled-supply:
> +    description: Voltage supply for the IR LED
> +
> +  proximity-near-level: true
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts

[Severity: Medium]
Should vdd-supply and vled-supply be included in this required list?

The commit message notes that the hardware explicitly expects two voltage
supplies, one for the core and the other for driving the infrared LED. If
they are omitted from the required list, an incomplete device tree
configuration could silently pass schema validation despite missing
properties that the hardware fundamentally requires.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-gp2ap070s-v2-0-1bdfee07d5ea@disroot.org?part=1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/3] iio: proximity: add driver for Sharp GP2AP070S proximity sensor
  2026-07-30 19:31 ` [PATCH v2 2/3] iio: proximity: add driver for " Kaustabh Chakraborty
  2026-07-30 19:36   ` Kaustabh Chakraborty
@ 2026-07-30 19:43   ` sashiko-bot
  2026-07-30 19:54   ` Uwe Kleine-König
  2 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-07-30 19:43 UTC (permalink / raw)
  To: Kaustabh Chakraborty; +Cc: devicetree, conor+dt, robh

Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [High] Potential Interrupt Storm on I2C Read Errors
- [High] Improper Use of WARN_ONCE for a Normal Physical Race Condition Allowing Denial of Service
- [Medium] Resource Leak and Unbalanced Hardware Lifecycle
- [Medium] Hardware Threshold Interrupts are Unconditionally Enabled at Probe
- [Medium] Missing Bounds Check on User-Supplied Sysfs Thresholds Enables Integer Truncation and Invariant Bypass
- [Medium] Missing Driver-Level Mutex Causes TOCTOU Race in Sysfs Writes
- [Medium] Missing System Suspend/Resume Operations Prevents Deep Sleep
- [Low] Inefficient Suboptimal I2C Reads in Threaded IRQ Handler
- [Low] Use of Deprecated sprintf in sysfs Output
--

--- Patch [2]: [PATCH v2 2/3] iio: proximity: add driver for Sharp GP2AP070S proximity sensor ---
commit 5c657e9abcf891397094f2fe629d2a5366679466
Author: Kaustabh Chakraborty <kauschluss@disroot.org>

iio: proximity: add driver for Sharp GP2AP070S proximity sensor

The GP2AP070S is a proximity sensor designed and manufactured by Sharp
Corporation. This sensor is used in mobile devices, including, but not
limited to - the Samsung Galaxy J6.

The driver has been adopted from Samsung's downstream kernel
implementation [1]. Due to the lack of public documentation about the
schematics of this device. The downstream driver acts as the secondary
source of information. Driver clarity has also been improved with the
help of the GP2AP* drivers in iio/light.

Link: https://github.com/Exynos7870/android_kernel_samsung_universal7870/blob/lineage-16.0/drivers/sensors/gp2ap070s.c [1]

> diff --git a/drivers/iio/proximity/gp2ap070s.c b/drivers/iio/proximity/gp2ap070s.c
> new file mode 100644
> index 0000000000000..9625f53d956ec
> --- /dev/null
> +++ b/drivers/iio/proximity/gp2ap070s.c
[ ... ]
> +static ssize_t gp2ap070s_iio_read_near_level(struct iio_dev *indio_dev,
> +					     uintptr_t priv,
> +					     const struct iio_chan_spec *chan,
> +					     char *buf)
> +{
> +	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%u\n", drvdata->near_level);

[Severity: Low]
Could this use sysfs_emit() instead of sprintf()? The kernel standard is to
use sysfs_emit() for sysfs show callbacks to ensure safety and consistent
formatting.

> +}
[ ... ]
> +static int gp2ap070s_iio_write_event_value(struct iio_dev *indio_dev,
> +					   const struct iio_chan_spec *chan,
> +					   enum iio_event_type type,
> +					   enum iio_event_direction dir,
> +					   enum iio_event_info info, int val,
> +					   int val2)
> +{
> +	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
> +	__le16 value;
> +	u16 threshold_other;
> +	int ret;

[Severity: Medium]
Is a driver-level lock needed here to serialize sysfs writes?

Since this function performs a read-modify-write sequence across multiple
independent registers to enforce the lo < hi threshold rule, could concurrent
sysfs writes race, read stale values, and write an invalid configuration?

> +
> +	if (type != IIO_EV_TYPE_THRESH || info != IIO_EV_INFO_VALUE)
> +		return -EINVAL;
> +
> +	switch (dir) {
> +	case IIO_EV_DIR_RISING:
> +		ret = regmap_raw_read(drvdata->regmap,
> +				      GP2AP070S_REG_PS_THD_LO_LE16, &value,
> +				      sizeof(value));
> +		if (ret)
> +			return ret;
> +
> +		/* Ensure lo_threshold < hi_threshold */
> +		threshold_other = le16_to_cpu(value);
> +		if (threshold_other >= val)
> +			return -EINVAL;

[Severity: Medium]
Could a negative val bypass this check?

Since val is a signed int and threshold_other is an unsigned u16, C integer
promotion rules will promote the u16 to a signed int for the comparison.

If a user writes -1, wouldn't 100 <= -1 evaluate to false, bypassing the
validation? The negative value would then wrap around when cast to u16
below, writing a potentially huge value to the hardware register. Should val
be bounds-checked (e.g., between 0 and U16_MAX)?

> +
> +		value = cpu_to_le16((u16)val);
> +		ret = regmap_raw_write(drvdata->regmap,
> +				       GP2AP070S_REG_PS_THD_HI_LE16, &value,
> +				       sizeof(value));
[ ... ]
> +static irqreturn_t gp2ap070s_irq_handler(int irq, void *private)
> +{
> +	struct iio_dev *indio_dev = private;
> +	struct gp2ap070s_drvdata *drvdata = iio_priv(indio_dev);
> +	struct device *dev = drvdata->dev;
> +	u16 threshold_lo, threshold_hi, distance;
> +	__le16 value;
> +	int ret;
> +
> +	ret = regmap_raw_read(drvdata->regmap, GP2AP070S_REG_PS_THD_LO_LE16,
> +			      &value, sizeof(value));

[Severity: Low]
Is it necessary to read the static low and high thresholds from the hardware
on every interrupt? Since these are configuration variables only modified by
the driver itself, could they be cached in struct gp2ap070s_drvdata to
prevent slow synchronous I2C bus traffic during the threaded IRQ handler?

> +	if (ret) {
> +		dev_err(dev, "Failed to read low threshold value (%d)\n", ret);
> +		return IRQ_HANDLED;
> +	}

[Severity: High]
Can returning IRQ_HANDLED here cause an interrupt storm? If the I2C read
fails, the handler exits without clearing the device's interrupt condition.

If the system's interrupt line is level-triggered, returning IRQ_HANDLED
instructs the IRQ core to unmask the line. The hardware will then immediately
re-assert the interrupt, leading to an infinite loop and CPU lockup. Should
this return IRQ_NONE or clear the interrupt state before returning?

> +
> +	threshold_lo = __le16_to_cpu(value);
> +
> +	ret = regmap_raw_read(drvdata->regmap, GP2AP070S_REG_PS_THD_HI_LE16,
> +			      &value, sizeof(value));
[ ... ]
> +	if (distance >= threshold_hi) {
> +		iio_push_event(indio_dev,
> +			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
> +						    IIO_EV_TYPE_THRESH,
> +						    IIO_EV_DIR_RISING),
> +			       iio_get_time_ns(indio_dev));
> +	} else if (distance <= threshold_lo) {
> +		iio_push_event(indio_dev,
> +			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
> +						    IIO_EV_TYPE_THRESH,
> +						    IIO_EV_DIR_FALLING),
> +			       iio_get_time_ns(indio_dev));
> +	} else {
> +		/*
> +		 * If none match, then it's stuck in the threshold band gap.
> +		 * The hardware generally does not issue interrupts here.
> +		 */
> +		WARN_ONCE(true, "spurious interrupt issued in proximity threshold gap\n");

[Severity: High]
Is it safe to use WARN_ONCE() for a condition triggered by external physical
events? If a physical object triggers the proximity interrupt but moves out
of the threshold bounds before the I2C read completes, it will fall into
this gap.

Using WARN_ONCE() here allows unprivileged actors to trigger a kernel panic
on systems configured with panic_on_warn. Could this be changed to
dev_dbg() or dev_warn()?

> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int gp2ap070s_probe_hw_register(struct gp2ap070s_drvdata *drvdata)
> +{
> +	struct device *dev = drvdata->dev;
> +	int ret;
> +
> +	ret = regmap_clear_bits(drvdata->regmap, GP2AP070S_REG_COM1, ~0);
> +	if (ret)
> +		return dev_err_probe(drvdata->dev, ret, "Failed to reset sensor\n");
> +
> +	ret = regmap_clear_bits(drvdata->regmap, GP2AP070S_REG_COM2, ~0);
> +	if (ret)
> +		return dev_err_probe(drvdata->dev, ret, "Failed to unmask interrupts\n");
> +
> +	ret = regmap_set_bits(drvdata->regmap, GP2AP070S_REG_COM3,
> +			      GP2AP070S_VAL_COM3_INT_PULSE);

[Severity: Medium]
Does this enable hardware threshold interrupts unconditionally during probe?
Typically, IIO devices should start with interrupts disabled and only enable
them when explicitly requested by userspace via write_event_config, to avoid
wasting CPU cycles on spurious interrupts before a consumer is ready.

> +	if (ret)
> +		return dev_err_probe(drvdata->dev, ret, "Failed to enable interrupt\n");
[ ... ]
> +static int gp2ap070s_probe(struct i2c_client *client)
> +{
> +	struct device *dev = &client->dev;
> +	struct iio_dev *indio_dev;
> +	struct gp2ap070s_drvdata *drvdata;
> +	int ret;
[ ... ]
> +	ret = gp2ap070s_probe_hw_register(drvdata);
> +	if (ret)
> +		return ret;

[Severity: Medium]
If gp2ap070s_probe_hw_register() succeeds but a subsequent probe step fails,
or if the module is later removed, will the hardware remain powered on and
active? Should there be a devm_add_action_or_reset() or a .remove callback
to properly power down the sensor and disable interrupts?

> +
> +	ret = devm_request_threaded_irq(dev, client->irq, NULL,
> +					gp2ap070s_irq_handler, IRQF_ONESHOT,
> +					"gp2ap070s-irq", indio_dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to request IRQ");
> +
> +	return devm_iio_device_register(&client->dev, indio_dev);
> +}
[ ... ]
> +static struct i2c_driver gp2ap070s_i2c_driver = {
> +	.driver = {
> +		.name = "gp2ap070s",
> +		.of_match_table = gp2ap070s_of_device_id,
> +	},
> +	.probe = gp2ap070s_probe,
> +	.id_table = gp2ap070s_i2c_device_id,
> +};
> +module_i2c_driver(gp2ap070s_i2c_driver);

[Severity: Medium]
Are power management operations missing for this device? Without a .pm
callback providing system suspend/resume handling, the active sensor may
continue pulsing its LED and interrupt the host, draining battery and
blocking deep sleep states when the system suspends.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-gp2ap070s-v2-0-1bdfee07d5ea@disroot.org?part=2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/3] iio: proximity: add driver for Sharp GP2AP070S proximity sensor
  2026-07-30 19:31 ` [PATCH v2 2/3] iio: proximity: add driver for " Kaustabh Chakraborty
  2026-07-30 19:36   ` Kaustabh Chakraborty
  2026-07-30 19:43   ` sashiko-bot
@ 2026-07-30 19:54   ` Uwe Kleine-König
  2 siblings, 0 replies; 8+ messages in thread
From: Uwe Kleine-König @ 2026-07-30 19:54 UTC (permalink / raw)
  To: Kaustabh Chakraborty
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Peter Griffin,
	Alim Akhtar, linux-iio, devicetree, linux-kernel,
	linux-arm-kernel, linux-samsung-soc

[-- Attachment #1: Type: text/plain, Size: 395 bytes --]

Hello,

On Fri, Jul 31, 2026 at 01:01:30AM +0530, Kaustabh Chakraborty wrote:
> +#include <linux/i2c.h>
> [...]
> +#include <linux/mod_devicetable.h>

<linux/i2c.h> is enough to get the definitions for i2c_device_id and
of_device_id. Please rely on that and don't explicitly add an include
for <linux/mod_devicetable.h>. The latter is a dependency hell and is
going away soon.

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-07-30 19:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 19:31 [PATCH v2 0/3] Add Sharp GP2AP070S Proximity Driver and enable it in Galaxy J6 (j6lte) Kaustabh Chakraborty
2026-07-30 19:31 ` [PATCH v2 1/3] dt-bindings: iio: proximity: add Sharp GP2AP070S proximity sensor Kaustabh Chakraborty
2026-07-30 19:38   ` sashiko-bot
2026-07-30 19:31 ` [PATCH v2 2/3] iio: proximity: add driver for " Kaustabh Chakraborty
2026-07-30 19:36   ` Kaustabh Chakraborty
2026-07-30 19:43   ` sashiko-bot
2026-07-30 19:54   ` Uwe Kleine-König
2026-07-30 19:31 ` [PATCH v2 3/3] arm64: dts: exynos7870-j6lte: add " Kaustabh Chakraborty

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox