drivers: dac: introduce gd32 dac driver
Add DAC driver for gd32 series SoCs. Signed-off-by: HaiLong Yang <cameledyang@pm.me>
This commit is contained in:
parent
222f42f2e8
commit
ba9c3a4d88
4 changed files with 185 additions and 0 deletions
|
@ -11,4 +11,5 @@ 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_SHELL dac_shell.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_MCP4725 dac_mcp4725.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_GD32 dac_gd32.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c)
|
||||
|
|
|
@ -44,4 +44,6 @@ source "drivers/dac/Kconfig.dacx3608"
|
|||
|
||||
source "drivers/dac/Kconfig.mcp4725"
|
||||
|
||||
source "drivers/dac/Kconfig.gd32"
|
||||
|
||||
endif # DAC
|
||||
|
|
15
drivers/dac/Kconfig.gd32
Normal file
15
drivers/dac/Kconfig.gd32
Normal file
|
@ -0,0 +1,15 @@
|
|||
# DAC configuration options
|
||||
|
||||
# Copyright (c) 2021 BrainCo Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Workaround for not being able to have commas in macro arguments
|
||||
DT_COMPAT_GD_GD32_DAC := gd,gd32-dac
|
||||
|
||||
config DAC_GD32
|
||||
bool "GD32 DAC driver"
|
||||
depends on SOC_FAMILY_GD32
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_GD_GD32_DAC))
|
||||
help
|
||||
Enable GigaDevice GD32 DAC driver
|
167
drivers/dac/dac_gd32.c
Normal file
167
drivers/dac/dac_gd32.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (c) 2021 BrainCo Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT gd_gd32_dac
|
||||
|
||||
#include <errno.h>
|
||||
#include <drivers/pinctrl.h>
|
||||
#include <drivers/dac.h>
|
||||
#include <soc.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(dac_gd32, CONFIG_DAC_LOG_LEVEL);
|
||||
|
||||
/**
|
||||
* GD32 DAC HAL use different DAC0 interface for 2 or 1 output channels SoCs.
|
||||
* Unify the DAC0 interface to DAC0_xx.
|
||||
*/
|
||||
#if DT_INST_PROP(0, num_channels) == 1
|
||||
#define DAC_CTL_DEN0 DAC_CTL_DEN
|
||||
#define DAC0_R8DH DAC_R8DH
|
||||
#define DAC0_R12DH DAC_R12DH
|
||||
#endif
|
||||
|
||||
struct dac_gd32_config {
|
||||
uint32_t reg;
|
||||
uint32_t rcu_periph_clock;
|
||||
const struct pinctrl_dev_config *pcfg;
|
||||
uint32_t num_channels;
|
||||
uint32_t reset_val;
|
||||
};
|
||||
|
||||
struct dac_gd32_data {
|
||||
uint8_t resolutions[2];
|
||||
};
|
||||
|
||||
static void dac_gd32_enable(uint8_t dacx)
|
||||
{
|
||||
switch (dacx) {
|
||||
case 0U:
|
||||
DAC_CTL |= DAC_CTL_DEN0;
|
||||
break;
|
||||
#if DT_INST_PROP(0, num_channels) == 2
|
||||
case 1U:
|
||||
DAC_CTL |= DAC_CTL_DEN1;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void dac_gd32_disable(uint8_t dacx)
|
||||
{
|
||||
switch (dacx) {
|
||||
case 0U:
|
||||
DAC_CTL &= ~DAC_CTL_DEN0;
|
||||
break;
|
||||
#if DT_INST_PROP(0, num_channels) == 2
|
||||
case 1U:
|
||||
DAC_CTL &= ~DAC_CTL_DEN1;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void dac_gd32_write(struct dac_gd32_data *data,
|
||||
uint8_t dacx, uint32_t value)
|
||||
{
|
||||
switch (dacx) {
|
||||
case 0U:
|
||||
if (data->resolutions[dacx] == 8U) {
|
||||
DAC0_R8DH = value;
|
||||
} else {
|
||||
DAC0_R12DH = value;
|
||||
}
|
||||
break;
|
||||
#if DT_INST_PROP(0, num_channels) == 2
|
||||
case 1U:
|
||||
if (data->resolutions[dacx] == 8U) {
|
||||
DAC1_R8DH = value;
|
||||
} else {
|
||||
DAC1_R12DH = value;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int dac_gd32_channel_setup(const struct device *dev,
|
||||
const struct dac_channel_cfg *channel_cfg)
|
||||
{
|
||||
struct dac_gd32_data *data = dev->data;
|
||||
const struct dac_gd32_config *config = dev->config;
|
||||
uint8_t dacx = channel_cfg->channel_id;
|
||||
|
||||
if (dacx >= config->num_channels) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* GD32 DAC only support 8 or 12 bits resolution */
|
||||
if ((channel_cfg->resolution != 8U) &&
|
||||
(channel_cfg->resolution != 12U)) {
|
||||
LOG_ERR("Only 8 and 12 bits resolutions are supported!");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
data->resolutions[dacx] = channel_cfg->resolution;
|
||||
|
||||
dac_gd32_disable(dacx);
|
||||
dac_gd32_write(data, dacx, config->reset_val);
|
||||
dac_gd32_enable(dacx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac_gd32_write_value(const struct device *dev,
|
||||
uint8_t dacx, uint32_t value)
|
||||
{
|
||||
struct dac_gd32_data *data = dev->data;
|
||||
const struct dac_gd32_config *config = dev->config;
|
||||
|
||||
if (dacx >= config->num_channels) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
dac_gd32_write(data, dacx, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dac_driver_api dac_gd32_driver_api = {
|
||||
.channel_setup = dac_gd32_channel_setup,
|
||||
.write_value = dac_gd32_write_value
|
||||
};
|
||||
|
||||
static int dac_gd32_init(const struct device *dev)
|
||||
{
|
||||
const struct dac_gd32_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to apply pinctrl state");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rcu_periph_clock_enable(cfg->rcu_periph_clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PINCTRL_DT_INST_DEFINE(0)
|
||||
|
||||
static struct dac_gd32_data dac_gd32_data_0;
|
||||
|
||||
static const struct dac_gd32_config dac_gd32_cfg_0 = {
|
||||
.reg = DT_INST_REG_ADDR(0),
|
||||
.rcu_periph_clock = DT_INST_PROP(0, rcu_periph_clock),
|
||||
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
|
||||
.num_channels = DT_INST_PROP(0, num_channels),
|
||||
.reset_val = DT_INST_PROP(0, reset_val),
|
||||
};
|
||||
|
||||
DEVICE_DT_INST_DEFINE(0, &dac_gd32_init, NULL, &dac_gd32_data_0,
|
||||
&dac_gd32_cfg_0, POST_KERNEL, CONFIG_DAC_INIT_PRIORITY,
|
||||
&dac_gd32_driver_api);
|
Loading…
Add table
Add a link
Reference in a new issue