Skip to content

Commit bfd200b

Browse files
bjarki-andreasenkartben
authored andcommitted
drivers: clock_control: add nrfs_audiopll clock driver
Add NRFS AudioPLL clock control device driver. Signed-off-by: Bjarki Arge Andreasen <[email protected]>
1 parent d88fa8d commit bfd200b

File tree

3 files changed

+314
-0
lines changed

3 files changed

+314
-0
lines changed

drivers/clock_control/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_PWM clock_cont
4141
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_control_rpi_pico.c)
4242
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL clock_control_nrf2_global_hsfll.c)
4343
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RTS5912_SCCON clock_control_rts5912_sccon.c)
44+
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL clock_control_nrf2_audiopll.c)
4445

4546
if(CONFIG_CLOCK_CONTROL_NRF2)
4647
zephyr_library_sources(clock_control_nrf2_common.c)

drivers/clock_control/Kconfig.nrf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,10 @@ config CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY
231231

232232
endif # CLOCK_CONTROL_NRF2_GLOBAL_HSFLL
233233

234+
config CLOCK_CONTROL_NRF2_AUDIOPLL
235+
bool "NRFS AudioPLL driver support"
236+
depends on DT_HAS_NORDIC_NRFS_AUDIOPLL_ENABLED
237+
depends on NRFS_AUDIOPLL_SERVICE_ENABLED
238+
default y
239+
234240
endif # CLOCK_CONTROL_NRF2
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT nordic_nrfs_audiopll
7+
8+
#include "clock_control_nrf2_common.h"
9+
#include <zephyr/devicetree.h>
10+
#include <zephyr/dt-bindings/clock/nrfs-audiopll.h>
11+
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
12+
#include <nrfs_audiopll.h>
13+
#include <nrfs_backend_ipc_service.h>
14+
15+
#include <zephyr/logging/log.h>
16+
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
17+
18+
#define SHIM_DEFAULT_PRESCALER AUDIOPLL_DIV_12
19+
20+
BUILD_ASSERT(
21+
DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
22+
"multiple instances not supported"
23+
);
24+
25+
BUILD_ASSERT(DT_INST_PROP(0, frequency) >= NRFS_AUDIOPLL_FREQ_MIN);
26+
BUILD_ASSERT(DT_INST_PROP(0, frequency) <= NRFS_AUDIOPLL_FREQ_MAX);
27+
28+
struct shim_data {
29+
struct onoff_manager mgr;
30+
onoff_notify_fn mgr_notify;
31+
const struct device *dev;
32+
struct k_sem evt_sem;
33+
nrfs_audiopll_evt_type_t evt;
34+
};
35+
36+
static int shim_nrfs_request_enable(const struct device *dev)
37+
{
38+
struct shim_data *dev_data = dev->data;
39+
nrfs_err_t err;
40+
41+
LOG_DBG("send enable request");
42+
43+
dev_data->evt = NRFS_AUDIOPLL_EVT_ENABLED;
44+
err = nrfs_audiopll_enable_request(dev_data);
45+
if (err != NRFS_SUCCESS) {
46+
return -EIO;
47+
}
48+
49+
return 0;
50+
}
51+
52+
static int shim_nrfs_request_disable(const struct device *dev)
53+
{
54+
struct shim_data *dev_data = dev->data;
55+
nrfs_err_t err;
56+
57+
LOG_DBG("send disable request");
58+
59+
dev_data->evt = NRFS_AUDIOPLL_EVT_DISABLED;
60+
err = nrfs_audiopll_disable_request(dev_data);
61+
if (err != NRFS_SUCCESS) {
62+
return -EIO;
63+
}
64+
65+
return 0;
66+
}
67+
68+
static void onoff_start_option(struct onoff_manager *mgr, onoff_notify_fn notify)
69+
{
70+
struct shim_data *dev_data = CONTAINER_OF(mgr, struct shim_data, mgr);
71+
const struct device *dev = dev_data->dev;
72+
int ret;
73+
74+
dev_data->mgr_notify = notify;
75+
76+
ret = shim_nrfs_request_enable(dev);
77+
if (ret) {
78+
dev_data->mgr_notify = NULL;
79+
notify(mgr, -EIO);
80+
}
81+
}
82+
83+
static void onoff_stop_option(struct onoff_manager *mgr, onoff_notify_fn notify)
84+
{
85+
struct shim_data *dev_data = CONTAINER_OF(mgr, struct shim_data, mgr);
86+
const struct device *dev = dev_data->dev;
87+
int ret;
88+
89+
dev_data->mgr_notify = notify;
90+
91+
ret = shim_nrfs_request_disable(dev);
92+
if (ret) {
93+
dev_data->mgr_notify = NULL;
94+
notify(mgr, -EIO);
95+
}
96+
}
97+
98+
static const struct onoff_transitions shim_mgr_transitions = {
99+
.start = onoff_start_option,
100+
.stop = onoff_stop_option
101+
};
102+
103+
/*
104+
* Formula:
105+
*
106+
* frequency = ((4 + (freq_fraction * 2^-16)) * 32000000) / 12
107+
*
108+
* Simplified linear approximation:
109+
*
110+
* frequency = 10666666 + (((13333292 - 10666666) / 65535) * freq_fraction)
111+
* frequency = 10666666 + ((2666626 / 65535) * freq_fraction)
112+
* frequency = ((10666666 * 65535) + (2666626 * freq_fraction)) / 65535
113+
* frequency = (699039956310 + (2666626 * freq_fraction)) / 65535
114+
*
115+
* Isolate freq_fraction:
116+
*
117+
* frequency = (699039956310 + (2666626 * freq_fraction)) / 65535
118+
* frequency * 65535 = 699039956310 + (2666626 * freq_fraction)
119+
* (frequency * 65535) - 699039956310 = 2666626 * freq_fraction
120+
* freq_fraction = ((frequency * 65535) - 699039956310) / 2666626
121+
*/
122+
static uint16_t shim_frequency_to_freq_fraction(uint32_t frequency)
123+
{
124+
uint64_t freq_fraction;
125+
126+
freq_fraction = frequency;
127+
freq_fraction *= 65535;
128+
freq_fraction -= 699039956310;
129+
freq_fraction = DIV_ROUND_CLOSEST(freq_fraction, 2666626);
130+
131+
return (uint16_t)freq_fraction;
132+
}
133+
134+
static int shim_nrfs_request_freq_sync(const struct device *dev, uint16_t freq_fraction)
135+
{
136+
struct shim_data *dev_data = dev->data;
137+
nrfs_err_t err;
138+
139+
LOG_DBG("send freq request");
140+
141+
err = nrfs_audiopll_request_freq(freq_fraction, dev_data);
142+
if (err != NRFS_SUCCESS) {
143+
return -EIO;
144+
}
145+
146+
k_sem_take(&dev_data->evt_sem, K_FOREVER);
147+
return dev_data->evt == NRFS_AUDIOPLL_EVT_FREQ_CONFIRMED ? 0 : -EIO;
148+
}
149+
150+
static int shim_nrfs_request_prescaler_sync(const struct device *dev,
151+
enum audiopll_prescaler_div div)
152+
{
153+
struct shim_data *dev_data = dev->data;
154+
nrfs_err_t err;
155+
156+
LOG_DBG("send prescaler request");
157+
158+
err = nrfs_audiopll_request_prescaler(div, dev_data);
159+
if (err != NRFS_SUCCESS) {
160+
return -EIO;
161+
}
162+
163+
k_sem_take(&dev_data->evt_sem, K_FOREVER);
164+
return dev_data->evt == NRFS_AUDIOPLL_EVT_PRESCALER_CONFIRMED ? 0 : -EIO;
165+
}
166+
167+
static void shim_nrfs_audiopll_init_evt_handler(nrfs_audiopll_evt_t const *evt, void *context)
168+
{
169+
struct shim_data *dev_data = context;
170+
171+
LOG_DBG("init resp evt %u", (uint32_t)evt->type);
172+
173+
dev_data->evt = evt->type;
174+
k_sem_give(&dev_data->evt_sem);
175+
}
176+
177+
static void shim_nrfs_audiopll_evt_handler(nrfs_audiopll_evt_t const *evt, void *context)
178+
{
179+
struct shim_data *dev_data = context;
180+
int ret;
181+
182+
LOG_DBG("resp evt %u", (uint32_t)evt->type);
183+
184+
if (dev_data->mgr_notify == NULL) {
185+
return;
186+
}
187+
188+
ret = evt->type == dev_data->evt ? 0 : -EIO;
189+
dev_data->mgr_notify(&dev_data->mgr, ret);
190+
}
191+
192+
static int api_request_audiopll(const struct device *dev,
193+
const struct nrf_clock_spec *spec,
194+
struct onoff_client *cli)
195+
{
196+
struct shim_data *dev_data = dev->data;
197+
struct onoff_manager *mgr = &dev_data->mgr;
198+
199+
ARG_UNUSED(spec);
200+
201+
return onoff_request(mgr, cli);
202+
}
203+
204+
static int api_release_audiopll(const struct device *dev,
205+
const struct nrf_clock_spec *spec)
206+
{
207+
struct shim_data *dev_data = dev->data;
208+
struct onoff_manager *mgr = &dev_data->mgr;
209+
210+
ARG_UNUSED(spec);
211+
212+
return onoff_release(mgr);
213+
}
214+
215+
static int api_cancel_or_release_audiopll(const struct device *dev,
216+
const struct nrf_clock_spec *spec,
217+
struct onoff_client *cli)
218+
{
219+
struct shim_data *dev_data = dev->data;
220+
struct onoff_manager *mgr = &dev_data->mgr;
221+
222+
ARG_UNUSED(spec);
223+
224+
return onoff_cancel_or_release(mgr, cli);
225+
}
226+
227+
static DEVICE_API(nrf_clock_control, shim_driver_api) = {
228+
.std_api = {
229+
.on = api_nosys_on_off,
230+
.off = api_nosys_on_off,
231+
},
232+
.request = api_request_audiopll,
233+
.release = api_release_audiopll,
234+
.cancel_or_release = api_cancel_or_release_audiopll,
235+
};
236+
237+
static int shim_init(const struct device *dev)
238+
{
239+
struct shim_data *dev_data = dev->data;
240+
nrfs_err_t err;
241+
int ret;
242+
uint16_t freq_fraction;
243+
244+
LOG_DBG("waiting for nrfs backend connected");
245+
err = nrfs_backend_wait_for_connection(K_FOREVER);
246+
if (err != NRFS_SUCCESS) {
247+
LOG_ERR("nrfs backend not connected");
248+
return -ENODEV;
249+
}
250+
251+
k_sem_init(&dev_data->evt_sem, 0, 1);
252+
253+
err = nrfs_audiopll_init(shim_nrfs_audiopll_init_evt_handler);
254+
if (err != NRFS_SUCCESS) {
255+
LOG_ERR("failed to init audiopll service");
256+
return -ENODEV;
257+
}
258+
259+
ret = shim_nrfs_request_prescaler_sync(dev, SHIM_DEFAULT_PRESCALER);
260+
if (ret) {
261+
LOG_ERR("failed to set prescaler divider");
262+
return ret;
263+
}
264+
265+
freq_fraction = shim_frequency_to_freq_fraction(DT_INST_PROP(0, frequency));
266+
267+
LOG_DBG("requesting freq_fraction %u for frequency %uHz",
268+
freq_fraction,
269+
DT_INST_PROP(0, frequency));
270+
271+
ret = shim_nrfs_request_freq_sync(dev, freq_fraction);
272+
if (ret) {
273+
LOG_ERR("failed to set freq_fraction");
274+
return ret;
275+
}
276+
277+
nrfs_audiopll_uninit();
278+
279+
ret = onoff_manager_init(&dev_data->mgr, &shim_mgr_transitions);
280+
if (ret < 0) {
281+
LOG_ERR("failed to init onoff manager");
282+
return ret;
283+
}
284+
285+
err = nrfs_audiopll_init(shim_nrfs_audiopll_evt_handler);
286+
if (err != NRFS_SUCCESS) {
287+
LOG_ERR("failed to init audiopll service");
288+
return -ENODEV;
289+
}
290+
291+
return 0;
292+
}
293+
294+
static struct shim_data shim_data = {
295+
.dev = DEVICE_DT_INST_GET(0),
296+
};
297+
298+
DEVICE_DT_INST_DEFINE(
299+
0,
300+
shim_init,
301+
NULL,
302+
&shim_data,
303+
NULL,
304+
POST_KERNEL,
305+
UTIL_INC(CONFIG_NRFS_BACKEND_IPC_SERVICE_INIT_PRIO),
306+
&shim_driver_api,
307+
);

0 commit comments

Comments
 (0)