Compare commits

...

13 commits

Author SHA1 Message Date
a8dd8e3eae samples: watchdog: add the ch32v003evt to the sample 2024-11-03 20:59:36 +01:00
1863af82c8 drivers: watchdog: add a CH32V00x Independent Watchdog (IWDT) driver 2024-11-03 20:53:35 +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
80 changed files with 2002 additions and 0 deletions

View file

@ -4871,6 +4871,14 @@ West:
labels: labels:
- "platform: TI" - "platform: TI"
"West project: hal_wch":
status: maintained
maintainers:
- nzmichaelh
- kholia
files:
- modules/hal_wch/
"West project: hal_wurthelektronik": "West project: hal_wurthelektronik":
status: maintained status: maintained
maintainers: 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

@ -98,3 +98,4 @@ endif()
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) 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_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_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.silabs"
source "drivers/clock_control/Kconfig.wch_rcc"
endif # CLOCK_CONTROL 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_TELINK_B91 gpio_b91.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_TEST gpio_test.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_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 gpio_mchp_xec.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_XEC_V2 gpio_mchp_xec_v2.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) 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.tca6424a"
source "drivers/gpio/Kconfig.test" source "drivers/gpio/Kconfig.test"
source "drivers/gpio/Kconfig.tle9104" source "drivers/gpio/Kconfig.tle9104"
source "drivers/gpio/Kconfig.wch_ch32v00x"
source "drivers/gpio/Kconfig.xec" source "drivers/gpio/Kconfig.xec"
source "drivers/gpio/Kconfig.xlnx" source "drivers/gpio/Kconfig.xlnx"
source "drivers/gpio/Kconfig.xlnx_ps" 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_RENESAS_RA_ICU intc_renesas_ra_icu.c)
zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.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_INTC_MTK_ADSP intc_mtk_adsp.c)
zephyr_library_sources_ifdef(CONFIG_WCH_PFIC intc_wch_pfic.c)
if(CONFIG_INTEL_VTD_ICTL) if(CONFIG_INTEL_VTD_ICTL)
zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) 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.mtk_adsp"
source "drivers/interrupt_controller/Kconfig.wch_pfic"
endmenu 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_MAX32 pinctrl_max32.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCMI pinctrl_imx_scmi.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_MCHP_MEC5 pinctrl_mchp_mec5.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_AFIO pinctrl_wch_afio.c)
add_subdirectory(renesas) add_subdirectory(renesas)

View file

@ -67,6 +67,7 @@ source "drivers/pinctrl/Kconfig.ene"
source "drivers/pinctrl/Kconfig.zynqmp" source "drivers/pinctrl/Kconfig.zynqmp"
source "drivers/pinctrl/Kconfig.max32" source "drivers/pinctrl/Kconfig.max32"
source "drivers/pinctrl/Kconfig.mec5" source "drivers/pinctrl/Kconfig.mec5"
source "drivers/pinctrl/Kconfig.wch_afio"
rsource "renesas/Kconfig" 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_STM32 uart_stm32.c)
zephyr_library_sources_ifdef(CONFIG_UART_SY1XX uart_sy1xx.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_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_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 uart_hvc_xen.c)
zephyr_library_sources_ifdef(CONFIG_UART_XEN_HVC_CONSOLEIO uart_hvc_xen_consoleio.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.si32"
source "drivers/serial/Kconfig.wch_usart"
endif # SERIAL 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_ARM_ARCH_TIMER arm_arch_timer.c)
zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_TIMER intel_adsp_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_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_CORTEX_M_SYSTICK cortex_m_systick.c)
zephyr_library_sources_ifdef(CONFIG_ESP32_SYS_TIMER esp32_sys_timer.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) 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.arm_arch"
source "drivers/timer/Kconfig.cavs" source "drivers/timer/Kconfig.cavs"
source "drivers/timer/Kconfig.cc13xx_cc26xx_rtc" source "drivers/timer/Kconfig.cc13xx_cc26xx_rtc"
source "drivers/timer/Kconfig.wch_ch32v00x"
source "drivers/timer/Kconfig.cortex_m_systick" source "drivers/timer/Kconfig.cortex_m_systick"
source "drivers/timer/Kconfig.esp32" source "drivers/timer/Kconfig.esp32"
source "drivers/timer/Kconfig.gecko" 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

@ -45,6 +45,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_AMBIQ wdt_ambiq.c)
zephyr_library_sources_ifdef(CONFIG_WDT_XMC4XXX wdt_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_WDT_XMC4XXX wdt_xmc4xxx.c)
zephyr_library_sources_ifdef(CONFIG_WWDT_NUMAKER wdt_wwdt_numaker.c) zephyr_library_sources_ifdef(CONFIG_WWDT_NUMAKER wdt_wwdt_numaker.c)
zephyr_library_sources_ifdef(CONFIG_WDT_ENE_KB1200 wdt_ene_kb1200.c) zephyr_library_sources_ifdef(CONFIG_WDT_ENE_KB1200 wdt_ene_kb1200.c)
zephyr_library_sources_ifdef(CONFIG_WDT_IWDG_CH32V00X wdt_iwdg_ch32v00x.c)
zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c) zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c)
zephyr_library_sources_ifdef(CONFIG_WDT_INTEL_ADSP wdt_intel_adsp.c wdt_dw_common.c) zephyr_library_sources_ifdef(CONFIG_WDT_INTEL_ADSP wdt_intel_adsp.c wdt_dw_common.c)

View file

@ -134,4 +134,6 @@ source "drivers/watchdog/Kconfig.ene"
source "drivers/watchdog/Kconfig.litex" source "drivers/watchdog/Kconfig.litex"
source "drivers/watchdog/Kconfig.ch32v00x"
endif # WATCHDOG endif # WATCHDOG

View file

@ -0,0 +1,9 @@
# Copyright (c) 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
config WDT_IWDG_CH32V00X
bool "CH32V00x Independent Watchdog (IWDG) driver"
default y
depends on DT_HAS_WCH_IWDG_ENABLED
help
Enable the Independent Watchdog (IWDG) driver for CH32V00x SOCs.

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2024 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT wch_iwdg
#include <zephyr/drivers/watchdog.h>
#include <zephyr/kernel.h>
#include <zephyr/sys_clock.h>
#include <errno.h>
#include <ch32_iwdg.h>
static int iwdg_ch32v00x_setup(const struct device *dev, uint8_t options)
{
if (options != 0) {
return -ENOTSUP;
}
IWDG->CTLR = CTLR_KEY_Enable;
return 0;
}
static int iwdg_ch32v00x_disable(const struct device *dev)
{
return -EPERM;
}
static int iwdg_ch32v00x_install_timeout(const struct device *dev,
const struct wdt_timeout_cfg *config)
{
/* The IWDT is driven by the 128 kHz LSI oscillator with at least a /4 prescaler. */
int prescaler = 0;
uint32_t reload = config->window.max * (128 / 4);
if (config->callback != NULL) {
return -ENOTSUP;
}
if (config->window.min != 0) {
return -ENOTSUP;
}
if ((config->flags & WDT_FLAG_RESET_MASK) != WDT_FLAG_RESET_CPU_CORE) {
return -ENOTSUP;
}
for (; reload > IWDG_RL && prescaler < IWDG_PR;) {
prescaler++;
reload /= 2;
}
/* The highest prescaler is effectively invalid. Use that to detect a too long timeout. */
if (prescaler == IWDG_PR) {
return -EINVAL;
}
/* Wait for the watchdog to be idle, unlock it, update, and wait for idle. */
while ((IWDG->STATR & (IWDG_RVU | IWDG_PVU)) != 0) {
}
IWDG->CTLR = IWDG_WriteAccess_Enable;
IWDG->PSCR = prescaler;
IWDG->RLDR = reload;
while ((IWDG->STATR & (IWDG_RVU | IWDG_PVU)) != 0) {
}
return 0;
}
static int iwdg_ch32v00x_feed(const struct device *dev, int channel_id)
{
IWDG->CTLR = CTLR_KEY_Reload;
return 0;
}
static const struct wdt_driver_api iwdg_ch32v00x_api = {
.setup = iwdg_ch32v00x_setup,
.disable = iwdg_ch32v00x_disable,
.install_timeout = iwdg_ch32v00x_install_timeout,
.feed = iwdg_ch32v00x_feed,
};
static int iwdg_ch32v00x_init(const struct device *dev)
{
return 0;
}
DEVICE_DT_INST_DEFINE(0, iwdg_ch32v00x_init, NULL, NULL, NULL, PRE_KERNEL_1,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &iwdg_ch32v00x_api);

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 vxt VXT Ltd
wand Wandbord (Technexion) wand Wandbord (Technexion)
waveshare Waveshare Electronics waveshare Waveshare Electronics
wch WinChipHead
wd Western Digital Corp. wd Western Digital Corp.
we Würth Elektronik GmbH. we Würth Elektronik GmbH.
weact WeAct Studio weact WeAct Studio

View file

@ -0,0 +1,12 @@
# Copyright (c) 2024 Google LLC.
# SPDX-License-Identifier: Apache-2.0
description: CH32V00x Independent Watchdog (IWDG)
compatible: "wch,iwdg"
include: base.yaml
properties:
reg:
required: true

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

@ -0,0 +1,157 @@
/*
* 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>;
};
iwdg: watchdog@40003000 {
compatible = "wch,iwdg";
reg = <0x40003000 16>;
};
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>;
};
};
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 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 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _CH32_IWDG_H
#define _CH32_IWDG_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,15 @@
/*
* Copyright (c) 2024 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
aliases {
watchdog0 = &iwdg;
};
};
&iwdg {
status = "okay";
};

View file

@ -40,6 +40,7 @@ _names = [
'jlink', 'jlink',
'linkserver', 'linkserver',
'mdb', 'mdb',
'minichlink',
'misc', 'misc',
'native', 'native',
'nios2', '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', 'linkserver',
'mdb-hw', 'mdb-hw',
'mdb-nsim', 'mdb-nsim',
'minichlink',
'misc-flasher', 'misc-flasher',
'native', 'native',
'nios2', '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 path: modules/hal/ti
groups: groups:
- hal - hal
- name: hal_wch
revision: 1de9d3e406726702ce7cfc504509a02ecc463554
path: modules/hal/wch
groups:
- hal
- name: hal_wurthelektronik - name: hal_wurthelektronik
revision: e3e2797b224fc48fdef1bc3e5a12a7c73108bba2 revision: e3e2797b224fc48fdef1bc3e5a12a7c73108bba2
path: modules/hal/wurthelektronik path: modules/hal/wurthelektronik