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..3b2a2e788a17c4 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml @@ -0,0 +1,78 @@ +# 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 + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,max14001 + - adi,max14002 + + reg: + maxItems: 1 + + vdd-supply: + description: + Isolated DC-DC power supply input voltage. + + vddl-supply: + description: + Logic power supply. + + vrefin-supply: + description: + ADC voltage reference supply. + + interrupts: + items: + - description: | + Interrupt for signaling when conversion results exceed the configured + upper threshold for ADC readings or fall below the lower threshold for + them. Interrupt source must be attached to COUT pin. + - description: | + Alert output that asserts low during a number of different error + conditions. The interrupt source must be attached to FAULT pin. + + spi-max-frequency: + maximum: 5000000 + +required: + - compatible + - reg + - vdd-supply + - vddl-supply + +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/MAINTAINERS b/MAINTAINERS index 56f521c7321d4a..c3031290f91ba0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13122,6 +13122,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/maxim,max11205.yaml F: drivers/iio/adc/max11205.c +MAXIM MAX14001/MAX14002 DRIVER +M: Marilene Andrade Garcia +L: linux-iio@vger.kernel.org +S: Maintained +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml +F: drivers/iio/adc/max14001.c + MAXIM MAX17040 FAMILY FUEL GAUGE DRIVERS R: Iskren Chernev R: Krzysztof Kozlowski diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index a9fa5cc30d63fe..d34acec61e0399 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-pmb.dtbo \ rpi-max14830-i2c.dtbo \ rpi-max14830-spi.dtbo \ rpi-max31335.dtbo \ 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..837113c22eeb2e --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-max14001-pmb-overlay.dts @@ -0,0 +1,77 @@ +// 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; + regulator-always-on; + 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; + regulator-always-on; + 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; + regulator-always-on; + status = "okay"; + }; +}; + +&spi0 { + status = "okay"; + max14001_u51: max14001@0 { + compatible = "adi,max14001"; + reg = <0x0>; + spi-max-frequency = <5000000>; + vdd-supply = <&vdd>; + vddl-supply = <&vddl>; + vrefin-supply = <&vrefin>; + status = "okay"; + }; + max14001_u11: max14001@1 { + compatible = "adi,max14001"; + reg = <0x1>; + spi-max-frequency = <5000000>; + vdd-supply = <&vdd>; + vddl-supply = <&vddl>; + vrefin-supply = <&vrefin>; + status = "okay"; + }; +}; + +&spidev0 { + status = "disabled"; +}; + +&spidev1 { + status = "disabled"; +}; 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..fb79f3b81e0c70 --- /dev/null +++ b/drivers/iio/adc/max14001.c @@ -0,0 +1,213 @@ +// 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 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) + +enum max14001_chip_model { + max14001, + max14002, +}; + +struct max14001_chip_info { + const char *name; +}; + +struct max14001_state { + const struct max14001_chip_info *chip_info; + struct spi_device *spi; + int vref_mv; + + __be16 rx_buffer __aligned(IIO_DMA_MINALIGN); + __be16 tx_buffer; +}; + +static struct max14001_chip_info max14001_chip_info_tbl[] = { + [max14001] = { + .name = "max14001", + }, + [max14002] = { + .name = "max14002", + }, +}; + +static int max14001_spi_read(struct max14001_state *st, u16 reg, int *val) +{ + struct spi_transfer xfer[] = { + { + .tx_buf = &st->tx_buffer, + .len = sizeof(st->tx_buffer), + .cs_change = 1, + }, + { + .rx_buf = &st->rx_buffer, + .len = sizeof(st->rx_buffer), + }, + }; + int ret; + + st->tx_buffer = FIELD_PREP(MAX14001_MASK_ADDR, reg) | + FIELD_PREP(MAX14001_MASK_WR, MAX14001_REG_READ); + st->tx_buffer = bitrev16(st->tx_buffer); + + ret = spi_sync_transfer(st->spi, xfer, ARRAY_SIZE(xfer)); + if (ret < 0) + return ret; + + st->rx_buffer = bitrev16(be16_to_cpu(st->rx_buffer)); + *val = FIELD_GET(MAX14001_MASK_DATA, st->rx_buffer); + + return 0; +} + +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); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = max14001_spi_read(st, MAX14001_REG_ADC, 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); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = st->vref_mv; + *val2 = 10; + + return IIO_VAL_FRACTIONAL_LOG2; + } + + return -EINVAL; +} + +static const struct iio_info max14001_info = { + .read_raw = max14001_read_raw, +}; + +static const struct iio_chan_spec max14001_channel[] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_AVERAGE_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static int max14001_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct max14001_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return dev_err_probe(dev, -ENODEV, "Failed to get match data\n"); + + indio_dev->name = st->chip_info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &max14001_info; + indio_dev->channels = max14001_channel; + indio_dev->num_channels = ARRAY_SIZE(max14001_channel); + + 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; + else + st->vref_mv = ret / 1000; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct spi_device_id max14001_id_table[] = { + { "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", + .data = &max14001_chip_info_tbl[max14001], }, + { .compatible = "adi,max14002", + .data = &max14001_chip_info_tbl[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");