mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/4] This series adds support for Texas Instruments OPT4041 Ambient light sensor
@ 2026-10-23 12:30 Jesper X Nilsson
  2026-10-23 12:30 ` [PATCH v2 1/4] dt-bindings: iio: light: opt4001: add opt4041 Jesper X Nilsson
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Jesper X Nilsson @ 2026-10-23 12:30 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Stefan Windfeldt-Prytz
  Cc: linux-iio, devicetree, linux-kernel, Jesper X Nilsson, kernel,
	Andy Shevchenko

Extend the opt4001 driver to support OPT4041, since it is so similar to
OPT4001. The OPT4041 adds a second channel, a wide band channel ranging
from 380nm to 1000nm. The register map is almost the same for both
devices. OPT4001 has an internal fifo of size four, OPT4041 has two
fifos of size two, one for each channel.

Since OPT4041 has two channels it has one bit in register 0Bh to select
which channel is compared to the threshold register. The driver does not
support setting the threshold registers, so no new support has been
added for this.

The OPT4041 is pin compatible and has the same package as
opt4001-sot-5x3. Although the device id is different, I added a new
compatible string since the driver already had different compatible
strings to differentiate between the two OPT4001.

Datasheet: https://www.ti.com/lit/gpn/opt4041
Signed-off-by: Jesper X Nilsson <jesper.x.nilsson@axis.com>

---
Changes in v2:
- Drop tag Assited-by: LLM from commit messages
- Include patch from Andy: Re-use generic struct s32_fract
- Add trailing commas to structs where it was missing
- Sort variables in reverse xmas tree order in opt4001_read_raw_value()
- Return -ENODATA if i2c_get_match() returns NULL
- Update tristate summary and copy the string to MODULE_DESCRIPTION()
  and to the comment in the top of the driver
- Change the help text to included OPT4001 and OPT4041 on seperate lines
- Link to v1: https://patch.msgid.link/20261023-opt4041-v1-0-45227f82d05c@axis.com

To: Jonathan Cameron <jic23@kernel.org>
To: David Lechner <dlechner@baylibre.com>
To: Nuno Sá <nuno.sa@analog.com>
To: Andy Shevchenko <andy@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: Stefan Windfeldt-Prytz <stefan.windfeldt-prytz@axis.com>
Cc: linux-iio@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

---
Andy Shevchenko (1):
      iio: light: opt4001: Re-use generic struct s32_fract

Jesper X Nilsson (3):
      dt-bindings: iio: light: opt4001: add opt4041
      iio: light: opt4001: refactor driver to prepare to support more devices
      iio: light: opt4001: add support for opt4041

 .../devicetree/bindings/iio/light/ti,opt4001.yaml  |   9 +-
 drivers/iio/light/Kconfig                          |   6 +-
 drivers/iio/light/opt4001.c                        | 164 +++++++++++++++------
 3 files changed, 133 insertions(+), 46 deletions(-)
---
base-commit: a3b3580713f3ac5a32dc2874ee546828977a1d68
change-id: 20261007-opt4041-18315d8510df

Best regards,
--  
Jesper X Nilsson <jesper.x.nilsson@axis.com>


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

* [PATCH v2 1/4] dt-bindings: iio: light: opt4001: add opt4041
  2026-10-23 12:30 [PATCH v2 0/4] This series adds support for Texas Instruments OPT4041 Ambient light sensor Jesper X Nilsson
@ 2026-10-23 12:30 ` Jesper X Nilsson
  2026-10-23 12:30 ` [PATCH v2 2/4] iio: light: opt4001: Re-use generic struct s32_fract Jesper X Nilsson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Jesper X Nilsson @ 2026-10-23 12:30 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Stefan Windfeldt-Prytz
  Cc: linux-iio, devicetree, linux-kernel, Jesper X Nilsson, kernel

Add a new compatible for opt4041. The opt4041 is only available in the
SOT-5X3 package. The device is pin compatible with the opt4001-sot-5x3
and shares the same properties. The opt4041 has one additional channel
compared to opt4001, the extra channel has a wide spectral bandwidth
ranging from 380nm to 1000nm.

Datasheet: https://www.ti.com/lit/gpn/opt4041
Signed-off-by: Jesper X Nilsson <jesper.x.nilsson@axis.com>
---
 Documentation/devicetree/bindings/iio/light/ti,opt4001.yaml | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/light/ti,opt4001.yaml b/Documentation/devicetree/bindings/iio/light/ti,opt4001.yaml
index 12b0c7ed5d72..35e9b0deb944 100644
--- a/Documentation/devicetree/bindings/iio/light/ti,opt4001.yaml
+++ b/Documentation/devicetree/bindings/iio/light/ti,opt4001.yaml
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/iio/light/ti,opt4001.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Texas Instruments OPT4001 Ambient Light Sensor
+title: Texas Instruments OPT4001/OPT4041 Ambient Light Sensor
 
 maintainers:
   - Stefan Windfeldt-Prytz <stefan.windfeldt-prytz@axis.com>
@@ -13,13 +13,16 @@ description:
   Ambient light sensor with an i2c interface.
   Last part of compatible is for the packaging used.
   Picostar is a 4 pinned SMT and sot-5x3 is a 8 pinned SOT.
+  OPT4041 is only available as sot-5x3 and adds a wide band channel.
   https://www.ti.com/lit/gpn/opt4001
+  https://www.ti.com/lit/gpn/opt4041
 
 properties:
   compatible:
     enum:
       - ti,opt4001-picostar
       - ti,opt4001-sot-5x3
+      - ti,opt4041-sot-5x3
 
   reg:
     maxItems: 1
@@ -39,7 +42,9 @@ allOf:
       properties:
         compatible:
           contains:
-            const: ti,opt4001-sot-5x3
+            enum:
+              - ti,opt4001-sot-5x3
+              - ti,opt4041-sot-5x3
     then:
       properties:
         interrupts:

-- 
2.43.0


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

* [PATCH v2 2/4] iio: light: opt4001: Re-use generic struct s32_fract
  2026-10-23 12:30 [PATCH v2 0/4] This series adds support for Texas Instruments OPT4041 Ambient light sensor Jesper X Nilsson
  2026-10-23 12:30 ` [PATCH v2 1/4] dt-bindings: iio: light: opt4001: add opt4041 Jesper X Nilsson
@ 2026-10-23 12:30 ` Jesper X Nilsson
  2026-10-23 12:30 ` [PATCH v2 3/4] iio: light: opt4001: refactor driver to prepare to support more devices Jesper X Nilsson
  2026-10-23 12:30 ` [PATCH v2 4/4] iio: light: opt4001: add support for opt4041 Jesper X Nilsson
  3 siblings, 0 replies; 7+ messages in thread
From: Jesper X Nilsson @ 2026-10-23 12:30 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Stefan Windfeldt-Prytz
  Cc: linux-iio, devicetree, linux-kernel, Jesper X Nilsson, kernel,
	Andy Shevchenko

From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Instead of custom data type re-use generic struct s32_fract.
No functional changes intended.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Jesper X Nilsson <jesper.x.nilsson@axis.com>
---
 drivers/iio/light/opt4001.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
index aa3d87995b7c..dcde10914a1e 100644
--- a/drivers/iio/light/opt4001.c
+++ b/drivers/iio/light/opt4001.c
@@ -75,8 +75,7 @@
  * lux values.
  */
 struct opt4001_chip_info {
-	int mul;
-	int div;
+	struct s32_fract ratio;
 	const char *name;
 };
 
@@ -88,14 +87,12 @@ struct opt4001_chip {
 };
 
 static const struct opt4001_chip_info opt4001_sot_5x3_info = {
-	.mul = 4375,
-	.div = 10000000,
+	.ratio = { .numerator = 4375, .denominator = 10000000 },
 	.name = "opt4001-sot-5x3"
 };
 
 static const struct opt4001_chip_info opt4001_picostar_info = {
-	.mul = 3125,
-	.div = 10000000,
+	.ratio = { .numerator = 3125, .denominator = 10000000 },
 	.name = "opt4001-picostar"
 };
 
@@ -199,8 +196,8 @@ static int opt4001_read_lux_value(struct iio_dev *indio_dev,
 		return -EIO;
 
 	lux_raw = lux_raw << exp;
-	lux_raw = lux_raw * chip->chip_info->mul;
-	*val = div_u64_rem(lux_raw, chip->chip_info->div, &rem);
+	lux_raw = lux_raw * chip->chip_info->ratio.numerator;
+	*val = div_u64_rem(lux_raw, chip->chip_info->ratio.denominator, &rem);
 	*val2 = rem * 100;
 
 	return IIO_VAL_INT_PLUS_NANO;

-- 
2.43.0


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

* [PATCH v2 3/4] iio: light: opt4001: refactor driver to prepare to support more devices
  2026-10-23 12:30 [PATCH v2 0/4] This series adds support for Texas Instruments OPT4041 Ambient light sensor Jesper X Nilsson
  2026-10-23 12:30 ` [PATCH v2 1/4] dt-bindings: iio: light: opt4001: add opt4041 Jesper X Nilsson
  2026-10-23 12:30 ` [PATCH v2 2/4] iio: light: opt4001: Re-use generic struct s32_fract Jesper X Nilsson
@ 2026-10-23 12:30 ` Jesper X Nilsson
  2026-10-23 13:51   ` Andy Shevchenko
  2026-10-23 12:30 ` [PATCH v2 4/4] iio: light: opt4001: add support for opt4041 Jesper X Nilsson
  3 siblings, 1 reply; 7+ messages in thread
From: Jesper X Nilsson @ 2026-10-23 12:30 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Stefan Windfeldt-Prytz
  Cc: linux-iio, devicetree, linux-kernel, Jesper X Nilsson, kernel

Prepare opt4001 driver to be able to support OPT4041. Extend struct
opt4001_chip_info with fields channels and device_id because OPT4041 has
two channels and another device id.

Datasheet: https://www.ti.com/lit/gpn/opt4041
Signed-off-by: Jesper X Nilsson <jesper.x.nilsson@axis.com>
---
 drivers/iio/light/opt4001.c | 85 +++++++++++++++++++++++++++++----------------
 1 file changed, 55 insertions(+), 30 deletions(-)

diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
index dcde10914a1e..dc2eac8ad4af 100644
--- a/drivers/iio/light/opt4001.c
+++ b/drivers/iio/light/opt4001.c
@@ -77,6 +77,9 @@
 struct opt4001_chip_info {
 	struct s32_fract ratio;
 	const char *name;
+	const struct iio_chan_spec *channels;
+	int num_channels;
+	u16 device_id;
 };
 
 struct opt4001_chip {
@@ -86,14 +89,30 @@ struct opt4001_chip {
 	const struct opt4001_chip_info *chip_info;
 };
 
+static const struct iio_chan_spec opt4001_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.address = OPT4001_LIGHT1_MSB,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+	},
+};
+
 static const struct opt4001_chip_info opt4001_sot_5x3_info = {
 	.ratio = { .numerator = 4375, .denominator = 10000000 },
-	.name = "opt4001-sot-5x3"
+	.name = "opt4001-sot-5x3",
+	.channels = opt4001_channels,
+	.num_channels = ARRAY_SIZE(opt4001_channels),
+	.device_id = OPT4001_DEVICE_ID_VAL,
 };
 
 static const struct opt4001_chip_info opt4001_picostar_info = {
 	.ratio = { .numerator = 3125, .denominator = 10000000 },
-	.name = "opt4001-picostar"
+	.name = "opt4001-picostar",
+	.channels = opt4001_channels,
+	.num_channels = ARRAY_SIZE(opt4001_channels),
+	.device_id = OPT4001_DEVICE_ID_VAL,
 };
 
 static const int opt4001_int_time_available[][2] = {
@@ -156,30 +175,28 @@ static u8 opt4001_calculate_crc(u8 exp, u32 mantissa, u8 count)
 	return crc;
 }
 
-static int opt4001_read_lux_value(struct iio_dev *indio_dev,
-				  int *val, int *val2)
+static int opt4001_read_raw_value(struct opt4001_chip *chip, unsigned int reg,
+				  u64 *raw_value)
 {
-	struct opt4001_chip *chip = iio_priv(indio_dev);
 	struct device *dev = &chip->client->dev;
 	unsigned int light1;
 	unsigned int light2;
+	u32 mantissa;
+	u8 calc_crc;
+	u8 count;
 	u16 msb;
 	u16 lsb;
+	int ret;
 	u8 exp;
-	u8 count;
 	u8 crc;
-	u8 calc_crc;
-	u64 lux_raw;
-	u32 rem;
-	int ret;
 
-	ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1);
+	ret = regmap_read(chip->regmap, reg, &light1);
 	if (ret < 0) {
 		dev_err(dev, "Failed to read data bytes");
 		return ret;
 	}
 
-	ret = regmap_read(chip->regmap, OPT4001_LIGHT1_LSB, &light2);
+	ret = regmap_read(chip->regmap, reg + 1, &light2);
 	if (ret < 0) {
 		dev_err(dev, "Failed to read data bytes");
 		return ret;
@@ -190,12 +207,27 @@ static int opt4001_read_lux_value(struct iio_dev *indio_dev,
 	crc = FIELD_GET(OPT4001_CRC_MASK, light2);
 	msb = FIELD_GET(OPT4001_MSB_MASK, light1);
 	lsb = FIELD_GET(OPT4001_LSB_MASK, light2);
-	lux_raw = (msb << 8) + lsb;
-	calc_crc = opt4001_calculate_crc(exp, lux_raw, count);
+	mantissa = (msb << 8) + lsb;
+	calc_crc = opt4001_calculate_crc(exp, mantissa, count);
 	if (calc_crc != crc)
 		return -EIO;
 
-	lux_raw = lux_raw << exp;
+	*raw_value = (u64)mantissa << exp;
+
+	return 0;
+}
+
+static int opt4001_read_lux_value(struct opt4001_chip *chip, unsigned int reg,
+				  int *val, int *val2)
+{
+	u64 lux_raw;
+	u32 rem;
+	int ret;
+
+	ret = opt4001_read_raw_value(chip, reg, &lux_raw);
+	if (ret)
+		return ret;
+
 	lux_raw = lux_raw * chip->chip_info->ratio.numerator;
 	*val = div_u64_rem(lux_raw, chip->chip_info->ratio.denominator, &rem);
 	*val2 = rem * 100;
@@ -230,15 +262,6 @@ static void opt4001_chip_off_action(void *data)
 		dev_err(&chip->client->dev, "Failed to power down\n");
 }
 
-static const struct iio_chan_spec opt4001_channels[] = {
-	{
-		.type = IIO_LIGHT,
-		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
-		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
-		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME)
-	},
-};
-
 static int opt4001_read_raw(struct iio_dev *indio_dev,
 			    struct iio_chan_spec const *chan,
 			    int *val, int *val2, long mask)
@@ -247,7 +270,7 @@ static int opt4001_read_raw(struct iio_dev *indio_dev,
 
 	switch (mask) {
 	case IIO_CHAN_INFO_PROCESSED:
-		return opt4001_read_lux_value(indio_dev, val, val2);
+		return opt4001_read_lux_value(chip, chan->address, val, val2);
 	case IIO_CHAN_INFO_INT_TIME:
 		*val = 0;
 		*val2 = opt4001_int_time_reg[chip->int_time][0];
@@ -385,19 +408,21 @@ static int opt4001_probe(struct i2c_client *client)
 		return dev_err_probe(&client->dev, ret,
 				     "failed to reinit regmap cache\n");
 
+	chip->chip_info = i2c_get_match_data(client);
+	if (!chip->chip_info)
+		return -ENODATA;
+
 	ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &dev_id);
 	if (ret < 0)
 		return dev_err_probe(&client->dev, ret,
 			"Failed to read the device ID register\n");
 
 	dev_id = FIELD_GET(OPT4001_DEVICE_ID_MASK, dev_id);
-	if (dev_id != OPT4001_DEVICE_ID_VAL)
+	if (dev_id != chip->chip_info->device_id)
 		dev_warn(&client->dev, "Device ID: %#04x unknown\n", dev_id);
 
-	chip->chip_info = i2c_get_match_data(client);
-
-	indio_dev->channels = opt4001_channels;
-	indio_dev->num_channels = ARRAY_SIZE(opt4001_channels);
+	indio_dev->channels = chip->chip_info->channels;
+	indio_dev->num_channels = chip->chip_info->num_channels;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->name = chip->chip_info->name;
 

-- 
2.43.0


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

* [PATCH v2 4/4] iio: light: opt4001: add support for opt4041
  2026-10-23 12:30 [PATCH v2 0/4] This series adds support for Texas Instruments OPT4041 Ambient light sensor Jesper X Nilsson
                   ` (2 preceding siblings ...)
  2026-10-23 12:30 ` [PATCH v2 3/4] iio: light: opt4001: refactor driver to prepare to support more devices Jesper X Nilsson
@ 2026-10-23 12:30 ` Jesper X Nilsson
  2026-10-23 13:53   ` Andy Shevchenko
  3 siblings, 1 reply; 7+ messages in thread
From: Jesper X Nilsson @ 2026-10-23 12:30 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Stefan Windfeldt-Prytz
  Cc: linux-iio, devicetree, linux-kernel, Jesper X Nilsson, kernel

Extend the opt4001 driver to also support OPT4041. The devices are very
similar, with the difference being OPT4041 having two channels, one
visible and one wide band channel ranging from 380nm to 1000nm.

The register map is almost the same. OPT4001 has registers to read out
the last four values sampled. OPT4041 maps to the same registers, but
has two channels, saving the last two samples for each channel.

Datasheet: https://www.ti.com/lit/gpn/opt4041
Signed-off-by: Jesper X Nilsson <jesper.x.nilsson@axis.com>
---
 drivers/iio/light/Kconfig   |  6 +++--
 drivers/iio/light/opt4001.c | 66 ++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 462fff1ddef2..26c3fa057a38 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -503,12 +503,14 @@ config OPT3001
 	  opt3001.
 
 config OPT4001
-	tristate "Texas Instruments OPT4001 Light Sensor"
+	tristate "Texas Instruments OPT4001 and compatible Light Sensors"
 	depends on I2C
 	select REGMAP_I2C
 	help
 	  If you say Y or M here, you get support for Texas Instruments
-	  OPT4001 Ambient Light Sensor.
+	  Ambient Light Sensors:
+	  - OPT4001
+	  - OPT4041
 
 	  If built as a dynamically linked module, it will be called
 	  opt4001.
diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
index dc2eac8ad4af..5dcf9fe0aaad 100644
--- a/drivers/iio/light/opt4001.c
+++ b/drivers/iio/light/opt4001.c
@@ -2,9 +2,11 @@
 /*
  * Copyright (C) 2023 Axis Communications AB
  *
- * Datasheet: https://www.ti.com/lit/gpn/opt4001
+ * Datasheets:
+ *  https://www.ti.com/lit/gpn/opt4001
+ *  https://www.ti.com/lit/gpn/opt4041
  *
- * Device driver for the Texas Instruments OPT4001.
+ * Texas Instruments OPT4001 and compatible Light Sensors
  */
 
 #include <linux/bitfield.h>
@@ -19,6 +21,8 @@
 /* OPT4001 register set */
 #define OPT4001_LIGHT1_MSB    0x00
 #define OPT4001_LIGHT1_LSB    0x01
+#define OPT4041_LIGHT2_MSB    0x02
+#define OPT4041_LIGHT2_LSB    0x03
 #define OPT4001_CTRL          0x0A
 #define OPT4001_DEVICE_ID     0x11
 
@@ -43,6 +47,7 @@
 
 /* OPT4001 constants */
 #define OPT4001_DEVICE_ID_VAL            0x121
+#define OPT4041_DEVICE_ID_VAL            0x221
 
 /* OPT4001 operating modes */
 #define OPT4001_CTRL_OPER_MODE_OFF        0x0
@@ -72,7 +77,7 @@
 
 /*
  * The different packaging of OPT4001 has different constants used when calculating
- * lux values.
+ * lux values and OPT4041 has one additional wide band channel.
  */
 struct opt4001_chip_info {
 	struct s32_fract ratio;
@@ -99,6 +104,25 @@ static const struct iio_chan_spec opt4001_channels[] = {
 	},
 };
 
+static const struct iio_chan_spec opt4041_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.address = OPT4001_LIGHT1_MSB,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+	},
+	{
+		.type = IIO_INTENSITY,
+		.modified = 1,
+		.channel2 = IIO_MOD_LIGHT_BOTH,
+		.address = OPT4041_LIGHT2_MSB,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+	},
+};
+
 static const struct opt4001_chip_info opt4001_sot_5x3_info = {
 	.ratio = { .numerator = 4375, .denominator = 10000000 },
 	.name = "opt4001-sot-5x3",
@@ -115,6 +139,14 @@ static const struct opt4001_chip_info opt4001_picostar_info = {
 	.device_id = OPT4001_DEVICE_ID_VAL,
 };
 
+static const struct opt4001_chip_info opt4041_sot_5x3_info = {
+	.ratio = {.numerator = 5850, .denominator = 10000000 },
+	.name = "opt4041-sot-5x3",
+	.channels = opt4041_channels,
+	.num_channels = ARRAY_SIZE(opt4041_channels),
+	.device_id = OPT4041_DEVICE_ID_VAL,
+};
+
 static const int opt4001_int_time_available[][2] = {
 	{ 0,    600 },
 	{ 0,   1000 },
@@ -267,10 +299,30 @@ static int opt4001_read_raw(struct iio_dev *indio_dev,
 			    int *val, int *val2, long mask)
 {
 	struct opt4001_chip *chip = iio_priv(indio_dev);
+	u64 raw_value;
+	u32 rem;
+	int ret;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_PROCESSED:
 		return opt4001_read_lux_value(chip, chan->address, val, val2);
+	case IIO_CHAN_INFO_RAW:
+		ret = opt4001_read_raw_value(chip, chan->address, &raw_value);
+		if (ret)
+			return ret;
+
+		*val = div_u64_rem(raw_value, 100, &rem);
+		*val2 = rem * 10000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_SCALE:
+		/*
+		 * OPT4041 CH1: datasheet specifies 0.1923 nW/cm^2 per ADC code
+		 * with a 520 nm stimulus. Convert to nW/m^2 (x10000) and
+		 * compensate for dividing the reported raw value by 100 (x100).
+		 * The resulting scale is 192300 nW/m^2 per reported unit.
+		 */
+		*val = 192300;
+		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_INT_TIME:
 		*val = 0;
 		*val2 = opt4001_int_time_reg[chip->int_time][0];
@@ -337,6 +389,8 @@ static bool opt4001_readable_reg(struct device *dev, unsigned int reg)
 	switch (reg) {
 	case OPT4001_LIGHT1_MSB:
 	case OPT4001_LIGHT1_LSB:
+	case OPT4041_LIGHT2_MSB:
+	case OPT4041_LIGHT2_LSB:
 	case OPT4001_CTRL:
 	case OPT4001_DEVICE_ID:
 		return true;
@@ -360,6 +414,8 @@ static bool opt4001_volatile_reg(struct device *dev, unsigned int reg)
 	switch (reg) {
 	case OPT4001_LIGHT1_MSB:
 	case OPT4001_LIGHT1_LSB:
+	case OPT4041_LIGHT2_MSB:
+	case OPT4041_LIGHT2_LSB:
 		return true;
 	default:
 		return false;
@@ -447,6 +503,7 @@ static int opt4001_probe(struct i2c_client *client)
 static const struct i2c_device_id opt4001_id[] = {
 	{ .name = "opt4001-sot-5x3", .driver_data = (kernel_ulong_t)&opt4001_sot_5x3_info },
 	{ .name = "opt4001-picostar", .driver_data = (kernel_ulong_t)&opt4001_picostar_info },
+	{ .name = "opt4041-sot-5x3", .driver_data = (kernel_ulong_t)&opt4041_sot_5x3_info },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, opt4001_id);
@@ -454,6 +511,7 @@ MODULE_DEVICE_TABLE(i2c, opt4001_id);
 static const struct of_device_id opt4001_of_match[] = {
 	{ .compatible = "ti,opt4001-sot-5x3", .data = &opt4001_sot_5x3_info},
 	{ .compatible = "ti,opt4001-picostar", .data = &opt4001_picostar_info},
+	{ .compatible = "ti,opt4041-sot-5x3", .data = &opt4041_sot_5x3_info},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, opt4001_of_match);
@@ -469,5 +527,5 @@ static struct i2c_driver opt4001_driver = {
 module_i2c_driver(opt4001_driver);
 
 MODULE_AUTHOR("Stefan Windfeldt-Prytz <stefan.windfeldt-prytz@axis.com>");
-MODULE_DESCRIPTION("Texas Instruments opt4001 ambient light sensor driver");
+MODULE_DESCRIPTION("Texas Instruments OPT4001 and compatible Light Sensors");
 MODULE_LICENSE("GPL");

-- 
2.43.0


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

* Re: [PATCH v2 3/4] iio: light: opt4001: refactor driver to prepare to support more devices
  2026-10-23 12:30 ` [PATCH v2 3/4] iio: light: opt4001: refactor driver to prepare to support more devices Jesper X Nilsson
@ 2026-10-23 13:51   ` Andy Shevchenko
  0 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2026-10-23 13:51 UTC (permalink / raw)
  To: Jesper X Nilsson
  Cc: Jonathan Cameron, David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Stefan Windfeldt-Prytz, linux-iio, devicetree, linux-kernel,
	kernel

On Fri, Oct 23, 2026 at 02:30:30PM +0200, Jesper X Nilsson wrote:
> Prepare opt4001 driver to be able to support OPT4041. Extend struct
> opt4001_chip_info with fields channels and device_id because OPT4041 has
> two channels and another device id.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

...

> -	ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1);
> +	ret = regmap_read(chip->regmap, reg, &light1);
>  	if (ret < 0) {
>  		dev_err(dev, "Failed to read data bytes");
>  		return ret;
>  	}
>  
> -	ret = regmap_read(chip->regmap, OPT4001_LIGHT1_LSB, &light2);
> +	ret = regmap_read(chip->regmap, reg + 1, &light2);
>  	if (ret < 0) {
>  		dev_err(dev, "Failed to read data bytes");
>  		return ret;

Can it be actually a bulk read? (Not part of this series, I assume.)

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v2 4/4] iio: light: opt4001: add support for opt4041
  2026-10-23 12:30 ` [PATCH v2 4/4] iio: light: opt4001: add support for opt4041 Jesper X Nilsson
@ 2026-10-23 13:53   ` Andy Shevchenko
  0 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2026-10-23 13:53 UTC (permalink / raw)
  To: Jesper X Nilsson
  Cc: Jonathan Cameron, David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Stefan Windfeldt-Prytz, linux-iio, devicetree, linux-kernel,
	kernel

On Fri, Oct 23, 2026 at 02:30:31PM +0200, Jesper X Nilsson wrote:
> Extend the opt4001 driver to also support OPT4041. The devices are very
> similar, with the difference being OPT4041 having two channels, one
> visible and one wide band channel ranging from 380nm to 1000nm.
> 
> The register map is almost the same. OPT4001 has registers to read out
> the last four values sampled. OPT4041 maps to the same registers, but
> has two channels, saving the last two samples for each channel.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

-- 
With Best Regards,
Andy Shevchenko



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

end of thread, other threads:[~2026-10-23 13:53 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-23 12:30 [PATCH v2 0/4] This series adds support for Texas Instruments OPT4041 Ambient light sensor Jesper X Nilsson
2026-10-23 12:30 ` [PATCH v2 1/4] dt-bindings: iio: light: opt4001: add opt4041 Jesper X Nilsson
2026-10-23 12:30 ` [PATCH v2 2/4] iio: light: opt4001: Re-use generic struct s32_fract Jesper X Nilsson
2026-10-23 12:30 ` [PATCH v2 3/4] iio: light: opt4001: refactor driver to prepare to support more devices Jesper X Nilsson
2026-10-23 13:51   ` Andy Shevchenko
2026-10-23 12:30 ` [PATCH v2 4/4] iio: light: opt4001: add support for opt4041 Jesper X Nilsson
2026-10-23 13:53   ` Andy Shevchenko

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

all inboxes | Powered by JetHome®