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:
Gerard Marull-Paretas 2024-04-29 13:20:27 +02:00 committed by Carles Cufí
parent c0163e9362
commit 47e14dbf82
4 changed files with 146 additions and 0 deletions

View file

@ -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)

View file

@ -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

View 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.

View 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)