Browse Source

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>
pull/82071/head
Michael Hope 1 year ago committed by Fabio Baltieri
parent
commit
c1c0413eed
  1. 1
      drivers/clock_control/CMakeLists.txt
  2. 2
      drivers/clock_control/Kconfig
  3. 7
      drivers/clock_control/Kconfig.wch_rcc
  4. 154
      drivers/clock_control/clock_control_wch_rcc.c
  5. 8
      dts/bindings/clock/wch,ch32v00x-hse-clock.yaml
  6. 8
      dts/bindings/clock/wch,ch32v00x-hsi-clock.yaml
  7. 16
      dts/bindings/clock/wch,ch32v00x-pll-clock.yaml
  8. 15
      dts/bindings/clock/wch,rcc.yaml
  9. 29
      dts/riscv/wch/ch32v00x.dtsi
  10. 42
      include/zephyr/dt-bindings/clock/ch32v00x-clocks.h

1
drivers/clock_control/CMakeLists.txt

@ -98,3 +98,4 @@ endif() @@ -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)

2
drivers/clock_control/Kconfig

@ -100,4 +100,6 @@ source "drivers/clock_control/Kconfig.arm_scmi" @@ -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

7
drivers/clock_control/Kconfig.wch_rcc

@ -0,0 +1,7 @@ @@ -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

154
drivers/clock_control/clock_control_wch_rcc.c

@ -0,0 +1,154 @@ @@ -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 <ch32fun.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);
val |= 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 & (RCC_HPRE_0 | RCC_HPRE_1 | RCC_HPRE_2)) >> 4);
} else {
/* The range 0b0nnn divides by n + 1, where 0b0000 is /1, 0b001 is /2, etc. */
ahbclk /= ((cfgr0 & (RCC_HPRE_0 | RCC_HPRE_1 | RCC_HPRE_2)) >> 4) + 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)

8
dts/bindings/clock/wch,ch32v00x-hse-clock.yaml

@ -0,0 +1,8 @@ @@ -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]

8
dts/bindings/clock/wch,ch32v00x-hsi-clock.yaml

@ -0,0 +1,8 @@ @@ -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]

16
dts/bindings/clock/wch,ch32v00x-pll-clock.yaml

@ -0,0 +1,16 @@ @@ -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

15
dts/bindings/clock/wch,rcc.yaml

@ -0,0 +1,15 @@ @@ -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

29
dts/riscv/wch/ch32v00x.dtsi

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
* 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>
@ -25,6 +26,34 @@ @@ -25,6 +26,34 @@
};
};
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>;

42
include/zephyr/dt-bindings/clock/ch32v00x-clocks.h

@ -0,0 +1,42 @@ @@ -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
Loading…
Cancel
Save