17
17
18
18
#include <zephyr/devicetree.h>
19
19
#include <zephyr/kernel.h>
20
- #include <zephyr/devicetree.h>
21
20
#include <zephyr/init.h>
22
21
#include <zephyr/logging/log.h>
23
22
#include <zephyr/cache.h>
@@ -50,46 +49,43 @@ static inline void power_and_clock_configuration(void)
50
49
*/
51
50
#if DT_ENUM_HAS_VALUE (LFXO_NODE , load_capacitors , internal )
52
51
uint32_t xosc32ktrim = NRF_FICR -> XOSC32KTRIM ;
53
-
54
- uint32_t offset_k =
55
- (xosc32ktrim & FICR_XOSC32KTRIM_OFFSET_Msk ) >> FICR_XOSC32KTRIM_OFFSET_Pos ;
56
-
52
+ /* The SLOPE field is in the two's complement form, hence this special
53
+ * handling. Ideally, it would result in just one SBFX instruction for
54
+ * extracting the slope value, at least gcc is capable of producing such
55
+ * output, but since the compiler apparently tries first to optimize
56
+ * additions and subtractions, it generates slightly less than optimal
57
+ * code.
58
+ */
57
59
uint32_t slope_field_k =
58
60
(xosc32ktrim & FICR_XOSC32KTRIM_SLOPE_Msk ) >> FICR_XOSC32KTRIM_SLOPE_Pos ;
59
61
uint32_t slope_mask_k = FICR_XOSC32KTRIM_SLOPE_Msk >> FICR_XOSC32KTRIM_SLOPE_Pos ;
60
62
uint32_t slope_sign_k = (slope_mask_k - (slope_mask_k >> 1 ));
61
63
int32_t slope_k = (int32_t )(slope_field_k ^ slope_sign_k ) - (int32_t )slope_sign_k ;
62
-
64
+ uint32_t offset_k =
65
+ (xosc32ktrim & FICR_XOSC32KTRIM_OFFSET_Msk ) >> FICR_XOSC32KTRIM_OFFSET_Pos ;
63
66
/* As specified in the nRF54L15 PS:
64
67
* CAPVALUE = round( (2*CAPACITANCE - 12) * (FICR->XOSC32KTRIM.SLOPE + 0.765625 * 2^9)/(2^9)
65
68
* + FICR->XOSC32KTRIM.OFFSET/(2^6) );
66
69
* where CAPACITANCE is the desired capacitor value in pF, holding any
67
70
* value between 4 pF and 18 pF in 0.5 pF steps.
68
71
*/
69
72
70
- /* Encoding of desired capacitance (single ended) to value required for INTCAP core
71
- * calculation: (CAP_VAL - 4 pF)* 0.5
72
- * That translate to ((CAP_VAL_FEMTO_F - 4000fF) * 2UL) / 1000UL
73
- *
74
- * NOTE: The desired capacitance value is used in encoded from in INTCAP calculation formula
75
- * That is different than in case of HFXO.
76
- */
77
- uint32_t cap_val_encoded = (((DT_PROP (LFXO_NODE , load_capacitance_femtofarad ) - 4000UL )
78
- * 2UL ) / 1000UL );
73
+ uint32_t lfxo_intcap_femto_f = DT_PROP (LFXO_NODE , load_capacitance_femtofarad );
79
74
80
75
/* Calculation of INTCAP code before rounding. Min that calculations here are done on
81
76
* values multiplied by 2^9, e.g. 0.765625 * 2^9 = 392.
82
77
* offset_k should be divided by 2^6, but to add it to value shifted by 2^9 we have to
83
- * multiply it be 2^3.
78
+ * multiply it be 2^3. Capacitance value passed to the formula is in femto Farads to
79
+ * avoid floating point data type. Hence, offset_k needs to be multiplied by 1000.
84
80
*/
85
- uint32_t mid_val = (2UL * cap_val_encoded - 12UL ) * ( uint32_t )( slope_k + 392UL )
86
- + (offset_k << 3UL );
81
+ uint32_t lfxo_intcap_mid_val = (2UL * lfxo_intcap_femto_f - 12000UL )
82
+ * ( uint32_t )( slope_k + 392UL ) + (offset_k << 3UL ) * 1000UL ;
87
83
88
- /* Get integer part of the INTCAP code */
89
- uint32_t lfxo_intcap = mid_val >> 9UL ;
84
+ /* Get integer part of the INTCAP by dividing by 2^9 and convert to pico Farads. */
85
+ uint32_t lfxo_intcap = lfxo_intcap_mid_val / 512000UL ;
90
86
91
- /* Round based on fractional part */
92
- if (( mid_val & BIT_MASK ( 9 )) > ( BIT_MASK ( 9 ) / 2 ) ) {
87
+ /* Round based on fractional part. */
88
+ if (lfxo_intcap_mid_val % 512000UL >= 256000UL ) {
93
89
lfxo_intcap ++ ;
94
90
}
95
91
@@ -107,11 +103,11 @@ static inline void power_and_clock_configuration(void)
107
103
* additions and subtractions, it generates slightly less than optimal
108
104
* code.
109
105
*/
110
- uint32_t slope_field =
106
+ uint32_t slope_field_m =
111
107
(xosc32mtrim & FICR_XOSC32MTRIM_SLOPE_Msk ) >> FICR_XOSC32MTRIM_SLOPE_Pos ;
112
- uint32_t slope_mask = FICR_XOSC32MTRIM_SLOPE_Msk >> FICR_XOSC32MTRIM_SLOPE_Pos ;
113
- uint32_t slope_sign = (slope_mask - (slope_mask >> 1 ));
114
- int32_t slope_m = (int32_t )(slope_field ^ slope_sign ) - (int32_t )slope_sign ;
108
+ uint32_t slope_mask_m = FICR_XOSC32MTRIM_SLOPE_Msk >> FICR_XOSC32MTRIM_SLOPE_Pos ;
109
+ uint32_t slope_sign_m = (slope_mask_m - (slope_mask_m >> 1 ));
110
+ int32_t slope_m = (int32_t )(slope_field_m ^ slope_sign_m ) - (int32_t )slope_sign_m ;
115
111
uint32_t offset_m =
116
112
(xosc32mtrim & FICR_XOSC32MTRIM_OFFSET_Msk ) >> FICR_XOSC32MTRIM_OFFSET_Pos ;
117
113
/* As specified in the nRF54L15 PS:
@@ -121,22 +117,19 @@ static inline void power_and_clock_configuration(void)
121
117
* holding any value between 4.0 pF and 17.0 pF in 0.25 pF steps.
122
118
*/
123
119
124
- /* NOTE 1: Requested HFXO internal capacitance in femto Faradas is used directly in formula
125
- * to calculate INTCAP code. That is different than in case of LFXO.
126
- *
127
- * NOTE 2: PS formula uses piko Farads, the implementation of the formula uses femto Farads
128
- * to avoid use of floating point data type.
129
- */
130
- uint32_t cap_val_femto_f = DT_PROP (HFXO_NODE , load_capacitance_femtofarad );
120
+ uint32_t hfxo_intcap_femto_f = DT_PROP (HFXO_NODE , load_capacitance_femtofarad );
131
121
132
- uint32_t mid_val_intcap = (((cap_val_femto_f - 5500UL ) * (uint32_t )(slope_m + 791UL ))
133
- + (offset_m << 2UL ) * 1000UL ) >> 8UL ;
122
+ /* Capacitance value passed to the formula is in femto Farads to
123
+ * avoid floating point data type. Hence, offset_m needs to be multiplied by 1000.
124
+ */
125
+ uint32_t hfxo_intcap_mid_val = (((hfxo_intcap_femto_f - 5500UL )
126
+ * (uint32_t )(slope_m + 791UL )) + (offset_m << 2UL ) * 1000UL ) >> 8UL ;
134
127
135
- /* Convert the calculated value to piko Farads */
136
- uint32_t hfxo_intcap = mid_val_intcap / 1000 ;
128
+ /* Convert the calculated value to piko Farads. */
129
+ uint32_t hfxo_intcap = hfxo_intcap_mid_val / 1000 ;
137
130
138
- /* Round based on fractional part */
139
- if (mid_val_intcap % 1000 >= 500 ) {
131
+ /* Round based on fractional part. */
132
+ if (hfxo_intcap_mid_val % 1000 >= 500 ) {
140
133
hfxo_intcap ++ ;
141
134
}
142
135
0 commit comments