From f7d62761e7a4f650058c1194d7bc73a664fd5f92 Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Wed, 16 Mar 2022 13:49:21 +0800 Subject: [PATCH 1/6] dts: introduce gd32 adc Add support for gd32 adc. Signed-off-by: HaiLong Yang --- dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi | 13 ++++++ dts/arm/gigadevice/gd32f403/gd32f403.dtsi | 33 +++++++++++++ dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi | 33 +++++++++++++ dts/bindings/adc/gd,gd32-adc.yaml | 56 +++++++++++++++++++++++ dts/riscv/gigadevice/gd32vf103.dtsi | 24 ++++++++++ include/zephyr/dt-bindings/adc/gd32f3x0.h | 24 ++++++++++ 6 files changed, 183 insertions(+) create mode 100644 dts/bindings/adc/gd,gd32-adc.yaml create mode 100644 include/zephyr/dt-bindings/adc/gd32f3x0.h diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi b/dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi index 3bf08dbc9c37e3..307f9ec3d1a213 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi +++ b/dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi @@ -6,6 +6,7 @@ #include #include +#include / { cpus { @@ -57,6 +58,18 @@ label = "USART_1"; }; + adc0: adc@40012400 { + compatible = "gd,gd32-adc"; + reg = <0x40012400 0x400>; + interrupts = <12 0>; + rcu-periph-clock = <0x609>; + rcu-clock-source = ; + channels = <16>; + status = "disabled"; + label = "ADC_0"; + #io-channel-cells = <1>; + }; + pinctrl: pin-controller@48000000 { compatible = "gd,gd32-pinctrl-af"; reg = <0x48000000 0x1800>; diff --git a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi index b87f2e46d17d5d..0407689959f345 100644 --- a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi +++ b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi @@ -128,6 +128,39 @@ #size-cells = <0>; }; + adc0: adc@40012400 { + compatible = "gd,gd32-adc"; + reg = <0x40012400 0x400>; + interrupts = <18 0>; + rcu-periph-clock = <0x609>; + channels = <16>; + status = "disabled"; + label = "ADC_0"; + #io-channel-cells = <1>; + }; + + adc1: adc@40012800 { + compatible = "gd,gd32-adc"; + reg = <0x40012800 0x400>; + interrupts = <18 0>; + rcu-periph-clock = <0x60A>; + channels = <16>; + status = "disabled"; + label = "ADC_1"; + #io-channel-cells = <1>; + }; + + adc2: adc@40013c00 { + compatible = "gd,gd32-adc"; + reg = <0x40013c00 0x400>; + interrupts = <47 0>; + rcu-periph-clock = <0x60F>; + channels = <16>; + status = "disabled"; + label = "ADC_2"; + #io-channel-cells = <1>; + }; + exti: interrupt-controller@40010400 { compatible = "gd,gd32-exti"; interrupt-controller; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi index 3d6933a0e746c6..5762babf42cfd6 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi +++ b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi @@ -204,6 +204,39 @@ #size-cells = <0>; }; + adc0: adc@40012000 { + compatible = "gd,gd32-adc"; + reg = <0x40012000 0x100>; + interrupts = <18 0>; + rcu-periph-clock = <0x1108>; + channels = <16>; + status = "disabled"; + label = "ADC_0"; + #io-channel-cells = <1>; + }; + + adc1: adc@40012100 { + compatible = "gd,gd32-adc"; + reg = <0x40012100 0x100>; + interrupts = <18 0>; + rcu-periph-clock = <0x1109>; + channels = <16>; + status = "disabled"; + label = "ADC_1"; + #io-channel-cells = <1>; + }; + + adc2: adc@40012200 { + compatible = "gd,gd32-adc"; + reg = <0x40012200 0x100>; + interrupts = <18 0>; + rcu-periph-clock = <0x110A>; + channels = <16>; + status = "disabled"; + label = "ADC_2"; + #io-channel-cells = <1>; + }; + syscfg: syscfg@40013800 { compatible = "gd,gd32-syscfg"; reg = <0x40013800 0x400>; diff --git a/dts/bindings/adc/gd,gd32-adc.yaml b/dts/bindings/adc/gd,gd32-adc.yaml new file mode 100644 index 00000000000000..503e1456fae945 --- /dev/null +++ b/dts/bindings/adc/gd,gd32-adc.yaml @@ -0,0 +1,56 @@ +# Copyright (c) 2022 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: GigaDevice GD32 ADC + +# gd32 adc irq have some special cases as below: +# 1. adc number no larger than 3. +# 2. adc0 and adc1 share the same irq number. +# 3. For gd32f4xx, adc2 share the same irq number with adc0 and adc1. +# +# To cover this cases, adc_gd32 driver use node-label 'adc0', 'adc1' and +# 'adc2' to handle gd32 adc irq config directly. +# +# Sorry for the restriction, But new added gd32 adc node-label must be 'adc0', +# 'adc1' and 'adc2'. + +compatible: "gd,gd32-adc" + +include: [adc-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + rcu-periph-clock: + type: int + description: Reset Control Unit Peripheral Clock ID + required: true + + rcu-clock-source: + type: int + required: false + description: | + Some GD32 ADC have additional clock source, like IRC14M or IRC28M. + This property used to select the clock and related prescaler, valid + values defined at 'dts-bindings/adc/gd32xxx.h' headers. + + channels: + type: int + description: Number of external channels + required: true + + interrupts: + required: true + + "#io-channel-cells": + const: 1 + + pinctrl-0: + required: true + + pinctrl-names: + required: true + +io-channel-cells: + - input diff --git a/dts/riscv/gigadevice/gd32vf103.dtsi b/dts/riscv/gigadevice/gd32vf103.dtsi index 525ea60537cb7b..3770a23e5d33e0 100644 --- a/dts/riscv/gigadevice/gd32vf103.dtsi +++ b/dts/riscv/gigadevice/gd32vf103.dtsi @@ -99,6 +99,30 @@ label = "UART_2"; }; + adc0: adc@40012400 { + compatible = "gd,gd32-adc"; + reg = <0x40012400 0x400>; + interrupts = <37 0>; + interrupt-parent = <&eclic>; + rcu-periph-clock = <0x609>; + channels = <16>; + status = "disabled"; + label = "ADC_0"; + #io-channel-cells = <1>; + }; + + adc1: adc@40012800 { + compatible = "gd,gd32-adc"; + reg = <0x40012800 0x400>; + interrupts = <37 0>; + interrupt-parent = <&eclic>; + rcu-periph-clock = <0x60A>; + channels = <16>; + status = "disabled"; + label = "ADC_1"; + #io-channel-cells = <1>; + }; + dac: dac@40007400 { compatible = "gd,gd32-dac"; reg = <0x40007400 0x400>; diff --git a/include/zephyr/dt-bindings/adc/gd32f3x0.h b/include/zephyr/dt-bindings/adc/gd32f3x0.h new file mode 100644 index 00000000000000..a10a6bea3dada6 --- /dev/null +++ b/include/zephyr/dt-bindings/adc/gd32f3x0.h @@ -0,0 +1,24 @@ +/* + * Copyright 2022 BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_GD32F3X0_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_GD32F3X0_H_ + +/* + * ADC clock and prescaler definition refer from rcu_adc_clock_enum which + * defined at GD32F3X0 RCU HAL. + */ +#define GD32_RCU_ADCCK_IRC28M_DIV2 0 +#define GD32_RCU_ADCCK_IRC28M 1 +#define GD32_RCU_ADCCK_APB2_DIV2 2 +#define GD32_RCU_ADCCK_AHB_DIV3 3 +#define GD32_RCU_ADCCK_APB2_DIV4 4 +#define GD32_RCU_ADCCK_AHB_DIV5 5 +#define GD32_RCU_ADCCK_APB2_DIV6 6 +#define GD32_RCU_ADCCK_AHB_DIV7 7 +#define GD32_RCU_ADCCK_APB2_DIV8 8 +#define GD32_RCU_ADCCK_AHB_DIV9 9 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ADC_GD32F3X0_H_ */ From c071015c7e98cff8be470cbf3db3253b9587a25b Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Wed, 16 Mar 2022 13:50:41 +0800 Subject: [PATCH 2/6] drivers: adc: introduce gd32 adc driver This driver based on single conversion mode with regular channel. Signed-off-by: HaiLong Yang --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.gd32 | 13 ++ drivers/adc/adc_gd32.c | 461 +++++++++++++++++++++++++++++++++++++ 4 files changed, 477 insertions(+) create mode 100644 drivers/adc/Kconfig.gd32 create mode 100644 drivers/adc/adc_gd32.c diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 8e0d279e3e8746..f86666dc6d6524 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -24,3 +24,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_EMUL adc_emul.c) zephyr_library_sources_ifdef(CONFIG_ADC_XEC_V2 adc_mchp_xec_v2.c) zephyr_library_sources_ifdef(CONFIG_ADC_TEST adc_test.c) zephyr_library_sources_ifdef(CONFIG_ADC_ADS1X1X adc_ads1x1x.c) +zephyr_library_sources_ifdef(CONFIG_ADC_GD32 adc_gd32.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 3e5453b8ce4550..4369cb3c7e82c6 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -72,4 +72,6 @@ source "drivers/adc/Kconfig.test" source "drivers/adc/Kconfig.ads1x1x" +source "drivers/adc/Kconfig.gd32" + endif # ADC diff --git a/drivers/adc/Kconfig.gd32 b/drivers/adc/Kconfig.gd32 new file mode 100644 index 00000000000000..119733bf34b291 --- /dev/null +++ b/drivers/adc/Kconfig.gd32 @@ -0,0 +1,13 @@ +# ADC configuration options + +# Copyright (c) 2021 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +DT_COMPAT_GD_GD32_ADC := gd,gd32-adc + +config ADC_GD32 + bool "GD32 ADC driver" + depends on (SOC_FAMILY_GD32 || SOC_SERIES_GD32VF103) + default $(dt_compat_enabled,$(DT_COMPAT_GD_GD32_ADC)) + help + Enable GigaDevice GD32 ADC driver diff --git a/drivers/adc/adc_gd32.c b/drivers/adc/adc_gd32.c new file mode 100644 index 00000000000000..a08a05e2e8845e --- /dev/null +++ b/drivers/adc/adc_gd32.c @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2022 BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gd_gd32_adc + +#include +#include +#include +#include + +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#include +LOG_MODULE_REGISTER(adc_gd32, CONFIG_ADC_LOG_LEVEL); + +/** + * @brief gd32 adc irq have some special cases as below: + * 1. adc number no larger than 3. + * 2. adc0 and adc1 share the same irq number. + * 3. For gd32f4xx, adc2 share the same irq number with adc0 and adc1. + * + * To cover this cases, gd32_adc driver use node-label 'adc0', 'adc1' and + * 'adc2' to handle gd32 adc irq config directly.' + * + * @note Sorry for the restriction, But new added gd32 adc node-label must be 'adc0', + * 'adc1' and 'adc2'. + */ +#define ADC0_NODE DT_NODELABEL(adc0) +#define ADC1_NODE DT_NODELABEL(adc1) +#define ADC2_NODE DT_NODELABEL(adc2) + +#define ADC0_ENABLE DT_NODE_HAS_STATUS(ADC0_NODE, okay) +#define ADC1_ENABLE DT_NODE_HAS_STATUS(ADC1_NODE, okay) +#define ADC2_ENABLE DT_NODE_HAS_STATUS(ADC2_NODE, okay) + +#ifndef ADC0 +/** + * @brief The name of gd32 ADC HAL are different between single and multi ADC SoCs. + * This adjust the single ADC SoC HAL, so we can call gd32 ADC HAL in a common way. + */ +#undef ADC_STAT +#undef ADC_CTL0 +#undef ADC_CTL1 +#undef ADC_SAMPT0 +#undef ADC_SAMPT1 +#undef ADC_RSQ2 +#undef ADC_RDATA + +#define ADC_STAT(adc0) REG32((adc0) + 0x00000000U) +#define ADC_CTL0(adc0) REG32((adc0) + 0x00000004U) +#define ADC_CTL1(adc0) REG32((adc0) + 0x00000008U) +#define ADC_SAMPT0(adc0) REG32((adc0) + 0x0000000CU) +#define ADC_SAMPT1(adc0) REG32((adc0) + 0x00000010U) +#define ADC_RSQ2(adc0) REG32((adc0) + 0x00000034U) +#define ADC_RDATA(adc0) REG32((adc0) + 0x0000004CU) +#endif + +#define SPT_WIDTH 3U +#define SAMPT1_SIZE 10U + +#if defined(CONFIG_SOC_SERIES_GD32F4XX) +#define SMP_TIME(x) ADC_SAMPLETIME_##x + +static const uint16_t acq_time_tbl[8] = {3, 15, 28, 56, 84, 112, 144, 480}; +static const uint32_t table_samp_time[] = { + SMP_TIME(3), + SMP_TIME(15), + SMP_TIME(28), + SMP_TIME(56), + SMP_TIME(84), + SMP_TIME(112), + SMP_TIME(144), + SMP_TIME(480) +}; +#else +#define SMP_TIME(x) ADC_SAMPLETIME_##x##POINT5 + +static const uint16_t acq_time_tbl[8] = {2, 8, 14, 29, 42, 56, 72, 240}; +static const uint32_t table_samp_time[] = { + SMP_TIME(1), + SMP_TIME(7), + SMP_TIME(13), + SMP_TIME(28), + SMP_TIME(41), + SMP_TIME(55), + SMP_TIME(71), + SMP_TIME(239) +}; +#endif + +struct adc_gd32_config { + uint32_t reg; + uint32_t rcu_periph_clock; +#ifdef CONFIG_SOC_SERIES_GD32F3X0 + uint32_t rcu_clock_source; +#endif + uint8_t channels; + const struct pinctrl_dev_config *pcfg; + uint8_t irq_num; + void (*irq_config_func)(void); +}; + +struct adc_gd32_data { + struct adc_context ctx; + const struct device *dev; + uint16_t *buffer; + uint16_t *repeat_buffer; +}; + +static void adc_gd32_isr(const struct device *dev) +{ + struct adc_gd32_data *data = dev->data; + const struct adc_gd32_config *cfg = dev->config; + + if (ADC_STAT(cfg->reg) & ADC_STAT_EOC) { + *data->buffer++ = ADC_RDATA(cfg->reg); + + /* Disable EOC interrupt. */ + ADC_CTL0(cfg->reg) &= ~ADC_CTL0_EOCIE; + /* Clear EOC bit. */ + ADC_STAT(cfg->reg) &= ~ADC_STAT_EOC; + + adc_context_on_sampling_done(&data->ctx, dev); + } +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_gd32_data *data = CONTAINER_OF(ctx, struct adc_gd32_data, ctx); + const struct device *dev = data->dev; + const struct adc_gd32_config *cfg = dev->config; + + data->repeat_buffer = data->buffer; + + /* Enable EOC interrupt */ + ADC_CTL0(cfg->reg) |= ADC_CTL0_EOCIE; + + /* Set ADC software conversion trigger. */ + ADC_CTL1(cfg->reg) |= ADC_CTL1_SWRCST; +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct adc_gd32_data *data = CONTAINER_OF(ctx, struct adc_gd32_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static inline void adc_gd32_calibration(const struct adc_gd32_config *cfg) +{ + ADC_CTL1(cfg->reg) |= ADC_CTL1_RSTCLB; + /* Wait for calibration registers initialized. */ + while (ADC_CTL1(cfg->reg) & ADC_CTL1_RSTCLB) { + } + + ADC_CTL1(cfg->reg) |= ADC_CTL1_CLB; + /* Wait for calibration complete. */ + while (ADC_CTL1(cfg->reg) & ADC_CTL1_CLB) { + } +} + +static int adc_gd32_configure_sampt(const struct adc_gd32_config *cfg, + uint8_t channel, uint16_t acq_time) +{ + uint8_t index = 0, offset; + + if (acq_time != ADC_ACQ_TIME_DEFAULT) { + /* Acquisition time unit is adc clock cycle. */ + if (ADC_ACQ_TIME_UNIT(acq_time) != ADC_ACQ_TIME_TICKS) { + return -EINVAL; + } + + for ( ; index < ARRAY_SIZE(acq_time_tbl); index++) { + if (ADC_ACQ_TIME_VALUE(acq_time) <= acq_time_tbl[index]) { + break; + } + } + + if (ADC_ACQ_TIME_VALUE(acq_time) != acq_time_tbl[index]) { + return -ENOTSUP; + } + } + + if (channel < SAMPT1_SIZE) { + offset = SPT_WIDTH * channel; + ADC_SAMPT1(cfg->reg) &= ~(ADC_SAMPTX_SPTN << offset); + ADC_SAMPT1(cfg->reg) |= table_samp_time[index] << offset; + } else { + offset = SPT_WIDTH * (channel - SAMPT1_SIZE); + ADC_SAMPT0(cfg->reg) &= ~(ADC_SAMPTX_SPTN << offset); + ADC_SAMPT0(cfg->reg) |= table_samp_time[index] << offset; + } + + return 0; +} + +static int adc_gd32_channel_setup(const struct device *dev, + const struct adc_channel_cfg *chan_cfg) +{ + const struct adc_gd32_config *cfg = dev->config; + + if (chan_cfg->gain != ADC_GAIN_1) { + LOG_ERR("Gain is not valid"); + return -ENOTSUP; + } + + if (chan_cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Reference is not valid"); + return -ENOTSUP; + } + + if (chan_cfg->differential) { + LOG_ERR("Differential sampling not supported"); + return -ENOTSUP; + } + + if (chan_cfg->channel_id >= cfg->channels) { + LOG_ERR("Invalid channel (%u)", chan_cfg->channel_id); + return -EINVAL; + } + + return adc_gd32_configure_sampt(cfg, chan_cfg->channel_id, + chan_cfg->acquisition_time); +} + +static int adc_gd32_start_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + struct adc_gd32_data *data = dev->data; + const struct adc_gd32_config *cfg = dev->config; + uint8_t resolution_id; + uint32_t index; + + index = find_lsb_set(sequence->channels) - 1; + if (sequence->channels > BIT(index)) { + LOG_ERR("Only single channel supported"); + return -ENOTSUP; + } + + switch (sequence->resolution) { + case 12U: + resolution_id = 0U; + break; + case 10U: + resolution_id = 1U; + break; + case 8U: + resolution_id = 2U; + break; + case 6U: + resolution_id = 3U; + break; + default: + return -EINVAL; + } + +#if defined(CONFIG_SOC_SERIES_GD32F4XX) || \ + defined(CONFIG_SOC_SERIES_GD32F3X0) + ADC_CTL0(cfg->reg) &= ~ADC_CTL0_DRES; + ADC_CTL0(cfg->reg) |= CTL0_DRES(resolution_id); +#elif defined(CONFIG_SOC_SERIES_GD32F403) + ADC_OVSAMPCTL(cfg->reg) &= ~ADC_OVSAMPCTL_DRES; + ADC_OVSAMPCTL(cfg->reg) |= OVSAMPCTL_DRES(resolution_id); +#elif defined(CONFIG_SOC_SERIES_GD32VF103) + ADC_OVSCR(cfg->reg) &= ~ADC_OVSCR_DRES; + ADC_OVSCR(cfg->reg) |= OVSCR_DRES(resolution_id); +#endif + + if (sequence->calibrate) { + adc_gd32_calibration(cfg); + } + + /* Signle conversion mode with regular group. */ + ADC_RSQ2(cfg->reg) &= ~ADC_RSQX_RSQN; + ADC_RSQ2(cfg->reg) = index; + + data->buffer = sequence->buffer; + + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int adc_gd32_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + struct adc_gd32_data *data = dev->data; + int error; + + adc_context_lock(&data->ctx, false, NULL); + error = adc_gd32_start_read(dev, sequence); + adc_context_release(&data->ctx, error); + + return error; +} + +#ifdef CONFIG_ADC_ASYNC +static int adc_gd32_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_gd32_data *data = dev->data; + int error; + + adc_context_lock(&data->ctx, true, async); + error = adc_gd32_start_read(dev, sequence); + adc_context_release(&data->ctx, error); + + return error; +} +#endif /* CONFIG_ADC_ASYNC */ + +static struct adc_driver_api adc_gd32_driver_api = { + .channel_setup = adc_gd32_channel_setup, + .read = adc_gd32_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_gd32_read_async, +#endif /* CONFIG_ADC_ASYNC */ +}; + +static int adc_gd32_init(const struct device *dev) +{ + struct adc_gd32_data *data = dev->data; + const struct adc_gd32_config *cfg = dev->config; + int ret; + + data->dev = dev; + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_SOC_SERIES_GD32F3X0 + /* Select adc clock source and its prescaler. */ + rcu_adc_clock_config(cfg->rcu_clock_source); +#endif + + rcu_periph_clock_enable(cfg->rcu_periph_clock); + +#if defined(CONFIG_SOC_SERIES_GD32F403) || \ + defined(CONFIG_SOC_SERIES_GD32VF103) || \ + defined(CONFIG_SOC_SERIES_GD32F3X0) + /* Set SWRCST as the regular channel external trigger. */ + ADC_CTL1(cfg->reg) &= ~ADC_CTL1_ETSRC; + ADC_CTL1(cfg->reg) |= CTL1_ETSRC(7); + + /* Enable external trigger for regular channel. */ + ADC_CTL1(cfg->reg) |= ADC_CTL1_ETERC; +#endif + + /* Enable ADC */ + ADC_CTL1(cfg->reg) |= ADC_CTL1_ADCON; + + adc_gd32_calibration(cfg); + + cfg->irq_config_func(); + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +#define HANDLE_SHARED_IRQ(n, active_irq) \ + static const struct device *dev_##n = DEVICE_DT_INST_GET(n); \ + const struct adc_gd32_config *cfg_##n = dev_##n->config; \ + \ + if ((cfg_##n->irq_num == active_irq) && \ + (ADC_CTL0(cfg_##n->reg) & ADC_CTL0_EOCIE)) { \ + adc_gd32_isr(dev_##n); \ + } + +static void adc_gd32_global_irq_handler(const struct device *dev) +{ + const struct adc_gd32_config *cfg = dev->config; + + LOG_DBG("global irq handler: %u", cfg->irq_num); + + DT_INST_FOREACH_STATUS_OKAY_VARGS(HANDLE_SHARED_IRQ, (cfg->irq_num)); +} + +static void adc_gd32_global_irq_cfg(void) +{ + static bool global_irq_init = true; + + if (!global_irq_init) { + return; + } + + global_irq_init = false; + +#if ADC0_ENABLE + /* Shared irq config default to adc0. */ + IRQ_CONNECT(DT_IRQN(ADC0_NODE), + DT_IRQ(ADC0_NODE, priority), + adc_gd32_global_irq_handler, + DEVICE_DT_GET(ADC0_NODE), + 0); + irq_enable(DT_IRQN(ADC0_NODE)); +#elif ADC1_ENABLE + IRQ_CONNECT(DT_IRQN(ADC1_NODE), + DT_IRQ(ADC1_NODE, priority), + adc_gd32_global_irq_handler, + DEVICE_DT_GET(ADC1_NODE), + 0); + irq_enable(DT_IRQN(ADC1_NODE)); +#endif + +#if (ADC0_ENABLE || ADC1_ENABLE) && \ + defined(CONFIG_SOC_SERIES_GD32F4XX) + /* gd32f4xx adc2 share the same irq number with adc0 and adc1. */ +#elif ADC2_ENABLE + IRQ_CONNECT(DT_IRQN(ADC2_NODE), + DT_IRQ(ADC2_NODE, priority), + adc_gd32_global_irq_handler, + DEVICE_DT_GET(ADC2_NODE), + 0); + irq_enable(DT_IRQN(ADC2_NODE)); +#endif +} + +#ifdef CONFIG_SOC_SERIES_GD32F3X0 +#define ADC_CLOCK_SOURCE(n) \ + .rcu_clock_source = DT_INST_PROP(n, rcu_periph_clock) +#else +#define ADC_CLOCK_SOURCE(n) +#endif + +#define ADC_GD32_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static struct adc_gd32_data adc_gd32_data_##n = { \ + ADC_CONTEXT_INIT_TIMER(adc_gd32_data_##n, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_gd32_data_##n, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_gd32_data_##n, ctx), \ + }; \ + const static struct adc_gd32_config adc_gd32_config_##n = { \ + .reg = DT_INST_REG_ADDR(n), \ + .rcu_periph_clock = DT_INST_PROP(n, rcu_periph_clock), \ + .channels = DT_INST_PROP(n, channels), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .irq_num = DT_INST_IRQN(n), \ + .irq_config_func = adc_gd32_global_irq_cfg, \ + ADC_CLOCK_SOURCE(n) \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + &adc_gd32_init, NULL, \ + &adc_gd32_data_##n, &adc_gd32_config_##n, \ + POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ + &adc_gd32_driver_api); \ + +DT_INST_FOREACH_STATUS_OKAY(ADC_GD32_INIT) From c7540071646da1a3e4d3dee2c78a66a60209016a Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Wed, 16 Mar 2022 13:51:09 +0800 Subject: [PATCH 3/6] boards: add adc support for gd32 boards This add adc support for gd32f350r_eval, gd32f450i_eval and gd32vf103v_eval boards. Signed-off-by: HaiLong Yang --- boards/arm/gd32f350r_eval/doc/index.rst | 3 +++ boards/arm/gd32f350r_eval/gd32f350r_eval-pinctrl.dtsi | 6 ++++++ boards/arm/gd32f350r_eval/gd32f350r_eval.dts | 8 ++++++++ boards/arm/gd32f403z_eval/doc/index.rst | 3 ++- boards/arm/gd32f403z_eval/gd32f403z_eval-pinctrl.dtsi | 6 ++++++ boards/arm/gd32f403z_eval/gd32f403z_eval.dts | 6 ++++++ boards/arm/gd32f450i_eval/doc/index.rst | 3 +++ boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi | 6 ++++++ boards/arm/gd32f450i_eval/gd32f450i_eval.dts | 6 ++++++ boards/riscv/gd32vf103v_eval/doc/index.rst | 3 +++ boards/riscv/gd32vf103v_eval/gd32vf103v_eval-pinctrl.dtsi | 6 ++++++ boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts | 6 ++++++ 12 files changed, 61 insertions(+), 1 deletion(-) diff --git a/boards/arm/gd32f350r_eval/doc/index.rst b/boards/arm/gd32f350r_eval/doc/index.rst index 674b61e829c6b3..7aa8ce3bb80b17 100644 --- a/boards/arm/gd32f350r_eval/doc/index.rst +++ b/boards/arm/gd32f350r_eval/doc/index.rst @@ -62,6 +62,9 @@ The board configuration supports the following hardware features: * - PINMUX - :kconfig:option:`CONFIG_PINCTRL` - :dtcompatible:`gd,gd32-pinctrl-af` + * - ADC + - :kconfig:option:`CONFIG_ADC` + - :dtcompatible:`gd,gd32-adc` Serial Port =========== diff --git a/boards/arm/gd32f350r_eval/gd32f350r_eval-pinctrl.dtsi b/boards/arm/gd32f350r_eval/gd32f350r_eval-pinctrl.dtsi index 40d1c1514058ee..043f678f34378c 100644 --- a/boards/arm/gd32f350r_eval/gd32f350r_eval-pinctrl.dtsi +++ b/boards/arm/gd32f350r_eval/gd32f350r_eval-pinctrl.dtsi @@ -11,4 +11,10 @@ pinmux = , ; }; }; + + adc0_default: adc0_default { + group1 { + pinmux = ; + }; + }; }; diff --git a/boards/arm/gd32f350r_eval/gd32f350r_eval.dts b/boards/arm/gd32f350r_eval/gd32f350r_eval.dts index 1f1e90693aef3c..cd09e4f4304383 100644 --- a/boards/arm/gd32f350r_eval/gd32f350r_eval.dts +++ b/boards/arm/gd32f350r_eval/gd32f350r_eval.dts @@ -26,3 +26,11 @@ pinctrl-0 = <&usart0_default>; pinctrl-names = "default"; }; + +&adc0 { + status = "okay"; + /* Set ADC0 clock source to RCU_ADCCK_APB2_DIV4. */ + rcu-clock-source = <4>; + pinctrl-0 = <&adc0_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/gd32f403z_eval/doc/index.rst b/boards/arm/gd32f403z_eval/doc/index.rst index dbf31aea5130aa..54d3756792123d 100644 --- a/boards/arm/gd32f403z_eval/doc/index.rst +++ b/boards/arm/gd32f403z_eval/doc/index.rst @@ -72,7 +72,8 @@ The board configuration supports the following hardware features: +-----------+------------+-----------------------+ | UART | on-chip | serial port-polling | +-----------+------------+-----------------------+ - +| ADC | on-chip | ADC | ++-----------+------------+-----------------------+ Serial Port =========== diff --git a/boards/arm/gd32f403z_eval/gd32f403z_eval-pinctrl.dtsi b/boards/arm/gd32f403z_eval/gd32f403z_eval-pinctrl.dtsi index 14194428177a07..4d375482a1a3dc 100644 --- a/boards/arm/gd32f403z_eval/gd32f403z_eval-pinctrl.dtsi +++ b/boards/arm/gd32f403z_eval/gd32f403z_eval-pinctrl.dtsi @@ -12,6 +12,12 @@ }; }; + adc0_default: adc0_default { + group1 { + pinmux = ; + }; + }; + pwm0_default: pwm0_default { group1 { pinmux = ; diff --git a/boards/arm/gd32f403z_eval/gd32f403z_eval.dts b/boards/arm/gd32f403z_eval/gd32f403z_eval.dts index 6e021a2241a774..1315ef628be182 100644 --- a/boards/arm/gd32f403z_eval/gd32f403z_eval.dts +++ b/boards/arm/gd32f403z_eval/gd32f403z_eval.dts @@ -88,6 +88,12 @@ status = "okay"; }; +&adc0 { + status = "okay"; + pinctrl-0 = <&adc0_default>; + pinctrl-names = "default"; +}; + &usart0 { status = "okay"; current-speed = <115200>; diff --git a/boards/arm/gd32f450i_eval/doc/index.rst b/boards/arm/gd32f450i_eval/doc/index.rst index aac8ff80900f87..23d4c97ae510d2 100644 --- a/boards/arm/gd32f450i_eval/doc/index.rst +++ b/boards/arm/gd32f450i_eval/doc/index.rst @@ -86,6 +86,9 @@ The board configuration supports the following hardware features: * - EEPROM - :kconfig:option:`CONFIG_EEPROM` - :dtcompatible:`atmel,at24` + * - ADC + - :kconfig:option:`CONFIG_ADC` + - :dtcompatible:`gd,gd32-adc` Serial Port =========== diff --git a/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi b/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi index ba51202ecef741..b7a763db40b4f9 100644 --- a/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi +++ b/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi @@ -12,6 +12,12 @@ }; }; + adc0_default: adc0_default { + group1 { + 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 f7b7f0ccc7f39b..3588689d92bd27 100644 --- a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts +++ b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts @@ -104,6 +104,12 @@ pinctrl-names = "default"; }; +&adc0 { + status = "okay"; + pinctrl-0 = <&adc0_default>; + pinctrl-names = "default"; +}; + &dac { status = "okay"; pinctrl-0 = <&dac_default>; diff --git a/boards/riscv/gd32vf103v_eval/doc/index.rst b/boards/riscv/gd32vf103v_eval/doc/index.rst index a32305eff78ab5..09e6344651209b 100644 --- a/boards/riscv/gd32vf103v_eval/doc/index.rst +++ b/boards/riscv/gd32vf103v_eval/doc/index.rst @@ -67,6 +67,9 @@ The board configuration supports the following hardware features: * - USART - :kconfig:option:`CONFIG_SERIAL` - :dtcompatible:`gd,gd32-usart` + * - ADC + - :kconfig:option:`CONFIG_ADC` + - :dtcompatible:`gd,gd32-adc` Serial Port =========== diff --git a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval-pinctrl.dtsi b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval-pinctrl.dtsi index 12c5773566e6d9..7960ac373f7126 100644 --- a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval-pinctrl.dtsi +++ b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval-pinctrl.dtsi @@ -30,4 +30,10 @@ ; }; }; + + adc0_default: adc0_default { + group1 { + pinmux = ; + }; + }; }; diff --git a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts index f9426837f20c6d..44bba140dcd4c9 100644 --- a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts +++ b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts @@ -137,3 +137,9 @@ jedec-id = [c8 40 15]; }; }; + +&adc0 { + status = "okay"; + pinctrl-0 = <&adc0_default>; + pinctrl-names = "default"; +}; From 4e96a5f400748fd18365dd2af7c23a01b4a4af5c Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Wed, 16 Mar 2022 13:51:40 +0800 Subject: [PATCH 4/6] samples: drivers: adc: add gd32 boards support This add gd32 boards support for the adc sample. Signed-off-by: HaiLong Yang --- .../drivers/adc/boards/gd32f350r_eval.overlay | 27 +++++++++++++++++++ .../drivers/adc/boards/gd32f403z_eval.overlay | 27 +++++++++++++++++++ .../drivers/adc/boards/gd32f450i_eval.overlay | 27 +++++++++++++++++++ .../adc/boards/gd32vf103v_eval.overlay | 27 +++++++++++++++++++ samples/drivers/adc/sample.yaml | 2 +- 5 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 samples/drivers/adc/boards/gd32f350r_eval.overlay create mode 100644 samples/drivers/adc/boards/gd32f403z_eval.overlay create mode 100644 samples/drivers/adc/boards/gd32f450i_eval.overlay create mode 100644 samples/drivers/adc/boards/gd32vf103v_eval.overlay diff --git a/samples/drivers/adc/boards/gd32f350r_eval.overlay b/samples/drivers/adc/boards/gd32f350r_eval.overlay new file mode 100644 index 00000000000000..33ccdace971d67 --- /dev/null +++ b/samples/drivers/adc/boards/gd32f350r_eval.overlay @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2022 BrainCo Inc. + */ + +#include + + / { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 11>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@b { + reg = <11>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/boards/gd32f403z_eval.overlay b/samples/drivers/adc/boards/gd32f403z_eval.overlay new file mode 100644 index 00000000000000..e5a0e931b9a954 --- /dev/null +++ b/samples/drivers/adc/boards/gd32f403z_eval.overlay @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2022 BrainCo Inc. + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 13>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@d { + reg = <13>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/boards/gd32f450i_eval.overlay b/samples/drivers/adc/boards/gd32f450i_eval.overlay new file mode 100644 index 00000000000000..e5a0e931b9a954 --- /dev/null +++ b/samples/drivers/adc/boards/gd32f450i_eval.overlay @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2022 BrainCo Inc. + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 13>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@d { + reg = <13>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/boards/gd32vf103v_eval.overlay b/samples/drivers/adc/boards/gd32vf103v_eval.overlay new file mode 100644 index 00000000000000..42903b3af55503 --- /dev/null +++ b/samples/drivers/adc/boards/gd32vf103v_eval.overlay @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2022 BrainCo Inc. + */ + +#include + + / { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 13>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@d { + reg = <13>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/sample.yaml b/samples/drivers/adc/sample.yaml index c8aad45b9ba4c3..465b8b9c138379 100644 --- a/samples/drivers/adc/sample.yaml +++ b/samples/drivers/adc/sample.yaml @@ -6,7 +6,7 @@ tests: depends_on: adc platform_allow: nucleo_l073rz disco_l475_iot1 cc3220sf_launchxl cc3235sf_launchxl stm32l496g_disco nrf51dk_nrf51422 nrf52840dk_nrf52840 - mec172xevb_assy6906 + mec172xevb_assy6906 gd32f350r_eval gd32f450i_eval gd32vf103v_eval gd32f403z_eval integration_platforms: - nucleo_l073rz - nrf52840dk_nrf52840 From 3afe7ce614ffcd5aa06c4f74fc60ff716b63d9d2 Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Wed, 16 Mar 2022 15:03:48 +0800 Subject: [PATCH 5/6] MAINTAINERS: add cameled as gd32 platform collaborator Add cameled as gd32 platform collaborator. Signed-off-by: HaiLong Yang --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b65fb0dd550239..d1f82d5ea99cda 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1553,6 +1553,7 @@ GD32 Platforms: - gmarull collaborators: - soburi + - cameled files: - boards/arm/gd32*/ - boards/riscv/gd32*/ From af3c808d0644bf217c807e5539e1f7a79ec2d3c2 Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Tue, 28 Jun 2022 00:36:26 +0800 Subject: [PATCH 6/6] dst: gigadevice: change usart3 address to lower case DTS node address should use lower case. This fix an incorrect gd32f403 usart3 node address. Signed-off-by: HaiLong Yang --- dts/arm/gigadevice/gd32f403/gd32f403.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi index 0407689959f345..360e59e401df0a 100644 --- a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi +++ b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi @@ -77,9 +77,9 @@ label = "USART_2"; }; - uart3: usart@40004C00 { + uart3: usart@40004c00 { compatible = "gd,gd32-usart"; - reg = <0x40004C00 0x400>; + reg = <0x40004c00 0x400>; interrupts = <52 0>; rcu-periph-clock = <0x714>; status = "disabled";