* [PATCH 0/2] Add support for AS7343 multi-spectral sensor
@ 2026-09-05 5:53 Chang Yu
2026-09-05 5:53 ` [PATCH 1/2] dt-bindings: iio: light: add as7343 Chang Yu
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Chang Yu @ 2026-09-05 5:53 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Chang Yu, Jonathan Cameron, David Lechner, Nuno Sá,
linux-iio, linux-kernel
This series adds initial support for the AMS AS7343 14-channel
multi-spectral sensor.
The sensor has 14 optical channels (11 visible + NIR + clear +
flicker) in total. This initial driver supports reading raw counts
from all 12 spectral channels (11 visible + NIR) via sysfs and basic
power management.
Not yet supported:
- Configurable integration time and gain
- Interrupt support
- Clear (VIS) channel and flicker detection
The driver uses `extend_name` to differentiate channels, exposing
files like in_intensity_F1_raw for channel F1, etc. via sysfs.
Patch 1 adds device tree bindings.
Patch 2 adds the driver.
Testing was performed on a Raspberry Pi 4.
Datasheet: [1]
Link: https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf [1]
Chang Yu (2):
dt-bindings: iio: light: add as7343
iio: light: add AS7343 multi-spectral sensor driver
.../bindings/iio/light/ams,as7343.yaml | 46 +++
MAINTAINERS | 7 +
drivers/iio/light/Kconfig | 11 +
drivers/iio/light/Makefile | 1 +
drivers/iio/light/as7343.c | 309 ++++++++++++++++++
5 files changed, 374 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/light/ams,as7343.yaml
create mode 100644 drivers/iio/light/as7343.c
--
2.55.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/2] dt-bindings: iio: light: add as7343
2026-09-05 5:53 [PATCH 0/2] Add support for AS7343 multi-spectral sensor Chang Yu
@ 2026-09-05 5:53 ` Chang Yu
2026-09-05 7:23 ` Krzysztof Kozlowski
2026-09-06 0:30 ` Jonathan Cameron
2026-09-05 5:53 ` [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver Chang Yu
2026-09-05 7:51 ` [PATCH 0/2] Add support for AS7343 multi-spectral sensor Andy Shevchenko
2 siblings, 2 replies; 12+ messages in thread
From: Chang Yu @ 2026-09-05 5:53 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Chang Yu, Jonathan Cameron, David Lechner, Nuno Sá,
linux-iio, linux-kernel
Add binding for AMS AS7343 which is a 14-channel multi-spectral sensor
with i2c address of 0x39.
Signed-off-by: Chang Yu <marcus.yu.56@gmail.com>
---
.../bindings/iio/light/ams,as7343.yaml | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/light/ams,as7343.yaml
diff --git a/Documentation/devicetree/bindings/iio/light/ams,as7343.yaml b/Documentation/devicetree/bindings/iio/light/ams,as7343.yaml
new file mode 100644
index 000000000000..fb996160cf8d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/light/ams,as7343.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/ams,as7343.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AMS AS7343 14-Channel Multi-Spectral Sensor
+
+maintainers:
+ - Chang Yu <marcus.yu.56@gmail.com>
+
+description: |
+ The AMS AS7343 is a 14-channel multi-spectral sensor with i2c address of 0x39.
+ https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf
+
+properties:
+ compatible:
+ enum:
+ - ams,as7343
+
+ reg:
+ description:
+ I2C address of the device (0x39).
+ maxItems: 1
+
+ vdd-supply: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ as73211@74 {
+ compatible = "ams,as7343";
+ reg = <0x39>;
+ };
+ };
--
2.55.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver
2026-09-05 5:53 [PATCH 0/2] Add support for AS7343 multi-spectral sensor Chang Yu
2026-09-05 5:53 ` [PATCH 1/2] dt-bindings: iio: light: add as7343 Chang Yu
@ 2026-09-05 5:53 ` Chang Yu
2026-09-05 6:42 ` Joshua Crofts
2026-09-06 0:30 ` Jonathan Cameron
2026-09-05 7:51 ` [PATCH 0/2] Add support for AS7343 multi-spectral sensor Andy Shevchenko
2 siblings, 2 replies; 12+ messages in thread
From: Chang Yu @ 2026-09-05 5:53 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Chang Yu, Jonathan Cameron, David Lechner, Nuno Sá,
linux-iio, linux-kernel
This patch adds a driver for the AMS AS7343 14-channel multi-spectral
sensor with I2C interface.
The driver exposes 12 spectral channels (11 visible + 1 near-infrared)
via the IIO sysfs interface. Each channel's raw data is provided as a
16-bit little-endian unsigned integer.
Basic power management (suspend/resume) is supported. More complex
features such as interrupt support and configurable gain/integration
time will be added in future patches.
Signed-off-by: Chang Yu <marcus.yu.56@gmail.com>
---
MAINTAINERS | 7 +
drivers/iio/light/Kconfig | 11 ++
drivers/iio/light/Makefile | 1 +
drivers/iio/light/as7343.c | 309 +++++++++++++++++++++++++++++++++++++
4 files changed, 328 insertions(+)
create mode 100644 drivers/iio/light/as7343.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 04fa5322d9f7..236102b3c28e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1430,6 +1430,13 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
F: drivers/iio/light/as73211.c
+AMS AS7343 DRIVER
+M: Chang Yu <marcus.yu.56@gmail.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/light/ams,as7343.yaml
+F: drivers/iio/light/as7343.c
+
AMT (Automatic Multicast Tunneling)
M: Taehee Yoo <ap420073@gmail.com>
L: netdev@vger.kernel.org
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index ef36824f312f..edbeeba9d873 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -149,6 +149,17 @@ config AS73211
This driver can also be built as a module. If so, the module
will be called as73211.
+config AS7343
+ tristate "AMS AS7343 14-Channel Multi-Spectral Sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y here to build support for the AMS AS7343 14-channel
+ multi-spectral sensor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called as7343.
+
config BH1745
tristate "ROHM BH1745 colour sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 64e354c49ed8..5d0d33802519 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_APDS9306) += apds9306.o
obj-$(CONFIG_APDS9960) += apds9960.o
obj-$(CONFIG_APDS9999) += apds9999.o
obj-$(CONFIG_AS73211) += as73211.o
+obj-$(CONFIG_AS7343) += as7343.o
obj-$(CONFIG_BH1745) += bh1745.o
obj-$(CONFIG_BH1750) += bh1750.o
obj-$(CONFIG_BH1780) += bh1780.o
diff --git a/drivers/iio/light/as7343.c b/drivers/iio/light/as7343.c
new file mode 100644
index 000000000000..b620dd308380
--- /dev/null
+++ b/drivers/iio/light/as7343.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Support for AMS AS7343 14-channel multi-spectral sensor.
+ * (7-bit I2C slave address 0x39)
+ *
+ * Based on the work of:
+ * Christian Eggers <ceggers@arri.de> (AS73211 driver)
+ *
+ * Copyright (c) 2026 Chang Yu <marcus.yu.56@gmail.com>
+ *
+ * Datasheets:
+ * https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf
+ *
+ * TODO:
+ * - Support for configurable gain and integration time
+ * - Interrupt support
+ * - Add support for reading the VIS channel
+ * - Flicker detection
+ */
+
+#include "linux/array_size.h"
+#include "linux/regmap.h"
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/stringify.h>
+
+#define AS7343_DRV_NAME "as7343"
+#define AS7343_DEVICE_ID 0x81
+
+/* AS7343 registers */
+#define AS7343_REG_ID 0x5a
+#define AS7343_REG_ENABLE 0x80
+#define AS7343_REG_ATIME 0x81
+#define AS7343_REG_CFG0 0xbf
+#define AS7343_REG_CFG1 0xc6
+#define AS7343_REG_CFG20 0xd6
+#define AS7343_REG_CONTROL 0xfa
+#define AS7343_REG_ASTATUS 0x94
+/* AS7343 data registers */
+#define AS7343_REG_DATA_FZ 0x95
+#define AS7343_REG_DATA_FY 0x97
+#define AS7343_REG_DATA_FXL 0x99
+#define AS7343_REG_DATA_NIR 0x9b
+#define AS7343_REG_DATA_F2 0xa1
+#define AS7343_REG_DATA_F3 0xa3
+#define AS7343_REG_DATA_F4 0xa5
+#define AS7343_REG_DATA_F6 0xa7
+#define AS7343_REG_DATA_F1 0xad
+#define AS7343_REG_DATA_F7 0xaf
+#define AS7343_REG_DATA_F8 0xb1
+#define AS7343_REG_DATA_F5 0xb3
+#define AS7343_REG_MAX 0xff
+
+/* AS7343 register bit masks */
+#define AS7343_ENABLE_PON BIT(0)
+#define AS7343_ENABLE_SP_EN BIT(1)
+#define AS7343_CFG0_REG_BANK BIT(4)
+#define AS7343_CFG20_AUTO_SMUX GENMASK(6, 5)
+#define AS7343_CONTROL_SW_RESET BIT(3)
+#define AS7343_CFG1_AGAIN GENMASK(4, 0)
+
+/* AS7343 settings */
+#define AS7343_INT_TIME 29 /* (29 + 1) * 2.87ms = 83.4ms */
+#define AS7343_GAIN 7 /* 64x gain */
+#define AS7343_AUTO_CHANNEL_READOUT 3 /* Automatic all-channel readout */
+
+/* AS7343 scan indices */
+#define AS7343_SCAN_INDEX_F1 0
+#define AS7343_SCAN_INDEX_F2 1
+#define AS7343_SCAN_INDEX_FZ 2
+#define AS7343_SCAN_INDEX_F3 3
+#define AS7343_SCAN_INDEX_F4 4
+#define AS7343_SCAN_INDEX_FY 5
+#define AS7343_SCAN_INDEX_F5 6
+#define AS7343_SCAN_INDEX_FXL 7
+#define AS7343_SCAN_INDEX_F6 8
+#define AS7343_SCAN_INDEX_F7 9
+#define AS7343_SCAN_INDEX_F8 10
+#define AS7343_SCAN_INDEX_NIR 11
+#define AS7343_SCAN_INDEX_TS 12
+
+#define AS7343_SCAN_MASK_ALL \
+ (BIT(AS7343_SCAN_INDEX_F1) | BIT(AS7343_SCAN_INDEX_F2) | \
+ BIT(AS7343_SCAN_INDEX_FZ) | BIT(AS7343_SCAN_INDEX_F3) | \
+ BIT(AS7343_SCAN_INDEX_F4) | BIT(AS7343_SCAN_INDEX_FY) | \
+ BIT(AS7343_SCAN_INDEX_F5) | BIT(AS7343_SCAN_INDEX_FXL) | \
+ BIT(AS7343_SCAN_INDEX_F6) | BIT(AS7343_SCAN_INDEX_F7) | \
+ BIT(AS7343_SCAN_INDEX_F8) | BIT(AS7343_SCAN_INDEX_NIR))
+
+static const unsigned long as7343_scan_masks[] = { AS7343_SCAN_MASK_ALL, 0 };
+
+#define AS7343_CHAN(_chan) \
+ { \
+ .type = IIO_INTENSITY, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .address = AS7343_REG_DATA_##_chan, \
+ .extend_name = __stringify(_chan), \
+ .scan_index = AS7343_SCAN_INDEX_##_chan, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ }, \
+}
+
+static const struct iio_chan_spec as7343_channels[] = {
+ AS7343_CHAN(F1),
+ AS7343_CHAN(F2),
+ AS7343_CHAN(FZ),
+ AS7343_CHAN(F3),
+ AS7343_CHAN(F4),
+ AS7343_CHAN(FY),
+ AS7343_CHAN(F5),
+ AS7343_CHAN(FXL),
+ AS7343_CHAN(F6),
+ AS7343_CHAN(F7),
+ AS7343_CHAN(F8),
+ AS7343_CHAN(NIR),
+ IIO_CHAN_SOFT_TIMESTAMP(AS7343_SCAN_INDEX_TS),
+};
+
+/**
+ * struct as7343_data - Instance data for one AS7343
+ * @client: I2C client.
+ * @regmap: Register map.
+ */
+struct as7343_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+};
+
+static int as7343_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct as7343_data *data = iio_priv(indio_dev);
+ unsigned int low, high;
+ unsigned int unused;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ /* Reading ASTATUS latches all data registers to this read.
+ * We don't care about the returned saturation/gain status for
+ * now.
+ */
+ ret = regmap_read(data->regmap, AS7343_REG_ASTATUS, &unused);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, chan->address, &low);
+ if (ret < 0)
+ return ret;
+ ret = regmap_read(data->regmap, chan->address + 1, &high);
+ if (ret < 0)
+ return ret;
+ *val = (high << 8) | low;
+ return IIO_VAL_INT;
+ }
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info as7343_info = {
+ .read_raw = as7343_read_raw,
+};
+
+static const struct regmap_config as7343_regmap_config = {
+ .name = "as7343",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AS7343_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+ .cache_type = REGCACHE_NONE,
+};
+
+static int as7343_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct as7343_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ unsigned int val;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &as7343_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ data->regmap = regmap;
+
+ indio_dev->name = AS7343_DRV_NAME;
+ indio_dev->info = &as7343_info;
+ indio_dev->channels = as7343_channels;
+ indio_dev->num_channels = ARRAY_SIZE(as7343_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->available_scan_masks = as7343_scan_masks;
+
+ ret = devm_regulator_get_enable(&client->dev, "vdd");
+ if (ret < 0)
+ return ret;
+ /* Power on */
+ ret = regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
+ AS7343_ENABLE_PON);
+ if (ret < 0)
+ return ret;
+
+ /* Need to set REG_BANK to 1 before we can access ID */
+ ret = regmap_set_bits(data->regmap, AS7343_REG_CFG0,
+ AS7343_CFG0_REG_BANK);
+ if (ret < 0)
+ return ret;
+ /* Check device ID */
+ ret = regmap_read(data->regmap, AS7343_REG_ID, &val);
+ if (val != AS7343_DEVICE_ID)
+ return -ENODEV;
+ /* Unset REG_BANK */
+ ret = regmap_clear_bits(data->regmap, AS7343_REG_CFG0,
+ AS7343_CFG0_REG_BANK);
+ if (ret < 0)
+ return ret;
+
+ /* Configure the SMUX to readout all channels */
+ ret = regmap_update_bits(data->regmap, AS7343_REG_CFG20,
+ AS7343_CFG20_AUTO_SMUX,
+ FIELD_PREP(AS7343_CFG20_AUTO_SMUX,
+ AS7343_AUTO_CHANNEL_READOUT));
+ if (ret < 0)
+ return ret;
+
+ /* Set 83.4ms integration time and x64 gain for now */
+ ret = regmap_write(data->regmap, AS7343_REG_ATIME, AS7343_INT_TIME);
+ if (ret < 0)
+ return ret;
+ ret = regmap_update_bits(data->regmap, AS7343_REG_CFG1,
+ AS7343_CFG1_AGAIN,
+ FIELD_PREP(AS7343_CFG1_AGAIN, AS7343_GAIN));
+ if (ret < 0)
+ return ret;
+
+ /* Start measurements */
+ ret = regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
+ AS7343_ENABLE_SP_EN);
+ if (ret < 0)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int as7343_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct as7343_data *data = iio_priv(indio_dev);
+
+ return regmap_clear_bits(data->regmap, AS7343_REG_ENABLE,
+ AS7343_ENABLE_SP_EN);
+}
+
+static int as7343_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct as7343_data *data = iio_priv(indio_dev);
+
+ return regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
+ AS7343_ENABLE_SP_EN);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(as7343_pm_ops, as7343_suspend, as7343_resume);
+
+static const struct of_device_id as7343_of_match[] = {
+ { .compatible = "ams,as7343" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, as7343_of_match);
+
+static const struct i2c_device_id as7343_id[] = {
+ { .name = "as7343" },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, as7343_id);
+
+static struct i2c_driver as7343_driver = {
+ .driver = {
+ .name = AS7343_DRV_NAME,
+ .of_match_table = as7343_of_match,
+ .pm = pm_sleep_ptr(&as7343_pm_ops),
+ },
+ .probe = as7343_probe,
+ .id_table = as7343_id,
+};
+module_i2c_driver(as7343_driver);
+
+MODULE_AUTHOR("Chang Yu <marcus.yu.56@gmail.com>");
+MODULE_DESCRIPTION("AS7343 14 Channel Multi-Spectral Sensor driver");
+MODULE_LICENSE("GPL");
--
2.55.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver
2026-09-05 5:53 ` [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver Chang Yu
@ 2026-09-05 6:42 ` Joshua Crofts
2026-09-06 0:11 ` Jonathan Cameron
2026-09-06 0:30 ` Jonathan Cameron
1 sibling, 1 reply; 12+ messages in thread
From: Joshua Crofts @ 2026-09-05 6:42 UTC (permalink / raw)
To: Chang Yu
Cc: Andy Shevchenko, Jonathan Cameron, David Lechner, Nuno Sá,
linux-iio, linux-kernel
Hi Chang,
Comments inline.
Josh
On Fri, 4 Sep 2026 22:53:26 -0700
Chang Yu <marcus.yu.56@gmail.com> wrote:
> This patch adds a driver for the AMS AS7343 14-channel multi-spectral
> sensor with I2C interface.
>
> The driver exposes 12 spectral channels (11 visible + 1 near-infrared)
> via the IIO sysfs interface. Each channel's raw data is provided as a
> 16-bit little-endian unsigned integer.
>
> Basic power management (suspend/resume) is supported. More complex
> features such as interrupt support and configurable gain/integration
> time will be added in future patches.
>
> Signed-off-by: Chang Yu <marcus.yu.56@gmail.com>
> ---
> MAINTAINERS | 7 +
> drivers/iio/light/Kconfig | 11 ++
> drivers/iio/light/Makefile | 1 +
> drivers/iio/light/as7343.c | 309 +++++++++++++++++++++++++++++++++++++
> 4 files changed, 328 insertions(+)
> create mode 100644 drivers/iio/light/as7343.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 04fa5322d9f7..236102b3c28e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1430,6 +1430,13 @@ S: Maintained
> F: Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
> F: drivers/iio/light/as73211.c
>
> +AMS AS7343 DRIVER
> +M: Chang Yu <marcus.yu.56@gmail.com>
> +L: linux-iio@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/iio/light/ams,as7343.yaml
This goes into the first patch in your series, i.e. the dt-binding
patch.
> +F: drivers/iio/light/as7343.c
This line should be then added in this patch.
> +
> AMT (Automatic Multicast Tunneling)
> M: Taehee Yoo <ap420073@gmail.com>
> L: netdev@vger.kernel.org
> diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
> index ef36824f312f..edbeeba9d873 100644
> --- a/drivers/iio/light/Kconfig
> +++ b/drivers/iio/light/Kconfig
> @@ -149,6 +149,17 @@ config AS73211
> This driver can also be built as a module. If so, the module
> will be called as73211.
>
> +config AS7343
> + tristate "AMS AS7343 14-Channel Multi-Spectral Sensor"
> + depends on I2C
> + select REGMAP_I2C
> + help
> + Say Y here to build support for the AMS AS7343 14-channel
> + multi-spectral sensor.
> +
> + To compile this driver as a module, choose M here: the module will
> + be called as7343.
> +
> config BH1745
> tristate "ROHM BH1745 colour sensor"
> depends on I2C
> diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
> index 64e354c49ed8..5d0d33802519 100644
> --- a/drivers/iio/light/Makefile
> +++ b/drivers/iio/light/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_APDS9306) += apds9306.o
> obj-$(CONFIG_APDS9960) += apds9960.o
> obj-$(CONFIG_APDS9999) += apds9999.o
> obj-$(CONFIG_AS73211) += as73211.o
> +obj-$(CONFIG_AS7343) += as7343.o
> obj-$(CONFIG_BH1745) += bh1745.o
> obj-$(CONFIG_BH1750) += bh1750.o
> obj-$(CONFIG_BH1780) += bh1780.o
> diff --git a/drivers/iio/light/as7343.c b/drivers/iio/light/as7343.c
> new file mode 100644
> index 000000000000..b620dd308380
> --- /dev/null
> +++ b/drivers/iio/light/as7343.c
> @@ -0,0 +1,309 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Support for AMS AS7343 14-channel multi-spectral sensor.
> + * (7-bit I2C slave address 0x39)
> + *
> + * Based on the work of:
> + * Christian Eggers <ceggers@arri.de> (AS73211 driver)
> + *
> + * Copyright (c) 2026 Chang Yu <marcus.yu.56@gmail.com>
> + *
> + * Datasheets:
> + * https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf
> + *
> + * TODO:
> + * - Support for configurable gain and integration time
> + * - Interrupt support
> + * - Add support for reading the VIS channel
> + * - Flicker detection
> + */
> +
> +#include "linux/array_size.h"
> +#include "linux/regmap.h"
Why did you use quotation marks here? <linux/array_size.h>
and <linux/regmap.h> are valid.
> +#include <linux/bitfield.h>
> +#include <linux/i2c.h>
> +#include <linux/iio/iio.h>
It's common to have the IIO headers separately below the
generic <linux/*> headers.
> +#include <linux/module.h>
> +#include <linux/pm.h>
> +#include <linux/stringify.h>
You're missing err.h, regulator/consumer.h,
> +
> +#define AS7343_DRV_NAME "as7343"
> +#define AS7343_DEVICE_ID 0x81
> +
> +/* AS7343 registers */
> +#define AS7343_REG_ID 0x5a
> +#define AS7343_REG_ENABLE 0x80
> +#define AS7343_REG_ATIME 0x81
> +#define AS7343_REG_CFG0 0xbf
> +#define AS7343_REG_CFG1 0xc6
> +#define AS7343_REG_CFG20 0xd6
> +#define AS7343_REG_CONTROL 0xfa
> +#define AS7343_REG_ASTATUS 0x94
Blank line here.
> +/* AS7343 data registers */
> +#define AS7343_REG_DATA_FZ 0x95
> +#define AS7343_REG_DATA_FY 0x97
> +#define AS7343_REG_DATA_FXL 0x99
> +#define AS7343_REG_DATA_NIR 0x9b
> +#define AS7343_REG_DATA_F2 0xa1
> +#define AS7343_REG_DATA_F3 0xa3
> +#define AS7343_REG_DATA_F4 0xa5
> +#define AS7343_REG_DATA_F6 0xa7
> +#define AS7343_REG_DATA_F1 0xad
> +#define AS7343_REG_DATA_F7 0xaf
> +#define AS7343_REG_DATA_F8 0xb1
> +#define AS7343_REG_DATA_F5 0xb3
> +#define AS7343_REG_MAX 0xff
> +
> +/* AS7343 register bit masks */
> +#define AS7343_ENABLE_PON BIT(0)
> +#define AS7343_ENABLE_SP_EN BIT(1)
> +#define AS7343_CFG0_REG_BANK BIT(4)
> +#define AS7343_CFG20_AUTO_SMUX GENMASK(6, 5)
> +#define AS7343_CONTROL_SW_RESET BIT(3)
> +#define AS7343_CFG1_AGAIN GENMASK(4, 0)
> +
> +/* AS7343 settings */
> +#define AS7343_INT_TIME 29 /* (29 + 1) * 2.87ms = 83.4ms */
> +#define AS7343_GAIN 7 /* 64x gain */
> +#define AS7343_AUTO_CHANNEL_READOUT 3 /* Automatic all-channel readout */
> +
> +/* AS7343 scan indices */
> +#define AS7343_SCAN_INDEX_F1 0
> +#define AS7343_SCAN_INDEX_F2 1
> +#define AS7343_SCAN_INDEX_FZ 2
> +#define AS7343_SCAN_INDEX_F3 3
> +#define AS7343_SCAN_INDEX_F4 4
> +#define AS7343_SCAN_INDEX_FY 5
> +#define AS7343_SCAN_INDEX_F5 6
> +#define AS7343_SCAN_INDEX_FXL 7
> +#define AS7343_SCAN_INDEX_F6 8
> +#define AS7343_SCAN_INDEX_F7 9
> +#define AS7343_SCAN_INDEX_F8 10
> +#define AS7343_SCAN_INDEX_NIR 11
> +#define AS7343_SCAN_INDEX_TS 12
> +
> +#define AS7343_SCAN_MASK_ALL \
> + (BIT(AS7343_SCAN_INDEX_F1) | BIT(AS7343_SCAN_INDEX_F2) | \
> + BIT(AS7343_SCAN_INDEX_FZ) | BIT(AS7343_SCAN_INDEX_F3) | \
> + BIT(AS7343_SCAN_INDEX_F4) | BIT(AS7343_SCAN_INDEX_FY) | \
> + BIT(AS7343_SCAN_INDEX_F5) | BIT(AS7343_SCAN_INDEX_FXL) | \
> + BIT(AS7343_SCAN_INDEX_F6) | BIT(AS7343_SCAN_INDEX_F7) | \
> + BIT(AS7343_SCAN_INDEX_F8) | BIT(AS7343_SCAN_INDEX_NIR))
> +
> +static const unsigned long as7343_scan_masks[] = { AS7343_SCAN_MASK_ALL, 0 };
> +
> +#define AS7343_CHAN(_chan) \
> + { \
> + .type = IIO_INTENSITY, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .address = AS7343_REG_DATA_##_chan, \
> + .extend_name = __stringify(_chan), \
> + .scan_index = AS7343_SCAN_INDEX_##_chan, \
> + .scan_type = { \
> + .sign = 'u', \
> + .realbits = 16, \
> + .storagebits = 16, \
> + .endianness = IIO_LE, \
> + }, \
> +}
> +
> +static const struct iio_chan_spec as7343_channels[] = {
> + AS7343_CHAN(F1),
> + AS7343_CHAN(F2),
> + AS7343_CHAN(FZ),
> + AS7343_CHAN(F3),
> + AS7343_CHAN(F4),
> + AS7343_CHAN(FY),
> + AS7343_CHAN(F5),
> + AS7343_CHAN(FXL),
> + AS7343_CHAN(F6),
> + AS7343_CHAN(F7),
> + AS7343_CHAN(F8),
> + AS7343_CHAN(NIR),
Don't forget to update any mentions of only 12 channels being
implemented once you add support for the Flicker and VIS channel.
> + IIO_CHAN_SOFT_TIMESTAMP(AS7343_SCAN_INDEX_TS),
> +};
> +
> +/**
> + * struct as7343_data - Instance data for one AS7343
> + * @client: I2C client.
> + * @regmap: Register map.
> + */
Eh, I'd remove the comment for now as the contents of the struct
are pretty self explanatory.
> +struct as7343_data {
> + struct i2c_client *client;
> + struct regmap *regmap;
> +};
> +
> +static int as7343_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + struct as7343_data *data = iio_priv(indio_dev);
> + unsigned int low, high;
> + unsigned int unused;
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW: {
> + /* Reading ASTATUS latches all data registers to this read.
> + * We don't care about the returned saturation/gain status for
> + * now.
> + */
> + ret = regmap_read(data->regmap, AS7343_REG_ASTATUS, &unused);
> + if (ret < 0)
> + return ret;
> +
> + ret = regmap_read(data->regmap, chan->address, &low);
> + if (ret < 0)
> + return ret;
Blank line here.
> + ret = regmap_read(data->regmap, chan->address + 1, &high);
> + if (ret < 0)
> + return ret;
> + *val = (high << 8) | low;
> + return IIO_VAL_INT;
> + }
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
...
> + /* Need to set REG_BANK to 1 before we can access ID */
> + ret = regmap_set_bits(data->regmap, AS7343_REG_CFG0,
> + AS7343_CFG0_REG_BANK);
> + if (ret < 0)
> + return ret;
> + /* Check device ID */
Unnecessary comment, add a blank line instead.
> + ret = regmap_read(data->regmap, AS7343_REG_ID, &val);
> + if (val != AS7343_DEVICE_ID)
> + return -ENODEV;
It's better to just do a dev_warn() in case of any fallback
devices instead of a hard return.
> + /* Unset REG_BANK */
Unnecessary comment.
> + ret = regmap_clear_bits(data->regmap, AS7343_REG_CFG0,
> + AS7343_CFG0_REG_BANK);
> + if (ret < 0)
> + return ret;
> +
> + /* Configure the SMUX to readout all channels */
> + ret = regmap_update_bits(data->regmap, AS7343_REG_CFG20,
> + AS7343_CFG20_AUTO_SMUX,
> + FIELD_PREP(AS7343_CFG20_AUTO_SMUX,
> + AS7343_AUTO_CHANNEL_READOUT));
> + if (ret < 0)
> + return ret;
> +
> + /* Set 83.4ms integration time and x64 gain for now */
Good for an initial draft, however you'll definitely have to
implement the write function for this to get merged into mainline.
Skimming the datasheet shows that there are more integration times
possible, not to mention that you can also set the gain etc.
> + ret = regmap_write(data->regmap, AS7343_REG_ATIME, AS7343_INT_TIME);
> + if (ret < 0)
> + return ret;
Blank line.
> + ret = regmap_update_bits(data->regmap, AS7343_REG_CFG1,
> + AS7343_CFG1_AGAIN,
> + FIELD_PREP(AS7343_CFG1_AGAIN, AS7343_GAIN));
> + if (ret < 0)
> + return ret;
> +
> + /* Start measurements */
> + ret = regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
> + AS7343_ENABLE_SP_EN);
> + if (ret < 0)
> + return ret;
> +
> + return devm_iio_device_register(dev, indio_dev);
> +}
> +
> +static int as7343_suspend(struct device *dev)
> +{
> + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> + struct as7343_data *data = iio_priv(indio_dev);
> +
> + return regmap_clear_bits(data->regmap, AS7343_REG_ENABLE,
> + AS7343_ENABLE_SP_EN);
> +}
> +
> +static int as7343_resume(struct device *dev)
> +{
> + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> + struct as7343_data *data = iio_priv(indio_dev);
> +
> + return regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
> + AS7343_ENABLE_SP_EN);
> +}
> +
You have suspend/resume functions, yet you're missing a
devm_pm_runtime_enable() in probe. Additionally, you could enable
the autosuspend function as well (note, you'll have to wake the
device before reading, there are macros that simplify this though,
see PM_RUNTIME_ACQUIRE_AUTOSUSPEND)
Also, there isn't any devm_add_action_or_reset() function that
guarantees powering the device off on teardown (you can reuse your
suspend function as the callback).
> +static DEFINE_SIMPLE_DEV_PM_OPS(as7343_pm_ops, as7343_suspend, as7343_resume);
> +
> +static const struct of_device_id as7343_of_match[] = {
> + { .compatible = "ams,as7343" },
> + {},
Remove the comma + add a space in between the {}
Same goes for the struct i2c_device_id definition.
--
Kind regards,
Joshua Crofts
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] dt-bindings: iio: light: add as7343
2026-09-05 5:53 ` [PATCH 1/2] dt-bindings: iio: light: add as7343 Chang Yu
@ 2026-09-05 7:23 ` Krzysztof Kozlowski
2026-09-06 0:30 ` Jonathan Cameron
1 sibling, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-05 7:23 UTC (permalink / raw)
To: Chang Yu, Andy Shevchenko
Cc: Jonathan Cameron, David Lechner, Nuno Sá, linux-iio, linux-kernel
On 05/09/2026 07:53, Chang Yu wrote:
> Add binding for AMS AS7343 which is a 14-channel multi-spectral sensor
> with i2c address of 0x39.
>
> Signed-off-by: Chang Yu <marcus.yu.56@gmail.com>
Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.
Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.
You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time.
Please kindly resend and include all necessary To/Cc entries.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/2] Add support for AS7343 multi-spectral sensor
2026-09-05 5:53 [PATCH 0/2] Add support for AS7343 multi-spectral sensor Chang Yu
2026-09-05 5:53 ` [PATCH 1/2] dt-bindings: iio: light: add as7343 Chang Yu
2026-09-05 5:53 ` [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver Chang Yu
@ 2026-09-05 7:51 ` Andy Shevchenko
2026-09-05 23:40 ` Jonathan Cameron
2 siblings, 1 reply; 12+ messages in thread
From: Andy Shevchenko @ 2026-09-05 7:51 UTC (permalink / raw)
To: Chang Yu
Cc: Andy Shevchenko, Jonathan Cameron, David Lechner, Nuno Sá,
linux-iio, linux-kernel
On Fri, Sep 04, 2026 at 10:53:24PM -0700, Chang Yu wrote:
...
> Datasheet: [1]
>
> Link: https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf [1]
This is a Datasheet link, no need to have three lines for it, just
Datasheet: https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/2] Add support for AS7343 multi-spectral sensor
2026-09-05 7:51 ` [PATCH 0/2] Add support for AS7343 multi-spectral sensor Andy Shevchenko
@ 2026-09-05 23:40 ` Jonathan Cameron
0 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2026-09-05 23:40 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Chang Yu, Andy Shevchenko, Jonathan Cameron, David Lechner,
Nuno Sá,
linux-iio, linux-kernel
On 2026-09-05 10:51:48+03:00, Andy Shevchenko wrote:
> On Fri, Sep 04, 2026 at 10:53:24PM -0700, Chang Yu wrote:
>
> ...
>
> > Datasheet: [1]
> >
> > Link: https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf [1]
>
> This is a Datasheet link, no need to have three lines for it, just
>
> Datasheet: https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf
In addition to this I'd like to see the tag in the driver commit tag
block. That is more useful than having it in the cover letter.
Thanks,
Jonathan
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver
2026-09-05 6:42 ` Joshua Crofts
@ 2026-09-06 0:11 ` Jonathan Cameron
2026-09-07 6:36 ` Chang Yu
0 siblings, 1 reply; 12+ messages in thread
From: Jonathan Cameron @ 2026-09-06 0:11 UTC (permalink / raw)
To: Joshua Crofts
Cc: Chang Yu, Andy Shevchenko, David Lechner, Nuno Sá,
linux-iio, linux-kernel
On Sat, 5 Sep 2026 08:42:58 +0200
Joshua Crofts <joshua.crofts1@gmail.com> wrote:
> Hi Chang,
>
> Comments inline.
>
> Josh
>
> On Fri, 4 Sep 2026 22:53:26 -0700
> Chang Yu <marcus.yu.56@gmail.com> wrote:
>
> > This patch adds a driver for the AMS AS7343 14-channel multi-spectral
> > sensor with I2C interface.
> >
> > The driver exposes 12 spectral channels (11 visible + 1 near-infrared)
> > via the IIO sysfs interface. Each channel's raw data is provided as a
> > 16-bit little-endian unsigned integer.
> >
> > Basic power management (suspend/resume) is supported. More complex
> > features such as interrupt support and configurable gain/integration
> > time will be added in future patches.
> >
> > Signed-off-by: Chang Yu <marcus.yu.56@gmail.com>
Nice review. A few small comments on necessity of features etc
inline.
> > diff --git a/drivers/iio/light/as7343.c b/drivers/iio/light/as7343.c
> > new file mode 100644
> > index 000000000000..b620dd308380
> > --- /dev/null
> > +++ b/drivers/iio/light/as7343.c
> > + /* Need to set REG_BANK to 1 before we can access ID */
> > + ret = regmap_set_bits(data->regmap, AS7343_REG_CFG0,
> > + AS7343_CFG0_REG_BANK);
> > + if (ret < 0)
> > + return ret;
> > + /* Check device ID */
...
>
> > + ret = regmap_read(data->regmap, AS7343_REG_ID, &val);
> > + if (val != AS7343_DEVICE_ID)
> > + return -ENODEV;
>
> It's better to just do a dev_warn() in case of any fallback
> devices instead of a hard return.
dev_info(dev, "Unknown device ID: %x\n", val);
or something like this. In many cases a mismatch is not an error, it is a
fallback device tree compatible being used. This is common when a manufacturer
issues a new device that is a refresh of an older design and so interface
compatible but with a different device ID.
...
> > +
> > + /* Set 83.4ms integration time and x64 gain for now */
>
> Good for an initial draft, however you'll definitely have to
> implement the write function for this to get merged into mainline.
> Skimming the datasheet shows that there are more integration times
> possible, not to mention that you can also set the gain etc.
If there is a sensible default / initial value that works most of the time
(short value probably to avoid saturation) then controlling this isn't
a requirement for merge. It's a nice to have though!
...
> > +
> > +static int as7343_suspend(struct device *dev)
> > +{
> > + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> > + struct as7343_data *data = iio_priv(indio_dev);
> > +
> > + return regmap_clear_bits(data->regmap, AS7343_REG_ENABLE,
> > + AS7343_ENABLE_SP_EN);
> > +}
> > +
> > +static int as7343_resume(struct device *dev)
> > +{
> > + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> > + struct as7343_data *data = iio_priv(indio_dev);
> > +
> > + return regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
> > + AS7343_ENABLE_SP_EN);
> > +}
> > +
>
> You have suspend/resume functions, yet you're missing a
> devm_pm_runtime_enable() in probe.
There is not requirement to do any specific combination of power management
for an IIO driver because what is necessary is very dependent on the usecase
a particular developer has. So runtime pm is a nice to have only (as is the
suspend / resume stuff we have here). May well make sense to use the same
for both types (there are macros to ensure that).
> Additionally, you could enable
> the autosuspend function as well (note, you'll have to wake the
> device before reading, there are macros that simplify this though,
> see PM_RUNTIME_ACQUIRE_AUTOSUSPEND)
All nice to haves indeed - but not strictly necessary. Many drivers
don't go that far initially and it is fairly easy to retrofit this stuff
if someone cares.
Jonathan
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] dt-bindings: iio: light: add as7343
2026-09-05 5:53 ` [PATCH 1/2] dt-bindings: iio: light: add as7343 Chang Yu
2026-09-05 7:23 ` Krzysztof Kozlowski
@ 2026-09-06 0:30 ` Jonathan Cameron
1 sibling, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2026-09-06 0:30 UTC (permalink / raw)
To: Chang Yu
Cc: Andy Shevchenko, Jonathan Cameron, David Lechner, Nuno Sá,
linux-iio, linux-kernel
> Add binding for AMS AS7343 which is a 14-channel multi-spectral sensor
> with i2c address of 0x39.
>
> Signed-off-by: Chang Yu <marcus.yu.56@gmail.com>
Given you need to send again to include right folk for testing and
review here are a few initial things to fix up and make it a proper
v2
>
> diff --git a/Documentation/devicetree/bindings/iio/light/ams,as7343.yaml b/Documentation/devicetree/bindings/iio/light/ams,as7343.yaml
> new file mode 100644
> index 000000000000..fb996160cf8d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/light/ams,as7343.yaml
> @@ -0,0 +1,46 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/light/ams,as7343.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: AMS AS7343 14-Channel Multi-Spectral Sensor
> +
> +maintainers:
> + - Chang Yu <marcus.yu.56@gmail.com>
> +
> +description: |
> + The AMS AS7343 is a 14-channel multi-spectral sensor with i2c address of 0x39.
> + https://look.ams-osram.com/m/5f2d27fff9a874d2/original/AS7343-14-Channel-Multi-Spectral-Sensor.pdf
> +
> +properties:
> + compatible:
> + enum:
> + - ams,as7343
> +
> + reg:
> + description:
> + I2C address of the device (0x39).
> + maxItems: 1
> +
> + vdd-supply: true
Power supplies that are needed in practice for a device to function
are always added to the required list (there are some historical
quirks in some bindings). We do that even though the Linux regulator
framework will hand you a fake supply if you don't provide one via
the dt on basis the power is presumably always turned on. The reason
for this is otherwise we can't see when we have a truely optional
power supply (common for references where there may be a number of
alternative sources such as internal voltage references).
I'd expect some binding info about whether LDR is connected to
anything or not. (LED Driver - who picked a common term like LDR
which is normally Light Dependent Resistor?!!) We need the driver
to be able to decide to turn that on or off + set the drive
current. Look at proximity sensors for examples of ways this might
be done.
There is also an interrupt pin that definitely wants to
be documented. Bindings should be as full as possible. The only
time we leave stuff out is when we have no idea how to write
the binding - that happens for sufficiently unusual corners that
aren't true for this.
The gpio is more interesting but at lest one option is to use
it as just that, so I'd expect to see binding for that. The
sync stuff is perhaps an area where the binding design may be
less obvious and postponing that (mention it in the patch description)
might be the best path forwards.
> +
> +required:
> + - compatible
> + - reg
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/irq.h>
Sashiko:
[Severity: Low]
Is it necessary to include irq.h here? The example does not appear to
define or use any interrupts.
-
Seems like a valid thing to clean up!
> +
> + i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + as73211@74 {
Should be a generic name not the part number. If there isn't a
suitable one in the dt specification or in general use, make up
a new one. Maybe multispectral is suitable here - I haven't really
thought about it much!
> + compatible = "ams,as7343";
> + reg = <0x39>;
Sashiko:
[Severity: Low]
Does the unit address (@74) mismatch the first address in the reg property
(<0x39>)? This might trigger a unit_address_vs_reg warning during
dt_binding_check and dtc compilation.
Also, should the node name use a generic functional name (such as
sensor@39) instead of referring to a different device (as73211)?
-
> + };
> + };
Thanks,
Jonathan
--
Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver
2026-09-05 5:53 ` [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver Chang Yu
2026-09-05 6:42 ` Joshua Crofts
@ 2026-09-06 0:30 ` Jonathan Cameron
2026-09-07 6:51 ` Chang Yu
1 sibling, 1 reply; 12+ messages in thread
From: Jonathan Cameron @ 2026-09-06 0:30 UTC (permalink / raw)
To: Chang Yu
Cc: Andy Shevchenko, Jonathan Cameron, David Lechner, Nuno Sá,
linux-iio, linux-kernel
> This patch adds a driver for the AMS AS7343 14-channel multi-spectral
> sensor with I2C interface.
>
> The driver exposes 12 spectral channels (11 visible + 1 near-infrared)
> via the IIO sysfs interface. Each channel's raw data is provided as a
> 16-bit little-endian unsigned integer.
>
> Basic power management (suspend/resume) is supported. More complex
> features such as interrupt support and configurable gain/integration
> time will be added in future patches.
>
> Signed-off-by: Chang Yu <marcus.yu.56@gmail.com>
Hi Chang Yu,
I've avoided too much duplication with Joshua's already pretty
thorough review so just a few additional comments inline.
> diff --git a/drivers/iio/light/as7343.c b/drivers/iio/light/as7343.c
> new file mode 100644
> index 000000000000..b620dd308380
> --- /dev/null
> +++ b/drivers/iio/light/as7343.c
...
> +
> +#define AS7343_DRV_NAME "as7343"
> +#define AS7343_DEVICE_ID 0x81
For now I'd just put that inline. If you end up with additional
supported parts it will end up in a chip_info structure of some kind.
> +
> +/* AS7343 registers */
> +#define AS7343_REG_ID 0x5a
> +#define AS7343_REG_ENABLE 0x80
> +#define AS7343_REG_ATIME 0x81
> +#define AS7343_REG_CFG0 0xbf
> +#define AS7343_REG_CFG1 0xc6
> +#define AS7343_REG_CFG20 0xd6
It is useful practice to document a register address its fields
and their values all in one place. If you look at other drivers
we often do that using some indentiation. E.g.
This keeps the register map easy to read and the names all make
it very obvious if writes are to the wrong register or similar.
> +#define AS7343_REG_CONTROL 0xfa
> +#define AS7343_REG_ASTATUS 0x94
> +/* AS7343 data registers */
> +#define AS7343_REG_DATA_FZ 0x95
> +#define AS7343_REG_DATA_FY 0x97
> +#define AS7343_REG_DATA_FXL 0x99
> +#define AS7343_REG_DATA_NIR 0x9b
> +#define AS7343_REG_DATA_F2 0xa1
> +#define AS7343_REG_DATA_F3 0xa3
> +#define AS7343_REG_DATA_F4 0xa5
> +#define AS7343_REG_DATA_F6 0xa7
> +#define AS7343_REG_DATA_F1 0xad
> +#define AS7343_REG_DATA_F7 0xaf
> +#define AS7343_REG_DATA_F8 0xb1
> +#define AS7343_REG_DATA_F5 0xb3
> +#define AS7343_REG_MAX 0xff
> +
> +/* AS7343 register bit masks */
> +#define AS7343_ENABLE_PON BIT(0)
> +#define AS7343_ENABLE_SP_EN BIT(1)
> +#define AS7343_CFG0_REG_BANK BIT(4)
> +#define AS7343_CFG20_AUTO_SMUX GENMASK(6, 5)
> +#define AS7343_CONTROL_SW_RESET BIT(3)
> +#define AS7343_CFG1_AGAIN GENMASK(4, 0)
> +
> +/* AS7343 settings */
> +#define AS7343_INT_TIME 29 /* (29 + 1) * 2.87ms = 83.4ms */
Implement this as a function to do the maths and take the input in
usecs. Then you can call that with 83400 as the parameter to set the
default value. Why this default?
> +#define AS7343_GAIN 7 /* 64x gain */
This is a field value, so naming should refect that.
AS7343_CFG1_AGAIN_X64 or something like that. May well make sense
to just specify all the possible field values by define - or replace
them with function given they are powers of 2 I think (be it -1 as
the first one.
> +#define AS7343_AUTO_CHANNEL_READOUT 3 /* Automatic all-channel readout */
This is a field value in AS7343_CFG20_AUTO_SMUX so naming
should reflect that.
or something like that.
> +
> +/* AS7343 scan indices */
> +#define AS7343_SCAN_INDEX_F1 0
> +#define AS7343_SCAN_INDEX_F2 1
> +#define AS7343_SCAN_INDEX_FZ 2
> +#define AS7343_SCAN_INDEX_F3 3
> +#define AS7343_SCAN_INDEX_F4 4
> +#define AS7343_SCAN_INDEX_FY 5
> +#define AS7343_SCAN_INDEX_F5 6
> +#define AS7343_SCAN_INDEX_FXL 7
> +#define AS7343_SCAN_INDEX_F6 8
> +#define AS7343_SCAN_INDEX_F7 9
> +#define AS7343_SCAN_INDEX_F8 10
> +#define AS7343_SCAN_INDEX_NIR 11
> +#define AS7343_SCAN_INDEX_TS 12
Probably an enum is appropriate. Not used for now though so drop.
> +
> +#define AS7343_SCAN_MASK_ALL \
> + (BIT(AS7343_SCAN_INDEX_F1) | BIT(AS7343_SCAN_INDEX_F2) | \
> + BIT(AS7343_SCAN_INDEX_FZ) | BIT(AS7343_SCAN_INDEX_F3) | \
> + BIT(AS7343_SCAN_INDEX_F4) | BIT(AS7343_SCAN_INDEX_FY) | \
> + BIT(AS7343_SCAN_INDEX_F5) | BIT(AS7343_SCAN_INDEX_FXL) | \
> + BIT(AS7343_SCAN_INDEX_F6) | BIT(AS7343_SCAN_INDEX_F7) | \
> + BIT(AS7343_SCAN_INDEX_F8) | BIT(AS7343_SCAN_INDEX_NIR))
> +
> +static const unsigned long as7343_scan_masks[] = { AS7343_SCAN_MASK_ALL, 0 };
As below. This should only come in when or if you add buffered
data capture. Today it is meaningless so tremove it and the MASK_ALL
definition.
> +
> +#define AS7343_CHAN(_chan) \
> + { \
> + .type = IIO_INTENSITY, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .address = AS7343_REG_DATA_##_chan, \
> + .extend_name = __stringify(_chan), \
No for this - we no longer use extend_name. It was a terrible bit
of ABI design a long time back. Instead use channel labels to provide
in_intensityX_label with a suitable string.
> + .scan_index = AS7343_SCAN_INDEX_##_chan, \
> + .scan_type = { \
> + .sign = 'u', \
> + .realbits = 16, \
> + .storagebits = 16, \
> + .endianness = IIO_LE, \
> + }, \
You aren't implementing any buffered stuff so you definitely
aren't using all of this scan stuff.
Only specify values of things that you actually use.
> +}
> +
> +static const struct iio_chan_spec as7343_channels[] = {
> + AS7343_CHAN(F1),
> + AS7343_CHAN(F2),
> + AS7343_CHAN(FZ),
> + AS7343_CHAN(F3),
> + AS7343_CHAN(F4),
> + AS7343_CHAN(FY),
> + AS7343_CHAN(F5),
> + AS7343_CHAN(FXL),
> + AS7343_CHAN(F6),
> + AS7343_CHAN(F7),
> + AS7343_CHAN(F8),
> + AS7343_CHAN(NIR),
> + IIO_CHAN_SOFT_TIMESTAMP(AS7343_SCAN_INDEX_TS),
> +};
...
> +struct as7343_data {
> + struct i2c_client *client;
Not used that I can see - so drop client from this.
> + struct regmap *regmap;
> +};
> +
> +static int as7343_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + struct as7343_data *data = iio_priv(indio_dev);
> + unsigned int low, high;
> + unsigned int unused;
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW: {
> + /* Reading ASTATUS latches all data registers to this read.
Wrong comment style - see all the other IIO drivers.
Note only net and a few other places use this style in the kernel.
> + * We don't care about the returned saturation/gain status for
> + * now.
> + */
> + ret = regmap_read(data->regmap, AS7343_REG_ASTATUS, &unused);
> + if (ret < 0)
As below, for regmap calls prefer
if (ret)
return ret;
> + return ret;
> +
> + ret = regmap_read(data->regmap, chan->address, &low);
> + if (ret < 0)
> + return ret;
> + ret = regmap_read(data->regmap, chan->address + 1, &high);
> + if (ret < 0)
> + return ret;
No option to do a bulk read? I'd rather see one of those combined
with an appropriate endian conversion. The datasheet mentions auto
increment so that regmap_bulk_read() should just work I think.
> + *val = (high << 8) | low;
> + return IIO_VAL_INT;
> + }
> +
> + default:
> + return -EINVAL;
> + }
> +}
...
> +static const struct regmap_config as7343_regmap_config = {
> + .name = "as7343",
> + .reg_bits = 8,
> + .val_bits = 8,
> + .max_register = AS7343_REG_MAX,
> + .reg_format_endian = REGMAP_ENDIAN_LITTLE,
> + .val_format_endian = REGMAP_ENDIAN_LITTLE,
> + .cache_type = REGCACHE_NONE,
It is a big enough register map that it may make sense to use
regcache and provide all the info on what is volatile etc.
> +};
> +
> +static int as7343_probe(struct i2c_client *client)
> +{
> + struct device *dev = &client->dev;
> + struct as7343_data *data;
> + struct iio_dev *indio_dev;
> + struct regmap *regmap;
> + unsigned int val;
> + int ret;
> +
> + indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + regmap = devm_regmap_init_i2c(client, &as7343_regmap_config);
> + if (IS_ERR(regmap))
> + return PTR_ERR(regmap);
> +
> + data = iio_priv(indio_dev);
> + i2c_set_clientdata(client, indio_dev);
> + data->client = client;
This rings alarm bells given you also have a regmap. Turns
out you don't use it - so drop this from data.
> + data->regmap = regmap;
> +
> + indio_dev->name = AS7343_DRV_NAME;
Use the string directly here. There is no particular reason it should
be the same as the driver naming, so I'd much rather see what the
value is here.
> + indio_dev->info = &as7343_info;
> + indio_dev->channels = as7343_channels;
> + indio_dev->num_channels = ARRAY_SIZE(as7343_channels);
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->available_scan_masks = as7343_scan_masks;
This is only relevant if you are doing buffered outputs, which
you aren't. So it's unused. Remove it.
> +
> + ret = devm_regulator_get_enable(&client->dev, "vdd");
> + if (ret < 0)
> + return ret;
> + /* Power on */
> + ret = regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
> + AS7343_ENABLE_PON);
> + if (ret < 0)
regmap only uses 0 for sucess and negative for failure, so
where they are regmap calls I'd prefer
if (ret)
return ret;
That makes some places where you can do
return regmap*();
at the end of a function the same as all the places you have
to check it before carrying on.
> + return ret;
> +
...
> +static int as7343_suspend(struct device *dev)
> +{
> + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> + struct as7343_data *data = iio_priv(indio_dev);
As below.
> +
> + return regmap_clear_bits(data->regmap, AS7343_REG_ENABLE,
> + AS7343_ENABLE_SP_EN);
> +}
> +
> +static int as7343_resume(struct device *dev)
> +{
> + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct iio_dev *indio_dev = dev_get_drvdata(dev);
Whilst a little odd given you use i2c_set_clientdata() to set it up
this pattern is well enough known by reviewers that we do it
this way anyway to sae on complexity of going backwards and forwards
via the i2c client.
> + struct as7343_data *data = iio_priv(indio_dev);
> +
> + return regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
> + AS7343_ENABLE_SP_EN);
> +}
> +
> +static DEFINE_SIMPLE_DEV_PM_OPS(as7343_pm_ops, as7343_suspend, as7343_resume);
> +};
> +MODULE_DEVICE_TABLE(i2c, as7343_id);
> +
> +static struct i2c_driver as7343_driver = {
> + .driver = {
> + .name = AS7343_DRV_NAME,
As above, just put the string here. Only use macros for things
like this when they help readability or enforce necessary matching
between multiple locations.
--
Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver
2026-09-06 0:11 ` Jonathan Cameron
@ 2026-09-07 6:36 ` Chang Yu
0 siblings, 0 replies; 12+ messages in thread
From: Chang Yu @ 2026-09-07 6:36 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Joshua Crofts, Chang Yu, Andy Shevchenko, David Lechner,
Nuno Sá,
linux-iio, linux-kernel
Hi Jonathan and Joshua,
Thanks for the thorough review. Just adding some clarifying comments inline
for what I plan to do in v2. I should be able to send over v2 within a few
business days.
On Sun, Sep 06, 2026 at 01:11:45AM +0100, Jonathan Cameron wrote:
> On Sat, 5 Sep 2026 08:42:58 +0200
> Joshua Crofts <joshua.crofts1@gmail.com> wrote:
>
> > Hi Chang,
> >
> > Comments inline.
> >
> > Josh
> >
> > On Fri, 4 Sep 2026 22:53:26 -0700
> > Chang Yu <marcus.yu.56@gmail.com> wrote:
> >
> > > This patch adds a driver for the AMS AS7343 14-channel multi-spectral
> > > sensor with I2C interface.
>
> ...
>
> > > +
> > > + /* Set 83.4ms integration time and x64 gain for now */
> >
> > Good for an initial draft, however you'll definitely have to
> > implement the write function for this to get merged into mainline.
> > Skimming the datasheet shows that there are more integration times
> > possible, not to mention that you can also set the gain etc.
>
> If there is a sensible default / initial value that works most of the time
> (short value probably to avoid saturation) then controlling this isn't
> a requirement for merge. It's a nice to have though!
I'll defer controlling integration/gain to future patches then. x256
gain and 50.1ms integration test are the defaults recommended by the
datasheet. It is also what adafruit uses in their arduino driver
(https://github.com/adafruit/Adafruit_AS7343/blob/main/Adafruit_AS7343.cpp).
They also seem to work well enough when I was testing on hardware.
So I'll use those values in v2 for now.
>
> ...
>
> > > +
> > > +static int as7343_suspend(struct device *dev)
> > > +{
> > > + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> > > + struct as7343_data *data = iio_priv(indio_dev);
> > > +
> > > + return regmap_clear_bits(data->regmap, AS7343_REG_ENABLE,
> > > + AS7343_ENABLE_SP_EN);
> > > +}
> > > +
> > > +static int as7343_resume(struct device *dev)
> > > +{
> > > + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> > > + struct as7343_data *data = iio_priv(indio_dev);
> > > +
> > > + return regmap_set_bits(data->regmap, AS7343_REG_ENABLE,
> > > + AS7343_ENABLE_SP_EN);
> > > +}
> > > +
> >
> > You have suspend/resume functions, yet you're missing a
> > devm_pm_runtime_enable() in probe.
>
> There is not requirement to do any specific combination of power management
> for an IIO driver because what is necessary is very dependent on the usecase
> a particular developer has. So runtime pm is a nice to have only (as is the
> suspend / resume stuff we have here). May well make sense to use the same
> for both types (there are macros to ensure that).
>
> > Additionally, you could enable
> > the autosuspend function as well (note, you'll have to wake the
> > device before reading, there are macros that simplify this though,
> > see PM_RUNTIME_ACQUIRE_AUTOSUSPEND)
>
> All nice to haves indeed - but not strictly necessary. Many drivers
> don't go that far initially and it is fairly easy to retrofit this stuff
> if someone cares.
>
I'll fix up the suspend/resume stuff per Joshua's comments. But I'll
defer autosuspend to future patches. I'll mention this in the v2 patch as well.
Best,
Chang
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver
2026-09-06 0:30 ` Jonathan Cameron
@ 2026-09-07 6:51 ` Chang Yu
0 siblings, 0 replies; 12+ messages in thread
From: Chang Yu @ 2026-09-07 6:51 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Chang Yu, Andy Shevchenko, David Lechner, Nuno Sá,
linux-iio, linux-kernel
Hi Jonathan,
Thanks for the thorough review. Just some clarifying comments in line. I
should be able to send v2 over within a few business days.
On Sun, Sep 06, 2026 at 01:30:39AM +0100, Jonathan Cameron wrote:
> > This patch adds a driver for the AMS AS7343 14-channel multi-spectral
> > sensor with I2C interface.
> >
> > The driver exposes 12 spectral channels (11 visible + 1 near-infrared)
> > via the IIO sysfs interface. Each channel's raw data is provided as a
> > 16-bit little-endian unsigned integer.
> >
> > Basic power management (suspend/resume) is supported. More complex
> > features such as interrupt support and configurable gain/integration
> > time will be added in future patches.
> >
> > Signed-off-by: Chang Yu <marcus.yu.56@gmail.com>
> Hi Chang Yu,
>
> I've avoided too much duplication with Joshua's already pretty
> thorough review so just a few additional comments inline.
>
>
> > diff --git a/drivers/iio/light/as7343.c b/drivers/iio/light/as7343.c
> > new file mode 100644
> > index 000000000000..b620dd308380
> > --- /dev/null
> > +++ b/drivers/iio/light/as7343.c
>
> ...
>
> > +/* AS7343 register bit masks */
> > +#define AS7343_ENABLE_PON BIT(0)
> > +#define AS7343_ENABLE_SP_EN BIT(1)
> > +#define AS7343_CFG0_REG_BANK BIT(4)
> > +#define AS7343_CFG20_AUTO_SMUX GENMASK(6, 5)
> > +#define AS7343_CONTROL_SW_RESET BIT(3)
> > +#define AS7343_CFG1_AGAIN GENMASK(4, 0)
> > +
> > +/* AS7343 settings */
> > +#define AS7343_INT_TIME 29 /* (29 + 1) * 2.87ms = 83.4ms */
>
> Implement this as a function to do the maths and take the input in
> usecs. Then you can call that with 83400 as the parameter to set the
> default value. Why this default?
>
Annoyingly for this sensor the integration time is calculated from two
registers: (ATIME + 1) * (ASTEP + 1) * 2.78us. For simplicity, I'll use
define for these two values in v2 instead of a math function.
I'll adjust the default values. The defaults in v1 are just some random
values chosen by me. In v2 I'll change them to the official recommended
values in the datasheet (x256 gain and 50.1ms integration time). These
are also the values used by adafruit in their arduino driver.
(https://github.com/adafruit/Adafruit_AS7343/blob/main/Adafruit_AS7343.cpp)
>
> ...
>
> > +static const struct regmap_config as7343_regmap_config = {
> > + .name = "as7343",
> > + .reg_bits = 8,
> > + .val_bits = 8,
> > + .max_register = AS7343_REG_MAX,
> > + .reg_format_endian = REGMAP_ENDIAN_LITTLE,
> > + .val_format_endian = REGMAP_ENDIAN_LITTLE,
> > + .cache_type = REGCACHE_NONE,
>
> It is a big enough register map that it may make sense to use
> regcache and provide all the info on what is volatile etc.
>
I'm debating whether this is worth it or not. All data registers
are volatile. Plus ENABLE because we need power management.
Potentially ASTEP, ATIME, CFG1 as well if we want configurable
gain/integration test in the future. That leaves us with may be
1 or 2 registers in the mapping that are not volatile. I'm leaning
towards leaving this as REGCACHE_NONE for now. Let me know what you
think.
> --
> Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Best,
Chang
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-09-07 6:51 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-05 5:53 [PATCH 0/2] Add support for AS7343 multi-spectral sensor Chang Yu
2026-09-05 5:53 ` [PATCH 1/2] dt-bindings: iio: light: add as7343 Chang Yu
2026-09-05 7:23 ` Krzysztof Kozlowski
2026-09-06 0:30 ` Jonathan Cameron
2026-09-05 5:53 ` [PATCH 2/2] iio: light: add AS7343 multi-spectral sensor driver Chang Yu
2026-09-05 6:42 ` Joshua Crofts
2026-09-06 0:11 ` Jonathan Cameron
2026-09-07 6:36 ` Chang Yu
2026-09-06 0:30 ` Jonathan Cameron
2026-09-07 6:51 ` Chang Yu
2026-09-05 7:51 ` [PATCH 0/2] Add support for AS7343 multi-spectral sensor Andy Shevchenko
2026-09-05 23:40 ` Jonathan Cameron
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®