* Re: [PATCH v10 2/2] hwmon: add support for MCP998X
From: Guenter Roeck @ 2026-03-30 16:00 UTC (permalink / raw)
To: Victor.Duicu
Cc: corbet, linux-hwmon, devicetree, robh, linux-kernel, krzk+dt,
linux-doc, conor+dt, Marius.Cristea
In-Reply-To: <2d3955f5b906018fd7670ed5b8d37eaffa0ec207.camel@microchip.com>
On 3/30/26 05:01, Victor.Duicu@microchip.com wrote:
> Hi Guenter,
>
> ...
>
>>> + }
>>> +
>>> + switch (type) {
>>> + case hwmon_temp:
>>> + switch (attr) {
>>> + case hwmon_temp_input:
>>> + /* Block reading from addresses 0x00->0x09 is
>>> not allowed. */
>>> + ret = regmap_read(priv->regmap,
>>> MCP9982_HIGH_BYTE_ADDR(channel), ®_high);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + ret = regmap_read(priv->regmap,
>>> MCP9982_HIGH_BYTE_ADDR(channel) + 1,
>>> + ®_low);
>>> + if (ret)
>>> + return ret;
>>
>> Reading the 11-bit temperature value involves two separate 8-bit
>> register reads.
>> If the chip updates the temperature between these two reads, the
>> resulting value
>> may be torn. While some chips latch the low byte upon reading the
>> high byte,
>> the driver does not explicitly rely on or document this behavior, and
>> it's safer
>> to use regmap_bulk_read if supported, or at least ensure the correct
>> order and
>> atomicity if possible.
>>
>> Note: Maybe the low temperature is latched, but there is no
>> indication in the
>> datasheet that this would be the case. Even if it is, the code above
>> is
>> inefficient.
>
> The low temperature register is latched. In the documentation at
> page 32 it is described that when reading the high byte register,
> the value from the low byte register is copied into a 'shadow'
> register. In this way it is guaranteed that when we read the low byte,
> it will correspond to the high byte.
>
> Regarding the bulk read, the chip has a number of design quirks and
> because of that different commands are supported only on some
> particular memory regions.
>
> According to the documentation page 26, the only areas of memory that
> support SMBus block read are 80h->89h(temperature memory block) and
> 90h->97h(status memory block). In order to block read the temperatures,
> the area of memory targeted has to be the temperature memory block. In
> this context the read operation uses SMBus protocol and the first value
> returned will be the number of addresses that can be read (in our
> particular case a max value of 10 bytes).
>
> In v8 of the driver
> https://lore.kernel.org/all/20251120071248.3767-1-victor.duicu@microchip.com/
> ,
> the temperature values were read with regmap_bulk_read(). In that
> version, regmap_bulk_read() was also used to read the temperature
> limits, without returning count (this is an undocumented feature of the
> chip and because of that we could assume is not supported).
> In order to avoid this behaviour and avoid mixing the SMBus and I2C
> protocols all block readings were removed.
>
> In the hopes of bypassing a long chain of replies, I tested the
> behaviour of the chip with different read instructions.
> Regmap_bulk_read() when applied to the temperature memory block
> (80h->89h) returns count and the high and low bytes. When it is applied
> to the 00h->09h memory, it uses I2C. It returns one temperature byte,
> but all other bytes are returned as 0xFF. The chip behaves as if
> it is at the last register location in the temperature block while the
> host continues to ACK.(behaviour described at page 26).
> If we set use_single_read in regmap_config and apply regmap_bulk_read()
> to the 00h->09h register area the high and low temperature bytes are
> read successfully without count.
>
> Regmap_multi_reg_read() reads a number of registers one by one. When
> applied to the 00h->09h area, I2C is used and it returns only the high
> and low temperature bytes. When applied to the temperature memory block
> (80h->89h), because it is not a bulk function, returns the count till
> the end of the temperature memory block (aka SMBus count).
>
> I2c_smbus_read_block_data() when applied to the temperature block (80h-
> 89h) returns the count, the driver replies with an NACK and the
> communication is stopped. In our case, the board we are using to test
> the driver has an AT91 adapter and supports
> I2C_FUNC_SMBUS_READ_BLOCK_DATA. It seems that the I2C driver for AT91
> does not modify the buff length of the message, leaving it 1.
>
> I2c_smbus_read_i2c_block_data() when applied to the temperature block
> (80h-89h) returns count and the temperature values.
>
> If you are of the opinion that block reading the temperatures is worth
> introducing (even in case we need to skip count) then I can add it, but
> we should come to an agreement on which function to use.
> Please let me know your thoughts.
>
It is your chip, so I'll let you decide. Please include all the above
as comments into the code.
Thanks,
Guenter
^ permalink raw reply
* Re: [PATCH V2 3/5] dmaengine: xilinx_dma: Extend metadata handling for AXI MCDMA
From: Frank Li @ 2026-03-30 15:58 UTC (permalink / raw)
To: Srinivas Neeli
Cc: Vinod Koul, git, Frank Li, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Suraj Gupta,
Radhey Shyam Pandey, Thomas Gessler, Folker Schwesinger,
Tomi Valkeinen, Kees Cook, Abin Joseph, dmaengine, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260313062533.421249-4-srinivas.neeli@amd.com>
On Fri, Mar 13, 2026 at 11:55:31AM +0530, Srinivas Neeli wrote:
> From: Suraj Gupta <suraj.gupta2@amd.com>
>
> Extend probe logic to detect AXI Stream connections for MCDMA. When
> an AXI Stream interface is present, metadata operations are enabled for
> the MCDMA channel. The xilinx_dma_get_metadata_ptr() is enhanced to
> retrieve metadata directly from MCDMA descriptors.
Need extra empty line between paragraph
> Add corresponding channel reference in struct xilinx_dma_tx_descriptor to
> retrieve associated channel.
> These changes ensure proper metadata handling and accurate transfer
> size reporting for MCDMA transfers.
>
> Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
> Co-developed-by: Srinivas Neeli <srinivas.neeli@amd.com>
> Signed-off-by: Srinivas Neeli <srinivas.neeli@amd.com>
> ---
> drivers/dma/xilinx/xilinx_dma.c | 30 +++++++++++++++++++++++++-----
> 1 file changed, 25 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
> index 00200b4c2372..52203d44e7a4 100644
> --- a/drivers/dma/xilinx/xilinx_dma.c
> +++ b/drivers/dma/xilinx/xilinx_dma.c
> @@ -222,6 +222,8 @@
> #define XILINX_MCDMA_BD_EOP BIT(30)
> #define XILINX_MCDMA_BD_SOP BIT(31)
>
> +struct xilinx_dma_chan;
> +
> /**
> * struct xilinx_vdma_desc_hw - Hardware Descriptor
> * @next_desc: Next Descriptor Pointer @0x00
> @@ -371,6 +373,7 @@ struct xilinx_cdma_tx_segment {
>
> /**
> * struct xilinx_dma_tx_descriptor - Per Transaction structure
> + * @chan: DMA channel for which this descriptor is allocated
> * @async_tx: Async transaction descriptor
> * @segments: TX segments list
> * @node: Node in the channel descriptors list
> @@ -379,6 +382,7 @@ struct xilinx_cdma_tx_segment {
> * @residue: Residue of the completed descriptor
> */
> struct xilinx_dma_tx_descriptor {
> + struct xilinx_dma_chan *chan;
async_tx already include dma_chan's information.
Frank
^ permalink raw reply
* Re: [PATCH V2 2/5] dmaengine: xilinx_dma: Move descriptors to done list based on completion bit
From: Frank Li @ 2026-03-30 15:54 UTC (permalink / raw)
To: Srinivas Neeli
Cc: Vinod Koul, git, Frank Li, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Suraj Gupta,
Radhey Shyam Pandey, Thomas Gessler, Folker Schwesinger,
Tomi Valkeinen, Kees Cook, Abin Joseph, dmaengine, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260313062533.421249-3-srinivas.neeli@amd.com>
On Fri, Mar 13, 2026 at 11:55:30AM +0530, Srinivas Neeli wrote:
> In AXIMCDMA scatter-gather mode, the hardware sets the completion bit when
> a transfer finishes. The driver now checks this bit to free descriptors
> from the active list and move them to the done list.
Add check complete bit because irq may be triggered before a configured
threshold is reached when interrupt delay timeout Dly_IrqEn is enabled.
Frank
> This is required when interrupt delay timeout Dly_IrqEn is enabled,
> as interrupts may be triggered before the configured threshold is reached,
> even if not all descriptors have completed.
>
> Signed-off-by: Srinivas Neeli <srinivas.neeli@amd.com>
> ---
> drivers/dma/xilinx/xilinx_dma.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
> index 4a83492f2435..00200b4c2372 100644
> --- a/drivers/dma/xilinx/xilinx_dma.c
> +++ b/drivers/dma/xilinx/xilinx_dma.c
> @@ -1762,6 +1762,18 @@ static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
> struct xilinx_axidma_tx_segment, node);
> if (!(seg->hw.status & XILINX_DMA_BD_COMP_MASK) && chan->has_sg)
> break;
> + } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
> + struct xilinx_aximcdma_tx_segment *seg;
> + bool completed;
> +
> + seg = list_last_entry(&desc->segments,
> + struct xilinx_aximcdma_tx_segment,
> + node);
> + completed = (chan->direction == DMA_DEV_TO_MEM) ?
> + (seg->hw.s2mm_status & XILINX_DMA_BD_COMP_MASK) :
> + (seg->hw.mm2s_status & XILINX_DMA_BD_COMP_MASK);
> + if (!completed)
> + break;
> }
> if (chan->has_sg && chan->xdev->dma_config->dmatype !=
> XDMA_TYPE_VDMA)
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH 1/7] cache: ax45mp_cache: refactor cache driver for generic Andes platform support
From: Conor Dooley @ 2026-03-30 15:54 UTC (permalink / raw)
To: Hui Min Mina Chou
Cc: pjw, palmer, aou, alex, geert+renesas, prabhakar.mahadev-lad.rj,
magnus.damm, ben717, robh, krzk+dt, conor+dt, jonathan.cameron,
devicetree, linux-riscv, linux-kernel, linux-renesas-soc, tim609,
alex749, az70021, charles
In-Reply-To: <20260330102724.1012470-2-minachou@andestech.com>
[-- Attachment #1: Type: text/plain, Size: 19678 bytes --]
On Mon, Mar 30, 2026 at 06:27:18PM +0800, Hui Min Mina Chou wrote:
> Andes cache driver is not only usable with the AX45MP CPU but can also be
> applied to other CPU within Andes platform (such as A27L2).
> To improve maintainability and support future SoCs, this patch performs a
> comprehensive refactoring to move away from model-specific naming.
>
> key changes include:
> - replaced AX45MP-specific Kconfig and function names with generic "ANDES"
> prefixes to support multiple CPU types
> - updated all L2-related identifiers, structs, and prefixes to "LLC"
> to accurately reflect its role as the system's last-level cache
> - moved UCCTL* CSR definitions to <linux/soc/andes/csr.h>
Why? There's no user outside of the driver.
> - standardized L1D and LLC macro prefixes (ANDES_L1D_* and ANDES_LLC_*)
> for better clarity
> - renamed compatible strings from ax45mp-cache to generic llcache
> - rename ax45mp_cache.c to andes_llcache.c
This patch is, quite frankly, unreviewable. There's various additions
and changes hidden in here alongside renames. Every bullet point here
should be a patch, and then maybe I see some of them as trivial and
squash them, but what's here is just too annoying to spot what is a
rename and what is a snuck-in change.
>
> This is a structural refactoring; no functional behavior is changed.
You broke all users by removing a compatible, so this is clearly false.
>
> Signed-off-by: charles <dminus@andestech.com>
> Signed-off-by: Hui Min Mina Chou <minachou@andestech.com>
All patches in this series that have more than one signoff have a
problem. You're the last signoff and the author, what did any of these
other people do? Were they the real authors and authorship is screwed
up? Or should these people have Co-developed-by tags?
Thanks,
Conor.
> ---
> arch/riscv/Kconfig.errata | 2 +-
> drivers/cache/Kconfig | 6 +-
> drivers/cache/Makefile | 2 +-
> drivers/cache/andes_llcache.c | 224 ++++++++++++++++++++++++++++++++++
> drivers/cache/ax45mp_cache.c | 217 --------------------------------
> drivers/soc/renesas/Kconfig | 2 +-
> include/linux/soc/andes//Rcsr.h | 12 ++
> 7 files changed, 242 insertions(+), 223 deletions(-)
> create mode 100644 drivers/cache/andes_llcache.c
> delete mode 100644 drivers/cache/ax45mp_cache.c
> create mode 100644 include/linux/soc/andes/csr.h
>
> diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
> index 3c945d086c7d..e32f1563ce3a 100644
> --- a/arch/riscv/Kconfig.errata
> +++ b/arch/riscv/Kconfig.errata
> @@ -1,7 +1,7 @@
> menu "CPU errata selection"
>
> config ERRATA_ANDES
> - bool "Andes AX45MP errata"
> + bool "Andes errata"
> depends on RISCV_ALTERNATIVE && RISCV_SBI
> help
> All Andes errata Kconfig depend on this Kconfig. Disabling
> diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
> index 1518449d47b5..78142189f45c 100644
> --- a/drivers/cache/Kconfig
> +++ b/drivers/cache/Kconfig
> @@ -10,11 +10,11 @@ menuconfig CACHEMAINT_FOR_DMA
>
> if CACHEMAINT_FOR_DMA
>
> -config AX45MP_L2_CACHE
> - bool "Andes Technology AX45MP L2 Cache controller"
> +config ANDES_CACHE
> + bool "Andes platform CPUs Cache controller"
> select RISCV_NONSTANDARD_CACHE_OPS
> help
> - Support for the L2 cache controller on Andes Technology AX45MP platforms.
> + Support for the L1 and LLC (last level cache) controller on Andes platform CPUs.
>
> config SIFIVE_CCACHE
> bool "Sifive Composable Cache controller"
> diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile
> index b3362b15d6c1..4a218ad6cec0 100644
> --- a/drivers/cache/Makefile
> +++ b/drivers/cache/Makefile
> @@ -1,6 +1,6 @@
> # SPDX-License-Identifier: GPL-2.0
>
> -obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o
> +obj-$(CONFIG_ANDES_CACHE) += andes_llcache.o
> obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o
> obj-$(CONFIG_STARFIVE_STARLINK_CACHE) += starfive_starlink_cache.o
>
> diff --git a/drivers/cache/andes_llcache.c b/drivers/cache/andes_llcache.c
> new file mode 100644
> index 000000000000..d5e382f3c801
> --- /dev/null
> +++ b/drivers/cache/andes_llcache.c
> @@ -0,0 +1,224 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * non-coherent cache operations for Andes Platform CPUs.
> + *
> + * Copyright (C) 2023 Renesas Electronics Corp.
> + */
> +
> +#include <linux/cacheflush.h>
> +#include <linux/cacheinfo.h>
> +#include <linux/dma-direction.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/soc/andes/csr.h>
> +
> +#include <asm/dma-noncoherent.h>
> +
> +/* L1 D-cache operation encoding */
> +#define ANDES_L1D_CCTL_VA_INVAL 0x0 /* Invalidate an L1D cacheline */
> +#define ANDES_L1D_CCTL_VA_WB 0x1 /* Write-back an L1D cacheline */
> +#define ANDES_L1D_CCTL_VA_WBINVAL 0x2 /* Flush an L1D cacheline */
> +#define ANDES_L1D_CCTL_WBINVAL_ALL 0x6 /* Flush the entire L1D cache */
> +
> +/* LLC registers */
> +#define ANDES_LLC_REG_CFG_OFFSET 0x0
> +#define ANDES_LLC_REG_CTRL_OFFSET 0x8
> +#define ANDES_LLC_REG_ASYNC_ERR_OFFSET 0x30
> +#define ANDES_LLC_REG_ERR_OFFSET 0x38
> +#define ANDES_LLC_REG_CCTL_CMD_OFFSET_C0 0x40
> +#define ANDES_LLC_REG_CCTL_ACC_OFFSET_C0 0x48
> +#define ANDES_LLC_REG_CCTL_STATUS_OFFSET_C0 0x80
> +
> +/* LLC CCTL status encoding */
> +#define ANDES_LLC_CCTL_STATUS_IDLE 0x0
> +#define ANDES_LLC_CCTL_STATUS_RUNNING 0x1
> +#define ANDES_LLC_CCTL_STATUS_ILLEGAL 0x2
> +
> +/* LLC CCTL status core 0 mask */
> +#define ANDES_LLC_CCTL_STATUS_MASK_C0 GENMASK(3, 0)
> +
> +/* LLC operation encoding */
> +#define ANDES_LLC_CCTL_PA_INVAL 0x8 /* Invalidate an LLC cacheline */
> +#define ANDES_LLC_CCTL_PA_WB 0x9 /* Write-back an LLC cacheline */
> +#define ANDES_LLC_CCTL_PA_WBINVAL 0xa /* Flush an LLC cacheline */
> +#define ANDES_LLC_CCTL_WBINVAL_ALL 0x12 /* Flush the entire LLC cache */
> +
> +/* LLC CCTL registers and fields by core */
> +#define ANDES_LLC_REG_PER_CORE_OFFSET 0x10
> +#define ANDES_CCTL_LLC_STATUS_PER_CORE_OFFSET 0x4
> +
> +#define ANDES_LLC_REG_CCTL_CMD_OFFSET_BY_CORE(n) \
> + (ANDES_LLC_REG_CCTL_CMD_OFFSET_C0 + ((n) * ANDES_LLC_REG_PER_CORE_OFFSET))
> +#define ANDES_LLC_REG_CCTL_ACC_OFFSET_BY_CORE(n) \
> + (ANDES_LLC_REG_CCTL_ACC_OFFSET_C0 + ((n) * ANDES_LLC_REG_PER_CORE_OFFSET))
> +#define ANDES_LLC_CCTL_STATUS_MASK_BY_CORE(n) \
> + (ANDES_LLC_CCTL_STATUS_MASK_C0 << ((n) * ANDES_CCTL_LLC_STATUS_PER_CORE_OFFSET))
> +
> +#define ANDES_CACHE_LINE_SIZE 64
> +
> +struct andes_priv {
> + void __iomem *llc_base;
> + u32 andes_cache_line_size;
> +};
> +
> +static struct andes_priv andes_priv;
> +
> +/* LLC operations */
> +static inline uint32_t andes_cpu_llc_get_cctl_status(void)
> +{
> + return readl(andes_priv.llc_base + ANDES_LLC_REG_CCTL_STATUS_OFFSET_C0);
> +}
> +
> +static void andes_cpu_cache_operation(unsigned long start, unsigned long end,
> + unsigned int l1_op, unsigned int llc_op)
> +{
> + unsigned long line_size = andes_priv.andes_cache_line_size;
> + void __iomem *base = andes_priv.llc_base;
> + int mhartid = smp_processor_id();
> + unsigned long pa;
> +
> + while (end > start) {
> + csr_write(CSR_UCCTLBEGINADDR, start);
> + csr_write(CSR_UCCTLCOMMAND, l1_op);
> +
> + pa = virt_to_phys((void *)start);
> + writel(pa, base + ANDES_LLC_REG_CCTL_ACC_OFFSET_BY_CORE(mhartid));
> + writel(llc_op, base + ANDES_LLC_REG_CCTL_CMD_OFFSET_BY_CORE(mhartid));
> + while ((andes_cpu_llc_get_cctl_status() &
> + ANDES_LLC_CCTL_STATUS_MASK_BY_CORE(mhartid)) !=
> + ANDES_LLC_CCTL_STATUS_IDLE)
> + ;
> +
> + start += line_size;
> + }
> +}
> +
> +/* Write-back L1 and LLC entry */
> +static inline void andes_cpu_dcache_wb_range(unsigned long start, unsigned long end)
> +{
> + andes_cpu_cache_operation(start, end, ANDES_L1D_CCTL_VA_WB,
> + ANDES_LLC_CCTL_PA_WB);
> +}
> +
> +/* Invalidate the L1 and LLC entry */
> +static inline void andes_cpu_dcache_inval_range(unsigned long start, unsigned long end)
> +{
> + andes_cpu_cache_operation(start, end, ANDES_L1D_CCTL_VA_INVAL,
> + ANDES_LLC_CCTL_PA_INVAL);
> +}
> +
> +static void andes_dma_cache_inv(phys_addr_t paddr, size_t size)
> +{
> + unsigned long start = (unsigned long)phys_to_virt(paddr);
> + unsigned long end = start + size;
> + unsigned long line_size;
> + unsigned long flags;
> +
> + if (unlikely(start == end))
> + return;
> +
> + line_size = andes_priv.andes_cache_line_size;
> +
> + start = start & (~(line_size - 1));
> + end = ((end + line_size - 1) & (~(line_size - 1)));
> +
> + local_irq_save(flags);
> +
> + andes_cpu_dcache_inval_range(start, end);
> +
> + local_irq_restore(flags);
> +}
> +
> +static void andes_dma_cache_wback(phys_addr_t paddr, size_t size)
> +{
> + unsigned long start = (unsigned long)phys_to_virt(paddr);
> + unsigned long end = start + size;
> + unsigned long line_size;
> + unsigned long flags;
> +
> + if (unlikely(start == end))
> + return;
> +
> + line_size = andes_priv.andes_cache_line_size;
> + start = start & (~(line_size - 1));
> + end = ((end + line_size - 1) & (~(line_size - 1)));
> + local_irq_save(flags);
> + andes_cpu_dcache_wb_range(start, end);
> + local_irq_restore(flags);
> +}
> +
> +static void andes_dma_cache_wback_inv(phys_addr_t paddr, size_t size)
> +{
> + andes_dma_cache_wback(paddr, size);
> + andes_dma_cache_inv(paddr, size);
> +}
> +
> +static int andes_get_llc_line_size(struct device_node *np)
> +{
> + int ret;
> +
> + ret = of_property_read_u32(np, "cache-line-size", &andes_priv.andes_cache_line_size);
> + if (ret) {
> + pr_err("Failed to get cache-line-size, defaulting to 64 bytes\n");
> + return ret;
> + }
> +
> + if (andes_priv.andes_cache_line_size != ANDES_CACHE_LINE_SIZE) {
> + pr_err("Expected cache-line-size to be 64 bytes (found:%u)\n",
> + andes_priv.andes_cache_line_size);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static const struct riscv_nonstd_cache_ops andes_cmo_ops __initconst = {
> + .wback = &andes_dma_cache_wback,
> + .inv = &andes_dma_cache_inv,
> + .wback_inv = &andes_dma_cache_wback_inv,
> +};
> +
> +static const struct of_device_id andes_cache_ids[] = {
> + { .compatible = "andestech,llcache" },
> + { /* sentinel */ }
> +};
> +
> +static int __init andes_cache_init(void)
> +{
> + struct resource res;
> + int ret;
> +
> + struct device_node *np __free(device_node) =
> + of_find_matching_node(NULL, andes_cache_ids);
> + if (!of_device_is_available(np))
> + return -ENODEV;
> +
> + ret = of_address_to_resource(np, 0, &res);
> + if (ret)
> + return ret;
> +
> + /*
> + * If IOCP is present on the Andes AX45MP core riscv_cbom_block_size
> + * will be 0 for sure, so we can definitely rely on it. If
> + * riscv_cbom_block_size = 0 we don't need to handle CMO using SW any
> + * more so we just return success here and only if its being set we
> + * continue further in the probe path.
> + */
> + if (!riscv_cbom_block_size)
> + return 0;
> +
> + andes_priv.llc_base = ioremap(res.start, resource_size(&res));
> + if (!andes_priv.llc_base)
> + return -ENOMEM;
> +
> + ret = andes_get_llc_line_size(np);
> + if (ret) {
> + iounmap(andes_priv.llc_base);
> + return ret;
> + }
> +
> + riscv_noncoherent_register_cache_ops(&andes_cmo_ops);
> +
> + return 0;
> +}
> +early_initcall(andes_cache_init);
> diff --git a/drivers/cache/ax45mp_cache.c b/drivers/cache/ax45mp_cache.c
> deleted file mode 100644
> index 934c5087ec2b..000000000000
> --- a/drivers/cache/ax45mp_cache.c
> +++ /dev/null
> @@ -1,217 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -/*
> - * non-coherent cache functions for Andes AX45MP
> - *
> - * Copyright (C) 2023 Renesas Electronics Corp.
> - */
> -
> -#include <linux/cacheflush.h>
> -#include <linux/cacheinfo.h>
> -#include <linux/dma-direction.h>
> -#include <linux/of_address.h>
> -#include <linux/of_platform.h>
> -
> -#include <asm/dma-noncoherent.h>
> -
> -/* L2 cache registers */
> -#define AX45MP_L2C_REG_CTL_OFFSET 0x8
> -
> -#define AX45MP_L2C_REG_C0_CMD_OFFSET 0x40
> -#define AX45MP_L2C_REG_C0_ACC_OFFSET 0x48
> -#define AX45MP_L2C_REG_STATUS_OFFSET 0x80
> -
> -/* D-cache operation */
> -#define AX45MP_CCTL_L1D_VA_INVAL 0 /* Invalidate an L1 cache entry */
> -#define AX45MP_CCTL_L1D_VA_WB 1 /* Write-back an L1 cache entry */
> -
> -/* L2 CCTL status */
> -#define AX45MP_CCTL_L2_STATUS_IDLE 0
> -
> -/* L2 CCTL status cores mask */
> -#define AX45MP_CCTL_L2_STATUS_C0_MASK 0xf
> -
> -/* L2 cache operation */
> -#define AX45MP_CCTL_L2_PA_INVAL 0x8 /* Invalidate an L2 cache entry */
> -#define AX45MP_CCTL_L2_PA_WB 0x9 /* Write-back an L2 cache entry */
> -
> -#define AX45MP_L2C_REG_PER_CORE_OFFSET 0x10
> -#define AX45MP_CCTL_L2_STATUS_PER_CORE_OFFSET 4
> -
> -#define AX45MP_L2C_REG_CN_CMD_OFFSET(n) \
> - (AX45MP_L2C_REG_C0_CMD_OFFSET + ((n) * AX45MP_L2C_REG_PER_CORE_OFFSET))
> -#define AX45MP_L2C_REG_CN_ACC_OFFSET(n) \
> - (AX45MP_L2C_REG_C0_ACC_OFFSET + ((n) * AX45MP_L2C_REG_PER_CORE_OFFSET))
> -#define AX45MP_CCTL_L2_STATUS_CN_MASK(n) \
> - (AX45MP_CCTL_L2_STATUS_C0_MASK << ((n) * AX45MP_CCTL_L2_STATUS_PER_CORE_OFFSET))
> -
> -#define AX45MP_CCTL_REG_UCCTLBEGINADDR_NUM 0x80b
> -#define AX45MP_CCTL_REG_UCCTLCOMMAND_NUM 0x80c
> -
> -#define AX45MP_CACHE_LINE_SIZE 64
> -
> -struct ax45mp_priv {
> - void __iomem *l2c_base;
> - u32 ax45mp_cache_line_size;
> -};
> -
> -static struct ax45mp_priv ax45mp_priv;
> -
> -/* L2 Cache operations */
> -static inline uint32_t ax45mp_cpu_l2c_get_cctl_status(void)
> -{
> - return readl(ax45mp_priv.l2c_base + AX45MP_L2C_REG_STATUS_OFFSET);
> -}
> -
> -static void ax45mp_cpu_cache_operation(unsigned long start, unsigned long end,
> - unsigned int l1_op, unsigned int l2_op)
> -{
> - unsigned long line_size = ax45mp_priv.ax45mp_cache_line_size;
> - void __iomem *base = ax45mp_priv.l2c_base;
> - int mhartid = smp_processor_id();
> - unsigned long pa;
> -
> - while (end > start) {
> - csr_write(AX45MP_CCTL_REG_UCCTLBEGINADDR_NUM, start);
> - csr_write(AX45MP_CCTL_REG_UCCTLCOMMAND_NUM, l1_op);
> -
> - pa = virt_to_phys((void *)start);
> - writel(pa, base + AX45MP_L2C_REG_CN_ACC_OFFSET(mhartid));
> - writel(l2_op, base + AX45MP_L2C_REG_CN_CMD_OFFSET(mhartid));
> - while ((ax45mp_cpu_l2c_get_cctl_status() &
> - AX45MP_CCTL_L2_STATUS_CN_MASK(mhartid)) !=
> - AX45MP_CCTL_L2_STATUS_IDLE)
> - ;
> -
> - start += line_size;
> - }
> -}
> -
> -/* Write-back L1 and L2 cache entry */
> -static inline void ax45mp_cpu_dcache_wb_range(unsigned long start, unsigned long end)
> -{
> - ax45mp_cpu_cache_operation(start, end, AX45MP_CCTL_L1D_VA_WB,
> - AX45MP_CCTL_L2_PA_WB);
> -}
> -
> -/* Invalidate the L1 and L2 cache entry */
> -static inline void ax45mp_cpu_dcache_inval_range(unsigned long start, unsigned long end)
> -{
> - ax45mp_cpu_cache_operation(start, end, AX45MP_CCTL_L1D_VA_INVAL,
> - AX45MP_CCTL_L2_PA_INVAL);
> -}
> -
> -static void ax45mp_dma_cache_inv(phys_addr_t paddr, size_t size)
> -{
> - unsigned long start = (unsigned long)phys_to_virt(paddr);
> - unsigned long end = start + size;
> - unsigned long line_size;
> - unsigned long flags;
> -
> - if (unlikely(start == end))
> - return;
> -
> - line_size = ax45mp_priv.ax45mp_cache_line_size;
> -
> - start = start & (~(line_size - 1));
> - end = ((end + line_size - 1) & (~(line_size - 1)));
> -
> - local_irq_save(flags);
> -
> - ax45mp_cpu_dcache_inval_range(start, end);
> -
> - local_irq_restore(flags);
> -}
> -
> -static void ax45mp_dma_cache_wback(phys_addr_t paddr, size_t size)
> -{
> - unsigned long start = (unsigned long)phys_to_virt(paddr);
> - unsigned long end = start + size;
> - unsigned long line_size;
> - unsigned long flags;
> -
> - if (unlikely(start == end))
> - return;
> -
> - line_size = ax45mp_priv.ax45mp_cache_line_size;
> - start = start & (~(line_size - 1));
> - end = ((end + line_size - 1) & (~(line_size - 1)));
> - local_irq_save(flags);
> - ax45mp_cpu_dcache_wb_range(start, end);
> - local_irq_restore(flags);
> -}
> -
> -static void ax45mp_dma_cache_wback_inv(phys_addr_t paddr, size_t size)
> -{
> - ax45mp_dma_cache_wback(paddr, size);
> - ax45mp_dma_cache_inv(paddr, size);
> -}
> -
> -static int ax45mp_get_l2_line_size(struct device_node *np)
> -{
> - int ret;
> -
> - ret = of_property_read_u32(np, "cache-line-size", &ax45mp_priv.ax45mp_cache_line_size);
> - if (ret) {
> - pr_err("Failed to get cache-line-size, defaulting to 64 bytes\n");
> - return ret;
> - }
> -
> - if (ax45mp_priv.ax45mp_cache_line_size != AX45MP_CACHE_LINE_SIZE) {
> - pr_err("Expected cache-line-size to be 64 bytes (found:%u)\n",
> - ax45mp_priv.ax45mp_cache_line_size);
> - return -EINVAL;
> - }
> -
> - return 0;
> -}
> -
> -static const struct riscv_nonstd_cache_ops ax45mp_cmo_ops __initdata = {
> - .wback = &ax45mp_dma_cache_wback,
> - .inv = &ax45mp_dma_cache_inv,
> - .wback_inv = &ax45mp_dma_cache_wback_inv,
> -};
> -
> -static const struct of_device_id ax45mp_cache_ids[] = {
> - { .compatible = "andestech,ax45mp-cache" },
> - { /* sentinel */ }
> -};
> -
> -static int __init ax45mp_cache_init(void)
> -{
> - struct resource res;
> - int ret;
> -
> - struct device_node *np __free(device_node) =
> - of_find_matching_node(NULL, ax45mp_cache_ids);
> - if (!of_device_is_available(np))
> - return -ENODEV;
> -
> - ret = of_address_to_resource(np, 0, &res);
> - if (ret)
> - return ret;
> -
> - /*
> - * If IOCP is present on the Andes AX45MP core riscv_cbom_block_size
> - * will be 0 for sure, so we can definitely rely on it. If
> - * riscv_cbom_block_size = 0 we don't need to handle CMO using SW any
> - * more so we just return success here and only if its being set we
> - * continue further in the probe path.
> - */
> - if (!riscv_cbom_block_size)
> - return 0;
> -
> - ax45mp_priv.l2c_base = ioremap(res.start, resource_size(&res));
> - if (!ax45mp_priv.l2c_base)
> - return -ENOMEM;
> -
> - ret = ax45mp_get_l2_line_size(np);
> - if (ret) {
> - iounmap(ax45mp_priv.l2c_base);
> - return ret;
> - }
> -
> - riscv_noncoherent_register_cache_ops(&ax45mp_cmo_ops);
> -
> - return 0;
> -}
> -early_initcall(ax45mp_cache_init);
> diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
> index 1e50dc7c31cd..e0319c8236ee 100644
> --- a/drivers/soc/renesas/Kconfig
> +++ b/drivers/soc/renesas/Kconfig
> @@ -447,7 +447,7 @@ config ARCH_R9A07G043
> depends on !RISCV_ISA_ZICBOM
> depends on RISCV_SBI
> select ARCH_RZG2L
> - select AX45MP_L2_CACHE
> + select ANDES_CACHE
> select CACHEMAINT_FOR_DMA
> select DMA_GLOBAL_POOL
> select ERRATA_ANDES
> diff --git a/include/linux/soc/andes/csr.h b/include/linux/soc/andes/csr.h
> new file mode 100644
> index 000000000000..3214b4b08a46
> --- /dev/null
> +++ b/include/linux/soc/andes/csr.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2026 Andes Technology Corporation.
> + */
> +#ifndef __LINUX_SOC_ANDES_CSR_H
> +#define __LINUX_SOC_ANDES_CSR_H
> +
> +/* User mode control registers */
> +#define CSR_UCCTLBEGINADDR 0x80b
> +#define CSR_UCCTLCOMMAND 0x80c
> +
> +#endif /* !__LINUX_SOC_ANDES_CSR_H */
> --
> 2.34.1
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH 0/4] ASoC: Add support for GPIOs driven amplifiers
From: Mark Brown @ 2026-03-30 15:48 UTC (permalink / raw)
To: Herve Codina
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Saravana Kannan, Jaroslav Kysela, Takashi Iwai, linux-sound,
devicetree, linux-kernel, Christophe Leroy, Thomas Petazzoni
In-Reply-To: <20260330173944.3fdc27ec@bootlin.com>
[-- Attachment #1: Type: text/plain, Size: 590 bytes --]
On Mon, Mar 30, 2026 at 05:39:44PM +0200, Herve Codina wrote:
> Mark Brown <broonie@kernel.org> wrote:
> > This sounds a lot like simple-amplifier.c?
> The gpio driven amplifier proposed is more generic and can handle
> more complex design. I.e. op-amp + resistor and/or line (mute,
> bypass) switching. Hardwares handled by this driver are a superset
> of just dio2125 and so simple-amplifier.c.
> IMHO, it makes sense to have a specific driver for those kind
> of hardware design.
Right, and if it's a superset it feels like it should all be one driver
rather than two separate ones.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 7/8] drm/bridge: imx8mp-hdmi-tx: add an hdmi-connector when missing using a DT overlay at boot time
From: Luca Ceresoli @ 2026-03-30 15:47 UTC (permalink / raw)
To: Liu Ying, Marek Vasut, Stefan Agner, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Rob Herring, Saravana Kannan
Cc: Kory Maincent (TI.com), Hervé Codina, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, imx, linux-arm-kernel, linux-kernel,
devicetree, Adam Ford, Alexander Stein, Anson Huang,
Christopher Obbard, Daniel Scally, Emanuele Ghidoli,
Fabio Estevam, Francesco Dolcini, Frieder Schrempf, Gilles Talis,
Goran Rađenović, Heiko Schocher, Joao Paulo Goncalves,
Josua Mayer, Kieran Bingham, Marco Felsch, Martyn Welch,
Oleksij Rempel, Peng Fan, Philippe Schenker, Richard Hu,
Shengjiu Wang, Stefan Eichenberger, Vitor Soares
In-Reply-To: <5f06ea5a-5388-440f-91d6-cebb0bee0a88@nxp.com>
Hello Liu,
On Mon Mar 30, 2026 at 5:02 AM CEST, Liu Ying wrote:
>>>> --- a/drivers/gpu/drm/bridge/imx/Kconfig
>>>> +++ b/drivers/gpu/drm/bridge/imx/Kconfig
>>>> @@ -25,6 +25,23 @@ config DRM_IMX8MP_DW_HDMI_BRIDGE
>>>> Choose this to enable support for the internal HDMI encoder found
>>>> on the i.MX8MP SoC.
>>>>
>>>> +config DRM_IMX8MP_DW_HDMI_BRIDGE_CONNECTOR_FIXUP
>>>> + bool "Support device tree blobs without an hdmi-connector node"
>>>> + default y
>>>
>>> depends on DRM_IMX_LCDIF ?
>>
>> If the imx hdmi-tx is not enabled then HDMI won't work anyway, so users are
>> not affected and the overlay is not needed. Am I missing something?
>
> I meant I'm fine with "default y" and think that this could also depend on
> DRM_IMX_LCDIF, because no display controller driver other than the LCDIF
> driver needs the fixup.
Ah, I see your point. OK, I'll add 'depends on DRM_IMX_LCDIF'.
>>> I see build warnings(W=1):
>>> drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx-connector-fixup.dtso:25.8-37.4: Warning (unit_address_vs_reg): /fragment@0/__overlay__/soc@0: node has a unit name, but no reg or ranges property
>>> drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx-connector-fixup.dtso:26.16-36.5: Warning (unit_address_vs_reg): /fragment@0/__overlay__/soc@0/bus@32c00000: node has a unit name, but no reg or ranges property
>>> drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx-connector-fixup.dtso:27.18-35.6: Warning (unit_address_vs_reg): /fragment@0/__overlay__/soc@0/bus@32c00000/hdmi@32fd8000: node has a unit name, but no reg or ranges property
>>> drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx-connector-fixup.dtso:29.13-33.8: Warning (unit_address_vs_reg): /fragment@0/__overlay__/soc@0/bus@32c00000/hdmi@32fd8000/ports/port@1: node has a unit name, but no reg or ranges property
>>
>> AFAIK the device tree checkes just can't work on overlays. The tools just
>> cannot know on which base tree the overlay can be applied, so they cannot
>> know the existing properties. That might change in the future, but for now
>> my understanding is that it is OK to have overlays which produce such
>> harmless warnings, at least for driver-specific overlays like the tilcdc
>> one [0] which is already in linux-next since a few weeks.
>
> Hmm, not sure a few weeks in linux-next is long enough ;)
> I'd say, I saw the warnings, so simply reported along with a fix to suppress
> them. TBH, build warnings make me nervous, especially this DT overlay is
> under the "DRM DRIVERS FOR FREESCALE IMX BRIDGE" umbrella.
That's fine, I'll add the lines needed to suppress the warnings then.
>>>> + fixup-hdmi-connector {
>>>> + compatible = "hdmi-connector";
>>>> + label = "HDMI";
>>>> + type = "a";
>>>
>>> What if a board uses another type?
>>
>> For boards affected by this patch, currently the connector is created by
>> dw_hdmi_connector_create() which hardcodes type A [0], so there would be no
>> difference.
>
> Yes, that's from driver's PoV. However, userspace may get the type
> from /sys/firmware/devicetree/base/fixup-hdmi-connector/type and use it
> to do something.
I'd say this is incorrect, the device tree is not an API for that. The
connector type might be known to the driver by other means (ACPI, DP MST,
whatever). So I think this is a non-problem.
If userspace needs to know the connector type, that should come from the
ioctl (DRM_IOCTL_MODE_GETCONNECTOR perhaps).
> Maybe, that's trivial.
Not sure I got what you mean here, sorry. What are you referring to?
>> OTOH how can a common module know the specific connector?
>
> Hmm, maybe add a module parameter or let users set the type through Kconfig
I'm afraid none of this would work for distribution kernels, where who
configures the distribution has no idea on how many different hardware it
will run.
> or even define an unknown type to honestly tell users that we don't know it?
This sounds like a potentially valid idea, even though I'm not fully
convinced. Also I suspect it would be a pretty large change, and also
adding "unknown type" in the device tree seems not compliant with the rule
that DT describes the hardware (not the lack of info about the hardware).
But definitely it's not needed for this specific case, because:
* with current code, every imx8mp-hdmi-tx usage adds a type-A connector [0]
* with this patch the correct type will be created when described in DT,
and type-A will be used only as a fallback when the DT is lacking
So after the patch we'd do sometimes better, never worse in this respect.
Based on the above I'm sending v2 soon, but don't hesitate in following up
in case I may be missing something (this topic is tricky).
[0] https://elixir.bootlin.com/linux/v7.0-rc5/source/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c#L2601
>> Boards with a different connector should describe the connector in the
>> device tree, if they need to instantiate the exact type.
I think this is the only valid solution. It's very easy to do, nothing new
to invent.
Maybe on top of that we could add a warning when the overlay is applied,
e.g. "imx8mp-hdmi-tx used without a connector described in device tree;
adding a type A connector as a fallback; please add a valid description to
your device tree". Maybe pointing to a TODO entry in the documentation.
What do you think about this?
Thanks again for your careful review!
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v8 2/3] hwmon: ltc4283: Add support for the LTC4283 Swap Controller
From: Guenter Roeck @ 2026-03-30 15:47 UTC (permalink / raw)
To: Nuno Sá, Nuno Sá
Cc: linux-gpio, linux-hwmon, devicetree, linux-doc, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet, Linus Walleij,
Bartosz Golaszewski
In-Reply-To: <aco5L_6SZIB2DdpF@nsa>
On 3/30/26 02:28, Nuno Sá wrote:
> Hi Guenter, Regarding AI review, I think most of the points were
> discussed in previous revisions, but there are two valid.
>
> On Fri, Mar 27, 2026 at 05:26:15PM +0000, Nuno Sá wrote:
>> Support the LTC4283 Hot Swap Controller. The device features programmable
>> current limit with foldback and independently adjustable inrush current to
>> optimize the MOSFET safe operating area (SOA). The SOA timer limits MOSFET
>> temperature rise for reliable protection against overstresses.
>>
>> An I2C interface and onboard ADC allow monitoring of board current,
>> voltage, power, energy, and fault status.
>>
>> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
>> ---
>> Documentation/hwmon/index.rst | 1 +
>> Documentation/hwmon/ltc4283.rst | 266 ++++++
>> MAINTAINERS | 1 +
>> drivers/hwmon/Kconfig | 12 +
>> drivers/hwmon/Makefile | 1 +
>> drivers/hwmon/ltc4283.c | 1796 +++++++++++++++++++++++++++++++++++++++
>> 6 files changed, 2077 insertions(+)
>>
>
> ...
>
>> +static int ltc4283_read_in_alarm(struct ltc4283_hwmon *st, u32 channel,
>> + bool max_alm, long *val)
>> +{
>> + if (channel == LTC4283_VPWR)
>> + return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_1,
>> + BIT(2 + max_alm), val);
>> +
>> + if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_ADI_4) {
>> + u32 bit = (channel - LTC4283_CHAN_ADI_1) * 2;
>> + /*
>> + * Lower channels go to higher bits. We also want to go +1 down
>> + * in the min_alarm case.
>> + */
>> + return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_2,
>> + BIT(7 - bit - !max_alm), val);
>> + }
>> +
>> + if (channel >= LTC4283_CHAN_ADIO_1 && channel <= LTC4283_CHAN_ADIO_4) {
>> + u32 bit = (channel - LTC4283_CHAN_ADIO_1) * 2;
>> +
>> + return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_3,
>> + BIT(7 - bit - !max_alm), val);
>> + }
>> +
>> + if (channel >= LTC4283_CHAN_ADIN12 && channel <= LTC4283_CHAN_ADIN34) {
>> + u32 bit = (channel - LTC4283_CHAN_ADIN12) * 2;
>> +
>> + return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_5,
>> + BIT(7 - bit - !max_alm), val);
>> + }
>
> "Will this condition handle the ADIO12 and ADIO34 differential channels?
> It looks like channels 14 and 15 fall through to the default return intended
> for the DRAIN channel. Since reading the alarm implicitly clears the register
> bits, could reading these ADIO alarms unintentionally clear actual DRAIN
> alarms? Should the upper bound be LTC4283_CHAN_ADIO34?"
>
> Good catch and should be:
>
> - if (channel >= LTC4283_CHAN_ADIN12 && channel <= LTC4283_CHAN_ADIN34) {
> + if (channel >= LTC4283_CHAN_ADIN12 && channel <= LTC4283_CHAN_ADIO34) {
>
>> +
>> + if (channel == LTC4283_CHAN_DRNS)
>> + return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_4,
>> + BIT(6 + max_alm), val);
>> +
>> + return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_4, BIT(4 + max_alm),
>> + val);
>> +}
>
> ...
>
>> +
>> +static int ltc4283_probe(struct i2c_client *client)
>> +{
>> + struct device *dev = &client->dev, *hwmon;
>> + struct auxiliary_device *adev;
>> + struct ltc4283_hwmon *st;
>> + int ret;
>> +
>> + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
>> + if (!st)
>> + return -ENOMEM;
>> +
>> + if (!i2c_check_functionality(client->adapter,
>> + I2C_FUNC_SMBUS_BYTE_DATA |
>> + I2C_FUNC_SMBUS_WORD_DATA |
>> + I2C_FUNC_SMBUS_READ_I2C_BLOCK))
>> + return -EOPNOTSUPP;
>> +
>> + st->client = client;
>> + st->map = devm_regmap_init(dev, <c4283_regmap_bus, client,
>> + <c4283_regmap_config);
>> + if (IS_ERR(st->map))
>> + return dev_err_probe(dev, PTR_ERR(st->map),
>> + "Failed to create regmap\n");
>> +
>> + ret = ltc4283_setup(st, dev);
>> + if (ret)
>> + return ret;
>> +
>> + hwmon = devm_hwmon_device_register_with_info(dev, "ltc4283", st,
>> + <c4283_chip_info, NULL);
>> +
>> + if (IS_ERR(hwmon))
>> + return PTR_ERR(hwmon);
>> +
>> + ltc4283_debugfs_init(st, client);
>> +
>> + if (!st->gpio_mask)
>> + return 0;
>> +
>> + adev = devm_auxiliary_device_create(dev, "gpio", &st->gpio_mask);
>> + if (!adev)
>> + return dev_err_probe(dev, -ENODEV, "Failed to add GPIO device\n");
>
> "Does this allow multiple LTC4283 chips to probe successfully?
> Without allocating a unique ID per I2C instance, it seems the first probed
> chip takes the generic name. If a second chip is present, it might attempt
> to register with the exact same name, resulting in a failure in device_add()
> and aborting the probe."
>
> Also looks valid and I suspect is one of those that a quick look will
> find more "offenders". I would purpose:
>
> - adev = devm_auxiliary_device_create(dev, "gpio", &st->gpio_mask);
> + adev = __devm_auxiliary_device_create(dev, KBUILD_MODNAME, "gpio",
> + &st->gpio_mask, client->addr);
>
That would still fail if there are multiple chips at the same I2C address
on multiple I2C busses. Check drivers/gpu/drm/bridge/ti-sn65dsi86.c which has
the same problem.
> If there's nothing else and you agree with the above, is this something
> you can tweak while applying or should I spin a new version?
>
Please respin. Also, regarding the other concerns:
Can BIT(8) * st->rsense wrap to zero on 32-bit architectures?
BIT(8) is a 32-bit unsigned long and st->rsense is a u32. If a user sets a
very large sense resistor value via the device tree, the multiplication could
wrap to 0, causing a division-by-zero kernel panic. Should the divisor use
BIT_ULL(8)?
Unless I am missing something, this _can_ overflow. Try to provide a sense
resistor value of 1677721600. Yes, it is unreasonable to specify such large
rsense values, but why not just limit it such that it does not overflow ?
Also, for the overflow concerns, if you are sure they can not happen, I'll
really need to write the unit test code to make sure that this is indeed
the case.
Thanks,
Guenter
^ permalink raw reply
* Re: [PATCH V2 1/5] dmaengine: xilinx_dma: Fix MCDMA descriptor fields for MM2S vs S2MM
From: Frank Li @ 2026-03-30 15:46 UTC (permalink / raw)
To: Srinivas Neeli
Cc: Vinod Koul, git, Frank Li, Michal Simek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Suraj Gupta,
Radhey Shyam Pandey, Thomas Gessler, Folker Schwesinger,
Tomi Valkeinen, Kees Cook, Abin Joseph, dmaengine, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260313062533.421249-2-srinivas.neeli@amd.com>
On Fri, Mar 13, 2026 at 11:55:29AM +0530, Srinivas Neeli wrote:
> The MCDMA BD format differs between MM2S and S2MM directions, but the
Can you use DMA_DEV_TO_MEM and DMA_MEM_TO_DEV instead of MM2S and S2MM?
or memory to slave, at least first place need extend term MM2S(memory to
slave).
> driver was using generic 'status' and 'sideband_status' fields for both.
> This could lead to incorrect residue calculations when the hardware
> updates direction-specific fields.
driver was using generic 'status' and 'sideband_status' fields for both,
which lead ... (use Affirmative Tone)
>
> Refactor the descriptor structure to use unions with direction-specific
> field names (mm2s_status/s2mm_status, etc.). This ensures the driver
Ensure .. (needn't this)
Frank
> accesses the correct hardware fields based on channel direction and
> matches the hardware documentation.
>
> Fixes: 6ccd692bfb7f ("dmaengine: xilinx_dma: Add Xilinx AXI MCDMA Engine driver support")
> Signed-off-by: Srinivas Neeli <srinivas.neeli@amd.com>
> ---
> drivers/dma/xilinx/xilinx_dma.c | 29 ++++++++++++++++++++++-------
> 1 file changed, 22 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
> index b53292e02448..4a83492f2435 100644
> --- a/drivers/dma/xilinx/xilinx_dma.c
> +++ b/drivers/dma/xilinx/xilinx_dma.c
> @@ -275,8 +275,10 @@ struct xilinx_axidma_desc_hw {
> * @buf_addr_msb: MSB of Buffer address @0x0C
> * @rsvd: Reserved field @0x10
> * @control: Control Information field @0x14
> - * @status: Status field @0x18
> - * @sideband_status: Status of sideband signals @0x1C
> + * @mm2s_ctrl_sideband: Sideband control info for mm2s @0x18
> + * @s2mm_status: Status field for s2mm @0x18
> + * @mm2s_status: Status field for mm2s @0x1C
> + * @s2mm_sideband_status: Sideband status for s2mm @0x1C
> * @app: APP Fields @0x20 - 0x30
> */
> struct xilinx_aximcdma_desc_hw {
> @@ -286,8 +288,14 @@ struct xilinx_aximcdma_desc_hw {
> u32 buf_addr_msb;
> u32 rsvd;
> u32 control;
> - u32 status;
> - u32 sideband_status;
> + union {
> + u32 mm2s_ctrl_sideband;
> + u32 s2mm_status;
> + };
> + union {
> + u32 mm2s_status;
> + u32 s2mm_sideband_status;
> + };
> u32 app[XILINX_DMA_NUM_APP_WORDS];
> } __aligned(64);
>
> @@ -1013,9 +1021,16 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
> struct xilinx_aximcdma_tx_segment,
> node);
> aximcdma_hw = &aximcdma_seg->hw;
> - residue +=
> - (aximcdma_hw->control - aximcdma_hw->status) &
> - chan->xdev->max_buffer_len;
> + if (chan->direction == DMA_DEV_TO_MEM)
> + residue +=
> + (aximcdma_hw->control -
> + aximcdma_hw->s2mm_status) &
> + chan->xdev->max_buffer_len;
> + else
> + residue +=
> + (aximcdma_hw->control -
> + aximcdma_hw->mm2s_status) &
> + chan->xdev->max_buffer_len;
> }
> }
>
> --
> 2.43.0
>
^ permalink raw reply
* RE: [PATCH 07/22] ASoC: dt-bindings: renesas,rsnd: Add RZ/G3E support
From: John Madieu @ 2026-03-30 15:39 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Geert Uytterhoeven, Kuninori Morimoto, Vinod Koul, Mark Brown,
Rob Herring, Krzysztof Kozlowski, Michael Turquette, Stephen Boyd,
Conor Dooley, Frank Li, Liam Girdwood, magnus.damm,
Thomas Gleixner, Jaroslav Kysela, Takashi Iwai, Philipp Zabel,
Claudiu.Beznea, Biju Das, Fabrizio Castro, Prabhakar Mahadev Lad,
John Madieu, linux-renesas-soc@vger.kernel.org,
linux-clk@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, dmaengine@vger.kernel.org,
linux-sound@vger.kernel.org
In-Reply-To: <20260320-peculiar-cat-of-acumen-c6f6b3@quoll>
Hi Krzysztof,
Thanks for the review.
> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Friday, March 20, 2026 10:30 AM
> To: John Madieu <john.madieu.xa@bp.renesas.com>
> Subject: Re: [PATCH 07/22] ASoC: dt-bindings: renesas,rsnd: Add RZ/G3E
> support
>
> On Thu, Mar 19, 2026 at 04:53:19PM +0100, John Madieu wrote:
> > Add support for the RZ/G3E (R9A09G047) SoC audio subsystem.
> >
> > RZ/G3E has a different audio architecture from R-Car Gen2/Gen3/Gen4,
> > with additional clocks and resets:
> > - Per-SSI ADG clocks (adg.ssi.0-9)
> > - SCU related clocks (scu, scu_x2, scu_supply)
> > - SSIF supply clock
> > - AUDMAC peri-peri clock
> > - ADG clock
> > - Additional resets for SCU, ADG, and AUDMAC peri-peri
> >
> > RZ/G3E has 5 DMA controllers that can all be used by audio peripherals.
> > To allow the DMA core to distribute channels across all available
> > controllers, increase the maximum number of DMA entries in DVC, SRC,
> > and SSIU sub-nodes so that multiple providers can be listed with
> > repeated channel names.
> >
> > Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com>
> > ---
> > .../bindings/sound/renesas,rsnd.yaml | 169 +++++++++++++++---
> > 1 file changed, 148 insertions(+), 21 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
> > b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
> > index e8a2acb92646..bc8885c4fa24 100644
> > --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
> > +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
> > @@ -58,6 +58,7 @@ properties:
> > - renesas,rcar_sound-gen2
> > - renesas,rcar_sound-gen3
> > - renesas,rcar_sound-gen4
> > + - renesas,rcar_sound-r9a09g047 # RZ/G3E
>
> Do not use underscores in compatibles. Previously used wrong style is not
> the excuse here, just like previously poor code, mistakes, bugs,
> unreadable approches is not justification to repeat the same.
>
Got it.
> >
> > reg:
> > minItems: 1
> > @@ -97,20 +98,22 @@ properties:
> >
> > resets:
> > minItems: 1
> > - maxItems: 11
> > + maxItems: 14
> >
> > reset-names:
> > minItems: 1
> > - maxItems: 11
> > + maxItems: 14
> >
> > clocks:
> > description: References to SSI/SRC/MIX/CTU/DVC/AUDIO_CLK clocks.
> > minItems: 1
> > - maxItems: 31
> > + maxItems: 47
> >
> > clock-names:
> > description: List of necessary clock names.
> > # details are defined below
> > + minItems: 1
> > + maxItems: 47
> >
> > # ports is below
> > port:
> > @@ -136,9 +139,17 @@ properties:
> >
> > properties:
> > dmas:
> > - maxItems: 1
> > + description:
> > + Must contain unique DMA specifiers, one per available
> > + DMAC. On RZ/G3E, up to 5 for transmission.
> > + minItems: 1
> > + maxItems: 5
> > dma-names:
> > - const: tx
> > + minItems: 1
> > + maxItems: 5
> > + items:
> > + enum:
> > + - tx
>
> Multiple levels, multiple if:then: (further) - I don't find this binding
> manageable/readable. You should split it, with common binding defining
> common part of hardware or interface if there is such.
I as you suggested, I'll split it. Just to double check, should I fix
any bug found in there (like existing compatible strings having underscore
separators) ? Or should I just split and make sure only new SoC support is
bug free ?
Regards,
John
>
> Best regards,
> Krzysztof
^ permalink raw reply
* Re: [PATCH 0/4] ASoC: Add support for GPIOs driven amplifiers
From: Herve Codina @ 2026-03-30 15:39 UTC (permalink / raw)
To: Mark Brown
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Saravana Kannan, Jaroslav Kysela, Takashi Iwai, linux-sound,
devicetree, linux-kernel, Christophe Leroy, Thomas Petazzoni
In-Reply-To: <4daaa17d-5673-4efa-92ce-4f2ce87eb812@sirena.org.uk>
On Mon, 30 Mar 2026 16:08:47 +0100
Mark Brown <broonie@kernel.org> wrote:
> On Mon, Mar 30, 2026 at 12:16:04PM +0200, Herve Codina wrote:
> > On some embedded system boards, audio amplifiers are designed using
> > discrete components such as op-amp, several resistors and switches to
> > either adjust the gain (switching resistors) or fully switch the
> > audio signal path (mute and/or bypass features).
> >
> > Those switches are usually driven by simple GPIOs.
>
> This sounds a lot like simple-amplifier.c?
simple-amplifier.c doesn't handle amplifier driven by GPIOs.
The only used GPIO in simple-amplifier.c is used to handle the
enable pin the component.
simple-amplifier.c handles component such as dio2125 alone.
Here, we have op-amp but also several components around such as
switches.
The gpio driven amplifier proposed is more generic and can handle
more complex design. I.e. op-amp + resistor and/or line (mute,
bypass) switching. Hardwares handled by this driver are a superset
of just dio2125 and so simple-amplifier.c.
IMHO, it makes sense to have a specific driver for those kind
of hardware design.
Best regards,
Hervé
^ permalink raw reply
* Re: [PATCH v5 3/7] pinctrl: extract pinctrl_generic_to_map() from pinctrl_generic_pins_function_dt_node_to_map()
From: Conor Dooley @ 2026-03-30 15:33 UTC (permalink / raw)
To: Frank Li
Cc: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rafał Miłecki, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-kernel, linux-gpio,
devicetree, imx, linux-arm-kernel, Haibo Chen, Conor Dooley
In-Reply-To: <20260327-pinctrl-mux-v5-3-d4aec9d62c62@nxp.com>
[-- Attachment #1: Type: text/plain, Size: 932 bytes --]
On Fri, Mar 27, 2026 at 05:34:00PM -0400, Frank Li wrote:
> Refactor pinctrl_generic_pins_function_dt_subnode_to_map() by separating DT
> parsing logic from map creation. Introduce a new helper
> pinctrl_generic_to_map() to handle mapping to kernel data structures, while
> keeping DT property parsing in the subnode function.
>
> Improve code structure and enables easier reuse for platforms using
> different DT properties (e.g. pinmux) without modifying the
> dt_node_to_map-style callback API. Avoid unnecessary coupling to
> pinctrl_generic_pins_function_dt_node_to_map(), which provides
> functionality not needed when the phandle target is unambiguous.
>
> Maximize code reuse and provide a cleaner extension point for future
> pinctrl drivers.
>
> Suggested-by: Conor Dooley <conor.dooley@microchip.com>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH 5/7] dt-bindings: cache: ax45mp-cache: rename ax45mp-cache to llcache
From: Conor Dooley @ 2026-03-30 15:29 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Hui Min Mina Chou, pjw, palmer, aou, alex, geert+renesas,
prabhakar.mahadev-lad.rj, magnus.damm, ben717, robh, krzk+dt,
conor+dt, jonathan.cameron, devicetree, linux-riscv, linux-kernel,
linux-renesas-soc, tim609, alex749, az70021
In-Reply-To: <c2a135eb-c8fa-47d6-b774-430ccc4fbda4@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 738 bytes --]
On Mon, Mar 30, 2026 at 03:00:41PM +0200, Krzysztof Kozlowski wrote:
> On 30/03/2026 12:27, Hui Min Mina Chou wrote:
> > The AX45MP-specific cache binding is renamed to a generic Last Level
> > Cache (LLC) schema, as the driver now supports more Andes CPU cores
> > beyond just AX45MP.
> >
> > Updated compatible strings:
> > andestech,qilai-ax45mp-cache -> andestech,qilai-llcache
> > renesas,r9a07g043f-ax45mp-cache -> renesas,r9a07g043f-llcache
> > andestech,ax45mp-cache -> andestech,llcache
>
> Why? No explanations and that is clear ABI break.
Ye, I am not going to accept any compatible string renames for this
hardware. The break is too significant, since the devices *need* this to
function.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH 5/7] dt-bindings: cache: ax45mp-cache: rename ax45mp-cache to llcache
From: Conor Dooley @ 2026-03-30 15:28 UTC (permalink / raw)
To: Hui Min Mina Chou
Cc: pjw, palmer, aou, alex, geert+renesas, prabhakar.mahadev-lad.rj,
magnus.damm, ben717, robh, krzk+dt, conor+dt, jonathan.cameron,
devicetree, linux-riscv, linux-kernel, linux-renesas-soc, tim609,
alex749, az70021
In-Reply-To: <20260330102724.1012470-6-minachou@andestech.com>
[-- Attachment #1: Type: text/plain, Size: 3103 bytes --]
On Mon, Mar 30, 2026 at 06:27:22PM +0800, Hui Min Mina Chou wrote:
> The AX45MP-specific cache binding is renamed to a generic Last Level
> Cache (LLC) schema, as the driver now supports more Andes CPU cores
> beyond just AX45MP.
>
> Updated compatible strings:
> andestech,qilai-ax45mp-cache -> andestech,qilai-llcache
> renesas,r9a07g043f-ax45mp-cache -> renesas,r9a07g043f-llcache
> andestech,ax45mp-cache -> andestech,llcache
>
> Signed-off-by: Hui Min Mina Chou <minachou@andestech.com>
> ---
> ...ache.yaml => andestech,andes-llcache.yaml} | 20 +++++++++----------
> 1 file changed, 10 insertions(+), 10 deletions(-)
> rename Documentation/devicetree/bindings/cache/{andestech,ax45mp-cache.yaml => andestech,andes-llcache.yaml} (76%)
>
> diff --git a/Documentation/devicetree/bindings/cache/andestech,ax45mp-cache.yaml b/Documentation/devicetree/bindings/cache/andestech,andes-llcache.yaml
> similarity index 76%
> rename from Documentation/devicetree/bindings/cache/andestech,ax45mp-cache.yaml
> rename to Documentation/devicetree/bindings/cache/andestech,andes-llcache.yaml
> index b135ffa4ab6b..5b97625edd37 100644
> --- a/Documentation/devicetree/bindings/cache/andestech,ax45mp-cache.yaml
> +++ b/Documentation/devicetree/bindings/cache/andestech,andes-llcache.yaml
> @@ -2,17 +2,17 @@
> # Copyright (C) 2023 Renesas Electronics Corp.
> %YAML 1.2
> ---
> -$id: http://devicetree.org/schemas/cache/andestech,ax45mp-cache.yaml#
> +$id: http://devicetree.org/schemas/cache/andestech,llcache.yaml#
> $schema: http://devicetree.org/meta-schemas/core.yaml#
>
> -title: Andestech AX45MP L2 Cache Controller
> +title: Andestech Last Level Cache Controller
>
> maintainers:
> - Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> description:
> - A level-2 cache (L2C) is used to improve the system performance by providing
> - a large amount of cache line entries and reasonable access delays. The L2C
> + A last level cache (LLC) is used to improve the system performance by providing
> + a large amount of cache line entries and reasonable access delays. The LLC
> is shared between cores, and a non-inclusive non-exclusive policy is used.
>
> select:
> @@ -20,7 +20,7 @@ select:
> compatible:
> contains:
> enum:
> - - andestech,ax45mp-cache
> + - andestech,llcache
>
> required:
> - compatible
> @@ -29,9 +29,9 @@ properties:
> compatible:
> items:
> - enum:
> - - andestech,qilai-ax45mp-cache
> - - renesas,r9a07g043f-ax45mp-cache
> - - const: andestech,ax45mp-cache
> + - andestech,qilai-llcache
> + - renesas,r9a07g043f-llcache
> + - const: andestech,llcache
> - const: cache
If you want to add a more generalied compatible to use as a fallback,
insert it underneath andestech,ax45mp-cache. andestech,llcache is far
too generic though, and there appears to be no user that isn't an ax45mp
now anyway, so not sure what this even gives us right now?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* [PATCH 2/2] arm64: dts: marvell: armada-37xx: swap PHYs' order in USB3 controller node
From: Gabor Juhos @ 2026-03-30 15:25 UTC (permalink / raw)
To: Gregory Clement, Andrew Lunn, Sebastian Hesselbarth, Robert Marko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Greg Kroah-Hartman, Stanley Chang
Cc: linux-arm-kernel, devicetree, linux-kernel, Gabor Juhos
In-Reply-To: <20260330-armada-37xx-usb3-phy-cleanup-v1-0-34d77f1a1784@gmail.com>
It seems that the Armada 3700 is the only platform where the USB3 specific
PHY is defined before the USB2 specific one in the device tree:
$ git grep -E 'phy-names[ \t]*=[ \t]*"usb3-phy"[ \t]*,' next-20260327 -- *.dts *.dtsi | tr '\t' ' '
next-20260327:arch/arm64/boot/dts/marvell/armada-37xx.dtsi: phy-names = "usb3-phy", "usb2-utmi-otg-phy";
In contrary to this, there are 93 other platforms/boards where 'usb2-phy'
is defined first:
$ git grep -E 'phy-names[ \t]*=[ \t]*"usb2-phy"[ \t]*,' next-20260327 -- *.dts *.dtsi | wc -l
93
Swap the order of the USB3 and USB2 PHYs to follow the common pattern
used on other platforms.
No functional changes intended.
Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
---
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 7470d504a41081b32bee45368028189a13ea7087..360fc24fdde2204540ac415852146d3020be87c0 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -371,8 +371,8 @@ usb3: usb@58000 {
reg = <0x58000 0x4000>;
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sb_periph_clk 12>;
- phys = <&comphy0 0>, <&usb2_utmi_otg_phy>;
- phy-names = "usb3-phy", "usb2-phy";
+ phys = <&usb2_utmi_otg_phy>, <&comphy0 0>;
+ phy-names = "usb2-phy", "usb3-phy";
status = "disabled";
};
--
2.53.0
^ permalink raw reply related
* [PATCH 1/2] arm64: dts: marvell: armada-37xx: use 'usb2-phy' in USB3 controller's phy-names
From: Gabor Juhos @ 2026-03-30 15:25 UTC (permalink / raw)
To: Gregory Clement, Andrew Lunn, Sebastian Hesselbarth, Robert Marko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Greg Kroah-Hartman, Stanley Chang
Cc: linux-arm-kernel, devicetree, linux-kernel, Gabor Juhos
In-Reply-To: <20260330-armada-37xx-usb3-phy-cleanup-v1-0-34d77f1a1784@gmail.com>
Instead of the generic 'usb2-phy' name, the Armada 37xx device trees
are using a custom 'usb2-utmi-otg-phy' name for the USB2 PHY in the USB3
controller node. Since commit 53a2d95df836 ("usb: core: add phy notify
connect and disconnect"), this triggers a bug [1] in the USB core which
causes double use of the USB3 PHY.
Change the PHY name to 'usb2-phy' in the SoC and in the uDPU specific
dtsi files in order to avoid triggering the bug and also to keep the
names in line with the ones used by other platforms.
Link: https://lore.kernel.org/r/20260330-usb-avoid-usb3-phy-double-use-v1-1-d2113aecb535@gmail.com # [1]
Fixes: 53a2d95df836 ("usb: core: add phy notify connect and disconnect")
Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
---
arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi | 2 +-
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi
index cd856c0aba71e6f6fd3db8fb386ad607912e7577..12deacb741ccbea684d905f246f26a4399fc8cd8 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi
@@ -161,7 +161,7 @@ ð1 {
&usb3 {
status = "okay";
phys = <&usb2_utmi_otg_phy>;
- phy-names = "usb2-utmi-otg-phy";
+ phy-names = "usb2-phy";
};
&uart0 {
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 44c47409f8793ae1266303607812ef481edbfbc5..7470d504a41081b32bee45368028189a13ea7087 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -372,7 +372,7 @@ usb3: usb@58000 {
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sb_periph_clk 12>;
phys = <&comphy0 0>, <&usb2_utmi_otg_phy>;
- phy-names = "usb3-phy", "usb2-utmi-otg-phy";
+ phy-names = "usb3-phy", "usb2-phy";
status = "disabled";
};
--
2.53.0
^ permalink raw reply related
* [PATCH 0/2] arm64: dts: marvell: armada-37xx: USB3 PHY cleanup
From: Gabor Juhos @ 2026-03-30 15:25 UTC (permalink / raw)
To: Gregory Clement, Andrew Lunn, Sebastian Hesselbarth, Robert Marko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Greg Kroah-Hartman, Stanley Chang
Cc: linux-arm-kernel, devicetree, linux-kernel, Gabor Juhos
There are two small patches in the series. The first helps to avoid
triggering a bug in the USB core code, whereas the second one is a
small cleanup to align PHY definitions of the USB3 node with other
platforms.
Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
---
Gabor Juhos (2):
arm64: dts: marvell: armada-37xx: use 'usb2-phy' in USB3 controller's phy-names
arm64: dts: marvell: armada-37xx: swap PHYs' order in USB3 controller node
arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi | 2 +-
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
---
base-commit: 2ff6cc999a04bcb094b8cbba68a9251f03a5c876
change-id: 20260330-armada-37xx-usb3-phy-cleanup-922a5472794a
Best regards,
--
Gabor Juhos <j4g8y7@gmail.com>
^ permalink raw reply
* Re: [PATCH 2/7] cache: andes_llcache: refactor initialization and cache operations
From: Conor Dooley @ 2026-03-30 15:23 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Hui Min Mina Chou, pjw, palmer, aou, alex, geert+renesas,
prabhakar.mahadev-lad.rj, magnus.damm, ben717, robh, krzk+dt,
conor+dt, jonathan.cameron, devicetree, linux-riscv, linux-kernel,
linux-renesas-soc, tim609, alex749, az70021
In-Reply-To: <8c01c910-21b4-4a16-98e4-197c20883d23@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 754 bytes --]
On Mon, Mar 30, 2026 at 03:02:11PM +0200, Krzysztof Kozlowski wrote:
> On 30/03/2026 12:27, Hui Min Mina Chou wrote:
> > This patch cleans up the Andes LLC cache driver:
> > - improved error handling in andes_cache_init() by using goto labels
> > - updated andes_dma_cache_inv/wback() to check for !size instead of
> > start == end
> > - cache-line-size mismatch from an error to a warning
> > - Use ALIGN and ALIGN_DOWN helpers instead of the alignment logic in
> > andes_dma_cache_inv() and andes_dma_cache_wback().
>
> Please read submitting patches document. One thing per commit with
> proper rationale WHY you are doing this.
Applies to multiple patches too. Anything here with a bullet list needs
to be several patches.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH 10/16] clk: Add support for clock nexus dt bindings
From: Brian Masney @ 2026-03-30 15:16 UTC (permalink / raw)
To: Miquel Raynal (Schneider Electric)
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm, Thomas Petazzoni,
Pascal EBERHARD, Wolfram Sang, linux-clk, devicetree,
linux-kernel, linux-crypto, linux-renesas-soc, Herve Codina
In-Reply-To: <20260327-schneider-v7-0-rc1-crypto-v1-10-5e6ff7853994@bootlin.com>
On Fri, Mar 27, 2026 at 09:09:32PM +0100, Miquel Raynal (Schneider Electric) wrote:
> A nexus node is some kind of parent device abstracting the outer
> connections. They are particularly useful for describing connectors-like
> interfaces but not only. Certain IP blocks will typically include inner
> blocks and distribute resources to them.
>
> In the case of clocks, there is already the concept of clock controller,
> but this usually indicates some kind of control over the said clock,
> ie. gate or rate control. When there is none of this, an existing
> approach is to reference the upper clock, which is wrong from a hardware
> point of view.
>
> Nexus nodes are already part of the device-tree specification and clocks
> are already mentioned:
> https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter2-devicetree-basics.rst#nexus-nodes-and-specifier-mapping
>
> Following the introductions of nexus nodes support for interrupts, gpios
> and pwms, here is the same logic applied again to the clk subsystem,
> just by transitioning from of_parse_phandle_with_args() to
> of_parse_phandle_with_args_map():
>
> * Nexus OF support:
> commit bd6f2fd5a1d5 ("of: Support parsing phandle argument lists through a nexus node")
> * GPIO adoption:
> commit c11e6f0f04db ("gpio: Support gpio nexus dt bindings")
> * PWM adoption:
> commit e71e46a6f19c ("pwm: Add support for pwm nexus dt bindings")
>
> Expected Nexus properties supported:
> - clock-map: maps inner clocks to inlet clocks,
> - clock-map-mask: specifier cell(s) which will be remapped,
> - clock-map-pass-thru: specifier cell(s) not used for remapping,
> forwarded as-is.
>
> In my own usage I had to deal with controllers where clock-map-mask and
> clock-map-pass-thru were not relevant, but here is a made up example
> showing how all these properties could go together:
>
> Example:
> soc_clk: clock-controller {
> #clock-cells = <2>;
> };
>
> container: container {
> #clock-cells = <2>;
> clock-map = <0 0 &soc_clk 2 0>,
> <1 0 &soc_clk 6 0>;
> clock-map-mask = <0xffffffff 0x0>;
> clock-map-pass-thru = <0x0 0xffffffff>;
>
> child-device {
> clocks = <&container 1 0>;
> /* This is equivalent to <&soc_clk 6 0> */
> };
> };
>
> The child device does not need to know about the outer implementation,
> and only knows about what the nexus provides. The nexus acts as a
> pass-through, with no extra control.
>
> Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
> Reviewed-by: Herve Codina <herve.codina@bootlin.com>
> ---
> drivers/clk/clk.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 93e33ff30f3a..196ba727e84b 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -5218,8 +5218,8 @@ static int of_parse_clkspec(const struct device_node *np, int index,
> */
> if (name)
> index = of_property_match_string(np, "clock-names", name);
> - ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells",
> - index, out_args);
> + ret = of_parse_phandle_with_args_map(np, "clocks", "clock",
> + index, out_args);
Before I left my Reviewed-by, I should have double checked Sashiko. It
has several questions about this patch. The first is:
Are there other places in the clock framework that need to transition to the
new map API to ensure assigned clocks work?
For instance, assigned-clocks and assigned-clock-parents are parsed in
drivers/clk/clk-conf.c using of_parse_phandle_with_args(). If a device
specifies an assigned clock that routes through a nexus node, will it fail
to configure because the map is not traversed?
https://sashiko.dev/#/patchset/20260327-schneider-v7-0-rc1-crypto-v1-0-5e6ff7853994%40bootlin.com?patch=12563
Brian
^ permalink raw reply
* [PATCH v5 2/2] hwmon: Add support for TI INA4230 power monitor
From: Alexey Charkov @ 2026-03-30 15:14 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-hwmon, devicetree, linux-kernel, Alexey Charkov
In-Reply-To: <20260330-ina4230-v5-0-eeb322d95b3a@flipper.net>
Add a driver for the TI INA4230, a 4-channel power monitor with I2C
interface.
The driver supports voltage, current, power and energy measurements, but
skips the alert functionality in this initial implementation.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
MAINTAINERS | 1 +
drivers/hwmon/Kconfig | 11 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/ina4230.c | 986 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 999 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index acfa0b0585a5..9fc627b809a4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12579,6 +12579,7 @@ M: Alexey Charkov <alchark@flipper.net>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/hwmon/ti,ina4230.yaml
+F: drivers/hwmon/ina4230.c
INDEX OF FURTHER KERNEL DOCUMENTATION
M: Carlos Bilbao <carlos.bilbao@kernel.org>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 9d49cfd4ef3d..4649f00f24ca 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -2296,6 +2296,17 @@ config SENSORS_INA3221
This driver can also be built as a module. If so, the module
will be called ina3221.
+config SENSORS_INA4230
+ tristate "Texas Instruments INA4230 Quad Current/Voltage Monitor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the TI INA4230 Quad
+ Current/Voltage Monitor.
+
+ This driver can also be built as a module. If so, the module
+ will be called ina4230.
+
config SENSORS_SPD5118
tristate "SPD5118 Compliant Temperature Sensors"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 556e86d277b1..3d83eba94bec 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -104,6 +104,7 @@ obj-$(CONFIG_SENSORS_INA209) += ina209.o
obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
obj-$(CONFIG_SENSORS_INA238) += ina238.o
obj-$(CONFIG_SENSORS_INA3221) += ina3221.o
+obj-$(CONFIG_SENSORS_INA4230) += ina4230.o
obj-$(CONFIG_SENSORS_INTEL_M10_BMC_HWMON) += intel-m10-bmc-hwmon.o
obj-$(CONFIG_SENSORS_ISL28022) += isl28022.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
diff --git a/drivers/hwmon/ina4230.c b/drivers/hwmon/ina4230.c
new file mode 100644
index 000000000000..a31a3f995afc
--- /dev/null
+++ b/drivers/hwmon/ina4230.c
@@ -0,0 +1,986 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * INA4230 Quad Current/Voltage Monitor
+ *
+ * Based on INA3221 driver by Texas Instruments Incorporated - https://www.ti.com/
+ * Adapted for INA4230 by Alexey Charkov <alchark@flipper.net>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/byteorder/generic.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/util_macros.h>
+
+#define INA4230_DRIVER_NAME "ina4230"
+
+#define INA4230_SHUNT_VOLTAGE_CH1 0x00
+#define INA4230_BUS_VOLTAGE_CH1 0x01
+#define INA4230_CURRENT_CH1 0x02
+#define INA4230_POWER_CH1 0x03
+#define INA4230_ENERGY_CH1 0x04
+#define INA4230_CALIBRATION_CH1 0x05
+#define INA4230_ALERT_LIMIT1 0x06
+#define INA4230_ALERT_CONFIG1 0x07
+#define INA4230_SHUNT_VOLTAGE_CH2 0x08
+#define INA4230_BUS_VOLTAGE_CH2 0x09
+#define INA4230_CURRENT_CH2 0x0A
+#define INA4230_POWER_CH2 0x0B
+#define INA4230_ENERGY_CH2 0x0C
+#define INA4230_CALIBRATION_CH2 0x0D
+#define INA4230_ALERT_LIMIT2 0x0E
+#define INA4230_ALERT_CONFIG2 0x0F
+#define INA4230_SHUNT_VOLTAGE_CH3 0x10
+#define INA4230_BUS_VOLTAGE_CH3 0x11
+#define INA4230_CURRENT_CH3 0x12
+#define INA4230_POWER_CH3 0x13
+#define INA4230_ENERGY_CH3 0x14
+#define INA4230_CALIBRATION_CH3 0x15
+#define INA4230_ALERT_LIMIT3 0x16
+#define INA4230_ALERT_CONFIG3 0x17
+#define INA4230_SHUNT_VOLTAGE_CH4 0x18
+#define INA4230_BUS_VOLTAGE_CH4 0x19
+#define INA4230_CURRENT_CH4 0x1A
+#define INA4230_POWER_CH4 0x1B
+#define INA4230_ENERGY_CH4 0x1C
+#define INA4230_CALIBRATION_CH4 0x1D
+#define INA4230_ALERT_LIMIT4 0x1E
+#define INA4230_ALERT_CONFIG4 0x1F
+#define INA4230_CONFIG1 0x20
+#define INA4230_CONFIG2 0x21
+#define INA4230_FLAGS 0x22
+#define INA4230_MANUFACTURER_ID 0x7E
+
+#define INA4230_CALIBRATION_MASK GENMASK(14, 0)
+
+#define INA4230_ALERT_CHANNEL_MASK GENMASK(4, 3)
+#define INA4230_ALERT_MASK GENMASK(2, 0)
+/* Shunt voltage over limit */
+#define INA4230_ALERT_MASK_SOL 0x1
+/* Shunt voltage under limit */
+#define INA4230_ALERT_MASK_SUL 0x2
+/* Bus voltage over limit */
+#define INA4230_ALERT_MASK_BOL 0x3
+/* Bus voltage under limit */
+#define INA4230_ALERT_MASK_BUL 0x4
+/* Power over limit */
+#define INA4230_ALERT_MASK_POL 0x5
+
+#define INA4230_CONFIG1_ACTIVE_CHANNEL_MASK GENMASK(15, 12)
+#define INA4230_CONFIG1_AVG_MASK GENMASK(11, 9)
+#define INA4230_CONFIG1_VBUSCT_MASK GENMASK(8, 6)
+#define INA4230_CONFIG1_VSHCT_MASK GENMASK(5, 3)
+#define INA4230_CONFIG1_MODE_MASK GENMASK(2, 0)
+#define INA4230_MODE_POWERDOWN 0
+#define INA4230_MODE_SHUNT_SINGLE 1
+#define INA4230_MODE_BUS_SINGLE 2
+#define INA4230_MODE_BUS_SHUNT_SINGLE 3
+#define INA4230_MODE_POWERDOWN1 4
+#define INA4230_MODE_SHUNT_CONTINUOUS 5
+#define INA4230_MODE_BUS_CONTINUOUS 6
+#define INA4230_MODE_BUS_SHUNT_CONTINUOUS 7
+
+#define INA4230_CONFIG2_RST BIT(15)
+#define INA4230_CONFIG2_ACC_RST_MASK GENMASK(11, 8)
+#define INA4230_CONFIG2_CNVR_MASK BIT(7)
+#define INA4230_CONFIG2_ENOF_MASK BIT(6)
+#define INA4230_CONFIG2_ALERT_LATCH BIT(5)
+#define INA4230_CONFIG2_ALERT_POL BIT(4)
+#define INA4230_CONFIG2_RANGE_MASK GENMASK(3, 0)
+#define INA4230_CONFIG2_RANGE_CH(x) \
+ FIELD_PREP(INA4230_CONFIG2_RANGE_MASK, BIT((x)))
+
+#define INA4230_FLAGS_LIMIT4_ALERT BIT(15)
+#define INA4230_FLAGS_LIMIT3_ALERT BIT(14)
+#define INA4230_FLAGS_LIMIT2_ALERT BIT(13)
+#define INA4230_FLAGS_LIMIT1_ALERT BIT(12)
+#define INA4230_FLAGS_ENERGY_OVERFLOW_CH4 BIT(11)
+#define INA4230_FLAGS_ENERGY_OVERFLOW_CH3 BIT(10)
+#define INA4230_FLAGS_ENERGY_OVERFLOW_CH2 BIT(9)
+#define INA4230_FLAGS_ENERGY_OVERFLOW_CH1 BIT(8)
+#define INA4230_FLAGS_CVRF BIT(7)
+#define INA4230_FLAGS_MATH_OVERFLOW BIT(6)
+
+#define INA4230_RSHUNT_DEFAULT 10000
+#define INA4230_CONFIG_DEFAULT \
+ (FIELD_PREP(INA4230_CONFIG1_ACTIVE_CHANNEL_MASK, 0xF) | \
+ FIELD_PREP(INA4230_CONFIG1_AVG_MASK, 0x1) | \
+ FIELD_PREP(INA4230_CONFIG1_VBUSCT_MASK, 0x4) | \
+ FIELD_PREP(INA4230_CONFIG1_VSHCT_MASK, 0x4) | \
+ FIELD_PREP(INA4230_CONFIG1_MODE_MASK, 0x7))
+#define INA4230_CONFIG_CHx_EN(x) \
+ FIELD_PREP(INA4230_CONFIG1_ACTIVE_CHANNEL_MASK, BIT((x)))
+
+enum ina4230_fields {
+ /* Alert configuration settings: channel masks */
+ F_ALERT1_CH, F_ALERT2_CH, F_ALERT3_CH, F_ALERT4_CH,
+ /* Alert configuration settings: alert masks */
+ F_ALERT1_TYPE, F_ALERT2_TYPE, F_ALERT3_TYPE, F_ALERT4_TYPE,
+ /* Configuration registers */
+ F_CH_EN, F_AVG, F_VBUSCT, F_VSHCT, F_MODE,
+ F_RST, F_ACC_RST, F_CNV_ALERT, F_ENOF, F_ALERT_LATCH, F_ALERT_POL, F_RANGE,
+ /* Status flags */
+ F_LIMIT1_ALERT, F_LIMIT2_ALERT, F_LIMIT3_ALERT, F_LIMIT4_ALERT,
+ F_ENERGY_OVERFLOW_CH1, F_ENERGY_OVERFLOW_CH2, F_ENERGY_OVERFLOW_CH3, F_ENERGY_OVERFLOW_CH4,
+ F_CVRF, F_MATH_OVERFLOW,
+ /* sentinel */
+ F_MAX_FIELDS
+};
+
+static const struct reg_field ina4230_reg_fields[] = {
+ [F_ALERT1_CH] = REG_FIELD(INA4230_ALERT_CONFIG1, 3, 4),
+ [F_ALERT2_CH] = REG_FIELD(INA4230_ALERT_CONFIG2, 3, 4),
+ [F_ALERT3_CH] = REG_FIELD(INA4230_ALERT_CONFIG3, 3, 4),
+ [F_ALERT4_CH] = REG_FIELD(INA4230_ALERT_CONFIG4, 3, 4),
+
+ [F_ALERT1_TYPE] = REG_FIELD(INA4230_ALERT_CONFIG1, 0, 2),
+ [F_ALERT2_TYPE] = REG_FIELD(INA4230_ALERT_CONFIG2, 0, 2),
+ [F_ALERT3_TYPE] = REG_FIELD(INA4230_ALERT_CONFIG3, 0, 2),
+ [F_ALERT4_TYPE] = REG_FIELD(INA4230_ALERT_CONFIG4, 0, 2),
+
+ [F_CH_EN] = REG_FIELD(INA4230_CONFIG1, 12, 15),
+ [F_AVG] = REG_FIELD(INA4230_CONFIG1, 9, 11),
+ [F_VBUSCT] = REG_FIELD(INA4230_CONFIG1, 6, 8),
+ [F_VSHCT] = REG_FIELD(INA4230_CONFIG1, 3, 5),
+ [F_MODE] = REG_FIELD(INA4230_CONFIG1, 0, 2),
+ [F_RST] = REG_FIELD(INA4230_CONFIG2, 15, 15),
+ [F_ACC_RST] = REG_FIELD(INA4230_CONFIG2, 8, 11),
+ [F_CNV_ALERT] = REG_FIELD(INA4230_CONFIG2, 7, 7),
+ [F_ENOF] = REG_FIELD(INA4230_CONFIG2, 6, 6),
+ [F_ALERT_LATCH] = REG_FIELD(INA4230_CONFIG2, 5, 5),
+ [F_ALERT_POL] = REG_FIELD(INA4230_CONFIG2, 4, 4),
+ [F_RANGE] = REG_FIELD(INA4230_CONFIG2, 0, 3),
+
+ [F_LIMIT1_ALERT] = REG_FIELD(INA4230_FLAGS, 12, 12),
+ [F_LIMIT2_ALERT] = REG_FIELD(INA4230_FLAGS, 13, 13),
+ [F_LIMIT3_ALERT] = REG_FIELD(INA4230_FLAGS, 14, 14),
+ [F_LIMIT4_ALERT] = REG_FIELD(INA4230_FLAGS, 15, 15),
+ [F_ENERGY_OVERFLOW_CH1] = REG_FIELD(INA4230_FLAGS, 8, 8),
+ [F_ENERGY_OVERFLOW_CH2] = REG_FIELD(INA4230_FLAGS, 9, 9),
+ [F_ENERGY_OVERFLOW_CH3] = REG_FIELD(INA4230_FLAGS, 10, 10),
+ [F_ENERGY_OVERFLOW_CH4] = REG_FIELD(INA4230_FLAGS, 11, 11),
+ [F_CVRF] = REG_FIELD(INA4230_FLAGS, 7, 7),
+ [F_MATH_OVERFLOW] = REG_FIELD(INA4230_FLAGS, 6, 6),
+};
+
+enum ina4230_channels {
+ INA4230_CHANNEL1,
+ INA4230_CHANNEL2,
+ INA4230_CHANNEL3,
+ INA4230_CHANNEL4,
+ INA4230_NUM_CHANNELS
+};
+
+/**
+ * struct ina4230_input - channel input source specific information
+ * @label: label of channel input source
+ * @shunt_resistor: shunt resistor value of channel input source
+ * @shunt_gain: gain of shunt voltage for current calculation
+ * @max_expected_current: maximum expected current in micro-Ampere for ADC
+ * calibration
+ * @current_lsb_uA: current LSB in micro-Amperes
+ * @disconnected: connection status of channel input source
+ */
+struct ina4230_input {
+ const char *label;
+ int shunt_resistor;
+ int shunt_gain;
+ int max_expected_current;
+ int current_lsb_uA;
+ bool disconnected;
+};
+
+/**
+ * struct ina4230_data - device specific information
+ * @pm_dev: Device pointer for pm runtime
+ * @regmap: Register map of the device
+ * @fields: Register fields of the device
+ * @inputs: Array of channel input source specific structures
+ * @reg_config1: cached value of CONFIG1 register
+ * @reg_config2: cached value of CONFIG2 register
+ * @alert_active_high: flag indicating alert polarity is active high
+ */
+struct ina4230_data {
+ struct device *pm_dev;
+ struct regmap *regmap;
+ struct regmap_field *fields[F_MAX_FIELDS];
+ struct ina4230_input inputs[INA4230_NUM_CHANNELS];
+ unsigned int reg_config1;
+ unsigned int reg_config2;
+ bool alert_active_high;
+};
+
+static inline bool ina4230_is_enabled(struct ina4230_data *ina, int channel)
+{
+ return pm_runtime_active(ina->pm_dev) &&
+ !ina->inputs[channel].disconnected &&
+ ina->reg_config1 & INA4230_CONFIG_CHx_EN(channel);
+}
+
+/* Lookup table for Bus and Shunt conversion times in usec */
+static const u16 ina4230_conv_time[] = {
+ 140, 204, 332, 588, 1100, 2116, 4156, 8244,
+};
+
+/* Lookup table for number of samples used in averaging mode */
+static const int ina4230_avg_samples[] = {
+ 1, 4, 16, 64, 128, 256, 512, 1024,
+};
+
+/* Converting update_interval in msec to conversion time in usec */
+static inline u32 ina4230_interval_ms_to_conv_time(u16 config, int interval)
+{
+ u32 channels = hweight16(config & INA4230_CONFIG1_ACTIVE_CHANNEL_MASK);
+ u32 samples_idx = FIELD_GET(INA4230_CONFIG1_AVG_MASK, config);
+ u32 samples = ina4230_avg_samples[samples_idx];
+
+ if (!channels)
+ return U32_MAX;
+
+ /* Bisect the result to Bus and Shunt conversion times */
+ return DIV_ROUND_CLOSEST(interval * 1000 / 2, channels * samples);
+}
+
+/* Converting CONFIG register value to update_interval in usec */
+static inline u32 ina4230_reg_to_interval_us(u16 config)
+{
+ u32 channels = hweight16(config & INA4230_CONFIG1_ACTIVE_CHANNEL_MASK);
+ u32 vbus_ct_idx = FIELD_GET(INA4230_CONFIG1_VBUSCT_MASK, config);
+ u32 vsh_ct_idx = FIELD_GET(INA4230_CONFIG1_VSHCT_MASK, config);
+ u32 vbus_ct = ina4230_conv_time[vbus_ct_idx];
+ u32 vsh_ct = ina4230_conv_time[vsh_ct_idx];
+
+ /* Calculate total conversion time */
+ return channels * (vbus_ct + vsh_ct);
+}
+
+static const u8 ina4230_calibration_reg[] = {
+ INA4230_CALIBRATION_CH1,
+ INA4230_CALIBRATION_CH2,
+ INA4230_CALIBRATION_CH3,
+ INA4230_CALIBRATION_CH4,
+};
+
+static int ina4230_set_calibration(struct ina4230_data *ina, int channel)
+{
+ struct ina4230_input *input = &ina->inputs[channel];
+ u8 reg = ina4230_calibration_reg[channel];
+ int shunt_range_uV, ret;
+ u32 calibration;
+ u64 n, d;
+
+ shunt_range_uV = mult_frac(input->max_expected_current,
+ input->shunt_resistor,
+ 1000000);
+ input->shunt_gain = shunt_range_uV > 20480 ? 1 : 4;
+ ina->reg_config2 &= ~INA4230_CONFIG2_RANGE_CH(channel);
+ if (input->shunt_gain == 4)
+ ina->reg_config2 |= INA4230_CONFIG2_RANGE_CH(channel);
+
+ ret = regmap_write(ina->regmap, INA4230_CONFIG2, ina->reg_config2);
+ if (ret)
+ return ret;
+
+ input->current_lsb_uA = DIV_ROUND_UP(input->max_expected_current, 32768);
+ n = 5120000000ULL;
+ d = (u64)input->current_lsb_uA * input->shunt_resistor * input->shunt_gain;
+ /* Ensure rounding to the closest integer */
+ n += d / 2;
+ n = div64_u64(n, d);
+ if (n > INA4230_CALIBRATION_MASK) {
+ dev_err(ina->pm_dev,
+ "Shunt %duOhm too low for expected current %duA, cannot calibrate channel %d\n",
+ input->shunt_resistor, input->max_expected_current, channel + 1);
+ return -ERANGE;
+ }
+
+ calibration = n & INA4230_CALIBRATION_MASK;
+
+ return regmap_write(ina->regmap, reg, calibration);
+}
+
+static const u8 ina4230_in_reg[] = {
+ INA4230_BUS_VOLTAGE_CH1,
+ INA4230_BUS_VOLTAGE_CH2,
+ INA4230_BUS_VOLTAGE_CH3,
+ INA4230_BUS_VOLTAGE_CH4,
+ INA4230_SHUNT_VOLTAGE_CH1,
+ INA4230_SHUNT_VOLTAGE_CH2,
+ INA4230_SHUNT_VOLTAGE_CH3,
+ INA4230_SHUNT_VOLTAGE_CH4,
+};
+
+static const u8 ina4230_curr_reg[][INA4230_NUM_CHANNELS] = {
+ [hwmon_curr_input] = { INA4230_CURRENT_CH1, INA4230_CURRENT_CH2,
+ INA4230_CURRENT_CH3, INA4230_CURRENT_CH4 },
+};
+
+static const u8 ina4230_power_reg[] = {
+ INA4230_POWER_CH1, INA4230_POWER_CH2, INA4230_POWER_CH3, INA4230_POWER_CH4
+};
+
+static const u8 ina4230_energy_reg[] = {
+ INA4230_ENERGY_CH1, INA4230_ENERGY_CH2,
+ INA4230_ENERGY_CH3, INA4230_ENERGY_CH4
+};
+
+static int ina4230_read_chip(struct device *dev, u32 attr, long *val)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ int regval;
+
+ switch (attr) {
+ case hwmon_chip_samples:
+ regval = FIELD_GET(INA4230_CONFIG1_AVG_MASK, ina->reg_config1);
+ *val = ina4230_avg_samples[regval];
+ return 0;
+ case hwmon_chip_update_interval:
+ /* Return in msec */
+ *val = ina4230_reg_to_interval_us(ina->reg_config1);
+ *val = DIV_ROUND_CLOSEST(*val, 1000);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ina4230_read_in(struct device *dev, u32 attr, int channel, long *val)
+{
+ const bool is_shunt = channel > INA4230_CHANNEL4;
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ u8 reg = ina4230_in_reg[channel];
+ int regval, ret;
+
+ /*
+ * Translate shunt channel index to sensor channel index
+ */
+ channel %= INA4230_NUM_CHANNELS;
+
+ switch (attr) {
+ case hwmon_in_input:
+ if (!ina4230_is_enabled(ina, channel))
+ return -ENODATA;
+
+ ret = regmap_read(ina->regmap, reg, ®val);
+ if (ret)
+ return ret;
+
+ /*
+ * Scale of shunt voltage (uV): LSB is 2.5uV or 625nV
+ * depending on gain setting
+ * Scale of bus voltage (mV): LSB is 1.6mV
+ */
+ if (is_shunt)
+ *val = mult_frac((long)(int16_t)regval,
+ 2500 / ina->inputs[channel].shunt_gain,
+ 1000000);
+ else
+ *val = mult_frac((long)(int16_t)regval,
+ 1600,
+ 1000);
+ return 0;
+ case hwmon_in_enable:
+ *val = ina4230_is_enabled(ina, channel);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ina4230_read_power(struct device *dev, u32 attr, int channel, long *val)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ u8 reg = ina4230_power_reg[channel];
+ int regval, ret;
+
+ switch (attr) {
+ case hwmon_power_input:
+ if (!ina4230_is_enabled(ina, channel))
+ return -ENODATA;
+
+ ret = regmap_read(ina->regmap, reg, ®val);
+ if (ret)
+ return ret;
+
+ *val = (int16_t)regval *
+ (long)ina->inputs[channel].current_lsb_uA * 32;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ina4230_read_energy(struct device *dev, u32 attr, int channel, long *val)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ u8 reg = ina4230_energy_reg[channel];
+ int ret;
+ __be32 regval;
+
+ switch (attr) {
+ case hwmon_energy_input:
+ if (!ina4230_is_enabled(ina, channel))
+ return -ENODATA;
+
+ ret = regmap_noinc_read(ina->regmap, reg, ®val, sizeof(regval));
+ if (ret)
+ return ret;
+
+ *val = be32_to_cpu(regval) *
+ (long)ina->inputs[channel].current_lsb_uA * 32;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ina4230_read_curr(struct device *dev, u32 attr,
+ int channel, long *val)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ u8 reg = ina4230_curr_reg[attr][channel];
+ int regval, ret;
+
+ switch (attr) {
+ case hwmon_curr_input:
+ if (!ina4230_is_enabled(ina, channel))
+ return -ENODATA;
+
+ ret = regmap_read(ina->regmap, reg, ®val);
+ if (ret)
+ return ret;
+
+ *val = (int16_t)regval *
+ (long)ina->inputs[channel].current_lsb_uA / 1000;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ina4230_write_chip(struct device *dev, u32 attr, long val)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ int idx;
+ u32 tmp;
+
+ switch (attr) {
+ case hwmon_chip_samples:
+ idx = find_closest(val, ina4230_avg_samples,
+ ARRAY_SIZE(ina4230_avg_samples));
+
+ FIELD_MODIFY(INA4230_CONFIG1_AVG_MASK, &ina->reg_config1, idx);
+ return regmap_write(ina->regmap, INA4230_CONFIG1, ina->reg_config1);
+ case hwmon_chip_update_interval:
+ tmp = ina4230_interval_ms_to_conv_time(ina->reg_config1, val);
+ idx = find_closest(tmp, ina4230_conv_time,
+ ARRAY_SIZE(ina4230_conv_time));
+
+ FIELD_MODIFY(INA4230_CONFIG1_VBUSCT_MASK, &ina->reg_config1, idx);
+ FIELD_MODIFY(INA4230_CONFIG1_VSHCT_MASK, &ina->reg_config1, idx);
+ return regmap_write(ina->regmap, INA4230_CONFIG1, ina->reg_config1);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ina4230_write_enable(struct device *dev, int channel, bool enable)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ u16 config, mask = INA4230_CONFIG_CHx_EN(channel);
+ u16 config_old = ina->reg_config1 & mask;
+ u32 tmp;
+ int ret;
+
+ config = enable ? mask : 0;
+
+ /* Bypass if enable status is not being changed */
+ if (config_old == config)
+ return 0;
+
+ /* For enabling routine, increase refcount and resume() at first */
+ if (enable) {
+ ret = pm_runtime_resume_and_get(ina->pm_dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get PM runtime\n");
+ return ret;
+ }
+ }
+
+ /* Enable or disable the channel */
+ tmp = (ina->reg_config1 & ~mask) | (config & mask);
+ ret = regmap_write(ina->regmap, INA4230_CONFIG1, tmp);
+ if (ret)
+ goto fail;
+
+ /* Cache the latest config register value */
+ ina->reg_config1 = tmp;
+
+ /* For disabling routine, decrease refcount or suspend() at last */
+ if (!enable)
+ pm_runtime_put_sync(ina->pm_dev);
+
+ return 0;
+
+fail:
+ if (enable) {
+ dev_err(dev, "Failed to enable channel %d: error %d\n",
+ channel, ret);
+ pm_runtime_put_sync(ina->pm_dev);
+ }
+
+ return ret;
+}
+
+static int ina4230_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ int ret;
+
+ switch (type) {
+ case hwmon_chip:
+ ret = ina4230_read_chip(dev, attr, val);
+ break;
+ case hwmon_in:
+ /* 0-align channel ID */
+ ret = ina4230_read_in(dev, attr, channel - 1, val);
+ break;
+ case hwmon_curr:
+ ret = ina4230_read_curr(dev, attr, channel, val);
+ break;
+ case hwmon_power:
+ ret = ina4230_read_power(dev, attr, channel, val);
+ break;
+ case hwmon_energy:
+ ret = ina4230_read_energy(dev, attr, channel, val);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static int ina4230_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ int ret;
+
+ switch (type) {
+ case hwmon_chip:
+ ret = ina4230_write_chip(dev, attr, val);
+ break;
+ case hwmon_in:
+ /* 0-align channel ID */
+ ret = ina4230_write_enable(dev, channel - 1, val);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static int ina4230_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ int index = channel - 1;
+
+ *str = ina->inputs[index].label;
+
+ return 0;
+}
+
+static umode_t ina4230_is_visible(const void *drvdata,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct ina4230_data *ina = drvdata;
+ const struct ina4230_input *input = NULL;
+
+ switch (type) {
+ case hwmon_chip:
+ switch (attr) {
+ case hwmon_chip_samples:
+ case hwmon_chip_update_interval:
+ return 0644;
+ default:
+ return 0;
+ }
+ case hwmon_in:
+ /* Ignore in0_ */
+ if (channel == 0)
+ return 0;
+
+ switch (attr) {
+ case hwmon_in_label:
+ if (channel - 1 <= INA4230_CHANNEL4)
+ input = &ina->inputs[channel - 1];
+ /* Hide label node if label is not provided */
+ return (input && input->label) ? 0444 : 0;
+ case hwmon_in_input:
+ return 0444;
+ case hwmon_in_enable:
+ return 0644;
+ default:
+ return 0;
+ }
+ case hwmon_curr:
+ switch (attr) {
+ case hwmon_curr_input:
+ return 0444;
+ default:
+ return 0;
+ }
+ case hwmon_power:
+ switch (attr) {
+ case hwmon_power_input:
+ return 0444;
+ default:
+ return 0;
+ }
+ case hwmon_energy:
+ switch (attr) {
+ case hwmon_energy_input:
+ return 0444;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+static const struct hwmon_channel_info * const ina4230_info[] = {
+ HWMON_CHANNEL_INFO(chip,
+ HWMON_C_SAMPLES,
+ HWMON_C_UPDATE_INTERVAL),
+ HWMON_CHANNEL_INFO(in,
+ /* 0: dummy, skipped in is_visible */
+ HWMON_I_INPUT,
+ /* 1-4: input voltage Channels */
+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
+ /* 5-8: shunt voltage Channels */
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT),
+ HWMON_CHANNEL_INFO(curr,
+ /* 1-4: current channels*/
+ HWMON_C_INPUT,
+ HWMON_C_INPUT,
+ HWMON_C_INPUT,
+ HWMON_C_INPUT),
+ HWMON_CHANNEL_INFO(power,
+ /* 1-4: power channels*/
+ HWMON_P_INPUT,
+ HWMON_P_INPUT,
+ HWMON_P_INPUT,
+ HWMON_P_INPUT),
+ HWMON_CHANNEL_INFO(energy,
+ /* 1-4: energy channels*/
+ HWMON_E_INPUT,
+ HWMON_E_INPUT,
+ HWMON_E_INPUT,
+ HWMON_E_INPUT),
+ NULL
+};
+
+static const struct hwmon_ops ina4230_hwmon_ops = {
+ .is_visible = ina4230_is_visible,
+ .read_string = ina4230_read_string,
+ .read = ina4230_read,
+ .write = ina4230_write,
+};
+
+static const struct hwmon_chip_info ina4230_chip_info = {
+ .ops = &ina4230_hwmon_ops,
+ .info = ina4230_info,
+};
+
+static const struct regmap_range ina4230_vol_ranges[] = {
+ regmap_reg_range(INA4230_SHUNT_VOLTAGE_CH1, INA4230_ENERGY_CH1),
+ regmap_reg_range(INA4230_SHUNT_VOLTAGE_CH2, INA4230_ENERGY_CH2),
+ regmap_reg_range(INA4230_SHUNT_VOLTAGE_CH3, INA4230_ENERGY_CH3),
+ regmap_reg_range(INA4230_SHUNT_VOLTAGE_CH4, INA4230_ENERGY_CH4),
+ regmap_reg_range(INA4230_CONFIG2, INA4230_CONFIG2),
+ regmap_reg_range(INA4230_FLAGS, INA4230_FLAGS),
+};
+
+static const struct regmap_access_table ina4230_volatile_table = {
+ .yes_ranges = ina4230_vol_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ina4230_vol_ranges),
+};
+
+static const struct regmap_config ina4230_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_table = &ina4230_volatile_table,
+};
+
+static int ina4230_probe_child_from_dt(struct device *dev,
+ struct device_node *child,
+ struct ina4230_data *ina)
+{
+ struct ina4230_input *input;
+ u32 val;
+ int ret;
+
+ ret = of_property_read_u32(child, "reg", &val);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing reg property of %pOFn\n", child);
+ else if (val > INA4230_CHANNEL4)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid reg %d of %pOFn\n", val, child);
+
+ input = &ina->inputs[val];
+
+ /* Log the disconnected channel input */
+ if (!of_device_is_available(child)) {
+ input->disconnected = true;
+ return 0;
+ }
+
+ /* Save the connected input label if available */
+ of_property_read_string(child, "label", &input->label);
+
+ /* Overwrite default shunt resistor value optionally */
+ if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) {
+ if (val < 1 || val > INT_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid shunt resistor value %u of %pOFn\n",
+ val, child);
+
+ input->shunt_resistor = val;
+ }
+
+ /* Save the expected maxcurrent */
+ if (!of_property_read_u32(child, "ti,maximum-expected-current-microamp", &val)) {
+ if (val < 32768 || val > INT_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid max current value %u of %pOFn\n",
+ val, child);
+
+ input->max_expected_current = val;
+ }
+
+ return 0;
+}
+
+static int ina4230_probe_from_dt(struct device *dev, struct ina4230_data *ina)
+{
+ const struct device_node *np = dev->of_node;
+ int ret;
+
+ /* Compatible with non-DT platforms */
+ if (!np)
+ return 0;
+
+ ina->alert_active_high = of_property_read_bool(np, "ti,alert-polarity-active-high");
+
+ for_each_child_of_node_scoped(np, child) {
+ ret = ina4230_probe_child_from_dt(dev, child, ina);
+ if (ret)
+ return ret;
+ }
+
+ ret = devm_regulator_get_enable_optional(dev, "vs");
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get regulator\n");
+
+ return 0;
+}
+
+static int ina4230_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct ina4230_data *ina;
+ struct device *hwmon_dev;
+ int i, ret;
+
+ ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL);
+ if (!ina)
+ return -ENOMEM;
+
+ ina->regmap = devm_regmap_init_i2c(client, &ina4230_regmap_config);
+ if (IS_ERR(ina->regmap))
+ return PTR_ERR(ina->regmap);
+
+ ret = devm_regmap_field_bulk_alloc(dev, ina->regmap, ina->fields,
+ ina4230_reg_fields,
+ ARRAY_SIZE(ina4230_reg_fields));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < INA4230_NUM_CHANNELS; i++) {
+ ina->inputs[i].shunt_resistor = INA4230_RSHUNT_DEFAULT;
+ /* Default for 1mA LSB current measurements */
+ ina->inputs[i].max_expected_current = 32768000;
+ }
+
+ ret = ina4230_probe_from_dt(dev, ina);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Unable to probe from device tree\n");
+
+ /* The driver will be reset, so use reset value */
+ ina->reg_config1 = INA4230_CONFIG_DEFAULT;
+ ina->reg_config2 = 0;
+
+ if (ina->alert_active_high)
+ FIELD_MODIFY(INA4230_CONFIG2_ALERT_POL, &ina->reg_config2, 1);
+
+ /* Disable channels if their inputs are disconnected */
+ for (i = 0; i < INA4230_NUM_CHANNELS; i++) {
+ if (ina->inputs[i].disconnected)
+ ina->reg_config1 &= ~INA4230_CONFIG_CHx_EN(i);
+ }
+
+ ina->pm_dev = dev;
+ dev_set_drvdata(dev, ina);
+
+ /* Enable PM runtime -- status is suspended by default */
+ pm_runtime_enable(ina->pm_dev);
+
+ /* Initialize (resume) the device */
+ for (i = 0; i < INA4230_NUM_CHANNELS; i++) {
+ if (ina->inputs[i].disconnected)
+ continue;
+
+ /* Match the refcount with number of enabled channels */
+ ret = pm_runtime_get_sync(ina->pm_dev);
+ if (ret < 0)
+ goto fail;
+ }
+
+ /* Set calibration values after device resume/reset */
+ for (i = 0; i < INA4230_NUM_CHANNELS; i++) {
+ if (!ina->inputs[i].disconnected) {
+ ret = ina4230_set_calibration(ina, i);
+ if (ret)
+ goto fail;
+ }
+ }
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina,
+ &ina4230_chip_info,
+ NULL);
+ if (IS_ERR(hwmon_dev)) {
+ ret = dev_err_probe(dev, PTR_ERR(hwmon_dev),
+ "Unable to register hwmon device\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ pm_runtime_disable(ina->pm_dev);
+ pm_runtime_set_suspended(ina->pm_dev);
+ /* pm_runtime_put_noidle() for connected channels to balance get_sync */
+ for (i = 0; i < INA4230_NUM_CHANNELS; i++) {
+ if (!ina->inputs[i].disconnected &&
+ ina->reg_config1 & INA4230_CONFIG_CHx_EN(i))
+ pm_runtime_put_noidle(ina->pm_dev);
+ }
+
+ return ret;
+}
+
+static void ina4230_remove(struct i2c_client *client)
+{
+ struct ina4230_data *ina = dev_get_drvdata(&client->dev);
+ int i;
+
+ pm_runtime_disable(ina->pm_dev);
+ pm_runtime_set_suspended(ina->pm_dev);
+
+ /* pm_runtime_put_noidle() for connected channels to balance get_sync */
+ for (i = 0; i < INA4230_NUM_CHANNELS; i++) {
+ if (!ina->inputs[i].disconnected &&
+ ina->reg_config1 & INA4230_CONFIG_CHx_EN(i))
+ pm_runtime_put_noidle(ina->pm_dev);
+ }
+}
+
+static int ina4230_suspend(struct device *dev)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ int ret;
+
+ /* Save config register value and enable cache-only */
+ ret = regmap_read(ina->regmap, INA4230_CONFIG1, &ina->reg_config1);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(ina->regmap, true);
+ regcache_mark_dirty(ina->regmap);
+
+ return 0;
+}
+
+static int ina4230_resume(struct device *dev)
+{
+ struct ina4230_data *ina = dev_get_drvdata(dev);
+ int ret;
+
+ regcache_cache_only(ina->regmap, false);
+
+ /* Software reset the chip */
+ ret = regmap_field_write(ina->fields[F_RST], true);
+ if (ret) {
+ dev_err(dev, "Unable to reset device\n");
+ return ret;
+ }
+
+ /* Restore cached register values to hardware */
+ ret = regcache_sync(ina->regmap);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ina4230_pm, ina4230_suspend, ina4230_resume,
+ NULL);
+
+static const struct of_device_id ina4230_of_match_table[] = {
+ { .compatible = "ti,ina4230", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ina4230_of_match_table);
+
+static const struct i2c_device_id ina4230_ids[] = {
+ { "ina4230" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, ina4230_ids);
+
+static struct i2c_driver ina4230_i2c_driver = {
+ .probe = ina4230_probe,
+ .remove = ina4230_remove,
+ .driver = {
+ .name = INA4230_DRIVER_NAME,
+ .of_match_table = ina4230_of_match_table,
+ .pm = pm_ptr(&ina4230_pm),
+ },
+ .id_table = ina4230_ids,
+};
+module_i2c_driver(ina4230_i2c_driver);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@flipper.net>");
+MODULE_DESCRIPTION("Texas Instruments INA4230 HWMon Driver");
+MODULE_LICENSE("GPL");
--
2.52.0
^ permalink raw reply related
* [PATCH v5 1/2] dt-bindings: hwmon: Add TI INA4230 4-channel I2C power monitor
From: Alexey Charkov @ 2026-03-30 15:14 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-hwmon, devicetree, linux-kernel, Alexey Charkov,
Krzysztof Kozlowski
In-Reply-To: <20260330-ina4230-v5-0-eeb322d95b3a@flipper.net>
Add TI INA4230, which is a 48V 4-channel 16-bit I2C-based
current/voltage/power/energy monitor with alert function.
Link: https://www.ti.com/product/INA4230
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
.../devicetree/bindings/hwmon/ti,ina4230.yaml | 134 +++++++++++++++++++++
MAINTAINERS | 6 +
2 files changed, 140 insertions(+)
diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina4230.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina4230.yaml
new file mode 100644
index 000000000000..d9b5f9857249
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/ti,ina4230.yaml
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/ti,ina4230.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments INA4230 quad-channel power monitors
+
+maintainers:
+ - Alexey Charkov <alchark@flipper.net>
+
+description: |
+ The INA4230 is a 48V quad-channel 16-bit current, voltage, power and energy
+ monitor with an I2C interface.
+
+ Datasheet:
+ https://www.ti.com/product/INA4230
+
+properties:
+ compatible:
+ enum:
+ - ti,ina4230
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ description: Required only if a child node is present.
+ const: 1
+
+ "#size-cells":
+ description: Required only if a child node is present.
+ const: 0
+
+ vs-supply:
+ description: phandle to the regulator that provides the VS supply typically
+ in range from 1.7 V to 5.5 V.
+
+ ti,alert-polarity-active-high:
+ description: Alert pin is asserted based on the value of Alert polarity Bit
+ of the CONFIG2 register. Default value is 0, for which the alert pin
+ toggles from high to low during faults. When this property is set, the
+ corresponding register bit is set to 1, and the alert pin toggles from
+ low to high during faults.
+ $ref: /schemas/types.yaml#/definitions/flag
+
+patternProperties:
+ "^input@[0-3]$":
+ description: Optional subnodes for four input channels. Each subnode
+ describes one input channel. Input channels default to enabled in the
+ chip. Unless channels are explicitly disabled in device-tree, input
+ channels will be enabled.
+ type: object
+ additionalProperties: false
+ properties:
+ reg:
+ description: Must be 0, 1, 2 or 3, corresponding to the IN1, IN2, IN3
+ or IN4 ports of the INA4230, respectively.
+ enum: [ 0, 1, 2, 3 ]
+
+ label:
+ description: name of the input source
+
+ shunt-resistor-micro-ohms:
+ description: shunt resistor value in micro-Ohm
+
+ ti,maximum-expected-current-microamp:
+ description: |
+ This value indicates the maximum current in microamps that you can
+ expect to measure with ina4230 in your circuit.
+
+ This value will be used to calculate the Current_LSB to maximize the
+ available precision while ensuring your expected maximum current fits
+ within the chip's ADC range. It will also enable built-in shunt gain
+ to increase ADC granularity by a factor of 4 if the provided maximum
+ current / shunt resistance combination does not produce more than
+ 20.48 mV drop at the shunt.
+ minimum: 32768
+ maximum: 2147483647
+ default: 32768000
+
+ required:
+ - reg
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: hwmon-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ power-sensor@44 {
+ compatible = "ti,ina4230";
+ reg = <0x44>;
+ vs-supply = <&vdd_3v0>;
+ ti,alert-polarity-active-high;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ input@0 {
+ reg = <0x0>;
+ /*
+ * Input channels are enabled by default in the device and so
+ * to disable, must be explicitly disabled in device-tree.
+ */
+ status = "disabled";
+ };
+
+ input@1 {
+ reg = <0x1>;
+ shunt-resistor-micro-ohms = <50000>;
+ ti,maximum-expected-current-microamp = <300000>;
+ };
+
+ input@2 {
+ reg = <0x2>;
+ label = "VDD_5V";
+ shunt-resistor-micro-ohms = <10000>;
+ ti,maximum-expected-current-microamp = <5000000>;
+ };
+
+ input@3 {
+ reg = <0x3>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index ff935e197c21..acfa0b0585a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12574,6 +12574,12 @@ S: Maintained
F: Documentation/hwmon/ina233.rst
F: drivers/hwmon/pmbus/ina233.c
+INA4230 HWMON DRIVER
+M: Alexey Charkov <alchark@flipper.net>
+L: linux-hwmon@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/hwmon/ti,ina4230.yaml
+
INDEX OF FURTHER KERNEL DOCUMENTATION
M: Carlos Bilbao <carlos.bilbao@kernel.org>
S: Maintained
--
2.52.0
^ permalink raw reply related
* [PATCH v5 0/2] Add support for Texas Instruments INA4230 power monitor
From: Alexey Charkov @ 2026-03-30 15:14 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-hwmon, devicetree, linux-kernel, Alexey Charkov,
Krzysztof Kozlowski
TI INA4230 is a 4-channel power monitor with I2C interface, similar in
operation to INA3221 (3-channel) and INA219 (single-channel) but with
a different register layout, different alerting mechanism and slightly
different support for directly reading calculated current/power/energy
values (pre-multiplied by the device itself and needing only to be scaled
by the driver depending on its selected LSB unit values).
In this initial implementation, the driver supports reading voltage,
current, power and energy values, but does not yet support alerts, which
can be added separately if needed. Also the overflows during hardware
calculations are not yet handled, nor is the support for the device's
internal 32-bit energy counter reset.
An example device tree using this binding and driver is available at [1]
(not currently upstreamed, as the device in question is in engineering
phase and not yet publicly available)
[1] https://github.com/flipperdevices/flipper-linux-kernel/blob/flipper-devel/arch/arm64/boot/dts/rockchip/rk3576-flipper-one-rev-f0b0c1.dts
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
Changes in v5:
- Reworded per-channel subnodes description in the binding for clarity (Sashiko)
- NB: Sashiko's suggestion to allow interrupts in the binding sounds premature,
as the alerts mechanism is not implemented yet and there are no known users
to test it. If anyone has hardware with the alert pins wired to an interrupt
line - please shout and we can test/extend it together
- Avoid division by zero when setting the conversion time with all inputs
disabled (Sashiko)
- Added the missed HWMON_I_ENABLE bits (Sashiko)
- Dropped extra sysfs attributes for reading/writing shunt values, as the
implementation was potentially racy and it's unlikely anyone would resolder
the shunts on a running system (Sashiko)
- Skip pm_runtime_put_noidle() for disabled (not just disconnected) channels
in remove and probe error path to avoid refcount underflow (Sashiko)
- Mark CONFIG2 register as volatile, as the reset bits in it are self-clearing
- NB: Sashiko's inquiry about the update interval being underreported due to
not accounting for the number of averaging samples: no, the hardware still
reports updates after each channels * (vbus_ct + vsh_ct), but the reported
value changes slowly due to the averaging
- NB: Sashiko's inquiry about regmap_noinc_read(): same as Guenter's AI
feedback. No, it doesn't break the byte order, as it uses byte-sized reads
- NB: Sashiko's inquiry about potential falling of ina->reg_config1 out of sync
with the hardware upon failed regmap_write() calls: yes, but it will be
written at the next successful write call, so the worst that can happen is
the averaging / conversion time can be wrong for a while. And it will return
a failed status for the failed write call too, so no big deal.
- NB: Sashiko's inquiry about reg_config1 not being written out during probe:
it is written out when the device is runtime-resumed as the refcount gets
incremented during the probe function
- Link to v4: https://lore.kernel.org/r/20260326-ina4230-v4-0-c1e312c09de7@flipper.net
Changes in v4:
- Aligned the maximum value of ti,maximum-expected-current-microamp property
in the binding with the one expected by the driver (Guenter Roeck)
"2147A ought to be enough for anybody (c)"
- Actually requested the optional vs-supply regulator in the driver (Guenter Roeck)
- Program the ALERT_POL bit according to the value of ti,alert-polarity-active-high
even though the alerts themselves are not yet implemented (Guenter Roeck)
- Added a check for manually disabled channels in the is_enabled() function to
avoid reading invalid data from them (Guenter Roeck)
- Dropped support for the single-shot mode as its operation is not clearly
documented in the datasheet and there is no pressing need to support it (Guenter Roeck)
- NB: AI feedback regarding regmap_noinc_read() producing incorrect byte order on LE
hosts is incorrect, as its implementation does a byte-wise read and doesn't care
about the regmap value width or endianness flags, so it produces a 4-byte output
buffer in the same byte order as the device returns, which is BE in this case
- NB: AI feedback regarding fail-path pm_runtime_put_noidle() potentially being
unbalanced if the probe loop failed early is technically correct but practically
irrelevant, as the driver will simply fail to load, and the usage count won't
decrease beyond zero anyway. The alternatives are cumbersome for no real benefit
- Link to v3: https://lore.kernel.org/r/20260310-ina4230-v3-0-06ab3a77c570@flipper.net
Changes in v3:
- Updated the description of the ti,maximum-expected-current-microamp property
in the binding to clarify how it is used, and drop the irrelevant mention of
the PMbus (Guenter Roeck)
- Use div64_u64() instead of do_div() for the final division in the calibration value
calculation to avoid overflows in the denominator (Guenter Roeck)
- Avoid overflow while scaling the voltage values on 32-bit platforms (Guenter Roeck)
- Use regmap_noinc_read() instead of regmap_raw_read() for reading the energy values
to ensure that the regmap / bus driver don't wander off to adjacent registers
during the read operation (on INA4230 the whole 32 bits should be read from
the same register offset) (Guenter Roeck)
- Remove redundant call to ina4230_set_calibration() in the current read path,
as the calibration value is already set when enabling the channel and restored
across PM changes via regcache_sync() (Guenter Roeck)
- Add missing write_enable() function to make hwmon_in_enable writes work as
advertised in is_visible() (Guenter Roeck)
- Add a check for disabled channels before calling pm_runtime_put_noidle() on them
to avoid refcount underflow due to imbalanced get_sync/put_noidle calls (Guenter Roeck)
- Dropped unused include of linux/debugfs.h
- Add missing return checks on regmap_write() calls
- uO -> uOhm in the error message to avoid confusion
- Move probe-time calibration after enabling runtime PM to avoid it being reverted
by the PM sync
- Link to v2: https://lore.kernel.org/r/20260302-ina4230-v2-0-55b49d19d2ab@flipper.net
Changes in v2:
- Replace u64/u64 division with do_div() (kernel test robot)
- Add an example with ti,maximum-expected-current-microamp property in
bindings (Krzysztof Kozlowski)
- Include the newly added binding in MAINTAINERS file (Krzysztof Kozlowski)
- Use dev_err_probe() where appropriate in the driver (Krzysztof Kozlowski)
- Switch to devm_regmap_field_bulk_alloc() instead of an open-coded loop
- Add a bounds check for the calculated calibration value,
and a corresponding error message
- Link to v1: https://lore.kernel.org/r/20260225-ina4230-v1-0-92b1de981d46@flipper.net
---
Alexey Charkov (2):
dt-bindings: hwmon: Add TI INA4230 4-channel I2C power monitor
hwmon: Add support for TI INA4230 power monitor
.../devicetree/bindings/hwmon/ti,ina4230.yaml | 134 +++
MAINTAINERS | 7 +
drivers/hwmon/Kconfig | 11 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/ina4230.c | 986 +++++++++++++++++++++
5 files changed, 1139 insertions(+)
---
base-commit: 3b058d1aeeeff27a7289529c4944291613b364e9
change-id: 20260219-ina4230-74a02409153d
Best regards,
--
Alexey Charkov <alchark@flipper.net>
^ permalink raw reply
* Re: [PATCH 4/8] drm/bridge: dw-hdmi: document the output_port field
From: Luca Ceresoli @ 2026-03-30 15:10 UTC (permalink / raw)
To: Damon Ding, Liu Ying, Marek Vasut, Stefan Agner,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Rob Herring,
Saravana Kannan
Cc: Kory Maincent (TI.com), Hervé Codina, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, imx, linux-arm-kernel, linux-kernel,
devicetree, Adam Ford, Alexander Stein, Anson Huang,
Christopher Obbard, Daniel Scally, Emanuele Ghidoli,
Fabio Estevam, Francesco Dolcini, Frieder Schrempf, Gilles Talis,
Goran Rađenović, Heiko Schocher, Joao Paulo Goncalves,
Josua Mayer, Kieran Bingham, Marco Felsch, Martyn Welch,
Oleksij Rempel, Peng Fan, Philippe Schenker, Richard Hu,
Shengjiu Wang, Stefan Eichenberger, Vitor Soares
In-Reply-To: <4396e94d-7b88-4599-a938-3c1932a2f9cb@rock-chips.com>
Hello Damon,
On Mon Mar 30, 2026 at 3:13 AM CEST, Damon Ding wrote:
>>>>> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
>>>>> index 336f062e1f9d..45f6ba1a8ee1 100644
>>>>> --- a/include/drm/bridge/dw_hdmi.h
>>>>> +++ b/include/drm/bridge/dw_hdmi.h
>>>>> @@ -126,6 +126,11 @@ struct dw_hdmi_phy_ops {
>>>>> struct dw_hdmi_plat_data {
>>>>> struct regmap *regm;
>>>>>
>>>>> + /*
>>>>> + * The HDMI output port number (which must be 1) if it is described
>>>>
>>>> I'd rephrase:
>>>> The HDMI output port number must be 1 ...
>>>>
>>>
>>> Yes, the output port number should be 1, but I found that the output
>>> port number in the Rockchip-side dw-hdmi driver remains 0.
>>
>> Really? I checked all the bindings in
>> Documentation/devicetree/bindings/display/rockchip/*hdmi* and all mention
>> port@1 as the output port number. Can you point to code using port@0 as the
>> output port?
>>
>> Should it be true, that would be unfortunate because the output_port
>> variable does not handle this case. It's used as a sort of bool-or-int
>> variable:
>>
>> * as a bool [0] to find out whether the DT is supposed to describe the
>> output port
>> * as an integer to tell the port number to parse in DT [1]
>>
>> So saying "please parse port 0" is impossible.
>>
>> [0] https://elixir.bootlin.com/linux/v7.0-rc5/source/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c#L3310
>> [1] https://elixir.bootlin.com/linux/v7.0-rc5/source/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c#L3315
>>
>
> Aha, my description might be a little misleading. The
> &dw_hdmi_plat_data.output_port is 0 on the Rockchip side, so the next
> bridge will not be parsed for it.
>
> Then I think the &dw_hdmi_plat_data.output_port should be 1, as this
> helps support the hdmi-connector and other bridge chips.
Ah, OK, that's all clear now.
> BTW: The Rockchip side dw-hdmi patches for bridge connector support will
> be updated as a follow-up to your patch series. :-)
Great! Don't forget to Cc me.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH 10/16] clk: Add support for clock nexus dt bindings
From: Brian Masney @ 2026-03-30 15:09 UTC (permalink / raw)
To: Miquel Raynal (Schneider Electric)
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm, Thomas Petazzoni,
Pascal EBERHARD, Wolfram Sang, linux-clk, devicetree,
linux-kernel, linux-crypto, linux-renesas-soc, Herve Codina
In-Reply-To: <20260327-schneider-v7-0-rc1-crypto-v1-10-5e6ff7853994@bootlin.com>
On Fri, Mar 27, 2026 at 09:09:32PM +0100, Miquel Raynal (Schneider Electric) wrote:
> A nexus node is some kind of parent device abstracting the outer
> connections. They are particularly useful for describing connectors-like
> interfaces but not only. Certain IP blocks will typically include inner
> blocks and distribute resources to them.
>
> In the case of clocks, there is already the concept of clock controller,
> but this usually indicates some kind of control over the said clock,
> ie. gate or rate control. When there is none of this, an existing
> approach is to reference the upper clock, which is wrong from a hardware
> point of view.
>
> Nexus nodes are already part of the device-tree specification and clocks
> are already mentioned:
> https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter2-devicetree-basics.rst#nexus-nodes-and-specifier-mapping
>
> Following the introductions of nexus nodes support for interrupts, gpios
> and pwms, here is the same logic applied again to the clk subsystem,
> just by transitioning from of_parse_phandle_with_args() to
> of_parse_phandle_with_args_map():
>
> * Nexus OF support:
> commit bd6f2fd5a1d5 ("of: Support parsing phandle argument lists through a nexus node")
> * GPIO adoption:
> commit c11e6f0f04db ("gpio: Support gpio nexus dt bindings")
> * PWM adoption:
> commit e71e46a6f19c ("pwm: Add support for pwm nexus dt bindings")
>
> Expected Nexus properties supported:
> - clock-map: maps inner clocks to inlet clocks,
> - clock-map-mask: specifier cell(s) which will be remapped,
> - clock-map-pass-thru: specifier cell(s) not used for remapping,
> forwarded as-is.
>
> In my own usage I had to deal with controllers where clock-map-mask and
> clock-map-pass-thru were not relevant, but here is a made up example
> showing how all these properties could go together:
>
> Example:
> soc_clk: clock-controller {
> #clock-cells = <2>;
> };
>
> container: container {
> #clock-cells = <2>;
> clock-map = <0 0 &soc_clk 2 0>,
> <1 0 &soc_clk 6 0>;
> clock-map-mask = <0xffffffff 0x0>;
> clock-map-pass-thru = <0x0 0xffffffff>;
>
> child-device {
> clocks = <&container 1 0>;
> /* This is equivalent to <&soc_clk 6 0> */
> };
> };
>
> The child device does not need to know about the outer implementation,
> and only knows about what the nexus provides. The nexus acts as a
> pass-through, with no extra control.
>
> Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
> Reviewed-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Brian Masney <bmasney@redhat.com>
^ permalink raw reply
* Re: [PATCH 0/4] ASoC: Add support for GPIOs driven amplifiers
From: Mark Brown @ 2026-03-30 15:08 UTC (permalink / raw)
To: Herve Codina
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Saravana Kannan, Jaroslav Kysela, Takashi Iwai, linux-sound,
devicetree, linux-kernel, Christophe Leroy, Thomas Petazzoni
In-Reply-To: <20260330101610.57942-1-herve.codina@bootlin.com>
[-- Attachment #1: Type: text/plain, Size: 431 bytes --]
On Mon, Mar 30, 2026 at 12:16:04PM +0200, Herve Codina wrote:
> On some embedded system boards, audio amplifiers are designed using
> discrete components such as op-amp, several resistors and switches to
> either adjust the gain (switching resistors) or fully switch the
> audio signal path (mute and/or bypass features).
>
> Those switches are usually driven by simple GPIOs.
This sounds a lot like simple-amplifier.c?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] arm64: dts: qcom: Add Motorola edge 30 (dubai) DTS
From: Val Packett @ 2026-03-30 15:03 UTC (permalink / raw)
To: Konrad Dybcio, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kees Cook, Tony Luck,
Guilherme G. Piccoli
Cc: linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <5c0747dc-f0de-4b78-b0fd-8f6a6690e86c@oss.qualcomm.com>
On 3/30/26 7:03 AM, Konrad Dybcio wrote:
> On 3/29/26 12:16 PM, Val Packett wrote:
>> The Motorola edge 30 is a smartphone released in 2022.
>>
>> This commit has the following features working:
>> - Display (simplefb)
>> - Touchscreen
>> - Power and volume buttons
>> - Storage (UFS 3.1)
>> - Battery (ADSP battmgr)
>> - USB (Type-C, 2.0, dual-role)
>> - Wi-Fi and Bluetooth (WCN6750 hw1.0)
>>
>> Signed-off-by: Val Packett <val@packett.cool>
>> ---
> [...]
>
>> +/ {
>> + model = "Motorola edge 30";
> nit: Google tells me the 'e' in 'Edge' is uppercase
They do the lowercase thing a lot in the marketing materials but not
consistently. I guess it would make sense to ignore that and make it
uppercase, sure.
> [...]
>
>> + framebuffer0: framebuffer@e1000000 {
>> + compatible = "simple-framebuffer";
>> + reg = <0x0 0xe1000000 0x0 (1080 * 2400 * 4)>;
> Let's drop reg and use the memory-region binding (also drop unit address)
How come no one told be about memory-region for simplefb before? :D Ack
> [...]
>> + ports {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + port@0 {
>> + reg = <0>;
>> +
>> + pmic_glink_hs_in: endpoint {
>> + remote-endpoint = <&usb_1_dwc3_hs>;
>> + };
>> + };
>> +
>> + port@1 {
>> + reg = <1>;
> SBU would be @2
I was wondering about this, now I see it is specified in the bindings..
Looks like many other dts should be fixed too.
>> + cont-splash@e1000000 {
> framebuffer@
>
> [...]
>
>> + thermal-zones {
>> + cam-flash-thermal {
>> + polling-delay-passive = <0>;
> that's the default setting, you may drop all polling-delay(-passive) = <0>
ack
> [...]
>
>> +&usb_1 {
>> + /* USB 2.0 only */
>> + qcom,select-utmi-as-pipe-clk;
>> + maximum-speed = "high-speed";
>> +
>> + /* Remove USB3 phy */
>> + phys = <&usb_1_hsphy>;
>> + phy-names = "usb2-phy";
> Is it really not wired up in hw, or do you perhaps have a fake cable?
I didn't even try testing it myself since not even all flagships have
USB3 routed these days (hello oneplus) and this is a cheaper
upper-mid-range phone.
USB0_{SS_*,DP_*} are actually NC on the schematic,
and in downstream dts there is maximum-speed = "high-speed" and usb-phy
= hsphy + nop.
~val
^ 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