* Re: [PATCH v4 12/12] iio: dac: ad5686: add gain control support
From: sashiko-bot @ 2026-06-23 11:13 UTC (permalink / raw)
To: Rodrigo Alencar via B4 Relay; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260623-ad5686-new-features-v4-12-28962a57db0f@analog.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Data race in `ad5686_read_avail()` due to lockless access of `st->double_scale`, which is temporarily mutated in `ad5686_write_raw()`.
--
commit 7b5b8c7fbbe74efe7dd9f093ff8593661667e614
Author: Rodrigo Alencar <rodrigo.alencar@analog.com>
iio: dac: ad5686: add gain control support
Adds gain control support to the ad5686 driver, allowing a 2x multiplier
to be applied to the output voltage either via a dedicated GAIN pin or
a control register bit field. It exposes available scales to userspace
and adds tracking of the double scale state.
> diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
> index 4dc681eb077d6..bad214b89257f 100644
> --- a/drivers/iio/dac/ad5686.c
> +++ b/drivers/iio/dac/ad5686.c
[ ... ]
> @@ -217,6 +229,84 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
>
> return ad5686_write(st, AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
> chan->address, val << chan->scan_type.shift);
> + case IIO_CHAN_INFO_SCALE:
> + if (val == st->scale_avail[0] && val2 == st->scale_avail[1])
> + double_scale = false;
> + else if (val == st->scale_avail[2] && val2 == st->scale_avail[3])
> + double_scale = true;
> + else
> + return -EINVAL;
> +
> + if (st->double_scale == double_scale)
> + return 0; /* no change */
> +
> + st->double_scale = double_scale;
> + switch (st->chip_info->regmap_type) {
> + case AD5310_REGMAP:
> + ret = ad5310_control_sync(st);
> + break;
> + case AD5683_REGMAP:
> + ret = ad5683_control_sync(st);
> + break;
> + case AD5686_REGMAP:
> + if (!st->gain_gpio) {
> + ret = -EINVAL;
> + break;
> + }
> +
> + ret = gpiod_set_value_cansleep(st->gain_gpio,
> + st->double_scale ? 1 : 0);
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + if (ret)
> + st->double_scale = !double_scale; /* revert on failure */
> + return ret;
[ ... ]
> +static int ad5686_read_avail(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int **vals, int *type, int *length,
> + long mask)
> +{
> + struct ad5686_state *st = iio_priv(indio_dev);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_SCALE:
> + *type = IIO_VAL_INT_PLUS_NANO;
> +
> + if (st->chip_info->regmap_type == AD5686_REGMAP && !st->gain_gpio) {
> + /*
> + * GAIN pin is board-strapped, so only the current
> + * scale is available.
> + */
> + *vals = st->double_scale ? &st->scale_avail[2] :
> + &st->scale_avail[0];
[Severity: Medium]
Is there a potential data race on st->double_scale here?
In ad5686_write_raw(), st->double_scale is temporarily modified and then
reverted on failure under st->lock. However, ad5686_read_avail() accesses
st->double_scale without holding st->lock.
If a sysfs read on in_voltage_scale_available happens concurrently with a
failing sysfs write on in_voltage_scale for a board-strapped device, could
the read observe the temporary invalid state of st->double_scale before
it is reverted and returned to userspace?
> + *length = 2;
> + return IIO_AVAIL_LIST;
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623-ad5686-new-features-v4-0-28962a57db0f@analog.com?part=12
^ permalink raw reply
* Re: [PATCH v4 11/12] iio: dac: ad5686: add triggered buffer support
From: sashiko-bot @ 2026-06-23 11:14 UTC (permalink / raw)
To: Rodrigo Alencar via B4 Relay; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260623-ad5686-new-features-v4-11-28962a57db0f@analog.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The ad5686_trigger_handler fails to convert Big Endian buffer data to native CPU endianness before passing it to the write operations, causing scrambled DAC values on Little Endian systems.
--
commit b9bb35e4f394ef5515930983f7b76ce0cae1335e
Author: Rodrigo Alencar <rodrigo.alencar@analog.com>
iio: dac: ad5686: add triggered buffer support
This commit implements a trigger handler for the AD5686 DAC driver to update
all channels simultaneously when the LDAC GPIO is available. It also flushes
multiple channel writes at once using the sync() operation.
> diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
> index db175e77b0b7c..4dc681eb077d6 100644
> --- a/drivers/iio/dac/ad5686.c
> +++ b/drivers/iio/dac/ad5686.c
[ ... ]
> @@ -467,6 +472,60 @@ const struct ad5686_chip_info ad5679r_chip_info = {
> };
> EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686");
>
> +static irqreturn_t ad5686_trigger_handler(int irq, void *p)
> +{
> + struct iio_poll_func *pf = p;
> + struct iio_dev *indio_dev = pf->indio_dev;
> + struct iio_buffer *buffer = indio_dev->buffer;
> + struct ad5686_state *st = iio_priv(indio_dev);
> + u16 val[AD5686_MAX_CHANNELS] = { };
> + unsigned int scan_count, ch, i;
> + bool async_update;
> + int ret;
> + u8 cmd;
> +
> + ret = iio_pop_from_buffer(buffer, val);
> + if (ret) {
> + iio_trigger_notify_done(indio_dev->trig);
> + return IRQ_HANDLED;
> + }
> +
> + guard(mutex)(&st->lock);
> +
> + scan_count = bitmap_weight(indio_dev->active_scan_mask,
> + iio_get_masklength(indio_dev));
> + async_update = st->ldac_gpio && scan_count > 1;
> + if (async_update) {
> + /* use LDAC to update all channels simultaneously */
> + cmd = AD5686_CMD_WRITE_INPUT_N;
> + gpiod_set_value_cansleep(st->ldac_gpio, 0);
> + } else {
> + cmd = AD5686_CMD_WRITE_INPUT_N_UPDATE_N;
> + }
> +
> + i = 0;
> + iio_for_each_active_channel(indio_dev, ch) {
> + ret = st->ops->write(st, cmd, indio_dev->channels[ch].address, val[i++]);
[Severity: High]
Will this send scrambled data on Little Endian CPUs?
Since the driver declares IIO_BE, the data populated by iio_pop_from_buffer()
into the val array is in Big Endian format. Passing val[i++] directly to
st->ops->write() as a native u16 without using be16_to_cpu() means the bytes
might be incorrectly byte-swapped before transmission.
> + if (ret)
> + break;
> + }
> +
> + /*
> + * If sync() is available, it is called here regardless of write
> + * failure to allow bus implementation to reset. In that case, partial
> + * writes are unlikely as the write operations would just queue up
> + * the transfers.
> + */
> + if (st->ops->sync)
> + st->ops->sync(st);
> +
> + if (async_update)
> + gpiod_set_value_cansleep(st->ldac_gpio, 1);
> +
> + iio_trigger_notify_done(indio_dev->trig);
> + return IRQ_HANDLED;
> +}
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623-ad5686-new-features-v4-0-28962a57db0f@analog.com?part=11
^ permalink raw reply
* Re: [PATCH] dt-bindings: clock: ti,clockdomain: Convert to DT schema
From: kernel test robot @ 2026-06-23 11:14 UTC (permalink / raw)
To: Bhargav Joshi, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Tero Kristo
Cc: oe-kbuild-all, linux-clk, devicetree, linux-kernel, goledhruva,
m-chawdhry, daniel.baluta, simona.toaca, j.bhargav.u
In-Reply-To: <20260621-ti-clockdomain-v1-1-e99a56af98ea@gmail.com>
Hi Bhargav,
kernel test robot noticed the following build warnings:
[auto build test WARNING on acb7500801e98639f6d8c2d796ed9f64cba83d3a]
url: https://github.com/intel-lab-lkp/linux/commits/Bhargav-Joshi/dt-bindings-clock-ti-clockdomain-Convert-to-DT-schema/20260623-022037
base: acb7500801e98639f6d8c2d796ed9f64cba83d3a
patch link: https://lore.kernel.org/r/20260621-ti-clockdomain-v1-1-e99a56af98ea%40gmail.com
patch subject: [PATCH] dt-bindings: clock: ti,clockdomain: Convert to DT schema
compiler: clang version 22.1.8 (https://github.com/llvm/llvm-project ca7933e47d3a3451d81e72ac174dcb5aa28b59d1)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260623/202606231306.COGVL9ZT-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606231306.COGVL9ZT-lkp@intel.com/
All warnings (new ones prefixed by >>):
from /zdci/src/kernel-tests/common.sh:210: redirect_command_errors
from /zdci/src/kernel-tests/lib/builder/htmldocs.sh:86: builder_execute_build
from /zdci/src/kernel-tests/lib/kbuild.sh:6419: compile_one_config
from /zdci/src/kernel-tests/lib/builder/base.sh:88: builder_compile
from /zdci/src/kernel-tests/bisect-test-build-error.sh:102: main
>> Warning: Documentation/devicetree/bindings/clock/ti/ti,gate-clock.yaml references a file that doesn't exist: Documentation/devicetree/bindings/clock/ti/clockdomain.txt
Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
Warning: Documentation/devicetree/bindings/regulator/motorola,cpcap-regulator.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Warning: Documentation/devicetree/bindings/regulator/siliconmitus,sm5703-regulator.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/siliconmitus,sm5703.yaml
Warning: Documentation/devicetree/bindings/rtc/motorola,cpcap-rtc.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH 0/2] arm64: dts: socfpga: agilex7-gen2: Add initial device tree support
From: muhammad.nazim.amirul.nazle.asmade @ 2026-06-23 11:17 UTC (permalink / raw)
To: dinguyen; +Cc: robh, krzk+dt, conor+dt, devicetree, linux-kernel
From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
This series introduces initial device tree support for the Intel
SoCFPGA Agilex7 Gen2 platform.
The first patch registers the new SoC and board compatible strings in
the DT binding. The second patch adds the SoC DTSI and board DTS with
basic platform nodes.
Nazim Amirul (2):
dt-bindings: arm: altera: Add Agilex7 Gen2 SoCFPGA compatible strings
arm64: dts: socfpga: agilex7-gen2: Add initial device tree
.../devicetree/bindings/arm/altera.yaml | 6 +
arch/arm64/boot/dts/intel/Makefile | 1 +
.../boot/dts/intel/socfpga_agilex7_gen2.dtsi | 175 ++++++++++++++++++
.../dts/intel/socfpga_agilex7_gen2_socdk.dts | 15 ++
4 files changed, 197 insertions(+)
create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex7_gen2.dtsi
create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex7_gen2_socdk.dts
--
2.43.7
^ permalink raw reply
* [PATCH 1/2] dt-bindings: arm: altera: Add Agilex7 Gen2 SoCFPGA compatible strings
From: muhammad.nazim.amirul.nazle.asmade @ 2026-06-23 11:17 UTC (permalink / raw)
To: dinguyen; +Cc: robh, krzk+dt, conor+dt, devicetree, linux-kernel
In-Reply-To: <20260623111716.16690-1-muhammad.nazim.amirul.nazle.asmade@altera.com>
From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
Add the SoC and board compatible strings for the Intel SoCFPGA
Agilex7 Gen2 platform.
Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
---
Documentation/devicetree/bindings/arm/altera.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/altera.yaml b/Documentation/devicetree/bindings/arm/altera.yaml
index 4b096e52243e..da32ff31aea0 100644
--- a/Documentation/devicetree/bindings/arm/altera.yaml
+++ b/Documentation/devicetree/bindings/arm/altera.yaml
@@ -115,6 +115,12 @@ properties:
- intel,socfpga-agilex5-socdk-nand
- const: intel,socfpga-agilex5
+ - description: Agilex7 Gen2 boards
+ items:
+ - enum:
+ - intel,socfpga-agilex7-gen2-socdk
+ - const: intel,socfpga-agilex7-gen2
+
- description: Agilex7m boards
items:
- enum:
--
2.43.7
^ permalink raw reply related
* [PATCH 2/2] arm64: dts: socfpga: agilex7-gen2: Add initial device tree
From: muhammad.nazim.amirul.nazle.asmade @ 2026-06-23 11:17 UTC (permalink / raw)
To: dinguyen; +Cc: robh, krzk+dt, conor+dt, devicetree, linux-kernel
In-Reply-To: <20260623111716.16690-1-muhammad.nazim.amirul.nazle.asmade@altera.com>
From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
Add initial device tree support for the Intel SoCFPGA Agilex7 Gen2
platform. This introduces the SoC DTSI and the SoCDK board DTS as
the first upstream submission for this platform.
The Agilex7 Gen2 SoC features a heterogeneous CPU cluster with
Cortex-A520 and Cortex-A720 cores, and includes an SMMU v3 for
memory management.
Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
---
arch/arm64/boot/dts/intel/Makefile | 1 +
.../boot/dts/intel/socfpga_agilex7_gen2.dtsi | 119 ++++++++++++++++++
.../dts/intel/socfpga_agilex7_gen2_socdk.dts | 15 +++
3 files changed, 135 insertions(+)
create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex7_gen2.dtsi
create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex7_gen2_socdk.dts
diff --git a/arch/arm64/boot/dts/intel/Makefile b/arch/arm64/boot/dts/intel/Makefile
index 088a03b89c99..7a53b3c174a1 100644
--- a/arch/arm64/boot/dts/intel/Makefile
+++ b/arch/arm64/boot/dts/intel/Makefile
@@ -8,6 +8,7 @@ dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_agilex_n6000.dtb \
socfpga_agilex5_socdk_013b.dtb \
socfpga_agilex5_socdk_modular.dtb \
socfpga_agilex5_socdk_nand.dtb \
+ socfpga_agilex7_gen2_socdk.dtb \
socfpga_agilex7m_socdk.dtb \
socfpga_n5x_socdk.dtb
dtb-$(CONFIG_ARCH_KEEMBAY) += keembay-evm.dtb
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2.dtsi
new file mode 100644
index 000000000000..e3b777408f9a
--- /dev/null
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2.dtsi
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026, Altera Corporation
+ */
+/dts-v1/;
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ compatible = "intel,socfpga-agilex7-gen2";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ atf_reserved: atf@80000000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0x80000000 0x0 0x100000>;
+ alignment = <0x1000>;
+ no-map;
+ };
+
+ service_reserved: svcbuffer@80100000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0x80100000 0x0 0xf00000>;
+ alignment = <0x1000>;
+ no-map;
+ };
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a520";
+ device_type = "cpu";
+ enable-method = "psci";
+ reg = <0x0>;
+ };
+
+ cpu1: cpu@100 {
+ compatible = "arm,cortex-a520";
+ device_type = "cpu";
+ enable-method = "psci";
+ reg = <0x100>;
+ };
+
+ cpu2: cpu@200 {
+ compatible = "arm,cortex-a720";
+ device_type = "cpu";
+ enable-method = "psci";
+ reg = <0x200>;
+ };
+
+ cpu3: cpu@300 {
+ compatible = "arm,cortex-a720";
+ device_type = "cpu";
+ enable-method = "psci";
+ reg = <0x300>;
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ intc: interrupt-controller@7000000 {
+ compatible = "arm,gic-v3";
+ reg = <0x0 0x7000000 0x0 0x10000>,
+ <0x0 0x7080000 0x0 0x100000>;
+ ranges;
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-controller;
+ #redistributor-regions = <1>;
+ redistributor-stride = <0x0 0x40000>;
+
+ its: msi-controller@7040000 {
+ compatible = "arm,gic-v3-its";
+ reg = <0x0 0x7040000 0x0 0x20000>;
+ msi-controller;
+ #msi-cells = <1>;
+ };
+ };
+
+ soc: soc@0 {
+ compatible = "simple-bus";
+ ranges = <0 0 0 0xffffffff>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ interrupt-parent = <&intc>;
+
+ smmu: iommu@c100000 {
+ compatible = "arm,smmu-v3";
+ reg = <0x0c100000 0x30000>;
+ interrupts = <GIC_SPI 134 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 129 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 132 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eventq", "gerror", "priq";
+ dma-coherent;
+ #iommu-cells = <1>;
+ };
+
+ ocram: sram@0 {
+ compatible = "mmio-sram";
+ reg = <0x00000000 0x80000>;
+ ranges = <0 0 0x80000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2_socdk.dts
new file mode 100644
index 000000000000..416d033445ff
--- /dev/null
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2_socdk.dts
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026, Altera Corporation
+ */
+#include "socfpga_agilex7_gen2.dtsi"
+
+/ {
+ model = "Altera SoCFPGA Agilex7 Gen2 SoCDK";
+ compatible = "intel,socfpga-agilex7-gen2-socdk", "intel,socfpga-agilex7-gen2";
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x0 0x80000000 0x0 0x80000000>;
+ };
+};
--
2.43.7
^ permalink raw reply related
* Re: [PATCH v2] arm64: dts: qcom: glymur-crd: merge duplicate &pmh0101_gpios node extensions
From: Pankaj Patil @ 2026-06-23 11:22 UTC (permalink / raw)
To: Gopikrishna Garmidi, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Dmitry Baryshkov
Cc: Sibi Sankar, Rajendra Nayak, linux-arm-msm, devicetree,
linux-kernel
In-Reply-To: <20260602-merge-duplicate-pmh0101-gpios-node-v2-1-251107b3d9fe@oss.qualcomm.com>
On 6/2/2026 3:18 PM, Gopikrishna Garmidi wrote:
> The &pmh0101_gpios node is extended twice in glymur-crd.dtsi. The first
> extension defines the nvme_reg_en pinctrl state for the NVMe regulator
> enable GPIO (gpio14), and the second adds key_vol_up_default for the
> volume-up key (gpio6).
>
> Merge both pinctrl states into a single &pmh0101_gpios block to avoid
> the duplicate node extension.
>
> No functional change intended.
>
> Fixes: a5ad8a8e473c ("arm64: dts: qcom: Commonize Glymur CRD DTSI")
> Signed-off-by: Gopikrishna Garmidi <gopikrishna.garmidi@oss.qualcomm.com>
> ---
> Changes in v2:
> - Reorder nodes in alphabetical order
> - Link to v1: https://lore.kernel.org/r/20260526-merge-duplicate-pmh0101-gpios-node-v1-1-c4ab4983f8be@oss.qualcomm.com
> ---
> arch/arm64/boot/dts/qcom/glymur-crd.dtsi | 16 +++++++---------
> 1 file changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dtsi b/arch/arm64/boot/dts/qcom/glymur-crd.dtsi
> index e784b538f42e..782578a2c5ff 100644
> --- a/arch/arm64/boot/dts/qcom/glymur-crd.dtsi
> +++ b/arch/arm64/boot/dts/qcom/glymur-crd.dtsi
> @@ -538,6 +538,13 @@ &pcie6_port0 {
> };
>
> &pmh0101_gpios {
> + key_vol_up_default: key-vol-up-default-state {
> + pins = "gpio6";
> + function = "normal";
> + output-disable;
> + bias-pull-up;
> + };
> +
> nvme_reg_en: nvme-reg-en-state {
> pins = "gpio14";
> function = "normal";
> @@ -553,15 +560,6 @@ nvme_sec_reg_en: nvme-reg-en-state {
> };
> };
>
> -&pmh0101_gpios {
> - key_vol_up_default: key-vol-up-default-state {
> - pins = "gpio6";
> - function = "normal";
> - output-disable;
> - bias-pull-up;
> - };
> -};
> -
> &pmk8850_rtc {
> qcom,no-alarm;
> };
>
> ---
> base-commit: 08484c504b55a98bd100527fbe10a3caf55ff3ff
> change-id: 20260526-merge-duplicate-pmh0101-gpios-node-52eaf99f8485
>
> Best regards,
Reviewed-by: Pankaj Patil <pankaj.patil@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH 3/8] arm64: dts: qcom: sm8450: Modify GPU operating points
From: Konrad Dybcio @ 2026-06-23 11:23 UTC (permalink / raw)
To: esteuwu, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-3-37e2ee8df9da@proton.me>
On 6/23/26 2:54 AM, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
>
> These frecuencies don't exist in downstream device trees.
> Both 220MHz and 285MHz belong to SM8475, and I'm not sure where 317MHz
> came from.
>
> Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
> ---
> arch/arm64/boot/dts/qcom/sm8450.dtsi | 15 ---------------
> 1 file changed, 15 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
> index e34e3c05bf74..5e331a25e22a 100644
> --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
> @@ -2495,21 +2495,6 @@ opp-350000000 {
> opp-hz = /bits/ 64 <350000000>;
> opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
> };
> -
> - opp-317000000 {
> - opp-hz = /bits/ 64 <317000000>;
> - opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
> - };
> -
> - opp-285000000 {
> - opp-hz = /bits/ 64 <285000000>;
> - opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS_D1>;
> - };
> -
> - opp-220000000 {
> - opp-hz = /bits/ 64 <220000000>;
> - opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS_D1>;
> - };
These are valid frequency points, although downstream didn't advertize
them.
Funnily enough, the frequency plan lists them as:
LOWSVS_D2 -> 317 MHz // in downstream, at LOW_SVS
LOWSVS_D1 -> 285 MHz // in downstream as-is
LOWSVS_D0 -> 220 MHz // in downstream, LOW_SVS_D1
(the above are what it says in the doc, yes, lower voltage for
higher frequencies.. certainly seems like a bug..)
LOW_SVS -> 350 Mhz // this and the following are in downstream too
LOW_SVS_L1-> 421 MHz
SVS -> 492 MHz
SVS_L0 -> 545 MHz
SVS_L1 -> 599 MHz
SVS_L2 -> 640 MHz
NOM -> 734 MHz
NOM_L1 -> 791 MHz
TURBO -> 818 MHz
so in short, the existing map seems to be OK
Konrad
^ permalink raw reply
* Re: [PATCH 5/8] iommu/arm-smmu-qcom: Add SM8450 MDSS compatible
From: Konrad Dybcio @ 2026-06-23 11:23 UTC (permalink / raw)
To: esteuwu, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-5-37e2ee8df9da@proton.me>
On 6/23/26 2:54 AM, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
>
> Add the compatible for the MDSS client on the Snapdragon 8 Gen 1 so it
> can be properly configured by the IOMMU driver.
>
> Otherwise, there is an unhandled context fault.
"because the framebuffer is already configured in UEFI"
>
> Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* [PATCH] arm64: dts: qcom: eliza: Fix disp_cc_mdss_mdp_clk_src RCG stall on Eliza EVK
From: Krzysztof Kozlowski @ 2026-06-23 11:27 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-arm-msm, devicetree, linux-kernel
Cc: Krzysztof Kozlowski
Eliza EVK (eliza-cqs-evk.dts) does not have display enabled, however its
Display Clock Controller is enabled and references parent clocks from
DSI PHYs. Devices which in base DTSI do not have all required resources
available (e.g. because they are simply disabled), should not be enabled
in the first place.
Having DISPCC enabled without DSI PHYs causes clock reparenting issues
and warning on Eliza EVK:
disp_cc_mdss_mdp_clk_src: rcg didn't update its configuration.
WARNING: drivers/clk/qcom/clk-rcg2.c:136 at update_config+0xd4/0xe4, CPU#1: udevd/273
...
update_config (drivers/clk/qcom/clk-rcg2.c:136 (discriminator 2)) (P)
clk_rcg2_shared_disable (drivers/clk/qcom/clk-rcg2.c:1471)
clk_rcg2_shared_init (drivers/clk/qcom/clk-rcg2.c:1540)
__clk_register (drivers/clk/clk.c:3959 drivers/clk/clk.c:4368)
devm_clk_hw_register (drivers/clk/clk.c:4448 (discriminator 1) drivers/clk/clk.c:4672 (discriminator 1))
devm_clk_register_regmap (drivers/clk/qcom/clk-regmap.c:104)
qcom_cc_really_probe (drivers/clk/qcom/common.c:418)
qcom_cc_probe (drivers/clk/qcom/common.c:445)
disp_cc_eliza_probe (dispcc-eliza.c:?) dispcc_eliza
platform_probe (drivers/base/platform.c:1432)
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/eliza-mtp.dts | 4 ++++
arch/arm64/boot/dts/qcom/eliza.dtsi | 1 +
2 files changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/eliza-mtp.dts b/arch/arm64/boot/dts/qcom/eliza-mtp.dts
index 7b42e37e5bf8..28063e952f69 100644
--- a/arch/arm64/boot/dts/qcom/eliza-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/eliza-mtp.dts
@@ -425,6 +425,10 @@ vreg_l7k: ldo7 {
};
};
+&dispcc {
+ status = "okay";
+};
+
&gpi_dma1 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/eliza.dtsi b/arch/arm64/boot/dts/qcom/eliza.dtsi
index aa72d5f042a7..5b62272e242f 100644
--- a/arch/arm64/boot/dts/qcom/eliza.dtsi
+++ b/arch/arm64/boot/dts/qcom/eliza.dtsi
@@ -3220,6 +3220,7 @@ dispcc: clock-controller@af00000 {
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
+ status = "disabled";
};
videocc: clock-controller@aaf0000 {
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v2 03/12] iio: adc: at91-sama5d2_adc: adapt the driver for sama7d65
From: sashiko-bot @ 2026-06-23 11:28 UTC (permalink / raw)
To: Varshini Rajendran; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260623105944.128840-4-varshini.rajendran@microchip.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Uninitialized touch channel indices incorrectly configure regular channel 0 as a touchscreen channel, breaking IIO buffered reads.
- [High] Temperature channel scan_index (31) exceeds the defined max_index (25), breaking IIO bitmap validations and hardware triggers.
--
commit 2d567bf99b76168b7ea132082c84ddd5029c1706
Author: Varshini Rajendran <varshini.rajendran@microchip.com>
iio: adc: at91-sama5d2_adc: adapt the driver for sama7d65
Add support for sama7d65 ADC. The differences are highlighted with the
compatible. The calibration data layout is the main difference.
> diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
> index b569d175f4c3d..237d339f342a1 100644
> --- a/drivers/iio/adc/at91-sama5d2_adc.c
> +++ b/drivers/iio/adc/at91-sama5d2_adc.c
[ ... ]
> @@ -768,6 +778,24 @@ static const struct at91_adc_platform sama7g5_platform = {
> .temp_calib_layout = &sama7g5_temp_calib,
> };
>
> +static const struct at91_adc_platform sama7d65_platform = {
> + .layout = &sama7g5_layout,
> + .adc_channels = &at91_sama7g5_adc_channels,
> + .nr_channels = AT91_SAMA7G5_SINGLE_CHAN_CNT +
> + AT91_SAMA7G5_DIFF_CHAN_CNT +
> + AT91_SAMA7G5_TEMP_CHAN_CNT,
[Severity: High]
This isn't a bug introduced by this patch, but inherited from the SAMA7G5
implementation. Does omitting the touch channel indices cause an issue for
channel 0?
By omitting touch_chan_x and similar fields, they default to 0. Later,
during probe, this zero-initialized value is used:
at91_adc_probe() {
...
bitmap_set(&st->touch_st.channels_bitmask,
st->soc_info.platform->touch_chan_x, 1);
...
}
Will this cause the driver to incorrectly set bit 0 in the touchscreen
bitmask, diverting regular channel 0 captures into the touchscreen logic
and breaking IIO buffered reads for that channel?
> + .max_channels = ARRAY_SIZE(at91_sama7g5_adc_channels),
> + .max_index = AT91_SAMA7G5_MAX_CHAN_IDX,
[Severity: High]
This is also a pre-existing issue inherited from the SAMA7G5 implementation,
but does this max_index configuration conflict with the temperature channel?
The max_index is configured to 25 (AT91_SAMA7G5_MAX_CHAN_IDX), but the
temperature channel has a scan_index of 31. This mismatch appears to break
IIO bitmap validations and hardware triggers.
For instance, in the hardware enablement path:
at91_adc_active_scan_mask_to_reg() {
...
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
...
return mask & GENMASK(st->soc_info.platform->nr_channels, 0);
}
This applies a 26-bit mask, which permanently ignores the temperature channel
at index 31. Does this structurally break the temperature channel for IIO
buffered reads by causing the core to expect data that the driver never
fetches?
> + .hw_trig_cnt = AT91_SAMA7G5_HW_TRIG_CNT,
> + .osr_mask = GENMASK(18, 16),
> + .oversampling_avail = { 1, 4, 16, 64, 256, },
> + .oversampling_avail_no = 5,
> + .chan_realbits = 16,
> + .temp_sensor = true,
> + .temp_chan = AT91_SAMA7G5_ADC_TEMP_CHANNEL,
> + .temp_calib_layout = &sama7d65_temp_calib,
> +};
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623105944.128840-1-varshini.rajendran@microchip.com?part=3
^ permalink raw reply
* Re: [PATCH 2/2] arm64: dts: socfpga: agilex7-gen2: Add initial device tree
From: sashiko-bot @ 2026-06-23 11:28 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260623111716.16690-3-muhammad.nazim.amirul.nazle.asmade@altera.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] Missing mandatory ARM architected timer (`arm,armv8-timer`) node.
- [High] The ATF (ARM Trusted Firmware) reserved memory is improperly declared as a shared DMA pool.
- [Medium] Missing Energy Aware Scheduling (EAS) capacity and topology maps for heterogeneous big.LITTLE CPUs.
- [Medium] Missing UART/serial console and `chosen` node.
- [Medium] Missing VGIC maintenance interrupt in the GICv3 node.
- [Low] Invalid combination of `reg` and `alignment` properties in `reserved-memory` nodes.
- [Low] Incorrect `#address-cells` for 64-bit CPUs.
--
commit 686f550501dd7f94cdc969838594ed32ff4cbd42
Author: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
arm64: dts: socfpga: agilex7-gen2: Add initial device tree
This patch adds the initial device tree support for the Intel SoCFPGA Agilex7
Gen2 platform. It includes the SoC DTSI and the SoCDK board DTS, featuring
a heterogeneous CPU cluster with Cortex-A520 and Cortex-A720 cores.
> diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2.dtsi
> new file mode 100644
> index 0000000000000..e3b777408f9a6
> --- /dev/null
> +++ b/arch/arm64/boot/dts/intel/socfpga_agilex7_gen2.dtsi
> @@ -0,0 +1,119 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026, Altera Corporation
> + */
> +/dts-v1/;
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/interrupt-controller/irq.h>
> +
> +/ {
> + compatible = "intel,socfpga-agilex7-gen2";
> + #address-cells = <2>;
> + #size-cells = <2>;
[Severity: Critical]
Is it intentional to omit the arm,armv8-timer node from the root level? Without
the architectural timer node, the system may fail to establish a clocksource
and clockevents, which typically leads to an indefinite hang during early boot
when timer_probe() fails.
[Severity: Medium]
Does this platform need a chosen node and UART serial console configured at
the root level? Omitting them usually results in no interactive console or
kernel boot logs over serial, which makes early boot validation very difficult.
> +
> + reserved-memory {
> + #address-cells = <2>;
> + #size-cells = <2>;
> + ranges;
> +
> + atf_reserved: atf@80000000 {
> + compatible = "shared-dma-pool";
[Severity: High]
Does declaring the ATF reserved memory as a shared-dma-pool expose the secure
EL3 memory region to the kernel's DMA allocator? If the kernel resolves a DMA
allocation to this region and a device writes to it, it could overwrite the
TrustZone firmware, potentially triggering a secure access violation (SError).
> + reg = <0x0 0x80000000 0x0 0x100000>;
> + alignment = <0x1000>;
[Severity: Low]
Is it necessary to include the alignment property when reg is already
explicitly provided? Device tree schema validation typically rejects combining
reg and alignment in reserved-memory nodes, as the kernel parser typically
ignores alignment when reg is present.
> + no-map;
> + };
> +
> + service_reserved: svcbuffer@80100000 {
> + compatible = "shared-dma-pool";
> + reg = <0x0 0x80100000 0x0 0xf00000>;
> + alignment = <0x1000>;
[Severity: Low]
Similar to the ATF reserved node, is the alignment property needed here when a
reg property is explicitly defined?
> + no-map;
> + };
> + };
> +
> + cpus {
> + #address-cells = <1>;
[Severity: Low]
Should #address-cells be 2 for 64-bit ARM CPUs? While it might work if the
Aff3 field is zero, setting it to 1 truncates the MPIDR_EL1 representation to
32 bits and violates ARM64 device tree binding conventions.
> + #size-cells = <0>;
> +
> + cpu0: cpu@0 {
> + compatible = "arm,cortex-a520";
> + device_type = "cpu";
> + enable-method = "psci";
> + reg = <0x0>;
> + };
[ ... ]
> + cpu3: cpu@300 {
> + compatible = "arm,cortex-a720";
[Severity: Medium]
Are the Energy Aware Scheduling (EAS) capacity and topology maps missing for
these heterogeneous cores? Without them, the scheduler might treat the
Cortex-A520 and Cortex-A720 as having identical performance capabilities,
leading to suboptimal task placement.
> + device_type = "cpu";
> + enable-method = "psci";
> + reg = <0x300>;
> + };
> + };
> +
> + psci {
> + compatible = "arm,psci-0.2";
> + method = "smc";
> + };
> +
> + intc: interrupt-controller@7000000 {
> + compatible = "arm,gic-v3";
> + reg = <0x0 0x7000000 0x0 0x10000>,
> + <0x0 0x7080000 0x0 0x100000>;
> + ranges;
> + #interrupt-cells = <3>;
> + #address-cells = <2>;
> + #size-cells = <2>;
> + interrupt-controller;
> + #redistributor-regions = <1>;
> + redistributor-stride = <0x0 0x40000>;
[Severity: Medium]
Does the GICv3 node need to declare a VGIC maintenance interrupt? Without this
interrupt, the KVM hypervisor might not receive maintenance interrupts,
which can break virtualized interrupt state management for guest VMs.
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623111716.16690-1-muhammad.nazim.amirul.nazle.asmade@altera.com?part=2
^ permalink raw reply
* Re: [PATCH net] net: ethernet: qualcomm: ppe: Demote from supported and fix maintainer addresses
From: Andrew Lunn @ 2026-06-23 11:31 UTC (permalink / raw)
To: Jie Luo
Cc: Krzysztof Kozlowski, Bjorn Andersson, Michael Turquette,
Stephen Boyd, Brian Masney, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Lei Wei, Suruchi Agarwal, Pavithra R,
linux-kernel, linux-arm-msm, linux-clk, devicetree, netdev
In-Reply-To: <8b0560ae-af5c-4d54-be02-d186be1d799c@oss.qualcomm.com>
On Tue, Jun 23, 2026 at 05:42:34PM +0800, Jie Luo wrote:
>
>
> On 6/23/2026 4:10 PM, Andrew Lunn wrote:
> >> Driver is not supported - in terms of how netdev understands supported
> >> commitment - if maintainer does not care to receive the patches for its
> >> code, so demote it to "maintained" to reflect true status.
> >
> > Maybe "Orphan" would be better, if the listed Maintainer is not doing
> > any Maintainer work?
> >
> > Andrew
>
> Hello Andrew, Krzysztof,
> I will continue to maintain the listed drivers, so their status can
> remain Supported.
Please understand that being a Maintainer requires that you respond to
patches and questions about this driver, give Reviewed-by:, ask for
patches to be changed etc. If you don't respond, ideally with 2 to 3
days, the driver will be set to Orphaned.
If you want to maintain the Supported status, we can help you set up
the needed CI system, and get it registered so it reports the results.
Andrew
^ permalink raw reply
* Re: [PATCH] arm64: dts: qcom: eliza: Fix disp_cc_mdss_mdp_clk_src RCG stall on Eliza EVK
From: Krzysztof Kozlowski @ 2026-06-23 11:31 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20260623112755.317180-2-krzysztof.kozlowski@oss.qualcomm.com>
On 23/06/2026 13:27, Krzysztof Kozlowski wrote:
> Eliza EVK (eliza-cqs-evk.dts) does not have display enabled, however its
> Display Clock Controller is enabled and references parent clocks from
> DSI PHYs. Devices which in base DTSI do not have all required resources
> available (e.g. because they are simply disabled), should not be enabled
> in the first place.
>
> Having DISPCC enabled without DSI PHYs causes clock reparenting issues
> and warning on Eliza EVK:
>
> disp_cc_mdss_mdp_clk_src: rcg didn't update its configuration.
> WARNING: drivers/clk/qcom/clk-rcg2.c:136 at update_config+0xd4/0xe4, CPU#1: udevd/273
> ...
> update_config (drivers/clk/qcom/clk-rcg2.c:136 (discriminator 2)) (P)
> clk_rcg2_shared_disable (drivers/clk/qcom/clk-rcg2.c:1471)
> clk_rcg2_shared_init (drivers/clk/qcom/clk-rcg2.c:1540)
> __clk_register (drivers/clk/clk.c:3959 drivers/clk/clk.c:4368)
> devm_clk_hw_register (drivers/clk/clk.c:4448 (discriminator 1) drivers/clk/clk.c:4672 (discriminator 1))
> devm_clk_register_regmap (drivers/clk/qcom/clk-regmap.c:104)
> qcom_cc_really_probe (drivers/clk/qcom/common.c:418)
> qcom_cc_probe (drivers/clk/qcom/common.c:445)
> disp_cc_eliza_probe (dispcc-eliza.c:?) dispcc_eliza
> platform_probe (drivers/base/platform.c:1432)
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/eliza-mtp.dts | 4 ++++
> arch/arm64/boot/dts/qcom/eliza.dtsi | 1 +
> 2 files changed, 5 insertions(+)
I should call it RFC, because this feels like a band-aid and should be
fixed in clock drivers maybe. Eventually DISPCC should be enabled on
Eliza EVK for HDMI, but DSI PHY will stay disabled.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH net] net: ethernet: qualcomm: ppe: Demote from supported and fix maintainer addresses
From: Andrew Lunn @ 2026-06-23 11:33 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Jie Luo, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Lei Wei, Suruchi Agarwal, Pavithra R, linux-kernel,
linux-arm-msm, linux-clk, devicetree, netdev
In-Reply-To: <f8441903-c768-46a1-8f95-b1b25d420a2c@oss.qualcomm.com>
> If address did not work for half a year, I really doubt that you commit
> to above.
I tend to agree. Maybe we should set it to Orphaned, and then decide
in 6 months time if it can be set back to Maintained?
Andrew
^ permalink raw reply
* Re: [PATCH v11 3/5] iio: adc: versal-sysmon: add I2C driver
From: Erim, Salih @ 2026-06-23 11:33 UTC (permalink / raw)
To: jic23, andy
Cc: dlechner, nuno.sa, robh, krzk+dt, conor+dt, conall.ogriofa,
michal.simek, linux, erimsalih, linux-iio, devicetree,
linux-kernel, Andy Shevchenko
In-Reply-To: <20260623014036.3865402-4-salih.erim@amd.com>
Addressing Sashiko findings on this patch:
- [High] Non-atomic I2C read transaction releases the bus lock,
making it vulnerable to bus interleaving.
The SysMon I2C interface is typically on a dedicated bus with
no other devices. The current implementation works correctly
in all tested configurations. Switching to i2c_transfer() with
Repeated Start would match the TRM protocol diagram but would
require hardware testing on a board with I2C-accessible SysMon.
No change for now.
Thanks,
Salih
On 23/06/2026 02:40, Salih Erim wrote:
> Add an I2C transport driver for the Versal SysMon block. The SysMon
> provides an I2C slave interface that allows an external master to
> read voltage and temperature measurements through the same register
> map used by the MMIO path.
>
> The I2C command frame is an 8-byte structure containing a 4-byte data
> payload, a 2-byte register offset, and a 1-byte instruction field.
> Read operations send the frame with a read instruction, then receive
> a 4-byte response containing the register value.
>
> Events are not supported on the I2C path because there is no
> interrupt line and the I2C regmap backend cannot be called from
> atomic context.
>
> Co-developed-by: Conall O'Griofa <conall.ogriofa@amd.com>
> Signed-off-by: Conall O'Griofa <conall.ogriofa@amd.com>
> Signed-off-by: Salih Erim <salih.erim@amd.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
> ---
> Changes in v11:
> - No code changes
>
> Changes in v10:
> - No code changes
>
> Changes in v9:
> - Add Reviewed-by tag from Andy Shevchenko
> - Add MODULE_IMPORT_NS("VERSAL_SYSMON") (Andy, from P2 namespace)
>
> Changes in v8:
> - Add volatile register comment for regmap cache (Andy)
> - Update devm_versal_sysmon_core_probe call site (Andy, from P2 rename)
>
> Changes in v7:
> - No code changes
>
> Changes in v6:
> - Add types.h include (IWYU) (Andy)
> - Add local struct device *dev, join devm_regmap_init on
> one line (Andy)
>
> Changes in v5:
> - Add err.h, mod_devicetable.h includes (IWYU) (Andy)
>
> Changes in v4:
> - Replace enum with defines for I2C frame offsets (Jonathan)
> - Use get_unaligned_le32() for read data reassembly (Jonathan)
> - Use put_unaligned_le32/le16() for write data and register offset
> packing (Jonathan)
> - Named initializer in i2c_device_id (Jonathan)
> - Drop bitfield.h, add unaligned.h (FIELD_GET/FIELD_PREP replaced
> by unaligned accessors)
>
> Changes in v3:
> - IWYU: fix includes (Andy)
> - Enum: assign all values explicitly for HW-mapped fields (Andy)
> - Remove sysmon_i2c wrapper struct, pass i2c_client directly
> (Andy)
> - Use sizeof() for I2C buffer lengths instead of defines (Andy)
> - Use = { } instead of = { 0 } for initializers (Andy)
> - Use single compatible xlnx,versal-sysmon (Krzysztof)
> - Adapt to core_probe interface change: irq moved to core,
> remove irq parameter from bus driver (Jonathan)
>
> Changes in v2:
> - New patch (I2C was deferred to Series B in v1)
> - Uses regmap API with custom I2C read/write callbacks
> - Shares core module with MMIO driver via sysmon_core_probe()
> - No event support (I2C has no interrupt line)
> - Separate VERSAL_SYSMON_I2C Kconfig symbol
> - Reverse Christmas Tree variable ordering in read/write functions
> drivers/iio/adc/Kconfig | 13 +++
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/versal-sysmon-i2c.c | 134 ++++++++++++++++++++++++++++
> 3 files changed, 148 insertions(+)
> create mode 100644 drivers/iio/adc/versal-sysmon-i2c.c
>
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index c7f19057484..8f9fc9de74a 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -1963,6 +1963,19 @@ config VERSAL_SYSMON
> To compile this driver as a module, choose M here: the module
> will be called versal-sysmon.
>
> +config VERSAL_SYSMON_I2C
> + tristate "AMD Versal SysMon I2C driver"
> + depends on I2C
> + select VERSAL_SYSMON_CORE
> + help
> + Say yes here to have support for the AMD/Xilinx Versal System
> + Monitor (SysMon) via I2C interface. This driver enables voltage
> + and temperature monitoring when the Versal chip has SysMon
> + configured with I2C access.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called versal-sysmon-i2c.
> +
> config VF610_ADC
> tristate "Freescale vf610 ADC driver"
> depends on HAS_IOMEM
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index d7696b1b157..5abb611fe46 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -169,6 +169,7 @@ obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
> obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
> obj-$(CONFIG_VERSAL_SYSMON_CORE) += versal-sysmon-core.o
> obj-$(CONFIG_VERSAL_SYSMON) += versal-sysmon.o
> +obj-$(CONFIG_VERSAL_SYSMON_I2C) += versal-sysmon-i2c.o
> obj-$(CONFIG_VF610_ADC) += vf610_adc.o
> obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
> obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o
> diff --git a/drivers/iio/adc/versal-sysmon-i2c.c b/drivers/iio/adc/versal-sysmon-i2c.c
> new file mode 100644
> index 00000000000..e9a7629159a
> --- /dev/null
> +++ b/drivers/iio/adc/versal-sysmon-i2c.c
> @@ -0,0 +1,134 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * AMD Versal SysMon I2C driver
> + *
> + * Copyright (C) 2023 - 2026, Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/types.h>
> +#include <linux/unaligned.h>
> +
> +#include "versal-sysmon.h"
> +
> +#define SYSMON_I2C_INSTR_READ BIT(2)
> +#define SYSMON_I2C_INSTR_WRITE BIT(3)
> +
> +/*
> + * I2C command frame layout (8 bytes):
> + * [0..3] data payload (little-endian u32)
> + * [4..5] register offset >> 2 (little-endian u16)
> + * [6] instruction (read/write)
> + * [7] reserved
> + */
> +#define SYSMON_I2C_DATA_OFS 0
> +#define SYSMON_I2C_REG_OFS 4
> +#define SYSMON_I2C_INSTR_OFS 6
> +
> +static int sysmon_i2c_reg_read(void *context, unsigned int reg,
> + unsigned int *val)
> +{
> + struct i2c_client *client = context;
> + u8 write_buf[8] = { };
> + u8 read_buf[4];
> + int ret;
> +
> + put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]);
> + write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_READ;
> +
> + ret = i2c_master_send(client, write_buf, sizeof(write_buf));
> + if (ret < 0)
> + return ret;
> + if (ret != sizeof(write_buf))
> + return -EIO;
> +
> + ret = i2c_master_recv(client, read_buf, sizeof(read_buf));
> + if (ret < 0)
> + return ret;
> + if (ret != sizeof(read_buf))
> + return -EIO;
> +
> + *val = get_unaligned_le32(read_buf);
> +
> + return 0;
> +}
> +
> +static int sysmon_i2c_reg_write(void *context, unsigned int reg,
> + unsigned int val)
> +{
> + struct i2c_client *client = context;
> + u8 write_buf[8] = { };
> + int ret;
> +
> + put_unaligned_le32(val, &write_buf[SYSMON_I2C_DATA_OFS]);
> + put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]);
> + write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_WRITE;
> +
> + ret = i2c_master_send(client, write_buf, sizeof(write_buf));
> + if (ret < 0)
> + return ret;
> + if (ret != sizeof(write_buf))
> + return -EIO;
> +
> + return 0;
> +}
> +
> +/*
> + * Almost all registers are volatile (live ADC readings, interrupt
> + * status). The rest are not accessed often enough to benefit from
> + * caching.
> + */
> +static const struct regmap_config sysmon_i2c_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = SYSMON_REG_STRIDE,
> + .max_register = SYSMON_MAX_REG,
> + .reg_read = sysmon_i2c_reg_read,
> + .reg_write = sysmon_i2c_reg_write,
> +};
> +
> +static int sysmon_i2c_probe(struct i2c_client *client)
> +{
> + struct device *dev = &client->dev;
> + struct regmap *regmap;
> +
> + regmap = devm_regmap_init(dev, NULL, client, &sysmon_i2c_regmap_config);
> + if (IS_ERR(regmap))
> + return PTR_ERR(regmap);
> +
> + /* I2C has no IRQ connection; events are not supported */
> + return devm_versal_sysmon_core_probe(dev, regmap);
> +}
> +
> +static const struct of_device_id sysmon_i2c_of_match_table[] = {
> + { .compatible = "xlnx,versal-sysmon" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, sysmon_i2c_of_match_table);
> +
> +static const struct i2c_device_id sysmon_i2c_id_table[] = {
> + { .name = "versal-sysmon" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, sysmon_i2c_id_table);
> +
> +static struct i2c_driver sysmon_i2c_driver = {
> + .probe = sysmon_i2c_probe,
> + .driver = {
> + .name = "versal-sysmon-i2c",
> + .of_match_table = sysmon_i2c_of_match_table,
> + },
> + .id_table = sysmon_i2c_id_table,
> +};
> +module_i2c_driver(sysmon_i2c_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("AMD Versal SysMon I2C Driver");
> +MODULE_IMPORT_NS("VERSAL_SYSMON");
> +MODULE_AUTHOR("Conall O'Griofa <conall.ogriofa@amd.com>");
> +MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
^ permalink raw reply
* Re: [PATCH 7/8] phy: qcom: qmp-combo: Correct pre-emphasis table for QMP v4 DP PHYs
From: Konrad Dybcio @ 2026-06-23 11:36 UTC (permalink / raw)
To: esteuwu, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong, Dmitry Baryshkov
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-7-37e2ee8df9da@proton.me>
On 6/23/26 2:54 AM, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
>
> Comparing sm8350 and sm8450 tables, this seems to be typo.
>
> Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
> ---
> drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> index 9bd666ac2c49..5b278fd54a16 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> @@ -2108,7 +2108,7 @@ static const u8 qmp_dp_v4_pre_emphasis_hbr3_hbr2[4][4] = {
> static const u8 qmp_dp_v4_pre_emphasis_hbr_rbr[4][4] = {
> { 0x00, 0x0d, 0x14, 0x1a },
> { 0x00, 0x0e, 0x15, 0xff },
> - { 0x00, 0x0d, 0xff, 0xff },
> + { 0x00, 0x0e, 0xff, 0xff },
> { 0x03, 0xff, 0xff, 0xff }
It seems like 8350/8450 should be using what this driver calls
v5 tables, with this fixup:
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index cdcfad2e86b1..63a4f2127e3c 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -2134,7 +2134,7 @@ static const u8 qmp_dp_v5_voltage_swing_hbr3_hbr2[4][4] = {
};
static const u8 qmp_dp_v5_pre_emphasis_hbr_rbr[4][4] = {
- { 0x20, 0x2d, 0x34, 0x3a },
+ { 0x20, 0x2e, 0x35, 0x3b },
{ 0x20, 0x2e, 0x35, 0xff },
{ 0x20, 0x2e, 0xff, 0xff },
{ 0x24, 0xff, 0xff, 0xff }
+Dmitry please confirm
Konrad
^ permalink raw reply related
* Re: [PATCH v11 4/5] iio: adc: versal-sysmon: add threshold event support
From: Erim, Salih @ 2026-06-23 11:36 UTC (permalink / raw)
To: jic23, andy
Cc: dlechner, nuno.sa, robh, krzk+dt, conor+dt, conall.ogriofa,
michal.simek, linux, erimsalih, linux-iio, devicetree,
linux-kernel, Andy Shevchenko
In-Reply-To: <20260623014036.3865402-5-salih.erim@amd.com>
Addressing Sashiko findings on this patch:
- [High] Use-After-Free due to flawed devres initialization order
for the delayed worker.
sysmon_disable_interrupts masks all interrupts via SYSMON_IDR
before cancelling the worker. Once masked, no new interrupts
fire and the handler cannot re-schedule the work. The IRQ
handler only schedules work after processing active ISR bits,
which requires unmasked interrupts. No issue.
- [High] Error paths in the IRQ handler skip clearing hardware
flags but unconditionally return IRQ_HANDLED.
Theoretical only. The regmap uses MMIO with fast_io, so
regmap_write cannot fail. The error paths exist for API
correctness. No change needed.
- [High] The delayed worker clears all pending interrupts,
causing voltage alarms to be lost.
The worker only runs when temperature interrupts are masked.
Supply alarms are handled directly in the IRQ handler and are
never masked. A concurrent voltage alarm between the worker's
ISR read and write could theoretically be cleared but the
window is narrow and not observed in testing. No change needed.
- [Medium] Atomic context violation on I2C devices.
The I2C path does not register an IRQ handler.
fwnode_irq_get() returns 0 for I2C nodes and
sysmon_init_interrupt skips IRQ registration. Not applicable.
- [Medium] Negative temperatures invoke undefined left-shift
behavior and are not masked to 16 bits.
Addressed in v11 with bounds checking. Temperature threshold
writes are now validated against the Q8.7 range (-256000 to
255992 mC) before conversion. Out-of-range values return
-EINVAL. The computed lower threshold is also clamped.
- [Medium] Race condition between sysfs event disable and the
unmask worker.
The worker runs on a 500ms delayed schedule. The race window
between the IDR write and temp_mask update is microseconds.
If the worker runs in this window, it self-corrects on the
next cycle. No change needed.
- [Medium] Cached hysteresis value is not reverted if the
hardware threshold write fails.
The regmap uses MMIO with fast_io. MMIO writes cannot fail.
The error path exists for API correctness. No change needed.
Thanks,
Salih
On 23/06/2026 02:40, Salih Erim wrote:
> Add threshold event support for temperature and supply voltage
> channels.
>
> Temperature events:
> - Rising threshold with configurable value on the device
> temperature channel (current max across all satellites)
> - Per-channel hysteresis as a millicelsius value
> - Event direction is IIO_EV_DIR_RISING (hysteresis mode)
>
> Supply voltage events:
> - Rising/falling threshold per supply channel
> - Per-channel alarm enable via alarm configuration registers
>
> The hardware supports both window and hysteresis alarm modes for
> temperature. This driver uses hysteresis mode, where the upper
> threshold triggers the alarm and the lower threshold clears it
> (re-arm point). The hardware has a single ISR bit per temperature
> channel with no indication of which threshold was crossed, so
> hysteresis mode is the natural fit. The lower threshold register
> is computed internally as (upper - hysteresis).
>
> Hysteresis is stored in the driver as a millicelsius value,
> initialized from the hardware registers at probe. Writing the
> rising threshold or hysteresis recomputes the lower register.
> ALARM_CONFIG is hard-coded to hysteresis mode during init.
>
> The hardware also provides a separate over-temperature (OT)
> threshold, but it is not exposed through IIO as it serves as a
> hardware safety mechanism for platform shutdown. OT will be
> exposed through the thermal framework in a follow-up series.
>
> The interrupt handler masks active threshold interrupts (which are
> level-sensitive) and schedules a delayed worker to poll for condition
> clear before unmasking. When no hardware IRQ is available, event
> specs are not attached and interrupt init is skipped, since the
> I2C regmap backend cannot be called from atomic context.
>
> When disabling a supply channel alarm, the group interrupt remains
> active if any other channel in the same alarm group still has an
> alarm enabled.
>
> A devm cleanup action masks all interrupts on driver unbind to
> prevent unhandled interrupt storms after the IRQ handler is freed.
>
> Signed-off-by: Salih Erim <salih.erim@amd.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
> ---
> Changes in v11:
> - Add bounds check for temperature threshold writes; return
> -EINVAL if out of Q8.7 range (Jonathan)
> - Add bounds check for supply voltage threshold writes to
> prevent integer overflow (Jonathan)
> - Clamp computed lower threshold to Q8.7 range in
> sysmon_update_temp_lower (found during audit)
> - Add comment explaining that threshold register upper bits
> (FMT/MODE) are ignored on write (Jonathan)
>
> Changes in v10:
> - Add Reviewed-by tag from Andy Shevchenko
> - Add limits.h include for U16_MAX, S16_MIN, S16_MAX (Andy)
>
> Changes in v9:
> - Add minmax.h include for clamp() (Andy)
> - Join sysmon_supply_thresh_offset to one line, change address
> parameter to unsigned long for consistency (Andy)
> - Combine mask declaration with initialization in
> sysmon_read_event_config (Andy)
> - Rename ier to mask in sysmon_write_event_config for
> consistency with sysmon_read_event_config (Andy)
> - Remove blank line in sysmon_update_temp_lower between
> semantically coupled lines (Andy)
> - Rename unmask to ier (u32) in sysmon_unmask_temp (Andy)
> - Variable name and type consistency audit across all
> event functions (Andy)
>
> Changes in v8:
> - Use MILLIDEGREE_PER_DEGREE in q8p7 conversion functions (Andy)
> - Use regmap_test_bits() in sysmon_read_alarm_config (Andy)
> - Join sysmon_parse_fw signature onto one line (Andy)
> - Fix devm teardown race: replace devm_delayed_work_autocancel
> with INIT_DELAYED_WORK; fold cancel_delayed_work_sync into
> sysmon_disable_interrupts to prevent the worker from
> re-enabling interrupts after the IRQ handler is freed (Sashiko)
> - Drop devm-helpers.h include (no longer needed)
>
> Changes in v7:
> - Move TEMP threshold event onto channel 0; drop OT as
> separate IIO channel -- OT is a hardware safety mechanism
> better suited for the thermal framework follow-up (Jonathan)
> - Use single temp_channels array; attach event spec to
> channel 0 at runtime when IRQ is available, matching the
> pattern used for supply channels (Jonathan)
> - Remove sysmon_temp_thresh_offset; use SYSMON_TEMP_TH_UP
> and SYSMON_TEMP_TH_LOW defines directly at call sites
> - Return administrative state from temp_mask in
> read_event_config instead of transient hardware IMR
> (Jonathan, Sashiko)
> - Add devm_add_action_or_reset to mask all HW interrupts
> on driver unbind (Sashiko)
> - Remove SYSMON_CHAN_TEMP_EVENT macro, SYSMON_ADDR_TEMP_EVENT,
> SYSMON_ADDR_OT_EVENT, SYSMON_BIT_OT, SYSMON_OT_HYST_MASK,
> OT_TH_LOW/UP registers, ot_hysteresis from struct
> - Simplify sysmon_get_event_mask, sysmon_update_temp_lower,
> sysmon_init_hysteresis -- all now operate on single TEMP
> channel only
>
>
> Changes in v6:
> - Remove types.h from header (not needed at any stage) (Andy)
> - Macro brace on separate line for SYSMON_CHAN_TEMP_EVENT (Andy)
> - switch(chan->type) in all event functions instead of cascading
> if statements (Andy)
> - switch(info) in read/write_event_value for nested
> dispatch (Andy)
> - Reversed xmas tree in sysmon_update_temp_lower and
> sysmon_init_hysteresis (Andy)
> - scoped_guard(spinlock_irq) with error check in
> sysmon_unmask_worker (Andy)
> - Combined regmap_read error check with || in
> sysmon_iio_irq (Andy)
> - Join devm_request_irq on one line (Andy)
> - Fix fwnode_irq_get() to propagate only -EPROBE_DEFER;
> treating all negatives as fatal broke probe on I2C nodes
> without interrupts property
>
> Changes in v5:
> - clamp() instead of clamp_t() (Andy)
> - regmap_assign_bits() instead of separate set/clear (Andy)
> - Remove unneeded parentheses (2 places) (Andy)
> - for_each_set_bit on single line (Andy)
> - regmap_clear_bits() instead of regmap_update_bits() (Andy)
> - Simplify unmask XOR to ~status & masked_temp (Andy)
> - Add comment explaining unmask &= ~temp_mask logic (Andy)
> - Split container_of across two lines (Andy)
> - Move ISR write after !isr check to avoid writing 0 (Andy)
> - unsigned int for init_hysteresis address param (Andy)
> - Add comment explaining error check policy in worker/IRQ (Andy)
> - Nested size_add() for overflow-safe allocation (Andy)
> - Propagate negative from fwnode_irq_get() for
> EPROBE_DEFER (Andy)
> - Pass irq instead of has_irq to sysmon_parse_fw (Andy)
>
> Changes in v4:
> - Merge event channels into static temp array; two arrays
> (with/without events) selected by has_irq (Jonathan)
> - Event-only channels have no info_mask; their addresses are
> logical identifiers, not readable registers
> - Drop RAW for voltage events, keep PROCESSED only (Jonathan)
> - Drop scan_type from event channel macro (Jonathan)
> - Blank lines between call+error-check blocks (Jonathan)
> - Fit under 80 chars on one line where possible (Jonathan)
> - default case returns -EINVAL instead of break (Jonathan)
> - sysmon_handle_event: return early in each case (Jonathan)
> - guard(spinlock) in sysmon_iio_irq, return IRQ_NONE/IRQ_HANDLED
> directly (Jonathan)
> - Take irq_lock in write_event_config for temp_mask updates to
> synchronize with unmask worker (Sashiko)
>
> Changes in v3:
> - IWYU: add new includes, group iio headers with blank line (Andy)
> - Reduce casts in millicelsius_to_q8p7, consistent style with
> q8p7_to_millicelsius (Andy)
> - Use clamp_t with typed constants, remove tmp & U16_MAX (Andy)
> - Use !! to return 0/1 from read_alarm_config (Andy)
> - Use regmap_set_bits/clear_bits in write_alarm_config (Andy)
> - Add comment explaining spinlock is safe (I2C never reaches
> event code path) (Andy)
> - Add comment explaining IMR negation logic (Andy)
> - Split read_event_value/write_event_value parameters logically
> across lines (Andy)
> - Move mask/shift after regmap_read error check (Andy)
> - Remove redundant else in read_event_value and
> write_event_value (Andy)
> - Use named constant for hysteresis bit, if-else not ternary
> (Andy)
> - Loop variable declared in for() scope (Andy)
> - Add error checks in sysmon_handle_event (Andy)
> - Use IRQ_RETVAL() macro (Andy)
> - Use devm_delayed_work_autocancel instead of manual INIT +
> devm_add_action (Andy)
> - Use FIELD_GET/FIELD_PREP for hysteresis register bits
> (Jonathan)
> - Split OT vs TEMP handling with FIELD_GET (Jonathan)
> - Rework hysteresis: store as millicelsius value, hardcode
> ALARM_CONFIG to hysteresis mode, compute lower threshold
> from (upper - hysteresis), initialize from HW at probe
> (Jonathan)
> - Remove falling threshold for temperature; single event
> spec per channel with IIO_EV_DIR_RISING (Jonathan)
> - Push IIO_EV_DIR_RISING events for temperature,
> IIO_EV_DIR_EITHER for voltage (Jonathan)
>
> Changes in v2:
> - Reverse Christmas Tree variable ordering in all functions
> - Named constants for hysteresis bits: SYSMON_OT_HYST_BIT,
> SYSMON_TEMP_HYST_BIT instead of magic 0x1/0x2
> - SYSMON_ALARM_BITS_PER_REG replaces magic number 32
> - SYSMON_ALARM_OFFSET() helper macro deduplicates alarm register
> offset computation
> - BIT() macro for shift expressions in conversion functions
> - Hysteresis input validated to single-bit range (0 or 1)
> - Event channels only created when irq > 0 (I2C safety)
> - Group alarm interrupt stays active while any channel in the
> group has an alarm enabled
> - write_event_value returns -EINVAL for unhandled types
> - IRQ_NONE returned for spurious interrupts
> - Q8.7 write path uses multiplication instead of left-shift
> to avoid undefined behavior with negative temperatures
> - (u16) mask prevents garbage in reserved register bits
> - regmap_write return values checked for IER/IDR writes
> - devm cleanup ordering: cancel_work before request_irq
> drivers/iio/adc/versal-sysmon-core.c | 613 ++++++++++++++++++++++++++-
> drivers/iio/adc/versal-sysmon.h | 36 ++
> 2 files changed, 645 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
> index 03a745d3fb4..8f2c502d9cb 100644
> --- a/drivers/iio/adc/versal-sysmon-core.c
> +++ b/drivers/iio/adc/versal-sysmon-core.c
> @@ -12,6 +12,9 @@
> #include <linux/cleanup.h>
> #include <linux/device.h>
> #include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/limits.h>
> +#include <linux/minmax.h>
> #include <linux/module.h>
> #include <linux/overflow.h>
> #include <linux/property.h>
> @@ -20,10 +23,18 @@
> #include <linux/sysfs.h>
> #include <linux/units.h>
>
> +#include <linux/iio/events.h>
> #include <linux/iio/iio.h>
>
> #include "versal-sysmon.h"
>
> +/* TEMP hysteresis mode bit in SYSMON_TEMP_EV_CFG */
> +#define SYSMON_TEMP_HYST_MASK BIT(1)
> +
> +/* Compute alarm register offset from a channel address */
> +#define SYSMON_ALARM_OFFSET(addr) \
> + (SYSMON_ALARM_REG + ((addr) / SYSMON_ALARM_BITS_PER_REG) * SYSMON_REG_STRIDE)
> +
> #define SYSMON_CHAN_TEMP(_chan, _address, _name) \
> { \
> .type = IIO_TEMP, \
> @@ -35,6 +46,45 @@
> .datasheet_name = _name, \
> }
>
> +enum sysmon_alarm_bit {
> + SYSMON_BIT_ALARM0 = 0,
> + SYSMON_BIT_ALARM1 = 1,
> + SYSMON_BIT_ALARM2 = 2,
> + SYSMON_BIT_ALARM3 = 3,
> + SYSMON_BIT_ALARM4 = 4,
> + SYSMON_BIT_TEMP = 9,
> +};
> +
> +/* Temperature event specification: rising threshold + hysteresis only */
> +static const struct iio_event_spec sysmon_temp_events[] = {
> + {
> + .type = IIO_EV_TYPE_THRESH,
> + .dir = IIO_EV_DIR_RISING,
> + .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
> + BIT(IIO_EV_INFO_VALUE) |
> + BIT(IIO_EV_INFO_HYSTERESIS),
> + },
> +};
> +
> +/* Supply event specifications */
> +static const struct iio_event_spec sysmon_supply_events[] = {
> + {
> + .type = IIO_EV_TYPE_THRESH,
> + .dir = IIO_EV_DIR_RISING,
> + .mask_separate = BIT(IIO_EV_INFO_VALUE),
> + },
> + {
> + .type = IIO_EV_TYPE_THRESH,
> + .dir = IIO_EV_DIR_FALLING,
> + .mask_separate = BIT(IIO_EV_INFO_VALUE),
> + },
> + {
> + .type = IIO_EV_TYPE_THRESH,
> + .dir = IIO_EV_DIR_EITHER,
> + .mask_separate = BIT(IIO_EV_INFO_ENABLE),
> + },
> +};
> +
> /*
> * Static temperature channels (always present).
> *
> @@ -52,6 +102,16 @@ static const struct iio_chan_spec temp_channels[] = {
> SYSMON_CHAN_TEMP(3, SYSMON_TEMP_MIN_MIN, "min_min"),
> };
>
> +static void sysmon_q8p7_to_millicelsius(s16 raw_data, int *val)
> +{
> + *val = (raw_data * MILLIDEGREE_PER_DEGREE) >> SYSMON_FRACTIONAL_SHIFT;
> +}
> +
> +static void sysmon_millicelsius_to_q8p7(u32 *raw_data, int val)
> +{
> + *raw_data = (val << SYSMON_FRACTIONAL_SHIFT) / MILLIDEGREE_PER_DEGREE;
> +}
> +
> static void sysmon_supply_rawtoprocessed(int raw_data, int *val)
> {
> int mantissa, format, exponent;
> @@ -69,6 +129,33 @@ static void sysmon_supply_rawtoprocessed(int raw_data, int *val)
> *val = (mantissa * (int)MILLI) >> exponent;
> }
>
> +static void sysmon_supply_processedtoraw(int val, u32 reg_val, u32 *raw_data)
> +{
> + int exponent = FIELD_GET(SYSMON_MODE_MASK, reg_val);
> + int format = FIELD_GET(SYSMON_FMT_MASK, reg_val);
> + int scale, tmp;
> +
> + scale = BIT(SYSMON_SUPPLY_MANTISSA_BITS - exponent);
> + tmp = (val * scale) / (int)MILLI;
> +
> + if (format)
> + tmp = clamp(tmp, S16_MIN, S16_MAX);
> + else
> + tmp = clamp(tmp, 0, U16_MAX);
> +
> + *raw_data = (u16)tmp;
> +}
> +
> +static int sysmon_supply_thresh_offset(unsigned long address, enum iio_event_direction dir)
> +{
> + if (dir == IIO_EV_DIR_RISING)
> + return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_UP;
> + if (dir == IIO_EV_DIR_FALLING)
> + return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_LOW;
> +
> + return -EINVAL;
> +}
> +
> static int sysmon_read_raw(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan,
> int *val, int *val2, long mask)
> @@ -115,6 +202,269 @@ static int sysmon_read_raw(struct iio_dev *indio_dev,
> }
> }
>
> +static u32 sysmon_get_event_mask(const struct iio_chan_spec *chan)
> +{
> + if (chan->type == IIO_TEMP)
> + return BIT(SYSMON_BIT_TEMP);
> +
> + return BIT(chan->address / SYSMON_ALARM_BITS_PER_REG);
> +}
> +
> +static int sysmon_read_alarm_config(struct sysmon *sysmon,
> + unsigned long address)
> +{
> + u32 shift = address % SYSMON_ALARM_BITS_PER_REG;
> + u32 offset = SYSMON_ALARM_OFFSET(address);
> +
> + return regmap_test_bits(sysmon->regmap, offset, BIT(shift));
> +}
> +
> +static int sysmon_write_alarm_config(struct sysmon *sysmon,
> + unsigned long address, bool enable)
> +{
> + u32 shift = address % SYSMON_ALARM_BITS_PER_REG;
> + u32 offset = SYSMON_ALARM_OFFSET(address);
> +
> + return regmap_assign_bits(sysmon->regmap, offset, BIT(shift), enable);
> +}
> +
> +static int sysmon_read_event_config(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir)
> +{
> + struct sysmon *sysmon = iio_priv(indio_dev);
> + u32 mask = sysmon_get_event_mask(chan);
> + unsigned int imr;
> + int config_value;
> + int ret;
> +
> + ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr);
> + if (ret)
> + return ret;
> +
> + /* IMR bits are 1=masked, invert to get 1=enabled */
> + imr = ~imr;
> +
> + switch (chan->type) {
> + case IIO_VOLTAGE:
> + config_value = sysmon_read_alarm_config(sysmon, chan->address);
> + if (config_value < 0)
> + return config_value;
> + return config_value && (imr & mask);
> +
> + case IIO_TEMP:
> + /*
> + * Return the administrative state, not the hardware IMR.
> + * The IRQ handler temporarily masks the interrupt during
> + * the polling window; reading IMR would show it as disabled.
> + * temp_mask bit is set when administratively disabled.
> + */
> + return !(sysmon->temp_mask & mask);
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int sysmon_write_event_config(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + bool state)
> +{
> + u32 offset = SYSMON_ALARM_OFFSET(chan->address);
> + struct sysmon *sysmon = iio_priv(indio_dev);
> + u32 mask = sysmon_get_event_mask(chan);
> + unsigned int alarm_config;
> + int ret;
> +
> + guard(mutex)(&sysmon->lock);
> +
> + switch (chan->type) {
> + case IIO_VOLTAGE:
> + ret = sysmon_write_alarm_config(sysmon, chan->address, state);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(sysmon->regmap, offset, &alarm_config);
> + if (ret)
> + return ret;
> +
> + if (alarm_config)
> + return regmap_write(sysmon->regmap, SYSMON_IER, mask);
> +
> + return regmap_write(sysmon->regmap, SYSMON_IDR, mask);
> +
> + case IIO_TEMP:
> + if (state) {
> + ret = regmap_write(sysmon->regmap, SYSMON_IER, mask);
> + if (ret)
> + return ret;
> +
> + scoped_guard(spinlock_irq, &sysmon->irq_lock)
> + sysmon->temp_mask &= ~mask;
> + } else {
> + ret = regmap_write(sysmon->regmap, SYSMON_IDR, mask);
> + if (ret)
> + return ret;
> +
> + scoped_guard(spinlock_irq, &sysmon->irq_lock)
> + sysmon->temp_mask |= mask;
> + }
> + return 0;
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +/*
> + * Recompute the lower threshold register from upper threshold and
> + * cached hysteresis. Called when either upper threshold or hysteresis
> + * is written.
> + */
> +static int sysmon_update_temp_lower(struct sysmon *sysmon)
> +{
> + unsigned int upper_reg;
> + int upper_mc, lower_mc;
> + u32 raw_val;
> + int ret;
> +
> + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
> + if (ret)
> + return ret;
> +
> + sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
> + lower_mc = clamp(upper_mc - sysmon->temp_hysteresis, -256000, 255992);
> + sysmon_millicelsius_to_q8p7(&raw_val, lower_mc);
> +
> + return regmap_write(sysmon->regmap, SYSMON_TEMP_TH_LOW, raw_val);
> +}
> +
> +static int sysmon_read_event_value(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + enum iio_event_info info,
> + int *val, int *val2)
> +{
> + struct sysmon *sysmon = iio_priv(indio_dev);
> + unsigned int reg_val;
> + int offset;
> + int ret;
> +
> + guard(mutex)(&sysmon->lock);
> +
> + switch (chan->type) {
> + case IIO_TEMP:
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, ®_val);
> + if (ret)
> + return ret;
> +
> + sysmon_q8p7_to_millicelsius(reg_val, val);
> +
> + return IIO_VAL_INT;
> +
> + case IIO_EV_INFO_HYSTERESIS:
> + *val = sysmon->temp_hysteresis;
> + return IIO_VAL_INT;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + case IIO_VOLTAGE:
> + offset = sysmon_supply_thresh_offset(chan->address, dir);
> + if (offset < 0)
> + return offset;
> +
> + ret = regmap_read(sysmon->regmap, offset, ®_val);
> + if (ret)
> + return ret;
> +
> + sysmon_supply_rawtoprocessed(reg_val, val);
> +
> + return IIO_VAL_INT;
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int sysmon_write_event_value(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + enum iio_event_info info,
> + int val, int val2)
> +{
> + struct sysmon *sysmon = iio_priv(indio_dev);
> + unsigned int reg_val;
> + u32 raw_val;
> + int offset;
> + int ret;
> +
> + guard(mutex)(&sysmon->lock);
> +
> + switch (chan->type) {
> + case IIO_TEMP:
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + /* Q8.7 signed range: -256000 to +255992 mC */
> + if (val < -256000 || val > 255992)
> + return -EINVAL;
> +
> + sysmon_millicelsius_to_q8p7(&raw_val, val);
> +
> + ret = regmap_write(sysmon->regmap, SYSMON_TEMP_TH_UP, raw_val);
> + if (ret)
> + return ret;
> +
> + /* Recompute lower = upper - hysteresis */
> + return sysmon_update_temp_lower(sysmon);
> +
> + case IIO_EV_INFO_HYSTERESIS:
> + if (val < 0)
> + return -EINVAL;
> +
> + sysmon->temp_hysteresis = val;
> +
> + return sysmon_update_temp_lower(sysmon);
> +
> + default:
> + return -EINVAL;
> + }
> +
> + case IIO_VOLTAGE:
> + offset = sysmon_supply_thresh_offset(chan->address, dir);
> + if (offset < 0)
> + return offset;
> +
> + ret = regmap_read(sysmon->regmap, offset, ®_val);
> + if (ret)
> + return ret;
> +
> + /* Clamp to prevent overflow in processedtoraw conversion */
> + if (val < -32768 || val > 32767)
> + return -EINVAL;
> +
> + sysmon_supply_processedtoraw(val, reg_val, &raw_val);
> +
> + /*
> + * The hardware threshold register returns FMT and MODE
> + * bits in the upper 16 bits on read, but only the lower
> + * 16-bit mantissa is used on write.
> + */
> + return regmap_write(sysmon->regmap, offset, raw_val);
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> static int sysmon_read_label(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan,
> char *label)
> @@ -128,20 +478,242 @@ static int sysmon_read_label(struct iio_dev *indio_dev,
> static const struct iio_info sysmon_iio_info = {
> .read_raw = sysmon_read_raw,
> .read_label = sysmon_read_label,
> + .read_event_config = sysmon_read_event_config,
> + .write_event_config = sysmon_write_event_config,
> + .read_event_value = sysmon_read_event_value,
> + .write_event_value = sysmon_write_event_value,
> };
>
> +static void sysmon_push_event(struct iio_dev *indio_dev, u32 address)
> +{
> + const struct iio_chan_spec *chan;
> + enum iio_event_direction dir;
> +
> + for (unsigned int i = 0; i < indio_dev->num_channels; i++) {
> + if (indio_dev->channels[i].address != address)
> + continue;
> +
> + chan = &indio_dev->channels[i];
> + /* Temp uses hysteresis mode (rising only), voltage uses window */
> + dir = (chan->type == IIO_TEMP) ? IIO_EV_DIR_RISING :
> + IIO_EV_DIR_EITHER;
> + iio_push_event(indio_dev,
> + IIO_UNMOD_EVENT_CODE(chan->type,
> + chan->channel,
> + IIO_EV_TYPE_THRESH,
> + dir),
> + iio_get_time_ns(indio_dev));
> + }
> +}
> +
> +static int sysmon_handle_event(struct iio_dev *indio_dev, u32 event)
> +{
> + u32 alarm_flag_offset = SYSMON_ALARM_FLAG + event * SYSMON_REG_STRIDE;
> + u32 alarm_reg_offset = SYSMON_ALARM_REG + event * SYSMON_REG_STRIDE;
> + struct sysmon *sysmon = iio_priv(indio_dev);
> + unsigned long alarm_flag_reg;
> + unsigned int reg_val;
> + u32 address, bit;
> + int ret;
> +
> + switch (event) {
> + case SYSMON_BIT_TEMP:
> + sysmon_push_event(indio_dev, SYSMON_TEMP_MAX);
> +
> + ret = regmap_write(sysmon->regmap, SYSMON_IDR, BIT(SYSMON_BIT_TEMP));
> + if (ret)
> + return ret;
> +
> + sysmon->masked_temp |= BIT(SYSMON_BIT_TEMP);
> + return 0;
> +
> + case SYSMON_BIT_ALARM0:
> + case SYSMON_BIT_ALARM1:
> + case SYSMON_BIT_ALARM2:
> + case SYSMON_BIT_ALARM3:
> + case SYSMON_BIT_ALARM4:
> + ret = regmap_read(sysmon->regmap, alarm_flag_offset, ®_val);
> + if (ret)
> + return ret;
> +
> + alarm_flag_reg = reg_val;
> +
> + for_each_set_bit(bit, &alarm_flag_reg, SYSMON_ALARM_BITS_PER_REG) {
> + address = bit + SYSMON_ALARM_BITS_PER_REG * event;
> + sysmon_push_event(indio_dev, address);
> + ret = regmap_clear_bits(sysmon->regmap, alarm_reg_offset, BIT(bit));
> + if (ret)
> + return ret;
> + }
> +
> + return regmap_write(sysmon->regmap, alarm_flag_offset, alarm_flag_reg);
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static void sysmon_handle_events(struct iio_dev *indio_dev,
> + unsigned long events)
> +{
> + unsigned int bit;
> +
> + for_each_set_bit(bit, &events, SYSMON_NO_OF_EVENTS)
> + sysmon_handle_event(indio_dev, bit);
> +}
> +
> +static void sysmon_unmask_temp(struct sysmon *sysmon, unsigned int isr)
> +{
> + unsigned int status;
> + u32 ier;
> +
> + status = isr & SYSMON_TEMP_INTR_MASK;
> +
> + ier = ~status & sysmon->masked_temp;
> + sysmon->masked_temp &= status;
> +
> + /* Only unmask if not administratively disabled by userspace */
> + ier &= ~sysmon->temp_mask;
> +
> + regmap_write(sysmon->regmap, SYSMON_IER, ier);
> +}
> +
> +/*
> + * Versal threshold interrupts are level-sensitive. Active threshold
> + * interrupts are masked in the handler and polled via delayed work
> + * until the condition clears, then unmasked.
> + */
> +static void sysmon_unmask_worker(struct work_struct *work)
> +{
> + struct sysmon *sysmon =
> + container_of(work, struct sysmon, sysmon_unmask_work.work);
> + unsigned int isr;
> +
> + /*
> + * If the ISR read fails, skip processing to avoid acting
> + * on undefined data.
> + */
> + scoped_guard(spinlock_irq, &sysmon->irq_lock) {
> + if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr))
> + break;
> + regmap_write(sysmon->regmap, SYSMON_ISR, isr);
> + sysmon_unmask_temp(sysmon, isr);
> + }
> +
> + if (sysmon->masked_temp)
> + schedule_delayed_work(&sysmon->sysmon_unmask_work,
> + msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS));
> + else
> + regmap_write(sysmon->regmap, SYSMON_STATUS_RESET, 1);
> +}
> +
> +static irqreturn_t sysmon_iio_irq(int irq, void *data)
> +{
> + struct iio_dev *indio_dev = data;
> + struct sysmon *sysmon = iio_priv(indio_dev);
> + unsigned int isr, imr;
> +
> + guard(spinlock)(&sysmon->irq_lock);
> +
> + if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr) ||
> + regmap_read(sysmon->regmap, SYSMON_IMR, &imr))
> + return IRQ_NONE;
> +
> + isr &= ~imr;
> + if (!isr)
> + return IRQ_NONE;
> +
> + regmap_write(sysmon->regmap, SYSMON_ISR, isr);
> +
> + sysmon_handle_events(indio_dev, isr);
> + schedule_delayed_work(&sysmon->sysmon_unmask_work,
> + msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS));
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void sysmon_disable_interrupts(void *data)
> +{
> + struct sysmon *sysmon = data;
> +
> + regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
> +
> + scoped_guard(spinlock_irq, &sysmon->irq_lock)
> + sysmon->masked_temp = 0;
> +
> + cancel_delayed_work_sync(&sysmon->sysmon_unmask_work);
> +}
> +
> +static int sysmon_init_interrupt(struct sysmon *sysmon,
> + struct device *dev,
> + struct iio_dev *indio_dev,
> + int irq)
> +{
> + unsigned int imr;
> + int ret;
> +
> + /* Events not supported without IRQ (e.g. I2C path) */
> + if (!irq)
> + return 0;
> +
> + INIT_DELAYED_WORK(&sysmon->sysmon_unmask_work, sysmon_unmask_worker);
> +
> + ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr);
> + if (ret)
> + return ret;
> + sysmon->temp_mask = imr & SYSMON_TEMP_INTR_MASK;
> +
> + ret = devm_request_irq(dev, irq, sysmon_iio_irq, 0, "sysmon-irq", indio_dev);
> + if (ret)
> + return ret;
> +
> + return devm_add_action_or_reset(dev, sysmon_disable_interrupts, sysmon);
> +}
> +
> +/*
> + * Initialize the cached hysteresis for a temperature channel from the
> + * current hardware threshold registers: hysteresis = upper - lower.
> + */
> +static int sysmon_init_hysteresis(struct sysmon *sysmon, int *hysteresis)
> +{
> + unsigned int upper_reg, lower_reg;
> + int upper_mc, lower_mc;
> + int ret;
> +
> + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_LOW, &lower_reg);
> + if (ret)
> + return ret;
> +
> + sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
> + sysmon_q8p7_to_millicelsius(lower_reg, &lower_mc);
> + *hysteresis = upper_mc - lower_mc;
> +
> + return 0;
> +}
> +
> /**
> * sysmon_parse_fw() - Parse firmware nodes and configure IIO channels.
> * @indio_dev: IIO device instance
> * @dev: Parent device
> + * @irq: IRQ number (positive enables event channels, 0 disables)
> *
> * Reads voltage-channels and temperature-channels container nodes from
> * firmware and builds the IIO channel array. Static temperature channels
> - * are prepended, followed by supply and satellite channels from DT.
> + * and event channels are prepended, followed by supply and satellite
> + * channels from DT.
> + *
> + * Event channels and per-channel event specs are only added when the
> + * device has an IRQ. I2C devices have no interrupt line, and the I2C
> + * regmap cannot be called from atomic context, so events are not
> + * supported on that path.
> *
> * Return: 0 on success, negative errno on failure.
> */
> -static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev)
> +static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int irq)
> {
> unsigned int num_chan, num_static, num_supply, num_temp;
> unsigned int idx, temp_chan_idx, volt_chan_idx;
> @@ -164,8 +736,14 @@ static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev)
> if (!sysmon_channels)
> return -ENOMEM;
>
> - /* Static temperature channels first */
> memcpy(sysmon_channels, temp_channels, sizeof(temp_channels));
> +
> + /* Attach event spec to channel 0 when IRQ is available */
> + if (irq > 0) {
> + sysmon_channels[0].event_spec = sysmon_temp_events;
> + sysmon_channels[0].num_event_specs = ARRAY_SIZE(sysmon_temp_events);
> + }
> +
> idx = num_static;
>
> /* Supply channels from DT */
> @@ -190,6 +768,10 @@ static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev)
> .indexed = 1,
> .address = reg,
> .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
> + .event_spec = irq > 0 ?
> + sysmon_supply_events : NULL,
> + .num_event_specs = irq > 0 ?
> + ARRAY_SIZE(sysmon_supply_events) : 0,
> .datasheet_name = label,
> };
> }
> @@ -255,6 +837,7 @@ int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
> {
> struct iio_dev *indio_dev;
> struct sysmon *sysmon;
> + int irq;
> int ret;
>
> indio_dev = devm_iio_device_alloc(dev, sizeof(*sysmon));
> @@ -267,6 +850,7 @@ int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
> ret = devm_mutex_init(dev, &sysmon->lock);
> if (ret)
> return ret;
> + spin_lock_init(&sysmon->irq_lock);
>
> /* Disable all interrupts and clear pending status */
> ret = regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
> @@ -276,13 +860,34 @@ int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
> if (ret)
> return ret;
>
> + irq = fwnode_irq_get(dev_fwnode(dev), 0);
> + if (irq == -EPROBE_DEFER)
> + return dev_err_probe(dev, irq, "failed to get IRQ\n");
> +
> indio_dev->name = "versal-sysmon";
> indio_dev->modes = INDIO_DIRECT_MODE;
>
> - ret = sysmon_parse_fw(indio_dev, dev);
> + ret = sysmon_parse_fw(indio_dev, dev, irq);
> if (ret)
> return ret;
>
> + if (irq > 0) {
> + /* Set hysteresis mode for temperature threshold */
> + ret = regmap_set_bits(sysmon->regmap, SYSMON_TEMP_EV_CFG,
> + SYSMON_TEMP_HYST_MASK);
> + if (ret)
> + return ret;
> +
> + /* Initialize cached hysteresis from hardware registers */
> + ret = sysmon_init_hysteresis(sysmon, &sysmon->temp_hysteresis);
> + if (ret)
> + return ret;
> +
> + ret = sysmon_init_interrupt(sysmon, dev, indio_dev, irq);
> + if (ret)
> + return ret;
> + }
> +
> return devm_iio_device_register(dev, indio_dev);
> }
> EXPORT_SYMBOL_NS_GPL(devm_versal_sysmon_core_probe, "VERSAL_SYSMON");
> diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
> index e27a5357575..9fe2793757a 100644
> --- a/drivers/iio/adc/versal-sysmon.h
> +++ b/drivers/iio/adc/versal-sysmon.h
> @@ -11,6 +11,8 @@
>
> #include <linux/bits.h>
> #include <linux/mutex.h>
> +#include <linux/spinlock_types.h>
> +#include <linux/workqueue.h>
>
> struct device;
> struct regmap;
> @@ -18,12 +20,22 @@ struct regmap;
> /* Register offsets (sorted by address) */
> #define SYSMON_NPI_LOCK 0x000C
> #define SYSMON_ISR 0x0044
> +#define SYSMON_IMR 0x0048
> +#define SYSMON_IER 0x004C
> #define SYSMON_IDR 0x0050
> #define SYSMON_TEMP_MAX 0x1030
> #define SYSMON_TEMP_MIN 0x1034
> #define SYSMON_SUPPLY_BASE 0x1040
> +#define SYSMON_ALARM_FLAG 0x1018
> +#define SYSMON_ALARM_REG 0x1940
> +#define SYSMON_TEMP_TH_LOW 0x1970
> +#define SYSMON_TEMP_TH_UP 0x1974
> +#define SYSMON_SUPPLY_TH_LOW 0x1980
> +#define SYSMON_SUPPLY_TH_UP 0x1C80
> +#define SYSMON_TEMP_EV_CFG 0x1F84
> #define SYSMON_TEMP_MIN_MIN 0x1F8C
> #define SYSMON_TEMP_MAX_MAX 0x1F90
> +#define SYSMON_STATUS_RESET 0x1F94
> #define SYSMON_TEMP_SAT_BASE 0x1FAC
> #define SYSMON_MAX_REG 0x24C0
>
> @@ -35,8 +47,12 @@ struct regmap;
>
> #define SYSMON_SUPPLY_IDX_MAX 159
> #define SYSMON_TEMP_SAT_MAX 64
> +#define SYSMON_NO_OF_EVENTS 32
> #define SYSMON_INTR_ALL_MASK GENMASK(31, 0)
>
> +/* ISR/IMR temperature alarm mask (bit 9) */
> +#define SYSMON_TEMP_INTR_MASK BIT(9)
> +
> /* Supply voltage conversion register fields */
> #define SYSMON_MANTISSA_MASK GENMASK(15, 0)
> #define SYSMON_FMT_MASK BIT(16)
> @@ -46,11 +62,21 @@ struct regmap;
> #define SYSMON_FRACTIONAL_SHIFT 7U
> #define SYSMON_SUPPLY_MANTISSA_BITS 16
>
> +/* Bits per alarm register */
> +#define SYSMON_ALARM_BITS_PER_REG 32
> +
> +#define SYSMON_UNMASK_WORK_DELAY_MS 500
> +
> /**
> * struct sysmon - Driver data for Versal SysMon
> * @regmap: register map for hardware access
> * @lock: protects read-modify-write sequences on threshold registers
> * and cached state that spans multiple regmap calls
> + * @irq_lock: protects interrupt mask register updates (MMIO path only)
> + * @masked_temp: currently masked temperature alarm bits
> + * @temp_mask: temperature interrupt configuration mask
> + * @temp_hysteresis: cached DEVICE_TEMP hysteresis in millicelsius
> + * @sysmon_unmask_work: re-enables events after alarm condition clears
> */
> struct sysmon {
> struct regmap *regmap;
> @@ -60,6 +86,16 @@ struct sysmon {
> * that spans multiple regmap calls.
> */
> struct mutex lock;
> + /*
> + * Protects interrupt mask register updates. Only used on the
> + * MMIO path (fast_io regmap); I2C has no IRQ and never reaches
> + * the event code that takes this lock.
> + */
> + spinlock_t irq_lock;
> + unsigned int masked_temp;
> + unsigned int temp_mask;
> + int temp_hysteresis;
> + struct delayed_work sysmon_unmask_work;
> };
>
> int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap);
^ permalink raw reply
* Re: [PATCH v11 5/5] iio: adc: versal-sysmon: add oversampling support
From: Erim, Salih @ 2026-06-23 11:37 UTC (permalink / raw)
To: jic23, andy
Cc: dlechner, nuno.sa, robh, krzk+dt, conor+dt, conall.ogriofa,
michal.simek, linux, erimsalih, linux-iio, devicetree,
linux-kernel, Andy Shevchenko
In-Reply-To: <20260623014036.3865402-6-salih.erim@amd.com>
Addressing Sashiko findings on this patch:
- [Medium] Missing hardware synchronization for oversampling
ratio caches during initialization.
The driver does not own the hardware state at probe time.
Writing a default could interfere with bootloader (PLM)
configuration. The cache initializes to 1 (no averaging),
which matches the hardware reset default. Discussed and
dismissed in v6 review.
Thanks,
Salih
On 23/06/2026 02:40, Salih Erim wrote:
> Add support for reading and writing the oversampling ratio through
> the IIO oversampling_ratio attribute. The hardware supports averaging
> 2, 4, 8, or 16 samples, plus a ratio of 1 (no averaging).
>
> Temperature and supply channels share oversampling configuration at
> the type level (all temperature channels share one ratio, all supply
> channels share another), exposed through info_mask_shared_by_type.
>
> The hardware encoding uses sample_count / 2 in a 4-bit field within
> the CONFIG register. Per-channel averaging enable registers must also
> be updated to activate or deactivate averaging.
>
> Signed-off-by: Salih Erim <salih.erim@amd.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
> ---
> Changes in v11:
> - Add oversampling info_mask bits to static SYSMON_CHAN_TEMP
> macro (Jonathan)
>
> Changes in v10:
> - No code changes
>
> Changes in v9:
> - Add Reviewed-by tag from Andy Shevchenko
> - No code changes
>
> Changes in v8:
> - Use unsigned int for val parameter and hw_val in both
> osr_write helpers (Andy)
> - Use ~0 instead of ~0U for avg enable bitmask (Andy)
>
> Changes in v7:
> - Split sysmon_osr_write into sysmon_osr_write_temp and
> sysmon_osr_write_supply; caller dispatches with if/else
> on chan->type (Jonathan)
> - Restore HW encoding comment in both helpers; fix
> cross-reference in sysmon_osr_write_supply
>
> Changes in v6:
> - Fix FIELD_PREP indentation in sysmon_osr_write (Andy)
> - unsigned int for loop index in sysmon_write_raw (Andy)
>
> Changes in v5:
> - Remove unneeded parentheses in i * SYSMON_REG_STRIDE (Andy)
> - Use struct regmap *map local variable in
> sysmon_set_avg_enable (Andy)
> - switch instead of redundant if/if on channel_type (Andy)
> - Add CONFIG register readback fence after oversampling update
> to prevent NoC bus hang from posted writes (found during
> hardware stress testing)
>
> Changes in v4:
> - Return directly from sysmon_set_avg_enable calls, remove
> else after early returns, drop unreachable return 0 (Jonathan)
> - Rename mask defines to SYSMON_CONFIG_SUPPLY_OSR and
> SYSMON_CONFIG_TEMP_SAT_OSR (Jonathan)
> - Drop "bits X:Y" from GENMASK comments (Jonathan)
> - Blank lines after if (ret) return ret blocks (Jonathan)
> - Move oversampling read inside guard(mutex) scope
>
> Changes in v3:
> - No changes
>
> Changes in v2:
> - EN_AVG per-channel bitmask registers written with all-ones
> instead of boolean 1 when oversampling is enabled
> - EN_AVG write errors propagated to userspace
> - Oversampling limited to satellite temp and supply channels;
> static temp channels do not participate
> - Oversampling exposes actual sample counts (1,2,4,8,16) to
> userspace with internal HW register translation
> - write_raw_get_fmt returns IIO_VAL_INT for oversampling ratio
> - HW encoding documented (sample_count/2, not log2)
> - oversampling_avail is const int[] (type match fix)
> drivers/iio/adc/versal-sysmon-core.c | 159 ++++++++++++++++++++++++++-
> drivers/iio/adc/versal-sysmon.h | 17 +++
> 2 files changed, 174 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
> index 8f2c502d9cb..1b55d343982 100644
> --- a/drivers/iio/adc/versal-sysmon-core.c
> +++ b/drivers/iio/adc/versal-sysmon-core.c
> @@ -28,6 +28,12 @@
>
> #include "versal-sysmon.h"
>
> +/*
> + * Oversampling ratio values exposed to userspace via IIO.
> + * Actual number of samples averaged: 1=none, 2=2x, 4=4x, 8=8x, 16=16x.
> + */
> +static const int sysmon_oversampling_avail[] = { 1, 2, 4, 8, 16 };
> +
> /* TEMP hysteresis mode bit in SYSMON_TEMP_EV_CFG */
> #define SYSMON_TEMP_HYST_MASK BIT(1)
>
> @@ -42,7 +48,11 @@
> .address = _address, \
> .channel = _chan, \
> .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> + .info_mask_shared_by_type = \
> + BIT(IIO_CHAN_INFO_SCALE) | \
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
> + .info_mask_shared_by_type_available = \
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
> .datasheet_name = _name, \
> }
>
> @@ -166,6 +176,12 @@ static int sysmon_read_raw(struct iio_dev *indio_dev,
>
> guard(mutex)(&sysmon->lock);
>
> + if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) {
> + *val = (chan->type == IIO_TEMP) ? sysmon->temp_oversampling :
> + sysmon->supply_oversampling;
> + return IIO_VAL_INT;
> + }
> +
> switch (chan->type) {
> case IIO_TEMP:
> if (mask == IIO_CHAN_INFO_SCALE) {
> @@ -465,6 +481,132 @@ static int sysmon_write_event_value(struct iio_dev *indio_dev,
> }
> }
>
> +static int sysmon_set_avg_enable(struct sysmon *sysmon,
> + u32 base, u32 count, u32 val)
> +{
> + struct regmap *map = sysmon->regmap;
> + int ret;
> +
> + for (unsigned int i = 0; i < count; i++) {
> + ret = regmap_write(map, base + i * SYSMON_REG_STRIDE, val);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int sysmon_osr_write_temp(struct sysmon *sysmon, unsigned int val)
> +{
> + /*
> + * HW register encoding is sample_count / 2:
> + * 0=none, 1=2x, 2=4x, 4=8x, 8=16x (not log2-based).
> + */
> + unsigned int hw_val = val >> 1;
> + unsigned int readback;
> + int ret;
> +
> + ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG,
> + SYSMON_CONFIG_TEMP_SAT_OSR,
> + FIELD_PREP(SYSMON_CONFIG_TEMP_SAT_OSR, hw_val));
> + if (ret)
> + return ret;
> +
> + /*
> + * Readback fence: the SysMon CONFIG register resides in the
> + * PMC domain behind the NoC. A posted write may not reach the
> + * hardware before the next MMIO access. Reading the register
> + * back forces the interconnect to complete the write, preventing
> + * a bus hang on the subsequent access.
> + */
> + regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback);
> +
> + return sysmon_set_avg_enable(sysmon, SYSMON_TEMP_EN_AVG_BASE,
> + SYSMON_TEMP_EN_AVG_COUNT,
> + hw_val ? ~0 : 0);
> +}
> +
> +static int sysmon_osr_write_supply(struct sysmon *sysmon, unsigned int val)
> +{
> + /* HW encoding: sample_count / 2 (see sysmon_osr_write_temp) */
> + unsigned int hw_val = val >> 1;
> + unsigned int readback;
> + int ret;
> +
> + ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG,
> + SYSMON_CONFIG_SUPPLY_OSR,
> + FIELD_PREP(SYSMON_CONFIG_SUPPLY_OSR, hw_val));
> + if (ret)
> + return ret;
> +
> + /* Readback fence -- see sysmon_osr_write_temp for details */
> + regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback);
> +
> + return sysmon_set_avg_enable(sysmon, SYSMON_SUPPLY_EN_AVG_BASE,
> + SYSMON_SUPPLY_EN_AVG_COUNT,
> + hw_val ? ~0 : 0);
> +}
> +
> +static int sysmon_write_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int val, int val2, long mask)
> +{
> + struct sysmon *sysmon = iio_priv(indio_dev);
> + unsigned int i;
> + int ret;
> +
> + if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
> + return -EINVAL;
> +
> + for (i = 0; i < ARRAY_SIZE(sysmon_oversampling_avail); i++) {
> + if (val == sysmon_oversampling_avail[i])
> + break;
> + }
> + if (i == ARRAY_SIZE(sysmon_oversampling_avail))
> + return -EINVAL;
> +
> + guard(mutex)(&sysmon->lock);
> +
> + if (chan->type == IIO_TEMP) {
> + ret = sysmon_osr_write_temp(sysmon, val);
> + if (ret)
> + return ret;
> + sysmon->temp_oversampling = val;
> + } else {
> + ret = sysmon_osr_write_supply(sysmon, val);
> + if (ret)
> + return ret;
> + sysmon->supply_oversampling = val;
> + }
> +
> + return 0;
> +}
> +
> +static int sysmon_write_raw_get_fmt(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + long mask)
> +{
> + if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO)
> + return IIO_VAL_INT;
> +
> + return -EINVAL;
> +}
> +
> +static int sysmon_read_avail(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int **vals, int *type,
> + int *length, long mask)
> +{
> + if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
> + return -EINVAL;
> +
> + *vals = sysmon_oversampling_avail;
> + *type = IIO_VAL_INT;
> + *length = ARRAY_SIZE(sysmon_oversampling_avail);
> +
> + return IIO_AVAIL_LIST;
> +}
> +
> static int sysmon_read_label(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan,
> char *label)
> @@ -477,6 +619,9 @@ static int sysmon_read_label(struct iio_dev *indio_dev,
>
> static const struct iio_info sysmon_iio_info = {
> .read_raw = sysmon_read_raw,
> + .write_raw = sysmon_write_raw,
> + .write_raw_get_fmt = sysmon_write_raw_get_fmt,
> + .read_avail = sysmon_read_avail,
> .read_label = sysmon_read_label,
> .read_event_config = sysmon_read_event_config,
> .write_event_config = sysmon_write_event_config,
> @@ -768,6 +913,10 @@ static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int ir
> .indexed = 1,
> .address = reg,
> .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
> + .info_mask_shared_by_type =
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> + .info_mask_shared_by_type_available =
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> .event_spec = irq > 0 ?
> sysmon_supply_events : NULL,
> .num_event_specs = irq > 0 ?
> @@ -799,7 +948,11 @@ static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int ir
> .address = SYSMON_TEMP_SAT_BASE +
> (reg - 1) * SYSMON_REG_STRIDE,
> .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
> + .info_mask_shared_by_type =
> + BIT(IIO_CHAN_INFO_SCALE) |
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> + .info_mask_shared_by_type_available =
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> .datasheet_name = label,
> };
> }
> @@ -846,6 +999,8 @@ int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
>
> sysmon = iio_priv(indio_dev);
> sysmon->regmap = regmap;
> + sysmon->temp_oversampling = 1;
> + sysmon->supply_oversampling = 1;
>
> ret = devm_mutex_init(dev, &sysmon->lock);
> if (ret)
> diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
> index 9fe2793757a..bb9a75bf71c 100644
> --- a/drivers/iio/adc/versal-sysmon.h
> +++ b/drivers/iio/adc/versal-sysmon.h
> @@ -23,11 +23,13 @@ struct regmap;
> #define SYSMON_IMR 0x0048
> #define SYSMON_IER 0x004C
> #define SYSMON_IDR 0x0050
> +#define SYSMON_CONFIG 0x0100
> #define SYSMON_TEMP_MAX 0x1030
> #define SYSMON_TEMP_MIN 0x1034
> #define SYSMON_SUPPLY_BASE 0x1040
> #define SYSMON_ALARM_FLAG 0x1018
> #define SYSMON_ALARM_REG 0x1940
> +#define SYSMON_SUPPLY_EN_AVG_BASE 0x1958
> #define SYSMON_TEMP_TH_LOW 0x1970
> #define SYSMON_TEMP_TH_UP 0x1974
> #define SYSMON_SUPPLY_TH_LOW 0x1980
> @@ -37,6 +39,7 @@ struct regmap;
> #define SYSMON_TEMP_MAX_MAX 0x1F90
> #define SYSMON_STATUS_RESET 0x1F94
> #define SYSMON_TEMP_SAT_BASE 0x1FAC
> +#define SYSMON_TEMP_EN_AVG_BASE 0x24B4
> #define SYSMON_MAX_REG 0x24C0
>
> /* NPI unlock value written to SYSMON_NPI_LOCK */
> @@ -53,6 +56,16 @@ struct regmap;
> /* ISR/IMR temperature alarm mask (bit 9) */
> #define SYSMON_TEMP_INTR_MASK BIT(9)
>
> +/* SYSMON_CONFIG: supply oversampling ratio */
> +#define SYSMON_CONFIG_SUPPLY_OSR GENMASK(17, 14)
> +
> +/* SYSMON_CONFIG: temperature satellite oversampling ratio */
> +#define SYSMON_CONFIG_TEMP_SAT_OSR GENMASK(27, 24)
> +
> +/* Per-channel averaging enable register counts */
> +#define SYSMON_SUPPLY_EN_AVG_COUNT 5
> +#define SYSMON_TEMP_EN_AVG_COUNT 2
> +
> /* Supply voltage conversion register fields */
> #define SYSMON_MANTISSA_MASK GENMASK(15, 0)
> #define SYSMON_FMT_MASK BIT(16)
> @@ -77,6 +90,8 @@ struct regmap;
> * @temp_mask: temperature interrupt configuration mask
> * @temp_hysteresis: cached DEVICE_TEMP hysteresis in millicelsius
> * @sysmon_unmask_work: re-enables events after alarm condition clears
> + * @temp_oversampling: current temp oversampling ratio
> + * @supply_oversampling: current supply oversampling ratio
> */
> struct sysmon {
> struct regmap *regmap;
> @@ -96,6 +111,8 @@ struct sysmon {
> unsigned int temp_mask;
> int temp_hysteresis;
> struct delayed_work sysmon_unmask_work;
> + unsigned int temp_oversampling;
> + unsigned int supply_oversampling;
> };
>
> int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap);
^ permalink raw reply
* Re: [PATCH] arm64: dts: qcom: eliza: Fix disp_cc_mdss_mdp_clk_src RCG stall on Eliza EVK
From: Konrad Dybcio @ 2026-06-23 11:38 UTC (permalink / raw)
To: Krzysztof Kozlowski, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, devicetree,
linux-kernel
In-Reply-To: <de941d2d-df5d-44b6-b95a-437e35917cd5@oss.qualcomm.com>
On 6/23/26 1:31 PM, Krzysztof Kozlowski wrote:
> On 23/06/2026 13:27, Krzysztof Kozlowski wrote:
>> Eliza EVK (eliza-cqs-evk.dts) does not have display enabled, however its
>> Display Clock Controller is enabled and references parent clocks from
>> DSI PHYs. Devices which in base DTSI do not have all required resources
>> available (e.g. because they are simply disabled), should not be enabled
>> in the first place.
>>
>> Having DISPCC enabled without DSI PHYs causes clock reparenting issues
>> and warning on Eliza EVK:
>>
>> disp_cc_mdss_mdp_clk_src: rcg didn't update its configuration.
>> WARNING: drivers/clk/qcom/clk-rcg2.c:136 at update_config+0xd4/0xe4, CPU#1: udevd/273
>> ...
>> update_config (drivers/clk/qcom/clk-rcg2.c:136 (discriminator 2)) (P)
>> clk_rcg2_shared_disable (drivers/clk/qcom/clk-rcg2.c:1471)
>> clk_rcg2_shared_init (drivers/clk/qcom/clk-rcg2.c:1540)
>> __clk_register (drivers/clk/clk.c:3959 drivers/clk/clk.c:4368)
>> devm_clk_hw_register (drivers/clk/clk.c:4448 (discriminator 1) drivers/clk/clk.c:4672 (discriminator 1))
>> devm_clk_register_regmap (drivers/clk/qcom/clk-regmap.c:104)
>> qcom_cc_really_probe (drivers/clk/qcom/common.c:418)
>> qcom_cc_probe (drivers/clk/qcom/common.c:445)
>> disp_cc_eliza_probe (dispcc-eliza.c:?) dispcc_eliza
>> platform_probe (drivers/base/platform.c:1432)
>>
>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>> ---
>> arch/arm64/boot/dts/qcom/eliza-mtp.dts | 4 ++++
>> arch/arm64/boot/dts/qcom/eliza.dtsi | 1 +
>> 2 files changed, 5 insertions(+)
>
>
> I should call it RFC, because this feels like a band-aid and should be
> fixed in clock drivers maybe. Eventually DISPCC should be enabled on
> Eliza EVK for HDMI, but DSI PHY will stay disabled.
I'd say all of that hardware should be kept enabled, if only to
make sure that it's parked safely
Konrad
^ permalink raw reply
* Re: [PATCH 3/3] backlight: lp8864: Convert from LED to backlight class driver
From: Daniel Thompson @ 2026-06-23 11:41 UTC (permalink / raw)
To: Sverdlin, Alexander
Cc: linux-leds@vger.kernel.org, afd@ti.com, jingoohan1@gmail.com,
linux-fbdev@vger.kernel.org, pavel@kernel.org, lee@kernel.org,
dri-devel@lists.freedesktop.org, robh@kernel.org,
linux-kernel@vger.kernel.org, krzk+dt@kernel.org,
danielt@kernel.org, conor+dt@kernel.org, deller@gmx.de,
devicetree@vger.kernel.org
In-Reply-To: <acb13aca040ab72b9e53abee3a5c8733ebc5b8dd.camel@siemens.com>
On Tue, Jun 16, 2026 at 07:17:23AM +0000, Sverdlin, Alexander wrote:
> Hi Andrew!
>
> On Mon, 2026-06-15 at 14:51 -0500, Andrew Davis wrote:
> > > Move the TI LP8864/LP8866 driver from drivers/leds/ to
> > > drivers/video/backlight/
> >
> > Why move it? You can register a backlight device from any directory.
>
> I'm personally fine with the driver residing in drivers/leds, it's
> just that currently there are no combined drivers there, the combined
> drivers providing both interfaces only live in video/backlight.
>
> But if it's OK from the maintainers' perspective, it will be even
> more consistent regarding Kconfig symbol.
>
> > > and convert it to register a backlight class
> > > device as its primary interface.
> > >
> >
> > What do you mean by "primary"? You should be able to register with
> > both frameworks and have the driver interop between as needed.
>
> Well, I only meant the user's (or my own) perspective, sorry for confusion.
>
> > > The motivation is a use case on a hot-pluggable segment of an I2C bus.
> > > The generic led-backlight driver (drivers/video/backlight/led_bl.c) is a
> > > platform driver and as such inherently non-hotpluggable.
> >
> > That isn't strictly true, there is platform_device_{del,unregister}(), so
> > whatever your mechanism for removing the I2C device would be, the same
> > could be done to the led_bl device before then removing the I2C device.
>
> led_bl is not really designed to act on dynamically instantiated devices,
> it's very much device-tree affine (of_count_phandle_with_args(), etc...)
>
> > We don't want to have to move every LED driver that could possibly
> > be used as a backlight to the backlight framework, the led_bl.c
> > handles adapting LED->backlight as needed. So what you really need
> > here is to de-couple led_bl.c from DT so it can better handle dynamic
> > add/remove. Then this LED driver simply could register a "led-backlight"
> > platform driver to handle the backlight interface, and remove the
> > backlight device when it itself (the LED device) is removed.
>
> The mechanism we have regarding hot plugging currently is just I2C bridge,
> which de-registers and registers the bridged bus. So no additional drivers
> are required, as long as I2C devices are self-contained and not glued with
> platform devices.
>
> So bottom line is, I'd prefer to just add the backlight interface to the
> existing driver, no matter where it would live in the future.
Is there any reasion that LP8864/LP8866 is unique in appearing on a
hotplugged I2C bus? In other words if support for dynamism is added
specifically to leds-lp8864.c rather than in led_bl.c then what will stop
the same dynamic tricks from being adde to other LED drivers?
Daniel.
^ permalink raw reply
* Re: [PATCH] arm64: dts: qcom: eliza: Fix disp_cc_mdss_mdp_clk_src RCG stall on Eliza EVK
From: Krzysztof Kozlowski @ 2026-06-23 11:42 UTC (permalink / raw)
To: Konrad Dybcio, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, devicetree,
linux-kernel
In-Reply-To: <be95b95b-dbcb-4b80-94dd-a7e97ef4c446@oss.qualcomm.com>
On 23/06/2026 13:38, Konrad Dybcio wrote:
> On 6/23/26 1:31 PM, Krzysztof Kozlowski wrote:
>> On 23/06/2026 13:27, Krzysztof Kozlowski wrote:
>>> Eliza EVK (eliza-cqs-evk.dts) does not have display enabled, however its
>>> Display Clock Controller is enabled and references parent clocks from
>>> DSI PHYs. Devices which in base DTSI do not have all required resources
>>> available (e.g. because they are simply disabled), should not be enabled
>>> in the first place.
>>>
>>> Having DISPCC enabled without DSI PHYs causes clock reparenting issues
>>> and warning on Eliza EVK:
>>>
>>> disp_cc_mdss_mdp_clk_src: rcg didn't update its configuration.
>>> WARNING: drivers/clk/qcom/clk-rcg2.c:136 at update_config+0xd4/0xe4, CPU#1: udevd/273
>>> ...
>>> update_config (drivers/clk/qcom/clk-rcg2.c:136 (discriminator 2)) (P)
>>> clk_rcg2_shared_disable (drivers/clk/qcom/clk-rcg2.c:1471)
>>> clk_rcg2_shared_init (drivers/clk/qcom/clk-rcg2.c:1540)
>>> __clk_register (drivers/clk/clk.c:3959 drivers/clk/clk.c:4368)
>>> devm_clk_hw_register (drivers/clk/clk.c:4448 (discriminator 1) drivers/clk/clk.c:4672 (discriminator 1))
>>> devm_clk_register_regmap (drivers/clk/qcom/clk-regmap.c:104)
>>> qcom_cc_really_probe (drivers/clk/qcom/common.c:418)
>>> qcom_cc_probe (drivers/clk/qcom/common.c:445)
>>> disp_cc_eliza_probe (dispcc-eliza.c:?) dispcc_eliza
>>> platform_probe (drivers/base/platform.c:1432)
>>>
>>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>>> ---
>>> arch/arm64/boot/dts/qcom/eliza-mtp.dts | 4 ++++
>>> arch/arm64/boot/dts/qcom/eliza.dtsi | 1 +
>>> 2 files changed, 5 insertions(+)
>>
>>
>> I should call it RFC, because this feels like a band-aid and should be
>> fixed in clock drivers maybe. Eventually DISPCC should be enabled on
>> Eliza EVK for HDMI, but DSI PHY will stay disabled.
>
> I'd say all of that hardware should be kept enabled, if only to
> make sure that it's parked safely
>
You mean enable DSI PHY, even though there is nothing attached?
My warning probably can be fixed same way as:
https://lore.kernel.org/all/20260622-sm8450-qol-v1-1-37e2ee8df9da@proton.me/
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v1] arm64: dts: ti: k3-am62-verdin: Add RPi Touch Display 2 7-inch
From: Francesco Dolcini @ 2026-06-23 11:43 UTC (permalink / raw)
To: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: Francesco Dolcini, linux-arm-kernel, devicetree, linux-kernel
From: Francesco Dolcini <francesco.dolcini@toradex.com>
Add a device tree overlay for the Raspberry Pi Touch Display 2 7" on
the Verdin DSI_1 interface.
Link: https://www.raspberrypi.com/products/touch-display-2/
Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
---
arch/arm64/boot/dts/ti/Makefile | 5 +
.../ti/k3-am625-verdin-rpi-display-2-7in.dtso | 102 ++++++++++++++++++
2 files changed, 107 insertions(+)
create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-rpi-display-2-7in.dtso
diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index 371f9a043fe5..f7f5448fcd84 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -48,6 +48,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-ov5640.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-10inch-dsi.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-10inch-lvds.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-rpi-display-2-7in.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-uart4-mcu.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia-dsi-to-hdmi.dtb
dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia-panel-cap-touch-10inch-dsi.dtb
@@ -244,6 +245,9 @@ k3-am625-verdin-wifi-dev-ov5640-dtbs := k3-am625-verdin-wifi-dev.dtb \
k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi-dtbs := \
k3-am625-verdin-wifi-dev.dtb \
k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
+k3-am625-verdin-wifi-dev-rpi-display-2-7in-dtbs := \
+ k3-am625-verdin-wifi-dev.dtb \
+ k3-am625-verdin-rpi-display-2-7in.dtbo
k3-am625-verdin-wifi-dev-uart4-mcu-dtbs := k3-am625-verdin-wifi-dev.dtb \
k3-am625-verdin-uart4-mcu.dtbo
k3-am625-verdin-wifi-mallow-panel-cap-touch-10inch-lvds-dtbs := \
@@ -357,6 +361,7 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
k3-am625-verdin-wifi-dev-ov5640-24mhz.dtb \
k3-am625-verdin-wifi-dev-ov5640.dtb \
k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi.dtb \
+ k3-am625-verdin-wifi-dev-rpi-display-2-7in.dtb \
k3-am625-verdin-wifi-dev-uart4-mcu.dtb \
k3-am625-verdin-wifi-mallow-panel-cap-touch-10inch-lvds.dtb \
k3-am62-lp-sk-hdmi-audio.dtb \
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-rpi-display-2-7in.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-rpi-display-2-7in.dtso
new file mode 100644
index 000000000000..9a2e7a170a28
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-rpi-display-2-7in.dtso
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Raspberry Pi Touch Display 2 7" on Verdin DSI_1 and I2C_2_DSI
+ *
+ * https://www.raspberrypi.com/products/touch-display-2/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&{/} {
+ backlight_rpi: backlight-rpi-display {
+ compatible = "pwm-backlight";
+ brightness-levels = <0 31>;
+ default-brightness-level = <15>;
+ num-interpolated-steps = <31>;
+ pwms = <&mcu_display_rpi 0 200000 0>;
+ };
+
+ reg_display_rpi: regulator-rpi-display {
+ compatible = "regulator-fixed";
+ regulator-max-microvolt = <5000000>;
+ regulator-min-microvolt = <5000000>;
+ regulator-name = "rpi-display";
+ };
+
+ reg_display_rpi_touch: regulator-rpi-display-touch {
+ compatible = "regulator-fixed";
+ gpio = <&mcu_display_rpi 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-max-microvolt = <3300000>;
+ regulator-min-microvolt = <3300000>;
+ regulator-name = "rpi-display-touch";
+ startup-delay-us = <50000>;
+ };
+
+};
+
+/* Verdin I2C_2_DSI */
+&main_i2c2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mcu_display_rpi: regulator@45 {
+ compatible = "raspberrypi,touchscreen-panel-regulator-v2";
+ reg = <0x45>;
+ #gpio-cells = <2>;
+ #pwm-cells = <3>;
+ gpio-controller;
+ };
+
+ touchscreen@5d {
+ compatible = "goodix,gt911";
+ reg = <0x5d>;
+ AVDD28-supply = <®_display_rpi_touch>;
+ touchscreen-size-x = <720>;
+ touchscreen-size-y = <1280>;
+ };
+};
+
+&dsi_bridge {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "okay";
+
+ panel@0 {
+ compatible = "raspberrypi,dsi-7inch", "ilitek,ili9881c";
+ reg = <0>;
+ backlight = <&backlight_rpi>;
+ power-supply = <®_display_rpi>;
+ reset-gpios = <&mcu_display_rpi 0 GPIO_ACTIVE_LOW>;
+
+ port {
+ dsi_panel_in: endpoint {
+ remote-endpoint = <&dsi_bridge_out>;
+ };
+ };
+ };
+};
+
+&dsi_bridge_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ reg = <1>;
+
+ dsi_bridge_out: endpoint {
+ data-lanes = <1 2>;
+ remote-endpoint = <&dsi_panel_in>;
+ };
+ };
+};
+
+&dss {
+ status = "okay";
+};
--
2.47.3
^ permalink raw reply related
* Re: [PATCH] arm64: dts: qcom: eliza: Fix disp_cc_mdss_mdp_clk_src RCG stall on Eliza EVK
From: Konrad Dybcio @ 2026-06-23 11:43 UTC (permalink / raw)
To: Krzysztof Kozlowski, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, devicetree,
linux-kernel
In-Reply-To: <6ad8d604-b04e-4f24-b616-980f0e18b4c5@oss.qualcomm.com>
On 6/23/26 1:42 PM, Krzysztof Kozlowski wrote:
> On 23/06/2026 13:38, Konrad Dybcio wrote:
>> On 6/23/26 1:31 PM, Krzysztof Kozlowski wrote:
>>> On 23/06/2026 13:27, Krzysztof Kozlowski wrote:
>>>> Eliza EVK (eliza-cqs-evk.dts) does not have display enabled, however its
>>>> Display Clock Controller is enabled and references parent clocks from
>>>> DSI PHYs. Devices which in base DTSI do not have all required resources
>>>> available (e.g. because they are simply disabled), should not be enabled
>>>> in the first place.
>>>>
>>>> Having DISPCC enabled without DSI PHYs causes clock reparenting issues
>>>> and warning on Eliza EVK:
>>>>
>>>> disp_cc_mdss_mdp_clk_src: rcg didn't update its configuration.
>>>> WARNING: drivers/clk/qcom/clk-rcg2.c:136 at update_config+0xd4/0xe4, CPU#1: udevd/273
>>>> ...
>>>> update_config (drivers/clk/qcom/clk-rcg2.c:136 (discriminator 2)) (P)
>>>> clk_rcg2_shared_disable (drivers/clk/qcom/clk-rcg2.c:1471)
>>>> clk_rcg2_shared_init (drivers/clk/qcom/clk-rcg2.c:1540)
>>>> __clk_register (drivers/clk/clk.c:3959 drivers/clk/clk.c:4368)
>>>> devm_clk_hw_register (drivers/clk/clk.c:4448 (discriminator 1) drivers/clk/clk.c:4672 (discriminator 1))
>>>> devm_clk_register_regmap (drivers/clk/qcom/clk-regmap.c:104)
>>>> qcom_cc_really_probe (drivers/clk/qcom/common.c:418)
>>>> qcom_cc_probe (drivers/clk/qcom/common.c:445)
>>>> disp_cc_eliza_probe (dispcc-eliza.c:?) dispcc_eliza
>>>> platform_probe (drivers/base/platform.c:1432)
>>>>
>>>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>>>> ---
>>>> arch/arm64/boot/dts/qcom/eliza-mtp.dts | 4 ++++
>>>> arch/arm64/boot/dts/qcom/eliza.dtsi | 1 +
>>>> 2 files changed, 5 insertions(+)
>>>
>>>
>>> I should call it RFC, because this feels like a band-aid and should be
>>> fixed in clock drivers maybe. Eventually DISPCC should be enabled on
>>> Eliza EVK for HDMI, but DSI PHY will stay disabled.
>>
>> I'd say all of that hardware should be kept enabled, if only to
>> make sure that it's parked safely
>>
>
> You mean enable DSI PHY, even though there is nothing attached?
Yes, so that Linux can shut it off no matter its initial state (which
may include "partially initialized" or "partially shut down")
> My warning probably can be fixed same way as:
> https://lore.kernel.org/all/20260622-sm8450-qol-v1-1-37e2ee8df9da@proton.me/
Quite possibly. IIRC Mike Tipton wasn't a huge fan of park-at-init
to begin with.
Konrad
^ permalink raw reply
* [PATCH v9 0/2] Add AMD I3C master controller driver and bindings
From: Shubham Patil @ 2026-06-23 11:44 UTC (permalink / raw)
To: git, michal.simek, alexandre.belloni, Frank.Li, robh, krzk+dt,
conor+dt, pgaj, wsa+renesas, tommaso.merciai.xr, arnd,
quic_msavaliy, Shyam-sundar.S-k, sakari.ailus, billy_tsai, kees,
gustavoars, jarkko.nikula, jorge.marques, linux-i3c, devicetree,
linux-kernel, linux-arch, linux-hardening
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
shubhamsanjay.patil
This patch series introduces support for the AMD I3C master controller,
including the device tree binding and driver implementation.
Compared to v8, the big-endian MMIO accessor and i3c FIFO-endianness
patches have been dropped; the driver now handles big-endian FIFO
accesses internally.
Note: There was an extended gap since v8 due to the transfer of ownership
of this series from Manikanta to Shubham. This transition contributed
to the delay in releasing the v9 update addressing the v8 review comments.
We appreciate your patience.
---
Changes for V9:
Dropped the three big-endian MMIO/FIFO infrastructure patches; the
driver now handles big-endian FIFO accesses internally.
Replaced the async transfer-queue with a synchronous transfer path.
Reworked error/response handling using enum i3c_error_code and proper
-ENODEV/-EIO returns; propagate err to CCCs and priv xfers.
Switched to the new .i3c_xfers op (reject non-SDR, report actual_len).
Reworked DAA (incremental address assignment, -ENOSPC bound, -ENODEV
end-of-enumeration, checked device registration).
Avoid busy-spin with usleep_range(); use FIELD_PREP() and inline
helpers; split the timeout macros with documented units.
Dropped ENTHDR (SDR-only); updated MAINTAINERS, Kconfig symbol
(AMD_AXI_I3C_MASTER), authors and binding maintainers.
Changes for V8:
Included dependent patch "i3c: fix big-endian FIFO transfers"
to this series as [3/5].
Resolved conflicts with "i3c: fix big-endian FIFO transfers".
Updated description.
Used time_left instead of timeout.
Used __free(kfree) for xfer to simplify err path in multiple places.
Changes for V7:
Added i3c controller version details to commit description.
Added Reviewed-by tag to binding patch [1/4].
Added big-endian MMIO accessors [2/4].
Added endianness support for i3c_readl_fifo() and i3c_writel_fifo() [3/4].
Updated timeout macro name.
Updated xi3c_master_wr_to_tx_fifo() and xi3c_master_rd_from_rx_fifo()
to use i3c_writel_fifo() and i3c_readl_fifo().
Changes for V6:
Corrected the $id in the YAML file to match the filename and fix
the dtschema warning.
Removed typecast for xi3c_getrevisionnumber(), xi3c_wrfifolevel(),
and xi3c_rdfifolevel().
Replaced dynamic allocation with a static variable for pid_bcr_dcr.
Fixed sparse warning in do_daa by typecasting the address parity value
to u8.
Fixed sparse warning in xi3c_master_bus_init by typecasting the pid value
to u64 in info.pid calculation.
Changes for V5:
Renamed the xlnx,axi-i3c.yaml file into xlnx,axi-i3c-1.0.yaml.
Used GENMASK_ULL for PID mask as it's 64bit mask.
Changes for V4:
Added h/w documentation details.
Updated timeout macros.
Removed type casting for xi3c_is_resp_available() macro.
Used ioread32() and iowrite32() instead of readl() and writel()
to keep consistency.
Read XI3C_RESET_OFFSET reg before udelay().
Removed xi3c_master_free_xfer() and directly used kfree().
Skipped checking return value of i3c_master_add_i3c_dev_locked().
Used devm_mutex_init() instead of mutex_init().
Changes for V3:
Updated commit description.
Corrected the order of properties and removed resets property.
Added compatible to required list.
Added interrupts to example.
Resolved merge conflicts.
Changes for V2:
Updated commit subject and description.
Moved allOf to after required.
Removed xlnx,num-targets property.
Added mixed mode support with clock configuration.
Converted smaller functions into inline functions.
Used FIELD_GET() in xi3c_get_response().
Updated xi3c_master_rd_from_rx_fifo() to use cmd->rx_buf.
Used parity8() for address parity calculation.
Added guards for locks.
Dropped num_targets and updated xi3c_master_do_daa().
Used __free(kfree) in xi3c_master_send_bdcast_ccc_cmd().
Dropped PM runtime support.
Updated xi3c_master_read() and xi3c_master_write() with
xi3c_is_resp_available() check.
Created separate functions: xi3c_master_init() and xi3c_master_reinit().
Used xi3c_master_init() in bus initialization and xi3c_master_reinit()
in error paths.
Added DAA structure to xi3c_master structure.
---
Manikanta Guntupalli (2):
dt-bindings: i3c: Add AMD I3C master controller support
i3c: master: Add driver for AMD AXI I3C master controller
.../bindings/i3c/xlnx,axi-i3c-1.0.yaml | 56 +
MAINTAINERS | 8 +
drivers/i3c/master/Kconfig | 15 +
drivers/i3c/master/Makefile | 1 +
drivers/i3c/master/amd-i3c-master.c | 1060 +++++++++++++++++
5 files changed, 1140 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
create mode 100644 drivers/i3c/master/amd-i3c-master.c
--
2.34.1
^ permalink raw reply
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