Compare commits

...

12 commits

Author SHA1 Message Date
1320c2e9b6 drivers: adc: add a WCH CH32V00x ADC driver
Signed-off-by: Michael Hope <mlhx@google.com>
2024-11-03 21:16:17 +01:00
9ba0ccf52d runners: add minichlink
This commit adds a runner wrapper for the 'minichlink' program which
offers a free, open mechanism to use the CH-LinkE programming dongle for
the CH32V003.

https://github.com/cnlohr/ch32v003fun/tree/master/minichlink

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-03 16:16:31 +05:30
81080a1ce1 boards: add ch32v003evt
This commit adds support for the CH32V003EVT board which features a
32-bit general-purpose RISC-V MCU.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-03 16:16:23 +05:30
2ab7d4317a drivers: add the gpio driver for wch ch32v003
This commit adds the gpio driver for WCH CH32V003.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:54:51 +05:30
bb64ab5f90 drivers: add the pfic interrupt controller
This commit adds the pfic interrupt controller driver for WCH CH32V003.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:54:51 +05:30
f8bc6df2be drivers: add the ch32v00x usart driver
This commit adds the usart driver for WCH CH32V003.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:54:51 +05:30
f52a0135d8 drivers: add the ch32v00x systick driver
This commit adds the systick driver for WCH CH32V003.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:54:51 +05:30
2af384ddfb drivers: add the ch32v00x clock controller
This commit adds the clock driver for WCH CH32V003.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:54:48 +05:30
5f14e9385d drivers: add ch32v00x pinctrl support
This commit adds the pinctrl driver for WCH CH32V003.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:46:08 +05:30
5c3c784846 soc: add wch_ch32v003 soc files
This commit adds the soc support for WCH CH32V003.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:46:05 +05:30
233f93aa24 dts: add the ch32v003 dtsi
This commit adds the dtsi and bindings for the WCH CH32V003 which is a
32-bit general-purpose RISC-V MCU.

Signed-off-by: Michael Hope <michaelh@juju.nz>
Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:32:21 +05:30
Dhiru Kholia
155bcc0385 west: add the hal_wch
This is used for WCH chips including the CH32V003.

Signed-off-by: Dhiru Kholia <dhiru.kholia@gmail.com>
2024-11-02 21:32:21 +05:30
81 changed files with 2103 additions and 0 deletions

View file

@ -4871,6 +4871,14 @@ West:
labels:
- "platform: TI"
"West project: hal_wch":
status: maintained
maintainers:
- nzmichaelh
- kholia
files:
- modules/hal_wch/
"West project: hal_wurthelektronik":
status: maintained
maintainers:

View file

@ -0,0 +1,5 @@
# Copyright (c) 2024 Dhiru Kholia
# SPDX-License-Identifier: Apache-2.0
board_set_flasher_ifnset(minichlink)
board_finalize_runner_args(minichlink)

View file

@ -0,0 +1,5 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
config BOARD_CH32V003EVT
select SOC_CH32V003

View file

@ -0,0 +1,8 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
board_runner_args(openocd "--use-elf" "--cmd-reset-halt" "halt")
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
board_runner_args(minichlink)
include(${ZEPHYR_BASE}/boards/common/minichlink.board.cmake)

View file

@ -0,0 +1,6 @@
board:
name: ch32v003evt
full_name: WCH CH32V003EVT
vendor: wch
socs:
- name: ch32v003

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2024 Michael Hope <michaelh@juju.nz>
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/pinctrl/ch32v003-pinctrl.h>
&pinctrl {
usart1_default: usart1_default {
group1 {
pinmux = <USART1_TX_PD5_0>;
output-high;
drive-push-pull;
slew-rate = "max-speed-10mhz";
};
group2 {
pinmux = <USART1_RX_PD6_0>;
bias-pull-up;
};
};
};

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2024 Michael Hope <michaelh@juju.nz>
* SPDX-License-Identifier: Apache-2.0
*/
/dts-v1/;
#include <wch/ch32v00x.dtsi>
#include "ch32v003evt-pinctrl.dtsi"
/ {
model = "ch32v003evt";
compatible = "wch,ch32v003";
chosen {
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,console = &usart1;
zephyr,shell-uart = &usart1;
};
leds {
compatible = "gpio-leds";
red_led: led0 {
gpios = <&gpiod 4 GPIO_ACTIVE_HIGH>;
};
};
aliases {
led0 = &red_led;
};
};
&clk_hse {
clock-frequency = <DT_FREQ_M(24)>;
status = "okay";
};
&pll {
clocks = <&clk_hse>;
status = "okay";
};
&rcc {
clocks = <&pll>;
};
&gpiod {
status = "okay";
};
&usart1 {
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&usart1_default>;
pinctrl-names = "default";
};

View file

@ -0,0 +1,11 @@
identifier: ch32v003evt
name: WCH CH32V003 Evaluation Board
type: mcu
arch: riscv
toolchain:
- cross-compile
- zephyr
ram: 2
flash: 16
supported:
- gpio

View file

@ -0,0 +1,8 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
CONFIG_MAIN_STACK_SIZE=512
CONFIG_IDLE_STACK_SIZE=256
CONFIG_ISR_STACK_SIZE=256

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View file

@ -0,0 +1,107 @@
.. zephyr:board:: ch32v003evt
Overview
********
The `WCH`_ CH32V003EVT hardware provides support for QingKe 32-bit RISC-V2A
processor and the following devices:
* CLOCK
* :abbr:`GPIO (General Purpose Input Output)`
* :abbr:`NVIC (Nested Vectored Interrupt Controller)`
The board is equipped with two LEDs. The `WCH webpage on CH32V003`_ contains
the processor's information and the datasheet.
Hardware
********
The QingKe 32-bit RISC-V2A processor of the WCH CH32V003EVT is clocked by an
external crystal and runs at 48 MHz.
Supported Features
==================
The ``ch32v003evt`` board target supports the following hardware features:
+-----------+------------+----------------------+
| Interface | Controller | Driver/Component |
+===========+============+======================+
| CLOCK | on-chip | clock_control |
+-----------+------------+----------------------+
| GPIO | on-chip | gpio |
+-----------+------------+----------------------+
| PWM | on-chip | pwm |
+-----------+------------+----------------------+
| PINCTRL | on-chip | pinctrl |
+-----------+------------+----------------------+
| TIMER | on-chip | timer |
+-----------+------------+----------------------+
| UART | on-chip | uart |
+-----------+------------+----------------------+
Other hardware features have not been enabled yet for this board.
Connections and IOs
===================
LED
---
* LED1 = Unconnected. Connect to an I/O pin (PD4).
Programming and Debugging
*************************
Applications for the ``ch32v003evt`` board target can be built and flashed
in the usual way (see :ref:`build_an_application` and :ref:`application_run`
for more details); however, an external programmer is required since the board
does not have any built-in debug support.
The following pins of the external programmer must be connected to the
following pins on the PCB (see image):
* VCC = VCC (do not power the board from the USB port at the same time)
* GND = GND
* SWIO = PD1
Flashing
========
You can use ``minichlink`` to flash the board. Once ``minichlink`` has been set
up, build and flash applications as usual (see :ref:`build_an_application` and
:ref:`application_run` for more details).
Here is an example for the :zephyr:code-sample:`blinky` application.
.. zephyr-app-commands::
:zephyr-app: samples/basic/blinky
:board: ch32v003evt
:goals: build flash
Debugging
=========
This board can be debugged via OpenOCD or ``minichlink``.
Testing the LED on the WCH CH32V003EVT
**************************************
There is 1 sample program that allow you to test that the LED on the board is
working properly with Zephyr:
.. code-block:: console
samples/basic/blinky
You can build and flash the examples to make sure Zephyr is running
correctly on your board. The button and LED definitions can be found
in :zephyr_file:`boards/wch/ch32v003evt/ch32v003evt.dts`.
References
**********
.. target-notes::
.. _WCH: http://www.wch-ic.com
.. _WCH webpage on CH32V003: https://www.wch-ic.com/products/CH32V003.html

View file

@ -0,0 +1,15 @@
#interface wlink
adapter driver wlink
wlink_set
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME
$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0
echo "Ready for Remote Connections"

10
boards/wch/index.rst Normal file
View file

@ -0,0 +1,10 @@
.. _boards-wch:
WCH - Nanjing Qinheng Microelectronics Co.
##########################################
.. toctree::
:maxdepth: 1
:glob:
**/*

View file

@ -55,3 +55,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_GAU adc_mcux_gau_adc.c)
zephyr_library_sources_ifdef(CONFIG_ADC_AMBIQ adc_ambiq.c)
zephyr_library_sources_ifdef(CONFIG_ADC_RENESAS_RA adc_renesas_ra.c)
zephyr_library_sources_ifdef(CONFIG_ADC_MAX32 adc_max32.c)
zephyr_library_sources_ifdef(CONFIG_ADC_CH32V00X adc_ch32v00x.c)

View file

@ -134,4 +134,6 @@ source "drivers/adc/Kconfig.renesas_ra"
source "drivers/adc/Kconfig.max32"
source "drivers/adc/Kconfig.ch32v00x"
endif # ADC

View file

@ -0,0 +1,9 @@
# Copyright (c) 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
config ADC_CH32V00X
bool "WCH CH32V00x ADC Driver"
default y
depends on DT_HAS_WCH_ADC_ENABLED
help
Enable the WCH CH32V00x family Analog-to-Digital Converter (ADC) driver.

148
drivers/adc/adc_ch32v00x.c Normal file
View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2024 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT wch_adc
#include <soc.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
LOG_MODULE_REGISTER(adc_ch32v00x, CONFIG_ADC_LOG_LEVEL);
#include <ch32_adc.h>
struct adc_ch32v00x_data {
};
struct adc_ch32v00x_config {
ADC_TypeDef *regs;
const struct device *clock_dev;
uint8_t clock_id;
};
static int adc_ch32v00x_channel_setup(const struct device *dev,
const struct adc_channel_cfg *channel_cfg)
{
if (channel_cfg->gain != ADC_GAIN_1) {
return -EINVAL;
}
if (channel_cfg->reference != ADC_REF_INTERNAL) {
return -EINVAL;
}
if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
return -EINVAL;
}
if (channel_cfg->differential) {
return -EINVAL;
}
if (channel_cfg->channel_id >= 10) {
return -EINVAL;
}
return 0;
}
static int adc_ch32v00x_read(const struct device *dev, const struct adc_sequence *sequence)
{
const struct adc_ch32v00x_config *config = dev->config;
ADC_TypeDef *regs = config->regs;
uint32_t channels = sequence->channels;
int rsqr = 2;
int sequence_id = 0;
int total_channels = 0;
int i;
uint16_t *samples = sequence->buffer;
if (sequence->options != NULL) {
return -ENOTSUP;
}
if (sequence->resolution != 10) {
return -EINVAL;
}
if (sequence->oversampling != 0) {
return -ENOTSUP;
}
if (sequence->channels >= (1 << 10)) {
return -EINVAL;
}
if (sequence->calibrate) {
regs->CTLR2 |= ADC_RSTCAL;
while ((regs->CTLR2 & ADC_RSTCAL) != 0) {
}
regs->CTLR2 |= ADC_CAL;
while ((ADC1->CTLR2 & ADC_CAL) != 0) {
}
}
regs->RSQR1 = 0;
regs->RSQR2 = 0;
regs->RSQR3 = 0;
for (i = 0; channels != 0; i++, channels >>= 1) {
if ((channels & 1) != 0) {
total_channels++;
(&regs->RSQR1)[rsqr] |= i << sequence_id;
/* The channel IDs are packed 5 bits at a time into RSQR3 down to RSQR1.
*/
sequence_id += ADC_SQ2_0;
if (sequence_id >= 32) {
sequence_id = 0;
rsqr--;
}
}
}
if (total_channels == 0) {
return 0;
}
if (sequence->buffer_size < total_channels * sizeof(*samples)) {
return -ENOMEM;
}
/* Set the number of channels to read. Note that '0' means 'one channel'. */
regs->RSQR1 |= (total_channels - 1) * ADC_L_0;
regs->CTLR2 |= ADC_SWSTART;
for (i = 0; i < total_channels; i++) {
while ((regs->STATR & ADC_EOC) == 0) {
}
*samples++ = regs->RDATAR;
}
return 0;
}
static int adc_ch32v00x_init(const struct device *dev)
{
const struct adc_ch32v00x_config *config = dev->config;
ADC_TypeDef *regs = config->regs;
clock_control_on(config->clock_dev, (clock_control_subsys_t *)(uintptr_t)config->clock_id);
regs->CTLR2 = ADC_ADON | ADC_EXTSEL;
return 0;
}
#define ADC_CH32V00X_DEVICE(n) \
static const struct adc_driver_api adc_ch32v00x_api_##n = { \
.channel_setup = adc_ch32v00x_channel_setup, \
.read = adc_ch32v00x_read, \
.ref_internal = DT_INST_PROP(n, vref_mv), \
}; \
\
static const struct adc_ch32v00x_config adc_ch32v00x_config_##n = { \
.regs = (ADC_TypeDef *)DT_INST_REG_ADDR(n), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
.clock_id = DT_INST_CLOCKS_CELL(n, id), \
}; \
\
DEVICE_DT_INST_DEFINE(n, adc_ch32v00x_init, NULL, NULL, &adc_ch32v00x_config_##n, \
POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, &adc_ch32v00x_api_##n);
DT_INST_FOREACH_STATUS_OKAY(ADC_CH32V00X_DEVICE)

View file

@ -98,3 +98,4 @@ endif()
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MAX32 clock_control_max32.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_control_nrf_auxpll.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_WCH_RCC clock_control_wch_rcc.c)

View file

@ -100,4 +100,6 @@ source "drivers/clock_control/Kconfig.arm_scmi"
source "drivers/clock_control/Kconfig.silabs"
source "drivers/clock_control/Kconfig.wch_rcc"
endif # CLOCK_CONTROL

View file

@ -0,0 +1,7 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
config CLOCK_CONTROL_WCH_RCC
bool "WCH CH32V00x Reset and Clock Control (RCC) driver"
default y
depends on DT_HAS_WCH_RCC_ENABLED

View file

@ -0,0 +1,154 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT wch_rcc
#include <stdint.h>
#include <zephyr/arch/cpu.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/sys/util_macro.h>
#include <ch32_rcc.h>
#define WCH_RCC_CLOCK_ID_OFFSET(id) (((id) >> 5) & 0xFF)
#define WCH_RCC_CLOCK_ID_BIT(id) ((id) & 0x1F)
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pll)) && DT_NODE_HAS_PROP(DT_NODELABEL(pll), clocks)
#define DT_PLL_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(pll))
#if DT_SAME_NODE(DT_PLL_CLOCKS_CTRL, DT_NODELABEL(clk_hsi))
#define WCH_RCC_PLL_SRC_IS_HSI 1
#endif
#if DT_SAME_NODE(DT_PLL_CLOCKS_CTRL, DT_NODELABEL(clk_hse))
#define WCH_RCC_PLL_SRC_IS_HSE 1
#endif
#endif
#define DT_RCC_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(rcc))
#if DT_SAME_NODE(DT_RCC_CLOCKS_CTRL, DT_NODELABEL(pll))
#define WCH_RCC_SRC_IS_PLL 1
#endif
#if DT_SAME_NODE(DT_RCC_CLOCKS_CTRL, DT_NODELABEL(clk_hsi))
#define WCH_RCC_SRC_IS_HSI 1
#endif
#if DT_SAME_NODE(DT_RCC_CLOCKS_CTRL, DT_NODELABEL(clk_hse))
#define WCH_RCC_SRC_IS_HSE 1
#endif
struct clock_control_wch_rcc_config {
RCC_TypeDef *regs;
};
static int clock_control_wch_rcc_on(const struct device *dev, clock_control_subsys_t sys)
{
const struct clock_control_wch_rcc_config *config = dev->config;
RCC_TypeDef *regs = config->regs;
uint8_t id = (uintptr_t)sys;
uint32_t reg = (uint32_t)(&regs->AHBPCENR + WCH_RCC_CLOCK_ID_OFFSET(id));
uint32_t val = sys_read32(reg);
reg |= BIT(WCH_RCC_CLOCK_ID_BIT(id));
sys_write32(val, reg);
return 0;
}
static int clock_control_wch_rcc_get_rate(const struct device *dev, clock_control_subsys_t sys,
uint32_t *rate)
{
const struct clock_control_wch_rcc_config *config = dev->config;
RCC_TypeDef *regs = config->regs;
uint32_t cfgr0 = regs->CFGR0;
uint32_t sysclk = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
uint32_t ahbclk = sysclk;
if ((cfgr0 & RCC_HPRE_3) != 0) {
/* The range 0b1000 divides by a power of 2, where 0b1000 is /2, 0b1001 is /4, etc.
*/
ahbclk /= 2 << ((cfgr0 >> 4) & 0x07);
} else {
/* The range 0b0nnn divides by n + 1, where 0b0000 is /1, 0b001 is /2, etc. */
ahbclk /= ((cfgr0 >> 4) & 0x07) + 1;
}
/* The datasheet says that AHB == APB1 == APB2, but the registers imply that APB1 and APB2
* can be divided from the AHB clock. Assume that the clock tree diagram is correct and
* always return AHB.
*/
*rate = ahbclk;
return 0;
}
static struct clock_control_driver_api clock_control_wch_rcc_api = {
.on = clock_control_wch_rcc_on,
.get_rate = clock_control_wch_rcc_get_rate,
};
static int clock_control_wch_rcc_init(const struct device *dev)
{
if (IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V00X_PLL_CLOCK_ENABLED)) {
/* Disable the PLL before potentially changing the input clocks. */
RCC->CTLR &= ~RCC_PLLON;
}
/* Always enable the LSI. */
RCC->RSTSCKR |= RCC_LSION;
while ((RCC->RSTSCKR & RCC_LSIRDY) == 0) {
}
if (IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V00X_HSI_CLOCK_ENABLED)) {
RCC->CTLR |= RCC_HSION;
while ((RCC->CTLR & RCC_HSIRDY) == 0) {
}
}
if (IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V00X_HSE_CLOCK_ENABLED)) {
RCC->CTLR |= RCC_HSEON;
while ((RCC->CTLR & RCC_HSERDY) == 0) {
}
}
if (IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V00X_PLL_CLOCK_ENABLED)) {
if (IS_ENABLED(WCH_RCC_PLL_SRC_IS_HSE)) {
RCC->CFGR0 |= RCC_PLLSRC;
} else if (IS_ENABLED(WCH_RCC_PLL_SRC_IS_HSI)) {
RCC->CFGR0 &= ~RCC_PLLSRC;
}
RCC->CTLR |= RCC_PLLON;
while ((RCC->CTLR & RCC_PLLRDY) == 0) {
}
}
if (IS_ENABLED(WCH_RCC_SRC_IS_HSI)) {
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
} else if (IS_ENABLED(WCH_RCC_SRC_IS_HSE)) {
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSE;
} else if (IS_ENABLED(WCH_RCC_SRC_IS_PLL)) {
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
}
RCC->CTLR |= RCC_CSSON;
/* Clear the interrupt flags. */
RCC->INTR = RCC_CSSC | RCC_PLLRDYC | RCC_HSERDYC | RCC_LSIRDYC;
/* HCLK = SYSCLK = APB1 */
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_HPRE) | RCC_HPRE_DIV1;
/* Set the Flash to 0 wait state */
FLASH->ACTLR = (FLASH->ACTLR & ~FLASH_ACTLR_LATENCY) | FLASH_ACTLR_LATENCY_1;
return 0;
}
#define CLOCK_CONTROL_WCH_RCC_INIT(idx) \
static const struct clock_control_wch_rcc_config clock_control_wch_rcc_##idx##_config = { \
.regs = (RCC_TypeDef *)DT_INST_REG_ADDR(idx), \
}; \
DEVICE_DT_INST_DEFINE(idx, clock_control_wch_rcc_init, NULL, NULL, \
&clock_control_wch_rcc_##idx##_config, PRE_KERNEL_1, \
CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_wch_rcc_api);
DT_INST_FOREACH_STATUS_OKAY(CLOCK_CONTROL_WCH_RCC_INIT)

View file

@ -94,6 +94,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_TCA6424A gpio_tca6424a.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_TEST gpio_test.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_TLE9104 gpio_tle9104.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_WCH_GPIO wch_gpio_ch32v00x.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_XEC gpio_mchp_xec.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_XEC_V2 gpio_mchp_xec_v2.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_AXI gpio_xlnx_axi.c)

View file

@ -178,6 +178,7 @@ source "drivers/gpio/Kconfig.sx1509b"
source "drivers/gpio/Kconfig.tca6424a"
source "drivers/gpio/Kconfig.test"
source "drivers/gpio/Kconfig.tle9104"
source "drivers/gpio/Kconfig.wch_ch32v00x"
source "drivers/gpio/Kconfig.xec"
source "drivers/gpio/Kconfig.xlnx"
source "drivers/gpio/Kconfig.xlnx_ps"

View file

@ -0,0 +1,7 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
config GPIO_WCH_GPIO
bool "WCH CH32V00x GPIO driver"
depends on DT_HAS_WCH_GPIO_ENABLED
default y

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/irq.h>
#include <ch32_gpio.h>
#define DT_DRV_COMPAT wch_gpio
struct gpio_ch32v00x_config {
struct gpio_driver_config common;
GPIO_TypeDef *regs;
const struct device *clock_dev;
uint8_t clock_id;
};
struct gpio_ch32v00x_data {
struct gpio_driver_data common;
};
static int gpio_ch32v00x_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
{
const struct gpio_ch32v00x_config *config = dev->config;
GPIO_TypeDef *regs = config->regs;
uint32_t cnf_mode;
uint32_t bshr = 0;
if ((flags & GPIO_OUTPUT) != 0) {
cnf_mode = 0x01;
if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
bshr = 1 << pin;
} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
bshr = 1 << (16 + pin);
}
} else if ((flags & GPIO_INPUT) != 0) {
if ((flags & GPIO_PULL_UP) != 0) {
cnf_mode = 0x08;
bshr = 1 << pin;
} else if ((flags & GPIO_PULL_DOWN) != 0) {
cnf_mode = 0x08;
bshr = 1 << (16 + pin);
} else {
cnf_mode = 0x04;
}
} else {
cnf_mode = 0x00;
}
regs->CFGLR = (regs->CFGLR & ~(0x0F << (4 * pin))) | (cnf_mode << (4 * pin));
regs->BSHR = bshr;
return 0;
}
static int gpio_ch32v00x_port_get_raw(const struct device *dev, uint32_t *value)
{
const struct gpio_ch32v00x_config *config = dev->config;
*value = config->regs->INDR;
return 0;
}
static int gpio_ch32v00x_port_set_masked_raw(const struct device *dev, uint32_t mask,
uint32_t value)
{
const struct gpio_ch32v00x_config *config = dev->config;
config->regs->BSHR = ((~value & mask) << 16) | (value & mask);
return 0;
}
static int gpio_ch32v00x_port_set_bits_raw(const struct device *dev, uint32_t pins)
{
const struct gpio_ch32v00x_config *config = dev->config;
config->regs->BSHR = pins;
return 0;
}
static int gpio_ch32v00x_port_clear_bits_raw(const struct device *dev, uint32_t pins)
{
const struct gpio_ch32v00x_config *config = dev->config;
config->regs->BCR = pins;
return 0;
}
static int gpio_ch32v00x_port_toggle_bits(const struct device *dev, uint32_t pins)
{
const struct gpio_ch32v00x_config *config = dev->config;
uint32_t changed = (config->regs->OUTDR ^ pins) & pins;
config->regs->BSHR = (changed & pins) | (~changed & pins) << 16;
return 0;
}
static const struct gpio_driver_api gpio_ch32v00x_driver_api = {
.pin_configure = gpio_ch32v00x_configure,
.port_get_raw = gpio_ch32v00x_port_get_raw,
.port_set_masked_raw = gpio_ch32v00x_port_set_masked_raw,
.port_set_bits_raw = gpio_ch32v00x_port_set_bits_raw,
.port_clear_bits_raw = gpio_ch32v00x_port_clear_bits_raw,
.port_toggle_bits = gpio_ch32v00x_port_toggle_bits,
};
static int gpio_ch32v00x_init(const struct device *dev)
{
const struct gpio_ch32v00x_config *config = dev->config;
clock_control_on(config->clock_dev, (clock_control_subsys_t *)(uintptr_t)config->clock_id);
return 0;
}
#define GPIO_CH32V00X_INIT(idx) \
static const struct gpio_ch32v00x_config gpio_ch32v00x_##idx##_config = { \
.common = \
{ \
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \
}, \
.regs = (GPIO_TypeDef *)DT_INST_REG_ADDR(idx), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \
.clock_id = DT_INST_CLOCKS_CELL(idx, id), \
}; \
\
static struct gpio_ch32v00x_data gpio_ch32v00x_##idx##_data; \
\
DEVICE_DT_INST_DEFINE(idx, gpio_ch32v00x_init, NULL, &gpio_ch32v00x_##idx##_data, \
&gpio_ch32v00x_##idx##_config, PRE_KERNEL_1, \
CONFIG_GPIO_INIT_PRIORITY, &gpio_ch32v00x_driver_api);
DT_INST_FOREACH_STATUS_OKAY(GPIO_CH32V00X_INIT)

View file

@ -43,6 +43,7 @@ zephyr_library_sources_ifdef(CONFIG_NXP_PINT intc_nxp_pint.c)
zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_renesas_ra_icu.c)
zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.c)
zephyr_library_sources_ifdef(CONFIG_INTC_MTK_ADSP intc_mtk_adsp.c)
zephyr_library_sources_ifdef(CONFIG_WCH_PFIC intc_wch_pfic.c)
if(CONFIG_INTEL_VTD_ICTL)
zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include)

View file

@ -108,4 +108,6 @@ source "drivers/interrupt_controller/Kconfig.nxp_irqsteer"
source "drivers/interrupt_controller/Kconfig.mtk_adsp"
source "drivers/interrupt_controller/Kconfig.wch_pfic"
endmenu

View file

@ -0,0 +1,9 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
config WCH_PFIC
bool "WCH Programmable Fast Interrupt Controller (PFIC)"
default y
depends on DT_HAS_WCH_PFIC_ENABLED
help
Interrupt controller for WCH PFIC.

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT wch_pfic
#include <ch32_pfic.h>
#include <zephyr/arch/cpu.h>
#include <zephyr/init.h>
#include <zephyr/irq.h>
#include <zephyr/kernel.h>
#define SEVONPEND (1 << 4)
#define WFITOWFE (1 << 3)
void arch_irq_enable(unsigned int irq)
{
PFIC->IENR[irq / 32] = 1 << (irq % 32);
}
void arch_irq_disable(unsigned int irq)
{
PFIC->IRER[irq / 32] |= 1 << (irq % 32);
}
int arch_irq_is_enabled(unsigned int irq)
{
return ((PFIC->ISR[irq >> 5] & (1 << (irq & 0x1F))) != 0);
}
static int pfic_init(void)
{
/* `wfi` is called with interrupts disabled. Configure the PFIC to wake up on any event,
* including any interrupt.
*/
PFIC->SCTLR = SEVONPEND | WFITOWFE;
return 0;
}
SYS_INIT(pfic_init, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY);

View file

@ -40,5 +40,6 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_MAX32 pinctrl_max32.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCMI pinctrl_imx_scmi.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_MCHP_MEC5 pinctrl_mchp_mec5.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_AFIO pinctrl_wch_afio.c)
add_subdirectory(renesas)

View file

@ -67,6 +67,7 @@ source "drivers/pinctrl/Kconfig.ene"
source "drivers/pinctrl/Kconfig.zynqmp"
source "drivers/pinctrl/Kconfig.max32"
source "drivers/pinctrl/Kconfig.mec5"
source "drivers/pinctrl/Kconfig.wch_afio"
rsource "renesas/Kconfig"

View file

@ -0,0 +1,9 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
config PINCTRL_WCH_AFIO
bool "WCH AFIO pin controller driver"
default y
depends on DT_HAS_WCH_AFIO_ENABLED
help
WCH AFIO pin controller driver.

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/dt-bindings/pinctrl/ch32v003-pinctrl.h>
#include <ch32_pinctrl.h>
static GPIO_TypeDef *const wch_afio_pinctrl_regs[] = {
GPIOA,
GPIOC,
GPIOD,
};
int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg)
{
int i;
for (i = 0; i < pin_cnt; i++, pins++) {
uint8_t port = (pins->config >> CH32V003_PINCTRL_PORT_SHIFT) & 0x03;
uint8_t pin = (pins->config >> CH32V003_PINCTRL_PIN_SHIFT) & 0x0F;
uint8_t bit0 = (pins->config >> CH32V003_PINCTRL_RM_BASE_SHIFT) & 0x1F;
uint8_t remap = (pins->config >> CH32V003_PINCTRL_RM_SHIFT) & 0x3;
GPIO_TypeDef *regs = wch_afio_pinctrl_regs[port];
uint32_t pcfr1 = AFIO->PCFR1;
uint8_t cfg = 0;
if (pins->output_high || pins->output_low) {
cfg |= (pins->slew_rate + 1);
if (pins->drive_open_drain) {
cfg |= BIT(2);
}
/* Select the alternate function */
cfg |= BIT(3);
} else {
if (pins->bias_pull_up || pins->bias_pull_down) {
cfg |= BIT(3);
}
}
regs->CFGLR = (regs->CFGLR & ~(0x0F << (pin * 4))) | (cfg << (pin * 4));
if (pins->output_high) {
regs->OUTDR |= BIT(pin);
regs->BSHR |= BIT(pin);
} else if (pins->output_low) {
regs->OUTDR |= BIT(pin);
/* Reset the pin. */
regs->BSHR |= BIT(pin + 16);
} else {
regs->OUTDR &= ~(1 << pin);
if (pins->bias_pull_up) {
regs->BSHR = BIT(pin);
}
if (pins->bias_pull_down) {
regs->BCR = BIT(pin);
}
}
if (bit0 == CH32V003_PINMUX_I2C1_RM) {
pcfr1 |= ((remap & 1) << CH32V003_PINMUX_I2C1_RM) |
(((remap >> 1) & 1) << CH32V003_PINMUX_I2C1_RM1);
} else if (bit0 == CH32V003_PINMUX_USART1_RM) {
pcfr1 |= ((remap & 1) << CH32V003_PINMUX_USART1_RM) |
(((remap >> 1) & 1) << CH32V003_PINMUX_USART1_RM1);
} else {
pcfr1 |= remap << bit0;
}
AFIO->PCFR1 = pcfr1;
}
return 0;
}

View file

@ -73,6 +73,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_STELLARIS uart_stellaris.c)
zephyr_library_sources_ifdef(CONFIG_UART_STM32 uart_stm32.c)
zephyr_library_sources_ifdef(CONFIG_UART_SY1XX uart_sy1xx.c)
zephyr_library_sources_ifdef(CONFIG_UART_TELINK_B91 uart_b91.c)
zephyr_library_sources_ifdef(CONFIG_UART_WCH_USART uart_wch_usart.c)
zephyr_library_sources_ifdef(CONFIG_UART_XEC uart_mchp_xec.c)
zephyr_library_sources_ifdef(CONFIG_UART_XEN_HVC uart_hvc_xen.c)
zephyr_library_sources_ifdef(CONFIG_UART_XEN_HVC_CONSOLEIO uart_hvc_xen_consoleio.c)

View file

@ -221,4 +221,6 @@ rsource "Kconfig.xmc4xxx"
source "drivers/serial/Kconfig.si32"
source "drivers/serial/Kconfig.wch_usart"
endif # SERIAL

View file

@ -0,0 +1,11 @@
# Copyright (c) 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
config UART_WCH_USART
bool "CH32V00x USART driver"
default y
depends on DT_HAS_WCH_USART_ENABLED
select SERIAL_HAS_DRIVER
select PINCTRL
help
This option enables the USART driver for CH32V00x SoC family.

View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2024 Google LLC.
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT wch_usart
#include <errno.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/pinctrl.h>
#include <ch32_uart.h>
struct usart_wch_config {
USART_TypeDef *regs;
const struct device *clock_dev;
uint32_t current_speed;
uint8_t parity;
uint8_t clock_id;
const struct pinctrl_dev_config *pin_cfg;
};
struct usart_wch_data {
};
static int usart_wch_init(const struct device *dev)
{
const struct usart_wch_config *config = dev->config;
USART_TypeDef *regs = config->regs;
uint32_t ctlr1 = USART_CTLR1_TE | USART_CTLR1_RE | USART_CTLR1_UE;
uint32_t clock_rate;
clock_control_subsys_t clock_sys = (clock_control_subsys_t *)(uintptr_t)config->clock_id;
uint32_t divn;
int err;
clock_control_on(config->clock_dev, clock_sys);
err = clock_control_get_rate(config->clock_dev, clock_sys, &clock_rate);
if (err != 0) {
return err;
}
divn = (clock_rate + config->current_speed / 2) / config->current_speed;
switch (config->parity) {
case UART_CFG_PARITY_NONE:
break;
case UART_CFG_PARITY_ODD:
ctlr1 |= USART_CTLR1_PCE | USART_CTLR1_PS;
break;
case UART_CFG_PARITY_EVEN:
ctlr1 |= USART_CTLR1_PCE;
break;
default:
return -EINVAL;
}
regs->BRR = divn;
regs->CTLR1 = ctlr1;
regs->CTLR2 = 0;
regs->CTLR3 = 0;
err = pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT);
if (err != 0) {
return err;
}
return 0;
}
static int usart_wch_poll_in(const struct device *dev, unsigned char *ch)
{
const struct usart_wch_config *config = dev->config;
USART_TypeDef *regs = config->regs;
if ((regs->STATR & USART_STATR_RXNE) == 0) {
return -1;
}
*ch = regs->DATAR;
return 0;
}
static void usart_wch_poll_out(const struct device *dev, unsigned char ch)
{
const struct usart_wch_config *config = dev->config;
USART_TypeDef *regs = config->regs;
while ((regs->STATR & USART_STATR_TXE) == 0) {
}
regs->DATAR = ch;
}
static int usart_wch_err_check(const struct device *dev)
{
const struct usart_wch_config *config = dev->config;
USART_TypeDef *regs = config->regs;
uint32_t statr = regs->STATR;
enum uart_rx_stop_reason errors = 0;
if ((statr & USART_STATR_PE) != 0) {
errors |= UART_ERROR_PARITY;
}
if ((statr & USART_STATR_FE) != 0) {
errors |= UART_ERROR_FRAMING;
}
if ((statr & USART_STATR_NE) != 0) {
errors |= UART_ERROR_NOISE;
}
if ((statr & USART_STATR_ORE) != 0) {
errors |= UART_ERROR_OVERRUN;
}
return errors;
}
static const struct uart_driver_api usart_wch_driver_api = {
.poll_in = usart_wch_poll_in,
.poll_out = usart_wch_poll_out,
.err_check = usart_wch_err_check,
};
#define USART_WCH_INIT(idx) \
PINCTRL_DT_INST_DEFINE(idx); \
static struct usart_wch_data usart_wch_##idx##_data; \
static const struct usart_wch_config usart_wch_##idx##_config = { \
.regs = (USART_TypeDef *)DT_INST_REG_ADDR(idx), \
.current_speed = DT_INST_PROP(idx, current_speed), \
.parity = DT_INST_ENUM_IDX_OR(idx, parity, UART_CFG_PARITY_NONE), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \
.clock_id = DT_INST_CLOCKS_CELL(idx, id), \
.pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
}; \
DEVICE_DT_INST_DEFINE(idx, &usart_wch_init, NULL, &usart_wch_##idx##_data, \
&usart_wch_##idx##_config, PRE_KERNEL_1, \
CONFIG_SERIAL_INIT_PRIORITY, &usart_wch_driver_api);
DT_INST_FOREACH_STATUS_OKAY(USART_WCH_INIT)

View file

@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_ARCV2_TIMER arcv2_timer0.c)
zephyr_library_sources_ifdef(CONFIG_ARM_ARCH_TIMER arm_arch_timer.c)
zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_TIMER intel_adsp_timer.c)
zephyr_library_sources_ifdef(CONFIG_CC13XX_CC26XX_RTC_TIMER cc13xx_cc26xx_rtc_timer.c)
zephyr_library_sources_ifdef(CONFIG_CH32V00X_SYSTICK wch_systick_ch32v00x.c)
zephyr_library_sources_ifdef(CONFIG_CORTEX_M_SYSTICK cortex_m_systick.c)
zephyr_library_sources_ifdef(CONFIG_ESP32_SYS_TIMER esp32_sys_timer.c)
zephyr_library_sources_ifdef(CONFIG_GECKO_BURTC_TIMER gecko_burtc_timer.c)

View file

@ -70,6 +70,7 @@ source "drivers/timer/Kconfig.arcv2"
source "drivers/timer/Kconfig.arm_arch"
source "drivers/timer/Kconfig.cavs"
source "drivers/timer/Kconfig.cc13xx_cc26xx_rtc"
source "drivers/timer/Kconfig.wch_ch32v00x"
source "drivers/timer/Kconfig.cortex_m_systick"
source "drivers/timer/Kconfig.esp32"
source "drivers/timer/Kconfig.gecko"

View file

@ -0,0 +1,8 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
config CH32V00X_SYSTICK
bool "CH32V00X systick timer"
depends on SOC_CH32V003
default y
depends on DT_HAS_WCH_SYSTICK_ENABLED

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT wch_systick
#include <soc.h>
#include <zephyr/device.h>
#include <zephyr/drivers/timer/system_timer.h>
#include <zephyr/irq.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#include <ch32_systick.h>
#define STK_SWIE BIT(31)
#define STK_STRE BIT(3)
#define STK_STCLK BIT(2)
#define STK_STIE BIT(1)
#define STK_STE BIT(0)
#define STK_CNTIF BIT(0)
#define CYCLES_PER_SEC sys_clock_hw_cycles_per_sec()
#define CYCLES_PER_TICK (CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
#define SYSTICK ((SysTick_Type *)(DT_INST_REG_ADDR(0)))
struct ch32v00x_systick_device {
};
static volatile uint32_t ch32v00x_systick_count;
static void ch32v00x_systick_irq(const struct ch32v00x_systick_device *unused)
{
ARG_UNUSED(unused);
SYSTICK->SR = 0;
ch32v00x_systick_count += CYCLES_PER_TICK; /* Track cycles. */
sys_clock_announce(1); /* Poke the scheduler. */
}
uint32_t sys_clock_cycle_get_32(void)
{
return ch32v00x_systick_count + SYSTICK->CNT;
}
uint32_t sys_clock_elapsed(void)
{
return 0;
}
static int ch32v00x_systick_init(void)
{
IRQ_CONNECT(DT_INST_IRQN(0), 0, ch32v00x_systick_irq, NULL, 0);
SYSTICK->SR = 0;
SYSTICK->CMP = CYCLES_PER_TICK;
SYSTICK->CNT = 0;
SYSTICK->CTLR = STK_STRE | STK_STCLK | STK_STIE | STK_STE;
irq_enable(DT_INST_IRQN(0));
return 0;
}
SYS_INIT(ch32v00x_systick_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);

View file

@ -0,0 +1,30 @@
# Copyright (c) 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x Analog-to-digital Converter (ADC)
compatible: "wch,adc"
include: adc-controller.yaml
properties:
reg:
required: true
interrupts:
required: true
clocks:
required: true
vref-mv:
type: int
default: 3300
description: |
Reference voltage of in mV. This is typically VDD.
"#io-channel-cells":
const: 1
io-channel-cells:
- input

View file

@ -0,0 +1,8 @@
# Copyright (c) 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x HSE Clock
compatible: "wch,ch32v00x-hse-clock"
include: [fixed-clock.yaml]

View file

@ -0,0 +1,8 @@
# Copyright (c) 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x HSI Clock
compatible: "wch,ch32v00x-hsi-clock"
include: [fixed-clock.yaml]

View file

@ -0,0 +1,16 @@
# Copyright (c) 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x PLL
compatible: "wch,ch32v00x-pll-clock"
include: [clock-controller.yaml, base.yaml]
properties:
"#clock-cells":
const: 0
clocks:
type: phandle-array
required: true

View file

@ -0,0 +1,15 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x Reset and Clock Control (RCC)
compatible: "wch,rcc"
include: [clock-controller.yaml, base.yaml]
properties:
"#clock-cells":
const: 1
clock-cells:
- id

View file

@ -0,0 +1,19 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x General-Purpose Input/Output (GPIO)
compatible: "wch,gpio"
include: [gpio-controller.yaml, base.yaml]
properties:
reg:
required: true
"#gpio-cells":
const: 2
gpio-cells:
- pin
- flags

View file

@ -0,0 +1,18 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x Programmable Fast Interrupt Controller (PFIC)
compatible: "wch,pfic"
include: [interrupt-controller.yaml, base.yaml]
properties:
reg:
required: true
"#interrupt-cells":
const: 1
interrupt-cells:
- irq

View file

@ -0,0 +1,52 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x AFIO
compatible: "wch,afio"
include: base.yaml
properties:
reg:
required: true
"#address-cells":
required: true
const: 1
"#size-cells":
required: true
const: 1
child-binding:
description: |
Each child node defines the configuration for a particular state.
child-binding:
description: |
The grandchild nodes group pins that share the same pin configuration.
include:
- name: pincfg-node.yaml
property-allowlist:
- bias-high-impedance
- bias-pull-up
- bias-pull-down
- drive-open-drain
- drive-push-pull
- output-high
- output-low
properties:
slew-rate:
type: string
default: "max-speed-2mhz"
enum:
- "max-speed-10mhz"
- "max-speed-2mhz"
- "max-speed-30mhz"
pinmux:
required: true
type: array
description: |
An array of pins sharing the same group properties. The pins should
be defined using pre-defined macros.

View file

@ -0,0 +1,9 @@
description: WCH CH32V00x UART
compatible: "wch,usart"
include: [uart-controller.yaml, pinctrl-device.yaml]
properties:
reg:
required: true

View file

@ -0,0 +1,15 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
description: WCH CH32V00x Systick
compatible: "wch,systick"
include: base.yaml
properties:
reg:
required: true
interrupts:
required: true

View file

@ -722,6 +722,7 @@ vot Vision Optical Technology Co., Ltd.
vxt VXT Ltd
wand Wandbord (Technexion)
waveshare Waveshare Electronics
wch WinChipHead
wd Western Digital Corp.
we Würth Elektronik GmbH.
weact WeAct Studio

161
dts/riscv/wch/ch32v00x.dtsi Normal file
View file

@ -0,0 +1,161 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <freq.h>
#include <mem.h>
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/clock/ch32v00x-clocks.h>
/ {
#address-cells = <1>;
#size-cells = <1>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
device_type = "cpu";
compatible = "wch,qingke-v2";
reg = <0>;
};
};
clocks {
clk_hse: clk-hse {
#clock-cells = <0>;
compatible = "wch,ch32v00x-hse-clock";
status = "disabled";
};
clk_hsi: clk-hsi {
#clock-cells = <0>;
compatible = "wch,ch32v00x-hsi-clock";
clock-frequency = <DT_FREQ_M(24)>;
status = "disabled";
};
clk_lsi: clk-lsi {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <DT_FREQ_K(128)>;
status = "disabled";
};
pll: pll {
#clock-cells = <0>;
compatible = "wch,ch32v00x-pll-clock";
status = "disabled";
};
};
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges;
sram0: memory@20000000 {
compatible = "mmio-sram";
reg = <0x20000000 0x800>;
};
flash: flash-controller@40022000 {
compatible = "wch,ch32v00x-flash-controller";
reg = <0x40022000 0x400>;
#address-cells = <1>;
#size-cells = <1>;
flash0: flash@0 {
compatible = "soc-nv-flash";
reg = <0 0x4000>;
};
};
pfic: interrupt-controller@e000e000 {
compatible = "wch,pfic";
#address-cells = <0>;
#interrupt-cells = <1>;
interrupt-controller;
reg = <0xe000e000 16>;
status = "okay";
};
systick: systimer@e000f000 {
compatible = "wch,systick";
reg = <0xe000f000 16>;
status = "okay";
interrupt-parent = <&pfic>;
interrupts = <12>;
};
pwr: pwr@40007000 {
compatible = "wch,pwr";
reg = <0x40007000 16>;
};
pinctrl: pin-controller@40010000 {
compatible = "wch,afio";
reg = <0x40010000 16>;
#address-cells = <1>;
#size-cells = <1>;
status = "okay";
gpioa: gpio@40010800 {
compatible = "wch,gpio";
reg = <0x40010800 32>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <8>;
clocks = <&rcc CH32V00X_CLOCK_IOPA>;
};
gpioc: gpio@40011000 {
compatible = "wch,gpio";
reg = <0x40011000 32>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <8>;
clocks = <&rcc CH32V00X_CLOCK_IOPC>;
};
gpiod: gpio@40011400 {
compatible = "wch,gpio";
reg = <0x40011400 32>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <8>;
clocks = <&rcc CH32V00X_CLOCK_IOPD>;
};
};
adc1: adc@40012400 {
compatible = "wch,adc";
reg = <0x40012400 16>;
clocks = <&rcc CH32V00X_CLOCK_ADC1>;
interrupt-parent = <&pfic>;
interrupts = <29>;
#io-channel-cells = <1>;
};
usart1: uart@40013800 {
compatible = "wch,usart";
reg = <0x40013800 16>;
clocks = <&rcc CH32V00X_CLOCK_USART1>;
interrupt-parent = <&pfic>;
interrupts = <32>;
};
rcc: rcc@40021000 {
compatible = "wch,rcc";
reg = <0x40021000 16>;
#clock-cells = <1>;
status = "okay";
};
};
};

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __CH32V00X_CLOCKS_H__
#define __CH32V00X_CLOCKS_H__
#define CH32V00X_AHB_PCENR_OFFSET 0
#define CH32V00X_APB2_PCENR_OFFSET 1
#define CH32V00X_APB1_PCENR_OFFSET 2
#define CH32V00X_CLOCK_CONFIG(bus, bit) (((CH32V00X_##bus##_PCENR_OFFSET) << 5) | (bit))
#define CH32V00X_CLOCK_DMA1 CH32V00X_CLOCK_CONFIG(AHB, 0)
#define CH32V00X_CLOCK_SRAM CH32V00X_CLOCK_CONFIG(AHB, 2)
#define CH32V00X_CLOCK_FLITF CH32V00X_CLOCK_CONFIG(AHB, 4)
#define CH32V00X_CLOCK_CRC CH32V00X_CLOCK_CONFIG(AHB, 6)
#define CH32V00X_CLOCK_USB CH32V00X_CLOCK_CONFIG(AHB, 12)
#define CH32V00X_CLOCK_AFIO CH32V00X_CLOCK_CONFIG(APB2, 0)
#define CH32V00X_CLOCK_IOPA CH32V00X_CLOCK_CONFIG(APB2, 2)
#define CH32V00X_CLOCK_IOPB CH32V00X_CLOCK_CONFIG(APB2, 3)
#define CH32V00X_CLOCK_IOPC CH32V00X_CLOCK_CONFIG(APB2, 4)
#define CH32V00X_CLOCK_IOPD CH32V00X_CLOCK_CONFIG(APB2, 5)
#define CH32V00X_CLOCK_ADC1 CH32V00X_CLOCK_CONFIG(APB2, 9)
#define CH32V00X_CLOCK_ADC2 CH32V00X_CLOCK_CONFIG(APB2, 10)
#define CH32V00X_CLOCK_TIM1 CH32V00X_CLOCK_CONFIG(APB2, 11)
#define CH32V00X_CLOCK_SPI1 CH32V00X_CLOCK_CONFIG(APB2, 12)
#define CH32V00X_CLOCK_USART1 CH32V00X_CLOCK_CONFIG(APB2, 14)
#define CH32V00X_CLOCK_TIM2 CH32V00X_CLOCK_CONFIG(APB1, 0)
#define CH32V00X_CLOCK_TIM3 CH32V00X_CLOCK_CONFIG(APB1, 1)
#define CH32V00X_CLOCK_WWDG CH32V00X_CLOCK_CONFIG(APB1, 11)
#define CH32V00X_CLOCK_USART2 CH32V00X_CLOCK_CONFIG(APB1, 17)
#define CH32V00X_CLOCK_I2C1 CH32V00X_CLOCK_CONFIG(APB1, 21)
#define CH32V00X_CLOCK_BKP CH32V00X_CLOCK_CONFIG(APB1, 27)
#define CH32V00X_CLOCK_PWR CH32V00X_CLOCK_CONFIG(APB1, 28)
#define CH32V00X_CLOCK_USB CH32V00X_CLOCK_CONFIG(APB1, 23)
#endif

View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __CH32V003_PINCTRL_H__
#define __CH32V003_PINCTRL_H__
#define CH32V003_PINMUX_PORT_PA 0
#define CH32V003_PINMUX_PORT_PC 1
#define CH32V003_PINMUX_PORT_PD 2
/*
* Defines the starting bit for the remap field. Note that the I2C1 and USART1 fields are not
* contigious.
*/
#define CH32V003_PINMUX_SPI1_RM 0
#define CH32V003_PINMUX_I2C1_RM 1
#define CH32V003_PINMUX_I2C1_RM1 23
#define CH32V003_PINMUX_USART1_RM 2
#define CH32V003_PINMUX_USART1_RM1 21
#define CH32V003_PINMUX_TIM1_RM 6
#define CH32V003_PINMUX_TIM2_RM 8
/* Port number with 0-2 */
#define CH32V003_PINCTRL_PORT_SHIFT 0
/* Pin number 0-15 */
#define CH32V003_PINCTRL_PIN_SHIFT 2
/* Base remap bit 0-31 */
#define CH32V003_PINCTRL_RM_BASE_SHIFT 6
/* Function remapping ID 0-3 */
#define CH32V003_PINCTRL_RM_SHIFT 11
#define CH32V003_PINMUX_DEFINE(port, pin, rm, remapping) \
((CH32V003_PINMUX_PORT_##port << CH32V003_PINCTRL_PORT_SHIFT) | \
(pin << CH32V003_PINCTRL_PIN_SHIFT) | \
(CH32V003_PINMUX_##rm##_RM << CH32V003_PINCTRL_RM_BASE_SHIFT) | \
(remapping << CH32V003_PINCTRL_RM_SHIFT))
#define TIM1_ETR_PC5_0 CH32V003_PINMUX_DEFINE(PC, 5, TIM1, 0)
#define TIM1_ETR_PC5_1 CH32V003_PINMUX_DEFINE(PC, 5, TIM1, 1)
#define TIM1_ETR_PD4_2 CH32V003_PINMUX_DEFINE(PD, 4, TIM1, 2)
#define TIM1_ETR_PC2_3 CH32V003_PINMUX_DEFINE(PC, 2, TIM1, 3)
#define TIM1_CH1_PD2_0 CH32V003_PINMUX_DEFINE(PD, 2, TIM1, 0)
#define TIM1_CH1_PC6_1 CH32V003_PINMUX_DEFINE(PC, 6, TIM1, 1)
#define TIM1_CH1_PD2_2 CH32V003_PINMUX_DEFINE(PD, 2, TIM1, 2)
#define TIM1_CH1_PC4_3 CH32V003_PINMUX_DEFINE(PC, 4, TIM1, 3)
#define TIM1_CH2_PA1_0 CH32V003_PINMUX_DEFINE(PA, 1, TIM1, 0)
#define TIM1_CH2_PC7_1 CH32V003_PINMUX_DEFINE(PC, 7, TIM1, 1)
#define TIM1_CH2_PA1_2 CH32V003_PINMUX_DEFINE(PA, 1, TIM1, 2)
#define TIM1_CH2_PC7_3 CH32V003_PINMUX_DEFINE(PC, 7, TIM1, 3)
#define TIM1_CH3_PC3_0 CH32V003_PINMUX_DEFINE(PC, 3, TIM1, 0)
#define TIM1_CH3_PC0_1 CH32V003_PINMUX_DEFINE(PC, 0, TIM1, 1)
#define TIM1_CH3_PC3_2 CH32V003_PINMUX_DEFINE(PC, 3, TIM1, 2)
#define TIM1_CH3_PC5_3 CH32V003_PINMUX_DEFINE(PC, 5, TIM1, 3)
#define TIM1_CH4_PC4_0 CH32V003_PINMUX_DEFINE(PC, 4, TIM1, 0)
#define TIM1_CH4_PD3_1 CH32V003_PINMUX_DEFINE(PD, 3, TIM1, 1)
#define TIM1_CH4_PC4_2 CH32V003_PINMUX_DEFINE(PC, 4, TIM1, 2)
#define TIM1_CH4_PD4_3 CH32V003_PINMUX_DEFINE(PD, 4, TIM1, 3)
#define TIM1_BKIN_PC2_0 CH32V003_PINMUX_DEFINE(PC, 2, TIM1, 0)
#define TIM1_BKIN_PC1_1 CH32V003_PINMUX_DEFINE(PC, 1, TIM1, 1)
#define TIM1_BKIN_PC2_2 CH32V003_PINMUX_DEFINE(PC, 2, TIM1, 2)
#define TIM1_BKIN_PC1_3 CH32V003_PINMUX_DEFINE(PC, 1, TIM1, 3)
#define TIM1_CH1N_PD0_0 CH32V003_PINMUX_DEFINE(PD, 0, TIM1, 0)
#define TIM1_CH1N_PC3_1 CH32V003_PINMUX_DEFINE(PC, 3, TIM1, 1)
#define TIM1_CH1N_PD0_2 CH32V003_PINMUX_DEFINE(PD, 0, TIM1, 2)
#define TIM1_CH1N_PC3_3 CH32V003_PINMUX_DEFINE(PC, 3, TIM1, 3)
#define TIM1_CH2N_PA2_0 CH32V003_PINMUX_DEFINE(PA, 2, TIM1, 0)
#define TIM1_CH2N_PC4_1 CH32V003_PINMUX_DEFINE(PC, 4, TIM1, 1)
#define TIM1_CH2N_PA2_2 CH32V003_PINMUX_DEFINE(PA, 2, TIM1, 2)
#define TIM1_CH2N_PD2_3 CH32V003_PINMUX_DEFINE(PD, 2, TIM1, 3)
#define TIM1_CH3N_PD1_0 CH32V003_PINMUX_DEFINE(PD, 1, TIM1, 0)
#define TIM1_CH3N_PD1_1 CH32V003_PINMUX_DEFINE(PD, 1, TIM1, 1)
#define TIM1_CH3N_PD1_2 CH32V003_PINMUX_DEFINE(PD, 1, TIM1, 2)
#define TIM1_CH3N_PC6_3 CH32V003_PINMUX_DEFINE(PC, 6, TIM1, 3)
#define TIM2_ETR_PD4_0 CH32V003_PINMUX_DEFINE(PD, 4, TIM2, 0)
#define TIM2_ETR_PC5_1 CH32V003_PINMUX_DEFINE(PC, 5, TIM2, 1)
#define TIM2_ETR_PC1_2 CH32V003_PINMUX_DEFINE(PC, 1, TIM2, 2)
#define TIM2_ETR_PC1_3 CH32V003_PINMUX_DEFINE(PC, 1, TIM2, 3)
#define TIM2_CH1_PD4_0 CH32V003_PINMUX_DEFINE(PD, 4, TIM2, 0)
#define TIM2_CH1_PC5_1 CH32V003_PINMUX_DEFINE(PC, 5, TIM2, 1)
#define TIM2_CH1_PC1_2 CH32V003_PINMUX_DEFINE(PC, 1, TIM2, 2)
#define TIM2_CH1_PC1_3 CH32V003_PINMUX_DEFINE(PC, 1, TIM2, 3)
#define TIM2_CH2_PD3_0 CH32V003_PINMUX_DEFINE(PD, 3, TIM2, 0)
#define TIM2_CH2_PC2_1 CH32V003_PINMUX_DEFINE(PC, 2, TIM2, 1)
#define TIM2_CH2_PD3_2 CH32V003_PINMUX_DEFINE(PD, 3, TIM2, 2)
#define TIM2_CH2_PC7_3 CH32V003_PINMUX_DEFINE(PC, 7, TIM2, 3)
#define TIM2_CH3_PC0_0 CH32V003_PINMUX_DEFINE(PC, 0, TIM2, 0)
#define TIM2_CH3_PD2_1 CH32V003_PINMUX_DEFINE(PD, 2, TIM2, 1)
#define TIM2_CH3_PC0_2 CH32V003_PINMUX_DEFINE(PC, 0, TIM2, 2)
#define TIM2_CH3_PD6_3 CH32V003_PINMUX_DEFINE(PD, 6, TIM2, 3)
#define TIM2_CH4_PD7_0 CH32V003_PINMUX_DEFINE(PD, 7, TIM2, 0)
#define TIM2_CH4_PC1_1 CH32V003_PINMUX_DEFINE(PC, 1, TIM2, 1)
#define TIM2_CH4_PD7_2 CH32V003_PINMUX_DEFINE(PD, 7, TIM2, 2)
#define TIM2_CH4_PD5_3 CH32V003_PINMUX_DEFINE(PD, 5, TIM2, 3)
#define USART1_CK_PD4_0 CH32V003_PINMUX_DEFINE(PD, 4, USART1, 0)
#define USART1_CK_PD7_1 CH32V003_PINMUX_DEFINE(PD, 7, USART1, 1)
#define USART1_CK_PD7_2 CH32V003_PINMUX_DEFINE(PD, 7, USART1, 2)
#define USART1_CK_PC5_3 CH32V003_PINMUX_DEFINE(PC, 5, USART1, 3)
#define USART1_TX_PD5_0 CH32V003_PINMUX_DEFINE(PD, 5, USART1, 0)
#define USART1_TX_PD0_1 CH32V003_PINMUX_DEFINE(PD, 0, USART1, 1)
#define USART1_TX_PD6_2 CH32V003_PINMUX_DEFINE(PD, 6, USART1, 2)
#define USART1_TX_PC0_3 CH32V003_PINMUX_DEFINE(PC, 0, USART1, 3)
#define USART1_RX_PD6_0 CH32V003_PINMUX_DEFINE(PD, 6, USART1, 0)
#define USART1_RX_PD1_1 CH32V003_PINMUX_DEFINE(PD, 1, USART1, 1)
#define USART1_RX_PD5_2 CH32V003_PINMUX_DEFINE(PD, 5, USART1, 2)
#define USART1_RX_PC1_3 CH32V003_PINMUX_DEFINE(PC, 1, USART1, 3)
#define USART1_CTS_PD3_0 CH32V003_PINMUX_DEFINE(PD, 3, USART1, 0)
#define USART1_CTS_PC3_1 CH32V003_PINMUX_DEFINE(PC, 3, USART1, 1)
#define USART1_CTS_PC6_2 CH32V003_PINMUX_DEFINE(PC, 6, USART1, 2)
#define USART1_CTS_PC6_3 CH32V003_PINMUX_DEFINE(PC, 6, USART1, 3)
#define USART1_RTS_PC2_0 CH32V003_PINMUX_DEFINE(PC, 2, USART1, 0)
#define USART1_RTS_PC2_1 CH32V003_PINMUX_DEFINE(PC, 2, USART1, 1)
#define USART1_RTS_PC7_2 CH32V003_PINMUX_DEFINE(PC, 7, USART1, 2)
#define USART1_RTS_PC7_3 CH32V003_PINMUX_DEFINE(PC, 7, USART1, 3)
#define SPI1_NSS_PC1_0 CH32V003_PINMUX_DEFINE(PC, 1, SPI1, 0)
#define SPI1_NSS_PC0_1 CH32V003_PINMUX_DEFINE(PC, 0, SPI1, 1)
#define SPI1_SCK_PC5_0 CH32V003_PINMUX_DEFINE(PC, 5, SPI1, 0)
#define SPI1_SCK_PC5_1 CH32V003_PINMUX_DEFINE(PC, 5, SPI1, 1)
#define SPI1_MISO_PC7_0 CH32V003_PINMUX_DEFINE(PC, 7, SPI1, 0)
#define SPI1_MISO_PC7_1 CH32V003_PINMUX_DEFINE(PC, 7, SPI1, 1)
#define SPI1_MOSI_PC6_0 CH32V003_PINMUX_DEFINE(PC, 6, SPI1, 0)
#define SPI1_MOSI_PC6_1 CH32V003_PINMUX_DEFINE(PC, 6, SPI1, 1)
#define I2C1_SCL_PC2_0 CH32V003_PINMUX_DEFINE(PC, 2, I2C1, 0)
#define I2C1_SCL_PD1_1 CH32V003_PINMUX_DEFINE(PD, 1, I2C1, 1)
#define I2C1_SCL_PC5_2 CH32V003_PINMUX_DEFINE(PC, 5, I2C1, 2)
#define I2C1_SDA_PC1_0 CH32V003_PINMUX_DEFINE(PC, 1, I2C1, 0)
#define I2C1_SDA_PD0_1 CH32V003_PINMUX_DEFINE(PD, 0, I2C1, 1)
#define I2C1_SDA_PC6_2 CH32V003_PINMUX_DEFINE(PC, 6, I2C1, 2)
#endif /* __CH32V003_PINCTRL_H__ */

View file

@ -0,0 +1,3 @@
if(CONFIG_SOC_SERIES_CH32V00X)
zephyr_include_directories(${ZEPHYR_HAL_WCH_MODULE_DIR}/ch32v003fun .)
endif()

7
modules/hal_wch/Kconfig Normal file
View file

@ -0,0 +1,7 @@
#
# Copyright (c) 2024 Dhiru Kholia
#
# SPDX-License-Identifier: Apache-2.0
#
# file is empty and kept as a place holder if/when Kconfig is needed

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_ADC_H
#define _CH32_ADC_H
#ifdef CONFIG_SOC_CH32V003
#include <ch32v003fun.h>
#else
#error "SoC not supported!"
#endif
#endif

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 Dhiru Kholia
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_GPIO_H
#define _CH32_GPIO_H
#ifdef CONFIG_SOC_CH32V003
#include <ch32v003fun.h>
#else
#error "SoC not supported!"
#endif
#endif

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 Dhiru Kholia
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_PFIC_H
#define _CH32_PFIC_H
#ifdef CONFIG_SOC_CH32V003
#include <ch32v003fun.h>
#else
#error "SoC not supported!"
#endif
#endif

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 Dhiru Kholia
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_PINCTRL_H
#define _CH32_PINCTRL_H
#ifdef CONFIG_SOC_CH32V003
#include <ch32v003fun.h>
#else
#error "SoC not supported!"
#endif
#endif

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 Dhiru Kholia
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_RCC_H
#define _CH32_RCC_H
#ifdef CONFIG_SOC_CH32V003
#include <ch32v003fun.h>
#else
#error "SoC not supported!"
#endif
#endif

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 Dhiru Kholia
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_SOC_H
#define _CH32_SOC_H
#ifdef CONFIG_SOC_CH32V003
#include <ch32v003fun.h>
#else
#error "SoC not supported!"
#endif
#endif

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 Dhiru Kholia
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_SYSTICK_H
#define _CH32_SYSTICK_H
#ifdef CONFIG_SOC_CH32V003
#include <ch32v003fun.h>
#else
#error "SoC not supported!"
#endif
#endif

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 Dhiru Kholia
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_UART_H
#define _CH32_UART_H
#ifdef CONFIG_SOC_CH32V003
#include <ch32v003fun.h>
#else
#error "SoC not supported!"
#endif
#endif

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2024 Dhiru Kholia
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _FUNCONFIG_H
#define _FUNCONFIG_H
#ifdef CONFIG_SOC_CH32V003
#define CH32V003 1
#endif
#endif

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2024 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/adc/adc.h>
/ {
zephyr,user {
/* Vcal (~1.20 V) and 1/2 Vref (~1.65 V). */
io-channels = <&adc1 8 &adc1 9>;
};
};
&adc1 {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
vcal@8 {
reg = <8>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,resolution = <10>;
};
vref_div_2@9 {
reg = <9>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,resolution = <10>;
};
};

View file

@ -10,6 +10,7 @@ tests:
- disco_l475_iot1
- cc3220sf_launchxl
- cc3235sf_launchxl
- ch32v003evt
- cy8cproto_063_ble
- stm32l496g_disco
- stm32h735g_disco

View file

@ -40,6 +40,7 @@ _names = [
'jlink',
'linkserver',
'mdb',
'minichlink',
'misc',
'native',
'nios2',

View file

@ -0,0 +1,95 @@
# Copyright (c) 2024 Google LLC.
#
# SPDX-License-Identifier: Apache-2.0
"""WCH CH32V00x specific runner."""
import argparse
from runners.core import ZephyrBinaryRunner, RunnerCaps, RunnerConfig
class MiniChLinkBinaryRunner(ZephyrBinaryRunner):
"""Runner for CH32V00x based devices using minichlink."""
def __init__(
self,
cfg: RunnerConfig,
minichlink: str,
erase: bool,
reset: bool,
dt_flash: bool,
terminal: bool,
):
super().__init__(cfg)
self.minichlink = minichlink
self.erase = erase
self.reset = reset
self.dt_flash = dt_flash
self.terminal = terminal
@classmethod
def name(cls):
return "minichlink"
@classmethod
def capabilities(cls) -> RunnerCaps:
return RunnerCaps(commands={"flash"}, flash_addr=True, erase=True, reset=True)
@classmethod
def do_add_parser(cls, parser: argparse.ArgumentParser):
parser.add_argument(
"--minichlink", default="minichlink", help="path to the minichlink binary"
)
parser.add_argument(
"--terminal",
default=False,
action=argparse.BooleanOptionalAction,
help="open the terminal after flashing. Implies --reset.",
)
parser.set_defaults(reset=True)
@classmethod
def do_create(cls, cfg: RunnerConfig, args: argparse.Namespace):
return MiniChLinkBinaryRunner(
cfg,
minichlink=args.minichlink,
erase=args.erase,
reset=args.reset,
dt_flash=(args.dt_flash == "y"),
terminal=args.terminal,
)
def do_run(self, command: str, **kwargs):
self.require(self.minichlink)
if command == "flash":
self.flash()
else:
raise ValueError("BUG: unhandled command f{command}")
def flash(self):
self.ensure_output("bin")
cmd = [self.minichlink, "-a"]
if self.erase:
cmd.append("-E")
flash_addr = 0
if self.dt_flash:
flash_addr = self.flash_address_from_build_conf(self.build_conf)
cmd.extend(["-w", self.cfg.bin_file or "", f"0x{flash_addr:x}"])
if self.reset or self.terminal:
cmd.append("-b")
if self.terminal:
cmd.append("-T")
if self.terminal:
self.check_call(cmd)
else:
self.check_output(cmd)

View file

@ -31,6 +31,7 @@ def test_runner_imports():
'linkserver',
'mdb-hw',
'mdb-nsim',
'minichlink',
'misc-flasher',
'native',
'nios2',

View file

@ -0,0 +1,9 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
zephyr_sources(
soc_irq.S
vector.S
)
set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "")

13
soc/wch/ch32v00x/Kconfig Normal file
View file

@ -0,0 +1,13 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
config SOC_CH32V003
select RISCV
select BUILD_OUTPUT_HEX
select RISCV_ISA_RV32E
select RISCV_ISA_EXT_ZICSR
select RISCV_ISA_EXT_ZIFENCEI
select RISCV_ISA_EXT_C
select CH32V00X_SYSTICK
select ATOMIC_OPERATIONS_C
imply XIP

View file

@ -0,0 +1,24 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
if SOC_CH32V003
config NUM_IRQS
default 48
config SYS_CLOCK_HW_CYCLES_PER_SEC
default 48000000
config MAIN_STACK_SIZE
default 512
config IDLE_STACK_SIZE
default 256
config ISR_STACK_SIZE
default 256
config CLOCK_CONTROL
default y
endif # SOC_CH32V003

View file

@ -0,0 +1,15 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
config SOC_SERIES_CH32V00X
bool
config SOC_CH32V003
bool
select SOC_SERIES_CH32V00X
config SOC_SERIES
default "ch32v00x" if SOC_SERIES_CH32V00X
config SOC
default "ch32v003" if SOC_CH32V003

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __PINCTRL_SOC_H__
#define __PINCTRL_SOC_H__
/**
* @brief Type to hold a pin's pinctrl configuration.
*/
struct ch32v003_pinctrl_soc_pin {
uint32_t config: 22;
bool bias_pull_up: 1;
bool bias_pull_down: 1;
bool drive_open_drain: 1;
bool drive_push_pull: 1;
bool output_high: 1;
bool output_low: 1;
uint8_t slew_rate: 2;
};
typedef struct ch32v003_pinctrl_soc_pin pinctrl_soc_pin_t;
#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \
{ \
.config = DT_PROP_BY_IDX(node_id, prop, idx), \
.bias_pull_up = DT_PROP(node_id, bias_pull_up), \
.bias_pull_down = DT_PROP(node_id, bias_pull_down), \
.drive_open_drain = DT_PROP(node_id, drive_open_drain), \
.drive_push_pull = DT_PROP(node_id, drive_push_pull), \
.output_high = DT_PROP(node_id, output_high), \
.output_low = DT_PROP(node_id, output_low), \
.slew_rate = DT_ENUM_IDX(node_id, slew_rate), \
},
#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \
{DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pinmux, \
Z_PINCTRL_STATE_PIN_INIT)}
#endif

14
soc/wch/ch32v00x/soc.h Normal file
View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SOC_H__
#define __SOC_H__
#ifndef _ASMLANGUAGE
#include <zephyr/types.h>
#endif /* !_ASMLANGUAGE */
#endif /* __SOC_H__ */

7
soc/wch/ch32v00x/soc.yml Normal file
View file

@ -0,0 +1,7 @@
# Copyright (c) 2024 Michael Hope
# SPDX-License-Identifier: Apache-2.0
series:
- name: ch32v00x
socs:
- name: ch32v003

View file

@ -0,0 +1,19 @@
/* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <offsets.h>
#include <zephyr/toolchain.h>
/* Exports */
GTEXT(__soc_is_irq)
GTEXT(__soc_handle_irq)
SECTION_FUNC(exception.other, __soc_is_irq)
csrr a0, mcause
srli a0, a0, 31
ret
SECTION_FUNC(exception.other, __soc_handle_irq)
ret

25
soc/wch/ch32v00x/vector.S Normal file
View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2024 Michael Hope
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/toolchain.h>
/* Exports */
GTEXT(__start)
/* Imports */
GTEXT(__initialize)
SECTION_FUNC(vectors, ivt)
.option norvc
j __start
.rept 38
.word _isr_wrapper
.endr
SECTION_FUNC(vectors, __start)
li a0, 3
csrw mtvec, a0
j __initialize

View file

@ -247,6 +247,11 @@ manifest:
path: modules/hal/ti
groups:
- hal
- name: hal_wch
revision: 1de9d3e406726702ce7cfc504509a02ecc463554
path: modules/hal/wch
groups:
- hal
- name: hal_wurthelektronik
revision: e3e2797b224fc48fdef1bc3e5a12a7c73108bba2
path: modules/hal/wurthelektronik