/*
 * Copyright (c) 2024 Analog Devices Inc.
 * Copyright (c) 2024 Baylibre SAS
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>

#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(gpio_max22190);

#include <zephyr/drivers/gpio/gpio_utils.h>

#define MAX22190_ENABLE  1
#define MAX22190_DISABLE 0

#define MAX22190_READ  0
#define MAX22190_WRITE 1

#define MAX22190_MAX_PKT_SIZE   3
#define MAX22190_CHANNELS       8
#define MAX22190_FAULT2_ENABLES 5

#define MAX22190_WB_REG           0x0
#define MAX22190_DI_REG           0x2
#define MAX22190_FAULT1_REG       0x4
#define MAX22190_FILTER_IN_REG(x) (0x6 + (2 * (x)))
#define MAX22190_CFG_REG          0x18
#define MAX22190_IN_EN_REG        0x1A
#define MAX22190_FAULT2_REG       0x1C
#define MAX22190_FAULT2_EN_REG    0x1E
#define MAX22190_GPO_REG          0x22
#define MAX22190_FAULT1_EN_REG    0x24
#define MAX22190_NOP_REG          0x26

#define MAX22190_CH_STATE_MASK(x) BIT(x)
#define MAX22190_DELAY_MASK       GENMASK(2, 0)
#define MAX22190_FBP_MASK         BIT(3)
#define MAX22190_WBE_MASK         BIT(4)
#define MAX22190_RW_MASK          BIT(7)
#define MAX22190_ADDR_MASK        GENMASK(6, 0)
#define MAX22190_ALARM_MASK       GENMASK(4, 3)
#define MAX22190_POR_MASK         BIT(6)

#define MAX22190_FAULT_MASK(x)   BIT(x)
#define MAX22190_FAULT2_WBE_MASK BIT(4)

#define MAX22190_FAULT2_EN_MASK GENMASK(5, 0)

#define MAX22190_CFG_REFDI_MASK BIT(0)
#define MAX22190_CFG_CLRF_MASK  BIT(3)
#define MAX22190_CFG_24VF_MASK  BIT(4)

#define PRINT_ERR_BIT(bit1, bit2)                                                                  \
	if (bit1 & bit2) {                                                                         \
		LOG_ERR("[%s] %d", #bit1, bit1);                                                   \
	}

#define MAX22190_CLEAN_POR(dev)                                                                    \
	max22190_reg_update(dev, MAX22190_FAULT1_REG, MAX22190_POR_MASK,                           \
			    FIELD_PREP(MAX22190_POR_MASK, 0))

enum max22190_variants {
	MAX22190,
	MAX22199,
};

enum max22190_ch_state {
	MAX22190_CH_OFF,
	MAX22190_CH_ON
};

enum max22190_ch_wb_state {
	MAX22190_CH_NO_WB_BREAK,
	MAX22190_CH_WB_COND_DET
};

enum max22190_mode {
	MAX22190_MODE_0,
	MAX22190_MODE_1,
	MAX22190_MODE_2,
	MAX22190_MODE_3,
};

union max22190_fault1 {
	uint8_t reg_raw;
	struct {
		uint8_t max22190_WBG: 1; /* BIT 0 */
		uint8_t max22190_24VM: 1;
		uint8_t max22190_24VL: 1;
		uint8_t max22190_ALRMT1: 1;
		uint8_t max22190_ALRMT2: 1;
		uint8_t max22190_FAULT2: 1;
		uint8_t max22190_POR: 1;
		uint8_t max22190_CRC: 1; /* BIT 7 */
	} reg_bits;
};

union max22190_fault1_en {
	uint8_t reg_raw;
	struct {
		uint8_t max22190_WBGE: 1; /* BIT 0 */
		uint8_t max22190_24VME: 1;
		uint8_t max22190_24VLE: 1;
		uint8_t max22190_ALRMT1E: 1;
		uint8_t max22190_ALRMT2E: 1;
		uint8_t max22190_FAULT2E: 1;
		uint8_t max22190_PORE: 1;
		uint8_t max22190_CRCE: 1; /* BIT 7 */
	} reg_bits;
};

union max22190_fault2 {
	uint8_t reg_raw;
	struct {
		uint8_t max22190_RFWBS: 1; /* BIT 0 */
		uint8_t max22190_RFWBO: 1;
		uint8_t max22190_RFDIS: 1;
		uint8_t max22190_RFDIO: 1;
		uint8_t max22190_OTSHDN: 1;
		uint8_t max22190_FAULT8CK: 1;
		uint8_t max22190_DUMMY: 2; /* BIT 7 */
	} reg_bits;
};

union max22190_fault2_en {
	uint8_t reg_raw;
	struct {
		uint8_t max22190_RFWBSE: 1; /* BIT 0 */
		uint8_t max22190_RFWBOE: 1;
		uint8_t max22190_RFDISE: 1;
		uint8_t max22190_RFDIOE: 1;
		uint8_t max22190_OTSHDNE: 1;
		uint8_t max22190_FAULT8CKE: 1;
		uint8_t max22190_DUMMY: 2; /* BIT 7 */
	} reg_bits;
};

union max22190_cfg {
	uint8_t reg_raw;
	struct {
		uint8_t max22190_DUMMY1: 3; /* BIT 0 */
		uint8_t max22190_24VF: 1;
		uint8_t max22190_CLRF: 1;
		uint8_t max22190_DUMMY2: 2;
		uint8_t max22190_REFDI_SH_EN: 1; /* BIT 7 */
	} reg_bits;
};

union max22190_filter {
	uint8_t reg_raw;
	struct {
		uint8_t max22190_DELAY: 3; /* BIT 0 */
		uint8_t max22190_FBP: 1;
		uint8_t max22190_WBE: 1;
		uint8_t max22190_DUMMY: 2; /* BIT 7 */
	} reg_bits;
};

enum max22190_delay {
	MAX22190_DELAY_50US,
	MAX22190_DELAY_100US,
	MAX22190_DELAY_400US,
	MAX22190_DELAY_800US,
	MAX22190_DELAY_1800US,
	MAX22190_DELAY_3200US,
	MAX22190_DELAY_12800US,
	MAX22190_DELAY_20000US
};

struct max22190_config {
	struct spi_dt_spec spi;
	struct gpio_dt_spec fault_gpio;
	struct gpio_dt_spec ready_gpio;
	struct gpio_dt_spec latch_gpio;
	union max22190_filter filter[8];
	bool crc_en;
	enum max22190_mode mode;
	uint8_t pkt_size;
	uint8_t variant;
};

struct max22190_data {
	struct gpio_driver_data common;
	enum max22190_ch_state channels[MAX22190_CHANNELS];
	enum max22190_ch_wb_state wb[MAX22190_CHANNELS];
	union max22190_cfg cfg;
	union max22190_fault1 fault1;
	union max22190_fault1_en fault1_en;
	union max22190_fault2 fault2;
	union max22190_fault2_en fault2_en;
};

/*
 * @brief Compute the CRC5 value for MAX22190
 * @param data - Data array to calculate CRC for.
 * @return CRC result.
 */
static uint8_t max22190_crc(uint8_t *data)
{
	int length = 19;
	uint8_t crc_step, tmp;
	uint8_t crc_init = 0x7;
	uint8_t crc_poly = 0x35;
	int i;

	/*
	 * This is the C custom implementation of CRC function for MAX22190, and
	 * can be found here:
	 * https://www.analog.com/en/design-notes/guidelines-to-implement-crc-algorithm.html
	 */
	uint32_t datainput = (uint32_t)((data[0] << 16) + (data[1] << 8) + data[2]);

	datainput = (datainput & 0xFFFFE0) + crc_init;

	tmp = (uint8_t)((datainput & 0xFC0000) >> 18);

	if ((tmp & 0x20) == 0x20) {
		crc_step = (uint8_t)(tmp ^ crc_poly);
	} else {
		crc_step = tmp;
	}

	for (i = 0; i < length - 1; i++) {
		tmp = (uint8_t)(((crc_step & 0x1F) << 1) +
				((datainput >> (length - 2 - i)) & 0x01));

		if ((tmp & 0x20) == 0x20) {
			crc_step = (uint8_t)(tmp ^ crc_poly);
		} else {
			crc_step = tmp;
		}
	}

	return (uint8_t)(crc_step & 0x1F);
}

/*
 * @brief Update chan WB state in max22190_data
 *
 * @param dev - MAX22190 device.
 * @param val - value to be set.
 */
static void max22190_update_wb_stat(const struct device *dev, uint8_t val)
{
	struct max22190_data *data = dev->data;

	for (int ch_n = 0; ch_n < 8; ch_n++) {
		data->wb[ch_n] = (val >> ch_n) & 0x1;
	}
}

/*
 * @brief Update chan IN state in max22190_data
 *
 * @param dev - MAX22190 device.
 * @param val - value to be set.
 */
static void max22190_update_in_stat(const struct device *dev, uint8_t val)
{
	struct max22190_data *data = dev->data;

	for (int ch_n = 0; ch_n < 8; ch_n++) {
		data->channels[ch_n] = (val >> ch_n) & 0x1;
	}
}

/*
 * @brief Register write function for MAX22190
 *
 * @param dev - MAX22190 device config.
 * @param addr - Register value to which data is written.
 * @param val - Value which is to be written to requested register.
 * @return 0 in case of success, negative error code otherwise.
 */
static int max22190_reg_transceive(const struct device *dev, uint8_t addr, uint8_t val, uint8_t rw)
{
	uint8_t crc;
	int ret;

	uint8_t local_rx_buff[MAX22190_MAX_PKT_SIZE] = {0};
	uint8_t local_tx_buff[MAX22190_MAX_PKT_SIZE] = {0};

	const struct max22190_config *config = dev->config;

	struct spi_buf tx_buf = {
		.buf = &local_tx_buff,
		.len = config->pkt_size,
	};
	const struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1};

	struct spi_buf rx_buf = {
		.buf = &local_rx_buff,
		.len = config->pkt_size,
	};
	const struct spi_buf_set rx = {.buffers = &rx_buf, .count = 1};

	local_tx_buff[0] =
		FIELD_PREP(MAX22190_ADDR_MASK, addr) | FIELD_PREP(MAX22190_RW_MASK, rw & 0x1);
	local_tx_buff[1] = val;

	/* If CRC enabled calculate it */
	if (config->crc_en) {
		local_tx_buff[2] = max22190_crc(&local_tx_buff[0]);
	}

	/* write cmd & read resp at once */
	ret = spi_transceive_dt(&config->spi, &tx, &rx);

	if (ret) {
		LOG_ERR("Err spi_transcieve_dt  [%d]\n", ret);
		return ret;
	}

	/* if CRC enabled check readed */
	if (config->crc_en) {
		crc = max22190_crc(&local_rx_buff[0]);
		if (crc != (local_rx_buff[2] & 0x1F)) {
			LOG_ERR("READ CRC ERR (%d)-(%d)\n", crc, (local_rx_buff[2] & 0x1F));
			return -EINVAL;
		}
	}

	/* always (R/W) get DI reg in first byte */
	max22190_update_in_stat(dev, local_rx_buff[0]);

	/* in case of writing register we get as second byte WB reg */
	if (rw == MAX22190_WRITE) {
		max22190_update_wb_stat(dev, local_rx_buff[1]);
	} else {
		/* in case of READ second byte is value we are looking for */
		ret = local_rx_buff[1];
	}

	return ret;
}

#define max22190_reg_read(dev, addr)       max22190_reg_transceive(dev, addr, 0, MAX22190_READ)
#define max22190_reg_write(dev, addr, val) max22190_reg_transceive(dev, addr, val, MAX22190_WRITE)

/*
 * @brief Register update function for MAX22190
 *
 * @param dev - MAX22190 device.
 * @param addr - Register valueto wich data is updated.
 * @param mask - Corresponding mask to the data that will be updated.
 * @param val - Updated value to be written in the register at update.
 * @return 0 in case of success, negative error code otherwise.
 */
static int max22190_reg_update(const struct device *dev, uint8_t addr, uint8_t mask, uint8_t val)
{
	int ret;
	uint32_t reg_val = 0;

	ret = max22190_reg_read(dev, addr);

	reg_val = ret;
	reg_val &= ~mask;
	reg_val |= mask & val;

	return max22190_reg_write(dev, addr, reg_val);
}

/*
 * @brief Check FAULT1 and FAULT2
 *
 * @param dev - MAX22190 device
 */
static void max22190_fault_check(const struct device *dev)
{
	struct max22190_data *data = dev->data;
	const struct max22190_config *config = dev->config;

	/* FAULT1 */
	data->fault1.reg_raw = max22190_reg_read(dev, MAX22190_FAULT1_REG);

	if (data->fault1.reg_raw) {
		/* FAULT1_EN */
		data->fault1_en.reg_raw = max22190_reg_read(dev, MAX22190_FAULT1_EN_REG);

		PRINT_ERR_BIT(data->fault1.reg_bits.max22190_CRC,
			      data->fault1_en.reg_bits.max22190_CRCE);
		PRINT_ERR_BIT(data->fault1.reg_bits.max22190_POR,
			      data->fault1_en.reg_bits.max22190_PORE);
		PRINT_ERR_BIT(data->fault1.reg_bits.max22190_FAULT2,
			      data->fault1_en.reg_bits.max22190_FAULT2E);
		PRINT_ERR_BIT(data->fault1.reg_bits.max22190_24VL,
			      data->fault1_en.reg_bits.max22190_24VLE);
		PRINT_ERR_BIT(data->fault1.reg_bits.max22190_24VM,
			      data->fault1_en.reg_bits.max22190_24VME);
		if (config->variant == MAX22190) {
			PRINT_ERR_BIT(data->fault1.reg_bits.max22190_ALRMT2,
				      data->fault1_en.reg_bits.max22190_ALRMT2E);
			PRINT_ERR_BIT(data->fault1.reg_bits.max22190_ALRMT1,
				      data->fault1_en.reg_bits.max22190_ALRMT1E);
			PRINT_ERR_BIT(data->fault1.reg_bits.max22190_WBG,
				      data->fault1_en.reg_bits.max22190_WBGE);
			if (data->fault1.reg_bits.max22190_WBG &
			    data->fault1_en.reg_bits.max22190_WBGE) {
				uint8_t wb_val = max22190_reg_read(dev, MAX22190_WB_REG);

				max22190_update_wb_stat(dev, (uint8_t)wb_val);
			}
		}
		if (data->fault1.reg_bits.max22190_FAULT2) {
			/* FAULT2 */
			data->fault2.reg_raw = max22190_reg_read(dev, MAX22190_FAULT2_REG);

			/* FAULT2_EN */
			data->fault2_en.reg_raw = max22190_reg_read(dev, MAX22190_FAULT2_EN_REG);

			PRINT_ERR_BIT(data->fault2.reg_bits.max22190_OTSHDN,
				      data->fault2_en.reg_bits.max22190_OTSHDNE);
			PRINT_ERR_BIT(data->fault2.reg_bits.max22190_FAULT8CK,
				      data->fault2_en.reg_bits.max22190_FAULT8CKE);
			if (config->variant == MAX22190) {
				PRINT_ERR_BIT(data->fault2.reg_bits.max22190_RFWBS,
					      data->fault2_en.reg_bits.max22190_RFWBSE);
				PRINT_ERR_BIT(data->fault2.reg_bits.max22190_RFWBO,
					      data->fault2_en.reg_bits.max22190_RFWBOE);
				PRINT_ERR_BIT(data->fault2.reg_bits.max22190_RFDIS,
					      data->fault2_en.reg_bits.max22190_RFDISE);
				PRINT_ERR_BIT(data->fault2.reg_bits.max22190_RFDIO,
					      data->fault2_en.reg_bits.max22190_RFDIOE);
			}
		}
	}
}

static void max22190_state_get(const struct device *dev)
{
	const struct max22190_config *config = dev->config;

	if (gpio_pin_get_dt(&config->fault_gpio)) {
		max22190_fault_check(dev);
	}

	/* We are reading WB reg because on first byte will be clocked out DI reg
	 * on second byte we will ge WB value.
	 */
	uint8_t wb_val = max22190_reg_read(dev, MAX22190_WB_REG);

	max22190_update_wb_stat(dev, (uint8_t)wb_val);
}

static int gpio_max22190_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
{
	int err = 0;

	if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) {
		return -ENOTSUP;
	}

	if ((flags & GPIO_SINGLE_ENDED) != 0) {
		return -ENOTSUP;
	}

	if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) {
		return -ENOTSUP;
	}

	if (flags & GPIO_INT_ENABLE) {
		return -ENOTSUP;
	}

	switch (flags & GPIO_DIR_MASK) {
	case GPIO_INPUT:
		LOG_INF("Nothing to do, only INPUT supported");
		break;
	default:
		LOG_ERR("On MAX22190 only input option is available!");
		return -ENOTSUP;
	}

	return err;
}

static void max22190_filter_set(const struct device *dev)
{
	const struct max22190_config *config = dev->config;

	for (int ch_n = 0; ch_n < 8; ch_n++) {
		max22190_reg_write(dev, MAX22190_FILTER_IN_REG(ch_n), config->filter[ch_n].reg_raw);
	}
}

static int max22190_fault_set(const struct device *dev)
{
	const struct max22190_data *data = dev->data;
	int ret = 0;

	ret = max22190_reg_write(dev, MAX22190_FAULT1_EN_REG, data->fault1_en.reg_raw);
	if (ret) {
		goto exit_fault_set;
	}

	ret = max22190_reg_write(dev, MAX22190_FAULT1_REG, data->fault1.reg_raw);
	if (ret) {
		goto exit_fault_set;
	}

	ret = max22190_reg_write(dev, MAX22190_FAULT2_EN_REG, data->fault2_en.reg_raw);
	if (ret) {
		goto exit_fault_set;
	}

	ret = max22190_reg_write(dev, MAX22190_FAULT2_REG, data->fault2.reg_raw);
	if (ret) {
		goto exit_fault_set;
	}

	return ret;

exit_fault_set:
	LOG_ERR("Err spi_transcieve_dt  [%d]\n", ret);

	return ret;
}

static int gpio_max22190_port_get_raw(const struct device *dev, gpio_port_value_t *value)
{
	const struct max22190_data *data = dev->data;

	max22190_state_get(dev);
	*value = 0;
	for (int ch_n = 0; ch_n < 8; ch_n++) {
		/* IN ch state */
		*value |= data->channels[ch_n] << ch_n;
	}

	return 0;
}

static int gpio_max22190_init(const struct device *dev)
{
	const struct max22190_config *config = dev->config;
	struct max22190_data *data = dev->data;

	LOG_DBG("GPIO MAX22190 init IN\n");

	int err = 0;

	if (!spi_is_ready_dt(&config->spi)) {
		LOG_ERR("SPI bus is not ready\n");
		return -ENODEV;
	}

	/* setup READY gpio - normal low */
	if (!gpio_is_ready_dt(&config->ready_gpio)) {
		LOG_ERR("READY GPIO device not ready");
		return -ENODEV;
	}

	err = gpio_pin_configure_dt(&config->ready_gpio, GPIO_INPUT);
	if (err < 0) {
		LOG_ERR("Failed to configure reset GPIO");
		return err;
	}

	/* setup FAULT gpio - normal high */
	if (!gpio_is_ready_dt(&config->fault_gpio)) {
		LOG_ERR("FAULT GPIO device not ready");
		return -ENODEV;
	}

	err = gpio_pin_configure_dt(&config->fault_gpio, GPIO_INPUT | GPIO_PULL_UP);
	if (err < 0) {
		LOG_ERR("Failed to configure DC GPIO");
		return err;
	}

	/* setup LATCH gpio - normal high */
	if (!gpio_is_ready_dt(&config->latch_gpio)) {
		LOG_ERR("LATCH GPIO device not ready");
		return -ENODEV;
	}

	err = gpio_pin_configure_dt(&config->latch_gpio, GPIO_OUTPUT_INACTIVE);
	if (err < 0) {
		LOG_ERR("Failed to configure busy GPIO");
		return err;
	}

	for (int i = 0; i < 8; i++) {
		if (config->variant == MAX22190) {
			LOG_DBG("IN%d WBE [%d] FBP[%d] DELAY[%d]\n", i,
				config->filter[i].reg_bits.max22190_WBE,
				config->filter[i].reg_bits.max22190_FBP,
				config->filter[i].reg_bits.max22190_DELAY);
		} else {
			LOG_DBG("IN%d FBP[%d] DELAY[%d]\n", i,
				config->filter[i].reg_bits.max22190_FBP,
				config->filter[i].reg_bits.max22190_DELAY);
		}
	}

	LOG_DBG(" > MAX22190 MODE: %x", config->mode);
	LOG_DBG(" > MAX22190 PKT SIZE: %dbits (%dbytes)", config->pkt_size * 8, config->pkt_size);
	LOG_DBG(" > MAX22190 CRC: %s", config->crc_en ? "enable" : "disable");

	if (config->variant == MAX22190) {
		data->fault1_en.reg_bits.max22190_WBGE = 1;
	}
	data->fault1_en.reg_bits.max22190_PORE = 1;

	/* Set all FAULT and FAULT_EN regs */
	max22190_fault_set(dev);

	/* Set channels filters */
	max22190_filter_set(dev);

	/* POR bit need to be cleared after start */
	MAX22190_CLEAN_POR(dev);

	LOG_DBG("GPIO MAX22190 init OUT\n");
	return 0;
}

static DEVICE_API(gpio, gpio_max22190_api) = {
	.pin_configure = gpio_max22190_config,
	.port_get_raw = gpio_max22190_port_get_raw,
};

/* Assign appropriate value for FILTER delay*/
#define MAX22190_FILTER_SET_DELAY(delay)                                                           \
	delay == 20000   ? MAX22190_DELAY_20000US                                                  \
	: delay == 12800 ? MAX22190_DELAY_12800US                                                  \
	: delay == 3200  ? MAX22190_DELAY_3200US                                                   \
	: delay == 1600  ? MAX22190_DELAY_1800US                                                   \
	: delay == 800   ? MAX22190_DELAY_800US                                                    \
	: delay == 400   ? MAX22190_DELAY_400US                                                    \
	: delay == 100   ? MAX22190_DELAY_100US                                                    \
	: delay == 50    ? MAX22190_DELAY_50US                                                     \
			 : MAX22190_DELAY_20000US

/* Assigning proper variant for differentiating register map */
#define MAX22190_CONFIG_SET_VARIANT(model)                                                         \
	model == 22190   ? MAX22190 /* MAX22190 */                                                 \
	: model == 22199 ? MAX22199 /* MAX22199 */                                                 \
			 : MAX22190 /* Default fallback */

/* Set FILTERx reg */
#define MAX22190_FILTER_BY_IDX(id, model, idx)                                                     \
	{                                                                                          \
		.reg_bits.max22190_DELAY =                                                         \
			MAX22190_FILTER_SET_DELAY(DT_INST_PROP_BY_IDX(id, filter_delays, idx)),    \
		.reg_bits.max22190_FBP = DT_INST_PROP_BY_IDX(id, filter_fbps, idx),                \
		.reg_bits.max22190_WBE =                                                           \
			(model == 22190) ? DT_INST_PROP_BY_IDX(id, filter_wbes, idx) : 0,          \
	}

#define GPIO_MAX22190_DEVICE(id, model)                                                            \
	static const struct max22190_config max##model##_##id##_cfg = {                            \
		.spi = SPI_DT_SPEC_INST_GET(id, SPI_OP_MODE_MASTER | SPI_WORD_SET(8U)),            \
		.ready_gpio = GPIO_DT_SPEC_INST_GET(id, drdy_gpios),                               \
		.fault_gpio = GPIO_DT_SPEC_INST_GET(id, fault_gpios),                              \
		.latch_gpio = GPIO_DT_SPEC_INST_GET(id, latch_gpios),                              \
		.mode = DT_INST_PROP(id, max22190_mode),                                           \
		.crc_en = !(DT_INST_PROP(id, max22190_mode) & 0x1),                                \
		.pkt_size = !(DT_INST_PROP(id, max22190_mode) & 0x1) ? 3 : 2,                      \
		.variant = MAX22190_CONFIG_SET_VARIANT(model),                                     \
		.filter =                                                                          \
			{                                                                          \
				MAX22190_FILTER_BY_IDX(id, model, 0),                              \
				MAX22190_FILTER_BY_IDX(id, model, 1),                              \
				MAX22190_FILTER_BY_IDX(id, model, 2),                              \
				MAX22190_FILTER_BY_IDX(id, model, 3),                              \
				MAX22190_FILTER_BY_IDX(id, model, 4),                              \
				MAX22190_FILTER_BY_IDX(id, model, 5),                              \
				MAX22190_FILTER_BY_IDX(id, model, 6),                              \
				MAX22190_FILTER_BY_IDX(id, model, 7),                              \
			},                                                                         \
	};                                                                                         \
                                                                                                   \
	static struct max22190_data max##model##_##id##_data;                                      \
                                                                                                   \
	DEVICE_DT_INST_DEFINE(id, &gpio_max22190_init, NULL, &max##model##_##id##_data,            \
			      &max##model##_##id##_cfg, POST_KERNEL,                               \
			      CONFIG_GPIO_MAX22190_INIT_PRIORITY, &gpio_max22190_api);

#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT adi_max22190_gpio
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MAX22190_DEVICE, 22190)

#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT adi_max22199_gpio
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MAX22190_DEVICE, 22199)

#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
#warning "GPIO MAX22190 driver enabled without any devices"
#endif
