Commit a2a89f1f authored by Camille BAUD's avatar Camille BAUD Committed by Benjamin Cabé
Browse files

drivers: clock_control: Introduce CH32V20x/30x clock control



This introduces support for CH32V20x/30x Clock schemes and
improves WCH Clock control driver

Signed-off-by: default avatarCamille BAUD <mail@massdriver.space>
parent d549af46
Loading
Loading
Loading
Loading
+30 −18
Original line number Diff line number Diff line
@@ -19,29 +19,23 @@
#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))
#if DT_NODE_HAS_COMPAT(DT_INST_CLOCKS_CTLR(0), wch_ch32v00x_pll_clock) ||                          \
	DT_NODE_HAS_COMPAT(DT_INST_CLOCKS_CTLR(0), wch_ch32v20x_30x_pll_clock)
#define WCH_RCC_SRC_IS_PLL 1
#if DT_NODE_HAS_COMPAT(DT_CLOCKS_CTLR(DT_INST_CLOCKS_CTLR(0)), wch_ch32v00x_hse_clock)
#define WCH_RCC_PLL_SRC_IS_HSE 1
#elif DT_NODE_HAS_COMPAT(DT_CLOCKS_CTLR(DT_INST_CLOCKS_CTLR(0)), wch_ch32v00x_hsi_clock)
#define WCH_RCC_PLL_SRC_IS_HSI 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))
#elif DT_NODE_HAS_COMPAT(DT_INST_CLOCKS_CTLR(0), wch_ch32v00x_hse_clock)
#define WCH_RCC_SRC_IS_HSE 1
#elif DT_NODE_HAS_COMPAT(DT_INST_CLOCKS_CTLR(0), wch_ch32v00x_hsi_clock)
#define WCH_RCC_SRC_IS_HSI 1
#endif

struct clock_control_wch_rcc_config {
	RCC_TypeDef *regs;
	uint8_t mul;
};

static int clock_control_wch_rcc_on(const struct device *dev, clock_control_subsys_t sys)
@@ -91,7 +85,10 @@ static DEVICE_API(clock_control, clock_control_wch_rcc_api) = {

static int clock_control_wch_rcc_init(const struct device *dev)
{
	if (IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V00X_PLL_CLOCK_ENABLED)) {
	const struct clock_control_wch_rcc_config *config = dev->config;

	if (IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V00X_PLL_CLOCK_ENABLED) ||
	    IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V20X_30X_PLL_CLOCK_ENABLED)) {
		/* Disable the PLL before potentially changing the input clocks. */
		RCC->CTLR &= ~RCC_PLLON;
	}
@@ -123,6 +120,17 @@ static int clock_control_wch_rcc_init(const struct device *dev)
		while ((RCC->CTLR & RCC_PLLRDY) == 0) {
		}
	}
	if (IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V20X_30X_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->CFGR0 |= (config->mul == 18 ? 0xF : (config->mul - 2)) << 0x12;
		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;
@@ -137,8 +145,10 @@ static int clock_control_wch_rcc_init(const struct device *dev)
	RCC->INTR = RCC_CSSC | RCC_PLLRDYC | RCC_HSERDYC | RCC_LSIRDYC;
	/* HCLK = SYSCLK = APB1 */
	RCC->CFGR0 = (RCC->CFGR0 & ~RCC_HPRE) | RCC_HPRE_DIV1;
#if defined(CONFIG_SOC_CH32V003)
	/* Set the Flash to 0 wait state */
	FLASH->ACTLR = (FLASH->ACTLR & ~FLASH_ACTLR_LATENCY) | FLASH_ACTLR_LATENCY_1;
#endif

	return 0;
}
@@ -146,9 +156,11 @@ static int clock_control_wch_rcc_init(const struct device *dev)
#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),                                      \
		.mul = DT_PROP_OR(DT_INST_CLOCKS_CTLR(idx), mul, 1),                               \
	};                                                                                         \
	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)
/* There is only ever one RCC */
CLOCK_CONTROL_WCH_RCC_INIT(0)
+39 −0
Original line number Diff line number Diff line
# Copyright (c) 2024 MASSDRIVER EI (massdriver.space)
# SPDX-License-Identifier: Apache-2.0

description: WCH CH32V20x/30x PLL

compatible: "wch,ch32v20x_30x-pll-clock"

include: [clock-controller.yaml, base.yaml]

properties:
  "#clock-cells":
    const: 0

  clocks:
    type: phandle-array
    required: true

  mul:
    type: int
    required: true
    description: |
        Main PLL multiplication factor
    enum:
      - 2   # x2
      - 3   # x3
      - 4   # x4
      - 5   # x5
      - 6   # x6
      - 7   # x7
      - 8   # x8
      - 9   # x2
      - 10  # x10
      - 11  # x11
      - 12  # x12
      - 13  # x13
      - 14  # x14
      - 15  # x15
      - 16  # x16
      - 18  # x18
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2024 MASSDRIVER EI (massdriver.space)
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef __CH32V20X_V30X_CLOCKS_H__
#define __CH32V20X_V30X_CLOCKS_H__

#define CH32V20X_V30X_AHB_PCENR_OFFSET  0
#define CH32V20X_V30X_APB2_PCENR_OFFSET 1
#define CH32V20X_V30X_APB1_PCENR_OFFSET 2

#define CH32V20X_V30X_CLOCK_CONFIG(bus, bit) (((CH32V20X_V30X_##bus##_PCENR_OFFSET) << 5) | (bit))

#define CH32V20X_V30X_CLOCK_DMA1     CH32V20X_V30X_CLOCK_CONFIG(AHB, 0)
#define CH32V20X_V30X_CLOCK_DMA2     CH32V20X_V30X_CLOCK_CONFIG(AHB, 1)
#define CH32V20X_V30X_CLOCK_SRAM     CH32V20X_V30X_CLOCK_CONFIG(AHB, 2)
#define CH32V20X_V30X_CLOCK_FLITF    CH32V20X_V30X_CLOCK_CONFIG(AHB, 4)
#define CH32V20X_V30X_CLOCK_CRC      CH32V20X_V30X_CLOCK_CONFIG(AHB, 6)
#define CH32V20X_V30X_CLOCK_FSMC     CH32V20X_V30X_CLOCK_CONFIG(AHB, 8)
#define CH32V20X_V30X_CLOCK_RNG      CH32V20X_V30X_CLOCK_CONFIG(AHB, 9)
#define CH32V20X_V30X_CLOCK_SDIO     CH32V20X_V30X_CLOCK_CONFIG(AHB, 10)
#define CH32V20X_V30X_CLOCK_USBHS    CH32V20X_V30X_CLOCK_CONFIG(AHB, 11)
#define CH32V20X_V30X_CLOCK_OTG_FS   CH32V20X_V30X_CLOCK_CONFIG(AHB, 12)
#define CH32V20X_V30X_CLOCK_DVP      CH32V20X_V30X_CLOCK_CONFIG(AHB, 13)
#define CH32V20X_V30X_CLOCK_ETHMAC   CH32V20X_V30X_CLOCK_CONFIG(AHB, 14)
#define CH32V20X_V30X_CLOCK_ETHMACTX CH32V20X_V30X_CLOCK_CONFIG(AHB, 15)
#define CH32V20X_V30X_CLOCK_ETHMACRX CH32V20X_V30X_CLOCK_CONFIG(AHB, 16)
#define CH32V20X_V30X_CLOCK_BLEC     CH32V20X_V30X_CLOCK_CONFIG(AHB, 16)
#define CH32V20X_V30X_CLOCK_BLES     CH32V20X_V30X_CLOCK_CONFIG(AHB, 17)

#define CH32V20X_V30X_CLOCK_AFIO   CH32V20X_V30X_CLOCK_CONFIG(APB2, 0)
#define CH32V20X_V30X_CLOCK_IOPA   CH32V20X_V30X_CLOCK_CONFIG(APB2, 2)
#define CH32V20X_V30X_CLOCK_IOPB   CH32V20X_V30X_CLOCK_CONFIG(APB2, 3)
#define CH32V20X_V30X_CLOCK_IOPC   CH32V20X_V30X_CLOCK_CONFIG(APB2, 4)
#define CH32V20X_V30X_CLOCK_IOPD   CH32V20X_V30X_CLOCK_CONFIG(APB2, 5)
#define CH32V20X_V30X_CLOCK_IOPE   CH32V20X_V30X_CLOCK_CONFIG(APB2, 6)
#define CH32V20X_V30X_CLOCK_ADC1   CH32V20X_V30X_CLOCK_CONFIG(APB2, 9)
#define CH32V20X_V30X_CLOCK_ADC2   CH32V20X_V30X_CLOCK_CONFIG(APB2, 10)
#define CH32V20X_V30X_CLOCK_TIM1   CH32V20X_V30X_CLOCK_CONFIG(APB2, 11)
#define CH32V20X_V30X_CLOCK_SPI1   CH32V20X_V30X_CLOCK_CONFIG(APB2, 12)
#define CH32V20X_V30X_CLOCK_TIM8   CH32V20X_V30X_CLOCK_CONFIG(APB2, 13)
#define CH32V20X_V30X_CLOCK_USART1 CH32V20X_V30X_CLOCK_CONFIG(APB2, 14)
#define CH32V20X_V30X_CLOCK_TIM9   CH32V20X_V30X_CLOCK_CONFIG(APB2, 19)
#define CH32V20X_V30X_CLOCK_TIM10  CH32V20X_V30X_CLOCK_CONFIG(APB2, 20)

#define CH32V20X_V30X_CLOCK_TIM2   CH32V20X_V30X_CLOCK_CONFIG(APB1, 0)
#define CH32V20X_V30X_CLOCK_TIM3   CH32V20X_V30X_CLOCK_CONFIG(APB1, 1)
#define CH32V20X_V30X_CLOCK_TIM4   CH32V20X_V30X_CLOCK_CONFIG(APB1, 2)
#define CH32V20X_V30X_CLOCK_TIM5   CH32V20X_V30X_CLOCK_CONFIG(APB1, 3)
#define CH32V20X_V30X_CLOCK_TIM6   CH32V20X_V30X_CLOCK_CONFIG(APB1, 4)
#define CH32V20X_V30X_CLOCK_TIM7   CH32V20X_V30X_CLOCK_CONFIG(APB1, 5)
#define CH32V20X_V30X_CLOCK_USART6 CH32V20X_V30X_CLOCK_CONFIG(APB1, 6)
#define CH32V20X_V30X_CLOCK_USART7 CH32V20X_V30X_CLOCK_CONFIG(APB1, 7)
#define CH32V20X_V30X_CLOCK_USART8 CH32V20X_V30X_CLOCK_CONFIG(APB1, 8)
#define CH32V20X_V30X_CLOCK_WWDG   CH32V20X_V30X_CLOCK_CONFIG(APB1, 11)
#define CH32V20X_V30X_CLOCK_SPI2   CH32V20X_V30X_CLOCK_CONFIG(APB1, 14)
#define CH32V20X_V30X_CLOCK_SPI3   CH32V20X_V30X_CLOCK_CONFIG(APB1, 15)
#define CH32V20X_V30X_CLOCK_USART2 CH32V20X_V30X_CLOCK_CONFIG(APB1, 17)
#define CH32V20X_V30X_CLOCK_USART3 CH32V20X_V30X_CLOCK_CONFIG(APB1, 18)
#define CH32V20X_V30X_CLOCK_USART4 CH32V20X_V30X_CLOCK_CONFIG(APB1, 19)
#define CH32V20X_V30X_CLOCK_USART5 CH32V20X_V30X_CLOCK_CONFIG(APB1, 20)
#define CH32V20X_V30X_CLOCK_I2C1   CH32V20X_V30X_CLOCK_CONFIG(APB1, 21)
#define CH32V20X_V30X_CLOCK_I2C2   CH32V20X_V30X_CLOCK_CONFIG(APB1, 22)
#define CH32V20X_V30X_CLOCK_USBD   CH32V20X_V30X_CLOCK_CONFIG(APB1, 23)
#define CH32V20X_V30X_CLOCK_CAN1   CH32V20X_V30X_CLOCK_CONFIG(APB1, 25)
#define CH32V20X_V30X_CLOCK_CAN2   CH32V20X_V30X_CLOCK_CONFIG(APB1, 26)
#define CH32V20X_V30X_CLOCK_BKP    CH32V20X_V30X_CLOCK_CONFIG(APB1, 27)
#define CH32V20X_V30X_CLOCK_PWR    CH32V20X_V30X_CLOCK_CONFIG(APB1, 28)
#define CH32V20X_V30X_CLOCK_DAC    CH32V20X_V30X_CLOCK_CONFIG(APB1, 29)

#endif