drivers: clock_control: add support for Nuvoton numaker series CLK
Add Nuvoton numaker series clock controller support, including: 1. Do system clock initialization in z_arm_platform_init(). 2. Support peripheral clock control API equivalent to BSP CLK_EnableModuleClock()/CLK_SetModuleClock(). Signed-off-by: cyliang tw <cyliang@nuvoton.com>
This commit is contained in:
parent
5879810137
commit
4ad399d54d
|
@ -23,6 +23,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RV32M1_PCC clock_cont
|
|||
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_INFINEON_CAT1 clock_control_ifx_cat1.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SAM clock_control_sam_pmc.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SMARTBOND clock_control_smartbond.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NUMAKER_SCC clock_control_numaker_scc.c)
|
||||
|
||||
|
||||
if(CONFIG_CLOCK_CONTROL_STM32_CUBE)
|
||||
|
|
|
@ -72,4 +72,6 @@ source "drivers/clock_control/Kconfig.sam"
|
|||
|
||||
source "drivers/clock_control/Kconfig.smartbond"
|
||||
|
||||
source "drivers/clock_control/Kconfig.numaker"
|
||||
|
||||
endif # CLOCK_CONTROL
|
||||
|
|
11
drivers/clock_control/Kconfig.numaker
Normal file
11
drivers/clock_control/Kconfig.numaker
Normal file
|
@ -0,0 +1,11 @@
|
|||
# NuMaker clock controller driver configuration options
|
||||
|
||||
# Copyright (c) 2022 Nuvoton Technology Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config CLOCK_CONTROL_NUMAKER_SCC
|
||||
bool "NuMaker system clock controller driver"
|
||||
default y
|
||||
depends on DT_HAS_NUVOTON_NUMAKER_SCC_ENABLED
|
||||
help
|
||||
Enable support for NuMaker system clock controller driver
|
162
drivers/clock_control/clock_control_numaker_scc.c
Normal file
162
drivers/clock_control/clock_control_numaker_scc.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nuvoton_numaker_scc
|
||||
|
||||
#include <zephyr/drivers/clock_control.h>
|
||||
#include <zephyr/drivers/clock_control/clock_control_numaker.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <NuMicro.h>
|
||||
|
||||
LOG_MODULE_REGISTER(clock_control_numaker_scc, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
|
||||
|
||||
struct numaker_scc_config {
|
||||
uint32_t clk_base;
|
||||
int hxt;
|
||||
int lxt;
|
||||
int hirc48;
|
||||
uint32_t clk_pclkdiv;
|
||||
uint32_t core_clock;
|
||||
};
|
||||
|
||||
static inline int numaker_scc_on(const struct device *dev, clock_control_subsys_t subsys)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
struct numaker_scc_subsys *scc_subsys = (struct numaker_scc_subsys *)subsys;
|
||||
|
||||
if (scc_subsys->subsys_id == NUMAKER_SCC_SUBSYS_ID_PCC) {
|
||||
SYS_UnlockReg();
|
||||
CLK_EnableModuleClock(scc_subsys->pcc.clk_modidx);
|
||||
SYS_LockReg();
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int numaker_scc_off(const struct device *dev, clock_control_subsys_t subsys)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
struct numaker_scc_subsys *scc_subsys = (struct numaker_scc_subsys *)subsys;
|
||||
|
||||
if (scc_subsys->subsys_id == NUMAKER_SCC_SUBSYS_ID_PCC) {
|
||||
SYS_UnlockReg();
|
||||
CLK_DisableModuleClock(scc_subsys->pcc.clk_modidx);
|
||||
SYS_LockReg();
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int numaker_scc_get_rate(const struct device *dev, clock_control_subsys_t subsys,
|
||||
uint32_t *rate)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(subsys);
|
||||
ARG_UNUSED(rate);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static inline int numaker_scc_set_rate(const struct device *dev, clock_control_subsys_t subsys,
|
||||
clock_control_subsys_rate_t rate)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(subsys);
|
||||
ARG_UNUSED(rate);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static inline int numaker_scc_configure(const struct device *dev, clock_control_subsys_t subsys,
|
||||
void *data)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(data);
|
||||
|
||||
struct numaker_scc_subsys *scc_subsys = (struct numaker_scc_subsys *)subsys;
|
||||
|
||||
if (scc_subsys->subsys_id == NUMAKER_SCC_SUBSYS_ID_PCC) {
|
||||
SYS_UnlockReg();
|
||||
CLK_SetModuleClock(scc_subsys->pcc.clk_modidx, scc_subsys->pcc.clk_src,
|
||||
scc_subsys->pcc.clk_div);
|
||||
SYS_LockReg();
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* System clock controller driver registration */
|
||||
static struct clock_control_driver_api numaker_scc_api = {
|
||||
.on = numaker_scc_on,
|
||||
.off = numaker_scc_off,
|
||||
.get_rate = numaker_scc_get_rate,
|
||||
.set_rate = numaker_scc_set_rate,
|
||||
.configure = numaker_scc_configure,
|
||||
};
|
||||
|
||||
/* At most one compatible with status "okay" */
|
||||
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) <= 1,
|
||||
"Requires at most one compatible with status \"okay\"");
|
||||
|
||||
#define LOG_OSC_SW(osc, sw) \
|
||||
if (sw == NUMAKER_SCC_CLKSW_ENABLE) { \
|
||||
LOG_DBG("Enable " #osc); \
|
||||
} else if (sw == NUMAKER_SCC_CLKSW_DISABLE) { \
|
||||
LOG_DBG("Disable " #osc); \
|
||||
}
|
||||
|
||||
static int numaker_scc_init(const struct device *dev)
|
||||
{
|
||||
const struct numaker_scc_config *cfg = dev->config;
|
||||
|
||||
LOG_DBG("CLK base: 0x%08x", cfg->clk_base);
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), hxt)
|
||||
LOG_OSC_SW(HXT, cfg->hxt);
|
||||
#endif
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), lxt)
|
||||
LOG_OSC_SW(LXT, cfg->lxt);
|
||||
#endif
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), hirc48)
|
||||
LOG_OSC_SW(HIRC48, cfg->hirc48);
|
||||
#endif
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), clk_pclkdiv)
|
||||
LOG_DBG("CLK_PCLKDIV: 0x%08x", cfg->clk_pclkdiv);
|
||||
#endif
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), core_clock)
|
||||
LOG_DBG("Core clock: %d (Hz)", cfg->core_clock);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* z_arm_platform_init() will respect above configurations and
|
||||
* actually take charge of system clock control initialization.
|
||||
*/
|
||||
|
||||
SystemCoreClockUpdate();
|
||||
LOG_DBG("SystemCoreClock: %d (Hz)", SystemCoreClock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NUMICRO_SCC_INIT(inst) \
|
||||
static const struct numaker_scc_config numaker_scc_config_##inst = { \
|
||||
.clk_base = DT_INST_REG_ADDR(inst), \
|
||||
.hxt = DT_INST_ENUM_IDX_OR(inst, hxt, NUMAKER_SCC_CLKSW_UNTOUCHED), \
|
||||
.lxt = DT_INST_ENUM_IDX_OR(inst, lxt, NUMAKER_SCC_CLKSW_UNTOUCHED), \
|
||||
.hirc48 = DT_INST_ENUM_IDX_OR(inst, hirc48, NUMAKER_SCC_CLKSW_UNTOUCHED), \
|
||||
.clk_pclkdiv = DT_INST_PROP_OR(inst, clk_pclkdiv, 0), \
|
||||
.core_clock = DT_INST_PROP_OR(inst, core_clock, 0), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(inst, &numaker_scc_init, NULL, NULL, &numaker_scc_config_##inst, \
|
||||
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &numaker_scc_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(NUMICRO_SCC_INIT);
|
|
@ -7,6 +7,7 @@
|
|||
#include <arm/armv7-m.dtsi>
|
||||
#include <mem.h>
|
||||
#include <zephyr/dt-bindings/pinctrl/numaker-m46x-pinctrl.h>
|
||||
#include <zephyr/dt-bindings/clock/numaker_m46x_clock.h>
|
||||
|
||||
/ {
|
||||
cpus {
|
||||
|
@ -39,6 +40,22 @@
|
|||
};
|
||||
|
||||
soc {
|
||||
scc: system-clock-controller@40000200 {
|
||||
compatible = "nuvoton,numaker-scc";
|
||||
reg = <0x40000200 0x100>;
|
||||
#clock-cells = <0>;
|
||||
/* hxt = "enable"; */
|
||||
/* lxt = "enable"; */
|
||||
clk-pclkdiv = <(NUMAKER_CLK_PCLKDIV_APB0DIV_DIV2 |
|
||||
NUMAKER_CLK_PCLKDIV_APB1DIV_DIV2)>;
|
||||
core-clock = <200000000>;
|
||||
|
||||
pcc: peripheral-clock-controller {
|
||||
compatible = "nuvoton,numaker-pcc";
|
||||
#clock-cells = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
pinctrl: pin-controller@40000500 {
|
||||
compatible = "nuvoton,numaker-pinctrl";
|
||||
reg = <0x40000500 0xa0>;
|
||||
|
|
17
dts/bindings/clock/nuvoton,numaker-pcc.yaml
Normal file
17
dts/bindings/clock/nuvoton,numaker-pcc.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2023 Nuvoton Technology Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Nuvoton NuMaker Peripheral Clock Controller (PCC)
|
||||
|
||||
compatible: "nuvoton,numaker-pcc"
|
||||
|
||||
include: [clock-controller.yaml, base.yaml]
|
||||
|
||||
properties:
|
||||
"#clock-cells":
|
||||
const: 3
|
||||
|
||||
clock-cells:
|
||||
- clock-module-index # Same as u32ModuleIdx on invoking BSP CLK driver CLK_SetModuleClock()
|
||||
- clock-source # Same as u32ClkSrc on invoking BSP CLK driver CLK_SetModuleClock()
|
||||
- clock-divider # Same as u32ClkDiv on invoking BSP CLK driver CLK_SetModuleClock()
|
49
dts/bindings/clock/nuvoton,numaker-scc.yaml
Normal file
49
dts/bindings/clock/nuvoton,numaker-scc.yaml
Normal file
|
@ -0,0 +1,49 @@
|
|||
# Copyright (c) 2023 Nuvoton Technology Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Nuvoton NuMaker System Clock Controller (SCC)
|
||||
|
||||
compatible: "nuvoton,numaker-scc"
|
||||
|
||||
include: [clock-controller.yaml, base.yaml]
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
hxt:
|
||||
type: string
|
||||
description: |
|
||||
Enable/disable 4~24 MHz external crystal oscillator (HXT)
|
||||
enum:
|
||||
- "untouched"
|
||||
- "enable"
|
||||
- "disable"
|
||||
|
||||
lxt:
|
||||
type: string
|
||||
description: |
|
||||
Enable/disable 32.768 kHz low-speed external crystal oscillator (LXT)
|
||||
enum:
|
||||
- "untouched"
|
||||
- "enable"
|
||||
- "disable"
|
||||
|
||||
hirc48:
|
||||
type: string
|
||||
description: |
|
||||
Enable/disable 48 MHz high-speed internal RC oscillator (HIRC48)
|
||||
enum:
|
||||
- "untouched"
|
||||
- "enable"
|
||||
- "disable"
|
||||
|
||||
clk-pclkdiv:
|
||||
type: int
|
||||
description: |
|
||||
Configure APB Clock Divider register
|
||||
|
||||
core-clock:
|
||||
type: int
|
||||
description: |
|
||||
Configure core clock (HCLK)
|
41
include/zephyr/drivers/clock_control/clock_control_numaker.h
Normal file
41
include/zephyr/drivers/clock_control/clock_control_numaker.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NUMAKER_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NUMAKER_H_
|
||||
|
||||
/**
|
||||
* @brief Enable/disable oscillators or other clocks
|
||||
*/
|
||||
#define NUMAKER_SCC_CLKSW_UNTOUCHED 0
|
||||
#define NUMAKER_SCC_CLKSW_ENABLE 1
|
||||
#define NUMAKER_SCC_CLKSW_DISABLE 2
|
||||
|
||||
/**
|
||||
* @brief SCC subsystem ID
|
||||
*/
|
||||
#define NUMAKER_SCC_SUBSYS_ID_PCC 1
|
||||
|
||||
struct numaker_scc_subsys {
|
||||
uint32_t subsys_id; /* SCC sybsystem ID */
|
||||
|
||||
/* Peripheral clock control configuration structure
|
||||
* clk_modidx is same as u32ModuleIdx in BSP CLK_SetModuleClock().
|
||||
* clk_src is same as u32ClkSrc in BSP CLK_SetModuleClock().
|
||||
* clk_div is same as u32ClkDiv in BSP CLK_SetModuleClock().
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
uint32_t clk_modidx;
|
||||
uint32_t clk_src;
|
||||
uint32_t clk_div;
|
||||
} pcc;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NUMAKER_H_ */
|
1303
include/zephyr/dt-bindings/clock/numaker_m46x_clock.h
Normal file
1303
include/zephyr/dt-bindings/clock/numaker_m46x_clock.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/clock_control/clock_control_numaker.h>
|
||||
/* Hardware and starter kit includes. */
|
||||
#include <NuMicro.h>
|
||||
|
||||
|
@ -21,13 +22,27 @@ void z_arm_platform_init(void)
|
|||
* -------------------
|
||||
*/
|
||||
|
||||
CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk);
|
||||
/* Wait for HXT clock ready */
|
||||
CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk);
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), hxt)
|
||||
/* Enable/disable 4~24 MHz external crystal oscillator (HXT) */
|
||||
if (DT_ENUM_IDX(DT_NODELABEL(scc), hxt) == NUMAKER_SCC_CLKSW_ENABLE) {
|
||||
CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk);
|
||||
/* Wait for HXT clock ready */
|
||||
CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk);
|
||||
} else if (DT_ENUM_IDX(DT_NODELABEL(scc), hxt) == NUMAKER_SCC_CLKSW_DISABLE) {
|
||||
CLK_DisableXtalRC(CLK_PWRCTL_HXTEN_Msk);
|
||||
}
|
||||
#endif
|
||||
|
||||
CLK_EnableXtalRC(CLK_PWRCTL_LXTEN_Msk);
|
||||
/* Wait for LXT clock ready */
|
||||
CLK_WaitClockReady(CLK_STATUS_LXTSTB_Msk);
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), lxt)
|
||||
/* Enable/disable 32.768 kHz low-speed external crystal oscillator (LXT) */
|
||||
if (DT_ENUM_IDX(DT_NODELABEL(scc), lxt) == NUMAKER_SCC_CLKSW_ENABLE) {
|
||||
CLK_EnableXtalRC(CLK_PWRCTL_LXTEN_Msk);
|
||||
/* Wait for LXT clock ready */
|
||||
CLK_WaitClockReady(CLK_STATUS_LXTSTB_Msk);
|
||||
} else if (DT_ENUM_IDX(DT_NODELABEL(scc), lxt) == NUMAKER_SCC_CLKSW_DISABLE) {
|
||||
CLK_DisableXtalRC(CLK_PWRCTL_LXTEN_Msk);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable 12 MHz high-speed internal RC oscillator (HIRC) */
|
||||
CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
|
||||
|
@ -39,15 +54,26 @@ void z_arm_platform_init(void)
|
|||
/* Wait for LIRC clock ready */
|
||||
CLK_WaitClockReady(CLK_STATUS_LIRCSTB_Msk);
|
||||
|
||||
CLK_EnableXtalRC(CLK_PWRCTL_HIRC48EN_Msk);
|
||||
/* Wait for HIRC48 clock ready */
|
||||
CLK_WaitClockReady(CLK_STATUS_HIRC48STB_Msk);
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), hirc48)
|
||||
/* Enable/disable 48 MHz high-speed internal RC oscillator (HIRC48) */
|
||||
if (DT_ENUM_IDX(DT_NODELABEL(scc), hirc48) == NUMAKER_SCC_CLKSW_ENABLE) {
|
||||
CLK_EnableXtalRC(CLK_PWRCTL_HIRC48EN_Msk);
|
||||
/* Wait for HIRC48 clock ready */
|
||||
CLK_WaitClockReady(CLK_STATUS_HIRC48STB_Msk);
|
||||
} else if (DT_ENUM_IDX(DT_NODELABEL(scc), hirc48) == NUMAKER_SCC_CLKSW_DISABLE) {
|
||||
CLK_DisableXtalRC(CLK_PWRCTL_HIRC48EN_Msk);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set PCLK0 and PCLK1 to HCLK/2 */
|
||||
CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2);
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), clk_pclkdiv)
|
||||
/* Set CLK_PCLKDIV register on request */
|
||||
CLK->PCLKDIV = DT_PROP(DT_NODELABEL(scc), clk_pclkdiv);
|
||||
#endif
|
||||
|
||||
/* Set core clock to 200MHz */
|
||||
CLK_SetCoreClock(200000000);
|
||||
#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), core_clock)
|
||||
/* Set core clock (HCLK) on request */
|
||||
CLK_SetCoreClock(DT_PROP(DT_NODELABEL(scc), core_clock));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update System Core Clock
|
||||
|
|
Loading…
Reference in a new issue