drivers: dac: add support for ltc1660/ltc1665
LTC1665/LTC1660 is a 8/10-bit Digital-to-Analog Converter (DAC) with eight individual channels. Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
This commit is contained in:
parent
d6990ff8d9
commit
10818f75e2
|
@ -9,6 +9,7 @@ zephyr_library_sources_ifdef(CONFIG_DAC_SAM dac_sam.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_DAC_SAM0 dac_sam0.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_DACX0508 dac_dacx0508.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_DACX3608 dac_dacx3608.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_LTC166X dac_ltc166x.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_SHELL dac_shell.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_MCP4725 dac_mcp4725.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_MCP4728 dac_mcp4728.c)
|
||||
|
|
|
@ -42,6 +42,8 @@ source "drivers/dac/Kconfig.dacx0508"
|
|||
|
||||
source "drivers/dac/Kconfig.dacx3608"
|
||||
|
||||
source "drivers/dac/Kconfig.ltc166x"
|
||||
|
||||
source "drivers/dac/Kconfig.mcp4725"
|
||||
|
||||
source "drivers/dac/Kconfig.mcp4728"
|
||||
|
|
23
drivers/dac/Kconfig.ltc166x
Normal file
23
drivers/dac/Kconfig.ltc166x
Normal file
|
@ -0,0 +1,23 @@
|
|||
# DAC configuration options
|
||||
|
||||
# Copyright (C) 2023 Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config DAC_LTC166X
|
||||
bool "Linear Technology LTC166X DAC"
|
||||
default y
|
||||
select SPI
|
||||
depends on DT_HAS_LLTC_LTC1660_ENABLED || DT_HAS_LLTC_LTC1665_ENABLED
|
||||
help
|
||||
Enable the driver for the Linear Technology LTC166X DAC
|
||||
|
||||
if DAC_LTC166X
|
||||
|
||||
config DAC_LTC166X_INIT_PRIORITY
|
||||
int "Init priority"
|
||||
default 80
|
||||
help
|
||||
Linear Technology LTC166X DAC device driver initialization priority.
|
||||
|
||||
endif # DAC_LTC166X
|
141
drivers/dac/dac_ltc166x.c
Normal file
141
drivers/dac/dac_ltc166x.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Driver for Linear Technology LTC1660/LTC1665 DAC
|
||||
*
|
||||
* Copyright (C) 2023 Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/drivers/dac.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(dac_ltc166x, CONFIG_DAC_LOG_LEVEL);
|
||||
|
||||
#define LTC166X_REG_MASK GENMASK(15, 12)
|
||||
#define LTC166X_DATA8_MASK GENMASK(11, 4)
|
||||
#define LTC166X_DATA10_MASK GENMASK(12, 2)
|
||||
|
||||
struct ltc166x_config {
|
||||
struct spi_dt_spec bus;
|
||||
uint8_t resolution;
|
||||
uint8_t nchannels;
|
||||
};
|
||||
|
||||
static int ltc166x_reg_write(const struct device *dev, uint8_t addr,
|
||||
uint32_t data)
|
||||
{
|
||||
const struct ltc166x_config *config = dev->config;
|
||||
uint16_t regval;
|
||||
|
||||
regval = FIELD_PREP(LTC166X_REG_MASK, addr);
|
||||
|
||||
if (config->resolution == 10) {
|
||||
regval |= FIELD_PREP(LTC166X_DATA10_MASK, data);
|
||||
} else {
|
||||
regval |= FIELD_PREP(LTC166X_DATA8_MASK, data);
|
||||
}
|
||||
|
||||
const struct spi_buf buf = {
|
||||
.buf = ®val,
|
||||
.len = sizeof(regval),
|
||||
};
|
||||
|
||||
struct spi_buf_set tx = {
|
||||
.buffers = &buf,
|
||||
.count = 1,
|
||||
};
|
||||
|
||||
return spi_write_dt(&config->bus, &tx);
|
||||
}
|
||||
|
||||
|
||||
static int ltc166x_channel_setup(const struct device *dev,
|
||||
const struct dac_channel_cfg *channel_cfg)
|
||||
{
|
||||
const struct ltc166x_config *config = dev->config;
|
||||
|
||||
if (channel_cfg->channel_id > config->nchannels - 1) {
|
||||
LOG_ERR("Unsupported channel %d", channel_cfg->channel_id);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (channel_cfg->resolution != config->resolution) {
|
||||
LOG_ERR("Unsupported resolution %d", channel_cfg->resolution);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltc166x_write_value(const struct device *dev, uint8_t channel,
|
||||
uint32_t value)
|
||||
{
|
||||
const struct ltc166x_config *config = dev->config;
|
||||
|
||||
if (channel > config->nchannels - 1) {
|
||||
LOG_ERR("unsupported channel %d", channel);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (value >= (1 << config->resolution)) {
|
||||
LOG_ERR("Value %d out of range", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ltc166x_reg_write(dev, channel + 1, value);
|
||||
}
|
||||
|
||||
static int ltc166x_init(const struct device *dev)
|
||||
{
|
||||
const struct ltc166x_config *config = dev->config;
|
||||
|
||||
if (!spi_is_ready_dt(&config->bus)) {
|
||||
LOG_ERR("SPI bus %s not ready", config->bus.bus->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dac_driver_api ltc166x_driver_api = {
|
||||
.channel_setup = ltc166x_channel_setup,
|
||||
.write_value = ltc166x_write_value,
|
||||
};
|
||||
|
||||
|
||||
#define INST_DT_LTC166X(inst, t) DT_INST(inst, lltc_ltc##t)
|
||||
|
||||
#define LTC166X_DEVICE(t, n, res, nchan) \
|
||||
static const struct ltc166x_config ltc##t##_config_##n = { \
|
||||
.bus = SPI_DT_SPEC_GET(INST_DT_LTC166X(n, t), \
|
||||
SPI_OP_MODE_MASTER | \
|
||||
SPI_WORD_SET(8), 0), \
|
||||
.resolution = res, \
|
||||
.nchannels = nchan, \
|
||||
}; \
|
||||
DEVICE_DT_DEFINE(INST_DT_LTC166X(n, t), \
|
||||
<c166x_init, NULL, \
|
||||
NULL, \
|
||||
<c##t##_config_##n, POST_KERNEL, \
|
||||
CONFIG_DAC_LTC166X_INIT_PRIORITY, \
|
||||
<c166x_driver_api)
|
||||
|
||||
/*
|
||||
* LTC1660: 10-bit
|
||||
*/
|
||||
#define LTC1660_DEVICE(n) LTC166X_DEVICE(1660, n, 10, 8)
|
||||
|
||||
/*
|
||||
* LTC1665: 8-bit
|
||||
*/
|
||||
#define LTC1665_DEVICE(n) LTC166X_DEVICE(1665, n, 8, 8)
|
||||
|
||||
#define CALL_WITH_ARG(arg, expr) expr(arg)
|
||||
|
||||
#define INST_DT_LTC166X_FOREACH(t, inst_expr) \
|
||||
LISTIFY(DT_NUM_INST_STATUS_OKAY(lltc_ltc##t), \
|
||||
CALL_WITH_ARG, (), inst_expr)
|
||||
|
||||
INST_DT_LTC166X_FOREACH(1660, LTC1660_DEVICE);
|
||||
INST_DT_LTC166X_FOREACH(1665, LTC1665_DEVICE);
|
Loading…
Reference in a new issue