* Re: [PATCH v2 2/5] iio: adc: add Versal SysMon driver
[not found] ` <20260502111951.538488-3-salih.erim@amd.com>
@ 2026-05-04 17:32 ` Jonathan Cameron
2026-05-04 19:26 ` Guenter Roeck
0 siblings, 1 reply; 3+ messages in thread
From: Jonathan Cameron @ 2026-05-04 17:32 UTC (permalink / raw)
To: Salih Erim
Cc: robh, krzk+dt, conor+dt, git, nuno.sa, andy, dlechner,
michal.simek, conall.ogriofa, erimsalih, linux-iio, devicetree,
linux-kernel, Guenter Roeck, linux-hwmon
On Sat, 2 May 2026 12:19:48 +0100
Salih Erim <salih.erim@amd.com> wrote:
> Add the AMD/Xilinx Versal System Monitor (SysMon) IIO driver.
>
> The driver is split into a bus-agnostic core module
> (versal-sysmon-core) and a memory-mapped I/O platform driver
> (versal-sysmon). The core uses the regmap API so that different
> bus implementations can share the same IIO logic.
>
> The core provides:
> - Static temperature channels (current max/min, peak max/min)
> - Supply voltage channels parsed from DT container nodes
> - Temperature satellite channels parsed from DT container nodes
> - read_raw for IIO_CHAN_INFO_RAW and IIO_CHAN_INFO_PROCESSED
> - read_label using the DT label property
Various comments inline. One thing to check.
Is this one strictly a hardware monitoring device? Or does it
get used for more general ADC purposes? Did you consider an HWMON driver
for it? The above sounds a lot like hwmon. So why IIO for this one?
I wasn't awake enough on v1 to raise this! Sorry about that.
+CC Guenter and linux-hwmon for that discussion.
Thanks,
Jonathan
>
> The MMIO platform driver provides:
> - Memory-mapped register access via custom regmap callbacks
> - NPI unlock before every register write (platform management
> controller may re-lock NPI unpredictably on Versal devices)
>
> Threshold events, oversampling, and I2C bus support are added in
> subsequent patches.
>
> Co-developed-by: Michal Simek <michal.simek@amd.com>
> Signed-off-by: Michal Simek <michal.simek@amd.com>
> Signed-off-by: Salih Erim <salih.erim@amd.com>
> diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
> new file mode 100644
> index 00000000000..37736c2900b
> --- /dev/null
> +++ b/drivers/iio/adc/versal-sysmon-core.c
> @@ -0,0 +1,320 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * AMD Versal SysMon core driver
> + *
> + * Copyright (C) 2019 - 2022, Xilinx, Inc.
> + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/cleanup.h>
> +#include <linux/iio/iio.h>
> +#include <linux/module.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +#include "versal-sysmon.h"
> +
> +#define SYSMON_CHAN_TEMP(_chan, _address, _ext) { \
> + .type = IIO_TEMP, \
> + .indexed = 1, \
> + .address = _address, \
> + .channel = _chan, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> + BIT(IIO_CHAN_INFO_PROCESSED), \
Why do you need raw and processed? There are a few reasons that can show
up in a driver.
1) Non linear transforms that aren't reversable and we need to be
able to threshold on the raw.
2) History - don't copy this but some drivers used _PROCESSED and
reviewers (i.e. mostly me) weren't paying attention. We then needed
to add _raw for buffered / events and so ended up with both.
1 might apply here I guess? If so add a comment to that affect above
.info_mask_separate being assigned. I don't want this to get copied
into most drivers where things aren't non linear.
> + .scan_type = { \
> + .sign = 's', \
> + .realbits = 15, \
> + .storagebits = 16, \
> + .endianness = IIO_CPU, \
> + }, \
> + .datasheet_name = _ext, \
Can we rename _ext. We still have legacy .extended_name in here
and people might assume that is in use (definitely don't use that!)
_name or something like that instead of _ext?
> +}
> +
> +/* Static temperature channels (always present) */
> +static const struct iio_chan_spec temp_channels[] = {
> + SYSMON_CHAN_TEMP(0, SYSMON_TEMP_MAX, "temp"),
> + SYSMON_CHAN_TEMP(1, SYSMON_TEMP_MIN, "min"),
> + SYSMON_CHAN_TEMP(2, SYSMON_TEMP_MAX_MAX, "max_max"),
> + SYSMON_CHAN_TEMP(3, SYSMON_TEMP_MIN_MIN, "min_min"),
> +};
> +
> +static void sysmon_q8p7_to_millicelsius(int raw_data, int *val)
> +{
> + *val = ((s16)raw_data * SYSMON_MILLI) >> SYSMON_FRACTIONAL_SHIFT;
> +}
> +
> +static void sysmon_supply_rawtoprocessed(int raw_data, int *val)
> +{
> + int mantissa, format, exponent;
> +
> + mantissa = FIELD_GET(SYSMON_MANTISSA_MASK, raw_data);
> + exponent = SYSMON_SUPPLY_MANTISSA_BITS - FIELD_GET(SYSMON_MODE_MASK, raw_data);
> + format = FIELD_GET(SYSMON_FMT_MASK, raw_data);
> + /*
> + * When format bit is set the mantissa is two's complement
> + * (per hardware spec); sign-extend to int for correct arithmetic.
> + */
> + if (format)
> + mantissa = (int)(s16)mantissa;
> +
> + *val = (mantissa * SYSMON_MILLI) >> exponent;
> +}
> +/**
> + * sysmon_parse_fw() - Parse firmware nodes and configure IIO channels.
> + * @indio_dev: IIO device instance
> + * @dev: Parent device
> + *
> + * Reads supply-channels and temperature-channels container nodes from
> + * firmware and builds the IIO channel array. Static temperature channels
> + * are prepended, followed by supply and satellite channels from DT.
> + *
> + * Return: 0 on success, negative errno on failure.
> + */
> +static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev)
> +{
> + unsigned int idx, temp_chan_idx, volt_chan_idx;
> + struct fwnode_handle *supply_node, *temp_node;
> + unsigned int num_supply = 0, num_temp = 0;
> + struct iio_chan_spec *sysmon_channels;
> + const char *label;
> + u32 reg;
> + int ret;
> +
> + supply_node = device_get_named_child_node(dev, "supply-channels");
> + if (supply_node)
> + num_supply = fwnode_get_child_node_count(supply_node);
> +
> + temp_node = device_get_named_child_node(dev, "temperature-channels");
> + if (temp_node)
> + num_temp = fwnode_get_child_node_count(temp_node);
Once you have these using __free() look closely at the various exit points.
Most can be direct returns and as this is only called from probe() you can
use dev_err_probe() to simplify things a little.
> diff --git a/drivers/iio/adc/versal-sysmon.c b/drivers/iio/adc/versal-sysmon.c
> new file mode 100644
> index 00000000000..c597934e869
> --- /dev/null
> +++ b/drivers/iio/adc/versal-sysmon.c
> +
> +static int sysmon_platform_probe(struct platform_device *pdev)
> +{
> + struct sysmon_mmio *mmio;
> + struct regmap *regmap;
> + int irq;
> +
> + mmio = devm_kzalloc(&pdev->dev, sizeof(*mmio), GFP_KERNEL);
> + if (!mmio)
> + return -ENOMEM;
> +
> + mmio->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(mmio->base))
> + return PTR_ERR(mmio->base);
> +
> + regmap = devm_regmap_init(&pdev->dev, NULL, mmio,
> + &sysmon_mmio_regmap_config);
> + if (IS_ERR(regmap))
> + return PTR_ERR(regmap);
> +
> + irq = platform_get_irq_optional(pdev, 0);
Could you instead use fwnode_irq_get(dev_fwnode(dev), 0) in the
shared code to get this? There may be subtle differences in
handling but those will be in strange corner cases that probably
don't apply here.
> +
> + return sysmon_core_probe(&pdev->dev, regmap, irq);
> +}
> diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
> new file mode 100644
> index 00000000000..fc4d2338328
> --- /dev/null
> +++ b/drivers/iio/adc/versal-sysmon.h
> @@ -0,0 +1,69 @@
> +
> +/* Q8.7 fractional shift */
> +#define SYSMON_FRACTIONAL_SHIFT 7U
> +#define SYSMON_SUPPLY_MANTISSA_BITS 16
> +
> +/* Signed milli scale (MILLI from linux/units.h is unsigned long) */
> +#define SYSMON_MILLI 1000
Cast that one rather than defining the number again. I see you discussed
this with Andy but no conclusion reached.
> +
> +/**
> + * struct sysmon - Driver data for Versal SysMon
> + * @dev: pointer to device struct
> + * @indio_dev: pointer to the iio device (needed for work callbacks)
> + * @regmap: register map for hardware access
> + * @lock: mutex for serializing user-space access
Normally we talk about what data is protected. The comment below
is better. Also ignore checkpatch, you don't need it commented down there
- in kernel-doc is absolutely fine.
> + * @irq: interrupt number
> + */
> +struct sysmon {
> + struct device *dev;
I'm always a bit in two minds about this. You can always get the dev
from the regmap but it can be a little more ugly than strictly necessary.
See how bad it is using regmap_get_device()
> + struct iio_dev *indio_dev;
This smells backwards. Given this sysmon structure is allocated in the
private area of iio_priv() we should never need to go in this direction.
I don't think you really use this beyond one place where you can easily pass
it to. Anyhow this indio_dev pointer needs to go.
> + struct regmap *regmap;
> + /* Serializes access to device registers and state */
> + struct mutex lock;
> + int irq;
It's relatively rare to need to keep irq around after probe() and
I don't think you need to here. Just store it in a local variable
that you pass into the interrupt init functions.
> +};
> +
> +int sysmon_core_probe(struct device *dev, struct regmap *regmap, int irq);
> +
> +#endif /* _VERSAL_SYSMON_H_ */
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2 2/5] iio: adc: add Versal SysMon driver
2026-05-04 17:32 ` [PATCH v2 2/5] iio: adc: add Versal SysMon driver Jonathan Cameron
@ 2026-05-04 19:26 ` Guenter Roeck
2026-05-12 11:35 ` Salih Erim
0 siblings, 1 reply; 3+ messages in thread
From: Guenter Roeck @ 2026-05-04 19:26 UTC (permalink / raw)
To: Jonathan Cameron, Salih Erim
Cc: robh, krzk+dt, conor+dt, git, nuno.sa, andy, dlechner,
michal.simek, conall.ogriofa, erimsalih, linux-iio, devicetree,
linux-kernel, linux-hwmon
On 5/4/26 10:32, Jonathan Cameron wrote:
> On Sat, 2 May 2026 12:19:48 +0100
> Salih Erim <salih.erim@amd.com> wrote:
>
>> Add the AMD/Xilinx Versal System Monitor (SysMon) IIO driver.
>>
>> The driver is split into a bus-agnostic core module
>> (versal-sysmon-core) and a memory-mapped I/O platform driver
>> (versal-sysmon). The core uses the regmap API so that different
>> bus implementations can share the same IIO logic.
>>
>> The core provides:
>> - Static temperature channels (current max/min, peak max/min)
>> - Supply voltage channels parsed from DT container nodes
>> - Temperature satellite channels parsed from DT container nodes
>> - read_raw for IIO_CHAN_INFO_RAW and IIO_CHAN_INFO_PROCESSED
>> - read_label using the DT label property
>
> Various comments inline. One thing to check.
> Is this one strictly a hardware monitoring device? Or does it
> get used for more general ADC purposes? Did you consider an HWMON driver
> for it? The above sounds a lot like hwmon. So why IIO for this one?
>
> I wasn't awake enough on v1 to raise this! Sorry about that.
> +CC Guenter and linux-hwmon for that discussion.
>
This very much sounds like a hardware monitoring device to me.
Guenter
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2 2/5] iio: adc: add Versal SysMon driver
2026-05-04 19:26 ` Guenter Roeck
@ 2026-05-12 11:35 ` Salih Erim
0 siblings, 0 replies; 3+ messages in thread
From: Salih Erim @ 2026-05-12 11:35 UTC (permalink / raw)
To: Guenter Roeck, Jonathan Cameron
Cc: robh, krzk+dt, conor+dt, git, nuno.sa, andy, dlechner,
michal.simek, conall.ogriofa, erimsalih, linux-iio, devicetree,
linux-kernel, linux-hwmon
Hi Guenter and Jonathan,
On 5/4/2026 8:26 PM, Guenter Roeck wrote:
>
>
> On 5/4/26 10:32, Jonathan Cameron wrote:
>> On Sat, 2 May 2026 12:19:48 +0100
>> Salih Erim <salih.erim@amd.com> wrote:
>>
>>> Add the AMD/Xilinx Versal System Monitor (SysMon) IIO driver.
>>>
>>> The driver is split into a bus-agnostic core module
>>> (versal-sysmon-core) and a memory-mapped I/O platform driver
>>> (versal-sysmon). The core uses the regmap API so that different
>>> bus implementations can share the same IIO logic.
>>>
>>> The core provides:
>>> - Static temperature channels (current max/min, peak max/min)
>>> - Supply voltage channels parsed from DT container nodes
>>> - Temperature satellite channels parsed from DT container nodes
>>> - read_raw for IIO_CHAN_INFO_RAW and IIO_CHAN_INFO_PROCESSED
>>> - read_label using the DT label property
>>
>> Various comments inline. One thing to check.
>> Is this one strictly a hardware monitoring device? Or does it
>> get used for more general ADC purposes? Did you consider an HWMON driver
>> for it? The above sounds a lot like hwmon. So why IIO for this one?
>>
>> I wasn't awake enough on v1 to raise this! Sorry about that.
>> +CC Guenter and linux-hwmon for that discussion.
>>
>
> This very much sounds like a hardware monitoring device to me.
The device is indeed used for hardware monitoring, but the hardware
characteristics push it towards IIO:
- The predecessor (Zynq UltraScale+ AMS, xilinx-ams.c) is already
in drivers/iio/adc/ upstream. This driver is the direct successor
for the Versal generation.
- The supply voltage encoding is a modified floating-point format
with per-register exponent and format bits. This non-linear
encoding doesn't map well to hwmon's linear in*_input model.
- The device has configurable threshold events with per-channel
alarm registers, hysteresis bits, and level-sensitive interrupt
masking/unmasking -- which maps directly to the IIO event
infrastructure.
- Oversampling is hardware-configurable per channel type with
per-channel averaging enable registers.
- Up to 160 voltage and 64 temperature channels are dynamically
configured from DT, which fits IIO's dynamic channel model
better than hwmon's compile-time attribute groups.
- The follow-up thermal driver uses the IIO consumer API
(iio_channel_read) to aggregate temperature data across
multiple satellites into thermal zones. The iio-hwmon bridge
then exposes the same data to hwmon userspace.
So the architecture is: IIO driver (provider) -> iio-hwmon bridge
(hwmon exposure) + IIO consumer (thermal zones). This gives both
hwmon and thermal framework access through a single IIO provider.
>
> Guenter
>
Salih.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-05-12 11:35 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260502111951.538488-1-salih.erim@amd.com>
[not found] ` <20260502111951.538488-3-salih.erim@amd.com>
2026-05-04 17:32 ` [PATCH v2 2/5] iio: adc: add Versal SysMon driver Jonathan Cameron
2026-05-04 19:26 ` Guenter Roeck
2026-05-12 11:35 ` Salih Erim
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox