drivers: clock_control: nrf_auxpll: add initial driver
Add a new driver for the AUXPLL peripheral found in some new Nordic SoCs, e.g. nRF54H20. AUXPLL is used to clock some peripherals like e.g. CAN. Note that driver is implemented natively as Nordic HAL lacks definitions for the AUXPLL IP, this may be changed once these become available. Note that usage of nrf_auxpll_config_set generates unnecessary extra assembly code compared to the proposed API in https://github.com/zephyrproject-rtos/hal_nordic/pull/185 which guarantees static initialization and single write access, possible in the Zephyr context. However, current solution has been enforced until further discussion on raw access APIs takes place. Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
This commit is contained in:
parent
c0163e9362
commit
47e14dbf82
4 changed files with 146 additions and 0 deletions
|
|
@ -77,3 +77,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)
|
||||
|
|
|
|||
|
|
@ -90,4 +90,6 @@ source "drivers/clock_control/Kconfig.pwm"
|
|||
|
||||
source "drivers/clock_control/Kconfig.rpi_pico"
|
||||
|
||||
source "drivers/clock_control/Kconfig.nrf_auxpll"
|
||||
|
||||
endif # CLOCK_CONTROL
|
||||
|
|
|
|||
9
drivers/clock_control/Kconfig.nrf_auxpll
Normal file
9
drivers/clock_control/Kconfig.nrf_auxpll
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config CLOCK_CONTROL_NRF_AUXPLL
|
||||
bool "nRF Auxiliary PLL driver"
|
||||
default y
|
||||
depends on DT_HAS_NORDIC_NRF_AUXPLL_ENABLED
|
||||
help
|
||||
Driver for nRF Auxiliary PLL.
|
||||
134
drivers/clock_control/clock_control_nrf_auxpll.c
Normal file
134
drivers/clock_control/clock_control_nrf_auxpll.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nordic_nrf_auxpll
|
||||
|
||||
#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.h>
|
||||
#include <zephyr/toolchain.h>
|
||||
|
||||
#include <hal/nrf_auxpll.h>
|
||||
|
||||
struct clock_control_nrf_auxpll_config {
|
||||
NRF_AUXPLL_Type *auxpll;
|
||||
uint32_t ref_clk_hz;
|
||||
uint32_t ficr_ctune;
|
||||
nrf_auxpll_config_t cfg;
|
||||
uint16_t frequency;
|
||||
nrf_auxpll_ctrl_outsel_t out_div;
|
||||
};
|
||||
|
||||
static int clock_control_nrf_auxpll_on(const struct device *dev, clock_control_subsys_t sys)
|
||||
{
|
||||
const struct clock_control_nrf_auxpll_config *config = dev->config;
|
||||
|
||||
ARG_UNUSED(sys);
|
||||
|
||||
nrf_auxpll_task_trigger(config->auxpll, NRF_AUXPLL_TASK_START);
|
||||
|
||||
while (!nrf_auxpll_mode_locked_check(config->auxpll)) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clock_control_nrf_auxpll_off(const struct device *dev, clock_control_subsys_t sys)
|
||||
{
|
||||
const struct clock_control_nrf_auxpll_config *config = dev->config;
|
||||
|
||||
ARG_UNUSED(sys);
|
||||
|
||||
nrf_auxpll_task_trigger(config->auxpll, NRF_AUXPLL_TASK_STOP);
|
||||
|
||||
while (nrf_auxpll_running_check(config->auxpll)) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clock_control_nrf_auxpll_get_rate(const struct device *dev, clock_control_subsys_t sys,
|
||||
uint32_t *rate)
|
||||
{
|
||||
const struct clock_control_nrf_auxpll_config *config = dev->config;
|
||||
uint8_t ratio;
|
||||
|
||||
ARG_UNUSED(sys);
|
||||
|
||||
ratio = nrf_auxpll_static_ratio_get(config->auxpll);
|
||||
|
||||
*rate = (ratio * config->ref_clk_hz +
|
||||
(config->ref_clk_hz * (uint64_t)config->frequency) /
|
||||
(AUXPLL_AUXPLLCTRL_FREQUENCY_FREQUENCY_MaximumDiv + 1U)) /
|
||||
config->out_div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum clock_control_status clock_control_nrf_auxpll_get_status(const struct device *dev,
|
||||
clock_control_subsys_t sys)
|
||||
{
|
||||
const struct clock_control_nrf_auxpll_config *config = dev->config;
|
||||
|
||||
ARG_UNUSED(sys);
|
||||
|
||||
if (nrf_auxpll_mode_locked_check(config->auxpll)) {
|
||||
return CLOCK_CONTROL_STATUS_ON;
|
||||
}
|
||||
|
||||
return CLOCK_CONTROL_STATUS_OFF;
|
||||
}
|
||||
|
||||
static struct clock_control_driver_api clock_control_nrf_auxpll_api = {
|
||||
.on = clock_control_nrf_auxpll_on,
|
||||
.off = clock_control_nrf_auxpll_off,
|
||||
.get_rate = clock_control_nrf_auxpll_get_rate,
|
||||
.get_status = clock_control_nrf_auxpll_get_status,
|
||||
};
|
||||
|
||||
static int clock_control_nrf_auxpll_init(const struct device *dev)
|
||||
{
|
||||
const struct clock_control_nrf_auxpll_config *config = dev->config;
|
||||
|
||||
nrf_auxpll_ctrl_frequency_set(config->auxpll, config->frequency);
|
||||
|
||||
nrf_auxpll_lock(config->auxpll);
|
||||
nrf_auxpll_trim_ctune_set(config->auxpll, sys_read8(config->ficr_ctune));
|
||||
nrf_auxpll_config_set(config->auxpll, &config->cfg);
|
||||
nrf_auxpll_ctrl_outsel_set(config->auxpll, config->out_div);
|
||||
nrf_auxpll_unlock(config->auxpll);
|
||||
|
||||
nrf_auxpll_ctrl_mode_set(config->auxpll, NRF_AUXPLL_CTRL_MODE_LOCKED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CLOCK_CONTROL_NRF_AUXPLL_DEFINE(n) \
|
||||
static const struct clock_control_nrf_auxpll_config config##n = { \
|
||||
.auxpll = (NRF_AUXPLL_Type *)DT_INST_REG_ADDR(n), \
|
||||
.ref_clk_hz = DT_PROP(DT_INST_CLOCKS_CTLR(n), clock_frequency), \
|
||||
.ficr_ctune = DT_REG_ADDR(DT_INST_PHANDLE(n, nordic_ficrs)) + \
|
||||
DT_INST_PHA(n, nordic_ficrs, offset), \
|
||||
.cfg = \
|
||||
{ \
|
||||
.outdrive = DT_INST_PROP(n, nordic_out_drive), \
|
||||
.current_tune = DT_INST_PROP(n, nordic_current_tune), \
|
||||
.sdm_off = DT_INST_PROP(n, nordic_sdm_disable), \
|
||||
.dither_off = DT_INST_PROP(n, nordic_dither_disable), \
|
||||
.range = DT_INST_ENUM_IDX(n, nordic_range), \
|
||||
}, \
|
||||
.frequency = DT_INST_PROP(n, nordic_frequency), \
|
||||
.out_div = DT_INST_PROP(n, nordic_out_div), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, clock_control_nrf_auxpll_init, NULL, NULL, &config##n, \
|
||||
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \
|
||||
&clock_control_nrf_auxpll_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(CLOCK_CONTROL_NRF_AUXPLL_DEFINE)
|
||||
Loading…
Reference in a new issue