Skip to content

Commit

Permalink
drivers: clock_control: nrf_auxpll: add initial driver
Browse files Browse the repository at this point in the history
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
zephyrproject-rtos/hal_nordic#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 <[email protected]>
  • Loading branch information
gmarull authored and carlescufi committed May 29, 2024
1 parent c0163e9 commit 47e14db
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/clock_control/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 2 additions & 0 deletions drivers/clock_control/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 9 additions & 0 deletions drivers/clock_control/Kconfig.nrf_auxpll
Original file line number Diff line number Diff line change
@@ -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 changes: 134 additions & 0 deletions drivers/clock_control/clock_control_nrf_auxpll.c
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 47e14db

Please sign in to comment.