Commit 9bdff044 authored by Bartosz Bilas's avatar Bartosz Bilas Committed by Carles Cufi
Browse files

drivers: mfd: add AD5592 MFD driver



This commit introduces a driver for
Analog AD5592 8-channel, configurable ADC/DAC/GPIO chip.

Signed-off-by: default avatarBartosz Bilas <b.bilas@grinn-global.com>
parent d2c101d4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -373,6 +373,7 @@
/drivers/led_strip/                       @mbolivar-ampere
/drivers/lora/                            @Mani-Sadhasivam
/drivers/mbox/                            @carlocaione
/drivers/mfd/mfd_ad5592.c                 @bbilas
/drivers/mfd/mfd_max20335.c               @bbilas
/drivers/misc/                            @tejlmand
/drivers/misc/ft8xx/                      @hubertmis
+1 −0
Original line number Diff line number Diff line
@@ -8,3 +8,4 @@ zephyr_library_sources_ifdef(CONFIG_MFD_NCT38XX mfd_nct38xx.c)
zephyr_library_sources_ifdef(CONFIG_MFD_NPM1300 mfd_npm1300.c)
zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c)
zephyr_library_sources_ifdef(CONFIG_MFD_AXP192 mfd_axp192.c)
zephyr_library_sources_ifdef(CONFIG_MFD_AD5592 mfd_ad5592.c)
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ config MFD_INIT_PRIORITY
	help
	  Multi-function devices initialization priority.

source "drivers/mfd/Kconfig.ad5592"
source "drivers/mfd/Kconfig.axp192"
source "drivers/mfd/Kconfig.max20335"
source "drivers/mfd/Kconfig.nct38xx"
+10 −0
Original line number Diff line number Diff line
# Copyright (c) 2023 Grinn
# SPDX -License-Identifier: Apache-2.0

config MFD_AD5592
	bool "Analog AD5592 SPI configurable ADC/DAC/GPIO chip"
	default y
	depends on DT_HAS_ADI_AD5592_ENABLED
	depends on SPI
	help
	  Enable driver for Analog AD5592.
+169 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2023 Grinn
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT adi_ad5592

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

#include <zephyr/drivers/mfd/ad5592.h>

#define AD5592_GPIO_READBACK_EN BIT(10)
#define AD5592_LDAC_READBACK_EN BIT(6)
#define AD5592_REG_SOFTWARE_RESET 0x0FU
#define AD5592_SOFTWARE_RESET_MAGIC_VAL 0xDAC
#define AD5592_REV_VAL_MASK 0x3FF
#define AD5592_REG_SHIFT_VAL 11
#define AD5592_REG_READBACK_SHIFT_VAL 2

#define AD5592_SPI_SPEC_CONF (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | \
			      SPI_OP_MODE_MASTER | SPI_MODE_CPOL)

struct mfd_ad5592_config {
	struct gpio_dt_spec reset_gpio;
	struct spi_dt_spec bus;
};

int mfd_ad5592_read_raw(const struct device *dev, uint16_t *val)
{
	const struct mfd_ad5592_config *config = dev->config;
	uint16_t nop_msg = 0;

	struct spi_buf tx_buf[] = {
		{
			.buf = &nop_msg,
			.len = sizeof(nop_msg)
		}
	};

	const struct spi_buf_set tx = {
		.buffers = tx_buf,
		.count = 1
	};

	struct spi_buf rx_buf[] = {
		{
			.buf = val,
			.len = sizeof(uint16_t)
		}
	};

	const struct spi_buf_set rx = {
		.buffers = rx_buf,
		.count = 1
	};

	return spi_transceive_dt(&config->bus, &tx, &rx);
}

int mfd_ad5592_write_raw(const struct device *dev, uint16_t val)
{
	const struct mfd_ad5592_config *config = dev->config;

	struct spi_buf tx_buf[] = {
		{
			.buf = &val,
			.len = sizeof(val)
		}
	};

	const struct spi_buf_set tx = {
		.buffers = tx_buf,
		.count = 1
	};

	return spi_write_dt(&config->bus, &tx);
}

int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val)
{
	uint16_t data;
	uint16_t msg;
	int ret;

	switch (reg) {
	case AD5592_REG_GPIO_INPUT_EN:
		msg = sys_cpu_to_be16(AD5592_GPIO_READBACK_EN |
				      (AD5592_REG_GPIO_INPUT_EN << AD5592_REG_SHIFT_VAL) |
				      reg_data);
		break;
	default:
		msg = sys_cpu_to_be16(AD5592_LDAC_READBACK_EN |
				      (AD5592_REG_READ_AND_LDAC << AD5592_REG_SHIFT_VAL) |
				      reg << AD5592_REG_READBACK_SHIFT_VAL);
		break;
	}

	ret = mfd_ad5592_write_raw(dev, msg);
	if (ret < 0) {
		return ret;
	}

	ret = mfd_ad5592_read_raw(dev, &data);
	if (ret < 0) {
		return ret;
	}

	*val = sys_be16_to_cpu(data);

	return 0;
}

int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val)
{
	uint16_t msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & AD5592_REV_VAL_MASK));

	return mfd_ad5592_write_raw(dev, msg);
}

static int mfd_add592_software_reset(const struct device *dev)
{
	return mfd_ad5592_write_reg(dev,
				    AD5592_REG_SOFTWARE_RESET,
				    AD5592_SOFTWARE_RESET_MAGIC_VAL);
}

static int mfd_ad5592_init(const struct device *dev)
{
	const struct mfd_ad5592_config *config = dev->config;
	int ret;

	if (!spi_is_ready_dt(&config->bus)) {
		return -ENODEV;
	}

	if (!gpio_is_ready_dt(&config->reset_gpio)) {
		return -ENODEV;
	}

	ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE);
	if (ret < 0) {
		return ret;
	}

	ret = mfd_add592_software_reset(dev);
	if (ret < 0) {
		return ret;
	}

	return 0;
}

#define MFD_AD5592_DEFINE(inst)							\
	static const struct mfd_ad5592_config mfd_ad5592_config_##inst = {	\
		.reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios),		\
		.bus = SPI_DT_SPEC_INST_GET(inst, AD5592_SPI_SPEC_CONF, 0),	\
	};									\
										\
	DEVICE_DT_INST_DEFINE(inst, mfd_ad5592_init, NULL,			\
			      NULL,						\
			      &mfd_ad5592_config_##inst,			\
			      POST_KERNEL,					\
			      CONFIG_MFD_INIT_PRIORITY,				\
			      NULL);

DT_INST_FOREACH_STATUS_OKAY(MFD_AD5592_DEFINE);
Loading