* [PATCH v5 03/16] media: iris: Introduce set_preset_register as a vpu_op
From: Dmitry Baryshkov @ 2026-06-16 0:04 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
In-Reply-To: <20260616-iris-ar50lt-v5-0-583b42770b6a@oss.qualcomm.com>
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
The set_preset_registers sequence is currently shared across all
supported devices. Starting with Qualcomm QCM2290 (AR50LT), the register
programming would differ.
Move set_preset_register into a vpu_op to allow per-device
customization.
This change prepares the driver for upcoming hardware variants.
No functional change so far for existing devices.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_vpu2.c | 1 +
drivers/media/platform/qcom/iris/iris_vpu3x.c | 3 +++
drivers/media/platform/qcom/iris/iris_vpu4x.c | 1 +
drivers/media/platform/qcom/iris/iris_vpu_common.c | 2 +-
drivers/media/platform/qcom/iris/iris_vpu_common.h | 1 +
5 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c
index b8714dcbad10..2dc121a3f5e8 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu2.c
@@ -45,4 +45,5 @@ const struct vpu_ops iris_vpu2_ops = {
.power_on_controller = iris_vpu_power_on_controller,
.calc_freq = iris_vpu2_calc_freq,
.set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu3x.c b/drivers/media/platform/qcom/iris/iris_vpu3x.c
index 3dad47be78b5..dc02ced1b931 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu3x.c
@@ -261,6 +261,7 @@ const struct vpu_ops iris_vpu3_ops = {
.power_on_controller = iris_vpu_power_on_controller,
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
const struct vpu_ops iris_vpu33_ops = {
@@ -270,6 +271,7 @@ const struct vpu_ops iris_vpu33_ops = {
.power_on_controller = iris_vpu_power_on_controller,
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
const struct vpu_ops iris_vpu35_ops = {
@@ -280,4 +282,5 @@ const struct vpu_ops iris_vpu35_ops = {
.program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers,
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu4x.c b/drivers/media/platform/qcom/iris/iris_vpu4x.c
index 02e100a4045f..f608a297d4a3 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu4x.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu4x.c
@@ -368,4 +368,5 @@ const struct vpu_ops iris_vpu4x_ops = {
.program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers,
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu4x_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c
index ab41da1f47c8..a49113b0da23 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c
@@ -483,7 +483,7 @@ int iris_vpu_power_on(struct iris_core *core)
iris_opp_set_rate(core->dev, freq);
- iris_vpu_set_preset_registers(core);
+ core->iris_platform_data->vpu_ops->set_preset_registers(core);
iris_vpu_interrupt_init(core);
core->intr_status = 0;
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h
index 09799a375c14..21ed4c9bd5e3 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h
@@ -22,6 +22,7 @@ struct vpu_ops {
void (*program_bootup_registers)(struct iris_core *core);
u64 (*calc_freq)(struct iris_inst *inst, size_t data_size);
int (*set_hwmode)(struct iris_core *core);
+ void (*set_preset_registers)(struct iris_core *core);
};
int iris_vpu_boot_firmware(struct iris_core *core);
--
2.47.3
^ permalink raw reply related
* [PATCH v5 02/16] media: iris: Filter UBWC raw formats based on hardware capabilities
From: Dmitry Baryshkov @ 2026-06-16 0:04 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
In-Reply-To: <20260616-iris-ar50lt-v5-0-583b42770b6a@oss.qualcomm.com>
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
The raw formats supported by Iris were previously advertised
unconditionally, assuming UBWC support on all platforms. However, some
platforms do not support UBWC which results in incorrect format
capability exposure.
Use the UBWC configuration provided by the platform to dynamically
filter raw formats at runtime. If UBWC is not supported, UBWC-based
formats are omitted from the advertised capability list, while linear
formats remain available.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_vdec.c | 26 ++++++++++++++++++++++----
drivers/media/platform/qcom/iris/iris_venc.c | 9 +++++++++
2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c
index 9e228b70420e..63b7c9dec60a 100644
--- a/drivers/media/platform/qcom/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/iris/iris_vdec.c
@@ -3,6 +3,7 @@
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <linux/soc/qcom/ubwc.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
@@ -69,8 +70,14 @@ static const u32 iris_vdec_formats_cap[] = {
[IRIS_FMT_QC10C] = V4L2_PIX_FMT_QC10C,
};
+static const u32 iris_vdec_formats_noubwc_cap[] = {
+ [IRIS_FMT_NV12] = V4L2_PIX_FMT_NV12,
+ [IRIS_FMT_TP10] = V4L2_PIX_FMT_P010,
+};
+
static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
{
+ const struct qcom_ubwc_cfg_data *ubwc = inst->core->ubwc_cfg;
unsigned int size, i;
const u32 *fmt;
@@ -80,8 +87,13 @@ static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
size = inst->core->iris_platform_data->inst_iris_fmts_size;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- fmt = iris_vdec_formats_cap;
- size = ARRAY_SIZE(iris_vdec_formats_cap);
+ if (ubwc->ubwc_enc_version) {
+ fmt = iris_vdec_formats_cap;
+ size = ARRAY_SIZE(iris_vdec_formats_cap);
+ } else {
+ fmt = iris_vdec_formats_noubwc_cap;
+ size = ARRAY_SIZE(iris_vdec_formats_noubwc_cap);
+ }
break;
default:
return false;
@@ -110,6 +122,7 @@ static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type)
{
+ const struct qcom_ubwc_cfg_data *ubwc = inst->core->ubwc_cfg;
unsigned int size;
const u32 *fmt;
@@ -119,8 +132,13 @@ static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type)
size = inst->core->iris_platform_data->inst_iris_fmts_size;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- fmt = iris_vdec_formats_cap;
- size = ARRAY_SIZE(iris_vdec_formats_cap);
+ if (ubwc->ubwc_enc_version) {
+ fmt = iris_vdec_formats_cap;
+ size = ARRAY_SIZE(iris_vdec_formats_cap);
+ } else {
+ fmt = iris_vdec_formats_noubwc_cap;
+ size = ARRAY_SIZE(iris_vdec_formats_noubwc_cap);
+ }
break;
default:
return 0;
diff --git a/drivers/media/platform/qcom/iris/iris_venc.c b/drivers/media/platform/qcom/iris/iris_venc.c
index a945992f63aa..2cafbe9f8abb 100644
--- a/drivers/media/platform/qcom/iris/iris_venc.c
+++ b/drivers/media/platform/qcom/iris/iris_venc.c
@@ -3,6 +3,7 @@
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <linux/soc/qcom/ubwc.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
@@ -91,6 +92,7 @@ static const u32 iris_venc_formats_out[] = {
static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
{
+ const struct qcom_ubwc_cfg_data *ubwc = inst->core->ubwc_cfg;
unsigned int size, i;
const u32 *fmt;
@@ -98,6 +100,9 @@ static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt = iris_venc_formats_out;
size = ARRAY_SIZE(iris_venc_formats_out);
+ /* Last format is UBWC; drop it if UBWC is unsupported */
+ if (!ubwc->ubwc_enc_version)
+ size--;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
fmt = iris_venc_formats_cap;
@@ -117,6 +122,7 @@ static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type)
{
+ const struct qcom_ubwc_cfg_data *ubwc = inst->core->ubwc_cfg;
unsigned int size;
const u32 *fmt;
@@ -124,6 +130,9 @@ static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type)
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt = iris_venc_formats_out;
size = ARRAY_SIZE(iris_venc_formats_out);
+ /* Last format is UBWC; drop it if UBWC is unsupported */
+ if (!ubwc->ubwc_enc_version)
+ size--;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
fmt = iris_venc_formats_cap;
--
2.47.3
^ permalink raw reply related
* [PATCH v5 01/16] media: iris: Skip UBWC configuration when not supported
From: Dmitry Baryshkov @ 2026-06-16 0:04 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal, Konrad Dybcio
In-Reply-To: <20260616-iris-ar50lt-v5-0-583b42770b6a@oss.qualcomm.com>
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
UBWC configuration is not applicable to all SoCs. Add a check to avoid
configuring UBWC during sys init on unsupported platforms.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c
index 0d05dd2afc07..6e04175eb904 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c
@@ -140,6 +140,9 @@ void iris_hfi_gen2_packet_sys_init(struct iris_core *core, struct iris_hfi_heade
&payload,
sizeof(u32));
+ if (!ubwc->ubwc_enc_version)
+ return;
+
payload = qcom_ubwc_macrotile_mode(ubwc) ? 8 : 4;
iris_hfi_gen2_create_packet(hdr,
HFI_PROP_UBWC_MAX_CHANNELS,
--
2.47.3
^ permalink raw reply related
* [PATCH v5 00/16] media: iris: Add AR50LT core support and enable Agatti platform
From: Dmitry Baryshkov @ 2026-06-16 0:04 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal, Konrad Dybcio
This series adds support for the AR50Lt VPU core to the iris driver and
enables the Agatti SoC to use Gen2 firmware and HFI.
AR50Lt introduces a few platform-specific requirements that need to be
handled in the iris core and VPU abstraction layer. To accommodate
this, the series adds minimal hooks and updates needed to allow the
firmware to operate correctly on AR50Lt without impacting existing
supported platforms.
Additionally, the series wires up Agatti to use the Gen2 firmware and
HFI path, aligning it with newer generations of supported Qualcomm
video hardware.
v4l2-compliance results:
v4l2-compliance -d /dev/video1 -s
v4l2-compliance 1.33.0-5421, 64 bits, 64-bit time_t
v4l2-compliance SHA: af4a91dea9a2 2025-10-29 10:33:25
Compliance test for iris_driver device /dev/video1:
Driver Info:
Driver name : iris_driver
Card type : Iris Encoder
Bus info : platform:5a00000.video-codec
Driver version : 6.19.0
Capabilities : 0x84204000
Video Memory-to-Memory Multiplanar
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04204000
Video Memory-to-Memory Multiplanar
Streaming
Extended Pix Format
Detected Stateful Encoder
Required ioctls:
test VIDIOC_QUERYCAP: OK
test invalid ioctls: OK
Allow for multiple opens:
test second /dev/video1 open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
test VIDIOC_G/S_CTRL: OK
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 43 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK
test Composing: OK (Not Supported)
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test CREATE_BUFS maximum buffers: OK
test VIDIOC_REMOVE_BUFS: OK
test VIDIOC_EXPBUF: OK
test Requests: OK (Not Supported)
test blocking wait: OK
Test input 0:
Streaming ioctls:
test read/write: OK67609.731994] use of bytesused == 0 is deprecated and will be removed in the future,
[67609.741833] use the actual size instead.
m (Not Supported)
Video Capture Multiplanar: Captured 61 buffers
test MMAP (select, REQBUFS): OK
Video Capture Multiplanar: Captured 61 buffers
test MMAP (epoll, REQBUFS): OK
Video Capture Multiplanar: Captured 61 buffers
test MMAP (select, CREATE_BUFS): OK
Video Capture Multiplanar: Captured 61 buffers
test MMAP (epoll, CREATE_BUFS): OK
test USERPTR (select): OK (Not Supported)
test DMABUF: Cannot test, specify --expbuf-device
Total for iris_driver device /dev/video1: 54, Succeeded: 54, Failed: 0, Warnings: 0
v4l2-compliance -d /dev/video0 -s5 --stream-from=/media/FVDO_Freeway_720p.264
v4l2-compliance 1.33.0-5421, 64 bits, 64-bit time_t
v4l2-compliance SHA: af4a91dea9a2 2025-10-29 10:33:25
Compliance test for iris_driver device /dev/video0:
Driver Info:
Driver name : iris_driver
Card type : Iris Decoder
Bus info : platform:5a00000.video-codec
Driver version : 6.19.0
Capabilities : 0x84204000
Video Memory-to-Memory Multiplanar
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04204000
Video Memory-to-Memory Multiplanar
Streaming
Extended Pix Format
Detected Stateful Decoder
Required ioctls:
test VIDIOC_QUERYCAP: OK
test invalid ioctls: OK
Allow for multiple opens:
test second /dev/video0 open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
test VIDIOC_G/S_CTRL: OK
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 12 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK
test Composing: OK
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test CREATE_BUFS maximum buffers: OK
test VIDIOC_REMOVE_BUFS: OK
test VIDIOC_EXPBUF: OK
test Requests: OK (Not Supported)
test blocking wait: OK
Test input 0:
Streaming ioctls:
test read/write: OK (Not Supported)
the input file is smaller than 7077888 bytes
Video Capture Multiplanar: Captured 465 buffers
test MMAP (select, REQBUFS): OK
the input file is smaller than 7077888 bytes
Video Capture Multiplanar: Captured 465 buffers
test MMAP (epoll, REQBUFS): OK
the input file is smaller than 7077888 bytes
Video Capture Multiplanar: Captured 465 buffers
test MMAP (select, CREATE_BUFS): OK
the input file is smaller than 7077888 bytes
Video Capture Multiplanar: Captured 465 buffers
test MMAP (epoll, CREATE_BUFS): OK
test USERPTR (select): OK (Not Supported)
test DMABUF: Cannot test, specify --expbuf-device
Total for iris_driver device /dev/video0: 54, Succeeded: 54, Failed: 0, Warnings: 0
Fluster results for HFI Gen2 firmware:
./fluster.py run -ts JVT-AVC_V1 -d GStreamer-H.264-V4L2-Gst1.0 - 77/135
The failing test case:
- Unsupported profile: H.264 Extended profile is deprecated.
- BA3_SVA_C
- Interlaced content is not supported yet.
- CABREF3_Sand_D
- CAFI1_SVA_C
- CAMA1_Sony_C
- CAMA1_TOSHIBA_B
- CAMA3_Sand_E
- CAMACI3_Sony_C
- CAMANL1_TOSHIBA_B
- CAMANL2_TOSHIBA_B
- CAMANL3_Sand_E
- CAMASL3_Sony_B
- CAMP_MOT_MBAFF_L30
- CAMP_MOT_MBAFF_L31
- CANLMA2_Sony_C
- CANLMA3_Sony_C
- CAPA1_TOSHIBA_B
- CAPAMA3_Sand_F
- CVCANLMA2_Sony_C
- CVFI1_SVA_C
- CVFI1_Sony_D
- CVFI2_SVA_C
- CVFI2_Sony_H
- CVMA1_Sony_D
- CVMA1_TOSHIBA_B
- CVMANL1_TOSHIBA_B
- CVMANL2_TOSHIBA_B
- CVMAPAQP3_Sony_E
- CVMAQP2_Sony_G
- CVMAQP3_Sony_D
- CVMP_MOT_FLD_L30_B
- CVMP_MOT_FRM_L31
- CVNLFI1_Sony_C
- CVNLFI2_Sony_H
- CVPA1_TOSHIBA_B
- FI1_Sony_E
- MR6_BT_B
- MR7_BT_B
- MR8_BT_B
- MR9_BT_B
- Sharp_MP_Field_1_B
- Sharp_MP_Field_2_B
- Sharp_MP_Field_3_B
- Sharp_MP_PAFF_1r2
- Sharp_MP_PAFF_2r
- cabac_mot_fld0_full
- cabac_mot_mbaff0_full
- cabac_mot_picaff0_full
- cama1_vtc_c
- cama2_vtc_b
- cama3_vtc_b
- cavlc_mot_fld0_full_B
- cavlc_mot_mbaff0_full_B
- cavlc_mot_picaff0_full_B
- Unsupported bitstream: num_slice_group_minus1 > 0 (slice groups not supported by hardware).
- FM1_BT_B
- FM1_FT_E
- FM2_SVA_C
- Unsupported bitstream: SP slice type is not supported by hardware.
- SP1_BT_A
- sp2_bt_b
./fluster.py run -ts JCT-VC-HEVC_V1 -d GStreamer-H.265-V4L2-Gst1.0 - 113/147
The failing test case:
- Unsupported level
- AMP_D_Hisilicon_3
- AMP_E_Hisilicon_3
- AMP_F_Hisilicon_3
- DELTAQP_A_BRCM_4
- IPRED_A_docomo_2
- IPRED_C_Mitsubishi_3
- LS_A_Orange_2
- LS_B_Orange_4
- PPS_A_qualcomm_7
- RAP_B_Bossen_2
- RPS_F_docomo_2
- SAO_G_Canon_3
- SDH_A_Orange_4
- 10bit content not supported yet
- DBLK_A_MAIN10_VIXS_4
- INITQP_B_Main10_Sony_1
- TSUNEQBD_A_MAIN10_Technicolor_2
- WPP_A_ericsson_MAIN10_2
- WPP_B_ericsson_MAIN10_2
- WPP_C_ericsson_MAIN10_2
- WPP_D_ericsson_MAIN10_2
- WPP_E_ericsson_MAIN10_2
- WPP_F_ericsson_MAIN10_2
- WP_A_MAIN10_Toshiba_3
- WP_MAIN10_B_Toshiba_3
- Unsupported resolution
- AMP_A_Samsung_7 - resolution is higher than max supported
- AMP_B_Samsung_7 - resolution is higher than max supported
- PICSIZE_A_Bossen_1 - resolution is higher than max supported
- PICSIZE_B_Bossen_1 - resolution is higher than max supported
- PICSIZE_C_Bossen_1 - resolution is higher than max supported
- PICSIZE_D_Bossen_1 - resolution is higher than max supported
- TUSIZE_A_Samsung_1 - resolution is higher than max supported
- WPP_D_ericsson_MAIN_2 - resolution is lower than min supported
- CRC mismatch
- RAP_A_docomo_6
- CRC mismatch - bitstream issue - fails with ffmpeg sw decoder as well
- VPSSPSPPS_A_MainConcept_1
./fluster.py run -ts VP9-TEST-VECTORS -d GStreamer-VP9-V4L2-Gst1.0 -j1 - 206/305
The failing test case:
- Unsupported resolution
- vp90-2-02-size-08x08.webm
- vp90-2-02-size-08x10.webm
- vp90-2-02-size-08x16.webm
- vp90-2-02-size-08x18.webm
- vp90-2-02-size-08x32.webm
- vp90-2-02-size-08x34.webm
- vp90-2-02-size-08x64.webm
- vp90-2-02-size-08x66.webm
- vp90-2-02-size-10x08.webm
- vp90-2-02-size-10x10.webm
- vp90-2-02-size-10x16.webm
- vp90-2-02-size-10x18.webm
- vp90-2-02-size-10x32.webm
- vp90-2-02-size-10x34.webm
- vp90-2-02-size-10x64.webm
- vp90-2-02-size-10x66.webm
- vp90-2-02-size-16x08.webm
- vp90-2-02-size-16x10.webm
- vp90-2-02-size-16x16.webm
- vp90-2-02-size-16x18.webm
- vp90-2-02-size-16x32.webm
- vp90-2-02-size-16x34.webm
- vp90-2-02-size-16x64.webm
- vp90-2-02-size-16x66.webm
- vp90-2-02-size-18x08.webm
- vp90-2-02-size-18x10.webm
- vp90-2-02-size-18x16.webm
- vp90-2-02-size-18x18.webm
- vp90-2-02-size-18x32.webm
- vp90-2-02-size-18x34.webm
- vp90-2-02-size-18x64.webm
- vp90-2-02-size-18x66.webm
- vp90-2-02-size-32x08.webm
- vp90-2-02-size-32x10.webm
- vp90-2-02-size-32x16.webm
- vp90-2-02-size-32x18.webm
- vp90-2-02-size-32x32.webm
- vp90-2-02-size-32x34.webm
- vp90-2-02-size-32x64.webm
- vp90-2-02-size-32x66.webm
- vp90-2-02-size-34x08.webm
- vp90-2-02-size-34x10.webm
- vp90-2-02-size-34x16.webm
- vp90-2-02-size-34x18.webm
- vp90-2-02-size-34x32.webm
- vp90-2-02-size-34x34.webm
- vp90-2-02-size-34x64.webm
- vp90-2-02-size-34x66.webm
- vp90-2-02-size-64x08.webm
- vp90-2-02-size-64x10.webm
- vp90-2-02-size-64x16.webm
- vp90-2-02-size-64x18.webm
- vp90-2-02-size-64x32.webm
- vp90-2-02-size-64x34.webm
- vp90-2-02-size-64x64.webm
- vp90-2-02-size-64x66.webm
- vp90-2-02-size-66x08.webm
- vp90-2-02-size-66x10.webm
- vp90-2-02-size-66x16.webm
- vp90-2-02-size-66x18.webm
- vp90-2-02-size-66x32.webm
- vp90-2-02-size-66x34.webm
- vp90-2-02-size-66x64.webm
- vp90-2-02-size-66x66.webm
- vp90-2-08-tile_1x8.webm - resolution is higher than max supported
- vp90-2-08-tile_1x8_frame_parallel.webm - resolution is higher than max supported
- vp90-2-14-resize-10frames-fp-tiles-1-2-4-8.webm - resolution is higher than max supported
- vp90-2-14-resize-10frames-fp-tiles-1-8.webm - resolution is higher than max supported
- vp90-2-14-resize-10frames-fp-tiles-2-8.webm - resolution is higher than max supported
- vp90-2-14-resize-10frames-fp-tiles-4-8.webm - resolution is higher than max supported
- vp90-2-14-resize-10frames-fp-tiles-8-1.webm - resolution is higher than max supported
- vp90-2-14-resize-10frames-fp-tiles-8-2.webm - resolution is higher than max supported
- vp90-2-14-resize-10frames-fp-tiles-8-4-2-1.webm - resolution is higher than max supported
- vp90-2-14-resize-10frames-fp-tiles-8-4.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-1-16.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-1-2-4-8-16.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-1-8.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-16-1.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-16-2.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-16-4.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-16-8-4-2-1.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-16-8.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-2-16.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-2-8.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-4-16.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-4-8.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-8-1.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-8-16.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-8-2.webm - resolution is higher than max supported
- vp90-2-14-resize-fp-tiles-8-4.webm - resolution is higher than max supported
- Unsupported format
- vp91-2-04-yuv422.webm
- vp91-2-04-yuv444.webm
- CRC mismatch
- vp90-2-22-svc_1280x720_3.ivf
- Unsupported resolution after sequence change
- vp90-2-18-resize.ivf
- vp90-2-21-resize_inter_320x180_5_1-2.webm
- vp90-2-21-resize_inter_320x180_7_1-2.webm
- vp90-2-21-resize_inter_320x240_5_1-2.webm
- p90-2-21-resize_inter_320x240_7_1-2.webm
- Unsupported stream
- vp90-2-16-intra-only.webm
Fluster results for HFI Gen1 firmware:
Tests failing with the Venus driver, but passing with the Iris:
- H.264: BA3_SVA_C
- H.265: ipcm_A_NEC_3, ipcm_B_NEC_3, ipcm_C_NEC_3, ipcm_D_NEC_3,
ipcm_E_NEC_2, IPRED_B_Nokia_3, VPSSPSPPS_A_MainConcept_1
- VP9: vp90-2-14-resize-10frames-fp-tiles-1-2.webm,
vp90-2-14-resize-10frames-fp-tiles-2-1.webm,
vp90-2-14-resize-fp-tiles-1-2.webm,
vp90-2-14-resize-fp-tiles-2-1.webm,
vp90-2-14-resize-fp-tiles-4-1.webm,
vp90-2-14-resize-fp-tiles-4-2.webm,
vp90-2-15-segkey.webm
Tests failing with the Iris driver, but passing with the Venus (due to
interlaced H.264 being not supported yet):
- H.264: cabac_mot_fld0_full, cabac_mot_mbaff0_full,
cabac_mot_picaff0_full, CABREF3_Sand_D, CAFI1_SVA_C, CAMA1_Sony_C,
CAMA1_TOSHIBA_B, cama1_vtc_c, cama2_vtc_b, CAMA3_Sand_E, cama3_vtc_b,
CAMACI3_Sony_C, CAMANL1_TOSHIBA_B, CAMANL2_TOSHIBA_B, CAMANL3_Sand_E,
CAMASL3_Sony_B, CAMP_MOT_MBAFF_L30, CAMP_MOT_MBAFF_L31,
CANLMA2_Sony_C, CANLMA3_Sony_C, CAPA1_TOSHIBA_B, CAPAMA3_Sand_F,
cavlc_mot_fld0_full_B, cavlc_mot_mbaff0_full_B,
cavlc_mot_picaff0_full_B, CVCANLMA2_Sony_C, CVFI1_Sony_D, CVFI1_SVA_C,
CVFI2_Sony_H, CVFI2_SVA_C, CVMA1_Sony_D, CVMA1_TOSHIBA_B,
CVMANL1_TOSHIBA_B, CVMANL2_TOSHIBA_B, CVMAPAQP3_Sony_E,
CVMAQP2_Sony_G, CVMAQP3_Sony_D, CVMP_MOT_FLD_L30_B,
CVMP_MOT_FRM_L31_B, CVNLFI1_Sony_C, CVNLFI2_Sony_H, CVPA1_TOSHIBA_B,
FI1_Sony_E, MR9_BT_B, Sharp_MP_Field_1_B, Sharp_MP_Field_2_B,
Sharp_MP_Field_3_B, Sharp_MP_PAFF_1r2, Sharp_MP_PAFF_2r
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
Changes in v5:
- Corrected UBWC formats handling for non-UBWC targets (Sashiko)
- Added missing data to x1p42100 data structures (Sashiko)
- Fixed bw calculations to use actual FPS, switched to common
iris_vpu2_calculate_frequency() (Sashiko, Vishnu)
- Added comment regarding hold_count vs min_count (Sashiko)
- Link to v4: https://patch.msgid.link/20260612-iris-ar50lt-v4-0-0abfb74d5b3c@oss.qualcomm.com
Changes in v4:
- Rebaed on linux-next, fixing conflicts. Note, these patches require
both media/fixes and media/next and thus can be applied only after
7.2-rc1.
- Link to v3: https://patch.msgid.link/20260515-iris-ar50lt-v3-0-df3846e74347@oss.qualcomm.com
Changes in v3:
- Corrected dependencies list in the cover letter
- Link to v2: https://patch.msgid.link/20260513-iris-ar50lt-v2-0-411e5f7bdc4c@oss.qualcomm.com
Changes in v2:
- Dropped OPP patch, applied by Bjorn.
- Dropped extra check for throttle clocks (Vishnu)
- Made iris_inst_fw_cap_gen1_ar50lt_dec and inst_fw_cap_sm8250_dec const
(Vishnu)
- Renamed iris_vpu_ar50lt_buf_size() to iris_vpu_ar50lt_gen2_buf_size()
(Vishnu)
- Link to v1: https://patch.msgid.link/20260507-iris-ar50lt-v1-0-d22cccedc3e2@oss.qualcomm.com
To: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
To: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
To: Abhinav Kumar <abhinav.kumar@linux.dev>
To: Bryan O'Donoghue <bod@kernel.org>
To: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: linux-media@vger.kernel.org
Cc: linux-arm-msm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Dikshita Agarwal (10):
media: iris: Skip UBWC configuration when not supported
media: iris: Filter UBWC raw formats based on hardware capabilities
media: iris: Introduce set_preset_register as a vpu_op
media: iris: Introduce interrupt_init as a vpu_op
media: iris: add vpu op hook to disable ARP buffer
media: iris: Add platform data field for watchdog interrupt mask
media: iris: Add platform flag for instantaneous bandwidth voting
media: iris: Add framework support for AR50_LITE video core
media: iris: Introduce buffer size calculations for AR50LT
media: iris: add Gen2 firmware support on the Agatti platform
Dmitry Baryshkov (6):
media: iris: skip PIPE if it is not supported by the platform
media: iris: add minimal GET_PROPERTY implementation
media: iris: update buffer requirements based on received info
media: iris: implement support for the Agatti platform
media: venus: skip QCM2290 if Iris driver is enabled
media: iris: constify inst_fw_cap_sm8250_dec
drivers/media/platform/qcom/iris/Makefile | 2 +
drivers/media/platform/qcom/iris/iris_core.c | 4 +
drivers/media/platform/qcom/iris/iris_ctrls.c | 3 +
drivers/media/platform/qcom/iris/iris_hfi_common.c | 4 +
drivers/media/platform/qcom/iris/iris_hfi_common.h | 1 +
drivers/media/platform/qcom/iris/iris_hfi_gen1.c | 229 +++++++-
.../platform/qcom/iris/iris_hfi_gen1_command.c | 21 +
.../platform/qcom/iris/iris_hfi_gen1_defines.h | 15 +
.../platform/qcom/iris/iris_hfi_gen1_response.c | 79 +++
drivers/media/platform/qcom/iris/iris_hfi_gen2.c | 613 +++++++++++++++++++++
.../platform/qcom/iris/iris_hfi_gen2_packet.c | 3 +
.../platform/qcom/iris/iris_platform_common.h | 11 +
.../media/platform/qcom/iris/iris_platform_vpu2.c | 6 +
.../media/platform/qcom/iris/iris_platform_vpu3x.c | 12 +
.../platform/qcom/iris/iris_platform_vpu_ar50lt.c | 117 ++++
drivers/media/platform/qcom/iris/iris_probe.c | 4 +
drivers/media/platform/qcom/iris/iris_resources.c | 2 +
drivers/media/platform/qcom/iris/iris_vdec.c | 26 +-
drivers/media/platform/qcom/iris/iris_venc.c | 9 +
drivers/media/platform/qcom/iris/iris_vpu2.c | 30 +-
drivers/media/platform/qcom/iris/iris_vpu3x.c | 6 +
drivers/media/platform/qcom/iris/iris_vpu4x.c | 2 +
drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c | 130 +++++
drivers/media/platform/qcom/iris/iris_vpu_buffer.c | 414 ++++++++++++++
drivers/media/platform/qcom/iris/iris_vpu_buffer.h | 38 ++
drivers/media/platform/qcom/iris/iris_vpu_common.c | 43 +-
drivers/media/platform/qcom/iris/iris_vpu_common.h | 6 +
.../platform/qcom/iris/iris_vpu_register_defines.h | 1 -
drivers/media/platform/qcom/venus/core.c | 4 +-
29 files changed, 1794 insertions(+), 41 deletions(-)
---
base-commit: 8d6dbbbe3ba62de0a63e962ee004afb848c8e3ac
change-id: 20260507-iris-ar50lt-06228469aa5b
prerequisite-change-id: 20260429-kodiak-gen2-support-v4-a7f055f15afb:v7
prerequisite-patch-id: 9cbeeeda00ce3c8ac611ded245740153cd54f899
Best regards,
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH RFC v3 4/6] arm64: dts: qcom: sm8550-hdk: add SPMI ADC channels and thermal nodes
From: Dmitry Baryshkov @ 2026-06-16 0:00 UTC (permalink / raw)
To: Neil Armstrong
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20260615-topic-sm8x50-adc5-gen3-v3-4-216a2b5ccb85@linaro.org>
On Mon, Jun 15, 2026 at 07:00:10PM +0200, Neil Armstrong wrote:
> Add the SPMI ADC channels on the PMK8550 SPMI5 ADC3 for the
> other PMICS on the system.
>
> The thermal nodes are sorted by the sensor channel to be
> coherent with the system thermal nodes ordering.
>
> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> ---
> arch/arm64/boot/dts/qcom/sm8550-hdk.dts | 279 ++++++++++++++++++++++++++++++++
> 1 file changed, 279 insertions(+)
>
> +
> + channel@747 {
> + reg = <PM8550B_ADC5_GEN3_AMUX_THM4_USB_THERM_100K_PU(7)>;
> + label = "pm8550b_usb_therm";
> + qcom,ratiometric;
> + qcom,hw-settle-time = <200>;
> + qcom,pre-scaling = <1 1>;
> + qcom,adc-tm;
> + };
> +
> + channel@749 {
> + reg = <PM8550B_ADC5_GEN3_AMUX_THM6_GPIO10_100K_PU(7)>;
> + label = "pm8550b_wls_therm";
> + qcom,ratiometric;
> + qcom,pre-scaling = <1 1>;
> + qcom,adc-tm;
Does this need
qcom,hw-settle-time = <200>;
> + };
> +};
> +
> &pon_pwrkey {
> status = "okay";
> };
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH RFC v3 3/6] arm64: dts: qcom: sm8550-qrd: add SPMI ADC channels and thermal nodes
From: Dmitry Baryshkov @ 2026-06-15 23:59 UTC (permalink / raw)
To: sashiko-reviews; +Cc: Neil Armstrong, devicetree, conor+dt, robh
In-Reply-To: <20260615171519.F2A851F00A3A@smtp.kernel.org>
On Mon, Jun 15, 2026 at 05:15:19PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Medium] Missing `qcom,hw-settle-time` for the `channel@749` 100kΩ pull-up thermistor (`pm8550b_wls_therm`), leading to inaccurate temperature readings.
> - [Low] The ADC channel nodes are not sorted by their unit address, violating standard device tree conventions.
> --
>
> commit 4a45cdf2d6ed588ab63165c08752b51ef046be4f
> Author: Neil Armstrong <neil.armstrong@linaro.org>
>
> arm64: dts: qcom: sm8550-qrd: add SPMI ADC channels and thermal nodes
>
> Add the SPMI ADC channels on the PMK8550 SPMI5 ADC3 for the
> other PMICS on the system.
>
> The thermal nodes are sorted by the sensor channel to be
> coherent with the system thermal nodes ordering.
>
>
> [Severity: Low]
> Similar to the above, this isn't a bug, but should channel@78e and
> channel@78f be placed after channel@747 and channel@749 to maintain
> proper unit address sorting?
Yes, sorting might need some improvements.
>
> > +
> > + channel@749 {
> > + reg = <PM8550B_ADC5_GEN3_AMUX_THM6_GPIO10_100K_PU(7)>;
> > + label = "pm8550b_wls_therm";
> > + qcom,ratiometric;
> > + qcom,pre-scaling = <1 1>;
> > + qcom,adc-tm;
> > + };
>
> [Severity: Medium]
> Does this node need qcom,hw-settle-time = <200> like the other 100K
> pull-up thermistor channels in this patch?
>
> Without it, the ADC measurement falls back to the default settle time,
> which might be insufficient for this high-impedance path and lead to
> inaccurate temperature readings for the pm8550b_wls_therm channel.
I'd also guess so. Neil, are you sure?
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH RFC v3 2/6] arm64: dts: qcom: pmk8550: add VADC node
From: Dmitry Baryshkov @ 2026-06-15 23:58 UTC (permalink / raw)
To: Neil Armstrong
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20260615-topic-sm8x50-adc5-gen3-v3-2-216a2b5ccb85@linaro.org>
On Mon, Jun 15, 2026 at 07:00:08PM +0200, Neil Armstrong wrote:
> Add the VADC node and the initial pmk8550 adc channels.
Nit: PMK8550, ADC.
>
> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> ---
> arch/arm64/boot/dts/qcom/pmk8550.dtsi | 30 ++++++++++++++++++++++++++++++
> 1 file changed, 30 insertions(+)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH RFC v3 1/6] arm64: dts: qcom: add PMIC5 Gen3 macros for channel numbers
From: Dmitry Baryshkov @ 2026-06-15 23:58 UTC (permalink / raw)
To: Neil Armstrong
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20260615-topic-sm8x50-adc5-gen3-v3-1-216a2b5ccb85@linaro.org>
On Mon, Jun 15, 2026 at 07:00:07PM +0200, Neil Armstrong wrote:
> Add the PMIC5 Gen3 macros to calculate the channel numbers which
> is a combination of SPMI bus number and a constant for the sensor
> type and configuration.
>
> The macros definitions were taken out of [1] where it was initially
> in the dt-bindings include directory but since those are not hardware
> bindings but logical numbers, they can be moved to local includes
> instead to make the DT source more readable.
>
> [1] https://lore.kernel.org/all/20250826083657.4005727-4-jishnu.prakash@oss.qualcomm.com/
>
> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> ---
> arch/arm64/boot/dts/qcom/qcom,adc5-gen3-channels.h | 88 ++++++++++++++++++++++
> arch/arm64/boot/dts/qcom/qcom,pm8550-adc5-gen3.h | 46 +++++++++++
> arch/arm64/boot/dts/qcom/qcom,pm8550b-adc5-gen3.h | 85 +++++++++++++++++++++
> arch/arm64/boot/dts/qcom/qcom,pm8550vx-adc5-gen3.h | 22 ++++++
> arch/arm64/boot/dts/qcom/qcom,pmk8550-adc5-gen3.h | 52 +++++++++++++
> 5 files changed, 293 insertions(+)
>
After 's/ACD5/ADC5/':
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH net-next v2 1/2] dt-bindings: net: pse-pd: add bindings for Realtek/Broadcom PSE MCU
From: Daniel Golle @ 2026-06-15 23:50 UTC (permalink / raw)
To: Rob Herring
Cc: Jonas Jelonek, Oleksij Rempel, Kory Maincent, Andrew Lunn,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
linux-kernel, Bjørn Mork
In-Reply-To: <20260615212959.GA1679454-robh@kernel.org>
On Mon, Jun 15, 2026 at 04:29:59PM -0500, Rob Herring wrote:
> On Fri, Jun 12, 2026 at 01:29:41PM +0000, Jonas Jelonek wrote:
> > +properties:
> > + compatible:
> > + enum:
> > + - realtek,pse-mcu-rtk
>
> The "rtk" feels redundant.
>
> > + - realtek,pse-mcu-bcm
>
> "brcm" is the standard vendor prefix, so use that instead of "bcm".
> Though who defined the protocol in this case? Realtek or Broadcom? In
> the latter case, I'd argue that "brcm" should be the vendor prefix.
The microcontroller firmware, and hence the protocol, is designed
by RealTek in both cases. However, they chose to design two incmpatible
protocol dialects based on the features of the PSE(s) connected to the
MCU.
^ permalink raw reply
* Re: [PATCH net v5 0/4] MAC-PHY interrupt changed to level triggered interrupt
From: patchwork-bot+netdevbpf @ 2026-06-15 23:40 UTC (permalink / raw)
To: Selvamani Rajagopal
Cc: parthiban.veerasooran, andrew+netdev, davem, edumazet, kuba,
pabeni, robh, krzk+dt, conor+dt, pier.beruto, andrew, netdev,
linux-kernel, conor.dooley, devicetree, Parthiban.Veerasooran,
Selvamani.Rajagopal
In-Reply-To: <20260611-level-trigger-v5-0-4533a9e85ce2@onsemi.com>
Hello:
This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 11 Jun 2026 14:55:37 -0700 you wrote:
> According to OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface
> specification, MAC-PHY interrupt is "active low, level triggered".
> The specification mentions about the conditions in which the IRQ
> is asserted and deasserted.
>
> Bug is inadvertently introduced by treating the IRQ in the OA TC6
> framework driver and in dt-binding YAML file as edge triggered.
>
> [...]
Here is the summary with links:
- [net,v5,1/4] net: ethernet: oa_tc6: Interrupt is active low, level triggered.
https://git.kernel.org/netdev/net/c/b542d13fab0f
- [net,v5,2/4] net: ethernet: oa_tc6: mdiobus->parent initialized with NULL
https://git.kernel.org/netdev/net/c/a221d3f7e3f3
- [net,v5,3/4] net: ethernet: oa_tc6: Remove FCS size in RX frame
https://git.kernel.org/netdev/net/c/a5a1d11dd372
- [net,v5,4/4] dt-bindings: net: updated interrupt type to be active low, level triggered
https://git.kernel.org/netdev/net/c/31e56112e654
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: (subset) [PATCH v11 0/9] Add support for NXP P3H2x4x I3C hub driver
From: Alexandre Belloni @ 2026-06-15 23:29 UTC (permalink / raw)
To: linux-kernel, linux-i3c, krzk+dt, robh, conor+dt, devicetree,
broonie, lee, Frank.Li, lgirdwood, Lakshay Piplani
Cc: vikash.bansal, priyanka.jain, aman.kumarpandey
In-Reply-To: <20260612111816.3688240-1-lakshay.piplani@nxp.com>
On Fri, 12 Jun 2026 16:48:07 +0530, Lakshay Piplani wrote:
> This series adds a driver for the NXP P3H2x4x family of multiport I3C hub
> devices.
>
> This is an MFD driver integrating I3C hub and on-die regulators.
>
> The series introduces:
> - Core I3C master enhancements required for hub support
> - Generic I3C hub framework
> - MFD driver with regulator and I3C hub child drivers for the P3H2x4x I3C hub
>
> [...]
Applied, thanks!
[1/9] i3c: master: rename i3c_master_reattach_i3c_dev() to *_locked
https://git.kernel.org/i3c/c/79c41666b397
[2/9] i3c: master: Expose the APIs to support I3C hub
https://git.kernel.org/i3c/c/8d8afa428318
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH 3/4] mfd: mt6397-core: add mt6323 AUXADC support
From: Roman Vivchar @ 2026-06-15 23:10 UTC (permalink / raw)
To: Lee Jones
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, linux-iio, devicetree, linux-kernel,
linux-arm-kernel, linux-mediatek, Ben Grisdale
In-Reply-To: <20260611163748.GB1212816@google.com>
Hi Lee,
On Thursday, June 11th, 2026 at 7:37 PM, Lee Jones <lee@kernel.org> wrote:
> Interesting. Has this been considered?
>
> /* Sashiko Automation: Issues Found (1 Findings) */
>
> On Tue, 02 Jun 2026, Roman Vivchar via B4 Relay wrote:
>
> > From: Roman Vivchar <rva333@protonmail.com>
> >
> > The mt6323 PMIC includes an AUXADC. Register the AUXADC in the mt6323
> > devices array to allow the corresponding driver to probe using compatible
> > string.
> >
> > Tested-by: Ben Grisdale <bengris32@protonmail.ch> # Amazon Echo Dot (2nd Generation)
> > Signed-off-by: Roman Vivchar <rva333@protonmail.com>
> > ---
> > drivers/mfd/mt6397-core.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
> > index 3e58d0764c7e..013b0857fb54 100644
> > --- a/drivers/mfd/mt6397-core.c
> > +++ b/drivers/mfd/mt6397-core.c
> > @@ -125,6 +125,9 @@ static const struct resource mt6323_pwrc_resources[] = {
> >
> > static const struct mfd_cell mt6323_devs[] = {
> > {
> > + .name = "mt6323-auxadc",
> > + .of_compatible = "mediatek,mt6323-auxadc",
>
> [Severity: High]
> Does adding this compatible string expose an unhandled edge case in the
> auxadc driver?
>
> If this device is instantiated directly from a Device Tree without an MFD
> parent (e.g., at the DT root), dev->parent could be the platform bus
> (which has a NULL parent) or NULL itself.
>
> Looking at mt6323_auxadc_probe() in drivers/iio/adc/mt6323-auxadc.c:
>
> regmap = dev_get_regmap(dev->parent->parent, NULL);
>
> Could blindly dereferencing dev->parent->parent here, or passing a NULL
> device to dev_get_regmap() (which calls devres_find()), result in a
> kernel oops if probed as a root node?
This is intended behavior, ADC always should be probed as a child of
the mt6323 MFD because it doesn't have own MMIO space. Otherwise the
devicetree is malformed. Recent mt6359 ADC driver has same thing with
dev->parent->parent regmap.
Best regards,
Roman
^ permalink raw reply
* Re: [PATCH v2 2/4] iio: adc: mt6323-auxadc: add mt6323 PMIC AUXADC driver
From: Roman Vivchar @ 2026-06-15 22:52 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Roman Vivchar via B4 Relay, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Lee Jones,
linux-iio, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Ben Grisdale
In-Reply-To: <20260614182214.65d052e4@jic23-huawei>
Hi Jonathan,
On Sunday, June 14th, 2026 at 8:22 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> On Tue, 09 Jun 2026 16:31:59 +0300
> Roman Vivchar via B4 Relay <devnull+rva333.protonmail.com@kernel.org> wrote:
...
> > +
> > +#define MTK_PMIC_IIO_CHAN(_name, _chan, _addr) \
> > +{ \
> > + .type = IIO_VOLTAGE, \
> > + .indexed = 1, \
> > + .channel = _chan, \
> > + .address = _addr, \
> > + .datasheet_name = __stringify(_name), \
> > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> > + BIT(IIO_CHAN_INFO_SCALE), \
> > +}
> > +
> > +static const struct iio_chan_spec mt6323_auxadc_channels[] = {
> > + MTK_PMIC_IIO_CHAN(baton2, MT6323_AUXADC_BATON2, MT6323_AUXADC_ADC6),
> > + MTK_PMIC_IIO_CHAN(ch6, MT6323_AUXADC_CH6, MT6323_AUXADC_ADC11),
> > + MTK_PMIC_IIO_CHAN(bat_temp, MT6323_AUXADC_BAT_TEMP, MT6323_AUXADC_ADC5),
>
> Reasonable query from Sashiko on why temperature channels are presented as voltages.
> If for some reason that is the right choice, then maybe a comment here.
mt6323 ADC always returns voltage. The thermal driver (which was in the
previous series and will be sent later) is required to map these to the
actual temperature. Ack.
...
> > +/*
> > + * The MediaTek MT6323 (as well as a lot of other PMICs) has the following hierarchy:
> > + * PMIC AUXADC <- PMIC MFD <- SoC PWRAP (wrapper for PWRAP FSM)
> > + *
> > + * Therefore, PWRAP regmap should be obtained using dev->parent->parent.
> > + */
> > +struct mt6323_auxadc {
> > + struct regmap *regmap;
> > + struct mutex lock;
> Locks should always have a comment on what data they are protecting.
> I think this one is about protecting the state of a device during a channel read
> by serializing those reads.
Nuno said kerneldoc looks unnecessary on v1 [1]. How the comment should
look?
...
> > +static int mt6323_auxadc_request(struct mt6323_auxadc *auxadc,
> > + unsigned long channel)
> > +{
> > + struct regmap *map = auxadc->regmap;
> > + int ret;
> > +
> > + ret = regmap_set_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN);
> > + if (ret)
> > + return ret;
> > +
> > + return regmap_set_bits(map, MT6323_AUXADC_CON22, BIT(channel));
>
> I'm not sure whether the sashiko question on this is valid or not. Make sure to take
> a look.
>
> https://sashiko.dev/#/patchset/20260609-mt6323-adc-v2-0-aa93a22309f9%40protonmail.com
> You may have carefully selected the numbering so the channel numbering matches
> the bits in this register. If so, it is probably worth a comment in the header
> to provide a cross reference. No idea if Sashiko will notice that, but at least
> humans should!
The hardware is pretty weird, but dt-bindings have correct numbers.
I have double checked with the vendor driver and the logic is the same.
'If regmap_set_bits() fails to set MT6323_AUXADC_CON22, does this leave the
AUXADC voltage buffer (VBUF) permanently enabled?' - if this happens,
then there's something really wrong with PWRAP and disabling VBUF may
not be possible. Same about the 'mt6323_auxadc_release' comment.
...
> > + case IIO_CHAN_INFO_RAW:
>
> What Andy suggested here is the preferred path in IIO at least.
> Mainly because it reduced indent without hurting readability.
> Just be careful to define the scope with { }
Ack.
>
>
> > + scoped_guard(mutex, &auxadc->lock) {
> > + ret = mt6323_auxadc_prepare_channel(auxadc);
> > + if (ret)
> > + return ret;
> > +
> > + ret = mt6323_auxadc_request(auxadc, chan->channel);
> > + if (ret)
> > + return ret;
> > +
> > + /* Hardware limitation: the AUXADC needs a delay to become ready. */
> > + fsleep(300);
> > +
> > + ret = mt6323_auxadc_read(auxadc, chan, val);
> > +
> > + if (mt6323_auxadc_release(auxadc, chan->channel))
> > + dev_err(&indio_dev->dev,
> > + "failed to release channel %d\n", chan->channel);
> > +
> > + if (ret)
> > + return ret;
> > + }
> > + return IIO_VAL_INT;
> > + default:
> > + return -EINVAL;
> > + }
> > +}
>
>
After these changes, should I keep or drop Andy's Reviewed-by?
[1]: https://lore.kernel.org/linux-iio/2df4cad5e29fbcb4c5c5f59ea0bf322c7a301bdc.camel@gmail.com/
Best regards,
Roman
^ permalink raw reply
* Re: [PATCH v3 3/3] iio: adc: Fix incorrect reading when datarate changed in single mode
From: David Lechner @ 2026-06-15 22:38 UTC (permalink / raw)
To: Jakub Szczudlo, linux-iio
Cc: andy, antoniu.miclaus, conor+dt, devicetree, duje, jic23,
jishnu.prakash, jorge.marques, krzk+dt, linusw, linux-kernel,
marcelo.schmitt, mazziesaccount, mike.looijmans, nuno.sa, robh,
sakari.ailus, wens, joshua.crofts1
In-Reply-To: <20260613190957.654798-4-jakubszczudlo40@gmail.com>
On 6/13/26 2:09 PM, Jakub Szczudlo wrote:
> When device is suspended and it is in single mode then changing
> datarate doesn't make it actual wait for new measurement, so to
s/actual/actually/
> be sure that read after change is correct functions that changes
> datarate and gain will wait for new data.
s/datarate/data rate/g
The commit message isn't very clear to me. Is the point that the
changes don't actually take effect in the ADC until a conversion
is done?
>
> Signed-off-by: Jakub Szczudlo <jakubszczudlo40@gmail.com>
> ---
> drivers/iio/adc/ti-ads1100.c | 55 ++++++++++++++++++++++++++++++++++--
> 1 file changed, 52 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c
> index 76de2466dc53..195394665cd1 100644
> --- a/drivers/iio/adc/ti-ads1100.c
> +++ b/drivers/iio/adc/ti-ads1100.c
> @@ -123,6 +123,36 @@ static int ads1100_get_voltage_microvolts(struct ads1100_data *data)
> return ads1100_get_voltage_milivolts(data) * MICRO / MILLI;
> }
>
> +static bool ads1100_new_data_ready(struct ads1100_data *data)
> +{
> + int ret;
> + u8 buffer[3];
> +
> + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer));
> + if (ret < 3) {
> + dev_err(&data->client->dev, "I2C read fail: %d\n", ret);
> + return ret;
> + }
> +
> + return FIELD_GET(ADS1100_CFG_ST_BSY, buffer[2]);
> +}
> +
> +static int ads1100_poll_data_ready(struct ads1100_data *data)
> +{
> + u8 buffer[3];
> + bool data_ready;
> + int datarate = data->ads_config->data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)];
> + // To be sure we wait 5 times more than datarate
> + unsigned long wait_time = DIV_ROUND_CLOSEST(MICRO, 5 * datarate);
> +
> + /* To be sure that polled value will have value after config change */
> + i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer));
> +
> + return read_poll_timeout(ads1100_new_data_ready, data_ready,
> + !data_ready, wait_time,
> + ADS1100_MAX_DRDY_TIMEOUT, false, data);
> +}
> +
> static int ads1100_data_bits(struct ads1100_data *data)
> {
> return ads1100_data_rate_bits[FIELD_GET(ADS1100_DR_MASK, data->config)];
> @@ -165,6 +194,7 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
> {
> int microvolts;
> int gain;
> + int ret;
>
> /* With Vdd between 2.7 and 5V, the scale is always below 1 */
> if (val)
> @@ -185,21 +215,40 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
> if (gain < BIT(0) || gain > BIT(3))
> return -EINVAL;
>
> + ret = pm_runtime_resume_and_get(&data->client->dev);
> + if (ret < 0)
> + return ret;
> +
> ads1100_set_config_bits(data, ADS1100_PGA_MASK, ffs(gain) - 1);
>
> - return 0;
> + ret = ads1100_poll_data_ready(data);
> +
> + pm_runtime_put_autosuspend(&data->client->dev);
> +
> + return ret;
> }
>
> static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate)
> {
> unsigned int i;
> unsigned int size;
> + int ret;
>
> size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1;
> for (i = 0; i < size; i++) {
> - if (data->ads_config->data_rate[i] == rate)
> - return ads1100_set_config_bits(data, ADS1100_DR_MASK,
> + if (data->ads_config->data_rate[i] != rate)
> + continue;
> +
> + ret = pm_runtime_resume_and_get(&data->client->dev);
> + if (ret < 0)
> + return ret;
> +
> + ads1100_set_config_bits(data, ADS1100_DR_MASK,
> FIELD_PREP(ADS1100_DR_MASK, i));
Why no longer checking the return value of ads1100_set_config_bits()?
> + ret = ads1100_poll_data_ready(data);
> +
> + pm_runtime_put_autosuspend(&data->client->dev);
> + return ret;
> }
>
> return -EINVAL;
^ permalink raw reply
* Re: [PATCH v3 2/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver
From: David Lechner @ 2026-06-15 22:29 UTC (permalink / raw)
To: Jakub Szczudlo, linux-iio
Cc: andy, antoniu.miclaus, conor+dt, devicetree, duje, jic23,
jishnu.prakash, jorge.marques, krzk+dt, linusw, linux-kernel,
marcelo.schmitt, mazziesaccount, mike.looijmans, nuno.sa, robh,
sakari.ailus, wens, joshua.crofts1
In-Reply-To: <20260613190957.654798-3-jakubszczudlo40@gmail.com>
On 6/13/26 2:09 PM, Jakub Szczudlo wrote:
> Add ADS1110 support that have faster datarate than ADS1100, it also uses
> internal voltage reference of 2.048V for measurement.
>
> Signed-off-by: Jakub Szczudlo <jakubszczudlo40@gmail.com>
> ---
> drivers/iio/adc/Kconfig | 6 +--
> drivers/iio/adc/ti-ads1100.c | 83 +++++++++++++++++++++++++++---------
> 2 files changed, 65 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index a9dedbb8eb46..54a0149a3838 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -1747,11 +1747,11 @@ config TI_ADS1018
> called ti-ads1018.
>
> config TI_ADS1100
> - tristate "Texas Instruments ADS1100 and ADS1000 ADC"
> + tristate "Texas Instruments ADS1100 and similar single channel I2C ADC"
> depends on I2C
> help
> - If you say yes here you get support for Texas Instruments ADS1100 and
> - ADS1000 ADC chips.
> + If you say yes here you get support TI ADS1100 and similar single
> + channel I2C Analog to Digital Converters
>
> This driver can also be built as a module. If so, the module will be
> called ti-ads1100.
> diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c
> index aa8946063c7d..76de2466dc53 100644
> --- a/drivers/iio/adc/ti-ads1100.c
> +++ b/drivers/iio/adc/ti-ads1100.c
> @@ -5,7 +5,7 @@
> * Copyright (c) 2023, Topic Embedded Products
> *
> * Datasheet: https://www.ti.com/lit/gpn/ads1100
> - * IIO driver for ADS1100 and ADS1000 ADC 16-bit I2C
> + * IIO driver for ADS1100 and similar single channel ADC 16-bit I2C
> */
>
> #include <linux/bitfield.h>
> @@ -15,6 +15,7 @@
> #include <linux/module.h>
> #include <linux/init.h>
> #include <linux/i2c.h>
> +#include <linux/iopoll.h>
> #include <linux/mutex.h>
> #include <linux/property.h>
> #include <linux/pm_runtime.h>
> @@ -39,17 +40,41 @@
> #define ADS1100_SINGLESHOT ADS1100_CFG_SC
>
> #define ADS1100_SLEEP_DELAY_MS 2000
> +#define ADS1110_REFERENCE_VOLTAGE_MILIVOLTS 2048
maybe a better name?
ADS1110_INTERNAL_REF_mV
> +
> +/* Timeout based on the minimum sample rate of 8 SPS (7500000us) */
I would make the value in the comment an easier to read number, e.g.
7.5 s
> +#define ADS1100_MAX_DRDY_TIMEOUT 7500000
Always nice to include the units in the identifier name.
ADS1100_MAX_DRDY_TIMEOUT_us
>
> static const int ads1100_data_rate[] = { 128, 32, 16, 8 };
> +static const int ads1110_data_rate[] = { 240, 60, 30, 15 };
> static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 };
>
> +struct ads1100_config {
> + const char *name;
> + const int *data_rate;
> + bool has_reference_voltage;
It would be helpful if this name was more specific. I think this means
has_internal_vref_only?
> +};
> +
> +static const struct ads1100_config ads1100_config = {
> + .name = "ads1100",
> + .data_rate = ads1100_data_rate,
> + .has_reference_voltage = false,
> +};
> +
> +static const struct ads1100_config ads1110_config = {
> + .name = "ads1110",
> + .data_rate = ads1110_data_rate,
> + .has_reference_voltage = true,
> +};
> +
> struct ads1100_data {
> struct i2c_client *client;
> struct regulator *reg_vdd;
> struct mutex lock;
> int scale_avail[2 * 4]; /* 4 gain settings */
> + struct ads1100_config *ads_config;
> u8 config;
> - bool supports_data_rate; /* Only the ADS1100 can select the rate */
> + bool supports_data_rate; /* Only the ADS1100/ADS1110 can select the rate */
I would just drop this comment since it is runtime detected.
Otherwise, it makes it sound like this belongs in struct ads1100_config.
> };
>
> static const struct iio_chan_spec ads1100_channel = {
> @@ -85,6 +110,19 @@ static int ads1100_set_config_bits(struct ads1100_data *data, u8 mask, u8 value)
> return 0;
> };
>
> +static int ads1100_get_voltage_milivolts(struct ads1100_data *data)
I could call this ads1100_get_vref_milivolts() or
ads1100_get_reference_milivolts().
> +{
> + if (data->ads_config->has_reference_voltage)
> + return ADS1110_REFERENCE_VOLTAGE_MILIVOLTS;
> + else
else is not necessary here
> + return regulator_get_voltage(data->reg_vdd) / MILLI;
Why not keeping (MICRO / MILLI)?
> +}
> +
> +static int ads1100_get_voltage_microvolts(struct ads1100_data *data)
> +{
> + return ads1100_get_voltage_milivolts(data) * MICRO / MILLI;
return ads1100_get_voltage_milivolts(data) * (MICRO / MILLI);
> +}
Although this is only used once, so don't really need the helper function.
> +
> static int ads1100_data_bits(struct ads1100_data *data)
> {
> return ads1100_data_rate_bits[FIELD_GET(ADS1100_DR_MASK, data->config)];
> @@ -107,9 +145,9 @@ static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val)
>
> pm_runtime_put_autosuspend(&data->client->dev);
>
> - if (ret < 0) {
> + if (ret < 2) {
> dev_err(&data->client->dev, "I2C read fail: %d\n", ret);
> - return ret;
> + return -EIO;
I think someone else mentioned this already, but ret < 0 should be propagated
rather than replaced with -EIO.
> }
>
> /* Value is always 16-bit 2's complement */
> @@ -135,7 +173,7 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
> if (!val2)
> return -EINVAL;
>
> - microvolts = regulator_get_voltage(data->reg_vdd);
> + microvolts = ads1100_get_voltage_microvolts(data);
> /*
> * val2 is in 'micro' units, n = val2 / 1000000
> * result must be millivolts, d = microvolts / 1000
> @@ -159,22 +197,17 @@ static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate)
>
> size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1;
This is a bit fragile now assuming that all configs have a list the same size
as ads1100_data_rate. It's a bit more verbose, but should probably also include
a size field in the config.
> for (i = 0; i < size; i++) {
> - if (ads1100_data_rate[i] == rate)
> + if (data->ads_config->data_rate[i] == rate)
> return ads1100_set_config_bits(data, ADS1100_DR_MASK,
> - FIELD_PREP(ADS1100_DR_MASK, i));
> + FIELD_PREP(ADS1100_DR_MASK, i));
> }
>
> return -EINVAL;
> }
>
> -static int ads1100_get_vdd_millivolts(struct ads1100_data *data)
> -{
> - return regulator_get_voltage(data->reg_vdd) / (MICRO / MILLI);
> -}
> -
> static void ads1100_calc_scale_avail(struct ads1100_data *data)
> {
> - int millivolts = ads1100_get_vdd_millivolts(data);
> + int millivolts = ads1100_get_voltage_milivolts(data);
> unsigned int i;
>
> for (i = 0; i < ARRAY_SIZE(data->scale_avail) / 2; i++) {
> @@ -196,7 +229,7 @@ static int ads1100_read_avail(struct iio_dev *indio_dev,
> switch (mask) {
> case IIO_CHAN_INFO_SAMP_FREQ:
> *type = IIO_VAL_INT;
> - *vals = ads1100_data_rate;
> + *vals = data->ads_config->data_rate;
> if (data->supports_data_rate)
> *length = ARRAY_SIZE(ads1100_data_rate);
Same here about the array size.
> else
> @@ -233,12 +266,11 @@ static int ads1100_read_raw(struct iio_dev *indio_dev,
> return IIO_VAL_INT;
> case IIO_CHAN_INFO_SCALE:
> /* full-scale is the supply voltage in millivolts */
> - *val = ads1100_get_vdd_millivolts(data);
> + *val = ads1100_get_voltage_milivolts(data);
> *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config);
> return IIO_VAL_FRACTIONAL_LOG2;
> case IIO_CHAN_INFO_SAMP_FREQ:
> - *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK,
> - data->config)];
> + *val = data->ads_config->data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)];
This line seems a bit long now.
> return IIO_VAL_INT;
> default:
> return -EINVAL;
> @@ -307,6 +339,7 @@ static int ads1100_probe(struct i2c_client *client)
> struct iio_dev *indio_dev;
> struct ads1100_data *data;
> struct device *dev = &client->dev;
> + const struct ads1100_config *model;
> int ret;
>
> indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> @@ -338,6 +371,12 @@ static int ads1100_probe(struct i2c_client *client)
> if (ret)
> return ret;
>
> + model = device_get_match_data(dev);
Should be i2c_get_match_data().
> + if (!model)
> + return dev_err_probe(dev, -EINVAL,
> + "Can't get device data from firmware\n");
> +
> + data->ads_config = (struct ads1100_config *)model;
> ret = ads1100_setup(data);
> if (ret)
> return dev_err_probe(dev, ret,
> @@ -400,16 +439,18 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops,
> NULL);
>
> static const struct i2c_device_id ads1100_id[] = {
> - { "ads1100" },
> - { "ads1000" },
> + { .name = "ads1000", .driver_data = (kernel_ulong_t)&ads1100_config },
> + { .name = "ads1100", .driver_data = (kernel_ulong_t)&ads1100_config },
> + { .name = "ads1110", .driver_data = (kernel_ulong_t)&ads1110_config },
> { }
> };
>
> MODULE_DEVICE_TABLE(i2c, ads1100_id);
>
> static const struct of_device_id ads1100_of_match[] = {
> - {.compatible = "ti,ads1100" },
> - {.compatible = "ti,ads1000" },
> + { .compatible = "ti,ads1000", .data = &ads1100_config },
> + { .compatible = "ti,ads1100", .data = &ads1100_config },
> + { .compatible = "ti,ads1110", .data = &ads1110_config },
> { }
> };
>
^ permalink raw reply
* Re: [PATCH v2] spi: dt-bindings: octeon: Convert to DT schema
From: Rob Herring @ 2026-06-15 22:19 UTC (permalink / raw)
To: Ninad Naik
Cc: broonie, krzk+dt, conor+dt, david.daney, linux-spi, devicetree,
linux-kernel, me, linux-kernel-mentees, skhan
In-Reply-To: <20260613192233.2229933-1-ninadnaik07@gmail.com>
On Sun, Jun 14, 2026 at 12:52:33AM +0530, Ninad Naik wrote:
> Convert octeon-3010 to DT schema
>
> Signed-off-by: Ninad Naik <ninadnaik07@gmail.com>
> ---
> Changes in v2:
> - Change the maintainer from Mark Brown to David Daney.
> - Use soc node wrapper instead of root node in the example to handle
> address-cells and size-cells requirements.
> - Remove interrupt controller provider from the example.
>
> .../bindings/spi/cavium,octeon-3010-spi.yaml | 61 +++++++++++++++++++
> .../devicetree/bindings/spi/spi-octeon.txt | 33 ----------
> 2 files changed, 61 insertions(+), 33 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/spi/cavium,octeon-3010-spi.yaml
> delete mode 100644 Documentation/devicetree/bindings/spi/spi-octeon.txt
>
> diff --git a/Documentation/devicetree/bindings/spi/cavium,octeon-3010-spi.yaml b/Documentation/devicetree/bindings/spi/cavium,octeon-3010-spi.yaml
> new file mode 100644
> index 000000000000..e35e661d0a58
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/spi/cavium,octeon-3010-spi.yaml
> @@ -0,0 +1,61 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/spi/cavium,octeon-3010-spi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cavium, Inc. OCTEON SoC SPI master controller
> +
> +description:
> + The Cavium OCTEON SPI controller is an SPI master controller found in
> + OCTEON SoCs.
> +
> +maintainers:
> + - David Daney <david.daney@cavium.com>
David doesn't seem to be active and I'm pretty sure this email doesn't
work any more. Just put me if there is no one else.
Rob
^ permalink raw reply
* Re: [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties
From: Dmitry Baryshkov @ 2026-06-15 22:15 UTC (permalink / raw)
To: Daniel Lezcano
Cc: Gaurav Kohli, Krzysztof Kozlowski, Bjorn Andersson,
Mathieu Poirier, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Amit Kucheria, Manivannan Sadhasivam, Konrad Dybcio, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers, linux-arm-msm,
linux-remoteproc, devicetree, linux-kernel, linux-pm,
linux-hardening, Manaf Meethalavalappu Pallikunhi
In-Reply-To: <dcdfe9f4-aeec-4d85-92a1-a42592fe11c8@oss.qualcomm.com>
On Mon, Jun 15, 2026 at 05:33:15PM +0200, Daniel Lezcano wrote:
>
>
> Le 15/06/2026 à 17:14, Dmitry Baryshkov a écrit :
> > On Mon, Jun 15, 2026 at 04:33:38PM +0200, Daniel Lezcano wrote:
> > >
> > >
> > > Le 15/06/2026 à 16:11, Dmitry Baryshkov a écrit :
> > > > On Mon, Jun 15, 2026 at 02:30:49PM +0200, Daniel Lezcano wrote:
> > > > > Hi Gaurav,
> > > > >
> > > > > Le 15/06/2026 à 14:12, Gaurav Kohli a écrit :
> > > > > >
> > > > > >
> > > > > > On 6/15/2026 4:04 PM, Daniel Lezcano wrote:
> > > > > > > On 6/13/26 13:05, Gaurav Kohli wrote:
> > > > > > > >
> > > > > > > >
> > > > > > > > On 6/13/2026 1:11 PM, Krzysztof Kozlowski wrote:
> > > > > > > > > On 12/06/2026 15:52, Gaurav Kohli wrote:
> > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > On 6/11/2026 5:53 PM, Krzysztof Kozlowski wrote:
> > > > > > > > > > > On 11/06/2026 13:12, Gaurav Kohli wrote:
> > > > > > > > > > > > > Why? And where is this generic property defined? You cannot just
> > > > > > > > > > > > > sprinkle generic properties in random bindings.
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Ack, will add why part.
> > > > > > > > > > > > These names are matched with the thermal
> > > > > > > > > > > > mitigation device identifiers
> > > > > > > > > > > > populated by remote firmware over QMI and define
> > > > > > > > > > > > mitigation devices are
> > > > > > > > > > > > exposed as cooling devices.
> > > > > > > > > > >
> > > > > > > > > > > No, -names correspond to values passed via DT, not
> > > > > > > > > > > some remote firmware.
> > > > > > > > > > > The remote firmware should give you interface which
> > > > > > > > > > > is explicit and does
> > > > > > > > > > > not need such properties.
> > > > > > > > > >
> > > > > > > > > > thanks Krzysztof for review, We need tmd-names because
> > > > > > > > > > of following reasons:
> > > > > > > > > >
> > > > > > > > > > Following Daniel's series [1], the thermal framework supports
> > > > > > > > > > mapping multiple cooling devices per remoteproc/device via indexed
> > > > > > > > > > cooling-cells.
> > > > > > > > > >
> > > > > > > > > > 1) The thermal framework's cooling-maps reference
> > > > > > > > > > cooling devices by index (for #cooling-cells = <3>).
> > > > > > > > > > Without tmd- names,
> > > > > > > > > > there's no way to know which index corresponds to which
> > > > > > > > > > TMD, as firmware
> > > > > > > > > > may return tmd-names in any order.
> > > > > > > > > >
> > > > > > > > > > below are the changes post new thermal mapping changes:
> > > > > > > > > > DT: tmd-names = "cdsp_sw", "xyz";
> > > > > > > > > > Firmware: ["cdsp_sw", "xyz1", "xyz2",]
> > > > > > > > > > Driver registers: Only "cdsp_sw" (index 0) and "xyz" (index 1)
> > > > > > > > >
> > > > > > > > > names property are not to instruct drivers to register or not to
> > > > > > > > > register something.
> > > > > > > > >
> > > > > > > > > I don't understand the problem and explanation in the binding is
> > > > > > > > > basically non-existing.
> > > > > > > > >
> > > > > > > > > Remember that all lists and indices ARE FIXED, so driver knows exactly
> > > > > > > > > which index means what.
> > > > > > > > >
> > > > > > > >
> > > > > > > > thanks for review, shall i use driver data, which is basically
> > > > > > > > pas data structure like below:
> > > > > > > >
> > > > > > > > static const struct qcom_pas_data {
> > > > > > > > .crash_reason_smem = 601,
> > > > > > > > .firmware_name = "cdsp.mdt",
> > > > > > > > .tmd_names = (const char *[]){"xyz", NULL},
> > > > > > > > .num_tmds = 1,
> > > > > > > >
> > > > > > > > Is something like above acceptable? and this will also help to
> > > > > > > > filter tmd names as well?
> > > > > > >
> > > > > > >
> > > > > > > How the thermal framework will bind the thermal zone with the TMD ?
> > > > > > > (node pointer, id) ?
> > > > > > >
> > > > > >
> > > > > > Hi Daniel,
> > > > > >
> > > > > > thanks for review.
> > > > > >
> > > > > > With id only, in this case instead of taking tmd names from device tree,
> > > > > > qmi_tmd will take tmd name from pas_data(driver) and register with the
> > > > > > cooling framework with id only. Please let us know if this looks fine.
> > > > > May be I'm missing something but:
> > > > >
> > > > > - The QMI TMD returns a list of names, not ids
> > > > > - The QMI TMD may return the list in different order than assumed
> > > > > - The cooling map index points to the name of the TMD in the DT
> > > > > - This name is used to match the name in the aformentionned list
> > > > > - The index in the list and the id in the DT can differ
> > > >
> > > > Would it be better if we define standard indices for the standard names?
> > > > This way we decouple the actual firmware strings from the DT.
> > >
> > > I don't think so, it seems to me too fragile and prone to error.
> > >
> > > It is a remote proc, an external subsystem. The contract between the client
> > > and the server is the protocol. The protocol specifies the identifier as
> > > named strings, the TMD names, not numerical identifiers.
> > >
> > > When asking for the list of TMDs, we get a list of strings. But as it is an
> > > external subsystems, may be tomorrow someone decide to send list ordered
> > > alphabetically, or per number of states, or whatever.
> > >
> > > With hardcoded id the QMI TMD clients break
> >
> > I was thinking about something like:
> >
> > #define QCOM_TMD_DSP 0
> > #define QCOM_TMD_PA 1
>
> Ah ok, it is correct if:
>
> tmd-names = "dsp", "pa"
>
> Or
>
> #define QCOM_TMD_PA 0
> #define QCOM_TMD_DSP 1
>
> tmd-names = "pa", "dsp"
I was more inclined about having the standard indices for the standard
mitigations.
BTW, I checked, which mitigations are being returned by the DSPs. Few
examples, just to provide some context.
SC8280XP, X13s:
TMD service: instance=0x01 (adsp) node=5 port=9
1 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
TMD service: instance=0x53 (slpi) node=9 port=9
1 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
TMD service: instance=0x43 (cdsp) node=10 port=8
3 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
[ 1] cdsp_hw max_mitigation_level=1
[ 2] cdsp_sw max_mitigation_level=7
SM6115, RB2:
TMD service: instance=0x00 (modem) node=0 port=20
9 mitigation device(s):
[ 0] pa max_mitigation_level=3
[ 1] modem max_mitigation_level=3
[ 2] cpuv_restriction_cold max_mitigation_level=1
[ 3] modem_current max_mitigation_level=3
[ 4] vbatt_low max_mitigation_level=3
[ 5] modem_skin max_mitigation_level=3
[ 6] modem_bw max_mitigation_level=5
[ 7] wlan max_mitigation_level=1
[ 8] wlan_bw max_mitigation_level=1
TMD service: instance=0x01 (adsp) node=5 port=8
1 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
TMD service: instance=0x43 (cdsp) node=10 port=8
3 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
[ 1] cdsp_hw max_mitigation_level=1
[ 2] cdsp_sw max_mitigation_level=5
SM8350, HDK:
TMD service: instance=0x00 (modem) node=0 port=22
28 mitigation device(s):
[ 0] pa max_mitigation_level=3
[ 1] pa_fr1 max_mitigation_level=3
[ 2] modem max_mitigation_level=3
[ 3] cpuv_restriction_cold max_mitigation_level=1
[ 4] modem_current max_mitigation_level=3
[ 5] vbatt_low max_mitigation_level=3
[ 6] charge_state max_mitigation_level=3
[ 7] modem_skin max_mitigation_level=3
[ 8] modem_bw max_mitigation_level=5
[ 9] mmw0 max_mitigation_level=3
[10] mmw1 max_mitigation_level=3
[11] mmw2 max_mitigation_level=3
[12] mmw3 max_mitigation_level=3
[13] mmw_skin0 max_mitigation_level=3
[14] mmw_skin1 max_mitigation_level=3
[15] mmw_skin2 max_mitigation_level=3
[16] mmw_skin3 max_mitigation_level=3
[17] mmw_skin0_dsc max_mitigation_level=15
[18] mmw_skin1_dsc max_mitigation_level=15
[19] mmw_skin2_dsc max_mitigation_level=15
[20] mmw_skin3_dsc max_mitigation_level=15
[21] wlan max_mitigation_level=4
[22] wlan_bw max_mitigation_level=1
[23] modem_skin_lte_dsc max_mitigation_level=255
[24] modem_skin_nr_dsc max_mitigation_level=255
[25] pa_dsc max_mitigation_level=255
[26] pa_fr1_dsc max_mitigation_level=255
[27] cpr_cold max_mitigation_level=3
TMD service: instance=0x01 (adsp) node=5 port=9
1 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
TMD service: instance=0x43 (cdsp) node=10 port=9
3 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
[ 1] cdsp_hw max_mitigation_level=1
[ 2] cdsp_sw max_mitigation_level=7
SM8150, HDK:
TMD service: instance=0x00 (modem) node=0 port=21
6 mitigation device(s):
[ 0] pa max_mitigation_level=3
[ 1] modem max_mitigation_level=3
[ 2] cpuv_restriction_cold max_mitigation_level=1
[ 3] modem_current max_mitigation_level=3
[ 4] vbatt_low max_mitigation_level=3
[ 5] modem_skin max_mitigation_level=3
TMD service: instance=0x01 node=5 port=8
1 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
TMD service: instance=0x53 node=9 port=8
1 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
TMD service: instance=0x43 (cdsp) node=10 port=8
1 mitigation device(s):
[ 0] cpuv_restriction_cold max_mitigation_level=1
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH v4 06/31] dt-bindings: firmware: arm,scmi: Add support for telemetry protocol
From: Rob Herring (Arm) @ 2026-06-15 22:14 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-doc, Conor Dooley, puranjay, usama.arif, philip.radford,
devicetree, souvik.chakravarty, linux-kernel, jic23, elif.topuz,
lukasz.luba, sudeep.holla, leitao, vincent.guittot, james.quinlan,
kernel-team, linux-arm-kernel, kas, arm-scmi, peng.fan,
linux-fsdevel, michal.simek, brauner, etienne.carriere, d-gole,
Krzysztof Kozlowski, f.fainelli
In-Reply-To: <20260612223802.1337232-7-cristian.marussi@arm.com>
On Fri, 12 Jun 2026 23:37:36 +0100, Cristian Marussi wrote:
> Add new SCMI v4.0 Telemetry protocol bindings definitions.
>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> v3 --> v4
> - changed protocol number to lowercase 1b
> - fixed misplaced block for protocol 0x1b
>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> ---
> Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 3/4] iio: adc: ti-ads112c14: implement gain on internal short SYS_MON channel
From: sashiko-bot @ 2026-06-15 22:14 UTC (permalink / raw)
Cc: robh, conor+dt, devicetree
In-Reply-To: <20260615-iio-adc-ti-ads122c14-v1-3-e6bdadf7cb2b@baylibre.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The `write_raw` and `read_avail` IIO callbacks completely ignore the `long mask` argument.
- [Medium] Data race when reading `sys_mon_chan_short_gain_val` without locking or READ_ONCE().
--
commit 7a8163396f906f80891d134c7fb8faa25cc0a10a
Author: David Lechner (TI) <dlechner@baylibre.com>
iio: adc: ti-ads112c14: implement gain on internal short SYS_MON channel
Implement support for the programmable gain amplifier on the internal
short SYS_MON channel. This channel is used for calibration, so it is
useful to be able to set the PGA to the same gain as the external
channels. The gain setting is implemented via the _scale attribute.
> diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c
> index 97097ae2a4872..202a449b4234f 100644
> --- a/drivers/iio/adc/ti-ads112c14.c
> +++ b/drivers/iio/adc/ti-ads112c14.c
[ ... ]
> @@ -366,6 +395,17 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
> return IIO_VAL_FRACTIONAL_LOG2;
> }
>
> + if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) {
> + int *scale_avail = data->sys_mon_chan_short_scale_available[
> + data->sys_mon_chan_short_gain_val
> + ];
[Severity: Medium]
Is there a potential data race when reading data->sys_mon_chan_short_gain_val
here?
This value is modified in ads112c14_write_raw() while holding the direct mode
lock, but it appears to be read here without locking or READ_ONCE(). Could a
concurrent sysfs write cause an issue while looking up the scale available
array?
> +
> + *val = scale_avail[0];
> + *val2 = scale_avail[1];
> +
> + return IIO_VAL_INT_PLUS_NANO;
> + }
> +
> *val = vref_uV / (MICRO / MILLI);
> /*
> * Last 3 SYS_MON channels (ext ref, AVDD, DVDD) need to be
> @@ -387,6 +427,61 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
> }
> }
>
> +static int ads112c14_read_avail(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan, const int **vals,
> + int *type, int *length, long mask)
> +{
> + struct ads112c14_data *data = iio_priv(indio_dev);
> +
> + switch (chan->channel) {
> + case ADS112C14_SYS_MON_CHANNEL_SHORT:
> + *vals = (const int *)data->sys_mon_chan_short_scale_available;
> + *length = 2 * ARRAY_SIZE(data->sys_mon_chan_short_scale_available);
> + *type = IIO_VAL_INT_PLUS_NANO;
> + return IIO_AVAIL_LIST;
[Severity: High]
Does this function need to check the mask parameter?
Currently, it returns the scale availability array unconditionally. If other
_available attributes are queried, this might incorrectly return scale data
for those non-scale queries.
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int ads112c14_write_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int val,
> + int val2, long mask)
> +{
> + struct ads112c14_data *data = iio_priv(indio_dev);
> +
> + switch (chan->channel) {
> + case ADS112C14_SYS_MON_CHANNEL_SHORT: {
> + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
> + if (IIO_DEV_ACQUIRE_FAILED(claim))
> + return -EBUSY;
[Severity: High]
Should this function also verify that mask == IIO_CHAN_INFO_SCALE?
Since there is no mask check, if the IIO core creates a writable _raw
attribute, any writes to it might be incorrectly interpreted as scale updates.
> +
> + for (u32 i = 0; i < ARRAY_SIZE(data->sys_mon_chan_short_scale_available); i++) {
> + if (val == data->sys_mon_chan_short_scale_available[i][0] &&
> + val2 == data->sys_mon_chan_short_scale_available[i][1]) {
> + data->sys_mon_chan_short_gain_val = i;
> + return 0;
> + }
> + }
> + return -EINVAL;
> + }
> + default:
> + return -EINVAL;
> + }
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-iio-adc-ti-ads122c14-v1-0-e6bdadf7cb2b@baylibre.com?part=3
^ permalink raw reply
* Re: [PATCH 4/4] iio: adc: ti-ads112c14: add measurement channel support
From: sashiko-bot @ 2026-06-15 22:13 UTC (permalink / raw)
Cc: robh, conor+dt, devicetree
In-Reply-To: <20260615-iio-adc-ti-ads122c14-v1-4-e6bdadf7cb2b@baylibre.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
New issues:
- [Critical] Heap buffer overflow in `ads112c14_populate_tables` due to incorrectly incremented `data->num_measurements`.
- [High] Incorrect error check for `devm_regulator_get_enable_read_voltage` causes valid probe successes to fail.
- [High] Uninitialized variable dereference in `ads112c14_read_raw()` for system monitor channels.
- [High] Integer overflow in `ads112c14_populate_scale_available()` breaks scaling factor calculation on 32-bit platforms.
Pre-existing issues:
- [High] Probe exits early and silently fails to register the IIO device if the reset command succeeds.
- [High] Short reads from I2C block reads leak uninitialized stack memory.
--
commit 6b05c003c593f091ad7d3f52a3dc20d0fab7fc26
Author: David Lechner (TI) <dlechner@baylibre.com>
iio: adc: ti-ads112c14: add measurement channel support
This patch adds support for parsing devicetree properties to dynamically
create measurement channels. It also adds the required algorithms and state
to do direct reads on these channels.
> diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c
> index 202a449b4234f..d1297445025f7 100644
> --- a/drivers/iio/adc/ti-ads112c14.c
> +++ b/drivers/iio/adc/ti-ads112c14.c
[ ... ]
> @@ -383,7 +512,8 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
> return -EINVAL;
> }
[Severity: High]
This isn't a bug introduced by this patch, but can a short read from
ads112c14_single_conversion() leak uninitialized stack memory?
If i2c_smbus_read_i2c_block_data() returns fewer bytes than requested
(e.g., 1 instead of 3), the return value is a positive integer. The check
`if (ret < 0)` earlier in ads112c14_read_raw() passes, and extracting the
value will read uninitialized bytes from the stack-allocated buffer.
>
> - *val = sign_extend32(*val, fsr_bits);
> + if (!measurement || measurement->bipolar)
[Severity: High]
Can `measurement` be uninitialized when dereferenced here?
If the requested channel is a system monitor channel (`chan->channel >= 100`),
the `measurement` pointer is left uninitialized at the start of
ads112c14_read_raw(). It is then evaluated in this condition, which could
lead to undefined behavior.
> + *val = sign_extend32(*val, fsr_bits);
>
> return IIO_VAL_INT;
> }
[ ... ]
> @@ -519,26 +687,187 @@ static const struct iio_info ads112c14_info = {
> .read_label = ads112c14_read_label,
> };
>
> +static int ads112c14_parse_channels(struct iio_dev *indio_dev,
> + bool *need_avdd_ref, bool *need_ext_ref)
> +{
[ ... ]
> + data->num_measurements = device_get_named_child_node_count(dev, "channel");
> +
> + data->measurements = devm_kcalloc(dev, data->num_measurements,
> + sizeof(*data->measurements), GFP_KERNEL);
> + if (!data->measurements)
> + return -ENOMEM;
> +
> + data->num_measurements += ARRAY_SIZE(ads112c14_sys_mon_channels);
[Severity: Critical]
Does this incorrectly inflate the measurement count?
By incrementing `data->num_measurements` by the size of the system monitor
channels here, the boundary for the measurements array becomes too large.
Later in ads112c14_populate_tables(), looping over `data->num_measurements`
will access `data->measurements` out-of-bounds, potentially corrupting
adjacent heap memory.
> +
> + channels = devm_kcalloc(dev, data->num_measurements +
> + ARRAY_SIZE(ads112c14_sys_mon_channels),
> + sizeof(*channels), GFP_KERNEL);
[ ... ]
> +static void ads112c14_populate_scale_available(int scale_avail[][2],
> + u32 vref_uV, u32 fsr_bits)
> +{
> + for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) {
> + int *entry = scale_avail[i];
> + u32 gain_x10 = ads112c14_pga_gains_x10[i];
> +
> + entry[0] = div_u64_rem(div64_u64((u64)(NANO * 10 /
> + (MICRO / MILLI)) * vref_uV,
[Severity: High]
Does this calculation overflow on 32-bit platforms?
`NANO` is defined as a 32-bit unsigned long, so multiplying it by 10 overflows
before the cast to `u64`. This truncates the value used to compute the scale
factor, leading to incorrect scaling values on 32-bit architectures.
> + (u64)gain_x10 * BIT(fsr_bits)),
> + NANO, &entry[1]);
> + }
> +}
> +
> static void ads112c14_populate_tables(struct ads112c14_data *data)
> {
> u32 vref_uV, fsr_bits;
> - int i;
> +
> + for (u32 i = 0; i < data->num_measurements; i++) {
> + struct ads112c14_measurement *measurement = &data->measurements[i];
[Severity: Critical]
Does this loop cause an out-of-bounds access?
Because `data->num_measurements` was artificially inflated in
ads112c14_parse_channels(), this loop goes past the allocated elements for
`data->measurements`. Writing to `measurement->scale_available` further down
in the loop will result in a heap buffer overflow.
[ ... ]
> @@ -560,13 +892,75 @@ static int ads112c14_probe(struct i2c_client *client)
> data->chip_info = info;
> data->client = client;
>
> + ret = ads112c14_parse_channels(indio_dev, &need_avdd_ref, &need_ext_ref);
> + if (ret)
> + return ret;
> +
> ret = devm_regulator_get_enable(&client->dev, "dvdd");
> if (ret)
> return dev_err_probe(dev, ret, "failed to get dvdd regulator\n");
>
> - ret = devm_regulator_get_enable(&client->dev, "avdd");
> - if (ret)
> - return dev_err_probe(dev, ret, "failed to get avdd regulator\n");
> + if (need_avdd_ref) {
> + ret = devm_regulator_get_enable_read_voltage(&client->dev, "avdd");
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to get avdd voltage\n");
[Severity: High]
Does this incorrectly fail on success?
`devm_regulator_get_enable_read_voltage()` returns the voltage in microvolts on
success, which is a positive integer. Checking `if (ret)` will evaluate to true
and abort the probe when the voltage is successfully read. This same pattern
appears below for the 'refp' and 'refn' regulators.
[ ... ]
> data->regmap = devm_regmap_init_i2c(client, &ads112c14_regmap_config);
> if (IS_ERR(data->regmap))
[Severity: High]
This isn't a bug introduced by this patch, but does the probe fail to
register the device if the reset command succeeds?
Just below this context, during probe, a software reset is sent via
regmap_write() and the return value is checked with:
if (ret != -EREMOTEIO)
return ret;
If the device acknowledges the write and regmap_write() successfully returns 0,
the check evaluates to true (`0 != -EREMOTEIO`), causing the driver to
prematurely return 0 without ever calling devm_iio_device_register(), leaving
the device entirely unusable.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-iio-adc-ti-ads122c14-v1-0-e6bdadf7cb2b@baylibre.com?part=4
^ permalink raw reply
* Re: [PATCH 2/4] iio: adc: add ti-ads112c14 driver
From: sashiko-bot @ 2026-06-15 22:11 UTC (permalink / raw)
Cc: robh, conor+dt, devicetree
In-Reply-To: <20260615-iio-adc-ti-ads122c14-v1-2-e6bdadf7cb2b@baylibre.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Incorrect error checking and status validation in `ads112c14_probe` causes the driver to always fail probing or exit early.
- [High] The polling timeout for data readiness is significantly shorter than the minimum conversion time, causing all reads to fail.
- [High] Short reads from the I2C block transfer cause uninitialized kernel stack memory to be exposed to userspace.
- [Medium] Setting the `CONV_MODE` bit places the device in continuous mode instead of the intended single-shot mode.
- [Low] The driver uses floating-point literals, which is prohibited in the kernel.
--
commit cac55fa736d39d53faf1e07aa41f7aa5d0909c7f
Author: David Lechner (TI) <dlechner@baylibre.com>
Subject: iio: adc: add ti-ads112c14 driver
Adds a basic driver for TI ADS112C14/ADS122C14 ADC chips supporting
power on/reset and system monitor channels.
diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c
new file mode 100644
index 0000000000000..97097ae2a4872
--- /dev/null
+++ b/drivers/iio/adc/ti-ads112c14.c
[ ... ]
> +struct ads112c14_data {
> + const struct ads112c14_chip_info *chip_info;
> + struct i2c_client *client;
> + struct regmap *regmap;
> +};
> +
> +/* Maps REF_VAL to microvolts. */
> +static const u32 ads112c14_internal_ref_uV[] = {
> + [ADS112C14_REFERENCE_CFG_REF_VAL_1_25V] = 1.25 * MICRO,
> + [ADS112C14_REFERENCE_CFG_REF_VAL_2_5V] = 2.5 * MICRO,
> +};
[Severity: Low]
Does this use floating-point literals which are prohibited in the kernel?
The kernel environment does not support floating-point arithmetic, so
using 1.25 and 2.5 could cause compilation errors or link failures on
architectures without a hardware FPU. Could integer arithmetic be used
instead, such as 1250000?
[ ... ]
> +static int ads112c14_single_conversion(struct ads112c14_data *data,
> + const struct iio_chan_spec *chan,
> + u8 *buf)
> +{
> + u32 reg_val;
> + int ret;
[ ... ]
> + ret = regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL,
> + ADS112C14_CONVERSION_CTRL_START);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read_poll_timeout(data->regmap,
> + ADS112C14_REG_STATUS_MSB, reg_val,
> + FIELD_GET(ADS112C14_STATUS_MSB_DRDY, reg_val),
> + 1 * USEC_PER_MSEC, 10 * USEC_PER_MSEC);
[Severity: High]
Is the 10ms timeout duration here long enough?
The ADC's data rate is left at its default value representing 20 SPS,
which means a single conversion would take approximately 50ms. Because
the maximum timeout here is 10ms, won't every read attempt timeout and
fail with -ETIMEDOUT before the DRDY bit can be set?
> + if (ret)
> + return ret;
> +
> + return i2c_smbus_read_i2c_block_data(data->client, ADS112C14_CMD_RDATA,
> + BITS_TO_BYTES(data->chip_info->resolution_bits),
> + buf);
> +}
> +
> +static int ads112c14_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + struct ads112c14_data *data = iio_priv(indio_dev);
> + u32 vref_uV, fsr_bits;
> +
> + /* Selecting V_REF source is not implemented yet. */
> + vref_uV = ads112c14_internal_ref_uV[ADS112C14_REFERENCE_CFG_REF_VAL_2_5V];
> +
> + /* Currently, everything is using signed data. */
> + fsr_bits = data->chip_info->resolution_bits - 1;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW: {
> + u8 buf[3];
> + int ret;
> +
> + if (!iio_device_claim_direct(indio_dev))
> + return -EBUSY;
> +
> + ret = ads112c14_single_conversion(data, chan, buf);
> + iio_device_release_direct(indio_dev);
> + if (ret < 0)
> + return ret;
> +
> + switch (data->chip_info->resolution_bits) {
> + case 16:
> + *val = get_unaligned_be16(buf);
[Severity: High]
Can this lead to uninitialized kernel stack memory being leaked to userspace?
In ads112c14_single_conversion(), i2c_smbus_read_i2c_block_data() returns
the number of bytes successfully read. If a short read occurs (e.g., it
returns 1 byte), ret will be a positive value.
Since the check here only looks for ret < 0, it treats a short read as a
success. This would cause the code to parse the partially uninitialized buf
array using get_unaligned_be16() or get_unaligned_be24(), exposing
uninitialized stack data.
Should this check verify that the expected number of bytes were actually
read?
[ ... ]
> +static int ads112c14_probe(struct i2c_client *client)
> +{
> + struct device *dev = &client->dev;
> + const struct ads112c14_chip_info *info;
> + struct iio_dev *indio_dev;
> + struct ads112c14_data *data;
> + u32 reg_val;
> + int ret;
[ ... ]
> + /* Write magic reset value (0x16) to ensure known state.*/
> + ret = regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL,
> + FIELD_PREP(ADS112C14_CONVERSION_CTRL_RESET, 0x16));
> + /*
> + * The reset may cause an -EREMOTEIO error because of failing to get the
> + * I2C ACK at the end of the message. The device still gets reset.
> + */
> + if (ret != -EREMOTEIO)
> + return ret;
[Severity: High]
Will this logic cause the probe to exit early with success instead of
continuing?
If the regmap_write() successfully resets the device, it returns 0. The
condition (0 != -EREMOTEIO) evaluates to true, causing the driver to
immediately return 0 and incorrectly skip the rest of the device registration
entirely.
> +
> + fsleep(ADS112C14_DELAY_RESET_us);
> +
> + ret = regmap_read(data->regmap, ADS112C14_REG_STATUS_MSB, ®_val);
> + if (ret)
> + return ret;
> +
> + if (FIELD_GET(ADS112C14_STATUS_MSB_RESETN, reg_val))
> + return dev_err_probe(dev, -EIO, "reset failed\n");
[Severity: High]
Is this reset status check inverted?
The ADS112C14_STATUS_MSB_RESETN bit is set to 1 upon a successful power-on
reset, which is corroborated by the subsequent comment mentioning clearing
the reset bit. If the reset is successful, this check will actively fail
the probe with -EIO.
> +
> + /*
> + * Clear reset bit to prepare for next probe. And clear AVDD fault since
> + * that happens on every reset.
> + */
> + ret = regmap_write(data->regmap, ADS112C14_REG_STATUS_MSB,
> + ADS112C14_STATUS_MSB_RESETN |
> + ADS112C14_STATUS_MSB_AVDD_UVN);
> + if (ret)
> + return ret;
> +
> + /* Place in single-shot conversion mode to make ready for raw read. */
> + ret = regmap_set_bits(data->regmap, ADS112C14_REG_DEVICE_CFG,
> + ADS112C14_DEVICE_CFG_CONV_MODE);
[Severity: Medium]
Does this configure the device for continuous conversion mode rather than
single-shot?
The comment notes the intention to place the device in single-shot
conversion mode, but setting the ADS112C14_DEVICE_CFG_CONV_MODE bit to 1
enables continuous mode instead. The default register value of 0 is
single-shot mode.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-iio-adc-ti-ads122c14-v1-0-e6bdadf7cb2b@baylibre.com?part=2
^ permalink raw reply
* Re: [PATCH 1/4] dt-bindings: iio: adc: add ti,ads122c14
From: sashiko-bot @ 2026-06-15 22:10 UTC (permalink / raw)
Cc: robh, devicetree, conor+dt
In-Reply-To: <20260615-iio-adc-ti-ads122c14-v1-1-e6bdadf7cb2b@baylibre.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] Invalid schema constraint applied directly to an array property (`reg`) in the child nodes, and it contradicts the `patternProperties` regex.
- [Low] Mismatched and inflexible constraints between `interrupts` and `interrupt-names`.
--
commit 73a67f643701ff236b57cf5c513f2db2525ad034
Author: David Lechner (TI) <dlechner@baylibre.com>
dt-bindings: iio: adc: add ti,ads122c14
This commit adds new bindings for the Texas Instruments ADS122C14 and similar
ADC chips. The devices are primarily intended for temperature sensors, and the
bindings include channel-specific reference voltage and current output
properties.
> diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads112c14.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads112c14.yaml
> new file mode 100644
> index 0000000000000..dc7f37cad7721
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads112c14.yaml
[ ... ]
> + interrupts:
> + minItems: 1
> + items:
> + - description: FAULT interrupt (GPIO2 pin)
> + - description: DRDY interrupt (GPIO3 pin)
> +
> + interrupt-names:
> + minItems: 1
> + maxItems: 2
> + items:
> + enum: [fault, drdy]
[Severity: Low]
Is it possible that this unordered enum for interrupt-names allows mismatched
arrays like [drdy, fault] to pass validation without enforcing order?
Also, the interrupts array strictly defines index 0 as FAULT and index 1 as
DRDY. If a board only wires up the DRDY interrupt, would it be forced to place
it at index 0 of the interrupts array, contradicting the description here?
Could this be improved by defining valid combinations using oneOf blocks with
exact items arrays for both interrupts and interrupt-names?
[ ... ]
> +patternProperties:
> + ^channel@[0-7]$:
> + $ref: adc.yaml
> +
> + unevaluatedProperties: false
> +
> + properties:
> + reg:
> + maximum: 16 # arbitrary limit, channel@ can be any combination of AIN0-AIN7
[Severity: Low]
Since the reg property is an array in device tree schemas, will applying the
JSON Schema maximum keyword directly to it be ignored by standard validators?
Should it define the maximum limit under an items list instead, similar to how
other array constraints are specified?
Additionally, does a limit of 16 contradict the regex ^channel@[0-7]$ on the
pattern properties node? The regex restricts the unit address to 0-7, which
prevents any reg value of 8 or higher from matching, rendering the maximum of
16 logically unreachable.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-iio-adc-ti-ads122c14-v1-0-e6bdadf7cb2b@baylibre.com?part=1
^ permalink raw reply
* Re: [PATCH v3 1/3] dt-bindings: iio: adc: ti,ads1100: add support for ADS1110
From: David Lechner @ 2026-06-15 22:07 UTC (permalink / raw)
To: Jakub Szczudlo, linux-iio
Cc: andy, antoniu.miclaus, conor+dt, devicetree, duje, jic23,
jishnu.prakash, jorge.marques, krzk+dt, linusw, linux-kernel,
marcelo.schmitt, mazziesaccount, mike.looijmans, nuno.sa, robh,
sakari.ailus, wens, joshua.crofts1
In-Reply-To: <20260613190957.654798-2-jakubszczudlo40@gmail.com>
On 6/13/26 2:09 PM, Jakub Szczudlo wrote:
> Register layouts are the same as for ADS1100 but ADS1110 have different
> datarates and have internal voltage reference that is always 2.048V
If we do a v4, would be nice to mention here that fixing the order
of ti,ads1100 was intentional while we are touching this.
>
> Signed-off-by: Jakub Szczudlo <jakubszczudlo40@gmail.com>
> ---
> .../devicetree/bindings/iio/adc/ti,ads1100.yaml | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml
> index 970ccab15e1e..28c5e2dd0ad6 100644
> --- a/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml
> +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml
> @@ -4,19 +4,23 @@
> $id: http://devicetree.org/schemas/iio/adc/ti,ads1100.yaml#
> $schema: http://devicetree.org/meta-schemas/core.yaml#
>
> -title: TI ADS1100/ADS1000 single channel I2C analog to digital converter
> +title: TI ADS1100 and similar single channel I2C Analog to Digital Converters
>
> maintainers:
> - Mike Looijmans <mike.looijmans@topic.nl>
>
> description: |
> - Datasheet at: https://www.ti.com/lit/gpn/ads1100
> + Datasheets:
> + - https://www.ti.com/lit/gpn/ads1000
> + - https://www.ti.com/lit/gpn/ads1100
> + - https://www.ti.com/lit/gpn/ads1110
>
> properties:
> compatible:
> enum:
> - - ti,ads1100
> - ti,ads1000
> + - ti,ads1100
> + - ti,ads1110
>
> reg:
> maxItems: 1
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: Add GPIO-locked fixed clock
From: Brian Masney @ 2026-06-15 22:01 UTC (permalink / raw)
To: V.Yurkov.EXT
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-kernel, linux-clk, devicetree,
Vyacheslav Yurkov
In-Reply-To: <20260603-feature-clock-guard-v3-1-01cca0aa04a5@bruker.com>
Hi Vyacheslav,
On Wed, Jun 03, 2026 at 11:16:42AM +0000, Vyacheslav Yurkov via B4 Relay wrote:
> From: Vyacheslav Yurkov <V.Yurkov.EXT@bruker.com>
>
> Some hardware designs provide fixed-frequency clocks generated outside
> software control, such as by FPGA-resident PLLs. While the clock rate is
> fixed, a separate GPIO signal indicates whether the clock source is
> locked and producing a valid output.
>
> Describe a GPIO-locked fixed clock provider that exposes a fixed-rate
> clock whose availability depends on one or more GPIO lock-status
> signals.
>
> Signed-off-by: Vyacheslav Yurkov <uvv.mail@gmail.com>
> Signed-off-by: Vyacheslav Yurkov <V.Yurkov.EXT@bruker.com>
> ---
> .../bindings/clock/gpio-locked-fixed-clock.yaml | 70 ++++++++++++++++++++++
> 1 file changed, 70 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/clock/gpio-locked-fixed-clock.yaml b/Documentation/devicetree/bindings/clock/gpio-locked-fixed-clock.yaml
> new file mode 100644
> index 000000000000..9106b800b673
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/gpio-locked-fixed-clock.yaml
> @@ -0,0 +1,70 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/gpio-locked-fixed-clock.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: GPIO Locked Fixed Clock
> +
> +maintainers:
> + - Vyacheslav Yurkov <V.Yurkov.EXT@bruker.com>
> +
> +description: |
> + Provides a clock output whose availability depends on a set of
> + prerequisite conditions. These conditions include the presence of
> + one or more parent clocks and the asserted state of one or more
> + GPIO lock indicators. An example of such clocks is FPGA clock that
> + are outside CPU control, with the lock status exposed through GPIO
> + signal.
> +
> + The output clock is considered available only when all configured
> + prerequisites are satisfied.
I'm stepping outside my usual review of just the clk drivers. Krzysztof
in v1 and v2 asked for more detailed hardware explanation. This feels to
me like this is a policy that says to not use these clocks until the
GPIO says they are ready. My gut feeling is that details like this
should live in a clk driver instead of a dt-binding.
Alternatively, if this is generic enough, then could
Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml be
extended?
Brian
> +
> +properties:
> + compatible:
> + const: gpio-locked-fixed-clock
> +
> + "#clock-cells":
> + const: 0
> +
> + clocks:
> + description: Input clocks whose validity is monitored by this provider.
> +
> + clock-output-names:
> + description: Names of the clock provided by this controller.
> + maxItems: 1
> +
> + locked-gpios:
> + description: |
> + GPIOs to check the lock state.
> + minItems: 1
> + maxItems: 32
> +
> +required:
> + - compatible
> + - "#clock-cells"
> +
> +anyOf:
> + - required:
> + - clocks
> + - required:
> + - locked-gpios
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> +
> + clk_gpio_locked: gpio-locked-fixed-clock {
> + compatible = "gpio-locked-fixed-clock";
> + #clock-cells = <0>;
> +
> + clocks = <&clk0 0>, <&pll 0>;
> +
> + locked-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>,
> + <&gpio0 5 GPIO_ACTIVE_HIGH>,
> + <&gpio1 2 GPIO_ACTIVE_LOW>;
> +
> + clock-output-names = "clkout0";
> + };
>
> --
> 2.34.1
>
>
^ permalink raw reply
* [PATCH 4/4] iio: adc: ti-ads112c14: add measurement channel support
From: David Lechner (TI) @ 2026-06-15 22:00 UTC (permalink / raw)
To: Jonathan Cameron, Nuno Sá, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: Kurt Borja, Nguyen Minh Tien, linux-iio, devicetree, linux-kernel,
David Lechner
In-Reply-To: <20260615-iio-adc-ti-ads122c14-v1-0-e6bdadf7cb2b@baylibre.com>
Add support for parsing devicetree properties for measurement channels
and doing direct reads on these.
There are quite a lot of conditions that have to be met for each
measurement to be made, so quite a bit of state and algorithms are
required to handle it.
Channels are created dynamically since the number of possibilities is
unreasonably large.
Signed-off-by: David Lechner (TI) <dlechner@baylibre.com>
---
drivers/iio/adc/ti-ads112c14.c | 486 +++++++++++++++++++++++++++++++++++++----
1 file changed, 439 insertions(+), 47 deletions(-)
diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c
index 202a449b4234..d1297445025f 100644
--- a/drivers/iio/adc/ti-ads112c14.c
+++ b/drivers/iio/adc/ti-ads112c14.c
@@ -9,8 +9,10 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/dev_printk.h>
+#include <linux/device/devres.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
@@ -26,6 +28,8 @@
#include <linux/unaligned.h>
#include <linux/units.h>
+#include <dt-bindings/iio/adc/ti,ads112c14.h>
+
/* Datasheet t_d(RST) - time to wait after reset before next I2C use. */
#define ADS112C14_DELAY_RESET_us 500
@@ -89,6 +93,9 @@
#define ADS112C14_REFERENCE_CFG_REF_VAL_1_25V 0
#define ADS112C14_REFERENCE_CFG_REF_VAL_2_5V 1
#define ADS112C14_REFERENCE_CFG_REF_SEL GENMASK(1, 0)
+#define ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL 0
+#define ADS112C14_REFERENCE_CFG_REF_SEL_EXTERNAL 1
+#define ADS112C14_REFERENCE_CFG_REF_SEL_AVDD 2
#define ADS112C14_REG_DIGITAL_CFG 0x0A
#define ADS112C14_DIGITAL_CFG_REG_MAP_CRC_EN BIT(6)
@@ -197,10 +204,30 @@ struct ads112c14_chip_info {
u32 resolution_bits;
};
+struct ads112c14_measurement {
+ const char *label;
+ u32 vref_source;
+ u32 idac_current_uA;
+ u8 iadc_count;
+ u8 idac1_mux;
+ u8 idac2_mux;
+ bool current_chop;
+ bool bipolar;
+ u8 gain_val;
+ int scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10)][2];
+};
+
struct ads112c14_data {
const struct ads112c14_chip_info *chip_info;
struct i2c_client *client;
struct regmap *regmap;
+ u32 avdd_uV;
+ u32 ext_ref_uV;
+ bool refp_is_avdd;
+ bool refn_is_gnd;
+ u32 ext_ref_ohms;
+ struct ads112c14_measurement *measurements;
+ u32 num_measurements;
u8 sys_mon_chan_short_gain_val;
int sys_mon_chan_short_scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10)][2];
};
@@ -265,12 +292,106 @@ static const struct iio_chan_spec ads112c14_sys_mon_channels[] = {
},
};
+static int ads112c14_prepare_measurement_channel(struct ads112c14_data *data,
+ const struct iio_chan_spec *chan)
+{
+ struct ads112c14_measurement *measurement = &data->measurements[chan->scan_index];
+ bool iunit = measurement->idac_current_uA > 100;
+ u32 idac1_val = measurement->iadc_count > 0 ?
+ measurement->idac_current_uA / (iunit ? 100 : 10) : 0;
+ u32 idac2_val = measurement->iadc_count > 1 ? idac1_val : 0;
+ u32 refp_buf_en, refn_buf_en;
+ u32 ref_val, ref_sel;
+ int ret;
+
+ ret = regmap_write(data->regmap, ADS112C14_REG_MUX_CFG,
+ FIELD_PREP(ADS112C14_MUX_CFG_AINP, chan->channel) |
+ FIELD_PREP(ADS112C14_MUX_CFG_AINN, chan->channel2));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG,
+ ADS112C14_DIGITAL_CFG_CODING,
+ FIELD_PREP(ADS112C14_DIGITAL_CFG_CODING,
+ measurement->bipolar ? 0 : 1));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_GAIN_CFG,
+ ADS112C14_GAIN_CFG_SYS_MON | ADS112C14_GAIN_CFG_GAIN,
+ FIELD_PREP(ADS112C14_GAIN_CFG_SYS_MON, 0) |
+ FIELD_PREP(ADS112C14_GAIN_CFG_GAIN,
+ measurement->gain_val));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, ADS112C14_REG_IDAC_MAG_CFG,
+ FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I2MAG, idac2_val) |
+ FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I1MAG, idac1_val));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, ADS112C14_REG_IDAC_MUX_CFG,
+ (iunit ? ADS112C14_IDAC_MUX_CFG_IUNIT : 0) |
+ FIELD_PREP(ADS112C14_IDAC_MUX_CFG_I2MUX,
+ measurement->idac2_mux) |
+ FIELD_PREP(ADS112C14_IDAC_MUX_CFG_I1MUX,
+ measurement->idac1_mux));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_DATA_RATE_CFG,
+ ADS112C14_DATA_RATE_CFG_GC_EN,
+ FIELD_PREP(ADS112C14_DATA_RATE_CFG_GC_EN,
+ measurement->current_chop));
+ if (ret)
+ return ret;
+
+ refp_buf_en = !data->refp_is_avdd &&
+ measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL;
+ refn_buf_en = !data->refn_is_gnd &&
+ measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL;
+
+ ref_val = measurement->vref_source == ADS112C14_VREF_SOURCE_INTERNAL_2_5V;
+
+ switch (measurement->vref_source) {
+ case ADS112C14_VREF_SOURCE_AVDD:
+ ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_AVDD;
+ break;
+ case ADS112C14_VREF_SOURCE_EXTERNAL:
+ ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_EXTERNAL;
+ break;
+ default:
+ ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL;
+ break;
+ }
+
+ return regmap_update_bits(data->regmap, ADS112C14_REG_REFERENCE_CFG,
+ ADS112C14_REFERENCE_CFG_REFP_BUF_EN |
+ ADS112C14_REFERENCE_CFG_REFN_BUF_EN |
+ ADS112C14_REFERENCE_CFG_REF_VAL |
+ ADS112C14_REFERENCE_CFG_REF_SEL,
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REFP_BUF_EN,
+ refp_buf_en) |
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REFN_BUF_EN,
+ refn_buf_en) |
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_VAL,
+ ref_val) |
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_SEL,
+ ref_sel));
+}
+
static int ads112c14_prepare_sys_mon_channel(struct ads112c14_data *data,
const struct iio_chan_spec *chan)
{
u32 gain_val;
int ret;
+ /*
+ * NB: IDAC registers are left as-is in case they are generating current
+ * needed for the external reference measurement.
+ */
+
/*
* All SYS_MON channels use GAIN of 1 to keep it simple. Other than
* the internal short channel, where it is useful in practice.
@@ -320,13 +441,14 @@ static int ads112c14_single_conversion(struct ads112c14_data *data,
u32 reg_val;
int ret;
- if (chan->channel >= 100) {
- ret = ads112c14_prepare_sys_mon_channel(data, chan);
+ if (chan->channel < 100) {
+ ret = ads112c14_prepare_measurement_channel(data, chan);
if (ret)
return ret;
} else {
- /* Not implemented yet. */
- return -EINVAL;
+ ret = ads112c14_prepare_sys_mon_channel(data, chan);
+ if (ret)
+ return ret;
}
ret = regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL,
@@ -351,13 +473,20 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct ads112c14_data *data = iio_priv(indio_dev);
+ struct ads112c14_measurement *measurement;
u32 vref_uV, fsr_bits;
+ int *scale_avail;
/* Selecting V_REF source is not implemented yet. */
vref_uV = ads112c14_internal_ref_uV[ADS112C14_REFERENCE_CFG_REF_VAL_2_5V];
- /* Currently, everything is using signed data. */
- fsr_bits = data->chip_info->resolution_bits - 1;
+ if (chan->channel < 100) {
+ measurement = &data->measurements[chan->scan_index];
+ fsr_bits = data->chip_info->resolution_bits - measurement->bipolar;
+ } else {
+ /* All SYS_MON channels are using signed coding. */
+ fsr_bits = data->chip_info->resolution_bits - 1;
+ }
switch (mask) {
case IIO_CHAN_INFO_RAW: {
@@ -383,7 +512,8 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
- *val = sign_extend32(*val, fsr_bits);
+ if (!measurement || measurement->bipolar)
+ *val = sign_extend32(*val, fsr_bits);
return IIO_VAL_INT;
}
@@ -396,7 +526,7 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
}
if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) {
- int *scale_avail = data->sys_mon_chan_short_scale_available[
+ scale_avail = data->sys_mon_chan_short_scale_available[
data->sys_mon_chan_short_gain_val
];
@@ -406,13 +536,23 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_NANO;
}
- *val = vref_uV / (MICRO / MILLI);
- /*
- * Last 3 SYS_MON channels (ext ref, AVDD, DVDD) need to be
- * multiplied by 8 to account for internal attenuation of / 8.
- */
- *val2 = fsr_bits - (chan->address >= 3 ? 3 : 0);
- return IIO_VAL_FRACTIONAL_LOG2;
+ if (chan->channel > 100) {
+ *val = vref_uV / (MICRO / MILLI);
+ /*
+ * Last 3 SYS_MON channels (ext ref, AVDD, DVDD) need to
+ * be multiplied by 8 to account for internal attenuation
+ * of / 8.
+ */
+ *val2 = fsr_bits - (chan->address >= 3 ? 3 : 0);
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+
+ scale_avail = measurement->scale_available[measurement->gain_val];
+ *val = scale_avail[0];
+ *val2 = scale_avail[1];
+
+ return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_OFFSET:
/* Only the temperature channel has an offset. */
if (chan->type != IIO_TEMP)
@@ -433,6 +573,16 @@ static int ads112c14_read_avail(struct iio_dev *indio_dev,
{
struct ads112c14_data *data = iio_priv(indio_dev);
+ if (chan->channel < 100) {
+ struct ads112c14_measurement *measurement =
+ &data->measurements[chan->scan_index];
+
+ *vals = (const int *)measurement->scale_available;
+ *length = 2 * ARRAY_SIZE(measurement->scale_available);
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+ }
+
switch (chan->channel) {
case ADS112C14_SYS_MON_CHANNEL_SHORT:
*vals = (const int *)data->sys_mon_chan_short_scale_available;
@@ -449,25 +599,31 @@ static int ads112c14_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct ads112c14_data *data = iio_priv(indio_dev);
+ const int (*scale_avail)[2];
+ u8 *gain_val;
+
+ if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) {
+ scale_avail = data->sys_mon_chan_short_scale_available;
+ gain_val = &data->sys_mon_chan_short_gain_val;
+ } else if (chan->channel < 100) {
+ scale_avail = data->measurements[chan->scan_index].scale_available;
+ gain_val = &data->measurements[chan->scan_index].gain_val;
+ } else {
+ return -EINVAL;
+ }
- switch (chan->channel) {
- case ADS112C14_SYS_MON_CHANNEL_SHORT: {
- IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
- if (IIO_DEV_ACQUIRE_FAILED(claim))
- return -EBUSY;
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
- for (u32 i = 0; i < ARRAY_SIZE(data->sys_mon_chan_short_scale_available); i++) {
- if (val == data->sys_mon_chan_short_scale_available[i][0] &&
- val2 == data->sys_mon_chan_short_scale_available[i][1]) {
- data->sys_mon_chan_short_gain_val = i;
- return 0;
- }
+ for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) {
+ if (val == scale_avail[i][0] && val2 == scale_avail[i][1]) {
+ *gain_val = i;
+ return 0;
}
- return -EINVAL;
- }
- default:
- return -EINVAL;
}
+
+ return -EINVAL;
}
static int ads112c14_write_raw_get_fmt(struct iio_dev *indio_dev,
@@ -485,8 +641,20 @@ static int ads112c14_write_raw_get_fmt(struct iio_dev *indio_dev,
static int ads112c14_read_label(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, char *label)
{
+ struct ads112c14_data *data = iio_priv(indio_dev);
const char *label_source;
+ /* measurement channels */
+ if (chan->channel < 100) {
+ struct ads112c14_measurement *measurement =
+ &data->measurements[chan->scan_index];
+
+ if (!measurement->label)
+ return -EINVAL;
+
+ return sysfs_emit(label, "%s\n", measurement->label);
+ }
+
/* System monitor channels. */
switch (chan->channel) {
case ADS112C14_SYS_MON_CHANNEL_TEMP:
@@ -519,26 +687,187 @@ static const struct iio_info ads112c14_info = {
.read_label = ads112c14_read_label,
};
+static int ads112c14_parse_channels(struct iio_dev *indio_dev,
+ bool *need_avdd_ref, bool *need_ext_ref)
+{
+ struct ads112c14_data *data = iio_priv(indio_dev);
+ struct device *dev = &data->client->dev;
+ struct iio_chan_spec *channels;
+ u32 pair[2];
+ int i = 0;
+ int ret;
+
+ *need_avdd_ref = false;
+ *need_ext_ref = false;
+
+ data->num_measurements = device_get_named_child_node_count(dev, "channel");
+
+ data->measurements = devm_kcalloc(dev, data->num_measurements,
+ sizeof(*data->measurements), GFP_KERNEL);
+ if (!data->measurements)
+ return -ENOMEM;
+
+ data->num_measurements += ARRAY_SIZE(ads112c14_sys_mon_channels);
+
+ channels = devm_kcalloc(dev, data->num_measurements +
+ ARRAY_SIZE(ads112c14_sys_mon_channels),
+ sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ device_for_each_named_child_node_scoped(dev, child, "channel") {
+ struct ads112c14_measurement *measurement = &data->measurements[i];
+ struct iio_chan_spec *spec = &channels[i];
+
+ if (!fwnode_device_is_available(child))
+ continue;
+
+ spec->type = IIO_VOLTAGE;
+ spec->indexed = 1;
+ spec->scan_index = i;
+ measurement->gain_val = 1;
+
+ fwnode_property_read_string(child, "label", &measurement->label);
+
+ if (fwnode_property_present(child, "single-channel")) {
+ ret = fwnode_property_read_u32(child, "single-channel", &spec->channel);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read single-channel property\n");
+
+ if (spec->channel >= 8)
+ return dev_err_probe(dev, -EINVAL,
+ "single-channel value must be between 0 and 7\n");
+ } else if (fwnode_property_present(child, "diff-channels")) {
+ ret = fwnode_property_read_u32_array(child, "diff-channels", pair, ARRAY_SIZE(pair));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read diff-channels property\n");
+
+ if (pair[0] >= 8 || pair[1] >= 8)
+ return dev_err_probe(dev, -EINVAL,
+ "diff-channels values must be between 0 and 7\n");
+
+ spec->channel = pair[0];
+ spec->channel2 = pair[1];
+ spec->differential = 1;
+ } else {
+ return dev_err_probe(dev, -EINVAL,
+ "channel node missing channel type property\n");
+ }
+
+ if (fwnode_property_present(child, "excitation-channels")) {
+ ret = fwnode_property_count_u32(child, "excitation-channels");
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to read excitation-channels property\n");
+
+ if (ret < 1 || ret > 2)
+ return dev_err_probe(dev, -EINVAL,
+ "excitation-channels property must have 1 or 2 values\n");
+
+ measurement->iadc_count = ret;
+ pair[1] = 0;
+
+ ret = fwnode_property_read_u32_array(child, "excitation-channels", pair, measurement->iadc_count);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read excitation-channels property\n");
+
+ if (pair[0] >= 8 || pair[1] >= 8)
+ return dev_err_probe(dev, -EINVAL,
+ "excitation-channels values must be between 0 and 7\n");
+
+ measurement->idac1_mux = pair[0];
+ measurement->idac2_mux = measurement->iadc_count > 1 ? pair[1] : 0;
+
+ ret = fwnode_property_read_u32(child, "excitation-current-microamp",
+ &measurement->idac_current_uA);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read excitation-current-microamp property\n");
+
+ measurement->current_chop = fwnode_property_read_bool(child, "current-chopping");
+ }
+
+ measurement->bipolar = fwnode_property_read_bool(child, "bipolar");
+
+ fwnode_property_read_u32(child, "ti,vref-source", &measurement->vref_source);
+ if (measurement->vref_source > ADS112C14_VREF_SOURCE_AVDD)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid vref-source value\n");
+
+ if (measurement->vref_source == ADS112C14_VREF_SOURCE_AVDD)
+ *need_avdd_ref = true;
+ if (measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL)
+ *need_ext_ref = true;
+
+ spec->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE);
+ spec->info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE);
+
+ i++;
+ }
+
+ memcpy(channels + i, ads112c14_sys_mon_channels, sizeof(ads112c14_sys_mon_channels));
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels = i + ARRAY_SIZE(ads112c14_sys_mon_channels);
+
+ return 0;
+}
+
+static void ads112c14_populate_scale_available(int scale_avail[][2],
+ u32 vref_uV, u32 fsr_bits)
+{
+ for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) {
+ int *entry = scale_avail[i];
+ u32 gain_x10 = ads112c14_pga_gains_x10[i];
+
+ entry[0] = div_u64_rem(div64_u64((u64)(NANO * 10 /
+ (MICRO / MILLI)) * vref_uV,
+ (u64)gain_x10 * BIT(fsr_bits)),
+ NANO, &entry[1]);
+ }
+}
+
static void ads112c14_populate_tables(struct ads112c14_data *data)
{
u32 vref_uV, fsr_bits;
- int i;
+
+ for (u32 i = 0; i < data->num_measurements; i++) {
+ struct ads112c14_measurement *measurement = &data->measurements[i];
+
+ switch (measurement->vref_source) {
+ case ADS112C14_VREF_SOURCE_EXTERNAL:
+ if (data->ext_ref_ohms)
+ vref_uV = measurement->idac_current_uA *
+ measurement->iadc_count * data->ext_ref_ohms;
+ else
+ vref_uV = data->ext_ref_uV;
+ break;
+ case ADS112C14_VREF_SOURCE_AVDD:
+ vref_uV = data->avdd_uV;
+ break;
+ case ADS112C14_VREF_SOURCE_INTERNAL_1_25V:
+ vref_uV = ads112c14_internal_ref_uV[ADS112C14_REFERENCE_CFG_REF_VAL_1_25V];
+ break;
+ default:
+ vref_uV = ads112c14_internal_ref_uV[ADS112C14_REFERENCE_CFG_REF_VAL_2_5V];
+ break;
+ }
+
+ fsr_bits = data->chip_info->resolution_bits - measurement->bipolar;
+
+ ads112c14_populate_scale_available(measurement->scale_available,
+ vref_uV, fsr_bits);
+ }
/* For now, assuming we are using 2.5V reference. */
vref_uV = ads112c14_internal_ref_uV[ADS112C14_REFERENCE_CFG_REF_VAL_2_5V];
fsr_bits = data->chip_info->resolution_bits - 1;
- for (i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) {
- int *scale_avail = &data->sys_mon_chan_short_scale_available[i][0];
- u32 gain_x10 = ads112c14_pga_gains_x10[i];
-
- /* NB: slightly odd arrangement to avoid overflow. */
- scale_avail[0] = div_u64_rem(div_u64((u64)NANO * 10 /
- (MICRO / MILLI) * vref_uV /
- gain_x10,
- BIT(fsr_bits)),
- NANO, &scale_avail[1]);
- }
+ ads112c14_populate_scale_available(data->sys_mon_chan_short_scale_available,
+ vref_uV, fsr_bits);
}
static int ads112c14_probe(struct i2c_client *client)
@@ -547,6 +876,9 @@ static int ads112c14_probe(struct i2c_client *client)
const struct ads112c14_chip_info *info;
struct iio_dev *indio_dev;
struct ads112c14_data *data;
+ bool need_avdd_ref, need_ext_ref;
+ u32 refp_uV = 0;
+ u32 refn_uV = 0;
u32 reg_val;
int ret;
@@ -560,13 +892,75 @@ static int ads112c14_probe(struct i2c_client *client)
data->chip_info = info;
data->client = client;
+ ret = ads112c14_parse_channels(indio_dev, &need_avdd_ref, &need_ext_ref);
+ if (ret)
+ return ret;
+
ret = devm_regulator_get_enable(&client->dev, "dvdd");
if (ret)
return dev_err_probe(dev, ret, "failed to get dvdd regulator\n");
- ret = devm_regulator_get_enable(&client->dev, "avdd");
- if (ret)
- return dev_err_probe(dev, ret, "failed to get avdd regulator\n");
+ if (need_avdd_ref) {
+ ret = devm_regulator_get_enable_read_voltage(&client->dev, "avdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get avdd voltage\n");
+
+ data->avdd_uV = ret;
+ } else {
+ ret = devm_regulator_get_enable(&client->dev, "avdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get avdd regulator\n");
+ }
+
+ if (device_property_present(dev, "refp-supply")) {
+ ret = devm_regulator_get_enable_read_voltage(&client->dev, "refp");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get refp voltage\n");
+
+ refp_uV = ret;
+
+ struct fwnode_handle *refp_fwnode __free(fwnode_handle) =
+ fwnode_find_reference(dev->fwnode, "refp-supply", 0);
+ if (IS_ERR(refp_fwnode))
+ return dev_err_probe(dev, PTR_ERR(refp_fwnode),
+ "failed to get refp fwnode\n");
+
+ struct fwnode_handle *avdd_fwnode __free(fwnode_handle) =
+ fwnode_find_reference(dev->fwnode, "avdd-supply", 0);
+ if (IS_ERR(avdd_fwnode))
+ return dev_err_probe(dev, PTR_ERR(avdd_fwnode),
+ "failed to get avdd fwnode\n");
+
+ data->refp_is_avdd = refp_fwnode == avdd_fwnode;
+ }
+
+ if (device_property_present(dev, "refn-supply")) {
+ ret = devm_regulator_get_enable_read_voltage(&client->dev, "refn");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get refn voltage\n");
+
+ refn_uV = ret;
+ } else {
+ data->refn_is_gnd = true;
+ }
+
+ data->ext_ref_uV = refp_uV - refn_uV;
+
+ if (device_property_present(dev, "refp-refn-resistor-ohms")) {
+ if (refp_uV != 0 || refn_uV != 0)
+ return dev_err_probe(dev, -EINVAL,
+ "refp-refn-resistor-ohms property should not be present when refp-supply or refn-supply is present\n");
+
+ ret = device_property_read_u32(dev, "refp-refn-resistor-ohms",
+ &data->ext_ref_ohms);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read refp-refn-resistor-ohms property\n");
+ } else {
+ if (need_ext_ref && data->ext_ref_uV == 0)
+ return dev_err_probe(dev, -EINVAL,
+ "external reference measurements require either refp-supply or refp-refn-resistor-ohms property\n");
+ }
data->regmap = devm_regmap_init_i2c(client, &ads112c14_regmap_config);
if (IS_ERR(data->regmap))
@@ -615,8 +1009,6 @@ static int ads112c14_probe(struct i2c_client *client)
indio_dev->name = info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = ads112c14_sys_mon_channels;
- indio_dev->num_channels = ARRAY_SIZE(ads112c14_sys_mon_channels);
indio_dev->info = &ads112c14_info;
return devm_iio_device_register(&client->dev, indio_dev);
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox