drivers/clock: Add clock drivers of it51xxx
Add clock drivers for ITE it51xxx series. Signed-off-by: Tim Lin <tim2.lin@ite.corp-partner.google.com>
This commit is contained in:
parent
f67c2a3d33
commit
df56c85e94
8 changed files with 291 additions and 0 deletions
|
@ -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_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_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_NRF2_AUDIOPLL clock_control_nrf2_audiopll.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_IT51XXX clock_control_it51xxx.c)
|
||||||
|
|
||||||
if(CONFIG_CLOCK_CONTROL_NRF2)
|
if(CONFIG_CLOCK_CONTROL_NRF2)
|
||||||
zephyr_library_sources(clock_control_nrf2_common.c)
|
zephyr_library_sources(clock_control_nrf2_common.c)
|
||||||
|
|
|
@ -108,4 +108,6 @@ source "drivers/clock_control/Kconfig.siwx91x"
|
||||||
|
|
||||||
source "drivers/clock_control/Kconfig.wch_rcc"
|
source "drivers/clock_control/Kconfig.wch_rcc"
|
||||||
|
|
||||||
|
source "drivers/clock_control/Kconfig.it51xxx"
|
||||||
|
|
||||||
endif # CLOCK_CONTROL
|
endif # CLOCK_CONTROL
|
||||||
|
|
17
drivers/clock_control/Kconfig.it51xxx
Normal file
17
drivers/clock_control/Kconfig.it51xxx
Normal file
|
@ -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
|
204
drivers/clock_control/clock_control_it51xxx.c
Normal file
204
drivers/clock_control/clock_control_it51xxx.c
Normal file
|
@ -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 <soc.h>
|
||||||
|
#include <zephyr/drivers/clock_control.h>
|
||||||
|
#include <zephyr/dt-bindings/clock/ite-it51xxx-clock.h>
|
||||||
|
#include <zephyr/dt-bindings/interrupt-controller/ite-it51xxx-intc.h>
|
||||||
|
#include <zephyr/irq.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
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);
|
33
dts/bindings/clock/ite,it51xxx-ecpm.yaml
Normal file
33
dts/bindings/clock/ite,it51xxx-ecpm.yaml
Normal file
|
@ -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
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <ite/it51xxx-wuc-map.dtsi>
|
#include <ite/it51xxx-wuc-map.dtsi>
|
||||||
#include <mem.h>
|
#include <mem.h>
|
||||||
|
#include <zephyr/dt-bindings/clock/ite-it51xxx-clock.h>
|
||||||
#include <zephyr/dt-bindings/dt-util.h>
|
#include <zephyr/dt-bindings/dt-util.h>
|
||||||
#include <zephyr/dt-bindings/gpio/gpio.h>
|
#include <zephyr/dt-bindings/gpio/gpio.h>
|
||||||
#include <zephyr/dt-bindings/interrupt-controller/ite-it51xxx-intc.h>
|
#include <zephyr/dt-bindings/interrupt-controller/ite-it51xxx-intc.h>
|
||||||
|
@ -914,6 +915,13 @@
|
||||||
#wuc-cells = <1>;
|
#wuc-cells = <1>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ecpm: clock-controller@f01e00 {
|
||||||
|
compatible = "ite,it51xxx-ecpm";
|
||||||
|
reg = <0x00f01e00 0x0a>;
|
||||||
|
pll-frequency = <PLL_48000_KHZ>;
|
||||||
|
#clock-cells = <2>;
|
||||||
|
};
|
||||||
|
|
||||||
gctrl: general-control@f02000 {
|
gctrl: general-control@f02000 {
|
||||||
compatible = "ite,it51xxx-gctrl";
|
compatible = "ite,it51xxx-gctrl";
|
||||||
reg = <0x00f02000 0x100>;
|
reg = <0x00f02000 0x100>;
|
||||||
|
|
21
include/zephyr/dt-bindings/clock/ite-it51xxx-clock.h
Normal file
21
include/zephyr/dt-bindings/clock/ite-it51xxx-clock.h
Normal file
|
@ -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_ */
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
#ifndef _ASMLANGUAGE
|
#ifndef _ASMLANGUAGE
|
||||||
|
|
||||||
|
struct ite_clk_cfg {
|
||||||
|
uint8_t ctrl;
|
||||||
|
uint8_t bits;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_HAS_ITE_INTC
|
#ifdef CONFIG_HAS_ITE_INTC
|
||||||
/*
|
/*
|
||||||
* Save current interrupt state of soc-level into ier_setting[] with
|
* Save current interrupt state of soc-level into ier_setting[] with
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue