* [PATCH v3 1/5] iio: light: stk3310: lower-case the i2c device ID names
2026-09-01 0:51 [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support Jorijn van der Graaf
@ 2026-09-01 0:51 ` Jorijn van der Graaf
2026-09-01 0:51 ` [PATCH v3 2/5] dt-bindings: iio: light: stk33xx: document the Sensortek STK36C61 Jorijn van der Graaf
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jorijn van der Graaf @ 2026-09-01 0:51 UTC (permalink / raw)
To: Jonathan Cameron, linux-iio
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Kees Cook, Gustavo A . R . Silva, linux-hardening, linux-kernel,
Luca Weiss, Marcelo Schmitt, Jorijn van der Graaf
The i2c device IDs were introduced in capitals, mirroring the ACPI
_HID entries added by the same commit be9e6229d676 ("iio: light: Add
support for Sensortek STK3310"); at that point the driver enumerated
through ACPI only, with no OF table and no i2c module alias export.
ACPI _HIDs have their own naming rules; i2c device names
conventionally use the lower-case part name, matching the devicetree
compatible suffix.
The spelling is visible: a client instantiated through the i2c sysfs
interface under the lower-case name taken from a compatible string
binds through the OF table's name fallback, but has no firmware node,
so i2c_match_id() is the only way for it to reach driver match data,
and its string comparison is case-sensitive, so the capitals can never
match. Lower-case the names so such clients match the id table, and
receive the per-chip match data a subsequent change attaches to it.
The module aliases follow the rename (i2c:STK3310 becomes
i2c:stk3310), and a sysfs client instantiated under a capitals name no
longer binds.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
---
drivers/iio/light/stk3310.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 7c8a1d2b2ed0..5b5b6812edc7 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -766,10 +766,10 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend,
stk3310_resume);
static const struct i2c_device_id stk3310_i2c_id[] = {
- { .name = "STK3013" },
- { .name = "STK3310" },
- { .name = "STK3311" },
- { .name = "STK3335" },
+ { .name = "stk3013" },
+ { .name = "stk3310" },
+ { .name = "stk3311" },
+ { .name = "stk3335" },
{ }
};
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 2/5] dt-bindings: iio: light: stk33xx: document the Sensortek STK36C61
2026-09-01 0:51 [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support Jorijn van der Graaf
2026-09-01 0:51 ` [PATCH v3 1/5] iio: light: stk3310: lower-case the i2c device ID names Jorijn van der Graaf
@ 2026-09-01 0:51 ` Jorijn van der Graaf
2026-09-01 0:51 ` [PATCH v3 3/5] iio: light: stk3310: move the data registers into the channel address Jorijn van der Graaf
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jorijn van der Graaf @ 2026-09-01 0:51 UTC (permalink / raw)
To: Jonathan Cameron, linux-iio
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Kees Cook, Gustavo A . R . Silva, linux-hardening, linux-kernel,
Luca Weiss, Marcelo Schmitt, Jorijn van der Graaf,
Krzysztof Kozlowski
The STK36C61 is a 3-in-1 ambient light / proximity / RGB colour sensor
found in the Fairphone 6. Its ambient light and proximity register
interface is compatible with the stk3310's, while the dedicated
compatible identifies the part, whose colour channels the fallback
does not describe.
Add sensortek,stk36c61 with a sensortek,stk3310 fallback, mirroring
the stk3013 entry, and widen the title and description to cover the
part.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
---
Documentation/devicetree/bindings/iio/light/stk33xx.yaml | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/light/stk33xx.yaml b/Documentation/devicetree/bindings/iio/light/stk33xx.yaml
index e4341fdced98..0165a348918b 100644
--- a/Documentation/devicetree/bindings/iio/light/stk33xx.yaml
+++ b/Documentation/devicetree/bindings/iio/light/stk33xx.yaml
@@ -4,14 +4,14 @@
$id: http://devicetree.org/schemas/iio/light/stk33xx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: |
- Sensortek STK33xx I2C Ambient Light and Proximity sensor
+title: Sensortek STK33xx/STK36C61 I2C Ambient Light and Proximity sensor
maintainers:
- Jonathan Cameron <jic23@kernel.org>
-description: |
- Ambient light and proximity sensor over an i2c interface.
+description:
+ Ambient light and proximity sensor over an i2c interface. The STK36C61
+ additionally provides RGBC colour channels.
allOf:
- $ref: ../common.yaml#
@@ -26,6 +26,7 @@ properties:
- items:
- enum:
- sensortek,stk3013
+ - sensortek,stk36c61
- const: sensortek,stk3310
reg:
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 3/5] iio: light: stk3310: move the data registers into the channel address
2026-09-01 0:51 [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support Jorijn van der Graaf
2026-09-01 0:51 ` [PATCH v3 1/5] iio: light: stk3310: lower-case the i2c device ID names Jorijn van der Graaf
2026-09-01 0:51 ` [PATCH v3 2/5] dt-bindings: iio: light: stk33xx: document the Sensortek STK36C61 Jorijn van der Graaf
@ 2026-09-01 0:51 ` Jorijn van der Graaf
2026-09-01 0:51 ` [PATCH v3 4/5] iio: light: stk3310: add per-chip match data Jorijn van der Graaf
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jorijn van der Graaf @ 2026-09-01 0:51 UTC (permalink / raw)
To: Jonathan Cameron, linux-iio
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Kees Cook, Gustavo A . R . Silva, linux-hardening, linux-kernel,
Luca Weiss, Marcelo Schmitt, Jorijn van der Graaf
The RAW read selects its data register with a per-channel-type branch.
Record each channel's data register in its .address field and read
from there, so adding a channel does not grow the branch.
Suggested-by: Jonathan Cameron <jic23@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
---
drivers/iio/light/stk3310.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 5b5b6812edc7..156888969366 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -184,6 +184,7 @@ static const struct iio_chan_spec_ext_info stk3310_ext_info[] = {
static const struct iio_chan_spec stk3310_channels[] = {
{
.type = IIO_LIGHT,
+ .address = STK3310_REG_ALS_DATA_MSB,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
@@ -191,6 +192,7 @@ static const struct iio_chan_spec stk3310_channels[] = {
},
{
.type = IIO_PROXIMITY,
+ .address = STK3310_REG_PS_DATA_MSB,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
@@ -370,25 +372,20 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
- u8 reg;
__be16 buf;
int ret;
unsigned int index;
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
+ struct regmap *map = data->regmap;
if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (chan->type == IIO_LIGHT)
- reg = STK3310_REG_ALS_DATA_MSB;
- else
- reg = STK3310_REG_PS_DATA_MSB;
-
mutex_lock(&data->lock);
- ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf));
+ ret = regmap_bulk_read(map, chan->address, &buf, sizeof(buf));
if (ret < 0) {
dev_err(&client->dev, "register read failed\n");
mutex_unlock(&data->lock);
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 4/5] iio: light: stk3310: add per-chip match data
2026-09-01 0:51 [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support Jorijn van der Graaf
` (2 preceding siblings ...)
2026-09-01 0:51 ` [PATCH v3 3/5] iio: light: stk3310: move the data registers into the channel address Jorijn van der Graaf
@ 2026-09-01 0:51 ` Jorijn van der Graaf
2026-09-01 0:51 ` [PATCH v3 5/5] iio: light: stk3310: support the Sensortek STK36C61 Jorijn van der Graaf
2026-09-05 0:51 ` [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support Jonathan Cameron
5 siblings, 0 replies; 9+ messages in thread
From: Jorijn van der Graaf @ 2026-09-01 0:51 UTC (permalink / raw)
To: Jonathan Cameron, linux-iio
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Kees Cook, Gustavo A . R . Silva, linux-hardening, linux-kernel,
Luca Weiss, Marcelo Schmitt, Jorijn van der Graaf
Introduce a chip_info structure carrying the device name and channel
specification, attach it to every i2c, OF and ACPI table entry, and
let probe take it from the match data, failing when there is none.
Every firmware bind path carries match data, and with the id names in
lower case a client instantiated through the sysfs new_device
interface under the compatible's lower-case suffix receives it
through the id table. The shared channel definitions move into
macros.
The ACPI table entries change to named initializers, matching the
other id tables.
This is a preparatory change for a variant that provides more channels
than the existing parts. No functional change for firmware-described
devices. A sysfs client under a name that binds without matching any
id entry (the full compatible string) now fails probe with an error
instead of probing as an stk3310.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
---
drivers/iio/light/stk3310.c | 95 ++++++++++++++++++++++++-------------
1 file changed, 61 insertions(+), 34 deletions(-)
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 156888969366..f5782a1e19bb 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -181,26 +181,48 @@ static const struct iio_chan_spec_ext_info stk3310_ext_info[] = {
{ }
};
+#define STK3310_LIGHT_CHANNEL { \
+ .type = IIO_LIGHT, \
+ .address = STK3310_REG_ALS_DATA_MSB, \
+ .info_mask_separate = \
+ BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_INT_TIME), \
+}
+
+#define STK3310_PROXIMITY_CHANNEL { \
+ .type = IIO_PROXIMITY, \
+ .address = STK3310_REG_PS_DATA_MSB, \
+ .info_mask_separate = \
+ BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_INT_TIME), \
+ .event_spec = stk3310_events, \
+ .num_event_specs = ARRAY_SIZE(stk3310_events), \
+ .ext_info = stk3310_ext_info, \
+}
+
static const struct iio_chan_spec stk3310_channels[] = {
- {
- .type = IIO_LIGHT,
- .address = STK3310_REG_ALS_DATA_MSB,
- .info_mask_separate =
- BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_SCALE) |
- BIT(IIO_CHAN_INFO_INT_TIME),
- },
- {
- .type = IIO_PROXIMITY,
- .address = STK3310_REG_PS_DATA_MSB,
- .info_mask_separate =
- BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_SCALE) |
- BIT(IIO_CHAN_INFO_INT_TIME),
- .event_spec = stk3310_events,
- .num_event_specs = ARRAY_SIZE(stk3310_events),
- .ext_info = stk3310_ext_info,
- }
+ STK3310_LIGHT_CHANNEL,
+ STK3310_PROXIMITY_CHANNEL,
+};
+
+/**
+ * struct stk3310_chip_info - chip-specific data
+ * @name: device name reported to the IIO core
+ * @channels: channel specification
+ * @num_channels: number of channels
+ */
+struct stk3310_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels __counted_by_ptr(num_channels);
+ unsigned int num_channels;
+};
+
+static const struct stk3310_chip_info stk3310_chip_info = {
+ .name = STK3310_DRIVER_NAME,
+ .channels = stk3310_channels,
+ .num_channels = ARRAY_SIZE(stk3310_channels),
};
static IIO_CONST_ATTR(in_illuminance_scale_available, STK3310_SCALE_AVAILABLE);
@@ -632,10 +654,16 @@ static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
static int stk3310_probe(struct i2c_client *client)
{
+ const struct stk3310_chip_info *chip_info;
+ struct device *dev = &client->dev;
int ret;
struct iio_dev *indio_dev;
struct stk3310_data *data;
+ chip_info = i2c_get_match_data(client);
+ if (!chip_info)
+ return dev_err_probe(dev, -ENODATA, "missing driver data\n");
+
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
@@ -654,10 +682,10 @@ static int stk3310_probe(struct i2c_client *client)
return ret;
indio_dev->info = &stk3310_info;
- indio_dev->name = STK3310_DRIVER_NAME;
+ indio_dev->name = chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = stk3310_channels;
- indio_dev->num_channels = ARRAY_SIZE(stk3310_channels);
+ indio_dev->channels = chip_info->channels;
+ indio_dev->num_channels = chip_info->num_channels;
ret = stk3310_init(indio_dev);
if (ret < 0)
@@ -763,28 +791,27 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend,
stk3310_resume);
static const struct i2c_device_id stk3310_i2c_id[] = {
- { .name = "stk3013" },
- { .name = "stk3310" },
- { .name = "stk3311" },
- { .name = "stk3335" },
+ { .name = "stk3013", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
+ { .name = "stk3310", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
+ { .name = "stk3311", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
+ { .name = "stk3335", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
static const struct acpi_device_id stk3310_acpi_id[] = {
- {"STK3013", 0},
- {"STK3310", 0},
- {"STK3311", 0},
+ { .id = "STK3013", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
+ { .id = "STK3310", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
+ { .id = "STK3311", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
{ }
};
-
MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id);
static const struct of_device_id stk3310_of_match[] = {
- { .compatible = "sensortek,stk3013", },
- { .compatible = "sensortek,stk3310", },
- { .compatible = "sensortek,stk3311", },
- { .compatible = "sensortek,stk3335", },
+ { .compatible = "sensortek,stk3013", .data = &stk3310_chip_info },
+ { .compatible = "sensortek,stk3310", .data = &stk3310_chip_info },
+ { .compatible = "sensortek,stk3311", .data = &stk3310_chip_info },
+ { .compatible = "sensortek,stk3335", .data = &stk3310_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, stk3310_of_match);
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 5/5] iio: light: stk3310: support the Sensortek STK36C61
2026-09-01 0:51 [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support Jorijn van der Graaf
` (3 preceding siblings ...)
2026-09-01 0:51 ` [PATCH v3 4/5] iio: light: stk3310: add per-chip match data Jorijn van der Graaf
@ 2026-09-01 0:51 ` Jorijn van der Graaf
2026-09-01 1:04 ` sashiko-bot
2026-09-05 0:50 ` Jonathan Cameron
2026-09-05 0:51 ` [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support Jonathan Cameron
5 siblings, 2 replies; 9+ messages in thread
From: Jorijn van der Graaf @ 2026-09-01 0:51 UTC (permalink / raw)
To: Jonathan Cameron, linux-iio
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Kees Cook, Gustavo A . R . Silva, linux-hardening, linux-kernel,
Luca Weiss, Marcelo Schmitt, Jorijn van der Graaf
The Sensortek STK36C61 is a 3-in-1 ambient light / proximity / RGB
colour sensor. Its register interface is compatible with the feature
set this driver uses. Add its chip ID to the known-ID list and the
device table entries.
Whenever the ALS engine runs, the chip also measures four colour
channels: red, green, blue and clear, laid out directly after the
ALS data as 16-bit big-endian values.
R, G and B are gained by the same ALSCTRL gain field the illuminance
channel uses, clear by its own gain field in the GAINCTRL register,
and the whole colour block integrates over the ALS integration time.
Expose the channels with per-channel scale and a shared integration
time, as suggested by Jonathan Cameron for the green channel.
The scales reuse the driver's existing gain-only table: green equals
the ALS data, so its scale must read identically to the pre-existing
in_illuminance_scale.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
---
Documentation/ABI/testing/sysfs-bus-iio | 1 +
drivers/iio/light/stk3310.c | 101 ++++++++++++++++++++----
2 files changed, 88 insertions(+), 14 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index a4f5595722ad..08a8de215814 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -507,6 +507,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_scale
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_scale
What: /sys/bus/iio/devices/iio:deviceX/in_volumeflow_scale
What: /sys/bus/iio/devices/iio:deviceX/in_volumeflowY_scale
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index f5782a1e19bb..0a16e326e939 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -40,7 +40,13 @@
#define STK3310_REG_PS_DATA_LSB 0x12
#define STK3310_REG_ALS_DATA_MSB 0x13
#define STK3310_REG_ALS_DATA_LSB 0x14
+#define STK36C61_REG_RED_DATA_MSB 0x15
+#define STK36C61_REG_GREEN_DATA_MSB 0x17
+#define STK36C61_REG_BLUE_DATA_MSB 0x19
+#define STK36C61_REG_CLEAR_DATA_MSB 0x1B
+#define STK36C61_REG_CLEAR_DATA_LSB 0x1C
#define STK3310_REG_ID 0x3E
+#define STK36C61_REG_GAINCTRL 0x4E
#define STK3310_MAX_REG 0x80
#define STK3310_STATE_EN_PS BIT(0)
@@ -54,6 +60,7 @@
#define STK3311S34_CHIP_ID_VAL 0x1E
#define STK3311X_CHIP_ID_VAL 0x12
#define STK3335_CHIP_ID_VAL 0x51
+#define STK36C61_CHIP_ID_VAL 0x95
#define STK3310_PSINT_EN 0x01
#define STK3310_PS_MAX_VAL 0xFFFF
@@ -83,6 +90,8 @@ static const struct reg_field stk3310_reg_field_als_gain =
REG_FIELD(STK3310_REG_ALSCTRL, 4, 5);
static const struct reg_field stk3310_reg_field_ps_gain =
REG_FIELD(STK3310_REG_PSCTRL, 4, 5);
+static const struct reg_field stk3310_reg_field_clear_gain =
+ REG_FIELD(STK36C61_REG_GAINCTRL, 4, 5);
static const struct reg_field stk3310_reg_field_als_it =
REG_FIELD(STK3310_REG_ALSCTRL, 0, 3);
static const struct reg_field stk3310_reg_field_ps_it =
@@ -102,6 +111,7 @@ static const u8 stk3310_chip_ids[] = {
STK3311X_CHIP_ID_VAL,
STK3311_CHIP_ID_VAL,
STK3335_CHIP_ID_VAL,
+ STK36C61_CHIP_ID_VAL,
};
/* Estimate maximum proximity values with regard to measurement scale. */
@@ -132,6 +142,7 @@ struct stk3310_data {
struct regmap_field *reg_state;
struct regmap_field *reg_als_gain;
struct regmap_field *reg_ps_gain;
+ struct regmap_field *reg_clear_gain;
struct regmap_field *reg_als_it;
struct regmap_field *reg_ps_it;
struct regmap_field *reg_int_ps;
@@ -202,11 +213,35 @@ static const struct iio_chan_spec_ext_info stk3310_ext_info[] = {
.ext_info = stk3310_ext_info, \
}
+#define STK36C61_INTENSITY_CHANNEL(_mod, _reg) { \
+ .type = IIO_INTENSITY, \
+ .address = _reg, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_LIGHT_##_mod, \
+ .info_mask_separate = \
+ BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type = \
+ BIT(IIO_CHAN_INFO_INT_TIME), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_INT_TIME), \
+}
+
static const struct iio_chan_spec stk3310_channels[] = {
STK3310_LIGHT_CHANNEL,
STK3310_PROXIMITY_CHANNEL,
};
+static const struct iio_chan_spec stk36c61_channels[] = {
+ STK3310_LIGHT_CHANNEL,
+ STK3310_PROXIMITY_CHANNEL,
+ STK36C61_INTENSITY_CHANNEL(RED, STK36C61_REG_RED_DATA_MSB),
+ STK36C61_INTENSITY_CHANNEL(GREEN, STK36C61_REG_GREEN_DATA_MSB),
+ STK36C61_INTENSITY_CHANNEL(BLUE, STK36C61_REG_BLUE_DATA_MSB),
+ STK36C61_INTENSITY_CHANNEL(CLEAR, STK36C61_REG_CLEAR_DATA_MSB),
+};
+
/**
* struct stk3310_chip_info - chip-specific data
* @name: device name reported to the IIO core
@@ -225,6 +260,12 @@ static const struct stk3310_chip_info stk3310_chip_info = {
.num_channels = ARRAY_SIZE(stk3310_channels),
};
+static const struct stk3310_chip_info stk36c61_chip_info = {
+ .name = "stk36c61",
+ .channels = stk36c61_channels,
+ .num_channels = ARRAY_SIZE(stk36c61_channels),
+};
+
static IIO_CONST_ATTR(in_illuminance_scale_available, STK3310_SCALE_AVAILABLE);
static IIO_CONST_ATTR(in_proximity_scale_available, STK3310_SCALE_AVAILABLE);
@@ -401,7 +442,8 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
struct i2c_client *client = data->client;
struct regmap *map = data->regmap;
- if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
+ if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY &&
+ chan->type != IIO_INTENSITY)
return -EINVAL;
switch (mask) {
@@ -417,10 +459,10 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&data->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
- if (chan->type == IIO_LIGHT)
- ret = regmap_field_read(data->reg_als_it, &index);
- else
+ if (chan->type == IIO_PROXIMITY)
ret = regmap_field_read(data->reg_ps_it, &index);
+ else
+ ret = regmap_field_read(data->reg_als_it, &index);
if (ret < 0)
return ret;
@@ -428,10 +470,12 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
*val2 = stk3310_it_table[index][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
- if (chan->type == IIO_LIGHT)
- ret = regmap_field_read(data->reg_als_gain, &index);
- else
+ if (chan->type == IIO_PROXIMITY)
ret = regmap_field_read(data->reg_ps_gain, &index);
+ else if (chan->channel2 == IIO_MOD_LIGHT_CLEAR)
+ ret = regmap_field_read(data->reg_clear_gain, &index);
+ else
+ ret = regmap_field_read(data->reg_als_gain, &index);
if (ret < 0)
return ret;
@@ -451,7 +495,8 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
int index;
struct stk3310_data *data = iio_priv(indio_dev);
- if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
+ if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY &&
+ chan->type != IIO_INTENSITY)
return -EINVAL;
switch (mask) {
@@ -462,10 +507,10 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
if (index < 0)
return -EINVAL;
mutex_lock(&data->lock);
- if (chan->type == IIO_LIGHT)
- ret = regmap_field_write(data->reg_als_it, index);
- else
+ if (chan->type == IIO_PROXIMITY)
ret = regmap_field_write(data->reg_ps_it, index);
+ else
+ ret = regmap_field_write(data->reg_als_it, index);
if (ret < 0)
dev_err(&data->client->dev,
"sensor configuration failed\n");
@@ -479,10 +524,12 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
if (index < 0)
return -EINVAL;
mutex_lock(&data->lock);
- if (chan->type == IIO_LIGHT)
- ret = regmap_field_write(data->reg_als_gain, index);
- else
+ if (chan->type == IIO_PROXIMITY)
ret = regmap_field_write(data->reg_ps_gain, index);
+ else if (chan->channel2 == IIO_MOD_LIGHT_CLEAR)
+ ret = regmap_field_write(data->reg_clear_gain, index);
+ else
+ ret = regmap_field_write(data->reg_als_gain, index);
if (ret < 0)
dev_err(&data->client->dev,
"sensor configuration failed\n");
@@ -493,9 +540,31 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
+static int stk3310_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)stk3310_scale_table;
+ *length = 2 * ARRAY_SIZE(stk3310_scale_table);
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_INT_TIME:
+ *vals = (const int *)stk3310_it_table;
+ *length = 2 * ARRAY_SIZE(stk3310_it_table);
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct iio_info stk3310_info = {
.read_raw = stk3310_read_raw,
.write_raw = stk3310_write_raw,
+ .read_avail = stk3310_read_avail,
.attrs = &stk3310_attribute_group,
.read_event_value = stk3310_read_event,
.write_event_value = stk3310_write_event,
@@ -567,6 +636,7 @@ static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case STK3310_REG_ALS_DATA_MSB:
case STK3310_REG_ALS_DATA_LSB:
+ case STK36C61_REG_RED_DATA_MSB ... STK36C61_REG_CLEAR_DATA_LSB:
case STK3310_REG_PS_DATA_LSB:
case STK3310_REG_PS_DATA_MSB:
case STK3310_REG_FLAG:
@@ -601,6 +671,7 @@ static int stk3310_regmap_init(struct stk3310_data *data)
STK3310_REGFIELD(state);
STK3310_REGFIELD(als_gain);
STK3310_REGFIELD(ps_gain);
+ STK3310_REGFIELD(clear_gain);
STK3310_REGFIELD(als_it);
STK3310_REGFIELD(ps_it);
STK3310_REGFIELD(int_ps);
@@ -795,6 +866,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = {
{ .name = "stk3310", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
{ .name = "stk3311", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
{ .name = "stk3335", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
+ { .name = "stk36c61", .driver_data = (kernel_ulong_t)&stk36c61_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
@@ -812,6 +884,7 @@ static const struct of_device_id stk3310_of_match[] = {
{ .compatible = "sensortek,stk3310", .data = &stk3310_chip_info },
{ .compatible = "sensortek,stk3311", .data = &stk3310_chip_info },
{ .compatible = "sensortek,stk3335", .data = &stk3310_chip_info },
+ { .compatible = "sensortek,stk36c61", .data = &stk36c61_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, stk3310_of_match);
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 5/5] iio: light: stk3310: support the Sensortek STK36C61
2026-09-01 0:51 ` [PATCH v3 5/5] iio: light: stk3310: support the Sensortek STK36C61 Jorijn van der Graaf
@ 2026-09-01 1:04 ` sashiko-bot
2026-09-05 0:50 ` Jonathan Cameron
1 sibling, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-09-01 1:04 UTC (permalink / raw)
To: Jorijn van der Graaf; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Possible Use-After-Free of IIO event interface (ev_int) during probe failure due to asymmetric IRQ lifecycle.
--
commit b4e1397431b4f12cb9a540f222673e8512090f40
Author: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
Subject: iio: light: stk3310: support the Sensortek STK36C61
The Sensortek STK36C61 is a 3-in-1 ambient light / proximity / RGB
colour sensor. This patch adds its chip ID to the known-ID list and
device table entries, exposing the colour channels alongside ALS and
proximity.
> diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
> index f5782a1e19bbc..0a16e326e9390 100644
> --- a/drivers/iio/light/stk3310.c
> +++ b/drivers/iio/light/stk3310.c
[ ... ]
> @@ -866,6 +866,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = {
> { .name = "stk3310", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
> { .name = "stk3311", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
> { .name = "stk3335", .driver_data = (kernel_ulong_t)&stk3310_chip_info },
> + { .name = "stk36c61", .driver_data = (kernel_ulong_t)&stk36c61_chip_info },
[Severity: High]
This isn't a bug introduced by this patch, but is it possible for the
pre-existing IRQ setup in stk3310_probe() (drivers/iio/light/stk3310.c,
around line 766) to trigger a use-after-free if probe fails?
Looking at stk3310_probe(), the IRQ handler is registered before the IIO
device:
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk3310_irq_handler,
stk3310_irq_event_handler,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"stk3310_event", indio_dev);
if (ret)
goto err_standby;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "device_register failed\n");
goto err_standby;
}
If iio_device_register() fails late in its execution, it cleans up its
partial state and frees the ev_int structure via kfree(). Because the IRQ
is managed by devres, it remains active until stk3310_probe() returns and
the devres unwinding phase disables it.
If a hardware interrupt fires during this window, stk3310_irq_event_handler()
(around line 714) will execute:
event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
IIO_EV_TYPE_THRESH,
(dir ? IIO_EV_DIR_FALLING :
IIO_EV_DIR_RISING));
iio_push_event(indio_dev, event, data->timestamp);
Can iio_push_event() dereference the freed ev_int structure here since there
is no synchronization with the iio_device_unregister_eventset() cleanup?
> { }
> };
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260901005114.203062-1-jorijnvdgraaf@catcrafts.net?part=5
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v3 5/5] iio: light: stk3310: support the Sensortek STK36C61
2026-09-01 0:51 ` [PATCH v3 5/5] iio: light: stk3310: support the Sensortek STK36C61 Jorijn van der Graaf
2026-09-01 1:04 ` sashiko-bot
@ 2026-09-05 0:50 ` Jonathan Cameron
1 sibling, 0 replies; 9+ messages in thread
From: Jonathan Cameron @ 2026-09-05 0:50 UTC (permalink / raw)
To: Jorijn van der Graaf
Cc: Jonathan Cameron, linux-iio, David Lechner, Nuno Sá,
Andy Shevchenko, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, devicetree, Kees Cook,
Gustavo A . R . Silva, linux-hardening, linux-kernel, Luca Weiss,
Marcelo Schmitt
> The Sensortek STK36C61 is a 3-in-1 ambient light / proximity / RGB
> colour sensor. Its register interface is compatible with the feature
> set this driver uses. Add its chip ID to the known-ID list and the
> device table entries.
>
> Whenever the ALS engine runs, the chip also measures four colour
> channels: red, green, blue and clear, laid out directly after the
> ALS data as 16-bit big-endian values.
>
> R, G and B are gained by the same ALSCTRL gain field the illuminance
> channel uses, clear by its own gain field in the GAINCTRL register,
> and the whole colour block integrates over the ALS integration time.
> Expose the channels with per-channel scale and a shared integration
> time, as suggested by Jonathan Cameron for the green channel.
>
> The scales reuse the driver's existing gain-only table: green equals
> the ALS data, so its scale must read identically to the pre-existing
> in_illuminance_scale.
>
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
So there is a Sashiko comment on this one. It's an exisiting issue
in the tear down path so out of scope for this series.
In general we probably need to look at the various things that
might get called on late running or spurious interrupts to be sure
they are safely dropped. Anyhow, yet another thing for the todo list.
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index a4f5595722ad..08a8de215814 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
We'd normally do a core ABI docs update in a separate patch, but
it is such a small one I'm not going to ask you to respin for that!
> @@ -507,6 +507,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_scale
> +What: /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_volumeflow_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_volumeflowY_scale
Thanks
Jonathan
--
Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support
2026-09-01 0:51 [PATCH v3 0/5] iio: light: stk3310: per-chip match data and STK36C61 support Jorijn van der Graaf
` (4 preceding siblings ...)
2026-09-01 0:51 ` [PATCH v3 5/5] iio: light: stk3310: support the Sensortek STK36C61 Jorijn van der Graaf
@ 2026-09-05 0:51 ` Jonathan Cameron
5 siblings, 0 replies; 9+ messages in thread
From: Jonathan Cameron @ 2026-09-05 0:51 UTC (permalink / raw)
To: Jorijn van der Graaf
Cc: linux-iio, David Lechner, Nuno Sá, Andy Shevchenko,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree, Kees Cook, Gustavo A . R . Silva, linux-hardening,
linux-kernel, Luca Weiss, Marcelo Schmitt
On Tue, 1 Sep 2026 02:51:09 +0200
Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net> wrote:
> The Sensortek STK36C61 is a 3-in-1 ambient light / proximity / RGB
> colour sensor whose register interface is compatible with the stk3310
> across the ALS and proximity data, threshold, gain and
> integration-time registers this driver uses. The part name comes from
> the Fairphone 6 manual, which lists the component as "3IN1 ALPS/RGB
> sensor/STK36C61". The layout was probed on the device: chip ID 0x95,
> the stk3310 STATE/FLAG bit layout, data and threshold registers
> (thresholds written through the event interface read back from the
> chip, and the FLAG near/far bit crosses with them), gain and
> integration-time fields the ALS and proximity readings scale with,
> and an RGBC data block directly after the ALS data, the red, green
> and blue assignments each confirmed by the matching channel
> dominating under the matching illumination and clear by its broadband
> response.
Applied to the testing branch of iio.git.
Thanks,
Jonathan
^ permalink raw reply [flat|nested] 9+ messages in thread