* [PATCH v2 4/4] arm64: dts: renesas: r8a779g0: Add GICv3 ITS and update PCIe nodes
From: Marek Vasut @ 2026-06-18 22:02 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Yoshihiro Shimoda, Krzysztof Wilczyński,
Bjorn Helgaas, Catalin Marinas, Conor Dooley, Geert Uytterhoeven,
Krzysztof Kozlowski, Lorenzo Pieralisi, Manivannan Sadhasivam,
Marc Zyngier, Rob Herring, devicetree, linux-arm-kernel,
linux-doc, linux-kernel, linux-renesas-soc
In-Reply-To: <20260618220427.14325-1-marek.vasut+renesas@mailbox.org>
This SoC implements GIC600 with GICv3 ITS and PCIe host mode on this
SoC can use it. Add GIC ITS node into GIC node, update interrupt-map
and add msi-map into PCIe controller node.
The GIC ITS does have master interface to issue transactions to RAM.
The interface does support cacheable transactions, however, it does
not support shareable attribute, because the AXI port signals are tied
to inactive in this implementation. Therefore, add "dma-noncoherent"
DT property into the GIC ITS subnode.
The GIC redistributor does not have cacheable/shareable, therefore
add "dma-noncoherent" DT property into the GIC node.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
NOTE: This would not be possible without prior work from Shimoda-san
https://lore.kernel.org/all/20240214052144.1966569-1-yoshihiro.shimoda.uh@renesas.com/
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
V2: No change
---
arch/arm64/boot/dts/renesas/r8a779g0.dtsi | 31 ++++++++++++++++-------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
index 3a8af825bb253..82e864acf2601 100644
--- a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
@@ -792,6 +792,7 @@ pciec0: pcie@e65d0000 {
resets = <&cpg 624>;
reset-names = "pwr";
max-link-speed = <4>;
+ msi-parent = <&its>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
@@ -802,10 +803,10 @@ pciec0: pcie@e65d0000 {
dma-ranges = <0x42000000 0 0x00000000 0 0x00000000 1 0x00000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
- interrupt-map = <0 0 0 1 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 2 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 3 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 4 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>;
snps,enable-cdm-check;
status = "disabled";
@@ -839,6 +840,7 @@ pciec1: pcie@e65d8000 {
resets = <&cpg 625>;
reset-names = "pwr";
max-link-speed = <4>;
+ msi-parent = <&its>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
@@ -849,10 +851,10 @@ pciec1: pcie@e65d8000 {
dma-ranges = <0x42000000 0 0x00000000 0 0x00000000 1 0x00000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
- interrupt-map = <0 0 0 1 &gic GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 2 &gic GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 3 &gic GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 4 &gic GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>;
snps,enable-cdm-check;
status = "disabled";
@@ -2131,11 +2133,22 @@ ipmmu_mm: iommu@eefc0000 {
gic: interrupt-controller@f1000000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
- #address-cells = <0>;
+ #address-cells = <2>;
+ #size-cells = <2>;
interrupt-controller;
reg = <0x0 0xf1000000 0 0x20000>,
<0x0 0xf1060000 0 0x110000>;
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ dma-noncoherent;
+
+ ranges = <0x0 0x0 0x0 0xf1000000 0x0 0x200000>;
+
+ its: msi-controller@40000 {
+ compatible = "arm,gic-v3-its";
+ reg = <0x0 0x40000 0x0 0x20000>;
+ dma-noncoherent;
+ msi-controller;
+ };
};
gpu: gpu@fd000000 {
--
2.53.0
^ permalink raw reply related
* Re: [PATCH 1/3] PCI: rcar-gen4: Configure AXIINTC if iMSI-RX not used
From: Marek Vasut @ 2026-06-18 21:53 UTC (permalink / raw)
To: Marc Zyngier, Marek Vasut
Cc: linux-pci, Yoshihiro Shimoda, Krzysztof Wilczyński,
Bjorn Helgaas, Catalin Marinas, Conor Dooley, Geert Uytterhoeven,
Krzysztof Kozlowski, Lorenzo Pieralisi, Manivannan Sadhasivam,
Rob Herring, devicetree, linux-arm-kernel, linux-doc,
linux-kernel, linux-renesas-soc
In-Reply-To: <8633yltylq.wl-maz@kernel.org>
On 6/17/26 9:28 AM, Marc Zyngier wrote:
[...]
>> +/* INTC address */
>> +#define AXIINTCADDR 0x0a00
>> +/* GITS GIC ITS translation register */
>> +#define AXIINTCADDR_VAL 0xf1050000
>
> Wouldn't it be preferable to source the address from the device tree,
> rather than hardcoding this?
It would, I will do so in V2.
^ permalink raw reply
* Re: [PATCH 2/3] irqchip/gic-v3: Add Renesas R-Car Gen4 erratum workaround
From: Marek Vasut @ 2026-06-18 21:54 UTC (permalink / raw)
To: Marc Zyngier
Cc: Marek Vasut, linux-pci, Yoshihiro Shimoda,
Krzysztof Wilczyński, Bjorn Helgaas, Catalin Marinas,
Conor Dooley, Geert Uytterhoeven, Krzysztof Kozlowski,
Lorenzo Pieralisi, Manivannan Sadhasivam, Rob Herring, devicetree,
linux-arm-kernel, linux-doc, linux-kernel, linux-renesas-soc
In-Reply-To: <86ldccs0oj.wl-maz@kernel.org>
On 6/18/26 10:38 AM, Marc Zyngier wrote:
Hello Marc,
>>>> Renesas R-Car S4/V4H/V4M GIC600 integration has address width for AXI
>>>> or APB interface configured to 32 bit, it can therefore access only
>>>> the first 4 GiB of physical address space. This information comes from
>>>> R-Car V4H Interface Specification sheet, there is currently no technical
>>>> update number assigned to this limitation. Further input from hardware
>>>> engineer indicates that this limitation also applies to R-Car S4 and V4M.
>>>> Name the limitation GEN4GICITS1, and add a driver quirk to mitigate this
>>>> limitation.
>>
>> My concern is this ^ , I do not have an erratum number, because there
>> isn't one. I am in touch with the hardware engineer and I did get a
>> glimpse at internal details of the three SoC, which confirm the
>> limitations. Is this sufficient ?
>
> To be honest, this is between you and the SoC vendor. I'll take
> whatever symbol you come up with at face value, and will assume that
> the vendor agrees with it. After all, they are on Cc and have their
> SoB on the patch.
All right.
>>>> Note that the 0x0201743b GIC600 ID is not Renesas-specific, it is
>>>> common for many ARM GICv3 implementations. Therefore, add an extra
>>>
>>> Not quite. It designates GIC600 unambiguously.
>>
>> What I am trying to communicate is, that the 0x0201743b ID is not ID
>> of the Renesas GIC implementation, but it is a generic ARM GIC600
>> ID. That is why we cannot match the quirk on the ID (it is generic ARM
>> GIC600 ID), and instead we have to match the quirk on the [ ID
>> combined with of_machine_is_compatible("renesas,...") ].
>
> This is understood, and is no different from the other broken
> platforms in the tree.
>
>>
>>> It is just that GIC600
>>> is integrated in zillions of SoCs, most of which don't have this
>>> problem (the machine I'm typing this from has a GIC600 *and* 96GB of
>>> RAM).
>>
>> Right.
>>
>> Shall I reword this paragraph somehow to make it clearer ?
>
> I'd simply say that the workaround is keyed on the combination of the
> GIC implementation and the platform identification in the device tree.
OK
>>>> of_machine_is_compatible() check.
>>>>
>>>> The GIC600 implementation in R-Car S4/V4H/V4M is r1p6.
>>>
>>> Is this relevant?
>>
>> I included it for the sake of completeness and to provide all relevant
>> information, based on previous discussions about similar limitations
>> that I could find on lore.k.o
>
> This information is already contained in the ID you quote (bits
> [19:12]), and can be decoded using the public TRM [1].
I'll drop it then.
Thanks
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: PCI: qcom: Document the Hawi PCIe Controller
From: sashiko-bot @ 2026-06-18 22:06 UTC (permalink / raw)
To: Matthew Leung; +Cc: conor+dt, linux-pci, robh, devicetree
In-Reply-To: <20260618-hawi-pcie-v3-1-f31880bfb3ec@oss.qualcomm.com>
> Add a dedicated schema for the PCIe controllers found on the Hawi
> platform.
>
> Signed-off-by: Matthew Leung <matthew.leung@oss.qualcomm.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-hawi-pcie-v3-0-f31880bfb3ec@oss.qualcomm.com?part=1
^ permalink raw reply
* Re: [PATCH v1 1/3] dt-bindings: sound: qcom,q6apm-dai: add optional qcom,vmid
From: Srinivas Kandagatla @ 2026-06-18 22:14 UTC (permalink / raw)
To: Ajay Kumar Nandam, Srinivas Kandagatla, Liam Girdwood, Mark Brown,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jaroslav Kysela,
Takashi Iwai
Cc: linux-sound, linux-arm-msm, devicetree, linux-kernel,
mohammad.rafi.shaik
In-Reply-To: <20260609064038.492641-2-ajay.nandam@oss.qualcomm.com>
On 6/9/26 7:40 AM, Ajay Kumar Nandam wrote:
> Add an optional qcom,vmid property for q6apm-dais nodes to describe
> additional VMIDs that should be granted access to PCM DMA buffers.
>
> The property is optional and bounded, and driver-side validation will
> reject invalid values such as including HLOS in the list or VMIDs that
> exceed 31, matching current SCM source-permission mask handling.
This is totally sounding like non-human text and not really adding any
value other than word count to the commit log.
It would be simple and clean to describe why this property is needed
and which platforms would be benifit from this.
>
> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
> ---
> .../devicetree/bindings/sound/qcom,q6apm-dai.yaml | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml
> index 9e5b30d9c6e6..b767625985a7 100644
> --- a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml
> +++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml
> @@ -20,6 +20,16 @@ properties:
> minItems: 1
> maxItems: 2
>
> + qcom,vmid:
> + description: Optional list of destination VMIDs to share PCM DMA buffers with.
> + HLOS retains RW access as source owner and must not be listed.
Description is not clear and accurate, this property is mandatory on
some platforms where we have mDSP providing audio services.
Pl remove HLOS and expand VMID.
> + $ref: /schemas/types.yaml#/definitions/uint32-array
> + items:
> + minimum: 1
> + maximum: 31
Why is the max value 31, do you have predefined list of VMIDs ?
> + minItems: 1
> + maxItems: 8
> +
> required:
> - compatible
> - iommus
^ permalink raw reply
* [PATCH v5 0/2] Add support for LTC3208 multi-display driver
From: Jan Carlo Roleda @ 2026-06-18 22:45 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, linux-leds, devicetree, Jan Carlo Roleda,
Krzysztof Kozlowski
The LTC3208 is a multi-display LED driver, using a high-efficiency, low
noise charge pump to provide power to 5 channels (MAIN, SUB, RGB, CAM,
AUX). Current for each LED is controlled by the I2C serial interface.
Four AUX current sources can be independently assigned via the I2C port
to the CAM, SUB, MAIN, or AUX DAC controlled displays
Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
---
Changes in v5:
- Fixed MAINTAINERS commit ordering
- removed i2c_client from ltc3208_dev
- renamed ltc3208_dev struct to ltc3208
- refactored brightness_set function to use regmap_field
- updated leds attribute to use constant size array
- updated regmap_config to use REGCACHE_FLAT_S cache type
- added max_register to regmap_config
- renamed variables in probe function
- renamed map to regmap for regmap instances
- moved AUX channel configuration inline to probe
- Link to v4: https://lore.kernel.org/r/20260416-upstream-ltc3208-v4-0-3884ed3e49f5@analog.com
Changes in v4:
- Reordered commit order to match dependency order
- Updated Kconfig to be more descriptive of device
- Added led@0-7 with more complete example properties (function and
color)
- Driver changes:
-- Removed unnecessary include headers
-- Formatted macros
-- Created helper `write_current_level` functions for LED current
configuration, using `regmap_update_bits()`
-- Adjusted awkward tabbing issues
-- Updated variable names in probe to be more descriptive
-- Updated inline comment capitalization
-- Initialized `i` within the for loop in AUX configuration in probe
-- Refactored `update_aux_dac` function to use array pointer
-- Fixed error messages in probe
- Link to v3: https://lore.kernel.org/r/20260406-upstream-ltc3208-v3-0-7f0b1d20ee7a@analog.com
Changes in v3:
- Edited device bindings descriptions
-- removed full stop in title
-- replaced quotes with double quotes for consistency
-- removed <dt-bindings/gpio/gpio.h> from example
-- removed led1-7 in example for brevity
- squashed maintainers commit to driver commit
- Link to v2: https://lore.kernel.org/r/20260326-upstream-ltc3208-v2-0-3dbc992b6098@analog.com
Changes in v2:
- Addressed DTSchema bot warnings and errors
-- removed extra blank lines
-- fixed $id to match current naming
- Addressed Kernel test warnings
-- fixed bounds for aux channel configurations
- Link to v0: https://lore.kernel.org/r/20260318-upstream-ltc3208-v1-0-015f1f1e9065@analog.com
---
Jan Carlo Roleda (2):
dt-bindings: leds: Document LTC3208 Multidisplay LED Driver
leds: ltc3208: Add driver for LTC3208 Multidisplay LED Driver
.../devicetree/bindings/leds/adi,ltc3208.yaml | 181 ++++++++++++++++
MAINTAINERS | 8 +
drivers/leds/Kconfig | 12 ++
drivers/leds/Makefile | 1 +
drivers/leds/leds-ltc3208.c | 239 +++++++++++++++++++++
5 files changed, 441 insertions(+)
---
base-commit: d43f1d792902ba0a53fd311bff2cf96095c7606d
change-id: 20260318-upstream-ltc3208-7cc8968bf69e
Best regards,
--
Jan Carlo Roleda <jancarlo.roleda@analog.com>
^ permalink raw reply
* [PATCH v5 2/2] leds: ltc3208: Add driver for LTC3208 Multidisplay LED Driver
From: Jan Carlo Roleda @ 2026-06-18 22:45 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, linux-leds, devicetree, Jan Carlo Roleda
In-Reply-To: <20260619-upstream-ltc3208-v5-0-075d18060606@analog.com>
Kernel driver implementation for LTC3208 Multidisplay LED Driver.
The LTC3208 is a Multi-display LED driver, designed to control up to
7 distinct LED channels (MAIN, SUB, AUX, CAMHI, CAMLO, RED, GREEN, BLUE),
each configurable with its own current level that is equally set to its
respective output current source pins for external LEDs.
It is programmed via the I2C serial interface.
MAIN and SUB support 8-bit current level resolution,
while AUX, CAMHI/LO, RED, GREEN, and BLUE support 4-bit levels.
The AUX LED channel can be configured to mirror the CAM, SUB, and MAIN
channel current levels, or as its own independent AUX channel.
The CAM LED channel is configured as 2 separate CAMHI and CAMLO register
sub-channels, which currnet is selected via the CAMHL pin, or set to
CAMHI register only via setting the S_CAMHILO bit high in register G (0x7).
Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
---
MAINTAINERS | 1 +
drivers/leds/Kconfig | 12 +++
drivers/leds/Makefile | 1 +
drivers/leds/leds-ltc3208.c | 239 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 253 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fd6ffdaaf04..e3b59485ecb3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15229,6 +15229,7 @@ L: linux-leds@vger.kernel.org
S: Maintained
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/leds/adi,ltc3208.yaml
+F: drivers/leds/leds-ltc3208.c
LTC4282 HARDWARE MONITOR DRIVER
M: Nuno Sa <nuno.sa@analog.com>
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index f4a0a3c8c870..d917ce3b72f4 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -1028,6 +1028,18 @@ config LEDS_ACER_A500
This option enables support for the Power Button LED of
Acer Iconia Tab A500.
+config LEDS_LTC3208
+ tristate "LED Driver for Analog Devices LTC3208"
+ depends on LEDS_CLASS && I2C
+ select REGMAP_I2C
+ help
+ Say Y to enable the LTC3208 LED driver.
+ This enables the LED device LTC3208, a 7-channel, 17-current source
+ multidisplay high-current LED driver, configured via I2C.
+
+ To compile this driver as a module, choose M here: the module will
+ be called ltc3208.
+
source "drivers/leds/blink/Kconfig"
comment "Flash and Torch LED drivers"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 7db3768912ca..0148b87e16ba 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
obj-$(CONFIG_LEDS_LP8864) += leds-lp8864.o
obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
+obj-$(CONFIG_LEDS_LTC3208) += leds-ltc3208.o
obj-$(CONFIG_LEDS_MAX5970) += leds-max5970.o
obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
obj-$(CONFIG_LEDS_MAX77705) += leds-max77705.o
diff --git a/drivers/leds/leds-ltc3208.c b/drivers/leds/leds-ltc3208.c
new file mode 100644
index 000000000000..fa2b6c6acc71
--- /dev/null
+++ b/drivers/leds/leds-ltc3208.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LED driver for Analog Devices LTC3208 Multi-Display Driver
+ *
+ * Copyright 2026 Analog Devices Inc.
+ *
+ * Author: Jan Carlo Roleda <jancarlo.roleda@analog.com>
+ */
+#include <linux/bitfield.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+/* Registers */
+#define LTC3208_REG_A_GRNRED 0x1 /* Green and Red current DAC*/
+#define LTC3208_REG_B_AUXBLU 0x2 /* AUX and Blue current DAC*/
+#define LTC3208_REG_C_MAIN 0x3 /* Main current DAC */
+#define LTC3208_REG_D_SUB 0x4 /* Sub current DAC */
+#define LTC3208_REG_E_AUX_SELECT 0x5 /* AUX DAC Select */
+#define LTC3208_AUX1_MASK GENMASK(1, 0)
+#define LTC3208_AUX2_MASK GENMASK(3, 2)
+#define LTC3208_AUX3_MASK GENMASK(5, 4)
+#define LTC3208_AUX4_MASK GENMASK(7, 6)
+#define LTC3208_REG_F_CAM 0x6 /* CAM (High and Low) current DAC*/
+#define LTC3208_REG_G_OPT 0x7 /* Device Options */
+#define LTC3208_OPT_CPO_MASK GENMASK(7, 6)
+#define LTC3208_OPT_DIS_RGBDROP BIT(3)
+#define LTC3208_OPT_DIS_CAMHILO BIT(2)
+#define LTC3208_OPT_EN_RGBS BIT(1)
+
+#define LTC3208_MAX_BRIGHTNESS_4BIT 0xF
+#define LTC3208_MAX_BRIGHTNESS_8BIT 0xFF
+
+#define LTC3208_NUM_LED_GRPS 8
+#define LTC3208_NUM_AUX_LEDS 4
+
+#define LTC3208_NUM_AUX_OPT 4
+#define LTC3208_MAX_CPO_OPT 3
+
+enum ltc3208_aux_channel {
+ LTC3208_AUX_CHAN_AUX = 0,
+ LTC3208_AUX_CHAN_MAIN,
+ LTC3208_AUX_CHAN_SUB,
+ LTC3208_AUX_CHAN_CAM
+};
+
+enum ltc3208_channel {
+ LTC3208_CHAN_MAIN = 0,
+ LTC3208_CHAN_SUB,
+ LTC3208_CHAN_AUX,
+ LTC3208_CHAN_CAML,
+ LTC3208_CHAN_CAMH,
+ LTC3208_CHAN_RED,
+ LTC3208_CHAN_BLUE,
+ LTC3208_CHAN_GREEN,
+ LTC3208_CHAN_N_COUNT,
+};
+
+static const char *const ltc3208_dt_aux_channels[] = { "adi,aux1-channel",
+ "adi,aux2-channel",
+ "adi,aux3-channel",
+ "adi,aux4-channel" };
+
+static const char *const ltc3208_aux_opt[] = { "aux", "main", "sub", "cam" };
+
+struct ltc3208_led {
+ struct led_classdev cdev;
+ struct i2c_client *client;
+ struct regmap_field *rfield;
+ enum ltc3208_channel channel;
+};
+
+struct ltc3208 {
+ struct ltc3208_led leds[LTC3208_NUM_LED_GRPS];
+ struct regmap *regmap;
+};
+
+static const struct regmap_config ltc3208_regmap_cfg = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LTC3208_REG_G_OPT,
+ .cache_type = REGCACHE_FLAT_S,
+};
+
+static const struct reg_field ltc3208_led_reg_field[LTC3208_CHAN_N_COUNT] = {
+ [LTC3208_CHAN_MAIN] = REG_FIELD(LTC3208_REG_C_MAIN, 0, 7),
+ [LTC3208_CHAN_SUB] = REG_FIELD(LTC3208_REG_D_SUB, 0, 7),
+ [LTC3208_CHAN_BLUE] = REG_FIELD(LTC3208_REG_B_AUXBLU, 0, 3),
+ [LTC3208_CHAN_AUX] = REG_FIELD(LTC3208_REG_B_AUXBLU, 4, 7),
+ [LTC3208_CHAN_CAML] = REG_FIELD(LTC3208_REG_F_CAM, 0, 3),
+ [LTC3208_CHAN_CAMH] = REG_FIELD(LTC3208_REG_F_CAM, 4, 7),
+ [LTC3208_CHAN_RED] = REG_FIELD(LTC3208_REG_A_GRNRED, 0, 3),
+ [LTC3208_CHAN_GREEN] = REG_FIELD(LTC3208_REG_A_GRNRED, 4, 7),
+};
+
+static int ltc3208_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct ltc3208_led *led =
+ container_of(led_cdev, struct ltc3208_led, cdev);
+ u8 current_level = brightness;
+
+ return regmap_field_write(led->rfield, current_level);
+}
+
+static int ltc3208_probe(struct i2c_client *client)
+{
+ enum ltc3208_aux_channel aux_channels[LTC3208_NUM_AUX_LEDS];
+ struct ltc3208 *ddata;
+ struct regmap *regmap;
+ bool disable_rgb_aux4_dropout_signal;
+ bool disable_camhl_pin;
+ bool set_sub_control_pin;
+ int ret;
+ u8 reg_val;
+
+ regmap = devm_regmap_init_i2c(client, <c3208_regmap_cfg);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(regmap),
+ "Failed to initialize regmap\n");
+
+ ddata = devm_kzalloc(&client->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ ddata->regmap = regmap;
+
+ disable_camhl_pin = device_property_read_bool(&client->dev,
+ "adi,disable-camhl-pin");
+ set_sub_control_pin =
+ device_property_read_bool(&client->dev, "adi,cfg-enrgbs-pin");
+ disable_rgb_aux4_dropout_signal = device_property_read_bool(
+ &client->dev, "adi,disable-rgb-aux4-dropout");
+
+ reg_val = FIELD_PREP(LTC3208_OPT_EN_RGBS, set_sub_control_pin) |
+ FIELD_PREP(LTC3208_OPT_DIS_CAMHILO, disable_camhl_pin) |
+ FIELD_PREP(LTC3208_OPT_DIS_RGBDROP,
+ disable_rgb_aux4_dropout_signal);
+
+ ret = regmap_write(regmap, LTC3208_REG_G_OPT, reg_val);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "error writing to options register\n");
+
+ /* Initialize aux channel configurations */
+ for (int i = 0; i < LTC3208_NUM_AUX_LEDS; i++) {
+ ret = device_property_match_property_string(
+ &client->dev, ltc3208_dt_aux_channels[i],
+ ltc3208_aux_opt, LTC3208_NUM_AUX_OPT);
+ /* Fallback to default value (AUX) if not found */
+ if (ret == -EINVAL)
+ aux_channels[i] = LTC3208_AUX_CHAN_AUX;
+ else if (ret >= 0)
+ aux_channels[i] = ret;
+ }
+
+ reg_val = FIELD_PREP(LTC3208_AUX1_MASK, aux_channels[0]) |
+ FIELD_PREP(LTC3208_AUX2_MASK, aux_channels[1]) |
+ FIELD_PREP(LTC3208_AUX3_MASK, aux_channels[2]) |
+ FIELD_PREP(LTC3208_AUX4_MASK, aux_channels[3]);
+
+ ret = regmap_write(regmap, LTC3208_REG_E_AUX_SELECT, reg_val);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "error writing to aux channel register.\n");
+
+ i2c_set_clientdata(client, ddata);
+
+ device_for_each_child_node_scoped(&client->dev, child) {
+ struct ltc3208_led *led;
+ struct led_init_data init_data = {};
+ u32 chan;
+
+ ret = fwnode_property_read_u32(child, "reg", &chan);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to get reg value of LED\n");
+ else if (chan >= LTC3208_NUM_LED_GRPS)
+ return dev_err_probe(&client->dev, ret,
+ "%d is an invalid LED ID\n", chan);
+
+ led = &ddata->leds[chan];
+
+ led->rfield =
+ devm_regmap_field_alloc(&client->dev, ddata->regmap,
+ ltc3208_led_reg_field[chan]);
+ if (IS_ERR(led->rfield))
+ return dev_err_probe(&client->dev, PTR_ERR(led->rfield),
+ "cannot allocate regmap field\n");
+ led->client = client;
+ led->channel = chan;
+ led->cdev.brightness_set_blocking = ltc3208_led_set_brightness;
+ led->cdev.max_brightness = LTC3208_MAX_BRIGHTNESS_4BIT;
+
+ if (chan == LTC3208_CHAN_MAIN || chan == LTC3208_CHAN_SUB)
+ led->cdev.max_brightness = LTC3208_MAX_BRIGHTNESS_8BIT;
+
+ init_data.fwnode = child;
+
+ ret = devm_led_classdev_register_ext(&client->dev, &led->cdev,
+ &init_data);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "LED %u Register failed.\n", chan);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id ltc3208_match_table[] = {
+ {.compatible = "adi,ltc3208"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, ltc3208_match_table);
+
+static const struct i2c_device_id ltc3208_idtable[] = {
+ { "ltc3208" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ltc3208_idtable);
+
+static struct i2c_driver ltc3208_driver = {
+ .driver = {
+ .name = "ltc3208",
+ .of_match_table = ltc3208_match_table,
+ },
+ .id_table = ltc3208_idtable,
+ .probe = ltc3208_probe,
+};
+module_i2c_driver(ltc3208_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan Carlo Roleda <jancarlo.roleda@analog.com>");
+MODULE_DESCRIPTION("LTC3208 LED Driver");
--
2.43.0
^ permalink raw reply related
* [PATCH v5 1/2] dt-bindings: leds: Document LTC3208 Multidisplay LED Driver
From: Jan Carlo Roleda @ 2026-06-18 22:45 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, linux-leds, devicetree, Jan Carlo Roleda,
Krzysztof Kozlowski
In-Reply-To: <20260619-upstream-ltc3208-v5-0-075d18060606@analog.com>
Add Devicetree Documentation for LTC3208 Multidisplay LED Driver.
Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../devicetree/bindings/leds/adi,ltc3208.yaml | 181 +++++++++++++++++++++
MAINTAINERS | 7 +
2 files changed, 188 insertions(+)
diff --git a/Documentation/devicetree/bindings/leds/adi,ltc3208.yaml b/Documentation/devicetree/bindings/leds/adi,ltc3208.yaml
new file mode 100644
index 000000000000..0a01e07e0ab7
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/adi,ltc3208.yaml
@@ -0,0 +1,181 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2026 Analog Devices, Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/adi,ltc3208.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LTC3208 Multidisplay LED Controller from Linear Technologies (Now Analog Devices)
+
+maintainers:
+ - Jan Carlo Roleda <jancarlo.roleda@analog.com>
+
+description:
+ The LTC3208 is a multidisplay LED controller that can support up to 1A to all
+ connected LEDs.
+
+ The datasheet for this device can be found in
+ https://www.analog.com/en/products/ltc3208.html
+
+properties:
+ compatible:
+ const: adi,ltc3208
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ adi,disable-camhl-pin:
+ type: boolean
+ description:
+ Configures whether the external CAMHL pin is disabled.
+ If disabled then the output pins associated with CAM will always select
+ the CAM register's high half-byte brightness.
+
+ adi,cfg-enrgbs-pin:
+ type: boolean
+ description:
+ Configures which channel the ENRGBS pin toggles when it receives a signal.
+ ENRGBS pin controls the SUB channel's output pins if this is set,
+ or RGB channel's output pins if this is unset.
+
+ adi,disable-rgb-aux4-dropout:
+ type: boolean
+ description:
+ Configures the RGB and AUX4 dropout signals to be disabled.
+
+ adi,aux1-channel:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ LED Channel that the AUX1 output pin mirrors its brightness level from.
+ enum: [aux, main, sub, cam]
+ default: aux
+
+ adi,aux2-channel:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ LED Channel that the AUX2 output pin mirrors its brightness level from.
+ enum: [aux, main, sub, cam]
+ default: aux
+
+ adi,aux3-channel:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ LED Channel that the AUX3 output pin mirrors its brightness level from.
+ enum: [aux, main, sub, cam]
+ default: aux
+
+ adi,aux4-channel:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ LED Channel that the AUX4 output pin mirrors its brightness level from.
+ enum: [aux, main, sub, cam]
+ default: aux
+
+patternProperties:
+ "^led@[0-7]$":
+ type: object
+ $ref: /schemas/leds/common.yaml#
+ unevaluatedProperties: false
+ properties:
+ reg:
+ description:
+ LED Channel Number. each channel maps to a specific channel group used
+ to configure the brightness level of the output pins corresponding to
+ the channel.
+ enum:
+ - 0 # Main Channel (8-bit brightness)
+ - 1 # Sub Channel (8-bit brightness)
+ - 2 # AUX Channel (4-bit brightness)
+ - 3 # Camera Channel, Low-side byte (4-bit brightness)
+ - 4 # Camera Channel, High-side byte (4-bit brightness)
+ - 5 # Red Channel (4-bit brightness)
+ - 6 # Blue Channel (4-bit brightness)
+ - 7 # Green Channel (4-bit brightness)
+ required:
+ - reg
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/leds/common.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led-controller@1b {
+ compatible = "adi,ltc3208";
+ reg = <0x1b>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ adi,disable-camhl-pin;
+ adi,cfg-enrgbs-pin;
+ adi,disable-rgb-aux4-dropout;
+
+ /* MAIN */
+ led@0 {
+ reg = <0>;
+ function = LED_FUNCTION_ACTIVITY;
+ color = <LED_COLOR_ID_WHITE>;
+ };
+
+ /* SUB */
+ led@1 {
+ reg = <1>;
+ function = LED_FUNCTION_ACTIVITY;
+ color = <LED_COLOR_ID_WHITE>;
+ };
+
+ /* AUX */
+ led@2 {
+ reg = <2>;
+ function = LED_FUNCTION_ACTIVITY;
+ color = <LED_COLOR_ID_WHITE>;
+ };
+
+ /* CAMLO */
+ led@3 {
+ reg = <3>;
+ function = LED_FUNCTION_FLASH;
+ color = <LED_COLOR_ID_WHITE>;
+ };
+
+ /* CAMHI */
+ led@4 {
+ reg = <4>;
+ function = LED_FUNCTION_FLASH;
+ color = <LED_COLOR_ID_WHITE>;
+ };
+
+ /* RED */
+ led@5 {
+ reg = <5>;
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_RED>;
+ };
+
+ /* BLUE */
+ led@6 {
+ reg = <6>;
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_BLUE>;
+ };
+
+ /* GREEN */
+ led@7 {
+ reg = <7>;
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_GREEN>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..2fd6ffdaaf04 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15223,6 +15223,13 @@ W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
F: drivers/iio/temperature/ltc2983.c
+LTC3208 LED DRIVER
+M: Jan Carlo Roleda <jancarlo.roleda@analog.com>
+L: linux-leds@vger.kernel.org
+S: Maintained
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/devicetree/bindings/leds/adi,ltc3208.yaml
+
LTC4282 HARDWARE MONITOR DRIVER
M: Nuno Sa <nuno.sa@analog.com>
L: linux-hwmon@vger.kernel.org
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v5 2/2] leds: ltc3208: Add driver for LTC3208 Multidisplay LED Driver
From: sashiko-bot @ 2026-06-18 22:56 UTC (permalink / raw)
To: Jan Carlo Roleda; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260619-upstream-ltc3208-v5-2-075d18060606@analog.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Duplicate `reg` property values in the device tree cause global `leds_list` corruption due to registering the exact same `led_classdev` object multiple times.
- [Medium] The `aux_channels` stack array can be left uninitialized if device tree properties fail to match due to errors other than `-EINVAL` (e.g., `-ENOENT` or `-ENODATA`), leading to uninitialized memory being used to configure the register.
- [Medium] Falsely successful probe and premature loop abortion when an invalid LED ID is encountered because `ret` is strictly 0.
--
commit b568fbfe98ac0a2fda2a035cd233d75353b8718c
Author: Jan Carlo Roleda <jancarlo.roleda@analog.com>
Subject: leds: ltc3208: Add driver for LTC3208 Multidisplay LED Driver
Kernel driver implementation for LTC3208 Multidisplay LED Driver.
The LTC3208 is a Multi-display LED driver, designed to control up to
7 distinct LED channels.
> diff --git a/drivers/leds/leds-ltc3208.c b/drivers/leds/leds-ltc3208.c
> new file mode 100644
> index 0000000000000..fa2b6c6acc713
> --- /dev/null
> +++ b/drivers/leds/leds-ltc3208.c
[ ... ]
> + /* Initialize aux channel configurations */
> + for (int i = 0; i < LTC3208_NUM_AUX_LEDS; i++) {
> + ret = device_property_match_property_string(
> + &client->dev, ltc3208_dt_aux_channels[i],
> + ltc3208_aux_opt, LTC3208_NUM_AUX_OPT);
> + /* Fallback to default value (AUX) if not found */
> + if (ret == -EINVAL)
> + aux_channels[i] = LTC3208_AUX_CHAN_AUX;
> + else if (ret >= 0)
> + aux_channels[i] = ret;
> + }
> +
> + reg_val = FIELD_PREP(LTC3208_AUX1_MASK, aux_channels[0]) |
> + FIELD_PREP(LTC3208_AUX2_MASK, aux_channels[1]) |
> + FIELD_PREP(LTC3208_AUX3_MASK, aux_channels[2]) |
> + FIELD_PREP(LTC3208_AUX4_MASK, aux_channels[3]);
[Severity: Medium]
What happens to aux_channels[i] if device_property_match_property_string()
returns an error code other than -EINVAL, such as -ENODATA?
It appears aux_channels[i] would remain uninitialized on the stack, and
this uninitialized memory would then be passed to FIELD_PREP() and
written to the LTC3208_REG_E_AUX_SELECT register.
Would it be safer to have a default catch-all else branch, or to fully
initialize the aux_channels array when it is declared?
[ ... ]
> + device_for_each_child_node_scoped(&client->dev, child) {
> + struct ltc3208_led *led;
> + struct led_init_data init_data = {};
> + u32 chan;
> +
> + ret = fwnode_property_read_u32(child, "reg", &chan);
> + if (ret)
> + return dev_err_probe(&client->dev, ret,
> + "Failed to get reg value of LED\n");
> + else if (chan >= LTC3208_NUM_LED_GRPS)
> + return dev_err_probe(&client->dev, ret,
> + "%d is an invalid LED ID\n", chan);
[Severity: Medium]
Does this return a success code of 0 instead of an error?
Because the preceding fwnode_property_read_u32() call succeeded, ret is
exactly 0 in this else if branch.
Calling dev_err_probe() with a 0 return code will cause the probe function
to abort iterating through the children but return a success status to the
driver core, masking the probe failure.
Should this return an explicit error like -EINVAL instead?
> +
> + led = &ddata->leds[chan];
> +
> + led->rfield =
> + devm_regmap_field_alloc(&client->dev, ddata->regmap,
> + ltc3208_led_reg_field[chan]);
[ ... ]
> + ret = devm_led_classdev_register_ext(&client->dev, &led->cdev,
> + &init_data);
[Severity: High]
Can duplicate reg properties in the device tree corrupt the led_classdev
list?
If a malformed device tree provides multiple children with the same reg
value, the driver will reuse the exact same struct ltc3208_led object
from the ddata->leds array without checking if it is already in use.
Calling devm_led_classdev_register_ext() multiple times with the identical
&led->cdev pointer would cause the LED core to add the same node to the
global leds_list twice, corrupting the doubly-linked list.
Could we add a check to verify if the channel has already been populated
before proceeding with registration?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260619-upstream-ltc3208-v5-0-075d18060606@analog.com?part=2
^ permalink raw reply
* [PATCH RFC 0/3] dt-bindings: iio: adc: Add reference, excitation and burn-out properties
From: Kurt Borja @ 2026-06-19 0:33 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner
Cc: Nuno Sá, Andy Shevchenko, linux-iio, devicetree,
linux-kernel, Kurt Borja
Hi all,
After submitting a patch series adding support for TI ADS126X ADCs [1],
I was made aware by David [2] that at least two more chip families,
ads1220 [3] and ads1x2c14, share very similar features (though these
chips are not really compatible between them). After that, I found one
more chip with the same features which is already upstream, the
AD4170-4.
As David explained in [2], these chips are intended to be used with
RTDs, thermocouples or other resistive sensors so they share the
following per-channel features:
- Configurable reference selection
- Burn-out Current Sources (BOCS) for diagnostic purpuses
- Excitation current sources (usually called IDACs TI) for sensor
current biasing
Given that these three features are present in all four devices and
three of these drivers are still under review, my proposal is to have
these features be described in adc.yaml and have this series merged
before the three others [1] [2] [3].
This series is sent as RFC because I still don't have much experience
with dt-bindings and I don't know if this approach or the properties are
general enough to be described like this.
No dependencies between properties were provided because not all devices
may be able to configure each one of them.
[1] https://lore.kernel.org/linux-iio/20260612-ads126x-v1-0-894c788d03ed@gmail.com/
[2] https://lore.kernel.org/linux-iio/20260615-iio-adc-ti-ads122c14-v1-0-e6bdadf7cb2b@baylibre.com/
[3] https://lore.kernel.org/linux-iio/20260610151342.44274-1-zizuzacker@gmail.com/
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
Kurt Borja (3):
dt-bindings: iio: adc: Add reference-source property
dt-bindings: iio: adc: Add excitation current sources properties
dt-bindings: iio: adc: Add burn-out current properties
Documentation/devicetree/bindings/iio/adc/adc.yaml | 47 ++++++++++++++++++++++
1 file changed, 47 insertions(+)
---
base-commit: a50909aa46dec46de3c73235fc15a7d6f763d996
change-id: 20260618-new-channel-props-4fbd52020da2
--
Thanks,
~ Kurt
^ permalink raw reply
* [PATCH RFC 1/3] dt-bindings: iio: adc: Add reference-source property
From: Kurt Borja @ 2026-06-19 0:33 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner
Cc: Nuno Sá, Andy Shevchenko, linux-iio, devicetree,
linux-kernel, Kurt Borja
In-Reply-To: <20260618-new-channel-props-v1-0-963c1b5cf40a@gmail.com>
Some ADCs have configurable voltage reference sources for each channel.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
Documentation/devicetree/bindings/iio/adc/adc.yaml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml
index b9bc02b5b07a4c..c74c2084fdb68c 100644
--- a/Documentation/devicetree/bindings/iio/adc/adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml
@@ -73,6 +73,16 @@ properties:
device design and can interact with other characteristics such as
settling time.
+ reference-source:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ maxItems: 2
+ minItems: 1
+ description:
+ Indicates the voltage reference source or sources for this channel.
+
+ This array describes either a single reference source or a positive and
+ negative reference sources.
+
anyOf:
- oneOf:
- required:
--
2.54.0
^ permalink raw reply related
* [PATCH RFC 2/3] dt-bindings: iio: adc: Add excitation current sources properties
From: Kurt Borja @ 2026-06-19 0:33 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner
Cc: Nuno Sá, Andy Shevchenko, linux-iio, devicetree,
linux-kernel, Kurt Borja
In-Reply-To: <20260618-new-channel-props-v1-0-963c1b5cf40a@gmail.com>
Some ADCs incorporate current sources that provide excitation current to
resistive temperature devices (RTDs), thermistors diodes and other
resistive sensors that require constant current biasing.
The maxItems constraint of 16 is arbitrary but should be big enough for
most devices.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
Documentation/devicetree/bindings/iio/adc/adc.yaml | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml
index c74c2084fdb68c..106b1e317411d5 100644
--- a/Documentation/devicetree/bindings/iio/adc/adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml
@@ -83,6 +83,29 @@ properties:
This array describes either a single reference source or a positive and
negative reference sources.
+ excitation-channels:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ maxItems: 16
+ minItems: 1
+ description:
+ Excitation current sources provide current to resistive temperature
+ devices (RTDs), thermistors diodes and other resistive sensors that
+ require constant current biasing.
+
+ This array describes the mux configuration of the excitation current
+ sources.
+
+ excitation-current-microamp:
+ maxItems: 16
+ minItems: 1
+ description:
+ Excitation current sources provide current to resistive temperature
+ devices (RTDs), thermistors diodes and other resistive sensors that
+ require constant current biasing.
+
+ This array describes the current configuration of the excitation current
+ sources or the single matched current for all sources.
+
anyOf:
- oneOf:
- required:
--
2.54.0
^ permalink raw reply related
* [PATCH RFC 3/3] dt-bindings: iio: adc: Add burn-out current properties
From: Kurt Borja @ 2026-06-19 0:33 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner
Cc: Nuno Sá, Andy Shevchenko, linux-iio, devicetree,
linux-kernel, Kurt Borja
In-Reply-To: <20260618-new-channel-props-v1-0-963c1b5cf40a@gmail.com>
Some ADCs incorporate burn-out current sources that provide current to
the channel's input pins for open-circuit or short-circuit detection.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
Documentation/devicetree/bindings/iio/adc/adc.yaml | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml
index 106b1e317411d5..6b63aac9ac04dd 100644
--- a/Documentation/devicetree/bindings/iio/adc/adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml
@@ -106,6 +106,20 @@ properties:
This array describes the current configuration of the excitation current
sources or the single matched current for all sources.
+ burn-out-current-microamp:
+ description:
+ Burn-out current sources provide current to the channel's input pins for
+ open-circuit or short-circuit detection.
+
+ burn-out-current-polarity:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ Burn-out current sources provide current to the channel's input pins for
+ open-circuit or short-circuit detection.
+ enum:
+ - pull-up
+ - pull-down
+
anyOf:
- oneOf:
- required:
--
2.54.0
^ permalink raw reply related
* Re: [PATCH RFC 1/3] dt-bindings: iio: adc: Add reference-source property
From: sashiko-bot @ 2026-06-19 0:40 UTC (permalink / raw)
To: Kurt Borja; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260618-new-channel-props-v1-1-963c1b5cf40a@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The `reference-source` property lacks specification for the order of positive and negative reference sources when two items are provided.
--
commit 5840bfcda5df91dc955f660547ba3a189d50489a
Author: Kurt Borja <kuurtb@gmail.com>
dt-bindings: iio: adc: Add reference-source property
This commit adds a new reference-source property to the IIO ADC bindings
to allow configuring the voltage reference source or sources for each channel.
> diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml
> --- a/Documentation/devicetree/bindings/iio/adc/adc.yaml
> +++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml
> @@ -73,6 +73,16 @@ properties:
> device design and can interact with other characteristics such as
> settling time.
>
> + reference-source:
> + $ref: /schemas/types.yaml#/definitions/uint32-array
> + maxItems: 2
> + minItems: 1
> + description:
> + Indicates the voltage reference source or sources for this channel.
> +
> + This array describes either a single reference source or a positive and
> + negative reference sources.
[Severity: Medium]
When two items are provided, how do we know which index corresponds to the
positive source and which to the negative source?
Without defining the order explicitly (for example, whether the first value
is positive and the second is negative), could this ambiguity lead to
inconsistent interpretations across different drivers and device trees?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-new-channel-props-v1-0-963c1b5cf40a@gmail.com?part=1
^ permalink raw reply
* Re: [PATCH RFC 3/3] dt-bindings: iio: adc: Add burn-out current properties
From: sashiko-bot @ 2026-06-19 0:45 UTC (permalink / raw)
To: Kurt Borja; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260618-new-channel-props-v1-3-963c1b5cf40a@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The `burn-out-current-microamp` property lacks array bounds (e.g., `maxItems`), allowing unbounded arrays to silently pass schema validation.
- [Low] The description for `burn-out-current-polarity` is incorrectly copy-pasted from `burn-out-current-microamp` and fails to describe the polarity property itself.
--
commit a77887c22cdfb0d199c09b61e65157768374c14a
Author: Kurt Borja <kuurtb@gmail.com>
dt-bindings: iio: adc: Add burn-out current properties
This commit adds the burn-out-current-microamp and burn-out-current-polarity
properties to the generic IIO ADC bindings to allow configuration of burn-out
current sources.
> diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml
> --- a/Documentation/devicetree/bindings/iio/adc/adc.yaml
> +++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml
> @@ -106,6 +106,20 @@ properties:
> This array describes the current configuration of the excitation current
> sources or the single matched current for all sources.
>
> + burn-out-current-microamp:
> + description:
> + Burn-out current sources provide current to the channel's input pins for
> + open-circuit or short-circuit detection.
[Severity: Medium]
Since standard device tree schema tools automatically map properties ending in
"-microamp" to an array structure, does this property need an array bound like
maxItems? Without bounds, the schema validator might incorrectly accept an
array of arbitrary size instead of enforcing a single configuration value per
channel.
> +
> + burn-out-current-polarity:
> + $ref: /schemas/types.yaml#/definitions/string
> + description:
> + Burn-out current sources provide current to the channel's input pins for
> + open-circuit or short-circuit detection.
[Severity: Low]
This isn't a bug, but it looks like this description was copy-pasted from
burn-out-current-microamp. Could the description be updated to explain what
the polarity configuration (pull-up/pull-down) actually does?
> + enum:
> + - pull-up
> + - pull-down
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-new-channel-props-v1-0-963c1b5cf40a@gmail.com?part=3
^ permalink raw reply
* Re: [PATCH v3 1/3] dt-bindings: media: qcom,qcm2290-venus: document shikra Iris compatible
From: Vishnu Reddy @ 2026-06-19 3:38 UTC (permalink / raw)
To: Vikash Garodia, Bryan O'Donoghue, Dikshita Agarwal,
Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jorge Ramirez-Ortiz, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-media, devicetree, linux-kernel
In-Reply-To: <20260618-shikra_vpu-v3-1-1a32e26a35a1@oss.qualcomm.com>
On 6/18/2026 4:09 PM, Vikash Garodia wrote:
> Document the iris video accelerator used on shikra platforms by adding
> the qcom,shikra-iris compatible.
>
> Although QCM2290 and shikra share the same video hardware and overall
> integration, their SMMU programming differs. QCM2290 exposes separate
> stream IDs for the video hardware and the Xtensa path, requiring two
> explicit IOMMU entries, whereas shikra uses a masked SMR to collapse
> equivalent stream IDs into a single mapping. Due to QCM2290’s SID layout
> and Xtensa isolation requirements, such SMR masking is not applicable on
> QCM2290 platforms.
> Since shikra uses the same video hardware as QCM2290 and shares the same
> programming model and capabilities, it is added as a fallback compatible
> to qcom,qcm2290-venus, with conditional handling to allow either one or
> two IOMMU entries.
>
> Signed-off-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
> ---
> .../bindings/media/qcom,qcm2290-venus.yaml | 26 ++++++++++++++++------
> 1 file changed, 19 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/media/qcom,qcm2290-venus.yaml b/Documentation/devicetree/bindings/media/qcom,qcm2290-venus.yaml
> index 5977e7d0a71b4fb5681f1c2094439c251366f01f..b27899ebf164229ceff1ca5cda50ee30d875e953 100644
> --- a/Documentation/devicetree/bindings/media/qcom,qcm2290-venus.yaml
> +++ b/Documentation/devicetree/bindings/media/qcom,qcm2290-venus.yaml
> @@ -13,14 +13,13 @@ description:
> The Venus AR50_LITE IP is a video encode and decode accelerator present
> on Qualcomm platforms.
>
> -allOf:
> - - $ref: qcom,venus-common.yaml#
> -
> properties:
> compatible:
> oneOf:
> - items:
> - - const: qcom,sm6115-venus
> + - enum:
> + - qcom,shikra-venus
> + - qcom,sm6115-venus
> - const: qcom,qcm2290-venus
> - const: qcom,qcm2290-venus
>
> @@ -45,9 +44,6 @@ properties:
> - const: vcodec0_core
> - const: vcodec0_bus
>
> - iommus:
> - maxItems: 2
> -
> interconnects:
> maxItems: 2
>
> @@ -65,6 +61,22 @@ required:
> - power-domain-names
> - iommus
>
> +allOf:
> + - $ref: qcom,venus-common.yaml#
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: qcom,shikra-venus
> + then:
> + properties:
> + iommus:
> + maxItems: 1
> + else:
> + properties:
> + iommus:
> + maxItems: 2
> +
> unevaluatedProperties: false
>
> examples:
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH 1/4] dt-bindings: input: Add binding for Qualcomm SPMI PMIC haptics
From: Krzysztof Kozlowski @ 2026-06-19 4:18 UTC (permalink / raw)
To: Fenglin Wu
Cc: linux-arm-msm, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lee Jones, Stephen Boyd, Bjorn Andersson,
Konrad Dybcio, David Collins, Subbaraman Narayanamurthy,
Kamal Wadhwa, kernel, linux-input, devicetree, linux-kernel
In-Reply-To: <c7191868-d141-4095-b703-230237721f28@oss.qualcomm.com>
On 17/06/2026 13:02, Fenglin Wu wrote:
>
> On 6/17/2026 6:35 PM, Krzysztof Kozlowski wrote:
>> On Tue, Jun 16, 2026 at 03:08:24AM -0700, Fenglin Wu wrote:
>>> ....
>>> +
>>> + qcom,lra-period-us:
>>> + description:
>>> + LRA actuator initial resonance period in microseconds
>>> + (1,000,000 / resonant_freq_hz). Used to configure T_LRA-based play
>>> + rates and the auto-resonance zero-crossing window.
>> This does not feel like static characteristic. Isn't period depending on
>> intensity of vibration you want to have? Why would that be fixed per
>> board?
>
> This period is specifically used for playbacks that require
> auto-resonance to be enabled, which I referred to as "T_LRA-based" and
> "auto-resonance zero-crossing window." It plays a key role in the
> "DIRECT_PLAY" mode, which produces a constant vibration effect. To
> adjust the vibration intensity during this constant effect, the hardware
> does it by scaling the peak voltage of the driver signals, rather than
> changing the frequency.
But maybe changing frequency runtime still would be useful?
What does the frequency depend on? IOW, how do you choose the value here
- based on some motor-part characteristics?
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 2/3] arm64: dts: qcom: shikra: Add Iris video codec node
From: Vishnu Reddy @ 2026-06-19 4:38 UTC (permalink / raw)
To: Vikash Garodia, Bryan O'Donoghue, Dikshita Agarwal,
Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jorge Ramirez-Ortiz, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-media, devicetree, linux-kernel,
Konrad Dybcio, Dmitry Baryshkov
In-Reply-To: <20260618-shikra_vpu-v3-2-1a32e26a35a1@oss.qualcomm.com>
On 6/18/2026 4:09 PM, Vikash Garodia wrote:
> Add the Iris video codec device tree node for the Shikra platform.
>
> Shikra reuses the QCM2290-class video hardware and programming model.
> The video node is added to describe the Iris based video decoder
> encoder block, allowing the media driver to probe and initialize
> the hardware.
>
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> Signed-off-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/shikra.dtsi | 61 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 61 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/shikra.dtsi b/arch/arm64/boot/dts/qcom/shikra.dtsi
> index 1ccb0f1419aaa34d32f3c3eaabdb8727a497b501..d8edd14d1f81a49e352f6939d27ea9cf8bb0f019 100644
> --- a/arch/arm64/boot/dts/qcom/shikra.dtsi
> +++ b/arch/arm64/boot/dts/qcom/shikra.dtsi
> @@ -655,6 +655,67 @@ gpucc: clock-controller@5990000 {
> #power-domain-cells = <1>;
> };
>
> + iris: video-codec@5a00000 {
> + compatible = "qcom,shikra-venus", "qcom,qcm2290-venus";
> + reg = <0x0 0x5a00000 0x0 0x200000>;
> + interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH 0>;
> +
> + power-domains = <&gcc GCC_VENUS_GDSC>,
> + <&gcc GCC_VCODEC0_GDSC>,
> + <&rpmpd QCM2290_VDDCX>;
> + power-domain-names = "venus",
> + "vcodec0",
> + "cx";
> + operating-points-v2 = <&venus_opp_table>;
> +
> + clocks = <&gcc GCC_VIDEO_VENUS_CTL_CLK>,
> + <&gcc GCC_VIDEO_AHB_CLK>,
> + <&gcc GCC_VENUS_CTL_AXI_CLK>,
> + <&gcc GCC_VIDEO_THROTTLE_CORE_CLK>,
> + <&gcc GCC_VIDEO_VCODEC0_SYS_CLK>,
> + <&gcc GCC_VCODEC0_AXI_CLK>;
> + clock-names = "core",
> + "iface",
> + "bus",
> + "throttle",
> + "vcodec0_core",
> + "vcodec0_bus";
> +
> + memory-region = <&video_mem>;
> + interconnects = <&mmnrt_virt MASTER_VIDEO_P0 RPM_ALWAYS_TAG
> + &mc_virt SLAVE_EBI_CH0 RPM_ALWAYS_TAG>,
> + <&mem_noc MASTER_AMPSS_M0 RPM_ACTIVE_TAG
> + &config_noc SLAVE_VENUS_CFG RPM_ACTIVE_TAG>;
> + interconnect-names = "video-mem",
> + "cpu-cfg";
> +
> + iommus = <&apps_smmu 0x780 0x0020>;
> +
> + venus_opp_table: opp-table {
> + compatible = "operating-points-v2";
> +
> + opp-133333333 {
> + opp-hz = /bits/ 64 <133333333>;
> + required-opps = <&rpmpd_opp_low_svs>;
> + };
> +
> + opp-240000000 {
> + opp-hz = /bits/ 64 <240000000>;
> + required-opps = <&rpmpd_opp_svs>;
> + };
> +
> + opp-300000000 {
> + opp-hz = /bits/ 64 <300000000>;
> + required-opps = <&rpmpd_opp_svs_plus>;
> + };
> +
> + opp-384000000 {
> + opp-hz = /bits/ 64 <384000000>;
> + required-opps = <&rpmpd_opp_nom>;
> + };
> + };
> + };
> +
> dispcc: clock-controller@5f00000 {
> compatible = "qcom,shikra-dispcc", "qcom,qcm2290-dispcc";
> reg = <0x0 0x05f00000 0x0 0x20000>;
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v3 3/3] arm64: dts: qcom: shikra-evk: Enable Iris core
From: Vishnu Reddy @ 2026-06-19 4:48 UTC (permalink / raw)
To: Vikash Garodia, Bryan O'Donoghue, Dikshita Agarwal,
Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jorge Ramirez-Ortiz, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-media, devicetree, linux-kernel,
Dmitry Baryshkov
In-Reply-To: <20260618-shikra_vpu-v3-3-1a32e26a35a1@oss.qualcomm.com>
On 6/18/2026 4:09 PM, Vikash Garodia wrote:
> Enable video en/decoder on the Shikra EVK board.
>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> Signed-off-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/shikra-evk.dtsi | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/shikra-evk.dtsi b/arch/arm64/boot/dts/qcom/shikra-evk.dtsi
> index d0c48bad704c61d17309753ba2a97e89bbfe083f..e2a3131594f0410931122657b12c8a6e70b435f0 100644
> --- a/arch/arm64/boot/dts/qcom/shikra-evk.dtsi
> +++ b/arch/arm64/boot/dts/qcom/shikra-evk.dtsi
> @@ -3,6 +3,12 @@
> * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> */
>
> +&iris {
> + firmware-name = "qcom/vpu/ar50lt_p1_gen2_s6.mbn";
> +
> + status = "okay";
> +};
> +
> &qupv3_0 {
> firmware-name = "qcom/shikra/qupv3fw.elf";
>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
^ permalink raw reply
* [PATCH 0/5] dmaengine: sun6i-dma: Add support for Allwinner A733 DMA controller
From: Yuanshen Cao @ 2026-06-19 4:53 UTC (permalink / raw)
To: Vinod Koul, Frank Li, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard
Cc: dmaengine, linux-arm-kernel, linux-sunxi, linux-kernel,
devicetree, Yuanshen Cao
Hi everyone,
This patch series introduces support for the Allwinner A733 DMA
controller in the `sun6i-dma` driver.
The A733 DMA controller differs from previous generations in several key
ways:
1. It supports higher address (up to 32G).
2. It uses a different interrupt register layout and mapping.
3. It has a different number of channels per interrupt register.
To support these differences without introducing complex conditional
logic throughout the driver, this series first refactors the
`sun6i_dma_config` structure. By moving interrupt handling, register
dumping, and address configuration into function pointers within the
configuration structure. This allows the driver to support the A733
and future hardware revisions. It also aligns with the DMA drivers in
Radxa BSP Package[1].
The series is organized as follows:
- Refactors the configuration structure to include function pointers for
interrupt and register operations.
- Moves address setting logic into the configuration structure to handle
varying address widths.
- Adds support for variable channels per interrupt register.
- Implements the A733-specific configuration and register mappings.
- Updates the device tree bindings documentation.
Tested on Radxa Cubie A7Z.
[1] https://github.com/radxa/allwinner-bsp/blob/cubie-aiot-v1.4.8/drivers/dma/sunxi-dma.c
Thanks!
Signed-off-by: Yuanshen Cao <alex.caoys@gmail.com>
---
Yuanshen Cao (5):
dmaengine: sun6i-dma: Refactor to support A733 interrupt and register handling
dmaengine: sun6i-dma: Add set_addr function pointer for variable address widths
dmaengine: sun6i-dma: Add num_channels_per_reg for flexible interrupt mapping
dmaengine: sun6i-dma: Implement support for Allwinner A733 DMA controller
dt-bindings: dma: sun50i-a64-dma: Update device tree bindings documentation for A733
.../bindings/dma/allwinner,sun50i-a64-dma.yaml | 2 +
drivers/dma/sun6i-dma.c | 223 +++++++++++++++++++--
2 files changed, 203 insertions(+), 22 deletions(-)
---
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
change-id: 20260619-sun60i-a733-dma-c2455149165d
Best regards,
--
Yuanshen Cao <alex.caoys@gmail.com>
^ permalink raw reply
* [PATCH 1/5] dmaengine: sun6i-dma: Refactor to support A733 interrupt and register handling
From: Yuanshen Cao @ 2026-06-19 4:53 UTC (permalink / raw)
To: Vinod Koul, Frank Li, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard
Cc: dmaengine, linux-arm-kernel, linux-sunxi, linux-kernel,
devicetree, Yuanshen Cao
In-Reply-To: <20260619-sun60i-a733-dma-v1-0-da4b649fc72a@gmail.com>
This patch is the first step in a refactoring effort to support the
Allwinner A733 DMA controller. Currently, the `sun6i-dma` driver has
several functions related to interrupt handling (reading/writing
interrupt enable and status registers) and register dumping that are
hardcoded.
To support the A733, which has different register layouts and interrupt
handling logic, these functions are being moved into the
`sun6i_dma_config` structure as function pointers. This allows the
driver to use a polymorphic approach where the specific implementation
is determined by the hardware configuration assigned during device
probing.
Changes:
- Added function pointers to `struct sun6i_dma_config` for:
- `dump_com_regs`
- `read_irq_en`
- `write_irq_en`
- `read_irq_stat`
- `write_irq_stat`
- Implemented generic `sun6i_read/write_irq_*` functions for existing
hardware.
- Updated existing `sun6i_dma_config` instances (A31, A23, H3, A64,
A100, H6, V3S) to use these new function pointers.
Signed-off-by: Yuanshen Cao <alex.caoys@gmail.com>
---
drivers/dma/sun6i-dma.c | 74 +++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 69 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index a9a254dbf8cb..d92e702320d9 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -138,6 +138,11 @@ struct sun6i_dma_config {
void (*set_burst_length)(u32 *p_cfg, s8 src_burst, s8 dst_burst);
void (*set_drq)(u32 *p_cfg, s8 src_drq, s8 dst_drq);
void (*set_mode)(u32 *p_cfg, s8 src_mode, s8 dst_mode);
+ void (*dump_com_regs)(struct sun6i_dma_dev *sdev);
+ u32 (*read_irq_en)(struct sun6i_dma_dev *sdev, u32 chan_num);
+ void (*write_irq_en)(struct sun6i_dma_dev *sdev, u32 chan_num, u32 irq_val);
+ u32 (*read_irq_stat)(struct sun6i_dma_dev *sdev, u32 chan_num);
+ void (*write_irq_stat)(struct sun6i_dma_dev *sdev, u32 chan_num, u32 status);
u32 src_burst_lengths;
u32 dst_burst_lengths;
u32 src_addr_widths;
@@ -347,6 +352,25 @@ static void sun6i_set_mode_h6(u32 *p_cfg, s8 src_mode, s8 dst_mode)
DMA_CHAN_CFG_DST_MODE_H6(dst_mode);
}
+static u32 sun6i_read_irq_en(struct sun6i_dma_dev *sdev, u32 chan_num)
+{
+ return readl(sdev->base + DMA_IRQ_EN(chan_num));
+}
+
+static void sun6i_write_irq_en(struct sun6i_dma_dev *sdev, u32 chan_num, u32 irq_val)
+{
+ writel(irq_val, sdev->base + DMA_IRQ_EN(chan_num));
+}
+static u32 sun6i_read_irq_stat(struct sun6i_dma_dev *sdev, u32 chan_num)
+{
+ return readl(sdev->base + DMA_IRQ_STAT(chan_num));
+}
+
+static void sun6i_write_irq_stat(struct sun6i_dma_dev *sdev, u32 chan_num, u32 status)
+{
+ writel(status, sdev->base + DMA_IRQ_STAT(chan_num));
+}
+
static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan)
{
struct sun6i_desc *txd = pchan->desc;
@@ -460,16 +484,16 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
vchan->irq_type = vchan->cyclic ? DMA_IRQ_PKG : DMA_IRQ_QUEUE;
- irq_val = readl(sdev->base + DMA_IRQ_EN(irq_reg));
+ irq_val = sdev->cfg->read_irq_en(sdev, irq_reg);
irq_val &= ~((DMA_IRQ_HALF | DMA_IRQ_PKG | DMA_IRQ_QUEUE) <<
(irq_offset * DMA_IRQ_CHAN_WIDTH));
irq_val |= vchan->irq_type << (irq_offset * DMA_IRQ_CHAN_WIDTH);
- writel(irq_val, sdev->base + DMA_IRQ_EN(irq_reg));
+ sdev->cfg->write_irq_en(sdev, irq_reg, irq_val);
writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR);
writel(DMA_CHAN_ENABLE_START, pchan->base + DMA_CHAN_ENABLE);
- sun6i_dma_dump_com_regs(sdev);
+ sdev->cfg->dump_com_regs(sdev);
sun6i_dma_dump_chan_regs(sdev, pchan);
return 0;
@@ -549,14 +573,14 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
u32 status;
for (i = 0; i < sdev->num_pchans / DMA_IRQ_CHAN_NR; i++) {
- status = readl(sdev->base + DMA_IRQ_STAT(i));
+ status = sdev->cfg->read_irq_stat(sdev, i);
if (!status)
continue;
dev_dbg(sdev->slave.dev, "DMA irq status %s: 0x%x\n",
str_high_low(i), status);
- writel(status, sdev->base + DMA_IRQ_STAT(i));
+ sdev->cfg->write_irq_stat(sdev, i, status);
for (j = 0; (j < DMA_IRQ_CHAN_NR) && status; j++) {
pchan = sdev->pchans + j;
@@ -1124,6 +1148,11 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_a31,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .dump_com_regs = sun6i_dma_dump_com_regs,
+ .read_irq_en = sun6i_read_irq_en,
+ .write_irq_en = sun6i_write_irq_en,
+ .read_irq_stat = sun6i_read_irq_stat,
+ .write_irq_stat = sun6i_write_irq_stat,
.src_burst_lengths = BIT(1) | BIT(8),
.dst_burst_lengths = BIT(1) | BIT(8),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1147,6 +1176,11 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_a31,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .dump_com_regs = sun6i_dma_dump_com_regs,
+ .read_irq_en = sun6i_read_irq_en,
+ .write_irq_en = sun6i_write_irq_en,
+ .read_irq_stat = sun6i_read_irq_stat,
+ .write_irq_stat = sun6i_write_irq_stat,
.src_burst_lengths = BIT(1) | BIT(8),
.dst_burst_lengths = BIT(1) | BIT(8),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1165,6 +1199,11 @@ static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_a31,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .dump_com_regs = sun6i_dma_dump_com_regs,
+ .read_irq_en = sun6i_read_irq_en,
+ .write_irq_en = sun6i_write_irq_en,
+ .read_irq_stat = sun6i_read_irq_stat,
+ .write_irq_stat = sun6i_write_irq_stat,
.src_burst_lengths = BIT(1) | BIT(8),
.dst_burst_lengths = BIT(1) | BIT(8),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1190,6 +1229,11 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_h3,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .dump_com_regs = sun6i_dma_dump_com_regs,
+ .read_irq_en = sun6i_read_irq_en,
+ .write_irq_en = sun6i_write_irq_en,
+ .read_irq_stat = sun6i_read_irq_stat,
+ .write_irq_stat = sun6i_write_irq_stat,
.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1211,6 +1255,11 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_h3,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .dump_com_regs = sun6i_dma_dump_com_regs,
+ .read_irq_en = sun6i_read_irq_en,
+ .write_irq_en = sun6i_write_irq_en,
+ .read_irq_stat = sun6i_read_irq_stat,
+ .write_irq_stat = sun6i_write_irq_stat,
.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1232,6 +1281,11 @@ static struct sun6i_dma_config sun50i_a100_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_h3,
.set_drq = sun6i_set_drq_h6,
.set_mode = sun6i_set_mode_h6,
+ .dump_com_regs = sun6i_dma_dump_com_regs,
+ .read_irq_en = sun6i_read_irq_en,
+ .write_irq_en = sun6i_write_irq_en,
+ .read_irq_stat = sun6i_read_irq_stat,
+ .write_irq_stat = sun6i_write_irq_stat,
.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1255,6 +1309,11 @@ static struct sun6i_dma_config sun50i_h6_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_h3,
.set_drq = sun6i_set_drq_h6,
.set_mode = sun6i_set_mode_h6,
+ .dump_com_regs = sun6i_dma_dump_com_regs,
+ .read_irq_en = sun6i_read_irq_en,
+ .write_irq_en = sun6i_write_irq_en,
+ .read_irq_stat = sun6i_read_irq_stat,
+ .write_irq_stat = sun6i_write_irq_stat,
.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1281,6 +1340,11 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_a31,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .dump_com_regs = sun6i_dma_dump_com_regs,
+ .read_irq_en = sun6i_read_irq_en,
+ .write_irq_en = sun6i_write_irq_en,
+ .read_irq_stat = sun6i_read_irq_stat,
+ .write_irq_stat = sun6i_write_irq_stat,
.src_burst_lengths = BIT(1) | BIT(8),
.dst_burst_lengths = BIT(1) | BIT(8),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
--
2.54.0
^ permalink raw reply related
* [PATCH 2/5] dmaengine: sun6i-dma: Add set_addr function pointer for variable address widths
From: Yuanshen Cao @ 2026-06-19 4:53 UTC (permalink / raw)
To: Vinod Koul, Frank Li, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard
Cc: dmaengine, linux-arm-kernel, linux-sunxi, linux-kernel,
devicetree, Yuanshen Cao
In-Reply-To: <20260619-sun60i-a733-dma-v1-0-da4b649fc72a@gmail.com>
The A733 DMA controller supports higher address (up to 32G) compared to
previous generations. The existing `sun6i_dma_set_addr` function uses a
hardcoded logic for setting the high-address bits in the LLI parameters.
By moving `set_addr` into the `sun6i_dma_config` structure, we can
provide specialized implementations for different hardware. This allows
the A733 to use a version of `set_addr` that correctly handles its
specific `SRC_HIGH_ADDR_32G` and `DST_HIGH_ADDR_32G` in the `set_addr`
register later in the series.
Changes:
- Added `set_addr` function pointer to `struct sun6i_dma_config`.
- Refactored `sun6i_dma_set_addr` and introduced
`sun6i_dma_set_addr_a100` (keeping the logic for high address
support).
- Updated all existing configuration structs to include the new
`set_addr` pointer.
- Removed `has_high_addr` since the logic is replaced by
`sun6i_dma_set_addr_a100`.
Signed-off-by: Yuanshen Cao <alex.caoys@gmail.com>
---
drivers/dma/sun6i-dma.c | 36 ++++++++++++++++++++++++++----------
1 file changed, 26 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index d92e702320d9..059455425e19 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -112,6 +112,7 @@
/* forward declaration */
struct sun6i_dma_dev;
+struct sun6i_dma_lli;
/*
* Hardware channels / ports representation
@@ -138,6 +139,8 @@ struct sun6i_dma_config {
void (*set_burst_length)(u32 *p_cfg, s8 src_burst, s8 dst_burst);
void (*set_drq)(u32 *p_cfg, s8 src_drq, s8 dst_drq);
void (*set_mode)(u32 *p_cfg, s8 src_mode, s8 dst_mode);
+ void (*set_addr)(struct sun6i_dma_dev *sdev, struct sun6i_dma_lli *v_lli,
+ dma_addr_t src, dma_addr_t dst);
void (*dump_com_regs)(struct sun6i_dma_dev *sdev);
u32 (*read_irq_en)(struct sun6i_dma_dev *sdev, u32 chan_num);
void (*write_irq_en)(struct sun6i_dma_dev *sdev, u32 chan_num, u32 irq_val);
@@ -147,7 +150,6 @@ struct sun6i_dma_config {
u32 dst_burst_lengths;
u32 src_addr_widths;
u32 dst_addr_widths;
- bool has_high_addr;
bool has_mbus_clk;
};
@@ -675,13 +677,20 @@ static int set_config(struct sun6i_dma_dev *sdev,
static inline void sun6i_dma_set_addr(struct sun6i_dma_dev *sdev,
struct sun6i_dma_lli *v_lli,
dma_addr_t src, dma_addr_t dst)
+{
+ v_lli->src = lower_32_bits(src);
+ v_lli->dst = lower_32_bits(dst);
+}
+
+static inline void sun6i_dma_set_addr_a100(struct sun6i_dma_dev *sdev,
+ struct sun6i_dma_lli *v_lli,
+ dma_addr_t src, dma_addr_t dst)
{
v_lli->src = lower_32_bits(src);
v_lli->dst = lower_32_bits(dst);
- if (sdev->cfg->has_high_addr)
- v_lli->para |= SRC_HIGH_ADDR(upper_32_bits(src)) |
- DST_HIGH_ADDR(upper_32_bits(dst));
+ v_lli->para |= SRC_HIGH_ADDR(upper_32_bits(src)) |
+ DST_HIGH_ADDR(upper_32_bits(dst));
}
static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
@@ -714,7 +723,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
v_lli->len = len;
v_lli->para = NORMAL_WAIT;
- sun6i_dma_set_addr(sdev, v_lli, src, dest);
+ sdev->cfg->set_addr(sdev, v_lli, src, dest);
burst = convert_burst(8);
width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
@@ -773,7 +782,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
v_lli->para = NORMAL_WAIT;
if (dir == DMA_MEM_TO_DEV) {
- sun6i_dma_set_addr(sdev, v_lli,
+ sdev->cfg->set_addr(sdev, v_lli,
sg_dma_address(sg),
sconfig->dst_addr);
v_lli->cfg = lli_cfg;
@@ -787,7 +796,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
sg_dma_len(sg), flags);
} else {
- sun6i_dma_set_addr(sdev, v_lli,
+ sdev->cfg->set_addr(sdev, v_lli,
sconfig->src_addr,
sg_dma_address(sg));
v_lli->cfg = lli_cfg;
@@ -858,7 +867,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
v_lli->para = NORMAL_WAIT;
if (dir == DMA_MEM_TO_DEV) {
- sun6i_dma_set_addr(sdev, v_lli,
+ sdev->cfg->set_addr(sdev, v_lli,
buf_addr + period_len * i,
sconfig->dst_addr);
v_lli->cfg = lli_cfg;
@@ -870,7 +879,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
&sconfig->dst_addr, &buf_addr,
buf_len, flags);
} else {
- sun6i_dma_set_addr(sdev, v_lli,
+ sdev->cfg->set_addr(sdev, v_lli,
sconfig->src_addr,
buf_addr + period_len * i);
v_lli->cfg = lli_cfg;
@@ -1148,6 +1157,7 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_a31,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .set_addr = sun6i_dma_set_addr,
.dump_com_regs = sun6i_dma_dump_com_regs,
.read_irq_en = sun6i_read_irq_en,
.write_irq_en = sun6i_write_irq_en,
@@ -1176,6 +1186,7 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_a31,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .set_addr = sun6i_dma_set_addr,
.dump_com_regs = sun6i_dma_dump_com_regs,
.read_irq_en = sun6i_read_irq_en,
.write_irq_en = sun6i_write_irq_en,
@@ -1199,6 +1210,7 @@ static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_a31,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .set_addr = sun6i_dma_set_addr,
.dump_com_regs = sun6i_dma_dump_com_regs,
.read_irq_en = sun6i_read_irq_en,
.write_irq_en = sun6i_write_irq_en,
@@ -1229,6 +1241,7 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_h3,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .set_addr = sun6i_dma_set_addr,
.dump_com_regs = sun6i_dma_dump_com_regs,
.read_irq_en = sun6i_read_irq_en,
.write_irq_en = sun6i_write_irq_en,
@@ -1255,6 +1268,7 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_h3,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .set_addr = sun6i_dma_set_addr,
.dump_com_regs = sun6i_dma_dump_com_regs,
.read_irq_en = sun6i_read_irq_en,
.write_irq_en = sun6i_write_irq_en,
@@ -1281,6 +1295,7 @@ static struct sun6i_dma_config sun50i_a100_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_h3,
.set_drq = sun6i_set_drq_h6,
.set_mode = sun6i_set_mode_h6,
+ .set_addr = sun6i_dma_set_addr_a100,
.dump_com_regs = sun6i_dma_dump_com_regs,
.read_irq_en = sun6i_read_irq_en,
.write_irq_en = sun6i_write_irq_en,
@@ -1296,7 +1311,6 @@ static struct sun6i_dma_config sun50i_a100_dma_cfg = {
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
- .has_high_addr = true,
.has_mbus_clk = true,
};
@@ -1309,6 +1323,7 @@ static struct sun6i_dma_config sun50i_h6_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_h3,
.set_drq = sun6i_set_drq_h6,
.set_mode = sun6i_set_mode_h6,
+ .set_addr = sun6i_dma_set_addr,
.dump_com_regs = sun6i_dma_dump_com_regs,
.read_irq_en = sun6i_read_irq_en,
.write_irq_en = sun6i_write_irq_en,
@@ -1340,6 +1355,7 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
.set_burst_length = sun6i_set_burst_length_a31,
.set_drq = sun6i_set_drq_a31,
.set_mode = sun6i_set_mode_a31,
+ .set_addr = sun6i_dma_set_addr,
.dump_com_regs = sun6i_dma_dump_com_regs,
.read_irq_en = sun6i_read_irq_en,
.write_irq_en = sun6i_write_irq_en,
--
2.54.0
^ permalink raw reply related
* [PATCH 3/5] dmaengine: sun6i-dma: Add num_channels_per_reg for flexible interrupt mapping
From: Yuanshen Cao @ 2026-06-19 4:53 UTC (permalink / raw)
To: Vinod Koul, Frank Li, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard
Cc: dmaengine, linux-arm-kernel, linux-sunxi, linux-kernel,
devicetree, Yuanshen Cao
In-Reply-To: <20260619-sun60i-a733-dma-v1-0-da4b649fc72a@gmail.com>
The previous implementation of `sun6i-dma` had some implicit assumptions
about the number of channels per interrupt register. Specifically,
functions like `sun6i_kill_tasklet` were hardcoded to only disable
interrupts for IRQ 0 and 1. `DMA_MAX_CHANNELS` is also not in used in
the past, and the old SoCs never has more than 16 channels.
The A733 has a different interrupt structure where the number of
channels per register may differ. This patch introduces
`num_channels_per_reg` to the `sun6i_dma_config`, similar to BSP, to
make the interrupt handling logic hardware-agnostic. It also sets
`DMA_MAX_CHANNELS` to 16 to align with the new BSP code and ensure loops
over interrupts are correctly bounded.
Changes:
- Change `DMA_MAX_CHANNELS` definition to 16.
- Added `num_channels_per_reg` to `struct sun6i_dma_config`.
- Replaced hardcoded IRQ register calculations with values from
`sdev->cfg->num_channels_per_reg`.
- Updated `sun6i_kill_tasklet` to loop through all possible interrupt
registers based on `DMA_MAX_CHANNELS` and the configuration.
Signed-off-by: Yuanshen Cao <alex.caoys@gmail.com>
---
drivers/dma/sun6i-dma.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 059455425e19..fb1c1a28744b 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -41,7 +41,7 @@
#define DMA_STAT 0x30
/* Offset between DMA_IRQ_EN and DMA_IRQ_STAT limits number of channels */
-#define DMA_MAX_CHANNELS (DMA_IRQ_CHAN_NR * 0x10 / 4)
+#define DMA_MAX_CHANNELS 16
/*
* sun8i specific registers
@@ -151,6 +151,7 @@ struct sun6i_dma_config {
u32 src_addr_widths;
u32 dst_addr_widths;
bool has_mbus_clk;
+ u32 num_channels_per_reg;
};
/*
@@ -481,8 +482,8 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
sun6i_dma_dump_lli(vchan, pchan->desc->v_lli, pchan->desc->p_lli);
- irq_reg = pchan->idx / DMA_IRQ_CHAN_NR;
- irq_offset = pchan->idx % DMA_IRQ_CHAN_NR;
+ irq_reg = pchan->idx / sdev->cfg->num_channels_per_reg;
+ irq_offset = pchan->idx % sdev->cfg->num_channels_per_reg;
vchan->irq_type = vchan->cyclic ? DMA_IRQ_PKG : DMA_IRQ_QUEUE;
@@ -574,7 +575,7 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
int i, j, ret = IRQ_NONE;
u32 status;
- for (i = 0; i < sdev->num_pchans / DMA_IRQ_CHAN_NR; i++) {
+ for (i = 0; i < sdev->num_pchans / sdev->cfg->num_channels_per_reg; i++) {
status = sdev->cfg->read_irq_stat(sdev, i);
if (!status)
continue;
@@ -584,7 +585,7 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
sdev->cfg->write_irq_stat(sdev, i, status);
- for (j = 0; (j < DMA_IRQ_CHAN_NR) && status; j++) {
+ for (j = 0; (j < sdev->cfg->num_channels_per_reg) && status; j++) {
pchan = sdev->pchans + j;
vchan = pchan->vchan;
if (vchan && (status & vchan->irq_type)) {
@@ -1108,9 +1109,11 @@ static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec,
static inline void sun6i_kill_tasklet(struct sun6i_dma_dev *sdev)
{
+ int i;
+
/* Disable all interrupts from DMA */
- writel(0, sdev->base + DMA_IRQ_EN(0));
- writel(0, sdev->base + DMA_IRQ_EN(1));
+ for (i = 0; i < DMA_MAX_CHANNELS / sdev->cfg->num_channels_per_reg; i++)
+ sdev->cfg->write_irq_en(sdev, i, 0);
/* Prevent spurious interrupts from scheduling the tasklet */
atomic_inc(&sdev->tasklet_shutdown);
@@ -1171,6 +1174,7 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR,
};
/*
@@ -1200,6 +1204,7 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR,
};
static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
@@ -1224,6 +1229,7 @@ static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR,
};
/*
@@ -1257,6 +1263,7 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR,
};
/*
@@ -1284,6 +1291,7 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR,
};
/*
@@ -1311,6 +1319,7 @@ static struct sun6i_dma_config sun50i_a100_dma_cfg = {
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR,
.has_mbus_clk = true,
};
@@ -1339,6 +1348,7 @@ static struct sun6i_dma_config sun50i_h6_dma_cfg = {
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR,
.has_mbus_clk = true,
};
@@ -1369,6 +1379,7 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR,
};
static const struct of_device_id sun6i_dma_match[] = {
--
2.54.0
^ permalink raw reply related
* [PATCH 4/5] dmaengine: sun6i-dma: Implement support for Allwinner A733 DMA controller
From: Yuanshen Cao @ 2026-06-19 4:53 UTC (permalink / raw)
To: Vinod Koul, Frank Li, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard
Cc: dmaengine, linux-arm-kernel, linux-sunxi, linux-kernel,
devicetree, Yuanshen Cao
In-Reply-To: <20260619-sun60i-a733-dma-v1-0-da4b649fc72a@gmail.com>
This patch implements the actual support for the Allwinner A733 DMA
controller. It defines the new register offsets and bitfield mappings
required for the A733, which slightly differs from the older `sun6i`
series.
Changes:
- New register macros for A733 interrupt enable `DMA_IRQ_EN_A733` and
status `DMA_IRQ_STAT_A733`.
- New `SRC_HIGH_ADDR_32G` and `DST_HIGH_ADDR_32G` macro to handle the
32G high-address field in the LLI.
- Implemented `sun6i_dma_set_addr_a733` and A733-specific interrupt
register accessors.
- Added `sun60i_a733_dma_config`, which ties all the refactored
functionality together for this specific hardware.
Signed-off-by: Yuanshen Cao <alex.caoys@gmail.com>
---
drivers/dma/sun6i-dma.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index fb1c1a28744b..9585b4a9e00d 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -52,6 +52,15 @@
#define SUNXI_H3_SECURE_REG 0x20
#define SUNXI_H3_DMA_GATE 0x28
#define SUNXI_H3_DMA_GATE_ENABLE 0x4
+
+/*
+ * sun60i specific registers
+ */
+#define DMA_IRQ_EN_A733(x) ((x) * 0x40 + 0x134)
+#define DMA_IRQ_STAT_A733(x) ((x) * 0x40 + 0x138)
+
+#define DMA_IRQ_CHAN_NR_A733 1
+
/*
* Channels specific registers
*/
@@ -100,6 +109,8 @@
*/
#define SRC_HIGH_ADDR(x) (((x) & 0x3U) << 16)
#define DST_HIGH_ADDR(x) (((x) & 0x3U) << 18)
+#define SRC_HIGH_ADDR_32G(x) (((x) & 0x7U) << 11)
+#define DST_HIGH_ADDR_32G(x) (((x) & 0x7U) << 15)
/*
* Various hardware related defines
@@ -257,6 +268,23 @@ static inline void sun6i_dma_dump_com_regs(struct sun6i_dma_dev *sdev)
DMA_STAT, readl(sdev->base + DMA_STAT));
}
+static inline void sun6i_dma_dump_com_regs_a733(struct sun6i_dma_dev *sdev)
+{
+ int i;
+
+ for (i = 0; i < sdev->num_pchans / sdev->cfg->num_channels_per_reg; i++) {
+ dev_dbg(sdev->slave.dev, "Common register:\n"
+ "chan num %d\n"
+ "\tmask(%04x): 0x%08x\n"
+ "\tpend(%04x): 0x%08x\n"
+ "\tstats(%04x): 0x%08x\n",
+ i,
+ DMA_IRQ_EN_A733(i), readl(sdev->base + DMA_IRQ_EN_A733(i)),
+ DMA_IRQ_STAT_A733(i), readl(sdev->base + DMA_IRQ_STAT_A733(i)),
+ DMA_STAT, readl(sdev->base + DMA_STAT));
+ }
+}
+
static inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev,
struct sun6i_pchan *pchan)
{
@@ -360,20 +388,41 @@ static u32 sun6i_read_irq_en(struct sun6i_dma_dev *sdev, u32 chan_num)
return readl(sdev->base + DMA_IRQ_EN(chan_num));
}
+static u32 sun6i_read_irq_en_a733(struct sun6i_dma_dev *sdev, u32 chan_num)
+{
+ return readl(sdev->base + DMA_IRQ_EN_A733(chan_num));
+}
+
static void sun6i_write_irq_en(struct sun6i_dma_dev *sdev, u32 chan_num, u32 irq_val)
{
writel(irq_val, sdev->base + DMA_IRQ_EN(chan_num));
}
+
+static void sun6i_write_irq_en_a733(struct sun6i_dma_dev *sdev, u32 chan_num, u32 irq_val)
+{
+ writel(irq_val, sdev->base + DMA_IRQ_EN_A733(chan_num));
+}
+
static u32 sun6i_read_irq_stat(struct sun6i_dma_dev *sdev, u32 chan_num)
{
return readl(sdev->base + DMA_IRQ_STAT(chan_num));
}
+static u32 sun6i_read_irq_stat_a733(struct sun6i_dma_dev *sdev, u32 chan_num)
+{
+ return readl(sdev->base + DMA_IRQ_STAT_A733(chan_num));
+}
+
static void sun6i_write_irq_stat(struct sun6i_dma_dev *sdev, u32 chan_num, u32 status)
{
writel(status, sdev->base + DMA_IRQ_STAT(chan_num));
}
+static void sun6i_write_irq_stat_a733(struct sun6i_dma_dev *sdev, u32 chan_num, u32 status)
+{
+ writel(status, sdev->base + DMA_IRQ_STAT_A733(chan_num));
+}
+
static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan)
{
struct sun6i_desc *txd = pchan->desc;
@@ -694,6 +743,17 @@ static inline void sun6i_dma_set_addr_a100(struct sun6i_dma_dev *sdev,
DST_HIGH_ADDR(upper_32_bits(dst));
}
+static inline void sun6i_dma_set_addr_a733(struct sun6i_dma_dev *sdev,
+ struct sun6i_dma_lli *v_lli,
+ dma_addr_t src, dma_addr_t dst)
+{
+ v_lli->src = lower_32_bits(src);
+ v_lli->dst = lower_32_bits(dst);
+
+ v_lli->para |= SRC_HIGH_ADDR_32G(upper_32_bits(src)) |
+ DST_HIGH_ADDR_32G(upper_32_bits(dst));
+}
+
static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t len, unsigned long flags)
@@ -1352,6 +1412,33 @@ static struct sun6i_dma_config sun50i_h6_dma_cfg = {
.has_mbus_clk = true,
};
+/*
+ * The A733 binding uses the number of dma channels from the
+ * device tree node.
+ */
+static struct sun6i_dma_config sun60i_a733_dma_cfg = {
+ .clock_autogate_enable = sun6i_enable_clock_autogate_h3,
+ .set_burst_length = sun6i_set_burst_length_h3,
+ .set_drq = sun6i_set_drq_h6,
+ .set_mode = sun6i_set_mode_h6,
+ .set_addr = sun6i_dma_set_addr_a733,
+ .dump_com_regs = sun6i_dma_dump_com_regs_a733,
+ .read_irq_en = sun6i_read_irq_en_a733,
+ .write_irq_en = sun6i_write_irq_en_a733,
+ .read_irq_stat = sun6i_read_irq_stat_a733,
+ .write_irq_stat = sun6i_write_irq_stat_a733,
+ .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+ .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+ .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+ .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+ .num_channels_per_reg = DMA_IRQ_CHAN_NR_A733,
+ .has_mbus_clk = true,
+};
+
/*
* The V3s have only 8 physical channels, a maximum DRQ port id of 23,
* and a total of 24 usable source and destination endpoints.
@@ -1392,6 +1479,7 @@ static const struct of_device_id sun6i_dma_match[] = {
{ .compatible = "allwinner,sun50i-a64-dma", .data = &sun50i_a64_dma_cfg },
{ .compatible = "allwinner,sun50i-a100-dma", .data = &sun50i_a100_dma_cfg },
{ .compatible = "allwinner,sun50i-h6-dma", .data = &sun50i_h6_dma_cfg },
+ { .compatible = "allwinner,sun60i-a733-dma", .data = &sun60i_a733_dma_cfg },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun6i_dma_match);
--
2.54.0
^ permalink raw reply related
* [PATCH 5/5] dt-bindings: dma: sun50i-a64-dma: Update device tree bindings documentation for A733
From: Yuanshen Cao @ 2026-06-19 4:53 UTC (permalink / raw)
To: Vinod Koul, Frank Li, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard
Cc: dmaengine, linux-arm-kernel, linux-sunxi, linux-kernel,
devicetree, Yuanshen Cao
In-Reply-To: <20260619-sun60i-a733-dma-v1-0-da4b649fc72a@gmail.com>
To complete the support for the A733 DMA controller, added
`allwinner,sun60i-a733-dma` to the list of compatible strings for
`allwinner,sun50i-a64-dma` dt-binding documentations..
Signed-off-by: Yuanshen Cao <alex.caoys@gmail.com>
---
Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
index c3e14eb6cfff..1cc3304b7414 100644
--- a/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
+++ b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
@@ -25,6 +25,7 @@ properties:
- allwinner,sun50i-a64-dma
- allwinner,sun50i-a100-dma
- allwinner,sun50i-h6-dma
+ - allwinner,sun60i-a733-dma
- items:
- const: allwinner,sun8i-r40-dma
- const: allwinner,sun50i-a64-dma
@@ -70,6 +71,7 @@ if:
- allwinner,sun20i-d1-dma
- allwinner,sun50i-a100-dma
- allwinner,sun50i-h6-dma
+ - allwinner,sun60i-a733-dma
then:
properties:
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox