From 0ecd86d24ed135b2fdb0b66369965602b8bc7969 Mon Sep 17 00:00:00 2001 From: Marilene A Garcia Date: Sun, 29 Jun 2025 17:56:40 -0300 Subject: [PATCH 1/5] iio: adc: Add initial driver support for MAX14001/MAX14002 The MAX14001/MAX14002 are configurable, isolated 10-bit ADCs for multi-range binary inputs. Datasheet: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf Signed-off-by: Marilene A Garcia --- arch/arm/boot/dts/overlays/Makefile | 1 + .../dts/overlays/rpi-max14001-overlay.dts | 35 +++ drivers/iio/adc/Kconfig | 10 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/max14001.c | 268 ++++++++++++++++++ 5 files changed, 315 insertions(+) create mode 100644 arch/arm/boot/dts/overlays/rpi-max14001-overlay.dts create mode 100644 drivers/iio/adc/max14001.c diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index a9fa5cc30d63fe..a6371122a43a63 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -309,6 +309,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ rpi-ltc2991.dtbo \ rpi-ltc4162.dtbo \ rpi-ltc6952.dtbo \ + rpi-max14001.dtbo \ rpi-max14830-i2c.dtbo \ rpi-max14830-spi.dtbo \ rpi-max31335.dtbo \ diff --git a/arch/arm/boot/dts/overlays/rpi-max14001-overlay.dts b/arch/arm/boot/dts/overlays/rpi-max14001-overlay.dts new file mode 100644 index 00000000000000..4a5e5bb56f3162 --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-max14001-overlay.dts @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Overlay for the MAX14001 ADC + * + * Copyright (c) 2025 Marilene Andrade Garcia + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2712"; + + vdd: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + status = "okay"; + }; +}; + +&spi0 { + status = "okay"; + max14001: max14001@0 { + compatible = "max14001"; + reg = <0>; + spi-max-frequency = <5000000>; + status = "okay"; + }; +}; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index d3d12ed064e50f..22b348bb675a87 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1126,6 +1126,16 @@ config MAX1363 To compile this driver as a module, choose M here: the module will be called max1363. +config MAX14001 + tristate "Analog Devices MAX14001/MAX14002 ADCs driver" + depends on SPI + help + Say yes here to build support for Analog Devices MAX14001/MAX14002 + Configurable, Isolated 10-bit ADCs for Multi-Range Binary Inputs. + + To compile this driver as a module, choose M here: the module will be + called max14001. + config MAX77541_ADC tristate "Analog Devices MAX77541 ADC driver" depends on MFD_MAX77541 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 6a71631c984217..bc4c6d7a57dd9a 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -156,6 +156,7 @@ obj-$(CONFIG_MAX11205) += max11205.o obj-$(CONFIG_MAX11410) += max11410.o obj-$(CONFIG_MAX1241) += max1241.o obj-$(CONFIG_MAX1363) += max1363.o +obj-$(CONFIG_MAX14001) += max14001.o obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o obj-$(CONFIG_MAX9611) += max9611.o obj-$(CONFIG_MCP320X) += mcp320x.o diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c new file mode 100644 index 00000000000000..0bf58cb38c8f86 --- /dev/null +++ b/drivers/iio/adc/max14001.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MAX14001/MAX14002 SPI ADC driver + * + * Copyright (c) 2025 Marilene Andrade Garcia + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +/* MAX14001 registers definition */ +#define MAX14001_REG_ADC 0x00 +#define MAX14001_REG_FADC 0x01 +#define MAX14001_REG_FLAGS 0x02 +#define MAX14001_REG_FLTEN 0x03 +#define MAX14001_REG_THL 0x04 +#define MAX14001_REG_THU 0x05 +#define MAX14001_REG_INRR 0x06 +#define MAX14001_REG_INRT 0x07 +#define MAX14001_REG_INRP 0x08 +#define MAX14001_REG_CFG 0x09 +#define MAX14001_REG_ENBL 0x0A +#define MAX14001_REG_ACT 0x0B +#define MAX14001_REG_WEN 0x0C + +/* MAX14001 verification registers definition */ +#define MAX14001_REG_VERIFICATION(x) (0x10 + (x)) +#define MAX14001_REG_FLTV 0x13 +#define MAX14001_REG_THLV 0x14 +#define MAX14001_REG_THUV 0x15 +#define MAX14001_REG_INRRV 0x16 +#define MAX14001_REG_INRTV 0x17 +#define MAX14001_REG_INRPV 0x18 +#define MAX14001_REG_CFGV 0x19 +#define MAX14001_REG_ENBLV 0x1A + +/* MAX14001 CONTROL values*/ +#define MAX14001_REG_WRITE 0x1 +#define MAX14001_REG_READ 0x0 + +/* MAX14001 MASKS */ +#define MAX14001_MASK_ADDR GENMASK(15, 11) +#define MAX14001_MASK_WR BIT(10) +#define MAX14001_MASK_DATA GENMASK(9, 0) + +/* MAX14001_REG_FLAGS MASKS */ +#define MAX14001_MASK_FLAGS_ADC BIT(1) +#define MAX14001_MASK_FLAGS_INRD BIT(2) +#define MAX14001_MASK_FLAGS_SPI BIT(3) +#define MAX14001_MASK_FLAGS_COM BIT(4) +#define MAX14001_MASK_FLAGS_CRCL BIT(5) +#define MAX14001_MASK_FLAGS_CRCF BIT(6) +#define MAX14001_MASK_FLAGS_FET BIT(7) +#define MAX14001_MASK_FLAGS_MV BIT(8) + +/* MAX14001_REG_FLTEN MASKS */ +#define MAX14001_MASK_FLTEN_DYEN BIT(0) +#define MAX14001_MASK_FLTEN_EADC BIT(1) +#define MAX14001_MASK_FLTEN_EINRD BIT(2) +#define MAX14001_MASK_FLTEN_ESPI BIT(3) +#define MAX14001_MASK_FLTEN_ECOM BIT(4) +#define MAX14001_MASK_FLTEN_ECRCL BIT(5) +#define MAX14001_MASK_FLTEN_ECRCF BIT(6) +#define MAX14001_MASK_FLTEN_EFET BIT(7) +#define MAX14001_MASK_FLTEN_EMV BIT(8) + +/* MAX14001_REG_WEN values*/ +#define MAX14001_REG_WEN_WRITE_ENABLE 0x294 +#define MAX14001_REG_WEN_WRITE_DISABLE 0x0 + +enum max14001_chips { + max14001, + max14002, +}; + +struct max14001_state { + struct spi_device *spi; +}; + +static int max14001_spi_read(struct max14001_state *st, u16 reg, u16 *val) +{ + u16 tx = 0; + u16 rx = 0; + u16 reversed = 0; + int ret = 0; + + pr_err("[Log Debug] max14001_spi_read: reg: %x, val: %x\n", reg, *val); + + tx |= FIELD_PREP(MAX14001_MASK_ADDR, reg); + tx |= FIELD_PREP(MAX14001_MASK_WR, MAX14001_REG_READ); + reversed = bitrev16(tx); + + ret = spi_write_then_read(st->spi, &reversed, 2, &rx, 2); + if (ret < 0) + return ret; + + reversed = bitrev16(be16_to_cpu(rx)); + *val = MAX14001_MASK_ADDR&reversed; + + return ret; +} + +static int max14001_spi_write(struct max14001_state *st, u16 reg, u16 val) +{ + u16 tx = 0; + u16 msg = 0; + u16 reversed = 0; + int ret = 0; + + pr_err("[Log Debug] max14001_spi_write: reg: %x, val: %x\n", reg, val); + + struct spi_transfer xfer = { + .tx_buf = NULL, + .len = 0, + }; + + msg |= FIELD_PREP(MAX14001_MASK_ADDR, reg); + msg |= FIELD_PREP(MAX14001_MASK_WR, MAX14001_REG_WRITE); + msg |= FIELD_PREP(MAX14001_MASK_DATA, val); + + reversed = bitrev16(msg); + put_unaligned_be16(reversed, &tx); + + xfer.tx_buf = &tx; + xfer.len = sizeof(tx); + + pr_err("[Log Debug] max14001_spi_write: msg: %x, tx: %x\n", msg, tx); + + ret = spi_sync_transfer(st->spi, &xfer, 1); + if (ret < 0) + return ret; + + return ret; +} + +static int max14001_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max14001_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + pr_err("[Log Debug] max14001_read_raw: IIO_CHAN_INFO_RAW\n"); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + pr_err("[Log Debug] max14001_read_raw: IIO_CHAN_INFO_SCALE\n"); + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int max14001_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct max14001_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + pr_err("[Log Debug] max14001_write_raw: IIO_CHAN_INFO_RAW\n"); + return 0; + } + + return -EINVAL; +} + +static const struct iio_info max14001_info = { + .read_raw = max14001_read_raw, + .write_raw = max14001_write_raw, +}; + +static const struct iio_chan_spec max14001_channel_voltage[] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .output = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static const struct iio_chan_spec max14001_channel_current[] = { + { + .type = IIO_CURRENT, + .indexed = 1, + .channel = 0, + .output = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static int max14001_probe(struct spi_device *spi) +{ + pr_err("[Log Debug] max14001_probe\n"); + + struct max14001_state *st; + struct iio_dev *indio_dev; + bool current_channel = false; + 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; + + indio_dev->name = "max14001"; //spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &max14001_info; + + for_each_available_child_of_node_scoped(spi->dev.of_node, child) { + current_channel = of_property_read_bool(child, "current-channel"); + if (current_channel) + break; + } + + if (current_channel) { + indio_dev->channels = max14001_channel_current; + indio_dev->num_channels = ARRAY_SIZE(max14001_channel_current); + } else { + indio_dev->channels = max14001_channel_voltage; + indio_dev->num_channels = ARRAY_SIZE(max14001_channel_voltage); + } + + //Enable register write + max14001_spi_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_WRITE_ENABLE); + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id max14001_id_table[] = { + { "max14001", max14001 }, + { "max14002", max14002 }, + {} +}; +MODULE_DEVICE_TABLE(spi, max14001_id_table); + +static const struct of_device_id max14001_of_match[] = { + { .compatible = "adi,max14001" }, + { .compatible = "adi,max14002" }, + {} +}; +MODULE_DEVICE_TABLE(of, max14001_of_match); + +static struct spi_driver max14001_driver = { + .driver = { + .name = "max14001", + .of_match_table = max14001_of_match, + }, + .probe = max14001_probe, + .id_table = max14001_id_table, +}; +module_spi_driver(max14001_driver); + +MODULE_AUTHOR("Marilene Andrade Garcia "); +MODULE_DESCRIPTION("Analog Devices MAX14001/MAX14002 ADCs driver"); +MODULE_LICENSE("GPL v2"); \ No newline at end of file From b45131977d4060910e4b109eaf59cfc888a40dc5 Mon Sep 17 00:00:00 2001 From: Marilene A Garcia Date: Sun, 20 Jul 2025 12:02:48 -0300 Subject: [PATCH 2/5] iio: adc: Improve initial drive features for MAX14001/MAX14002 - Update the ovelay file to reflect the evaluation board name - Add Vddl and Vrefin regulators to the overlay file - Update the log print methods - Remove unnecessary code - Improve code style - Add chip_info struct - Add max14001_spi_write_single_reg method, which enables and disables the write register when writing data to another register Signed-off-by: Marilene A Garcia --- arch/arm/boot/dts/overlays/Makefile | 2 +- .../dts/overlays/rpi-max14001-overlay.dts | 35 ------ .../dts/overlays/rpi-max14001-pmb-overlay.dts | 68 ++++++++++++ drivers/iio/adc/max14001.c | 105 ++++++++++++------ 4 files changed, 140 insertions(+), 70 deletions(-) delete mode 100644 arch/arm/boot/dts/overlays/rpi-max14001-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index a6371122a43a63..d34acec61e0399 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -309,7 +309,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ rpi-ltc2991.dtbo \ rpi-ltc4162.dtbo \ rpi-ltc6952.dtbo \ - rpi-max14001.dtbo \ + rpi-max14001-pmb.dtbo \ rpi-max14830-i2c.dtbo \ rpi-max14830-spi.dtbo \ rpi-max31335.dtbo \ diff --git a/arch/arm/boot/dts/overlays/rpi-max14001-overlay.dts b/arch/arm/boot/dts/overlays/rpi-max14001-overlay.dts deleted file mode 100644 index 4a5e5bb56f3162..00000000000000 --- a/arch/arm/boot/dts/overlays/rpi-max14001-overlay.dts +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Overlay for the MAX14001 ADC - * - * Copyright (c) 2025 Marilene Andrade Garcia - * - * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf - */ - -/dts-v1/; -/plugin/; - -/ { - compatible = "brcm,bcm2712"; - - vdd: fixedregulator@0 { - compatible = "regulator-fixed"; - regulator-name = "fixed-supply"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - enable-active-high; - status = "okay"; - }; -}; - -&spi0 { - status = "okay"; - max14001: max14001@0 { - compatible = "max14001"; - reg = <0>; - spi-max-frequency = <5000000>; - status = "okay"; - }; -}; diff --git a/arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts b/arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts new file mode 100644 index 00000000000000..a13fa54232eae1 --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Overlay for the MAX14001 ADC + * + * Copyright (c) 2025 Marilene Andrade Garcia + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2712"; + + vdd: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "Isolated DC-DC Power Supply Input Voltage"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + status = "okay"; + }; + + vddl: fixedregulator@1 { + compatible = "regulator-fixed"; + regulator-name = "Logic Power Supply Voltage"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + status = "okay"; + }; + + vrefin: fixedregulator@2 { + compatible = "regulator-fixed"; + regulator-name = "Reference Input Range Voltage"; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1250000>; + regulator-boot-on; + enable-active-high; + status = "okay"; + }; +}; + +&spi0 { + status = "okay"; + max14001_voltage_channel: max14001@0 { + compatible = "max14001"; + reg = <0x0>; + spi-max-frequency = <5000000>; + vdd-supply = <&vdd>; + vddl-supply = <&vddl>; + vrefin-supply = <&vrefin>; + status = "okay"; + }; + max14001_current_channel: max14001@1 { + compatible = "max14001"; + reg = <0x1>; + spi-max-frequency = <5000000>; + current-channel; + vdd-supply = <&vdd>; + vddl-supply = <&vddl>; + vrefin-supply = <&vrefin>; + status = "okay"; + }; +}; diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c index 0bf58cb38c8f86..208c5241e4842e 100644 --- a/drivers/iio/adc/max14001.c +++ b/drivers/iio/adc/max14001.c @@ -75,23 +75,36 @@ #define MAX14001_REG_WEN_WRITE_ENABLE 0x294 #define MAX14001_REG_WEN_WRITE_DISABLE 0x0 -enum max14001_chips { +enum max14001_chip_model { max14001, max14002, }; +struct max14001_chip_info { + const char *name; + /* TODO: Add more information */ +}; + +static struct max14001_chip_info max14001_chip_info_tbl[] = { + [max14001] = { + .name = "max14001", + }, + [max14002] = { + .name = "max14002", + }, +}; + struct max14001_state { struct spi_device *spi; + const struct max14001_chip_info *chip_info; }; static int max14001_spi_read(struct max14001_state *st, u16 reg, u16 *val) { - u16 tx = 0; - u16 rx = 0; - u16 reversed = 0; - int ret = 0; + u16 tx, rx, reversed; + int ret; - pr_err("[Log Debug] max14001_spi_read: reg: %x, val: %x\n", reg, *val); + dev_info(&st->spi->dev, "%s: reg: %x, val: %x\n", __func__, reg, *val); tx |= FIELD_PREP(MAX14001_MASK_ADDR, reg); tx |= FIELD_PREP(MAX14001_MASK_WR, MAX14001_REG_READ); @@ -101,37 +114,34 @@ static int max14001_spi_read(struct max14001_state *st, u16 reg, u16 *val) if (ret < 0) return ret; + /* TODO: Validate this line in the hw, could be le16_to_cpu */ reversed = bitrev16(be16_to_cpu(rx)); - *val = MAX14001_MASK_ADDR&reversed; + *val = FIELD_GET(MAX14001_MASK_ADDR, reversed); return ret; } static int max14001_spi_write(struct max14001_state *st, u16 reg, u16 val) { - u16 tx = 0; + struct spi_transfer xfer; + int ret; + u16 tx, reversed; u16 msg = 0; - u16 reversed = 0; - int ret = 0; - pr_err("[Log Debug] max14001_spi_write: reg: %x, val: %x\n", reg, val); - - struct spi_transfer xfer = { - .tx_buf = NULL, - .len = 0, - }; + dev_info(&st->spi->dev, "%s: reg: %x, val: %x\n", __func__, reg, val); msg |= FIELD_PREP(MAX14001_MASK_ADDR, reg); msg |= FIELD_PREP(MAX14001_MASK_WR, MAX14001_REG_WRITE); msg |= FIELD_PREP(MAX14001_MASK_DATA, val); reversed = bitrev16(msg); + /* TODO: Validate this line in the hw, could be put_unaligned_le16 */ put_unaligned_be16(reversed, &tx); xfer.tx_buf = &tx; xfer.len = sizeof(tx); - pr_err("[Log Debug] max14001_spi_write: msg: %x, tx: %x\n", msg, tx); + dev_info(&st->spi->dev, "%s: msg: %x, tx: %x\n", __func__, msg, tx); ret = spi_sync_transfer(st->spi, &xfer, 1); if (ret < 0) @@ -140,6 +150,28 @@ static int max14001_spi_write(struct max14001_state *st, u16 reg, u16 val) return ret; } +static int max14001_spi_write_single_reg(struct max14001_state *st, u16 reg, u16 val) +{ + int ret; + + //Enable register write + ret = max14001_spi_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_WRITE_ENABLE); + if (ret < 0) + return ret; + + //Write data into register + ret = max14001_spi_write(st, reg, val); + if (ret < 0) + return ret; + + //Disable register write + ret = max14001_spi_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_WRITE_DISABLE); + if (ret < 0) + return ret; + + return ret; +} + static int max14001_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -148,16 +180,17 @@ static int max14001_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - pr_err("[Log Debug] max14001_read_raw: IIO_CHAN_INFO_RAW\n"); + dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_RAW\n", __func__); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - pr_err("[Log Debug] max14001_read_raw: IIO_CHAN_INFO_SCALE\n"); + dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_SCALE\n", __func__); return IIO_VAL_INT; } return -EINVAL; } +/* TODO: Check if this method is nedeed */ static int max14001_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -165,9 +198,7 @@ static int max14001_write_raw(struct iio_dev *indio_dev, struct max14001_state *st = iio_priv(indio_dev); switch (mask) { - case IIO_CHAN_INFO_RAW: - pr_err("[Log Debug] max14001_write_raw: IIO_CHAN_INFO_RAW\n"); - return 0; + } return -EINVAL; @@ -183,7 +214,6 @@ static const struct iio_chan_spec max14001_channel_voltage[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .output = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), } @@ -194,7 +224,6 @@ static const struct iio_chan_spec max14001_channel_current[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 0, - .output = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), } @@ -202,24 +231,31 @@ static const struct iio_chan_spec max14001_channel_current[] = { static int max14001_probe(struct spi_device *spi) { - pr_err("[Log Debug] max14001_probe\n"); - + const struct max14001_chip_info *info; + struct device *dev = &spi->dev; struct max14001_state *st; struct iio_dev *indio_dev; bool current_channel = false; int ret; + info = spi_get_device_match_data(spi); + if (!dev) + return dev_err_probe(dev, -ENODEV, "Failed to get match data\n"); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); st->spi = spi; + st->chip_info = info; - indio_dev->name = "max14001"; //spi_get_device_id(spi)->name; + indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &max14001_info; + dev_info(&st->spi->dev, "%s: probe\n", __func__); + for_each_available_child_of_node_scoped(spi->dev.of_node, child) { current_channel = of_property_read_bool(child, "current-channel"); if (current_channel) @@ -234,21 +270,21 @@ static int max14001_probe(struct spi_device *spi) indio_dev->num_channels = ARRAY_SIZE(max14001_channel_voltage); } - //Enable register write - max14001_spi_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_WRITE_ENABLE); return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id max14001_id_table[] = { - { "max14001", max14001 }, - { "max14002", max14002 }, + { "max14001", (kernel_ulong_t)&max14001_chip_info_tbl[max14001] }, + { "max14002", (kernel_ulong_t)&max14001_chip_info_tbl[max14002] }, {} }; MODULE_DEVICE_TABLE(spi, max14001_id_table); static const struct of_device_id max14001_of_match[] = { - { .compatible = "adi,max14001" }, - { .compatible = "adi,max14002" }, + { .compatible = "adi,max14001", + .data = &max14001_chip_info_tbl[max14001], }, + { .compatible = "adi,max14002", + .data = &max14001_chip_info_tbl[max14002], }, {} }; MODULE_DEVICE_TABLE(of, max14001_of_match); @@ -265,4 +301,5 @@ module_spi_driver(max14001_driver); MODULE_AUTHOR("Marilene Andrade Garcia "); MODULE_DESCRIPTION("Analog Devices MAX14001/MAX14002 ADCs driver"); -MODULE_LICENSE("GPL v2"); \ No newline at end of file +MODULE_LICENSE("GPL v2"); + From 42f812b5cceb7fe632d18e0debf0a46bc894aee1 Mon Sep 17 00:00:00 2001 From: Marilene A Garcia Date: Tue, 22 Jul 2025 21:49:57 -0300 Subject: [PATCH 3/5] iio: adc: Add new methods for MAX14001/MAX14002 driver - Add regulators - Provide scale to convert opcodes to mV - Read ADC sample data Signed-off-by: Marilene A Garcia --- drivers/iio/adc/max14001.c | 89 +++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c index 208c5241e4842e..e9bbc552495b8f 100644 --- a/drivers/iio/adc/max14001.c +++ b/drivers/iio/adc/max14001.c @@ -14,6 +14,7 @@ #include #include #include +#include /* MAX14001 registers definition */ #define MAX14001_REG_ADC 0x00 @@ -75,6 +76,10 @@ #define MAX14001_REG_WEN_WRITE_ENABLE 0x294 #define MAX14001_REG_WEN_WRITE_DISABLE 0x0 +/* MAX14001 10-bit ADC */ +#define MAX14001_NUMBER_OF_DATA_BITS 10 +#define MAX14001_BIT_DIV (1 << 10) + enum max14001_chip_model { max14001, max14002, @@ -97,9 +102,52 @@ static struct max14001_chip_info max14001_chip_info_tbl[] = { struct max14001_state { struct spi_device *spi; const struct max14001_chip_info *chip_info; + int vref_mV; }; -static int max14001_spi_read(struct max14001_state *st, u16 reg, u16 *val) +static int max14001_get_scale(struct max14001_state *st) +{ + int scale; + + /* scale = range / 2^10 */ + scale = st->vref_mV / MAX14001_BIT_DIV; + return scale; +} + +static int max14001_get_vref_mV(struct max14001_state *st) +{ + struct device *dev = &st->spi->dev; + int ret = 0; + + ret = devm_regulator_get_enable_read_voltage(dev, "vrefin"); + if (ret < 0){ + st->vref_mV = 1250000 / 1000; + dev_info(&st->spi->dev, "%s: vrefin not found. vref_mV %d\n", __func__, st->vref_mV); + } else { + st->vref_mV = ret / 1000; + dev_info(&st->spi->dev, "%s: vrefin found. vref_mV %d\n", __func__, st->vref_mV); + } + + return ret; +} + +static int max14001_init_required_regulators(struct max14001_state *st) +{ + struct device *dev = &st->spi->dev; + int ret = 0; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable specified Vdd supply\n"); + + ret = devm_regulator_get_enable(dev, "vddl"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable specified Vddl supply\n"); + + return ret; +} + +static int max14001_spi_read(struct max14001_state *st, u16 reg, int *val) { u16 tx, rx, reversed; int ret; @@ -116,7 +164,7 @@ static int max14001_spi_read(struct max14001_state *st, u16 reg, u16 *val) /* TODO: Validate this line in the hw, could be le16_to_cpu */ reversed = bitrev16(be16_to_cpu(rx)); - *val = FIELD_GET(MAX14001_MASK_ADDR, reversed); + *val = FIELD_GET(MAX14001_MASK_DATA, reversed); return ret; } @@ -154,17 +202,17 @@ static int max14001_spi_write_single_reg(struct max14001_state *st, u16 reg, u16 { int ret; - //Enable register write + /* Enable register write */ ret = max14001_spi_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_WRITE_ENABLE); if (ret < 0) return ret; - //Write data into register + /* Write data into register */ ret = max14001_spi_write(st, reg, val); if (ret < 0) return ret; - //Disable register write + /* Disable register write */ ret = max14001_spi_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_WRITE_DISABLE); if (ret < 0) return ret; @@ -177,14 +225,30 @@ static int max14001_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct max14001_state *st = iio_priv(indio_dev); + int ret; switch (mask) { case IIO_CHAN_INFO_RAW: - dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_RAW\n", __func__); + ret = max14001_spi_read(st, MAX14001_REG_ADC, val); + dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_RAW: channel: %d, val: %d\n", __func__, chan->channel, val); + if (ret < 0) + return ret; + return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_SCALE\n", __func__); + case IIO_CHAN_INFO_AVERAGE_RAW: + ret = max14001_spi_read(st, MAX14001_REG_FADC, val); + dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_AVERAGE_RAW: channel: %d, val: %d\n", __func__, chan->channel, val); + if (ret < 0) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = max14001_get_scale(st); + *val = ret; + *val2 = MAX14001_NUMBER_OF_DATA_BITS; + dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_SCALE: val: %d, val2: %d\n", __func__, val, val2); + + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; @@ -215,6 +279,7 @@ static const struct iio_chan_spec max14001_channel_voltage[] = { .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_AVERAGE_RAW) | BIT(IIO_CHAN_INFO_SCALE), } }; @@ -225,6 +290,7 @@ static const struct iio_chan_spec max14001_channel_current[] = { .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_AVERAGE_RAW) | BIT(IIO_CHAN_INFO_SCALE), } }; @@ -254,8 +320,6 @@ static int max14001_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &max14001_info; - dev_info(&st->spi->dev, "%s: probe\n", __func__); - for_each_available_child_of_node_scoped(spi->dev.of_node, child) { current_channel = of_property_read_bool(child, "current-channel"); if (current_channel) @@ -270,6 +334,11 @@ static int max14001_probe(struct spi_device *spi) indio_dev->num_channels = ARRAY_SIZE(max14001_channel_voltage); } + dev_info(&st->spi->dev, "%s: probe\n", __func__); + + max14001_init_required_regulators(st); + max14001_get_vref_mV(st); + return devm_iio_device_register(&spi->dev, indio_dev); } From b77c248f39dc9048cad17b7291aef73fac455f08 Mon Sep 17 00:00:00 2001 From: Marilene A Garcia Date: Thu, 24 Jul 2025 18:35:24 -0300 Subject: [PATCH 4/5] iio: adc: Correct some values to properly reflect the IIO_CHAN_INFO_SCALE return value - Remove max14001_get_scale method - Fix typo Signed-off-by: Marilene A Garcia --- drivers/iio/adc/max14001.c | 39 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c index e9bbc552495b8f..c032a7ea44d981 100644 --- a/drivers/iio/adc/max14001.c +++ b/drivers/iio/adc/max14001.c @@ -76,10 +76,6 @@ #define MAX14001_REG_WEN_WRITE_ENABLE 0x294 #define MAX14001_REG_WEN_WRITE_DISABLE 0x0 -/* MAX14001 10-bit ADC */ -#define MAX14001_NUMBER_OF_DATA_BITS 10 -#define MAX14001_BIT_DIV (1 << 10) - enum max14001_chip_model { max14001, max14002, @@ -102,30 +98,21 @@ static struct max14001_chip_info max14001_chip_info_tbl[] = { struct max14001_state { struct spi_device *spi; const struct max14001_chip_info *chip_info; - int vref_mV; + int vref_mv; }; -static int max14001_get_scale(struct max14001_state *st) -{ - int scale; - - /* scale = range / 2^10 */ - scale = st->vref_mV / MAX14001_BIT_DIV; - return scale; -} - -static int max14001_get_vref_mV(struct max14001_state *st) +static int max14001_get_vref_mv(struct max14001_state *st) { struct device *dev = &st->spi->dev; int ret = 0; ret = devm_regulator_get_enable_read_voltage(dev, "vrefin"); if (ret < 0){ - st->vref_mV = 1250000 / 1000; - dev_info(&st->spi->dev, "%s: vrefin not found. vref_mV %d\n", __func__, st->vref_mV); + st->vref_mv = 1250000 / 1000; + dev_info(&st->spi->dev, "%s: vrefin not found. vref_mv %d\n", __func__, st->vref_mv); } else { - st->vref_mV = ret / 1000; - dev_info(&st->spi->dev, "%s: vrefin found. vref_mV %d\n", __func__, st->vref_mV); + st->vref_mv = ret / 1000; + dev_info(&st->spi->dev, "%s: vrefin found. vref_mv %d\n", __func__, st->vref_mv); } return ret; @@ -230,23 +217,22 @@ static int max14001_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: ret = max14001_spi_read(st, MAX14001_REG_ADC, val); - dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_RAW: channel: %d, val: %d\n", __func__, chan->channel, val); + dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_RAW: channel: %d, val: %d\n", __func__, chan->channel, *val); if (ret < 0) return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_AVERAGE_RAW: ret = max14001_spi_read(st, MAX14001_REG_FADC, val); - dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_AVERAGE_RAW: channel: %d, val: %d\n", __func__, chan->channel, val); + dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_AVERAGE_RAW: channel: %d, val: %d\n", __func__, chan->channel, *val); if (ret < 0) return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = max14001_get_scale(st); - *val = ret; - *val2 = MAX14001_NUMBER_OF_DATA_BITS; - dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_SCALE: val: %d, val2: %d\n", __func__, val, val2); + *val = st->vref_mv; + *val2 = 10; + dev_info(&st->spi->dev, "%s: IIO_CHAN_INFO_SCALE: val: %d, val2: %d\n", __func__, *val, *val2); return IIO_VAL_FRACTIONAL_LOG2; } @@ -262,7 +248,6 @@ static int max14001_write_raw(struct iio_dev *indio_dev, struct max14001_state *st = iio_priv(indio_dev); switch (mask) { - } return -EINVAL; @@ -337,7 +322,7 @@ static int max14001_probe(struct spi_device *spi) dev_info(&st->spi->dev, "%s: probe\n", __func__); max14001_init_required_regulators(st); - max14001_get_vref_mV(st); + max14001_get_vref_mv(st); return devm_iio_device_register(&spi->dev, indio_dev); } From 6c5e26010c49fc9271dc5a0e6b30b5d4251f2f2c Mon Sep 17 00:00:00 2001 From: Marilene A Garcia Date: Sun, 27 Jul 2025 02:02:36 -0300 Subject: [PATCH 5/5] iio: adc: Add MAX14001/Max14002 device tree documentation - Fix memory validation fault related to verification registers values at power-on-reset (POR) - Add device tree documentation for MAX14001/MAX14002 - Move regulators initialization logic to probe function Signed-off-by: Marilene A Garcia --- .../bindings/iio/adc/adi,max14001.yaml | 81 +++++++++++++ .../dts/overlays/rpi-max14001-pmb-overlay.dts | 4 +- drivers/iio/adc/max14001.c | 111 ++++++++++-------- 3 files changed, 143 insertions(+), 53 deletions(-) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml b/Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml new file mode 100644 index 00000000000000..76ea462b74bebb --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2025 Marilene Andrade Garcia +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,max14001.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices MAX14001-MAX14002 10-bit ADCs + +maintainers: + - Marilene Andrade Garcia + +description: + Bindings for the Analog Devices MAX14001-MAX14002 Configurable, + Isolated 10-bit ADCs for Multi-Range Binary Inputs. + + Datasheet can be found here: + https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf + +properties: + compatible: + enum: + - adi,max14001 + - adi,max14002 + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + vdd-supply: + description: + Isolated DC-DC power supply input voltage. + + vddl-supply: + description: + Logic power supply. + + vrefin-supply: + description: + Reference input range. + + spi-max-frequency: + maximum: 5000000 + + current-channel: + description: + Enable handle current channel measures instead the default + voltage channel measures. + type: boolean + +required: + - compatible + - reg + - vdd-supply + - vddl-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + max14001: adc@0 { + compatible = "adi,max14001"; + reg = <0>; + spi-max-frequency = <5000000>; + vdd-supply = <&vdd>; + vddl-supply = <&vddl>; + }; + }; +... diff --git a/arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts b/arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts index a13fa54232eae1..75dbd22ba42d38 100644 --- a/arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts +++ b/arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts @@ -47,7 +47,7 @@ &spi0 { status = "okay"; max14001_voltage_channel: max14001@0 { - compatible = "max14001"; + compatible = "adi,max14001"; reg = <0x0>; spi-max-frequency = <5000000>; vdd-supply = <&vdd>; @@ -56,7 +56,7 @@ status = "okay"; }; max14001_current_channel: max14001@1 { - compatible = "max14001"; + compatible = "adi,max14001"; reg = <0x1>; spi-max-frequency = <5000000>; current-channel; diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c index c032a7ea44d981..97c51dff5fabfd 100644 --- a/drivers/iio/adc/max14001.c +++ b/drivers/iio/adc/max14001.c @@ -101,42 +101,10 @@ struct max14001_state { int vref_mv; }; -static int max14001_get_vref_mv(struct max14001_state *st) -{ - struct device *dev = &st->spi->dev; - int ret = 0; - - ret = devm_regulator_get_enable_read_voltage(dev, "vrefin"); - if (ret < 0){ - st->vref_mv = 1250000 / 1000; - dev_info(&st->spi->dev, "%s: vrefin not found. vref_mv %d\n", __func__, st->vref_mv); - } else { - st->vref_mv = ret / 1000; - dev_info(&st->spi->dev, "%s: vrefin found. vref_mv %d\n", __func__, st->vref_mv); - } - - return ret; -} - -static int max14001_init_required_regulators(struct max14001_state *st) -{ - struct device *dev = &st->spi->dev; - int ret = 0; - - ret = devm_regulator_get_enable(dev, "vdd"); - if (ret) - return dev_err_probe(dev, ret, "Failed to enable specified Vdd supply\n"); - - ret = devm_regulator_get_enable(dev, "vddl"); - if (ret) - return dev_err_probe(dev, ret, "Failed to enable specified Vddl supply\n"); - - return ret; -} - static int max14001_spi_read(struct max14001_state *st, u16 reg, int *val) { - u16 tx, rx, reversed; + u16 rx, reversed; + u16 tx = 0; int ret; dev_info(&st->spi->dev, "%s: reg: %x, val: %x\n", __func__, reg, *val); @@ -207,6 +175,43 @@ static int max14001_spi_write_single_reg(struct max14001_state *st, u16 reg, u16 return ret; } +static int max14001_set_verification_registers_values(struct max14001_state *st) +{ + struct device *dev = &st->spi->dev; + int i, val_read_reg, ret; + u16 val_write_reg; + + /* Enable register write */ + ret = max14001_spi_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_WRITE_ENABLE); + if (ret < 0) + goto erro_condition; + + for (i = MAX14001_REG_FLTEN; i <= MAX14001_REG_ENBL; i++) { + /* Read register value */ + val_read_reg = 0; + ret = max14001_spi_read(st, i, &val_read_reg); + if (ret < 0) + goto erro_condition; + + /* Write verification register value */ + val_write_reg = (u16)val_read_reg; + ret = max14001_spi_write(st, MAX14001_REG_VERIFICATION(i), val_write_reg); + if (ret < 0) + goto erro_condition; + } + + /* Disable register write */ + ret = max14001_spi_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_WRITE_DISABLE); + if (ret < 0) + goto erro_condition; + + return ret; + +erro_condition: + return dev_err_probe(dev, ret, "Failed to set verification registers\n"); + +} + static int max14001_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -240,22 +245,8 @@ static int max14001_read_raw(struct iio_dev *indio_dev, return -EINVAL; } -/* TODO: Check if this method is nedeed */ -static int max14001_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct max14001_state *st = iio_priv(indio_dev); - - switch (mask) { - } - - return -EINVAL; -} - static const struct iio_info max14001_info = { .read_raw = max14001_read_raw, - .write_raw = max14001_write_raw, }; static const struct iio_chan_spec max14001_channel_voltage[] = { @@ -305,6 +296,23 @@ static int max14001_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &max14001_info; + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable specified Vdd supply\n"); + + ret = devm_regulator_get_enable(dev, "vddl"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable specified Vddl supply\n"); + + ret = devm_regulator_get_enable_read_voltage(dev, "vrefin"); + if (ret < 0) { + st->vref_mv = 1250000 / 1000; + dev_info(&st->spi->dev, "%s: vrefin not found. vref_mv %d\n", __func__, st->vref_mv); + } else { + st->vref_mv = ret / 1000; + dev_info(&st->spi->dev, "%s: vrefin found. vref_mv %d\n", __func__, st->vref_mv); + } + for_each_available_child_of_node_scoped(spi->dev.of_node, child) { current_channel = of_property_read_bool(child, "current-channel"); if (current_channel) @@ -321,8 +329,10 @@ static int max14001_probe(struct spi_device *spi) dev_info(&st->spi->dev, "%s: probe\n", __func__); - max14001_init_required_regulators(st); - max14001_get_vref_mv(st); + /* Write the appropriate verification registers values to clear the + * failed memory validation (MV Fault) + */ + max14001_set_verification_registers_values(st); return devm_iio_device_register(&spi->dev, indio_dev); } @@ -356,4 +366,3 @@ module_spi_driver(max14001_driver); MODULE_AUTHOR("Marilene Andrade Garcia "); MODULE_DESCRIPTION("Analog Devices MAX14001/MAX14002 ADCs driver"); MODULE_LICENSE("GPL v2"); -