From df56c85e94248a84daddc52ceddc2b14d015639b Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Thu, 21 Nov 2024 17:19:10 +0800 Subject: [PATCH] drivers/clock: Add clock drivers of it51xxx Add clock drivers for ITE it51xxx series. Signed-off-by: Tim Lin --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.it51xxx | 17 ++ drivers/clock_control/clock_control_it51xxx.c | 204 ++++++++++++++++++ dts/bindings/clock/ite,it51xxx-ecpm.yaml | 33 +++ dts/riscv/ite/it51xxx.dtsi | 8 + .../dt-bindings/clock/ite-it51xxx-clock.h | 21 ++ soc/ite/ec/common/soc_common.h | 5 + 8 files changed, 291 insertions(+) create mode 100644 drivers/clock_control/Kconfig.it51xxx create mode 100644 drivers/clock_control/clock_control_it51xxx.c create mode 100644 dts/bindings/clock/ite,it51xxx-ecpm.yaml create mode 100644 include/zephyr/dt-bindings/clock/ite-it51xxx-clock.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index fd481bde588..2e8cf830053 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -42,6 +42,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL clock_control_nrf2_global_hsfll.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RTS5912_SCCON clock_control_rts5912_sccon.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL clock_control_nrf2_audiopll.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_IT51XXX clock_control_it51xxx.c) if(CONFIG_CLOCK_CONTROL_NRF2) zephyr_library_sources(clock_control_nrf2_common.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index c4a0f83d6e1..229a45792e8 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -108,4 +108,6 @@ source "drivers/clock_control/Kconfig.siwx91x" source "drivers/clock_control/Kconfig.wch_rcc" +source "drivers/clock_control/Kconfig.it51xxx" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.it51xxx b/drivers/clock_control/Kconfig.it51xxx new file mode 100644 index 00000000000..2619f96f6c2 --- /dev/null +++ b/drivers/clock_control/Kconfig.it51xxx @@ -0,0 +1,17 @@ +# Copyright (c) 2025 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_IT51XXX + bool "ITE IT51XXX clock controller driver" + default y + depends on DT_HAS_ITE_IT51XXX_ECPM_ENABLED + help + This option enables the clock controller driver for IT51XXX. + +if CLOCK_CONTROL_IT51XXX + +config IT51XXX_PLL_SEQUENCE_PRIORITY + int + default 1 + +endif # CLOCK_CONTROL_IT51XXX diff --git a/drivers/clock_control/clock_control_it51xxx.c b/drivers/clock_control/clock_control_it51xxx.c new file mode 100644 index 00000000000..4cb5fdffef3 --- /dev/null +++ b/drivers/clock_control/clock_control_it51xxx.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2025 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ite_it51xxx_ecpm + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(clock_control_it51xxx, LOG_LEVEL_ERR); + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "only one ite,it51xxx-ecpm compatible node can be supported"); + +/* it51xxx ECPM registers definition */ +/* 0x02: Clock Gating Control 2 register */ +#define ECPM_CGCTRL2R 0x02 +#define ECPM_CIRCG BIT(5) +#define ECPM_SWUCCG BIT(4) +/* 0x03: PLL Control */ +#define ECPM_PLLCTRL 0x03 +/* 0x04: Auto Clock Gating */ +#define ECPM_AUTOCG 0x04 +#define ECPM_AUART1CG BIT(6) +#define ECPM_AUART2CG BIT(5) +#define ECPM_ASSPICG BIT(4) +#define ECPM_ACIRCG BIT(2) +/* 0x02: Clock Gating Control 5 register */ +#define ECPM_CGCTRL3R 0x05 +#define ECPM_PECICG BIT(3) +#define ECPM_SSPICG BIT(1) +/* 0x06: PLL Frequency */ +#define ECPM_PLLFREQR 0x06 +#define ECPM_PLLFREQ_MASK GENMASK(3, 0) + +static const uint8_t pll_cfg[] = { + [PLL_18400_KHZ] = 0x01, + [PLL_32300_KHZ] = 0x03, + [PLL_64500_KHZ] = 0x07, + [PLL_48000_KHZ] = 0x09, +}; + +struct clock_control_it51xxx_data { + const uint8_t *pll_configuration; +}; + +/* Driver config */ +struct clock_control_it51xxx_config { + mm_reg_t ecpm_base; + int pll_freq; +}; + +/* Clock controller local functions */ +static inline int clock_control_it51xxx_on(const struct device *dev, + clock_control_subsys_t sub_system) +{ + const struct clock_control_it51xxx_config *const config = dev->config; + struct ite_clk_cfg *clk_cfg = (struct ite_clk_cfg *)(sub_system); + + /* Enable the clock of this module */ + sys_write8(sys_read8(config->ecpm_base + clk_cfg->ctrl) & ~(clk_cfg->bits), + config->ecpm_base + clk_cfg->ctrl); + + return 0; +} + +static inline int clock_control_it51xxx_off(const struct device *dev, + clock_control_subsys_t sub_system) +{ + const struct clock_control_it51xxx_config *const config = dev->config; + struct ite_clk_cfg *clk_cfg = (struct ite_clk_cfg *)(sub_system); + uint8_t tmp_mask = 0; + + /* CGCTRL3R, bit 6, must always write a 1. */ + tmp_mask = (clk_cfg->ctrl == IT51XXX_ECPM_CGCTRL3R_OFF) ? 0x40 : 0x00; + sys_write8(sys_read8(config->ecpm_base + clk_cfg->ctrl) | clk_cfg->bits | tmp_mask, + config->ecpm_base + clk_cfg->ctrl); + + return 0; +} + +static int clock_control_it51xxx_get_rate(const struct device *dev, + clock_control_subsys_t sub_system, uint32_t *rate) +{ + const struct clock_control_it51xxx_config *const config = dev->config; + int reg_val = sys_read8(config->ecpm_base + ECPM_PLLFREQR) & ECPM_PLLFREQ_MASK; + + switch (reg_val) { + case 0x01: + *rate = KHZ(18400); + break; + case 0x03: + *rate = KHZ(32300); + break; + case 0x07: + *rate = KHZ(64500); + break; + case 0x09: + *rate = KHZ(48000); + break; + default: + return -ERANGE; + } + + return 0; +} + +static void pll_change_isr(const void *unused) +{ + ARG_UNUSED(unused); + + /* + * We are here because we have completed changing PLL sequence, + * so disabled PLL frequency change event interrupt. + */ + irq_disable(IT51XXX_IRQ_PLL_CHANGE); +} + +static void chip_configure_pll(const struct device *dev, uint8_t pll) +{ + const struct clock_control_it51xxx_config *config = dev->config; + + /* Set pll frequency change event */ + IRQ_CONNECT(IT51XXX_IRQ_PLL_CHANGE, 0, pll_change_isr, NULL, IRQ_TYPE_EDGE_RISING); + /* Clear interrupt status of pll frequency change event */ + ite_intc_isr_clear(IT51XXX_IRQ_PLL_CHANGE); + + irq_enable(IT51XXX_IRQ_PLL_CHANGE); + /* + * Configure PLL clock dividers. + * Writing data to these registers doesn't change the PLL frequency immediately until the + * status is changed into wakeup from the sleep mode. + * The following code is intended to make the system enter sleep mode, and wait PLL + * frequency change event to wakeup chip to complete PLL update. + */ + sys_write8(pll, config->ecpm_base + ECPM_PLLFREQR); + + /* Chip sleep after wait for interrupt (wfi) instruction */ + chip_pll_ctrl(CHIP_PLL_SLEEP); + /* Chip sleep and wait timer wake it up */ + __asm__ volatile("wfi"); + /* Chip sleep and wait timer wake it up */ + chip_pll_ctrl(CHIP_PLL_DOZE); +} + +static int clock_control_it51xxx_init(const struct device *dev) +{ + const struct clock_control_it51xxx_config *config = dev->config; + struct clock_control_it51xxx_data *data = dev->data; + int reg_val = sys_read8(config->ecpm_base + ECPM_PLLFREQR) & ECPM_PLLFREQ_MASK; + uint8_t autocg; + + /* Disable auto gating and enable it by the respective module. */ + autocg = sys_read8(config->ecpm_base + ECPM_AUTOCG); + sys_write8(autocg & ~(ECPM_AUART1CG | ECPM_AUART2CG | ECPM_ASSPICG | ECPM_ACIRCG), + config->ecpm_base + ECPM_AUTOCG); + + /* The following modules are gated in the initial state */ + sys_write8(ECPM_CIRCG | ECPM_SWUCCG, config->ecpm_base + ECPM_CGCTRL2R); + sys_write8(sys_read8(config->ecpm_base + ECPM_CGCTRL3R) | ECPM_PECICG | ECPM_SSPICG, + config->ecpm_base + ECPM_CGCTRL3R); + + if (IS_ENABLED(CONFIG_ITE_IT51XXX_INTC)) { + ite_intc_save_and_disable_interrupts(); + } + + if (reg_val != data->pll_configuration[config->pll_freq]) { + /* configure PLL clock */ + chip_configure_pll(dev, data->pll_configuration[config->pll_freq]); + } + + if (IS_ENABLED(CONFIG_ITE_IT51XXX_INTC)) { + ite_intc_restore_interrupts(); + } + + return 0; +} + +/* Clock controller driver registration */ +static DEVICE_API(clock_control, clock_control_it51xxx_api) = { + .on = clock_control_it51xxx_on, + .off = clock_control_it51xxx_off, + .get_rate = clock_control_it51xxx_get_rate, +}; + +static struct clock_control_it51xxx_data clock_control_it51xxx_data = { + .pll_configuration = pll_cfg, +}; + +static const struct clock_control_it51xxx_config clock_control_it51xxx_cfg = { + .ecpm_base = DT_INST_REG_ADDR(0), + .pll_freq = DT_INST_PROP(0, pll_frequency), +}; + +DEVICE_DT_INST_DEFINE(0, clock_control_it51xxx_init, NULL, &clock_control_it51xxx_data, + &clock_control_it51xxx_cfg, PRE_KERNEL_1, + CONFIG_IT51XXX_PLL_SEQUENCE_PRIORITY, &clock_control_it51xxx_api); diff --git a/dts/bindings/clock/ite,it51xxx-ecpm.yaml b/dts/bindings/clock/ite,it51xxx-ecpm.yaml new file mode 100644 index 00000000000..460828acdd1 --- /dev/null +++ b/dts/bindings/clock/ite,it51xxx-ecpm.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2025 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: ITE it51xxx ECPM (EC Clock and Power Management Controller) node + +compatible: "ite,it51xxx-ecpm" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + pll-frequency: + type: int + required: true + enum: + - 0 + - 1 + - 2 + - 3 + description: | + 0 = PLL_18400_KHZ, + 1 = PLL_32300_KHZ, + 2 = PLL_64500_KHZ, + 3 = PLL_48000_KHZ, + + "#clock-cells": + const: 2 + +clock-cells: + - ctrl + - bits diff --git a/dts/riscv/ite/it51xxx.dtsi b/dts/riscv/ite/it51xxx.dtsi index 6c28f7106f6..ffccfc3cda9 100644 --- a/dts/riscv/ite/it51xxx.dtsi +++ b/dts/riscv/ite/it51xxx.dtsi @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -914,6 +915,13 @@ #wuc-cells = <1>; }; + ecpm: clock-controller@f01e00 { + compatible = "ite,it51xxx-ecpm"; + reg = <0x00f01e00 0x0a>; + pll-frequency = ; + #clock-cells = <2>; + }; + gctrl: general-control@f02000 { compatible = "ite,it51xxx-gctrl"; reg = <0x00f02000 0x100>; diff --git a/include/zephyr/dt-bindings/clock/ite-it51xxx-clock.h b/include/zephyr/dt-bindings/clock/ite-it51xxx-clock.h new file mode 100644 index 00000000000..d2e2a7dd58d --- /dev/null +++ b/include/zephyr/dt-bindings/clock/ite-it51xxx-clock.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IT51XXX_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IT51XXX_CLOCK_H_ + +/* Clock control */ +#define IT51XXX_ECPM_CGCTRL2R_OFF 0x02 +#define IT51XXX_ECPM_CGCTRL3R_OFF 0x05 +#define IT51XXX_ECPM_CGCTRL4R_OFF 0x09 + +/* Clock PLL frequency */ +#define PLL_18400_KHZ 0 +#define PLL_32300_KHZ 1 +#define PLL_64500_KHZ 2 +#define PLL_48000_KHZ 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IT51XXX_CLOCK_H_ */ diff --git a/soc/ite/ec/common/soc_common.h b/soc/ite/ec/common/soc_common.h index 577d43b5381..31e1d8a9553 100644 --- a/soc/ite/ec/common/soc_common.h +++ b/soc/ite/ec/common/soc_common.h @@ -16,6 +16,11 @@ #ifndef _ASMLANGUAGE +struct ite_clk_cfg { + uint8_t ctrl; + uint8_t bits; +}; + #ifdef CONFIG_HAS_ITE_INTC /* * Save current interrupt state of soc-level into ier_setting[] with