mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
iio: adc: add Versal SysMon driver
Add the core driver and MMIO platform driver for the AMD/Xilinx Versal System Monitor (SysMon) block. The SysMon block resides in the platform management controller (PMC) and provides on-chip voltage and temperature monitoring through a 10-bit, 200 kSPS ADC. It can monitor up to 160 voltage channels and 64 temperature satellites distributed across the SoC, with a consistent sample rate of 8 kSPS per channel regardless of how many channels are enabled. The hardware also provides four aggregate temperature registers that are always present regardless of the device tree configuration: the current max and min across all active satellites, and the peak and trough values recorded since the last hardware reset. The driver is split into two compilation units: - versal-sysmon-core: Channel parsing, IIO registration, read_raw - versal-sysmon: MMIO platform driver with custom regmap accessors Voltage results are stored in a 19-bit modified floating-point format and converted to millivolts. Temperature results are stored in Q8.7 signed fixed-point Celsius format and converted to millicelsius. The MMIO regmap backend uses a custom reg_write accessor that automatically unlocks the NPI (NoC programming interface) lock register before each write, as required by the hardware. The regmap is configured with fast_io since the underlying MMIO accessors are safe to call from atomic context. 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> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
parent
bb6ea868b8
commit
50bf4fd85b
|
|
@ -29627,6 +29627,14 @@ F: Documentation/devicetree/bindings/memory-controllers/xlnx,versal-net-ddrmc5.y
|
|||
F: drivers/edac/versalnet_edac.c
|
||||
F: include/linux/cdx/edac_cdx_pcol.h
|
||||
|
||||
XILINX VERSAL SYSMON DRIVER
|
||||
M: Salih Erim <salih.erim@amd.com>
|
||||
M: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml
|
||||
F: drivers/iio/adc/versal-sysmon*
|
||||
|
||||
XILINX WATCHDOG DRIVER
|
||||
M: Srinivas Neeli <srinivas.neeli@amd.com>
|
||||
R: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
|
||||
|
|
|
|||
|
|
@ -1973,6 +1973,26 @@ config TWL6030_GPADC
|
|||
This driver can also be built as a module. If so, the module will be
|
||||
called twl6030-gpadc.
|
||||
|
||||
config VERSAL_SYSMON_CORE
|
||||
tristate
|
||||
select REGMAP
|
||||
|
||||
config VERSAL_SYSMON
|
||||
tristate "AMD Versal SysMon driver"
|
||||
depends on ARCH_ZYNQMP || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
select VERSAL_SYSMON_CORE
|
||||
help
|
||||
Say yes here to have support for the AMD/Xilinx Versal System
|
||||
Monitor (SysMon). This driver provides voltage and temperature
|
||||
monitoring through the IIO subsystem.
|
||||
|
||||
The SysMon measures up to 160 supply voltages and reads up to
|
||||
64 temperature satellites distributed across the SoC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called versal-sysmon.
|
||||
|
||||
config VF610_ADC
|
||||
tristate "Freescale vf610 ADC driver"
|
||||
depends on HAS_IOMEM
|
||||
|
|
|
|||
|
|
@ -169,6 +169,8 @@ obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
|
|||
obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o
|
||||
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
|
||||
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
|
||||
obj-$(CONFIG_VERSAL_SYSMON_CORE) += versal-sysmon-core.o
|
||||
obj-$(CONFIG_VERSAL_SYSMON) += versal-sysmon.o
|
||||
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
|
||||
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
|
||||
obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o
|
||||
|
|
|
|||
292
drivers/iio/adc/versal-sysmon-core.c
Normal file
292
drivers/iio/adc/versal-sysmon-core.c
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
// 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/array_size.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#include "versal-sysmon.h"
|
||||
|
||||
#define SYSMON_CHAN_TEMP(_chan, _address, _name) \
|
||||
{ \
|
||||
.type = IIO_TEMP, \
|
||||
.indexed = 1, \
|
||||
.address = _address, \
|
||||
.channel = _chan, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.datasheet_name = _name, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Static temperature channels (always present).
|
||||
*
|
||||
* These are hardware-computed aggregate registers across all active
|
||||
* temperature satellites:
|
||||
* temp: current max temperature across all active satellites
|
||||
* min: current min temperature across all active satellites
|
||||
* max_max: highest peak recorded since last hardware reset
|
||||
* min_min: lowest trough recorded since last hardware reset
|
||||
*/
|
||||
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_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 = sign_extend32(mantissa, 15);
|
||||
|
||||
*val = (mantissa * (int)MILLI) >> exponent;
|
||||
}
|
||||
|
||||
static int sysmon_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct sysmon *sysmon = iio_priv(indio_dev);
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&sysmon->lock);
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
if (mask == IIO_CHAN_INFO_SCALE) {
|
||||
/* Q8.7 to millicelsius: raw * 1000 / 128 */
|
||||
*val = MILLIDEGREE_PER_DEGREE;
|
||||
*val2 = BIT(SYSMON_FRACTIONAL_SHIFT);
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
}
|
||||
if (mask != IIO_CHAN_INFO_RAW)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_read(sysmon->regmap, chan->address, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = sign_extend32(regval, 15);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_VOLTAGE:
|
||||
if (mask != IIO_CHAN_INFO_PROCESSED)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_read(sysmon->regmap,
|
||||
chan->address * SYSMON_REG_STRIDE +
|
||||
SYSMON_SUPPLY_BASE, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sysmon_supply_rawtoprocessed(regval, val);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int sysmon_read_label(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
char *label)
|
||||
{
|
||||
if (chan->datasheet_name)
|
||||
return sysfs_emit(label, "%s\n", chan->datasheet_name);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info sysmon_iio_info = {
|
||||
.read_raw = sysmon_read_raw,
|
||||
.read_label = sysmon_read_label,
|
||||
};
|
||||
|
||||
/**
|
||||
* sysmon_parse_fw() - Parse firmware nodes and configure IIO channels.
|
||||
* @indio_dev: IIO device instance
|
||||
* @dev: Parent device
|
||||
*
|
||||
* Reads voltage-channels and temperature-channels container nodes from
|
||||
* firmware and builds the IIO channel array. Static temperature channels
|
||||
* are prepended, followed by supply and satellite channels from DT.
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure.
|
||||
*/
|
||||
static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev)
|
||||
{
|
||||
unsigned int num_chan, num_static, num_supply, num_temp;
|
||||
unsigned int idx, temp_chan_idx, volt_chan_idx;
|
||||
struct iio_chan_spec *sysmon_channels;
|
||||
const char *label;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
struct fwnode_handle *supply_node __free(fwnode_handle) =
|
||||
device_get_named_child_node(dev, "voltage-channels");
|
||||
num_supply = fwnode_get_child_node_count(supply_node);
|
||||
|
||||
struct fwnode_handle *temp_node __free(fwnode_handle) =
|
||||
device_get_named_child_node(dev, "temperature-channels");
|
||||
num_temp = fwnode_get_child_node_count(temp_node);
|
||||
|
||||
num_static = ARRAY_SIZE(temp_channels);
|
||||
num_chan = size_add(num_temp, size_add(num_static, num_supply));
|
||||
sysmon_channels = devm_kcalloc(dev, num_chan, sizeof(*sysmon_channels), GFP_KERNEL);
|
||||
if (!sysmon_channels)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Static temperature channels first */
|
||||
memcpy(sysmon_channels, temp_channels, sizeof(temp_channels));
|
||||
idx = num_static;
|
||||
|
||||
/* Supply channels from DT */
|
||||
fwnode_for_each_child_node_scoped(supply_node, child) {
|
||||
ret = fwnode_property_read_u32(child, "reg", ®);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"missing reg for supply channel\n");
|
||||
|
||||
if (reg > SYSMON_SUPPLY_IDX_MAX)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"supply reg %u exceeds max %u\n",
|
||||
reg, SYSMON_SUPPLY_IDX_MAX);
|
||||
|
||||
ret = fwnode_property_read_string(child, "label", &label);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"missing label for supply channel\n");
|
||||
|
||||
sysmon_channels[idx++] = (struct iio_chan_spec) {
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.address = reg,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
.datasheet_name = label,
|
||||
};
|
||||
}
|
||||
|
||||
/* Temperature satellite channels from DT */
|
||||
fwnode_for_each_child_node_scoped(temp_node, child) {
|
||||
ret = fwnode_property_read_u32(child, "reg", ®);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"missing reg for temp channel\n");
|
||||
|
||||
if (reg < 1 || reg > SYSMON_TEMP_SAT_MAX)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"temp reg %u out of range [1..%u]\n",
|
||||
reg, SYSMON_TEMP_SAT_MAX);
|
||||
|
||||
ret = fwnode_property_read_string(child, "label", &label);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"missing label for temp channel\n");
|
||||
|
||||
sysmon_channels[idx++] = (struct iio_chan_spec) {
|
||||
.type = IIO_TEMP,
|
||||
.indexed = 1,
|
||||
.address = SYSMON_TEMP_SAT_BASE +
|
||||
(reg - 1) * SYSMON_REG_STRIDE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
|
||||
.datasheet_name = label,
|
||||
};
|
||||
}
|
||||
|
||||
indio_dev->num_channels = idx;
|
||||
indio_dev->info = &sysmon_iio_info;
|
||||
|
||||
/*
|
||||
* Assign per-type sequential channel numbers.
|
||||
* IIO sysfs uses type prefix (in_tempN, in_voltageN)
|
||||
* so numbers only need to be unique within each type.
|
||||
*/
|
||||
temp_chan_idx = 0;
|
||||
volt_chan_idx = 0;
|
||||
for (unsigned int idx = 0; idx < indio_dev->num_channels; idx++) {
|
||||
if (sysmon_channels[idx].type == IIO_TEMP)
|
||||
sysmon_channels[idx].channel = temp_chan_idx++;
|
||||
else
|
||||
sysmon_channels[idx].channel = volt_chan_idx++;
|
||||
}
|
||||
|
||||
indio_dev->channels = sysmon_channels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_versal_sysmon_core_probe() - Initialize Versal SysMon core
|
||||
* @dev: Parent device
|
||||
* @regmap: Register map for hardware access
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure.
|
||||
*/
|
||||
int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct sysmon *sysmon;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*sysmon));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
sysmon = iio_priv(indio_dev);
|
||||
sysmon->regmap = regmap;
|
||||
|
||||
ret = devm_mutex_init(dev, &sysmon->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable all interrupts and clear pending status */
|
||||
ret = regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_write(sysmon->regmap, SYSMON_ISR, SYSMON_INTR_ALL_MASK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->name = "versal-sysmon";
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = sysmon_parse_fw(indio_dev, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(devm_versal_sysmon_core_probe, "VERSAL_SYSMON");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("AMD Versal SysMon Core Driver");
|
||||
MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
|
||||
92
drivers/iio/adc/versal-sysmon.c
Normal file
92
drivers/iio/adc/versal-sysmon.c
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* AMD Versal SysMon MMIO platform driver
|
||||
*
|
||||
* Copyright (C) 2019 - 2022, Xilinx, Inc.
|
||||
* Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "versal-sysmon.h"
|
||||
|
||||
struct sysmon_mmio {
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static int sysmon_mmio_reg_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct sysmon_mmio *mmio = context;
|
||||
|
||||
*val = readl(mmio->base + reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sysmon_mmio_reg_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct sysmon_mmio *mmio = context;
|
||||
|
||||
/* NPI must be unlocked before any register write except to NPI_LOCK */
|
||||
if (reg != SYSMON_NPI_LOCK)
|
||||
writel(SYSMON_NPI_UNLOCK_CODE, mmio->base + SYSMON_NPI_LOCK);
|
||||
writel(val, mmio->base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config sysmon_mmio_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = SYSMON_REG_STRIDE,
|
||||
.max_register = SYSMON_MAX_REG,
|
||||
.reg_read = sysmon_mmio_reg_read,
|
||||
.reg_write = sysmon_mmio_reg_write,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static int sysmon_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sysmon_mmio *mmio;
|
||||
struct regmap *regmap;
|
||||
|
||||
mmio = devm_kzalloc(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(dev, NULL, mmio, &sysmon_mmio_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return devm_versal_sysmon_core_probe(dev, regmap);
|
||||
}
|
||||
|
||||
static const struct of_device_id sysmon_of_match_table[] = {
|
||||
{ .compatible = "xlnx,versal-sysmon" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sysmon_of_match_table);
|
||||
|
||||
static struct platform_driver sysmon_platform_driver = {
|
||||
.probe = sysmon_platform_probe,
|
||||
.driver = {
|
||||
.name = "versal-sysmon",
|
||||
.of_match_table = sysmon_of_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(sysmon_platform_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("AMD Versal SysMon Platform Driver");
|
||||
MODULE_IMPORT_NS("VERSAL_SYSMON");
|
||||
MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
|
||||
67
drivers/iio/adc/versal-sysmon.h
Normal file
67
drivers/iio/adc/versal-sysmon.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* AMD Versal SysMon driver
|
||||
*
|
||||
* Copyright (C) 2019 - 2022, Xilinx, Inc.
|
||||
* Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _VERSAL_SYSMON_H_
|
||||
#define _VERSAL_SYSMON_H_
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
struct device;
|
||||
struct regmap;
|
||||
|
||||
/* Register offsets (sorted by address) */
|
||||
#define SYSMON_NPI_LOCK 0x000C
|
||||
#define SYSMON_ISR 0x0044
|
||||
#define SYSMON_IDR 0x0050
|
||||
#define SYSMON_TEMP_MAX 0x1030
|
||||
#define SYSMON_TEMP_MIN 0x1034
|
||||
#define SYSMON_SUPPLY_BASE 0x1040
|
||||
#define SYSMON_TEMP_MIN_MIN 0x1F8C
|
||||
#define SYSMON_TEMP_MAX_MAX 0x1F90
|
||||
#define SYSMON_TEMP_SAT_BASE 0x1FAC
|
||||
#define SYSMON_MAX_REG 0x24C0
|
||||
|
||||
/* NPI unlock value written to SYSMON_NPI_LOCK */
|
||||
#define SYSMON_NPI_UNLOCK_CODE 0xF9E8D7C6
|
||||
|
||||
/* Register stride: 4 bytes per 32-bit register */
|
||||
#define SYSMON_REG_STRIDE 4
|
||||
|
||||
#define SYSMON_SUPPLY_IDX_MAX 159
|
||||
#define SYSMON_TEMP_SAT_MAX 64
|
||||
#define SYSMON_INTR_ALL_MASK GENMASK(31, 0)
|
||||
|
||||
/* Supply voltage conversion register fields */
|
||||
#define SYSMON_MANTISSA_MASK GENMASK(15, 0)
|
||||
#define SYSMON_FMT_MASK BIT(16)
|
||||
#define SYSMON_MODE_MASK GENMASK(18, 17)
|
||||
|
||||
/* Q8.7 fractional shift */
|
||||
#define SYSMON_FRACTIONAL_SHIFT 7U
|
||||
#define SYSMON_SUPPLY_MANTISSA_BITS 16
|
||||
|
||||
/**
|
||||
* struct sysmon - Driver data for Versal SysMon
|
||||
* @regmap: register map for hardware access
|
||||
* @lock: protects read-modify-write sequences on threshold registers
|
||||
* and cached state that spans multiple regmap calls
|
||||
*/
|
||||
struct sysmon {
|
||||
struct regmap *regmap;
|
||||
/*
|
||||
* Protects read-modify-write sequences on threshold registers
|
||||
* and cached state (oversampling ratios, hysteresis values)
|
||||
* that spans multiple regmap calls.
|
||||
*/
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
#endif /* _VERSAL_SYSMON_H_ */
|
||||
Loading…
Reference in New Issue
Block a user