* [PATCH] dt-bindings: clock: renesas,versaclock7: Update maintainer
From: Biju @ 2026-06-23 16:20 UTC (permalink / raw)
To: Geert Uytterhoeven, Alex Helms, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Magnus Damm
Cc: Biju Das, Brian Masney, linux-renesas-soc, linux-clk, devicetree,
linux-kernel, Prabhakar Mahadev Lad, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
Alex's email is bouncing. Update the maintainers list with my contact
details to take over the schema maintenance.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
Ref [1]
[1] https://lore.kernel.org/all/ajqWevofEJ3fv856@redhat.com/
---
.../devicetree/bindings/clock/renesas,versaclock7.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml b/Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml
index b339f1f9f072..990d287d0a90 100644
--- a/Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml
+++ b/Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas Versaclock7 Programmable Clock
maintainers:
- - Alex Helms <alexander.helms.jy@renesas.com>
+ - Biju Das <biju.das.jz@bp.renesas.com>
description: |
Renesas Versaclock7 is a family of configurable clock generator and
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 2/2] dt-bindings: iio: dac: Add DAC8163
From: sashiko-bot @ 2026-06-23 16:18 UTC (permalink / raw)
To: Lukas Metz; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260623-dac8163-work-v1-2-5b508158faa0@gmx.net>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The schema does not properly enforce mutual exclusivity between `ti,internal-ref` and `vref-supply`.
--
commit c91535ac2ae4b61ce673dbacd2798488e644cdb0
Author: Lukas Metz <lukas.metz@gmx.net>
dt-bindings: iio: dac: Add DAC8163
This commit adds the device tree binding schema for the Texas Instruments
DAC8163 family of digital-to-analog converters.
> diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
> new file mode 100644
> index 0000000000000..bb4bad3893235
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
[ ... ]
> +required:
> + - compatible
> + - reg
> +
> +allOf:
> + - $ref: /schemas/spi/spi-peripheral-props.yaml#
> + - if:
> + not:
> + required:
> + - ti,internal-ref
> + then:
> + required:
> + - vref-supply
[Severity: Low]
Does this schema properly enforce mutual exclusivity between the internal
reference and an external supply?
If a devicetree incorrectly defines both the "ti,internal-ref" flag and a
"vref-supply" property, it seems this block will silently pass validation.
While it requires "vref-supply" when "ti,internal-ref" is absent, it doesn't
appear to forbid "vref-supply" (e.g., via `properties: { vref-supply: false }`)
when "ti,internal-ref" is present.
> +
> +unevaluatedProperties: false
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623-dac8163-work-v1-0-5b508158faa0@gmx.net?part=2
^ permalink raw reply
* Re: [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163
From: sashiko-bot @ 2026-06-23 16:18 UTC (permalink / raw)
To: Lukas Metz; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260623-dac8163-work-v1-1-5b508158faa0@gmx.net>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The SPI transfer buffer `tx` is allocated on the stack, which is not DMA-safe and violates SPI subsystem requirements.
- [High] The pointer returned by `spi_get_device_match_data()` is unconditionally dereferenced without a NULL check.
- [Medium] The IIO scale attribute calculation ignores the hardware gain when the internal reference is used, returning an incorrect scale factor.
--
commit db89a9af22e26ad0341eb42f1659ed8a2fad0e51
Author: Lukas Metz <lukas.metz@gmx.net>
iio: dac: dac8163: Add driver for DAC8163
This commit adds a new driver for the Texas Instruments DAC756x, DAC816x,
and DAC856x series devices. These are low-power, voltage-output,
dual-channel DACs with up to 16 bits of resolution.
> diff --git a/drivers/iio/dac/ti-dac8163.c b/drivers/iio/dac/ti-dac8163.c
> new file mode 100644
> index 0000000000000..84a9dfb5347d6
> --- /dev/null
> +++ b/drivers/iio/dac/ti-dac8163.c
[ ... ]
> +static int dacxx6x_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + struct dacxx6x_state *st;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
[ ... ]
> + case IIO_CHAN_INFO_SCALE:
> + st = iio_priv(indio_dev);
> + *val = st->vref_uv / MILLI; /* vref in mV */
> + *val2 = chan->scan_type.realbits;
[Severity: Medium]
Does this scale calculation account for the hardware gain when using the
internal reference?
When st->internal_ref is true, the internal reference is 2.5V, but these
devices typically have a default internal gain of 2, making the full-scale
voltage 5V.
Should the gain multiplier be factored into the vref_uv calculation before
exposing the scale to userspace?
> + return IIO_VAL_FRACTIONAL_LOG2;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int dacxx6x_write_reg(struct dacxx6x_state *st, int reg, int addr,
> + unsigned int val)
> +{
> + u8 tx[3];
> +
> + tx[0] = COMMAND_SET(reg, addr);
> + tx[1] = (val >> 8) & 0xff;
> + tx[2] = val & 0xff;
> +
> + return spi_write(st->spi, tx, sizeof(tx));
[Severity: High]
Is it safe to pass a stack-allocated buffer to spi_write() here?
Since spi_write() maps the provided buffer for DMA, passing a stack
variable can lead to invalid physical address mappings or memory corruption,
especially on systems with CONFIG_VMAP_STACK enabled.
Could the tx buffer be moved into the dacxx6x_state structure, protected by
the lock, and properly cacheline-aligned to ensure it is DMA-safe?
> +}
[ ... ]
> +static int dacxx6x_probe(struct spi_device *spi)
> +{
[ ... ]
> + ret = dacxx6x_write_reg(st, CMD_SEL_REFERENCE, 0,
> + FIELD_PREP(VOLTAGE_REFERENCE_MASK, st->internal_ref));
> +
> + if (ret < 0)
> + goto err;
> +
> + info = spi_get_device_match_data(spi);
> +
> + indio_dev->name = info->name;
[Severity: High]
Can spi_get_device_match_data() return NULL here if the device is
instantiated from userspace via sysfs (using driver_override and bind)
with a name that doesn't match the ID tables?
If it does return NULL, the subsequent dereference of info->name will cause
a kernel oops. Is a NULL check needed before accessing info?
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->info = &dacxx6x_iio_info;
> + indio_dev->channels = info->channels;
> + indio_dev->num_channels = 2;
> +
> + ret = iio_device_register(indio_dev);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623-dac8163-work-v1-0-5b508158faa0@gmx.net?part=1
^ permalink raw reply
* Re: [PATCH v2 2/3] iio: health: add MAX86150 ECG and PPG biosensor driver
From: sashiko-bot @ 2026-06-23 16:12 UTC (permalink / raw)
To: Md Shofiqul Islam; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260623155556.13701-3-shofiqtest@gmail.com>
Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [High] A stack-allocated buffer is passed to regmap_noinc_read(), which violates DMA mapping rules and can cause memory corruption if the I2C host controller uses DMA.
- [High] Redundant manual invocation of iio_trigger_put via a devm action causes a double put and a use-after-free when the IIO device is released.
- [Medium] The driver exposes unimplemented scale attributes to userspace, which unconditionally return an error.
- [Medium] The FIFO drain loop assigns incorrect, heavily clustered timestamps to buffered samples, destroying time-domain information.
- [Medium] The driver incorrectly uses devm_regulator_get_enable for optional supplies, erroneously assuming it gracefully handles missing regulators.
- [Medium] Uninitialized padding bytes in data->buf leak previous sensor readings to userspace when fewer than 3 channels are enabled.
- [Medium] Missing FIFO flush when enabling the triggered buffer leaves stale data to be processed immediately.
- [Medium] The driver calls iio_trigger_get() on its own trigger during probe, permanently elevating its own module reference count and preventing module unload.
--
commit 28ae0a6a433f8b0e50a4557f62c8f075a8c69870
Author: Md Shofiqul Islam <shofiqtest@gmail.com>
iio: health: add MAX86150 ECG and PPG biosensor driver
This commit adds a driver for the MAX86150 combined ECG and PPG biosensor.
It exposes three IIO channels and supports the IIO triggered buffer path for
continuous data capture.
> diff --git a/drivers/iio/health/max86150.c b/drivers/iio/health/max86150.c
> new file mode 100755
> index 0000000000000..70c51ccb4672b
> --- /dev/null
> +++ b/drivers/iio/health/max86150.c
[ ... ]
> +static const struct iio_chan_spec max86150_channels[] = {
> + {
> + /* PPG Red LED - optical intensity, 19-bit unsigned */
> + .type = IIO_INTENSITY,
> + .modified = 1,
> + .channel2 = IIO_MOD_LIGHT_RED,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE),
[Severity: Medium]
Will this cause sysfs reads for the scale attribute to always fail?
The driver exposes IIO_CHAN_INFO_SCALE for all channels here, but
max86150_read_raw() unconditionally returns -EINVAL for it. This breaks
the IIO ABI contract and might cause userspace tools to fail when discovering
channel properties.
[ ... ]
> +static int max86150_read_one_sample(struct max86150_data *data,
> + u32 *ppg_red, u32 *ppg_ir, s32 *ecg)
> +{
> + u8 buf[MAX86150_SAMPLE_BYTES]; /* 9 bytes */
> + int ret;
> +
> + ret = regmap_noinc_read(data->regmap, MAX86150_REG_FIFO_DATA,
> + buf, sizeof(buf));
[Severity: High]
Can this cause memory corruption if the I2C host controller uses DMA?
The buf array is allocated on the stack and passed directly to
regmap_noinc_read(). Since the regmap I2C implementation does not internally
bounce buffers, this passes a stack buffer directly to i2c_transfer(). When
CONFIG_VMAP_STACK is enabled, stack buffers are not physically contiguous and
are not DMA-safe.
[ ... ]
> + case IIO_CHAN_INFO_SCALE:
> + /*
> + * TODO: return the hardware scale factor based on the
> + * configured PPG ADC range (PPG_ADC_RGE) and ECG PGA gain
> + * (ECG_PGA_GAIN). For PPG, scale is nA/LSB; for ECG, uV/LSB.
> + */
> + return -EINVAL;
[Severity: Medium]
Is it intentional to advertise the scale attribute in the channel spec but
unconditionally reject it here?
This will cause reads of the sysfs attribute to always fail.
[ ... ]
> +static int max86150_set_trigger_state(struct iio_trigger *trig, bool state)
> +{
> + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> + struct max86150_data *data = iio_priv(indio_dev);
> + unsigned int mask = state ? MAX86150_INT_A_FULL : 0;
> +
> + return regmap_write(data->regmap, MAX86150_REG_INT_ENABLE1, mask);
[Severity: Medium]
Does the hardware FIFO need to be flushed before unmasking the interrupt here?
Since the device continuously acquires data into the FIFO starting from
probe(), the FIFO might already be full when userspace enables the triggered
buffer. This would cause the interrupt to assert immediately and drain
extremely stale samples into the new capture session.
[ ... ]
> + /*
> + * Pack only active channels at consecutive positions [0..j-1].
> + * iio_push_to_buffers_with_timestamp() uses scan_bytes (which
> + * accounts for the active channel count) to place the timestamp,
> + * so static indexing would misplace it when fewer than 3
> + * channels are enabled.
> + */
> + j = 0;
> + if (test_bit(MAX86150_IDX_PPG_RED, idev->active_scan_mask))
> + data->buf[j++] = ppg_red;
> + if (test_bit(MAX86150_IDX_PPG_IR, idev->active_scan_mask))
> + data->buf[j++] = ppg_ir;
> + if (test_bit(MAX86150_IDX_ECG, idev->active_scan_mask))
> + data->buf[j++] = ecg;
[Severity: Medium]
Does this sequentially pack active channels without zeroing the entire buffer
first, leaking previous sensor readings?
If the active channel count is reduced, unused array elements in data->buf
retain stale data from previous captures. iio_push_to_buffers_with_timestamp()
then copies the entire memory block up to the timestamp offset, exposing the
uninitialized padding bytes to userspace.
> +
> + iio_push_to_buffers_with_timestamp(idev, data->buf,
> + iio_get_time_ns(idev));
[Severity: Medium]
Will this assign the same batch execution time to all historical samples
pulled from the FIFO?
Inside the loop, fetching the current time for every sample means up to 32
samples will receive nearly identical timestamps separated only by I2C read
latencies. This misrepresents the true sample capture period (e.g., 100 Hz).
Should the driver backdate timestamps using the top-half IRQ timestamp
(pf->timestamp) instead?
[ ... ]
> + /*
> + * Enable power supplies before any I2C access. Both are optional
> + * in the device tree (devm_regulator_get_enable returns 0 when the
> + * supply is not described), but must be present and stable on real
> + * hardware before the first register read.
> + */
> + ret = devm_regulator_get_enable(&client->dev, "vdd");
[Severity: Medium]
Will this cause the probe to fail on boards where the regulator is legitimately
missing?
The comment indicates the supply is optional and assumes this API returns 0
when it is not described. However, devm_regulator_get_enable() only returns 0
for missing regulators if the system provides a dummy regulator. Otherwise, it
returns -ENODEV, fatally aborting the probe. Should this use
devm_regulator_get_enable_optional() instead?
[ ... ]
> + ret = devm_iio_trigger_register(&client->dev, data->trig);
> + if (ret)
> + return dev_err_probe(&client->dev, ret,
> + "Cannot register trigger\n");
> +
> + indio_dev->trig = iio_trigger_get(data->trig);
[Severity: Medium]
Does this take a circular reference on the driver's own module?
Calling iio_trigger_get() on a trigger owned by this module increments the
module reference count during probe(). The rmmod command will then refuse to
unload the module because the reference count will never drop to 0, permanently
pinning it in memory.
> + ret = devm_add_action_or_reset(&client->dev,
> + max86150_trigger_put,
> + data->trig);
[Severity: High]
Can this cause a double-put and a use-after-free when the IIO device is
released?
The IIO core automatically handles releasing the trigger during device
unregistration via iio_device_unregister_trigger_consumer() which implicitly
calls iio_trigger_put(). Because devm actions run subsequently,
max86150_trigger_put() drops the reference a second time, resulting in a
use-after-free of the trigger object.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623155556.13701-1-shofiqtest@gmail.com?part=2
^ permalink raw reply
* Re: [PATCH v14 4/4] crypto: spacc - Add SPAcc Kconfig and Makefile
From: Julian Braha @ 2026-06-23 16:10 UTC (permalink / raw)
To: Pavitrakumar Managutte, linux-crypto, linux-kernel, devicetree,
herbert, robh
Cc: krzk, conor+dt, Ruud.Derwig, rbannerm, manjunath.hadli, adityak,
navami.telsang, bhoomikak
In-Reply-To: <20260619144558.1868995-5-pavitrakumarm@vayavyalabs.com>
Hi Pavitrakumar,
On 6/19/26 15:45, Pavitrakumar Managutte wrote:
> diff --git a/drivers/crypto/dwc-spacc/Kconfig b/drivers/crypto/dwc-spacc/Kconfig
> new file mode 100644
> index 0000000000000..b253f8dc539c1
> --- /dev/null
> +++ b/drivers/crypto/dwc-spacc/Kconfig
> @@ -0,0 +1,87 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +config CRYPTO_DEV_SPACC
> + tristate "Support for dwc_spacc Security Protocol Accelerator"
> + depends on HAS_DMA
> + select CRYPTO_ENGINE
> + default n
> +
> + help
> + This enables support for SPAcc Hardware Accelerator.
> +
> +config CRYPTO_DEV_SPACC_HASH
> + bool "Enable HASH functionality"
> + depends on CRYPTO_DEV_SPACC
> + default y
> + select CRYPTO_HASH
> + select CRYPTO_SHA1
> + select CRYPTO_MD5
> + select CRYPTO_SHA256
> + select CRYPTO_SHA512
> + select CRYPTO_HMAC
> + select CRYPTO_SM3
> + select CRYPTO_CMAC
> + select CRYPTO_XCBC
> + select CRYPTO_AES
> + select CRYPTO_SM4_GENERIC
> +
> + help
> + Say y to enable Hash functionality of SPAcc.
> +
> +config CRYPTO_DEV_SPACC_AUTODETECT
> + bool "Enable Autodetect functionality"
> + depends on CRYPTO_DEV_SPACC
> + default y
> + help
> + Say y to enable Autodetect functionality of SPAcc.
> +
> +config CRYPTO_DEV_SPACC_DEBUG_TRACE_IO
> + bool "Enable Trace MMIO reads/writes stats"
> + depends on CRYPTO_DEV_SPACC
> + default n
> + help
> + Say y to enable Trace MMIO reads/writes stats.
> + To Debug and trace IO register read/write oprations.
> +
> +config CRYPTO_DEV_SPACC_DEBUG_TRACE_DDT
> + bool "Enable Trace DDT entries stats"
> + default n
> + depends on CRYPTO_DEV_SPACC
> + help
> + Say y to enable Enable DDT entry stats.
> + To Debug and trace DDT opration
> +
> +config CRYPTO_DEV_SPACC_SECURE_MODE
> + bool "Enable Spacc secure mode stats"
> + default n
> + depends on CRYPTO_DEV_SPACC
> + help
> + Say y to enable SPAcc secure modes stats.
> +
> +config CRYPTO_DEV_SPACC_PRIORITY
> + int "VSPACC priority value"
> + depends on CRYPTO_DEV_SPACC
> + range 0 15
> + default 1
> + help
> + Default arbitration priority weight for this Virtual SPAcc instance.
> + Hardware resets this to 1. Higher values means higher priority.
> +
> +config CRYPTO_DEV_SPACC_INTERNAL_COUNTER
> + int "SPAcc internal counter value"
> + depends on CRYPTO_DEV_SPACC
> + range 100000 1048575
> + default 100000
> + help
> + This value configures a hardware watchdog counter in the SPAcc engine.
> + The counter starts ticking when a completed cryptographic job is
> + sitting in the STATUS FIFO. If the job remains unprocessed for the
> + configured duration, an interrupt is triggered to ensure it is serviced.
> +
> +config CRYPTO_DEV_SPACC_CONFIG_DEBUG
> + bool "Enable SPAcc debug logs"
> + default n
> + depends on CRYPTO_DEV_SPACC
Just a kconfig style thing, it would be a bit cleaner to factor out the
repeated 'depends on CRYPTO_DEV_SPACC' by wrapping the options
in:
`if CRYPTO_DEV_SPACC .. endif`
- Julian Braha
^ permalink raw reply
* [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163
From: Lukas Metz @ 2026-06-23 16:07 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Lukas Metz
In-Reply-To: <20260623-dac8163-work-v1-0-5b508158faa0@gmx.net>
The DAC756x, DAC816x, and DAC856x devices are low-power, voltage-output,
dual-channel, 12-, 14-, and 16-bit digital-to-analog converters (DACs),
respectively. These devices include a 2.5-V, 4-ppm/°C internal
reference, giving a full-scale output voltage range of 2.5 V or 5 V.
Signed-off-by: Lukas Metz <lukas.metz@gmx.net>
---
MAINTAINERS | 6 +
drivers/iio/dac/Kconfig | 10 ++
drivers/iio/dac/Makefile | 1 +
drivers/iio/dac/ti-dac8163.c | 339 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 356 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index d238590a31f2..e82cc28e1bc3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26394,6 +26394,12 @@ S: Odd Fixes
F: drivers/clk/ti/
F: include/linux/clk/ti.h
+TI DAC8163 DAC DRIVER
+M: Lukas Metz <lukas.metz@gmx.net>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: drivers/iio/dac/ti-dac8163.c
+
TI DATA TRANSFORM AND HASHING ENGINE (DTHE) V2 CRYPTO DRIVER
M: T Pratham <t-pratham@ti.com>
L: linux-crypto@vger.kernel.org
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index db9f5c711b3d..6b6e5ee0732a 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -632,6 +632,16 @@ config TI_DAC7612
If compiled as a module, it will be called ti-dac7612.
+config TI_DAC8163
+ tristate "Texas Instruments 12/14/16-bit 2-channel DAC driver"
+ depends on SPI_MASTER
+ help
+ Driver for the Texas Instruments digital-to-analog converter
+ family dacxx6x compatible with the variants DAC7562,
+ DAC7563, DAC8162, DAC8163, DAC8562 and DAC8563.
+
+ If compiled as a module, it will be called ti-dac8163.
+
config VF610_DAC
tristate "Vybrid vf610 DAC driver"
depends on HAS_IOMEM
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 2a80bbf4e80a..359cde446623 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -62,4 +62,5 @@ obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o
obj-$(CONFIG_TI_DAC5571) += ti-dac5571.o
obj-$(CONFIG_TI_DAC7311) += ti-dac7311.o
obj-$(CONFIG_TI_DAC7612) += ti-dac7612.o
+obj-$(CONFIG_TI_DAC8163) += ti-dac8163.o
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
diff --git a/drivers/iio/dac/ti-dac8163.c b/drivers/iio/dac/ti-dac8163.c
new file mode 100644
index 000000000000..84a9dfb5347d
--- /dev/null
+++ b/drivers/iio/dac/ti-dac8163.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DACxx6x IIO driver (SPI)
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/iio/iio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+#include <linux/gpio/consumer.h>
+#include <linux/printk.h>
+#include <linux/bitfield.h>
+
+#define COMMAND_MASK GENMASK(6, 3)
+#define ADDRESS_MASK GENMASK(2, 0)
+
+#define COMMAND_SET(x, y) (FIELD_PREP(COMMAND_MASK, (x)) | \
+ FIELD_PREP(ADDRESS_MASK, (y)))
+
+#define CMD_WRITE_INPUT_REG 0x0
+#define CMD_UPDATE_DAC 0x1
+#define CMD_WRITE_UPDATE_ALL 0x2
+#define CMD_WRITE_UPDATE 0x3
+#define CMD_SET_PWR_MODE 0x4
+#define CMD_SOFT_RST 0x5
+
+#define CMD_LDAC_MODE 0x6
+#define LDAC_MODE_CHANNEL_A_MASK BIT(0)
+#define LDAC_MODE_CHANNEL_B_MASK BIT(1)
+
+#define CMD_SEL_REFERENCE 0x7
+#define VOLTAGE_REFERENCE_MASK BIT(0)
+
+enum dacxx6x_ldac_modes {
+ LDAC_MODE_ACTIVE = 0,
+ LDAC_MODE_INACTIVE = 1
+};
+
+enum dacxx6x_voltage_reference {
+ VOLTAGE_REFERENCE_EXTERNAL = 0,
+ VOLTAGE_REFERENCE_INTERNAL = 1
+};
+
+enum dacxx6x_supported_device_ids {
+ ID_DAC7562,
+ ID_DAC7563,
+ ID_DAC8162,
+ ID_DAC8163,
+ ID_DAC8562,
+ ID_DAC8563
+};
+
+struct dacxx6x_state {
+ struct spi_device *spi;
+
+ struct regulator *vref;
+ struct gpio_desc *loaddacs;
+
+ bool internal_ref;
+ int vref_uv;
+
+ unsigned int cached[2];
+
+ /*
+ * Lock to protect the state of the device from potential concurrent
+ * write accesses from userspace.
+ */
+ struct mutex lock;
+};
+
+struct dacxx6x_chip_info {
+ const char *name;
+ const struct iio_chan_spec channels[2];
+};
+
+#define DACXX6X_CHAN(id, resolution) \
+ { \
+ .type = IIO_VOLTAGE, .channel = (id), .output = 1, \
+ .indexed = 1, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_type = { .realbits = (resolution), \
+ .shift = 16 - (resolution) }, \
+ }
+
+static const struct dacxx6x_chip_info dacxx6x_chip_info_table[6] = {
+ [ID_DAC7562] = {
+ .name = "dac7562",
+ .channels = {
+ DACXX6X_CHAN(0, 12),
+ DACXX6X_CHAN(1, 12),
+ }
+ },
+ [ID_DAC7563] = {
+ .name = "dac7563",
+ .channels = {
+ DACXX6X_CHAN(0, 12),
+ DACXX6X_CHAN(1, 12),
+ }
+ },
+ [ID_DAC8162] = {
+ .name = "dac8162",
+ .channels = {
+ DACXX6X_CHAN(0, 14),
+ DACXX6X_CHAN(1, 14),
+ }
+ },
+ [ID_DAC8163] = {
+ .name = "dac8163",
+ .channels = {
+ DACXX6X_CHAN(0, 14),
+ DACXX6X_CHAN(1, 14),
+ }
+ },
+ [ID_DAC8562] = {
+ .name = "dac8562",
+ .channels = {
+ DACXX6X_CHAN(0, 16),
+ DACXX6X_CHAN(1, 16),
+ }
+ },
+ [ID_DAC8563] = {
+ .name = "dac8563",
+ .channels = {
+ DACXX6X_CHAN(0, 16),
+ DACXX6X_CHAN(1, 16),
+ }
+ },
+};
+
+static int dacxx6x_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct dacxx6x_state *st;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ st = iio_priv(indio_dev);
+ mutex_lock(&st->lock);
+ *val = st->cached[chan->channel];
+ mutex_unlock(&st->lock);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ st = iio_priv(indio_dev);
+ *val = st->vref_uv / MILLI; /* vref in mV */
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dacxx6x_write_reg(struct dacxx6x_state *st, int reg, int addr,
+ unsigned int val)
+{
+ u8 tx[3];
+
+ tx[0] = COMMAND_SET(reg, addr);
+ tx[1] = (val >> 8) & 0xff;
+ tx[2] = val & 0xff;
+
+ return spi_write(st->spi, tx, sizeof(tx));
+}
+
+static int dacxx6x_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct dacxx6x_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ dev_dbg(dev, "%s: val=%d val2=%d\n", __func__, val, val2);
+ if (val2 != 0)
+ return -EINVAL;
+
+ if (val < 0 || val >= BIT(chan->scan_type.realbits))
+ return -EINVAL;
+
+ mutex_lock(&st->lock);
+ int ret = dacxx6x_write_reg(st, CMD_WRITE_UPDATE, chan->channel,
+ (unsigned int)val
+ << chan->scan_type.shift);
+
+ if (!ret)
+ st->cached[chan->channel] = val;
+ mutex_unlock(&st->lock);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info dacxx6x_iio_info = {
+ .write_raw = dacxx6x_write_raw,
+ .read_raw = dacxx6x_read_raw
+};
+
+static int dacxx6x_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct dacxx6x_state *st;
+ const struct dacxx6x_chip_info *info;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+ spi_set_drvdata(spi, indio_dev);
+
+ st->loaddacs = devm_gpiod_get_optional(&spi->dev, "ti,loaddacs",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->loaddacs))
+ return PTR_ERR(st->loaddacs);
+
+ st->internal_ref =
+ device_property_read_bool(&spi->dev, "ti,internal-ref");
+
+ if (!st->internal_ref) {
+ st->vref = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->vref))
+ return PTR_ERR(st->vref);
+
+ ret = regulator_enable(st->vref);
+ if (ret < 0)
+ return ret;
+ }
+
+ mutex_init(&st->lock);
+
+ if (st->internal_ref) {
+ st->vref_uv = 2500000; /* 2.5V internal reference */
+ } else {
+ st->vref_uv = regulator_get_voltage(st->vref);
+ if (st->vref_uv < 0) {
+ ret = st->vref_uv;
+ goto err;
+ }
+ }
+
+ gpiod_set_value(st->loaddacs, 0);
+
+ ret = dacxx6x_write_reg(st, CMD_LDAC_MODE, 0,
+ FIELD_PREP(LDAC_MODE_CHANNEL_A_MASK, LDAC_MODE_INACTIVE) |
+ FIELD_PREP(LDAC_MODE_CHANNEL_B_MASK, LDAC_MODE_INACTIVE));
+
+ if (ret < 0)
+ goto err;
+
+ ret = dacxx6x_write_reg(st, CMD_SEL_REFERENCE, 0,
+ FIELD_PREP(VOLTAGE_REFERENCE_MASK, st->internal_ref));
+
+ if (ret < 0)
+ goto err;
+
+ info = spi_get_device_match_data(spi);
+
+ indio_dev->name = info->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &dacxx6x_iio_info;
+ indio_dev->channels = info->channels;
+ indio_dev->num_channels = 2;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ if (!st->internal_ref)
+ regulator_disable(st->vref);
+ mutex_destroy(&st->lock);
+ return ret;
+}
+
+static void dacxx6x_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct dacxx6x_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ mutex_destroy(&st->lock);
+ if (!st->internal_ref)
+ regulator_disable(st->vref);
+}
+
+#define DACXX6X_COMPATIBLE(of_compatible, id) \
+ { \
+ .compatible = of_compatible, \
+ .data = &dacxx6x_chip_info_table[id] \
+ }
+
+static const struct of_device_id dacxx6x_of_match[] = {
+ DACXX6X_COMPATIBLE("ti,dac7562", ID_DAC7562),
+ DACXX6X_COMPATIBLE("ti,dac7563", ID_DAC7563),
+ DACXX6X_COMPATIBLE("ti,dac8162", ID_DAC8162),
+ DACXX6X_COMPATIBLE("ti,dac8163", ID_DAC8163),
+ DACXX6X_COMPATIBLE("ti,dac8562", ID_DAC8562),
+ DACXX6X_COMPATIBLE("ti,dac8563", ID_DAC8563),
+ {}
+};
+MODULE_DEVICE_TABLE(of, dacxx6x_of_match);
+
+static const struct spi_device_id dacxx6x_id_table[] = {
+ { "dac7562", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC7562] },
+ { "dac7563", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC7563] },
+ { "dac8162", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC8162] },
+ { "dac8163", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC8163] },
+ { "dac8562", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC8562] },
+ { "dac8563", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC8563] },
+ {}
+};
+
+MODULE_DEVICE_TABLE(spi, dacxx6x_id_table);
+
+static struct spi_driver dacxx6x_driver = {
+ .driver = {
+ .name = "ti-dacxx6x",
+ .of_match_table = dacxx6x_of_match,
+ },
+ .probe = dacxx6x_probe,
+ .remove = dacxx6x_remove,
+ .id_table = dacxx6x_id_table,
+};
+
+module_spi_driver(dacxx6x_driver);
+
+MODULE_AUTHOR("Lukas Metz <lukas.metz@gmx.net>");
+MODULE_DESCRIPTION("Texas Instruments 12/14/16-bit 2-channel DAC driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH 0/2] Add driver for DAC8163:
From: Lukas Metz @ 2026-06-23 16:07 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Lukas Metz
This series adds an IIO driver for the Texas Instruments DAC7562, DAC7563,
DAC8162, DAC8163, DAC8562, and DAC8563 dual-channel voltage-output DACs.
These devices are pin-compatible 12-, 14-, and 16-bit variants sharing the
same 24-bit SPI command interface. Each device provides two independently
addressable output channels and includes a 2.5 V, 4 ppm/°C internal
reference that can be enabled via device tree, or an external reference
supplied through a regulator. The register and command structure differs
from already existing drivers which makes adding a new driver a
reasonable choice in my opinion.
The driver supports:
- All six device variants via a shared chip info table
- DAC updates in synchronous mode
- Configurable internal or external voltage reference
- Optional LDAC GPIO which has to be asserted permanently when using
synchronous updates.
- IIO_CHAN_INFO_RAW and IIO_CHAN_INFO_SCALE attributes per channel
Datasheet (DAC8163):
https://www.ti.com/lit/gpn/dac8163
The driver was tested with a DAC8163 on a custom STM32MP157F board with
external reference enabled.
Signed-off-by: Lukas Metz <lukas.metz@gmx.net>
---
Lukas Metz (2):
iio: dac: dac8163: Add driver for DAC8163
dt-bindings: iio: dac: Add DAC8163
.../devicetree/bindings/iio/dac/ti,dac8163.yaml | 75 +++++
MAINTAINERS | 7 +
drivers/iio/dac/Kconfig | 10 +
drivers/iio/dac/Makefile | 1 +
drivers/iio/dac/ti-dac8163.c | 339 +++++++++++++++++++++
5 files changed, 432 insertions(+)
---
base-commit: 76b6720279964612111352ca5d09f5bd61e41ce4
change-id: 20260413-dac8163-work-2138a775b515
Best regards,
--
Lukas <lukas.metz@gmx.net>
^ permalink raw reply
* [PATCH 2/2] dt-bindings: iio: dac: Add DAC8163
From: Lukas Metz @ 2026-06-23 16:07 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Lukas Metz
In-Reply-To: <20260623-dac8163-work-v1-0-5b508158faa0@gmx.net>
Add device tree binding for the Texas Instruments DAC8163 family
including the DAC7562, DAC7563, DAC8162, DAC8163, DAC8562 and DAC8563.
Signed-off-by: Lukas Metz <lukas.metz@gmx.net>
---
.../devicetree/bindings/iio/dac/ti,dac8163.yaml | 75 ++++++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 76 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
new file mode 100644
index 000000000000..bb4bad389323
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/ti,dac8163.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments DAC8163 family of DACs
+
+description:
+ The DAC756x, DAC816x, and DAC856x devices are low-power, voltage-output,
+ dual-channel, 12-, 14-, and 16-bit digital-to-analog converters (DACs),
+ respectively. These devices include a 2.5-V, 4-ppm/°C internal
+ reference, giving a full-scale output voltage range of 2.5 V or 5 V.
+
+maintainers:
+ - Lukas Metz <lukas.metz@gmx.net>
+
+properties:
+ compatible:
+ enum:
+ - ti,dac7562
+ - ti,dac7563
+ - ti,dac8162
+ - ti,dac8163
+ - ti,dac8562
+ - ti,dac8563
+
+ reg:
+ maxItems: 1
+
+ ti,loaddacs-gpios:
+ description:
+ Pin needs to be asserted permanently when updating the DAC synchronously.
+ maxItems: 1
+
+ vref-supply:
+ description:
+ Reference voltage for scaling if an external reference is used.
+
+ ti,internal-ref:
+ type: boolean
+ description:
+ Flag if the internal reference is used (external otherwise).
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+ - if:
+ not:
+ required:
+ - ti,internal-ref
+ then:
+ required:
+ - vref-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@1 {
+ compatible = "ti,dac8163";
+ reg = <0x1>; /* CS1 */
+ ti,loaddacs-gpios = <&gpiog 8 GPIO_ACTIVE_HIGH>;
+ ti,internal-ref; /* internal reference used*/
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index e82cc28e1bc3..5512f5eaab44 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26398,6 +26398,7 @@ TI DAC8163 DAC DRIVER
M: Lukas Metz <lukas.metz@gmx.net>
L: linux-iio@vger.kernel.org
S: Maintained
+F: Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
F: drivers/iio/dac/ti-dac8163.c
TI DATA TRANSFORM AND HASHING ENGINE (DTHE) V2 CRYPTO DRIVER
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2 1/3] dt-bindings: iio: health: add maxim,max86150
From: sashiko-bot @ 2026-06-23 16:02 UTC (permalink / raw)
To: Md Shofiqul Islam; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260623155556.13701-2-shofiqtest@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The YAML binding schema file is added with executable permissions (100755) instead of standard text file permissions (100644).
--
commit c219f77d4696cb841b5ce1448aac625e0d36d4ad
Author: Md Shofiqul Islam <shofiqtest@gmail.com>
dt-bindings: iio: health: add maxim,max86150
This commit adds a new YAML device tree binding schema for the Maxim
MAX86150 ECG and PPG biosensor.
> diff --git a/Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml b/Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
> new file mode 100755
[Severity: Low]
This isn't a bug, but should this YAML binding schema file be added with
standard text file permissions (100644) instead of being marked as executable?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623155556.13701-1-shofiqtest@gmail.com?part=1
^ permalink raw reply
* Re: [PATCH 0/3] SM8450 IPA support
From: Alex Elder @ 2026-06-23 15:56 UTC (permalink / raw)
To: esteuwu, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Alex Elder
Cc: linux-arm-msm, devicetree, linux-kernel, netdev
In-Reply-To: <20260622-sm8450-ipa-v1-0-532f0299f96e@proton.me>
On 6/22/26 8:44 PM, Esteban Urrutia via B4 Relay wrote:
> This series adds support for the IPA subsystem found in the SM8450 SoC.
> While IPA v5.0 is very similar to IPA v5.1 (heck, it even managed to
> properly get the modem up and running), it wasn't perfect, since the
> modem would sometimes hang when rebooting or powering the AP off.
> After a thorough investigation, I managed to create the proper data file
> required for IPA v5.1.
>
> Regards,
> Esteban
I assume you have implemented this based on what you found in
some downstream code. And if so, could you please indicate
where to find that (so I can do some cross-referencing myself).
I no longer have access to any Qualcomm internal documentation.
Thanks.
-Alex
> Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
> ---
> Esteban Urrutia (3):
> arm64: dts: qcom: sm8450: Add IPA support
> dt-bindings: net: qcom,ipa: Add SM8450 compatible string
> net: ipa: Add IPA v5.1 data
>
> .../devicetree/bindings/net/qcom,ipa.yaml | 1 +
> arch/arm64/boot/dts/qcom/sm8450.dtsi | 55 ++-
> drivers/net/ipa/Makefile | 2 +-
> drivers/net/ipa/data/ipa_data-v5.1.c | 477 +++++++++++++++++++++
> drivers/net/ipa/gsi_reg.c | 1 +
> drivers/net/ipa/ipa_data.h | 1 +
> drivers/net/ipa/ipa_main.c | 4 +
> drivers/net/ipa/ipa_reg.c | 1 +
> 8 files changed, 536 insertions(+), 6 deletions(-)
> ---
> base-commit: 948efecf22e49aa4bf55bb73ec79a0ddcfd38571
> change-id: 20260622-sm8450-ipa-5da81f67eb65
>
> Best regards,
> --
> Esteban Urrutia <esteuwu@proton.me>
>
>
^ permalink raw reply
* Re: [PATCH v4 11/12] iio: dac: ad5686: add triggered buffer support
From: Jonathan Cameron @ 2026-06-23 15:56 UTC (permalink / raw)
To: Rodrigo Alencar via B4 Relay
Cc: rodrigo.alencar, Michael Auchter, linux, linux-iio, devicetree,
linux-kernel, linux-hardening, Michael Hennerich, David Lechner,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Philipp Zabel, Kees Cook, Gustavo A. R. Silva
In-Reply-To: <20260623-ad5686-new-features-v4-11-28962a57db0f@analog.com>
On Tue, 23 Jun 2026 11:55:51 +0100
Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@kernel.org> wrote:
> From: Rodrigo Alencar <rodrigo.alencar@analog.com>
>
> Implement trigger handler by leveraging the LDAC gpio to update all DAC
> channels at once when it is available. Also, the multiple channel writes
> can be flushed at once with the sync() operation.
>
> Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
Hi Rodrigo
A follow up on the rework you did for this version,
Thanks,
Jonathan
> diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
> index db175e77b0b7..4dc681eb077d 100644
> --- a/drivers/iio/dac/ad5686.c
> +++ b/drivers/iio/dac/ad5686.c
> @@ -467,6 +472,60 @@ const struct ad5686_chip_info ad5679r_chip_info = {
> };
> EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686");
>
> +static irqreturn_t ad5686_trigger_handler(int irq, void *p)
> +{
> + struct iio_poll_func *pf = p;
> + struct iio_dev *indio_dev = pf->indio_dev;
> + struct iio_buffer *buffer = indio_dev->buffer;
> + struct ad5686_state *st = iio_priv(indio_dev);
> + u16 val[AD5686_MAX_CHANNELS] = { };
> + unsigned int scan_count, ch, i;
> + bool async_update;
> + int ret;
> + u8 cmd;
> +
> + ret = iio_pop_from_buffer(buffer, val);
> + if (ret) {
> + iio_trigger_notify_done(indio_dev->trig);
I think I'd prefer a wrapper to this if we are going to always say
it is IRQ_HANDLED (which is reasonable here I think)
Something like the following (unfortunately I only just read the
previous version thread so didn't head off the approach you have here.
static void do_ad5686_trigger_handler(struct iio_dev *indio_dev)
{
struct iio_buffer *buffer = indio_dev->buffer;
struct ad5686_state *st = iio_priv(indio_dev);
u16 val[AD5686_MAX_CHANNELS] = { };
int ret;
ret = iio_pop_from_buffer(buffer, val);
if (ret) {
iio_trigger_notify_done(indio_dev->trig);
guard(mutex)(&st->lock);
guts of current function
}
static irqreturn_t ad5686_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
do_ad5686_trigger_handler(indio_dev);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
> + return IRQ_HANDLED;
> + }
> +
> + guard(mutex)(&st->lock);
> +
> + scan_count = bitmap_weight(indio_dev->active_scan_mask,
> + iio_get_masklength(indio_dev));
> + async_update = st->ldac_gpio && scan_count > 1;
> + if (async_update) {
> + /* use LDAC to update all channels simultaneously */
> + cmd = AD5686_CMD_WRITE_INPUT_N;
> + gpiod_set_value_cansleep(st->ldac_gpio, 0);
> + } else {
> + cmd = AD5686_CMD_WRITE_INPUT_N_UPDATE_N;
> + }
> +
> + i = 0;
> + iio_for_each_active_channel(indio_dev, ch) {
> + ret = st->ops->write(st, cmd, indio_dev->channels[ch].address, val[i++]);
> + if (ret)
> + break;
> + }
> +
> + /*
> + * If sync() is available, it is called here regardless of write
> + * failure to allow bus implementation to reset. In that case, partial
> + * writes are unlikely as the write operations would just queue up
> + * the transfers.
> + */
> + if (st->ops->sync)
> + st->ops->sync(st);
> +
> + if (async_update)
> + gpiod_set_value_cansleep(st->ldac_gpio, 1);
> +
> + iio_trigger_notify_done(indio_dev->trig);
> + return IRQ_HANDLED;
> +}
^ permalink raw reply
* [PATCH v2 3/3] MAINTAINERS: add entry for MAX86150 IIO health driver
From: Md Shofiqul Islam @ 2026-06-23 15:55 UTC (permalink / raw)
To: linux-iio
Cc: jic23, dlechner, nuno.sa, robh, krzk+dt, conor+dt, devicetree,
joshua.crofts1, Md Shofiqul Islam
In-Reply-To: <20260623155556.13701-1-shofiqtest@gmail.com>
Add maintainer entry for the new MAX86150 ECG and PPG biosensor driver.
Signed-off-by: Md Shofiqul Islam <shofiqtest@gmail.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3115538ce829..a441ec44bb27 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15863,6 +15863,13 @@ S: Supported
F: Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml
F: drivers/power/supply/max77976_charger.c
+MAXIM MAX86150 ECG AND PPG BIOSENSOR DRIVER
+M: Md Shofiqul Islam <shofiqtest@gmail.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
+F: drivers/iio/health/max86150.c
+
MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
M: Krzysztof Kozlowski <krzk@kernel.org>
L: linux-pm@vger.kernel.org
--
2.51.1
^ permalink raw reply related
* [PATCH v2 2/3] iio: health: add MAX86150 ECG and PPG biosensor driver
From: Md Shofiqul Islam @ 2026-06-23 15:55 UTC (permalink / raw)
To: linux-iio
Cc: jic23, dlechner, nuno.sa, robh, krzk+dt, conor+dt, devicetree,
joshua.crofts1, Md Shofiqul Islam
In-Reply-To: <20260623155556.13701-1-shofiqtest@gmail.com>
The MAX86150 (Maxim/Analog Devices) integrates two PPG optical channels
(Red/IR LED) and one ECG biopotential channel in a single I2C device.
Data is captured via a 32-entry hardware FIFO with a configurable
almost-full interrupt.
The driver exposes three IIO channels:
- in_intensity_red_raw (PPG Red, 19-bit unsigned)
- in_intensity_ir_raw (PPG IR, 19-bit unsigned)
- in_voltage0_raw (ECG, 18-bit signed)
A hardware trigger is registered when an interrupt GPIO is provided in
the device tree, enabling the IIO triggered buffer path for continuous
low-overhead capture. The trigger enable/disable is driven by the
set_trigger_state callback to prevent the interrupt line from asserting
before the handler is ready.
FIFO reads use regmap_noinc_read() to burst-read 9 bytes (3 slots x
3 bytes) from the streaming FIFO_DATA register in a single I2C
transaction.
Signed-off-by: Md Shofiqul Islam <shofiqtest@gmail.com>
---
drivers/iio/health/Kconfig | 23 ++
drivers/iio/health/Makefile | 1 +
drivers/iio/health/max86150.c | 612 ++++++++++++++++++++++++++++++++++
3 files changed, 636 insertions(+)
create mode 100755 drivers/iio/health/max86150.c
diff --git a/drivers/iio/health/Kconfig b/drivers/iio/health/Kconfig
index a89f3abf11f4..6496cf55290c 100644
--- a/drivers/iio/health/Kconfig
+++ b/drivers/iio/health/Kconfig
@@ -13,6 +13,7 @@ config AFE4403
depends on SPI_MASTER
select REGMAP_SPI
select IIO_BUFFER
+ select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
help
Say yes to choose the Texas Instruments AFE4403
@@ -26,6 +27,7 @@ config AFE4404
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
+ select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
help
Say yes to choose the Texas Instruments AFE4404
@@ -39,6 +41,7 @@ config MAX30100
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
+ select IIO_TRIGGER
select IIO_KFIFO_BUF
help
Say Y here to build I2C interface support for the Maxim
@@ -52,6 +55,7 @@ config MAX30102
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
+ select IIO_TRIGGER
select IIO_KFIFO_BUF
help
Say Y here to build I2C interface support for the Maxim
@@ -62,4 +66,23 @@ config MAX30102
endmenu
+
+config MAX86150
+ tristate "MAX86150 ECG and PPG biosensor"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGER
+ select IIO_TRIGGERED_BUFFER
+ select REGMAP_I2C
+ help
+ Say Y here to enable support for the Maxim MAX86150 combined
+ ECG and photoplethysmography (PPG) biosensor.
+
+ The driver exposes three IIO channels: two PPG optical channels
+ (Red and IR LED) for heart rate and SpO2 monitoring, and one
+ ECG channel for biopotential recording.
+
+ This driver can also be built as a module. If so, the module
+ will be called max86150.
+
endmenu
diff --git a/drivers/iio/health/Makefile b/drivers/iio/health/Makefile
index 910817112258..04fc73c58444 100644
--- a/drivers/iio/health/Makefile
+++ b/drivers/iio/health/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_AFE4403) += afe4403.o
obj-$(CONFIG_AFE4404) += afe4404.o
obj-$(CONFIG_MAX30100) += max30100.o
obj-$(CONFIG_MAX30102) += max30102.o
+obj-$(CONFIG_MAX86150) += max86150.o
diff --git a/drivers/iio/health/max86150.c b/drivers/iio/health/max86150.c
new file mode 100755
index 000000000000..70c51ccb4672
--- /dev/null
+++ b/drivers/iio/health/max86150.c
@@ -0,0 +1,612 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MAX86150 combined ECG and PPG biosensor driver
+ *
+ * Copyright (C) 2026 Md Shofiqul Islam <shofiqtest@gmail.com>
+ *
+ * The MAX86150 integrates two PPG optical channels (Red/IR LED) and one
+ * ECG biopotential channel in a single I2C device. Data is captured
+ * through a 32-entry hardware FIFO with a configurable almost-full
+ * interrupt, making it well-suited for continuous monitoring with a
+ * low-power host.
+ *
+ * Datasheet:
+ * https://www.analog.com/media/en/technical-documentation/data-sheets/MAX86150.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+/* Register addresses */
+#define MAX86150_REG_INT_STATUS1 0x00
+#define MAX86150_REG_INT_STATUS2 0x01
+#define MAX86150_REG_INT_ENABLE1 0x02
+#define MAX86150_REG_INT_ENABLE2 0x03
+#define MAX86150_REG_FIFO_WR_PTR 0x04
+#define MAX86150_REG_OVF_COUNTER 0x05
+#define MAX86150_REG_FIFO_RD_PTR 0x06
+#define MAX86150_REG_FIFO_DATA 0x07
+#define MAX86150_REG_FIFO_CONFIG 0x08
+#define MAX86150_REG_FIFO_DCTRL1 0x09 /* FD1[3:0] FD2[7:4] */
+#define MAX86150_REG_FIFO_DCTRL2 0x0A /* FD3[3:0] FD4[7:4] */
+#define MAX86150_REG_SYS_CTRL 0x0D
+#define MAX86150_REG_PPG_CONFIG1 0x10
+#define MAX86150_REG_PPG_CONFIG2 0x11
+#define MAX86150_REG_LED1_PA 0x14 /* Red LED pulse amplitude */
+#define MAX86150_REG_LED2_PA 0x15 /* IR LED pulse amplitude */
+#define MAX86150_REG_ECG_CONFIG1 0x3C
+#define MAX86150_REG_ECG_CONFIG3 0x3E
+#define MAX86150_REG_PART_ID 0xFF
+
+/* Field masks */
+#define MAX86150_PART_ID_VAL 0x1E
+
+/* INT_STATUS1 / INT_ENABLE1 */
+#define MAX86150_INT_A_FULL BIT(7) /* FIFO almost full */
+#define MAX86150_INT_PPG_RDY BIT(6) /* new PPG sample ready */
+
+/* SYS_CTRL */
+#define MAX86150_SYS_SHDN BIT(1)
+#define MAX86150_SYS_RESET BIT(0)
+
+/* FIFO_CONFIG */
+#define MAX86150_FIFO_SMP_AVE GENMASK(7, 5)
+#define MAX86150_FIFO_ROLLOVER_EN BIT(4)
+#define MAX86150_FIFO_A_FULL GENMASK(3, 0)
+
+/* FIFO slot data-type codes */
+#define MAX86150_FD_NONE 0x0
+#define MAX86150_FD_LED1 0x1 /* Red PPG */
+#define MAX86150_FD_LED2 0x2 /* IR PPG */
+#define MAX86150_FD_ECG 0x9
+#define MAX86150_FIFO_FD1 GENMASK(3, 0)
+#define MAX86150_FIFO_FD2 GENMASK(7, 4)
+#define MAX86150_FIFO_FD3 GENMASK(3, 0)
+#define MAX86150_FIFO_FD4 GENMASK(7, 4)
+
+/* PPG_CONFIG1 */
+#define MAX86150_PPG_ADC_RGE GENMASK(7, 6)
+#define MAX86150_PPG_SR GENMASK(5, 1)
+
+/* Geometry */
+#define MAX86150_FIFO_DEPTH 32
+#define MAX86150_BYTES_PER_SLOT 3 /* 24-bit word per slot */
+#define MAX86150_NUM_SLOTS 3 /* Red, IR, ECG */
+#define MAX86150_SAMPLE_BYTES (MAX86150_NUM_SLOTS * MAX86150_BYTES_PER_SLOT)
+
+/* Default hardware configuration */
+#define MAX86150_LED_PA_DEFAULT 0x3F /* ~50 mA */
+#define MAX86150_PPG_SR_100HZ 4 /* PPG_SR field value for 100 Hz */
+#define MAX86150_PPG_ADC_RGE_16384 2 /* 16384 nA full scale */
+/* Fire A_FULL when 17 slots remain (32 - 15 = 17 samples in FIFO) */
+#define MAX86150_FIFO_A_FULL_VAL 15
+
+/* Scan element indices */
+enum max86150_scan_idx {
+ MAX86150_IDX_PPG_RED = 0,
+ MAX86150_IDX_PPG_IR = 1,
+ MAX86150_IDX_ECG = 2,
+ MAX86150_IDX_TS,
+};
+
+/**
+ * struct max86150_data - driver private state
+ * @regmap: register map for this device
+ * @dev: parent device (for dev_err logging)
+ * @trig: IIO hardware trigger backed by the device interrupt line
+ * @buf: DMA-safe capture buffer sized for worst-case (all 3 channels
+ * active): 3 x s32 (12 bytes) + 4-byte pad + s64 timestamp = 24
+ * bytes. __aligned(8) satisfies iio_push_to_buffers_with_timestamp().
+ */
+struct max86150_data {
+ struct regmap *regmap;
+ struct device *dev;
+ struct iio_trigger *trig;
+ s32 buf[6] __aligned(8);
+};
+
+/* IIO channel specification */
+
+static const struct iio_chan_spec max86150_channels[] = {
+ {
+ /* PPG Red LED - optical intensity, 19-bit unsigned */
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_RED,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = MAX86150_IDX_PPG_RED,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 19,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ /* PPG IR LED - optical intensity, 19-bit unsigned */
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_IR,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = MAX86150_IDX_PPG_IR,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 19,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ /* ECG biopotential - voltage, 18-bit signed two's complement */
+ .type = IIO_VOLTAGE,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = MAX86150_IDX_ECG,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 18,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(MAX86150_IDX_TS),
+};
+
+/* Regmap configuration */
+
+static const struct regmap_config max86150_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX86150_REG_PART_ID,
+};
+
+/* FIFO helper */
+
+/**
+ * max86150_read_one_sample - burst-read one complete 3-slot FIFO entry
+ * @data: driver state
+ * @ppg_red: out - 19-bit PPG Red ADC value (unsigned)
+ * @ppg_ir: out - 19-bit PPG IR ADC value (unsigned)
+ * @ecg: out - 18-bit ECG ADC value (sign-extended to s32)
+ *
+ * Each FIFO entry is 9 bytes (3 slots x 3 bytes). FIFO_DATA is a
+ * streaming register - the address does not auto-increment on each
+ * byte, so regmap_noinc_read() is used instead of regmap_bulk_read().
+ *
+ * Byte layout in the 24-bit FIFO word (MSB first):
+ * PPG 19-bit unsigned: bits [18:0], top 5 bits are always zero
+ * ECG 18-bit signed: bits [17:0], top 6 bits are sign extension
+ */
+static int max86150_read_one_sample(struct max86150_data *data,
+ u32 *ppg_red, u32 *ppg_ir, s32 *ecg)
+{
+ u8 buf[MAX86150_SAMPLE_BYTES]; /* 9 bytes */
+ int ret;
+
+ ret = regmap_noinc_read(data->regmap, MAX86150_REG_FIFO_DATA,
+ buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ /* Bytes [0..2]: PPG Red - 19-bit value in bits [18:0] */
+ *ppg_red = (u32)(buf[0] & 0x07) << 16 | (u32)buf[1] << 8 | buf[2];
+
+ /* Bytes [3..5]: PPG IR - same format */
+ *ppg_ir = (u32)(buf[3] & 0x07) << 16 | (u32)buf[4] << 8 | buf[5];
+
+ /* Bytes [6..8]: ECG - 18-bit signed, sign-extend to s32 */
+ *ecg = sign_extend32((u32)(buf[6] & 0x03) << 16 |
+ (u32)buf[7] << 8 | buf[8], 17);
+
+ return 0;
+}
+
+/* IIO read_raw */
+
+static int max86150_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct max86150_data *data = iio_priv(indio_dev);
+ u32 ppg_red, ppg_ir;
+ s32 ecg;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ /*
+ * Claim direct mode to prevent concurrent sysfs reads from
+ * corrupting the FIFO pointers while a triggered buffer
+ * capture is active.
+ */
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ /*
+ * Single-shot path: reset FIFO pointers so the next sample
+ * read is one that arrived after this call.
+ */
+ ret = regmap_write(data->regmap, MAX86150_REG_FIFO_WR_PTR, 0);
+ if (!ret)
+ ret = regmap_write(data->regmap,
+ MAX86150_REG_OVF_COUNTER, 0);
+ if (!ret)
+ ret = regmap_write(data->regmap,
+ MAX86150_REG_FIFO_RD_PTR, 0);
+ if (ret) {
+ iio_device_release_direct(indio_dev);
+ return ret;
+ }
+
+ /* Wait for one complete sample period at 100 Hz (<= 10 ms) */
+ usleep_range(11000, 13000);
+
+ ret = max86150_read_one_sample(data, &ppg_red, &ppg_ir, &ecg);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+
+ switch (chan->scan_index) {
+ case MAX86150_IDX_PPG_RED:
+ *val = ppg_red;
+ break;
+ case MAX86150_IDX_PPG_IR:
+ *val = ppg_ir;
+ break;
+ case MAX86150_IDX_ECG:
+ *val = ecg;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * TODO: return the hardware scale factor based on the
+ * configured PPG ADC range (PPG_ADC_RGE) and ECG PGA gain
+ * (ECG_PGA_GAIN). For PPG, scale is nA/LSB; for ECG, uV/LSB.
+ */
+ return -EINVAL;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info max86150_iio_info = {
+ .read_raw = max86150_read_raw,
+};
+
+/* Trigger */
+
+/*
+ * Enable or disable the FIFO almost-full interrupt when the IIO triggered
+ * buffer is started or stopped. Keeping the interrupt masked until capture
+ * is active prevents a pre-existing FIFO fill from asserting the line before
+ * the handler is ready to clear it.
+ */
+static int max86150_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct max86150_data *data = iio_priv(indio_dev);
+ unsigned int mask = state ? MAX86150_INT_A_FULL : 0;
+
+ return regmap_write(data->regmap, MAX86150_REG_INT_ENABLE1, mask);
+}
+
+static const struct iio_trigger_ops max86150_trigger_ops = {
+ .set_trigger_state = max86150_set_trigger_state,
+};
+
+/* Triggered buffer */
+
+/**
+ * max86150_trigger_handler - threaded IRQ handler for FIFO almost-full
+ *
+ * Called by the IIO buffer infrastructure when the hardware trigger fires.
+ * Reads INT_STATUS1 to de-assert the interrupt, then drains all available
+ * FIFO samples into the IIO push buffer, packing only the channels that
+ * are currently enabled in active_scan_mask.
+ */
+static irqreturn_t max86150_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *idev = pf->indio_dev;
+ struct max86150_data *data = iio_priv(idev);
+ unsigned int status, wr_ptr, rd_ptr, ovf, available;
+ u32 ppg_red, ppg_ir;
+ s32 ecg;
+ int ret, j;
+
+ /*
+ * Reading INT_STATUS1 clears the interrupt. Do this before touching
+ * the FIFO so the pin is de-asserted while we drain samples.
+ */
+ ret = regmap_read(data->regmap, MAX86150_REG_INT_STATUS1, &status);
+ if (ret)
+ goto done;
+
+ ret = regmap_read(data->regmap, MAX86150_REG_FIFO_WR_PTR, &wr_ptr);
+ if (ret)
+ goto done;
+ ret = regmap_read(data->regmap, MAX86150_REG_FIFO_RD_PTR, &rd_ptr);
+ if (ret)
+ goto done;
+
+ /*
+ * Read OVF_COUNTER to distinguish a full FIFO from an empty one:
+ * both produce wr_ptr == rd_ptr after the pointers wrap around.
+ * If OVF_COUNTER is non-zero the FIFO has saturated; treat all 32
+ * slots as available so we drain the entire FIFO and clear the
+ * interrupt condition.
+ */
+ ret = regmap_read(data->regmap, MAX86150_REG_OVF_COUNTER, &ovf);
+ if (ret)
+ goto done;
+
+ if (ovf > 0)
+ available = MAX86150_FIFO_DEPTH;
+ else
+ available = (wr_ptr - rd_ptr) & (MAX86150_FIFO_DEPTH - 1);
+
+ while (available--) {
+ ret = max86150_read_one_sample(data, &ppg_red, &ppg_ir, &ecg);
+ if (ret)
+ break;
+
+ /*
+ * Pack only active channels at consecutive positions [0..j-1].
+ * iio_push_to_buffers_with_timestamp() uses scan_bytes (which
+ * accounts for the active channel count) to place the timestamp,
+ * so static indexing would misplace it when fewer than 3
+ * channels are enabled.
+ */
+ j = 0;
+ if (test_bit(MAX86150_IDX_PPG_RED, idev->active_scan_mask))
+ data->buf[j++] = ppg_red;
+ if (test_bit(MAX86150_IDX_PPG_IR, idev->active_scan_mask))
+ data->buf[j++] = ppg_ir;
+ if (test_bit(MAX86150_IDX_ECG, idev->active_scan_mask))
+ data->buf[j++] = ecg;
+
+ iio_push_to_buffers_with_timestamp(idev, data->buf,
+ iio_get_time_ns(idev));
+ }
+
+done:
+ iio_trigger_notify_done(idev->trig);
+ return IRQ_HANDLED;
+}
+
+/* Chip initialisation / teardown */
+
+static void max86150_powerdown(void *arg)
+{
+ struct max86150_data *data = arg;
+
+ regmap_write(data->regmap, MAX86150_REG_INT_ENABLE1, 0);
+ regmap_write(data->regmap, MAX86150_REG_SYS_CTRL, MAX86150_SYS_SHDN);
+}
+
+static int max86150_chip_init(struct max86150_data *data)
+{
+ int ret;
+
+ /* Software reset; the bit self-clears within 1 ms */
+ ret = regmap_write(data->regmap, MAX86150_REG_SYS_CTRL,
+ MAX86150_SYS_RESET);
+ if (ret)
+ return ret;
+ usleep_range(1000, 2000);
+
+ /*
+ * FIFO: no sample averaging, rollover enabled, assert A_FULL when
+ * 17 samples are in the FIFO (32 - 15 = 17 available to read).
+ */
+ ret = regmap_write(data->regmap, MAX86150_REG_FIFO_CONFIG,
+ MAX86150_FIFO_ROLLOVER_EN |
+ FIELD_PREP(MAX86150_FIFO_A_FULL,
+ MAX86150_FIFO_A_FULL_VAL));
+ if (ret)
+ return ret;
+
+ /* Slot 1 = PPG Red (LED1), Slot 2 = PPG IR (LED2) */
+ ret = regmap_write(data->regmap, MAX86150_REG_FIFO_DCTRL1,
+ FIELD_PREP(MAX86150_FIFO_FD1, MAX86150_FD_LED1) |
+ FIELD_PREP(MAX86150_FIFO_FD2, MAX86150_FD_LED2));
+ if (ret)
+ return ret;
+
+ /* Slot 3 = ECG, Slot 4 = disabled */
+ ret = regmap_write(data->regmap, MAX86150_REG_FIFO_DCTRL2,
+ FIELD_PREP(MAX86150_FIFO_FD3, MAX86150_FD_ECG) |
+ FIELD_PREP(MAX86150_FIFO_FD4, MAX86150_FD_NONE));
+ if (ret)
+ return ret;
+
+ /* PPG: 100 Hz sample rate, 16384 nA ADC full-scale range */
+ ret = regmap_write(data->regmap, MAX86150_REG_PPG_CONFIG1,
+ FIELD_PREP(MAX86150_PPG_ADC_RGE,
+ MAX86150_PPG_ADC_RGE_16384) |
+ FIELD_PREP(MAX86150_PPG_SR,
+ MAX86150_PPG_SR_100HZ));
+ if (ret)
+ return ret;
+
+ /* LED pulse amplitudes (~50 mA) */
+ ret = regmap_write(data->regmap, MAX86150_REG_LED1_PA,
+ MAX86150_LED_PA_DEFAULT);
+ if (ret)
+ return ret;
+
+ return regmap_write(data->regmap, MAX86150_REG_LED2_PA,
+ MAX86150_LED_PA_DEFAULT);
+ /*
+ * Do NOT enable the A_FULL interrupt here. It is enabled and
+ * disabled via max86150_set_trigger_state() when the IIO triggered
+ * buffer is started and stopped, which prevents the edge-triggered
+ * interrupt line from asserting before the handler is registered.
+ */
+}
+
+static void max86150_trigger_put(void *trig)
+{
+ iio_trigger_put(trig);
+}
+
+/* Probe */
+
+static int max86150_probe(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev;
+ struct max86150_data *data;
+ unsigned int part_id;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->dev = &client->dev;
+
+ /*
+ * Enable power supplies before any I2C access. Both are optional
+ * in the device tree (devm_regulator_get_enable returns 0 when the
+ * supply is not described), but must be present and stable on real
+ * hardware before the first register read.
+ */
+ ret = devm_regulator_get_enable(&client->dev, "vdd");
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to get/enable vdd supply\n");
+
+ ret = devm_regulator_get_enable(&client->dev, "leds");
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to get/enable leds supply\n");
+
+ data->regmap = devm_regmap_init_i2c(client, &max86150_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
+ "Failed to initialise regmap\n");
+
+ ret = regmap_read(data->regmap, MAX86150_REG_PART_ID, &part_id);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Cannot read part ID\n");
+
+ if (part_id != MAX86150_PART_ID_VAL)
+ return dev_err_probe(&client->dev, -ENODEV,
+ "Unexpected part ID 0x%02x (expected 0x%02x)\n",
+ part_id, MAX86150_PART_ID_VAL);
+
+ ret = max86150_chip_init(data);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Chip initialisation failed\n");
+
+ ret = devm_add_action_or_reset(&client->dev, max86150_powerdown, data);
+ if (ret)
+ return ret;
+
+ indio_dev->name = "max86150";
+ indio_dev->channels = max86150_channels;
+ indio_dev->num_channels = ARRAY_SIZE(max86150_channels);
+ indio_dev->info = &max86150_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /*
+ * If the device tree provides an interrupt, set up a hardware
+ * trigger so userspace can use the FIFO almost-full signal to
+ * drive capture without polling.
+ */
+ if (client->irq > 0) {
+ data->trig = devm_iio_trigger_alloc(&client->dev,
+ "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!data->trig)
+ return -ENOMEM;
+
+ data->trig->ops = &max86150_trigger_ops;
+ iio_trigger_set_drvdata(data->trig, indio_dev);
+
+ /*
+ * iio_trigger_generic_data_rdy_poll is a hard-IRQ handler
+ * that calls iio_trigger_poll() and returns IRQ_HANDLED.
+ * No IRQF_ONESHOT is needed for this edge-triggered line.
+ */
+ ret = devm_request_irq(&client->dev, client->irq,
+ iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_FALLING,
+ "max86150", data->trig);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Cannot request IRQ %d\n",
+ client->irq);
+
+ ret = devm_iio_trigger_register(&client->dev, data->trig);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Cannot register trigger\n");
+
+ indio_dev->trig = iio_trigger_get(data->trig);
+ ret = devm_add_action_or_reset(&client->dev,
+ max86150_trigger_put,
+ data->trig);
+ if (ret)
+ return ret;
+ }
+
+ ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
+ iio_pollfunc_store_time,
+ max86150_trigger_handler,
+ NULL);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Cannot setup triggered buffer\n");
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+/* I2C driver table */
+
+static const struct i2c_device_id max86150_id[] = {
+ { "max86150" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max86150_id);
+
+static const struct of_device_id max86150_of_match[] = {
+ { .compatible = "maxim,max86150" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max86150_of_match);
+
+static struct i2c_driver max86150_driver = {
+ .driver = {
+ .name = "max86150",
+ .of_match_table = max86150_of_match,
+ },
+ .probe = max86150_probe,
+ .id_table = max86150_id,
+};
+module_i2c_driver(max86150_driver);
+
+MODULE_AUTHOR("Md Shofiqul Islam <shofiqtest@gmail.com>");
+MODULE_DESCRIPTION("MAX86150 ECG and PPG biosensor driver");
+MODULE_LICENSE("GPL");
--
2.51.1
^ permalink raw reply related
* [PATCH v2 1/3] dt-bindings: iio: health: add maxim,max86150
From: Md Shofiqul Islam @ 2026-06-23 15:55 UTC (permalink / raw)
To: linux-iio
Cc: jic23, dlechner, nuno.sa, robh, krzk+dt, conor+dt, devicetree,
joshua.crofts1, Md Shofiqul Islam
In-Reply-To: <20260623155556.13701-1-shofiqtest@gmail.com>
Add YAML schema binding for the Maxim MAX86150 combined ECG and PPG
biosensor. The device communicates over I2C at up to 400 kHz and
exposes an active-low interrupt when the 32-entry hardware FIFO
reaches its configurable almost-full threshold.
Signed-off-by: Md Shofiqul Islam <shofiqtest@gmail.com>
---
.../bindings/iio/health/maxim,max86150.yaml | 67 +++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100755 Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
diff --git a/Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml b/Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
new file mode 100755
index 000000000000..1bf10fd1a3d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/health/maxim,max86150.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim MAX86150 ECG and PPG Biosensor
+
+maintainers:
+ - Md Shofiqul Islam <shofiqtest@gmail.com>
+
+description: |
+ The MAX86150 is an integrated biosensor SoC that combines:
+ - Two PPG (photoplethysmography) channels: Red LED and IR LED,
+ for heart rate and blood-oxygen saturation (SpO2) measurement.
+ - One ECG (electrocardiogram) channel for biopotential recording.
+
+ The device communicates over I2C at up to 400 kHz and raises an
+ active-low interrupt when the 32-entry hardware FIFO reaches its
+ configurable almost-full threshold.
+
+ Datasheet:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/MAX86150.pdf
+
+properties:
+ compatible:
+ const: maxim,max86150
+
+ reg:
+ maxItems: 1
+ description: I2C device address, always 0x5E.
+
+ interrupts:
+ maxItems: 1
+ description: |
+ Active-low interrupt line. Asserted when the FIFO almost-full
+ threshold is reached or when a new PPG sample is ready.
+
+ vdd-supply:
+ description: Digital core supply, 1.71 V to 1.89 V.
+
+ leds-supply:
+ description: LED anode supply, 3.0 V to 5.5 V.
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ biosensor@5e {
+ compatible = "maxim,max86150";
+ reg = <0x5e>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+ vdd-supply = <&vdd_1v8>;
+ leds-supply = <&vdd_3v3>;
+ };
+ };
--
2.51.1
^ permalink raw reply related
* [PATCH v2 0/3] iio: health: add MAX86150 ECG and PPG biosensor driver
From: Md Shofiqul Islam @ 2026-06-23 15:55 UTC (permalink / raw)
To: linux-iio
Cc: jic23, dlechner, nuno.sa, robh, krzk+dt, conor+dt, devicetree,
joshua.crofts1, Md Shofiqul Islam
In-Reply-To: <20260623140113.12574-1-shofiqtest@gmail.com>
The MAX86150 (Maxim/Analog Devices) combines two PPG optical channels
(Red/IR LED) and one ECG biopotential channel in a single I2C device.
Data is produced at up to 3200 Hz and buffered in a 32-entry hardware
FIFO with a configurable almost-full interrupt.
This series adds:
1. DT binding YAML schema for maxim,max86150
2. IIO driver with triggered buffer support
3. MAINTAINERS entry
Changes in v2 (addressing Sashiko AI review, Joshua Crofts, Krzysztof Kozlowski):
- Fix buffer overflow: expand scan buffer to s32 buf[6] to hold
3 x s32 channels + 4-byte pad + s64 timestamp (24 bytes total)
- Add iio_device_claim_direct() in read_raw to prevent concurrent
sysfs reads from corrupting FIFO pointers during buffer capture
- Fix FIFO-full detection: read OVF_COUNTER to distinguish a fully
saturated FIFO (wr_ptr == rd_ptr after wrap) from an empty one
- Fix active_scan_mask handling: pack only active channels at
consecutive positions using test_bit(idx, active_scan_mask)
- Remove IRQF_ONESHOT from IRQ request (not needed for edge-triggered;
iio_trigger_generic_data_rdy_poll is a hard-IRQ handler)
- Add set_trigger_state callback to enable/disable A_FULL interrupt
only when the IIO buffer is active, preventing the interrupt line
from asserting before the handler is registered
- Fix endianness: change scan_type.endianness from IIO_LE to IIO_CPU
to match native integers written directly into the buffer
- Add max86150_powerdown() devm action to disable interrupts and
assert SYS_SHDN on driver unload
- Add devm_regulator_get_enable() for vdd-supply and leds-supply
before any I2C access
- Add devm action for iio_trigger_put() to balance the reference
count increment from iio_trigger_get()
- Split DT binding into a separate first patch (requested by Joshua Crofts)
- Add MAINTAINERS entry (requested by Joshua Crofts)
Known limitations (to be addressed in v3):
- IIO_CHAN_INFO_SCALE not yet implemented
- Runtime PM (SYS_CTRL SHDN bit) not yet implemented
- Not yet tested on physical hardware
Md Shofiqul Islam (3):
dt-bindings: iio: health: add maxim,max86150
iio: health: add MAX86150 ECG and PPG biosensor driver
MAINTAINERS: add entry for MAX86150 IIO health driver
.../bindings/iio/health/maxim,max86150.yaml | 67 ++
MAINTAINERS | 7 +
drivers/iio/health/Kconfig | 18 +
drivers/iio/health/Makefile | 1 +
drivers/iio/health/max86150.c | 612 ++++++++++++++++++
5 files changed, 705 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
create mode 100644 drivers/iio/health/max86150.c
--
2.51.1
^ permalink raw reply
* Re: [PATCH 1/8] clk: qcom: dispcc-sm8450: Fix mdss clocks
From: Konrad Dybcio @ 2026-06-23 15:50 UTC (permalink / raw)
To: esteuwu, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-1-37e2ee8df9da@proton.me>
On 6/23/26 2:54 AM, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
>
> Both of these changes allow the framebuffer to show upon boot and let
> the mdss driver take over afterwards.
> Before, none of these actions were possible. Only mdss takeover was
> possible, but screen had to be turned off first.
>
> OLE configuration may have been a misinterpretation... that's not
> something that's done on the downstream driver.
>
> Changing disp_cc_mdss_mdp_clk_src from clk_rcg2_shared_ops to
> clk_rcg2_shared_no_init_park_ops fixes this warning as well:
[...]
> drivers/clk/qcom/dispcc-sm8450.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c
> index 2e91332dd92a..b99d3eb5e195 100644
> --- a/drivers/clk/qcom/dispcc-sm8450.c
> +++ b/drivers/clk/qcom/dispcc-sm8450.c
> @@ -614,7 +614,7 @@ static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
> .parent_data = disp_cc_parent_data_5,
> .num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
> .flags = CLK_SET_RATE_PARENT,
> - .ops = &clk_rcg2_shared_ops,
> + .ops = &clk_rcg2_shared_no_init_park_ops,
> },
> };
>
> @@ -1824,8 +1824,8 @@ static int disp_cc_sm8450_probe(struct platform_device *pdev)
> disp_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE];
> disp_cc_pll1.clkr.hw.init = &sm8475_disp_cc_pll1_init;
>
> - clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &sm8475_disp_cc_pll0_config);
> - clk_lucid_ole_pll_configure(&disp_cc_pll1, regmap, &sm8475_disp_cc_pll1_config);
> + clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &sm8475_disp_cc_pll0_config);
> + clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &sm8475_disp_cc_pll1_config);
> } else {
> clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
> clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);
This can also be fixed by migrating to use qcom_cc_driver_data,
which takes a list of alpha PLLs to be configured, and thenthere's
a switch-statement in clk-alpha-pll.c that always assigns the
correct function
Konrad
^ permalink raw reply
* Re: [PATCH 2/13] dt-bindings: sound: Add Qualcomm QAIF binding
From: Konrad Dybcio @ 2026-06-23 15:48 UTC (permalink / raw)
To: Harendra Gautam
Cc: Srinivas Kandagatla, Mark Brown, Liam Girdwood, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-sound, linux-arm-msm,
devicetree, linux-kernel
In-Reply-To: <CAC-tS8CuhED2dvne=cuTBUcrL93WXPjNB-nDUYHWNtFF9oVVjQ@mail.gmail.com>
On 6/23/26 2:26 PM, Harendra Gautam wrote:
> On Tue, Jun 9, 2026 at 3:27 PM Konrad Dybcio
> <konrad.dybcio@oss.qualcomm.com> wrote:
>>
>> On 6/5/26 12:37 PM, Harendra Gautam wrote:
>>> Add a Devicetree binding for the Qualcomm Audio Interface (QAIF) CPU DAI
>>> controller used on the Shikra audio platform.
>>>
>>> QAIF moves PCM data between system memory and external serial audio
>>> interfaces through the AIF path, and between memory and the internal Bolero
>>> digital codec through the CIF path. The controller needs a binding so
>>> platform Devicetree files can describe its MMIO region, DMA IOMMU stream,
>>> clocks, interrupt, DAI cells and per-interface AIF configuration.
>>>
>>> Describe the single register region, one EE interrupt, the required GCC
>>> LPASS and audio core clocks, the DMA IOMMU mapping, and 'aif-interface@N'
>>> child nodes used for static PCM, TDM or MI2S configuration.
>>>
>>> Signed-off-by: Harendra Gautam <harendra.gautam@oss.qualcomm.com>
>>> ---
>>
>> [...]
>>
>>> + clock-names:
>>> + items:
>>> + - const: lpass_config_clk
>>> + - const: lpass_core_axim_clk
>>> + - const: aud_dma_clk
>>> + - const: aud_dma_mem_clk
>>> + - const: bus_clk
>>> + - const: aif_if0_ebit_clk
>>> + - const: aif_if0_ibit_clk
>>> + - const: aif_if1_ebit_clk
>>> + - const: aif_if1_ibit_clk
>>> + - const: aif_if2_ebit_clk
>>> + - const: aif_if2_ibit_clk
>>> + - const: aif_if3_ebit_clk
>>> + - const: aif_if3_ibit_clk
>>> + - const: ext_mclka_clk
>>> + - const: ext_mclkb_clk
>>
>> Drop the _clk suffix, we already know they are clocks, as they are
>> listed under the clocks property
> Okay, will correct.
>>
>> [...]
>>
>>> + qcom,qaif-aif-sync-mode:
>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>> + description:
>>> + Sync mode. Use QAIF_AIF_SYNC_MODE_SHORT (0) for short (pulse)
>>> + sync or QAIF_AIF_SYNC_MODE_LONG (1) for long (level) sync.
>>> + qcom,qaif-aif-sync-src:
>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>> + description:
>>> + Sync source. Use QAIF_AIF_SYNC_SRC_SLAVE (0) for slave mode
>>> + or QAIF_AIF_SYNC_SRC_MASTER (1) for master mode.
>>
>> Should these be boolean flags then?
> It should not be, the intention is to define explicitly, for better
> readability I can rename these flags as EXTERNAL/INTERNAL, Please
> suggest.
Are all 4 combinations of them being present/absent valid on shikra?
Konrad
^ permalink raw reply
* Re: [PATCH 1/7] dt-bindings: rtc: sun6i: Add Allwinner A733 support
From: Chen-Yu Tsai @ 2026-06-23 15:42 UTC (permalink / raw)
To: Jerome Brunet, Junhui Liu
Cc: Michael Turquette, Stephen Boyd, Jernej Skrabec, Samuel Holland,
Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard, linux-clk, linux-arm-kernel, linux-sunxi,
linux-kernel, linux-rtc, devicetree
In-Reply-To: <1j1pe7elxm.fsf@starbuckisacylon.baylibre.com>
On Tue, Jun 16, 2026 at 1:46 AM Jerome Brunet <jbrunet@baylibre.com> wrote:
>
> On sam. 28 mars 2026 at 20:37, Chen-Yu Tsai <wens@kernel.org> wrote:
>
> > On Wed, Jan 21, 2026 at 7:03 PM Junhui Liu <junhui.liu@pigmoral.tech> wrote:
> >>
> >> The RTC module in the Allwinner A733 SoC is functionally compatible with
> >> the sun6i RTC, but its internal Clock Control Unit (CCU) has significant
> >> changes.
> >>
> >> The A733 supports selecting the oscillator between three frequencies:
> >> 19.2MHz, 24MHz, and 26MHz. The RTC CCU relies on hardware to detect
> >> which frequency is actually used on the board. By defining all three
> >> frequencies as fixed-clocks in the device tree, the driver can identify
> >> the hardware-detected frequency and expose it to the rest of the system.
> >
> > No. The board device tree shall have the exact and correct frequency
> > defined in the external crystal device node. The operating system can
> > use the hardware-detected frequency to "fix" the in-system representation
> > if it is off.
> >
> >> Additionally, the A733 RTC CCU provides several new DCXO gate clocks for
> >> specific modules, including SerDes, HDMI, and UFS.
> >>
> >> Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
> >> ---
> >> .../bindings/rtc/allwinner,sun6i-a31-rtc.yaml | 38 ++++++++++++++++++++--
> >> include/dt-bindings/clock/sun60i-a733-rtc.h | 16 +++++++++
> >> 2 files changed, 52 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
> >> index 9df5cdb6f63f..b18431955783 100644
> >> --- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
> >> +++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
> >> @@ -26,6 +26,7 @@ properties:
> >> - allwinner,sun50i-h6-rtc
> >> - allwinner,sun50i-h616-rtc
> >> - allwinner,sun50i-r329-rtc
> >> + - allwinner,sun60i-a733-rtc
> >> - items:
> >> - const: allwinner,sun50i-a64-rtc
> >> - const: allwinner,sun8i-h3-rtc
> >> @@ -46,11 +47,11 @@ properties:
> >>
> >> clocks:
> >> minItems: 1
> >> - maxItems: 4
> >> + maxItems: 6
> >>
> >> clock-names:
> >> minItems: 1
> >> - maxItems: 4
> >> + maxItems: 6
> >>
> >> clock-output-names:
> >> minItems: 1
> >> @@ -156,6 +157,38 @@ allOf:
> >> - clocks
> >> - clock-names
> >>
> >> + - if:
> >> + properties:
> >> + compatible:
> >> + contains:
> >> + const: allwinner,sun60i-a733-rtc
> >> +
> >> + then:
> >> + properties:
> >> + clocks:
> >> + minItems: 5
> >> + items:
> >> + - description: Bus clock for register access
> >
> >> + - description: 19.2 MHz oscillator
> >> + - description: 24 MHz oscillator
> >> + - description: 26 MHz oscillator
> >
> > No. There is only one input. As in there is only one set of pins for the
> > DCXO. The inputs are the same as on R329 / A523. Just use that list.
> >
> >> + - description: AHB parent for internal SPI clock
> >> + - description: External 32768 Hz oscillator
> >> +
> >> + clock-names:
> >> + minItems: 5
> >> + items:
> >> + - const: bus
> >> + - const: osc19M
> >> + - const: osc24M
> >> + - const: osc26M
> >> + - const: ahb
> >> + - const: ext-osc32k
> >> +
> >> + required:
> >> + - clocks
> >> + - clock-names
> >> +
> >> - if:
> >> properties:
> >> compatible:
> >> @@ -164,6 +197,7 @@ allOf:
> >> - allwinner,sun8i-r40-rtc
> >> - allwinner,sun50i-h616-rtc
> >> - allwinner,sun50i-r329-rtc
> >> + - allwinner,sun60i-a733-rtc
> >>
> >> then:
> >> properties:
> >> diff --git a/include/dt-bindings/clock/sun60i-a733-rtc.h b/include/dt-bindings/clock/sun60i-a733-rtc.h
> >> new file mode 100644
> >> index 000000000000..8a2b5facad73
> >> --- /dev/null
> >> +++ b/include/dt-bindings/clock/sun60i-a733-rtc.h
> >> @@ -0,0 +1,16 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
> >> +
> >> +#ifndef _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_
> >> +#define _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_
> >> +
> >> +#define CLK_IOSC 0
> >> +#define CLK_OSC32K 1
> >> +#define CLK_HOSC 2
> >
> > The DCXO enable control has been present since at least the H6. We just
> > never added it, as we would never disable it anyway.
> >
> > If you compare the RTC clock trees of the A733 and A523, the only addition
> > besides the new gates seems to be the LOSC auto selection. But even that
> > is just an illusion, as the A523 has the same registers for that.
> >
> > One could say the A733 RTC is almost backward compatible to the A523, if
> > not for the two fastboot registers the A523 has at 0x120 and 0x124.
> >
> > So I ask that you try to integrate the differences into the existing
> > driver and bindings. You can tweak and export internal clks if you
> > need.
>
> I'd like to help with that. I think it is doable but I have a question
> regarding the binding of the existing driver, more precisely their usage
> here:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c?h=v7.1#n370
>
> Clock indexes are supposed to be stable in DT (AFAIK) but with the code
> linked the external 32k is at:
>
> * "ext-32k" - so index 3 - if "clock-names" is present
> * index 0 if clock names is not present
>
> ... but index 0 is supposed to be the bus clock according the binding
> doc, whether "clock-names" is there or not :/
>
> So what are those old r329 bindings ? is there a documentation defining
> them somewhere ?
You can look at
8487614a8a8a dt-bindings: rtc: sun6i: Add H616, R329, and D1 support
In hindsight maybe the two bindings should be separate. The old SoCs
did not have all these clock inputs from the main clock controller.
The only input it could possibly take was the external 32k crystal.
> Cleaning that part would help with A733 addition in the existing driver
> I think
Yeah. Also, we can treat the bindings and drivers separately. We could
have two bindings but one common driver, or vice versa. As you pointed
out, the bindings are a bit messed up, so we could consider separating
them.
If we end up with separate binding header files, maybe we could use
a different prefix for the new ones so they don't collide? That way
the driver could maybe still be shared?
As for whether to share the headers, I think they should be treated
as part of the binding, so if the bindings are shared, then they can
be shared as well; if the bindings are separate, then they should be
completely separate files as well.
And sorry for the late reply.
Thanks
ChenYu
> >
> >> +#define CLK_RTC_32K 3
> >
> > AFAICT besides being an internal clock, this is also fed to GPIO for
> > debounce? We probably need to expose this on the A523 as well.
> >
> >
> > Thanks
> > ChenYu
> >
> >
> >> +#define CLK_OSC32K_FANOUT 4
> >> +#define CLK_HOSC_SERDES1 5
> >> +#define CLK_HOSC_SERDES0 6
> >> +#define CLK_HOSC_HDMI 7
> >> +#define CLK_HOSC_UFS 8
> >> +
> >> +#endif /* _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_ */
> >>
> >> --
> >> 2.52.0
> >>
> >>
>
> --
> Jerome
>
^ permalink raw reply
* Re: [PATCH 1/8] clk: qcom: dispcc-sm8450: Fix mdss clocks
From: Krzysztof Kozlowski @ 2026-06-23 15:39 UTC (permalink / raw)
To: esteuwu, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-1-37e2ee8df9da@proton.me>
On 23/06/2026 02:54, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
>
> Both of these changes allow the framebuffer to show upon boot and let
> the mdss driver take over afterwards.
> Before, none of these actions were possible. Only mdss takeover was
> possible, but screen had to be turned off first.
>
> OLE configuration may have been a misinterpretation... that's not
> something that's done on the downstream driver.
>
> Changing disp_cc_mdss_mdp_clk_src from clk_rcg2_shared_ops to
> clk_rcg2_shared_no_init_park_ops fixes this warning as well:
These should be two separate commits, if I understand correctly.
Please use also Fixes tag.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 1/1] iio: health: add MAX86150 ECG and PPG biosensor driver
From: Krzysztof Kozlowski @ 2026-06-23 15:38 UTC (permalink / raw)
To: Md Shofiqul Islam, linux-iio
Cc: jic23, dlechner, nuno.sa, robh, krzk+dt, devicetree
In-Reply-To: <20260623140113.12574-2-shofiqtest@gmail.com>
On 23/06/2026 16:01, Md Shofiqul Islam wrote:
> The MAX86150 (Maxim/Analog Devices) integrates two PPG optical channels
> (Red/IR LED) and one ECG biopotential channel in a single I2C device.
> Data is captured via a 32-entry hardware FIFO with a configurable
> almost-full interrupt.
>
> The driver exposes three IIO channels:
> - in_intensity_red_raw (PPG Red, 19-bit unsigned)
> - in_intensity_ir_raw (PPG IR, 19-bit unsigned)
> - in_voltage0_raw (ECG, 18-bit signed)
>
> A hardware trigger is registered when an interrupt GPIO is provided in
> the device tree, enabling the IIO triggered buffer path for continuous
> low-overhead capture.
>
> FIFO reads use regmap_noinc_read() to burst-read 9 bytes (3 slots x
> 3 bytes) from the streaming FIFO_DATA register in a single I2C
> transaction.
>
> Signed-off-by: Md Shofiqul Islam <shofiqtest@gmail.com>
Please run scripts/checkpatch.pl on the patches and fix reported
warnings. After that, run also 'scripts/checkpatch.pl --strict' on the
patches and (probably) fix more warnings. Some warnings can be ignored,
especially from --strict run, but the code here looks like it needs a
fix. Feel free to get in touch if the warning is not clear.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 3/4] arm64: dts: allwinner: add Allwinner A733 SoC
From: Jerome Brunet @ 2026-06-23 15:35 UTC (permalink / raw)
To: Enzo Adriano via B4 Relay
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland, Maxime Ripard, Ulf Hansson,
enzo.adriano.code, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel, linux-mmc
In-Reply-To: <20260613-a733-dts-v1-public-ready-v1-3-7787c94681db@gmail.com>
On sam. 13 juin 2026 at 05:42, Enzo Adriano via B4 Relay <devnull+enzo.adriano.code.gmail.com@kernel.org> wrote:
> From: Enzo Adriano <enzo.adriano.code@gmail.com>
>
> Add the initial A733 SoC description with CPUs, timers, interrupt
> controller, clocks, pinctrl, UART0, and MMC0.
>
> Keep peripherals disabled by default. Board DTS files can enable only the
> devices that are proven on their hardware.
>
> Signed-off-by: Enzo Adriano <enzo.adriano.code@gmail.com>
> ---
> arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi | 198 +++++++++++++++++++++++++
> 1 file changed, 198 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi b/arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi
> new file mode 100644
> index 000000000000..3721aa9e8573
> --- /dev/null
> +++ b/arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi
> @@ -0,0 +1,198 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/clock/sun60i-a733-ccu.h>
> +#include <dt-bindings/reset/sun60i-a733-ccu.h>
> +
> +/ {
> + interrupt-parent = <&gic>;
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + cpus {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + cpu0: cpu@0 {
> + compatible = "arm,cortex-a55";
> + device_type = "cpu";
> + reg = <0x000>;
> + enable-method = "psci";
> + capacity-dmips-mhz = <530>;
> + };
> +
> + cpu1: cpu@100 {
> + compatible = "arm,cortex-a55";
> + device_type = "cpu";
> + reg = <0x100>;
> + enable-method = "psci";
> + capacity-dmips-mhz = <530>;
> + };
> +
> + cpu2: cpu@200 {
> + compatible = "arm,cortex-a55";
> + device_type = "cpu";
> + reg = <0x200>;
> + enable-method = "psci";
> + capacity-dmips-mhz = <530>;
> + };
> +
> + cpu3: cpu@300 {
> + compatible = "arm,cortex-a55";
> + device_type = "cpu";
> + reg = <0x300>;
> + enable-method = "psci";
> + capacity-dmips-mhz = <530>;
> + };
> +
> + cpu4: cpu@400 {
> + compatible = "arm,cortex-a55";
> + device_type = "cpu";
> + reg = <0x400>;
> + enable-method = "psci";
> + capacity-dmips-mhz = <530>;
> + };
> +
> + cpu5: cpu@500 {
> + compatible = "arm,cortex-a55";
> + device_type = "cpu";
> + reg = <0x500>;
> + enable-method = "psci";
> + capacity-dmips-mhz = <530>;
> + };
> +
> + cpu6: cpu@600 {
> + compatible = "arm,cortex-a76";
> + device_type = "cpu";
> + reg = <0x600>;
> + enable-method = "psci";
> + capacity-dmips-mhz = <1024>;
> + };
> +
> + cpu7: cpu@700 {
> + compatible = "arm,cortex-a76";
> + device_type = "cpu";
> + reg = <0x700>;
> + enable-method = "psci";
> + capacity-dmips-mhz = <1024>;
> + };
> + };
> +
> + osc24M: osc24M-clk {
Note A733 supports 19.2MHz, 24MHz and 26MHz xtals apparently.
The A7S and A7A do have a 26MHz xtal according to the schematics.
While this might be fine in the SoC dtsi, your are missing something in
your board dts to change the xtal rate, at least.
Also the node and clock name are a bit misleading now.
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <24000000>;
> + clock-output-names = "osc24M";
> + };
> +
> + osc32k: osc32k-clk {
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <32768>;
> + clock-output-names = "osc32k";
I think this is the ext32k supposed to feed the rtc ccu ...
> + };
> +
> + iosc: internal-osc-clk {
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <16000000>;
> + clock-output-names = "iosc";
> + };
> +
> + psci {
> + compatible = "arm,psci-1.0", "arm,psci-0.2";
> + method = "smc";
> + };
> +
> + timer {
> + compatible = "arm,armv8-timer";
> + arm,no-tick-in-suspend;
> + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH>;
> + };
> +
> + soc {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0x0 0x0 0x0 0x40000000>;
> +
> + pio: pinctrl@2000000 {
> + compatible = "allwinner,sun60i-a733-pinctrl";
> + reg = <0x02000000 0x600>;
> + interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&ccu CLK_APB1>, <&osc24M>, <&osc32k>;
> + clock-names = "apb", "hosc", "losc";
> + gpio-controller;
> + #gpio-cells = <3>;
> + interrupt-controller;
> + #interrupt-cells = <3>;
> +
> + mmc0_pins: mmc0-pins {
> + pins = "PF0", "PF1", "PF2",
> + "PF3", "PF4", "PF5";
> + function = "mmc0";
> + drive-strength = <30>;
> + bias-pull-up;
> + };
> + };
> +
> + ccu: clock-controller@2002000 {
> + compatible = "allwinner,sun60i-a733-ccu";
> + reg = <0x02002000 0x2000>;
> + clocks = <&osc24M>, <&osc32k>, <&iosc>;
^
... not directly the main CCU.
> + clock-names = "hosc", "losc", "iosc";
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> + };
> +
> + uart0: serial@2500000 {
> + compatible = "snps,dw-apb-uart";
> + reg = <0x02500000 0x400>;
> + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
> + reg-shift = <2>;
> + reg-io-width = <4>;
> + clocks = <&ccu CLK_BUS_UART0>;
> + resets = <&ccu RST_BUS_UART0>;
> + status = "disabled";
> + };
> +
> + gic: interrupt-controller@3400000 {
> + compatible = "arm,gic-v3";
> + #interrupt-cells = <3>;
> + interrupt-controller;
> + reg = <0x03400000 0x10000>,
> + <0x03460000 0x100000>;
> + };
> +
> + mmc0: mmc@4020000 {
> + compatible = "allwinner,sun60i-a733-mmc",
> + "allwinner,sun20i-d1-mmc";
> + reg = <0x04020000 0x1000>;
> + interrupts = <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
> + clock-names = "ahb", "mmc";
> + resets = <&ccu RST_BUS_MMC0>;
> + reset-names = "ahb";
> + pinctrl-names = "default";
> + pinctrl-0 = <&mmc0_pins>;
> + max-frequency = <200000000>;
> + cap-sd-highspeed;
> + status = "disabled";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + };
> + };
> +};
--
Jerome
^ permalink raw reply
* Re: [PATCH 7/7] clk: sunxi-ng: Add Allwinner A733 RTC CCU support
From: Chen-Yu Tsai @ 2026-06-23 15:23 UTC (permalink / raw)
To: Jerome Brunet
Cc: Junhui Liu, Michael Turquette, Stephen Boyd, Jernej Skrabec,
Samuel Holland, Alexandre Belloni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Maxime Ripard, linux-clk,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-rtc,
devicetree, André Przywara
In-Reply-To: <1jv7bjd6wi.fsf@starbuckisacylon.baylibre.com>
On Tue, Jun 16, 2026 at 1:56 AM Jerome Brunet <jbrunet@baylibre.com> wrote:
>
> On sam. 28 mars 2026 at 22:41, Chen-Yu Tsai <wens@kernel.org> wrote:
>
> > On Wed, Jan 21, 2026 at 7:04 PM Junhui Liu <junhui.liu@pigmoral.tech> wrote:
> >>
> >> Add support for the internal CCU found in the RTC module of the Allwinner
> >> A733 SoC. While the basic 16MHz (IOSC) and 32kHz logic remains compatible
> >> with older SoCs like the sun6i, the A733 introduces several new features.
> >>
> >> The A733 RTC CCU supports choosing one of three external crystal
> >> frequencies: 19.2MHz, 24MHz, and 26MHz. It features hardware detection
> >> logic to automatically identify the frequency used on the board and
> >> exports this DCXO signal as the "hosc" clock.
> >>
> >> Furthermore, the driver implements logic to derive a 32kHz reference
> >> from the HOSC. This is achieved through a muxed clock path using fixed
> >> pre-dividers to normalize the different crystal frequencies to ~32kHz.
> >
> > Have you tested whether the actually normalizes the frequency, i.e.
> > selects a different divider based on the DCXO frequency? Otherwise
> > we're just lying about the frequency.
> >
> >> This path reuses the same hardware mux registers as the HOSC clock.
> >>
> >> Additionally, this CCU provides several gate clocks for specific
> >> peripherals, including SerDes, HDMI, and UFS. The driver is implemented
> >> as an auxiliary driver to be bound to the sun6i-rtc driver.
> >>
> >> Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
> >> ---
>
> [...]
>
> >> +};
> >> +
> >> +static const struct clk_parent_data hosc_parents[] = {
> >> + { .fw_name = "osc24M" },
> >> + { .fw_name = "osc19M" },
> >> + { .fw_name = "osc26M" },
> >> + { .fw_name = "osc24M" },
> >> +};
> >
> > As mentioned in my reply to the binding, this is wrong. There is only
> > one input.
> >
> > The most you can do is check the rate of the parent clock against the
> > detected one, and _scream_ that the DT is wrong. And maybe override
> > the reported frequency.
> >
> > If you want to do the latter, you could add a new fixed rate gated
> > clock type to our library. You would fill in the rate before the
> > clocks get registered. I probably wouldn't go that far. We want people
> > to have correct hardware descriptions.
> >
> > Funnily enough Allwinner's BSP actually implements a fixed rate gate
> > for the next 24M-to-32k divider clock.
>
> What about implementing the register bellow as a read-only (and
> non-cached) divider using the factors provided by Junhui ? That would be
> an accurate description of the HW I think.
>
> The oscillator gets set in DT and if the output reported past the
> divider is not 32728Hz, you know you've got a problem (bad DT or HW gone
> bad)
>
> With a fixed-rate gate, you may actually end up lying about what
> actually happen, if the HW does not behave as expected.
>
> Do you prefer a fixed-rate gate still or should I try the RO divider
> approach ?
I think either one would work. The RO divider is probably more accurate.
Sorry for the late reply.
ChenYu
^ permalink raw reply
* Re: [PATCH V13 8/9] iio: imu: inv_icm42607: Add Gyroscope to icm42607
From: Jonathan Cameron @ 2026-06-23 15:15 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Chris Morgan, Chris Morgan, linux-iio, andy, nuno.sa, dlechner,
jean-baptiste.maneyrol, linux-rockchip, devicetree, heiko,
conor+dt, krzk+dt, robh
In-Reply-To: <ajotNPhg8fR3tLZp@ashevche-desk.local>
On Tue, 23 Jun 2026 09:52:36 +0300
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> On Wed, Jun 17, 2026 at 04:10:49PM -0500, Chris Morgan wrote:
> > On Tue, Jun 16, 2026 at 01:13:03PM +0300, Andy Shevchenko wrote:
> > > On Mon, Jun 15, 2026 at 12:25:51PM -0500, Chris Morgan wrote:
>
> ...
>
> > > Can be some of the code deduplicated between gyro and accel?
> >
> > Probably a fair amount, but the deduplication will likely need to be
> > undone somewhat if we get buffer, WoM or apex support added back
> > (I don't have any devices with such functionality, so if anyone will
> > do it then it won't be me). I can refactor more if you want, or we
> > can keep it split like this to make it easy if someone else wants to
> > tackle the buffers/IRQs stuff later? Your call.
>
> Just asking. Jonathan, David, Nuno, what's your opinion on this?
> Personal opinion is to avoid solving the issues that do not exist.
> If you are not committing into those features, let's not prepare
> driver for them right now.
>
Agreed. My only exception to this is normally when someone tells
me they have the code and plan to post a follow up set very shortly.
Then I get a bit more relaxed as they chances of 'preparing' for the
future being relevant become much higher!
Jonathan
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: iio: dac: Add AD5529R
From: Jonathan Cameron @ 2026-06-23 15:08 UTC (permalink / raw)
To: Conor Dooley
Cc: Nuno Sá, Rodrigo Alencar, Janani Sunil, Janani Sunil,
Lars-Peter Clausen, Michael Hennerich, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-iio, devicetree, linux-kernel, linux-doc, Mark Brown
In-Reply-To: <20260622-captive-tux-067efd31ceac@spud>
On Mon, 22 Jun 2026 19:39:43 +0100
Conor Dooley <conor@kernel.org> wrote:
> On Mon, Jun 22, 2026 at 05:29:11PM +0100, Jonathan Cameron wrote:
> > > > > Yeah. It's not clear to me how that works for the microchip devices
> > > > > (I suspect it doesn't!)
> > > > >
> > > > > Just thinking as I type, but could we do something a bit nasty with
> > > > > a gpio mux that doesn't actually switch but represents the GPIO being
> > > > > shared? Given this is all tied to the spi bus that should all happen
> > > > > under serializing locks.
> > > > >
> > > > > Agreed though that this would be nicer as an SPI thing that let
> > > > > us specify that a single CS is share by multiple devices and their
> > > > > is some other signal acting to select which one we are talking to.
> > > > >
> > > >
> > > > If the device-addressing on the same chip-select is to be handled
> > > > by the spi framework, wouldn't we lose device-specific features?
> > > >
> > > > I understand that this multi-device feature is there mostly to extend the
> > > > channel count from 16 to 32, 48 or 64. I suppose the command:
> > > >
> > > > "MULTI DEVICE SW LDAC MODE"
> > > >
> > > > exists so that software can update channel values accross multiple devices.
> > >
> > > Right! You do have a point! I agree the main driver for a feature like
> > > this is likely to extend the channel count and effectively "aggregate"
> > > devices.
> > >
> > > But I would say that even with the spi solution the MULTI DEVICE stuff
> > > should be doable (as we still need a sort of adi,pin-id property).
> > >
> > > But yes, I do feel that the whole feature is for aggregation so seeing
> > > one device with 32 channels is the expectation here? Rather than seeing
> > > two devices with 16 channels.
> >
> > Agreed - if we have messages that address both devices at once that needs
> > to be a unified driver and given they are about triggering simultaneous
> > update of all channels it needs to look like one big device.
> > This ends up similar to how we handle daisy chain devices.
> >
> > The question of what to do on devices that don't have this feature
> > is rather different. Good thing you read the datasheet :)
>
> I'm not sure it really is, the intent for the microchip devices I think
> is pretty similar. The mcp3911 datasheet cites three-phase power
> metering using three devices as a typical use-case, for example.
> Probably creating an amalgamated device is a good fit there too?
>
> I assume an amalgamated device for this ADI product means per-channel ID
> properties?
Per device as they are 8 channel each, but effectively the same.
(microchip devices are 2 channels each I think)
> If so, I think they should be made generic and the Microchip
> products retrofitted to use them, with a fallback to the proprietary
> property. Not going to ask for the support for multiple devices in those
> drivers, since the current way doesn't work and there'd be no loss of
> support. Someone from Microchip can do that. The proprietary property
> to generic conversion should be straightforward and provides weight to
> an argument for this being generic, since that'd be three devices that
> can all share?
I think the practical difference is that for the ADI part we have to support
it as a single device as some commands effectively don't use the address
bits in the message. For the microchip ones we could register multiple
separate SPI devices and just provide one address for each.
Equally we could treat the microchip ones as a unified device in which case
the binding will be the same and there will be a property with a bunch
of addresses (one for each device present). I'm fine with this option given
as you say the datasheet calls out using this for channel expansion.
Jonathan
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: iio: dac: Add AD5529R
From: Jonathan Cameron @ 2026-06-23 14:57 UTC (permalink / raw)
To: Rodrigo Alencar
Cc: Nuno Sá, Conor Dooley, Janani Sunil, Janani Sunil,
Lars-Peter Clausen, Michael Hennerich, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-iio, devicetree, linux-kernel, linux-doc, Mark Brown
In-Reply-To: <5guhkvoxhkzevjm4b45hhk3772akpnz3givr3gb56x5ywamzyf@oiycreun4y62>
On Tue, 23 Jun 2026 09:09:14 +0100
Rodrigo Alencar <455.rodrigo.alencar@gmail.com> wrote:
> On 22/06/26 13:20, Nuno Sá wrote:
> > On Mon, Jun 22, 2026 at 12:51:20PM +0100, Rodrigo Alencar wrote:
> > > On 22/06/26 11:29, Nuno Sá wrote:
> > > > On Mon, Jun 22, 2026 at 10:24:05AM +0100, Rodrigo Alencar wrote:
> > > > > On 21/06/26 15:33, Jonathan Cameron wrote:
> > > > > > On Fri, 19 Jun 2026 16:54:11 +0100
> > > > > > Nuno Sá <noname.nuno@gmail.com> wrote:
> > > > > >
> > > > > > > On Fri, Jun 19, 2026 at 03:12:07PM +0100, Conor Dooley wrote:
> > > > > > > > On Fri, Jun 19, 2026 at 02:01:08PM +0100, Nuno Sá wrote:
> > > > > > > > > On Fri, Jun 19, 2026 at 12:40:54PM +0100, Conor Dooley wrote:
> > > > > > > > > > On Fri, Jun 19, 2026 at 12:36:55PM +0100, Conor Dooley wrote:
> > > > > > > > > > > On Fri, Jun 19, 2026 at 12:33:11PM +0200, Janani Sunil wrote:
> > > > > > > > > > > >
> > > > > > > > > > > > On 6/14/26 21:44, Jonathan Cameron wrote:
> > > > > > > > > > > > > On Tue, 9 Jun 2026 16:47:23 +0200
> > > > > > > > > > > > > Janani Sunil <jan.sun97@gmail.com> wrote:
> > > > > > > > > > > > >
> > > > > > > > > > > > > > On 5/26/26 15:11, Rodrigo Alencar wrote:
> > > > > > > > > > > > > > > On 26/05/19 05:42PM, Janani Sunil wrote:
> > > > > > > > > > > > > > > > Devicetree bindings for AD5529R 16 channel 12/16 bit high voltage,
> > > > > > > > > > > > > > > > buffered voltage output digital-to-analog converter (DAC) with an
> > > > > > > > > > > > > > > > integrated precision reference.
> > > > > > > > > > > > > > > ...
> > > > > > > > > > > > > > > Probably others may comment on that, but...
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > This parent node may support device addressing for multi-device support through
> > > > > > > > > > > > > > > those ID pins. I suppose that each device may have its own power supplies or
> > > > > > > > > > > > > > > other resources like the toggle pins or reset and enable.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > That way I suppose that an example would look like...
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +patternProperties:
> > > > > > > > > > > > > > > > + "^channel@([0-9]|1[0-5])$":
> > > > > > > > > > > > > > > > + type: object
> > > > > > > > > > > > > > > > + description: Child nodes for individual channel configuration
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + properties:
> > > > > > > > > > > > > > > > + reg:
> > > > > > > > > > > > > > > > + description: Channel number.
> > > > > > > > > > > > > > > > + minimum: 0
> > > > > > > > > > > > > > > > + maximum: 15
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + adi,output-range-microvolt:
> > > > > > > > > > > > > > > > + description: |
> > > > > > > > > > > > > > > > + Output voltage range for this channel as [min, max] in microvolts.
> > > > > > > > > > > > > > > > + If not specified, defaults to 0V to 5V range.
> > > > > > > > > > > > > > > > + oneOf:
> > > > > > > > > > > > > > > > + - items:
> > > > > > > > > > > > > > > > + - const: 0
> > > > > > > > > > > > > > > > + - enum: [5000000, 10000000, 20000000, 40000000]
> > > > > > > > > > > > > > > > + - items:
> > > > > > > > > > > > > > > > + - const: -5000000
> > > > > > > > > > > > > > > > + - const: 5000000
> > > > > > > > > > > > > > > > + - items:
> > > > > > > > > > > > > > > > + - const: -10000000
> > > > > > > > > > > > > > > > + - const: 10000000
> > > > > > > > > > > > > > > > + - items:
> > > > > > > > > > > > > > > > + - const: -15000000
> > > > > > > > > > > > > > > > + - const: 15000000
> > > > > > > > > > > > > > > > + - items:
> > > > > > > > > > > > > > > > + - const: -20000000
> > > > > > > > > > > > > > > > + - const: 20000000
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + required:
> > > > > > > > > > > > > > > > + - reg
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + additionalProperties: false
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +required:
> > > > > > > > > > > > > > > > + - compatible
> > > > > > > > > > > > > > > > + - reg
> > > > > > > > > > > > > > > > + - vdd-supply
> > > > > > > > > > > > > > > > + - avdd-supply
> > > > > > > > > > > > > > > > + - hvdd-supply
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +dependencies:
> > > > > > > > > > > > > > > > + spi-cpha: [ spi-cpol ]
> > > > > > > > > > > > > > > > + spi-cpol: [ spi-cpha ]
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +allOf:
> > > > > > > > > > > > > > > > + - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +unevaluatedProperties: false
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +examples:
> > > > > > > > > > > > > > > > + - |
> > > > > > > > > > > > > > > > + #include <dt-bindings/gpio/gpio.h>
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + spi {
> > > > > > > > > > > > > > > > + #address-cells = <1>;
> > > > > > > > > > > > > > > > + #size-cells = <0>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + dac@0 {
> > > > > > > > > > > > > > > > + compatible = "adi,ad5529r-16";
> > > > > > > > > > > > > > > > + reg = <0>;
> > > > > > > > > > > > > > > > + spi-max-frequency = <25000000>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + vdd-supply = <&vdd_regulator>;
> > > > > > > > > > > > > > > > + avdd-supply = <&avdd_regulator>;
> > > > > > > > > > > > > > > > + hvdd-supply = <&hvdd_regulator>;
> > > > > > > > > > > > > > > > + hvss-supply = <&hvss_regulator>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + #address-cells = <1>;
> > > > > > > > > > > > > > > > + #size-cells = <0>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + channel@0 {
> > > > > > > > > > > > > > > > + reg = <0>;
> > > > > > > > > > > > > > > > + adi,output-range-microvolt = <0 5000000>;
> > > > > > > > > > > > > > > > + };
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + channel@1 {
> > > > > > > > > > > > > > > > + reg = <1>;
> > > > > > > > > > > > > > > > + adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > > > > > > > > > > > + };
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > + channel@2 {
> > > > > > > > > > > > > > > > + reg = <2>;
> > > > > > > > > > > > > > > > + adi,output-range-microvolt = <0 40000000>;
> > > > > > > > > > > > > > > > + };
> > > > > > > > > > > > > > > > + };
> > > > > > > > > > > > > > > > + };
> > > > > > > > > > > > > > > ...
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > spi {
> > > > > > > > > > > > > > > #address-cells = <1>;
> > > > > > > > > > > > > > > #size-cells = <0>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > multi-dac@0 {
> > > > > > > > > > > > > > > compatible = "adi,ad5529r-16";
> > > > > > > > > > > > > > > reg = <0>;
> > > > > > > > > > > > > > > spi-max-frequency = <25000000>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > #address-cells = <1>;
> > > > > > > > > > > > > > > #size-cells = <0>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > dac@0 {
> > > > > > > > > > > > > > > reg = <0>;
> > > > > > > > > > > > > > > vdd-supply = <&vdd_regulator>;
> > > > > > > > > > > > > > > avdd-supply = <&avdd_regulator>;
> > > > > > > > > > > > > > > hvdd-supply = <&hvdd_regulator>;
> > > > > > > > > > > > > > > hvss-supply = <&hvss_regulator>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > #address-cells = <1>;
> > > > > > > > > > > > > > > #size-cells = <0>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > channel@0 {
> > > > > > > > > > > > > > > reg = <0>;
> > > > > > > > > > > > > > > adi,output-range-microvolt = <0 5000000>;
> > > > > > > > > > > > > > > };
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > channel@1 {
> > > > > > > > > > > > > > > reg = <1>;
> > > > > > > > > > > > > > > adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > > > > > > > > > > };
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > channel@2 {
> > > > > > > > > > > > > > > reg = <2>;
> > > > > > > > > > > > > > > adi,output-range-microvolt = <0 40000000>;
> > > > > > > > > > > > > > > };
> > > > > > > > > > > > > > > }
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > dac@1 {
> > > > > > > > > > > > > > > reg = <1>;
> > > > > > > > > > > > > > > vdd-supply = <&vdd_regulator>;
> > > > > > > > > > > > > > > avdd-supply = <&avdd_regulator>;
> > > > > > > > > > > > > > > hvdd-supply = <&hvdd_regulator>;
> > > > > > > > > > > > > > > hvss-supply = <&hvss_regulator>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > reset-gpios = <&gpio0 88 GPIO_ACTIVE_LOW>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > #address-cells = <1>;
> > > > > > > > > > > > > > > #size-cells = <0>;
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > channel@0 {
> > > > > > > > > > > > > > > reg = <0>;
> > > > > > > > > > > > > > > adi,output-range-microvolt = <0 5000000>;
> > > > > > > > > > > > > > > };
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > channel@1 {
> > > > > > > > > > > > > > > reg = <1>;
> > > > > > > > > > > > > > > adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > > > > > > > > > > };
> > > > > > > > > > > > > > > }
> > > > > > > > > > > > > > > };
> > > > > > > > > > > > > > > };
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > then you might need something like:
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > patternProperties:
> > > > > > > > > > > > > > > "^dac@[0-3]$":
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > and put most of the things under this node pattern.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > So the main driver that you're putting together might need to handle up to four instances.
> > > > > > > > > > > > > > > Even if your current driver cannot handle this, the dt-bindings might need cover that.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > Need to double check if each dac node needs a separate compatible, so you would maybe populate
> > > > > > > > > > > > > > > a platform data to be shared with the child nodes, which would be a separate driver.
> > > > > > > > > > > > > > > (not sure if it would make sense to mix and match ad5529r-16 and ad5529r-12).
> > > > > > > > > > > > > > Hi Rodrigo,
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Thank you for looking at this.
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > For now, I would prefer to keep the binding scoped to a single AD5529R device instance. The current
> > > > > > > > > > > > > > hardware/use case we have only needs one device node and the driver is written around that model as well.
> > > > > > > > > > > > > > While the device addressing pins could allow multi-device topology, we do not have an actual platform using
> > > > > > > > > > > > > > that configuration at the moment, so I would prefer not to introduce an extra parent/child binding structure
> > > > > > > > > > > > > > speculatively without a validating use case.
> > > > > > > > > > > > > Interesting feature - kind of similar to address control on a typical i2c bus device, or
> > > > > > > > > > > > > looking at it another way a kind of distributed SPI mux.
> > > > > > > > > > > > >
> > > > > > > > > > > > > Challenge of a binding is we need to anticipate the future. So I think we do need something
> > > > > > > > > > > > > like Rodrigo is suggesting even if we only (for now) support a single instance in the driver.
> > > > > > > > > > > > > That would leave the path open to supporting the addressing at a later date.
> > > > > > > > > > > > > An alternative might be to look at it like a chained device setup. In those we pretend there
> > > > > > > > > > > > > is just one device with a lot of channels etc. The snag is that here things are more loosely
> > > > > > > > > > > > > coupled whereas for those devices it tends to be you have to read / write the same register
> > > > > > > > > > > > > in all devices in the chain as one big SPI message.
> > > > > > > > > > > > >
> > > > > > > > > > > > > +CC Mark Brown as he may know of some precedence for this feature. For his reference..
> > > > > > > > > > > > > - Each of these device has 2 ID pins. The SPI transfers have to contain the 2 bit
> > > > > > > > > > > > > value that matches that or they are ignored. Thus a single bus + 1 chip select can
> > > > > > > > > > > > > be used to talk to 4 devices. Question is what that looks like in device tree + I guess
> > > > > > > > > > > > > longer term how to support it cleanly in SPI.
> > > > > > > > > > >
> > > > > > > > > > > I'd swear I have seen this before, from some Microchip devices. Let me
> > > > > > > > > > > see if I can find what I am thinking of...
> > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > microchip,mcp3911 and microchip,mcp3564 both seem to do this with
> > > > > > > > > > slightly different properties.
> > > > > > > > > >
> > > > > > > > > > microchip,device-addr:
> > > > > > > > > > description: Device address when multiple MCP3911 chips are present on the same SPI bus.
> > > > > > > > > > $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > > enum: [0, 1, 2, 3]
> > > > > > > > > > default: 0
> > > > > > > > > >
> > > > > > > > > > and
> > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > microchip,hw-device-address:
> > > > > > > > > > $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > > minimum: 0
> > > > > > > > > > maximum: 3
> > > > > > > > > > description:
> > > > > > > > > > The address is set on a per-device basis by fuses in the factory,
> > > > > > > > > > configured on request. If not requested, the fuses are set for 0x1.
> > > > > > > > > > The device address is part of the device markings to avoid
> > > > > > > > > > potential confusion. This address is coded on two bits, so four possible
> > > > > > > > > > addresses are available when multiple devices are present on the same
> > > > > > > > > > SPI bus with only one Chip Select line for all devices.
> > > > > > > > > > Each device communication starts by a CS falling edge, followed by the
> > > > > > > > > > clocking of the device address (BITS[7:6] - top two bits of COMMAND BYTE
> > > > > > > > > > which is first one on the wire).
> > > > > > > > > >
> > > > > > > > > > This sounds exactly like the sort of feature that you're dealing with
> > > > > > > > > > here?
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > The core idea yes but for this chip, things are a bit more annoying (but
> > > > > > > > > Janani can correct me if I'm wrong). Here, each device can, in theory,
> > > > > > > > > have it's own supplies, pins and at the very least, channels with maybe
> > > > > > > > > different scales. That is why Janani is proposing dac nodes. Given I
> > > > > > > > > honestly don't like much of that "adi,ad5529r-bus" compatible I wondered
> > > > > > > > > about solving this at the spi level.
> > > > > > > > >
> > > > > > > > > Ah and to make it more annoying, we can also mix 12 and 16 bits variants
> > > > > > > > > together in the same bus.
> > > > > > > >
> > > > > > > > I'm definitely missing something, because that property for the
> > > > > > > > microchip devices is not impacted what else is on the bus. AFAICT, you
> > > > > > > > could have an mcp3911 and an mcp3564 on the same bus even though both
> > > > > > > > are completely different devices with different drivers. They have
> > > > > > > > individual device nodes and their own supplies etc etc. These aren't
> > > > > > > > per-channel properties on an adc or dac, they're per child device on a
> > > > > > > > spi bus.
> > > > > > >
> > > > > > > Maybe I'm the one missing something :). IIRC, spi would not allow two
> > > > > > > devices on the same CS right? Because for this chip we would need
> > > > > > > something like:
> > > > > > >
> > > > > > > spi {
> > > > > > > dac@0 {
> > > > > > > reg = <0>;
> > > > > > > adi,pin-id = <0>;
> > > > > > > };
> > > > > > >
> > > > > > > dac@1 {
> > > > > > > reg = <0>; // which seems already problematic?
> > > > > > > adi,pin-id <1>;
> > > > > > > };
> > > > > > >
> > > > > > > ...
> > > > > > >
> > > > > > > //up to 4
> > > > > > > };
> > > > > > Yeah. It's not clear to me how that works for the microchip devices
> > > > > > (I suspect it doesn't!)
> > > > > >
> > > > > > Just thinking as I type, but could we do something a bit nasty with
> > > > > > a gpio mux that doesn't actually switch but represents the GPIO being
> > > > > > shared? Given this is all tied to the spi bus that should all happen
> > > > > > under serializing locks.
> > > > > >
> > > > > > Agreed though that this would be nicer as an SPI thing that let
> > > > > > us specify that a single CS is share by multiple devices and their
> > > > > > is some other signal acting to select which one we are talking to.
> > > > > >
> > > > >
> > > > > If the device-addressing on the same chip-select is to be handled
> > > > > by the spi framework, wouldn't we lose device-specific features?
> > > > >
> > > > > I understand that this multi-device feature is there mostly to extend the
> > > > > channel count from 16 to 32, 48 or 64. I suppose the command:
> > > > >
> > > > > "MULTI DEVICE SW LDAC MODE"
> > > > >
> > > > > exists so that software can update channel values accross multiple devices.
> > > >
> > > > Right! You do have a point! I agree the main driver for a feature like
> > > > this is likely to extend the channel count and effectively "aggregate"
> > > > devices.
> > > >
> > > > But I would say that even with the spi solution the MULTI DEVICE stuff
> > > > should be doable (as we still need a sort of adi,pin-id property).
> > >
> > > I don't think we can have something like an IIO buffer shared by multiple
> > > devices. Synchronizing separate devices would be doable with proper hardware
> > > support for this (probably involving an FGPA).
> >
> > True!
> >
> > >
> > > > But yes, I do feel that the whole feature is for aggregation so seeing
> > > > one device with 32 channels is the expectation here? Rather than seeing
> > > > two devices with 16 channels.
> > >
> > > Yes, I think aggregation is the whole point there... so that the IIO driver
> > > is multi-device-aware.
> >
> > Which makes me feel that different pins per device might be possible
> > from an HW point of view but does not make much sense. For example, for
> > the buffer example I would expect LDAC to be shared between all the
> > devices.
>
> That is why I would still suggest the multi-dac node in the middle...
> the parent node can hold shared resources, while the dac children can
> have their own, overriding or inheriting stuff.
>
Before going down that path I'd want confirmation this is something we
actually think anyone will build.
Jonathan
^ 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