diff --git a/boards/arm/gd32f450i_eval/doc/index.rst b/boards/arm/gd32f450i_eval/doc/index.rst index 105ffca21f8f5..55d98f919968f 100644 --- a/boards/arm/gd32f450i_eval/doc/index.rst +++ b/boards/arm/gd32f450i_eval/doc/index.rst @@ -68,6 +68,9 @@ The board configuration supports the following hardware features: * - USART - :kconfig:`CONFIG_SERIAL` - :dtcompatible:`gd,gd32-usart` + * - DAC + - :kconfig:`CONFIG_DAC` + - :dtcompatible:`gd,gd32-dac` Serial Port =========== diff --git a/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi b/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi index 3ba9e064d4765..ff9f09724042d 100644 --- a/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi +++ b/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi @@ -11,4 +11,10 @@ pinmux = , ; }; }; + + dac_default: dac_default { + group1 { + pinmux = ; + }; + }; }; diff --git a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts index 729468a5cca5b..01c335fdea336 100644 --- a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts +++ b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts @@ -26,3 +26,9 @@ pinctrl-0 = <&usart0_default>; pinctrl-names = "default"; }; + +&dac { + status = "okay"; + pinctrl-0 = <&dac_default>; + pinctrl-names = "default"; +}; diff --git a/drivers/dac/CMakeLists.txt b/drivers/dac/CMakeLists.txt index e535516644057..f353b17ae072c 100644 --- a/drivers/dac/CMakeLists.txt +++ b/drivers/dac/CMakeLists.txt @@ -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) diff --git a/drivers/dac/Kconfig b/drivers/dac/Kconfig index d1b19ddbc62b8..4618f21e0aa6a 100644 --- a/drivers/dac/Kconfig +++ b/drivers/dac/Kconfig @@ -44,4 +44,6 @@ source "drivers/dac/Kconfig.dacx3608" source "drivers/dac/Kconfig.mcp4725" +source "drivers/dac/Kconfig.gd32" + endif # DAC diff --git a/drivers/dac/Kconfig.gd32 b/drivers/dac/Kconfig.gd32 new file mode 100644 index 0000000000000..d4db044d4675d --- /dev/null +++ b/drivers/dac/Kconfig.gd32 @@ -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 diff --git a/drivers/dac/dac_gd32.c b/drivers/dac/dac_gd32.c new file mode 100644 index 0000000000000..0dcd27b77d41a --- /dev/null +++ b/drivers/dac/dac_gd32.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2021 BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gd_gd32_dac + +#include +#include +#include +#include + +#include +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); diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi b/dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi new file mode 100644 index 0000000000000..30adec9199da3 --- /dev/null +++ b/dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + dac: dac@40007400 { + compatible = "gd,gd32-dac"; + reg = <0x40007400 0x400>; + rcu-periph-clock = <0x71d>; + num-channels = <1>; + label = "DAC"; + status = "disabled"; + #io-channel-cells = <1>; + }; + }; +}; diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi b/dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi index a01677ad17700..b72211064426a 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi +++ b/dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi b/dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi index f7e34166a6a86..7d15db8f5b309 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi +++ b/dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi index d84dd989f9983..73ba3e4a9aa44 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi +++ b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi @@ -118,6 +118,16 @@ label = "USART_7"; }; + dac: dac@40007400 { + compatible = "gd,gd32-dac"; + reg = <0x40007400 0x400>; + rcu-periph-clock = <0x101d>; + num-channels = <2>; + label = "DAC"; + status = "disabled"; + #io-channel-cells = <1>; + }; + pinctrl: pin-controller@40020000 { compatible = "gd,gd32-pinctrl-af"; reg = <0x40020000 0x2400>; diff --git a/dts/bindings/dac/gd,gd32-dac.yaml b/dts/bindings/dac/gd,gd32-dac.yaml new file mode 100644 index 0000000000000..0ad2ff2b952f5 --- /dev/null +++ b/dts/bindings/dac/gd,gd32-dac.yaml @@ -0,0 +1,34 @@ +# Copyright (c) 2021 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: GigaDevice GD32 series DAC module + +compatible: "gd,gd32-dac" + +include: [dac-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + rcu-periph-clock: + type: int + description: Reset Control Unit Peripheral Clock ID + required: true + + num-channels: + type: int + description: Number of DAC output channels + required: true + + reset-val: + type: int + default: 0 + description: Reset value of DAC output. Defaults to 0, the SoC default. + required: false + + "#io-channel-cells": + const: 1 + +io-channel-cells: + - output diff --git a/samples/drivers/dac/README.rst b/samples/drivers/dac/README.rst index e0a54990f09a3..7f63569fffd8e 100644 --- a/samples/drivers/dac/README.rst +++ b/samples/drivers/dac/README.rst @@ -176,6 +176,19 @@ built and executed for the :ref:`bl5340_dvk` as follows: DAC output is available on pin 1 of the MCP4725. +Building and Running for GD32450I-EVAL +====================================== +The sample can be built and executed for the +:ref:`gd32f450i_eval` as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/dac + :board: gd32f450i_eval + :goals: build flash + :compact: + +Bridge the JP23 to DAC with the jumper cap, then DAC output will available on JP7. + Sample output ============= diff --git a/samples/drivers/dac/boards/gd32f450i_eval.overlay b/samples/drivers/dac/boards/gd32f450i_eval.overlay new file mode 100644 index 0000000000000..38aa2ea304da2 --- /dev/null +++ b/samples/drivers/dac/boards/gd32f450i_eval.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2021 BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + dac = <&dac>; + dac-channel-id = <0>; + dac-resolution = <12>; + }; +}; diff --git a/samples/drivers/dac/sample.yaml b/samples/drivers/dac/sample.yaml index 5375038b4d248..fd75822640254 100644 --- a/samples/drivers/dac/sample.yaml +++ b/samples/drivers/dac/sample.yaml @@ -7,6 +7,7 @@ tests: arduino_zero frdm_k22f frdm_k64f nucleo_f091rc nucleo_g071rb nucleo_g431rb nucleo_l073rz nucleo_l152re twr_ke18f nucleo_f767zi nucleo_f429zi bl652_dvk bl653_dvk bl654_dvk bl5340_dvk_cpuapp stm32f3_disco stm32l562e_dk nucleo_l552ze_q + gd32f450i_eval depends_on: dac harness: console harness_config: