forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 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
1 parent
be8a8fa
commit 117be61
Showing
4 changed files
with
146 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |