Skip to content

Commit f0a433f

Browse files
rugeGerritsendanieldegrasse
authored andcommitted
drivers: clock_control: nrf2_lfclk: Fix selecting lowest power clock
The application or drivers can request the LFCLK with a given precision and accuracy. The driver should select the clock source which has the lowest power consumption and still satisfies the requested accuracy and precision. Before this commit, this was not the case. Consider the case where the BICR has configured the system to have LFXO with accuracy of 20 ppm. The existing code would have ordered the clock options as following: ``` [0] = {LFLPRC, 1000 ppm}, [1] = {LFRC, 500 ppm}, [2] = {SYNTH, 30 ppm}, [3] = {LFXO_PIERCE, 20 ppm}, [4] = {LFXO_PIERCE_HP, 20 ppm} ``` **Example 1**: The user requests the clock with an accuracy of 30 ppm. The existing code would request the power hungry "SYNTH". **Example 2**: The user requests a clock with an accuracy of 500 ppm. The existing code would request the LFRC which consumes more power than the LFXO. This commit fixes this issue by ordering the clock sources according to power consumption. For the examples above we user request would result in requesting the 20 ppm LFXO. Signed-off-by: Rubin Gerritsen <rubin.gerritsen@nordicsemi.no>
1 parent 2411238 commit f0a433f

File tree

1 file changed

+38
-23
lines changed

1 file changed

+38
-23
lines changed

drivers/clock_control/clock_control_nrf2_lfclk.c

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,25 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
3232

3333
#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr))
3434

35-
/* Clock options sorted from lowest to highest accuracy/precision */
35+
/* Clock options sorted from highest to lowest power consumption.
36+
* - Clock synthesized from a high frequency clock
37+
* - Internal RC oscillator
38+
* - Internal low power RC oscillator
39+
* - External clock. These are inserted into the list at driver initialization.
40+
* Set to one of the following:
41+
* - XTAL. Low or High precision
42+
* - External sine or square wave
43+
*/
3644
static struct clock_options {
3745
uint16_t accuracy : 15;
3846
uint16_t precision : 1;
3947
nrfs_clock_src_t src;
4048
} clock_options[LFCLK_MAX_OPTS] = {
4149
{
42-
.accuracy = LFCLK_LFLPRC_ACCURACY,
43-
.precision = 0,
44-
.src = NRFS_CLOCK_SRC_LFCLK_LFLPRC,
50+
/* NRFS will request FLL16M use HFXO in bypass mode if SYNTH src is used */
51+
.accuracy = LFCLK_HFXO_ACCURACY,
52+
.precision = 1,
53+
.src = NRFS_CLOCK_SRC_LFCLK_SYNTH,
4554
},
4655
{
4756
.accuracy = LFCLK_LFRC_ACCURACY,
@@ -50,10 +59,11 @@ static struct clock_options {
5059
},
5160
{
5261
/* NRFS will request FLL16M use HFXO in bypass mode if SYNTH src is used */
53-
.accuracy = LFCLK_HFXO_ACCURACY,
54-
.precision = 1,
55-
.src = NRFS_CLOCK_SRC_LFCLK_SYNTH,
62+
.accuracy = LFCLK_LFLPRC_ACCURACY,
63+
.precision = 0,
64+
.src = NRFS_CLOCK_SRC_LFCLK_LFLPRC,
5665
},
66+
/* Remaining options are populated on lfclk_init */
5767
};
5868

5969
struct lfclk_dev_data {
@@ -125,10 +135,15 @@ static int lfclk_resolve_spec_to_idx(const struct device *dev,
125135
? dev_data->max_accuracy
126136
: req_spec->accuracy;
127137

128-
for (int i = 0; i < dev_data->clock_options_cnt; ++i) {
129-
if ((req_accuracy &&
130-
req_accuracy < clock_options[i].accuracy) ||
131-
req_spec->precision > clock_options[i].precision) {
138+
for (int i = dev_data->clock_options_cnt - 1; i >= 0; --i) {
139+
/* Iterate to a more power hungry and accurate clock source
140+
* If the requested accuracy is higher (lower ppm) than what
141+
* the clock source can provide.
142+
*
143+
* In case of an accuracy of 0 (don't care), do not check accuracy.
144+
*/
145+
if ((req_accuracy != 0 && req_accuracy < clock_options[i].accuracy) ||
146+
(req_spec->precision > clock_options[i].precision)) {
132147
continue;
133148
}
134149

@@ -316,24 +331,24 @@ static int lfclk_init(const struct device *dev)
316331

317332
switch (lfosc_mode) {
318333
case NRF_BICR_LFOSC_MODE_CRYSTAL:
319-
clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy;
320-
clock_options[LFCLK_MAX_OPTS - 2].precision = 0;
321-
clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE;
322-
323334
clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy;
324-
clock_options[LFCLK_MAX_OPTS - 1].precision = 1;
325-
clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP;
335+
clock_options[LFCLK_MAX_OPTS - 1].precision = 0;
336+
clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE;
337+
338+
clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy;
339+
clock_options[LFCLK_MAX_OPTS - 2].precision = 1;
340+
clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP;
326341

327342
dev_data->clock_options_cnt += 2;
328343
break;
329344
case NRF_BICR_LFOSC_MODE_EXTSINE:
330-
clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy;
331-
clock_options[LFCLK_MAX_OPTS - 2].precision = 0;
332-
clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE;
333-
334345
clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy;
335-
clock_options[LFCLK_MAX_OPTS - 1].precision = 1;
336-
clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP;
346+
clock_options[LFCLK_MAX_OPTS - 1].precision = 0;
347+
clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE;
348+
349+
clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy;
350+
clock_options[LFCLK_MAX_OPTS - 2].precision = 1;
351+
clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP;
337352

338353
dev_data->clock_options_cnt += 2;
339354
break;

0 commit comments

Comments
 (0)