Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 29 additions & 20 deletions drivers/clock_control/clock_control_nrfs_audiopll.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);

#define SHIM_DEFAULT_PRESCALER AUDIOPLL_DIV_12
#define SHIM_DEFAULT_PRESCALER 12

BUILD_ASSERT(
DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
Expand All @@ -33,6 +33,25 @@ struct shim_data {
nrfs_audiopll_evt_type_t evt;
};

static enum audiopll_prescaler_div get_prescaler_div(uint8_t divider)
{
switch (divider) {
case 0:
return AUDIOPLL_DIV_DISABLED;
case 6:
return AUDIOPLL_DIV_6;
case 8:
return AUDIOPLL_DIV_8;
case 12:
return AUDIOPLL_DIV_12;
Copy link
Contributor

@bjarki-andreasen bjarki-andreasen Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prescaler div 12 was the only used and valid prescaler when this driver was written, has that changed?

case 16:
return AUDIOPLL_DIV_16;
default:
__ASSERT(divider <= 4, "invalid audiopll divider");
return (enum audiopll_prescaler_div)divider;
}
Comment on lines +38 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values seem to originate from nrfs header, but I have no idea why nrfs makes them available. I would prefer if AudioPLL just continues to use hardcoded AUDIOPLL_DIV_12 which is known to work.

}

static int shim_nrfs_request_enable(const struct device *dev)
{
struct shim_data *dev_data = dev->data;
Expand Down Expand Up @@ -103,30 +122,19 @@ static const struct onoff_transitions shim_mgr_transitions = {
/*
* Formula:
*
* frequency = ((4 + (freq_fraction * 2^-16)) * 32000000) / 12
*
* Simplified linear approximation:
*
* frequency = 10666666 + (((13333292 - 10666666) / 65535) * freq_fraction)
* frequency = 10666666 + ((2666626 / 65535) * freq_fraction)
* frequency = ((10666666 * 65535) + (2666626 * freq_fraction)) / 65535
* frequency = (699039956310 + (2666626 * freq_fraction)) / 65535
* frequency = ((4 + (freq_fraction * 2^-16)) * 32000000) / PRESCALER_DIV
*
* Isolate freq_fraction:
* Solving for freq_fraction:
*
* frequency = (699039956310 + (2666626 * freq_fraction)) / 65535
* frequency * 65535 = 699039956310 + (2666626 * freq_fraction)
* (frequency * 65535) - 699039956310 = 2666626 * freq_fraction
* freq_fraction = ((frequency * 65535) - 699039956310) / 2666626
* freq_fraction = (32 * PRESCALER_DIV * frequency) / 15625 - 262144
*/
static uint16_t shim_frequency_to_freq_fraction(uint32_t frequency)
static uint16_t shim_frequency_to_freq_fraction(uint32_t frequency, uint8_t prescaler_div)
{
uint64_t freq_fraction;

freq_fraction = frequency;
freq_fraction *= 65535;
freq_fraction -= 699039956310;
freq_fraction = DIV_ROUND_CLOSEST(freq_fraction, 2666626);
freq_fraction *= 32 * prescaler_div;
freq_fraction = DIV_ROUND_CLOSEST(freq_fraction, 15625) - 262144;

return (uint16_t)freq_fraction;
}
Expand Down Expand Up @@ -256,13 +264,14 @@ static int shim_init(const struct device *dev)
return -ENODEV;
}

ret = shim_nrfs_request_prescaler_sync(dev, SHIM_DEFAULT_PRESCALER);
ret = shim_nrfs_request_prescaler_sync(dev, get_prescaler_div(SHIM_DEFAULT_PRESCALER));
if (ret) {
LOG_ERR("failed to set prescaler divider");
return ret;
}

freq_fraction = shim_frequency_to_freq_fraction(DT_INST_PROP(0, frequency));
freq_fraction =
shim_frequency_to_freq_fraction(DT_INST_PROP(0, frequency), SHIM_DEFAULT_PRESCALER);

LOG_DBG("requesting freq_fraction %u for frequency %uHz",
freq_fraction,
Expand Down