@@ -22,6 +22,8 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
2222#define LFCLK_LFLPRC_ACCURACY DT_INST_PROP(0, lflprc_accuracy_ppm)
2323#define LFCLK_LFRC_ACCURACY DT_INST_PROP(0, lfrc_accuracy_ppm)
2424#define LFCLK_HFXO_ACCURACY DT_PROP(LFCLK_HFXO_NODE, accuracy_ppm)
25+ #define LFCLK_LFLPRC_STARTUP_TIME_US DT_INST_PROP(0, lflprc_startup_time_us)
26+ #define LFCLK_LFRC_STARTUP_TIME_US DT_INST_PROP(0, lfrc_startup_time_us)
2527
2628#define LFCLK_MAX_OPTS 5
2729#define LFCLK_DEF_OPTS 3
@@ -59,6 +61,8 @@ struct lfclk_dev_data {
5961 struct k_timer timer ;
6062 uint16_t max_accuracy ;
6163 uint8_t clock_options_cnt ;
64+ uint32_t hfxo_startup_time_us ;
65+ uint32_t lfxo_startup_time_us ;
6266};
6367
6468struct lfclk_dev_config {
@@ -105,45 +109,108 @@ static void lfclk_work_handler(struct k_work *work)
105109 }
106110}
107111
108- static struct onoff_manager * lfclk_find_mgr (const struct device * dev ,
109- const struct nrf_clock_spec * spec )
112+ static int lfclk_resolve_spec_to_idx (const struct device * dev ,
113+ const struct nrf_clock_spec * req_spec )
110114{
111115 struct lfclk_dev_data * dev_data = dev -> data ;
112116 const struct lfclk_dev_config * dev_config = dev -> config ;
113- uint16_t accuracy ;
117+ uint16_t req_accuracy ;
114118
115- if (!spec ) {
116- return & dev_data -> clk_cfg .onoff [0 ].mgr ;
117- }
118-
119- if (spec -> frequency > dev_config -> fixed_frequency ) {
119+ if (req_spec -> frequency > dev_config -> fixed_frequency ) {
120120 LOG_ERR ("invalid frequency" );
121- return NULL ;
121+ return - EINVAL ;
122122 }
123123
124- accuracy = spec -> accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX
125- ? dev_data -> max_accuracy
126- : spec -> accuracy ;
124+ req_accuracy = req_spec -> accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX
125+ ? dev_data -> max_accuracy
126+ : req_spec -> accuracy ;
127127
128128 for (int i = 0 ; i < dev_data -> clock_options_cnt ; ++ i ) {
129- if ((accuracy &&
130- accuracy < clock_options [i ].accuracy ) ||
131- spec -> precision > clock_options [i ].precision ) {
129+ if ((req_accuracy &&
130+ req_accuracy < clock_options [i ].accuracy ) ||
131+ req_spec -> precision > clock_options [i ].precision ) {
132132 continue ;
133133 }
134134
135- return & dev_data -> clk_cfg . onoff [ i ]. mgr ;
135+ return i ;
136136 }
137137
138138 LOG_ERR ("invalid accuracy or precision" );
139- return NULL ;
139+ return - EINVAL ;
140+ }
141+
142+ static void lfclk_get_spec_by_idx (const struct device * dev ,
143+ uint8_t idx ,
144+ struct nrf_clock_spec * spec )
145+ {
146+ const struct lfclk_dev_config * dev_config = dev -> config ;
147+
148+ spec -> frequency = dev_config -> fixed_frequency ;
149+ spec -> accuracy = clock_options [idx ].accuracy ;
150+ spec -> precision = clock_options [idx ].precision ;
151+ }
152+
153+ static struct onoff_manager * lfclk_get_mgr_by_idx (const struct device * dev , uint8_t idx )
154+ {
155+ struct lfclk_dev_data * dev_data = dev -> data ;
156+
157+ return & dev_data -> clk_cfg .onoff [idx ].mgr ;
158+ }
159+
160+ static int lfclk_get_startup_time_by_idx (const struct device * dev ,
161+ uint8_t idx ,
162+ uint32_t * startup_time_us )
163+ {
164+ struct lfclk_dev_data * dev_data = dev -> data ;
165+ nrfs_clock_src_t src = clock_options [idx ].src ;
166+
167+ switch (src ) {
168+ case NRFS_CLOCK_SRC_LFCLK_LFLPRC :
169+ * startup_time_us = LFCLK_LFLPRC_STARTUP_TIME_US ;
170+ return 0 ;
171+
172+ case NRFS_CLOCK_SRC_LFCLK_LFRC :
173+ * startup_time_us = LFCLK_LFRC_STARTUP_TIME_US ;
174+ return 0 ;
175+
176+ case NRFS_CLOCK_SRC_LFCLK_XO_PIXO :
177+ case NRFS_CLOCK_SRC_LFCLK_XO_PIERCE :
178+ case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE :
179+ case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE :
180+ case NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP :
181+ case NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP :
182+ * startup_time_us = dev_data -> lfxo_startup_time_us ;
183+ return 0 ;
184+
185+ case NRFS_CLOCK_SRC_LFCLK_SYNTH :
186+ * startup_time_us = dev_data -> hfxo_startup_time_us ;
187+ return 0 ;
188+
189+ default :
190+ break ;
191+ }
192+
193+ return - EINVAL ;
194+ }
195+
196+ static struct onoff_manager * lfclk_find_mgr_by_spec (const struct device * dev ,
197+ const struct nrf_clock_spec * spec )
198+ {
199+ int idx ;
200+
201+ if (!spec ) {
202+ return lfclk_get_mgr_by_idx (dev , 0 );
203+ }
204+
205+ idx = lfclk_resolve_spec_to_idx (dev , spec );
206+ return idx < 0 ? NULL : lfclk_get_mgr_by_idx (dev , idx );
140207}
141208
142209static int api_request_lfclk (const struct device * dev ,
143210 const struct nrf_clock_spec * spec ,
144211 struct onoff_client * cli )
145212{
146- struct onoff_manager * mgr = lfclk_find_mgr (dev , spec );
213+ struct onoff_manager * mgr = lfclk_find_mgr_by_spec (dev , spec );
147214
148215 if (mgr ) {
149216 return clock_config_request (mgr , cli );
@@ -155,7 +222,7 @@ static int api_request_lfclk(const struct device *dev,
155222static int api_release_lfclk (const struct device * dev ,
156223 const struct nrf_clock_spec * spec )
157224{
158- struct onoff_manager * mgr = lfclk_find_mgr (dev , spec );
225+ struct onoff_manager * mgr = lfclk_find_mgr_by_spec (dev , spec );
159226
160227 if (mgr ) {
161228 return onoff_release (mgr );
@@ -168,7 +235,7 @@ static int api_cancel_or_release_lfclk(const struct device *dev,
168235 const struct nrf_clock_spec * spec ,
169236 struct onoff_client * cli )
170237{
171- struct onoff_manager * mgr = lfclk_find_mgr (dev , spec );
238+ struct onoff_manager * mgr = lfclk_find_mgr_by_spec (dev , spec );
172239
173240 if (mgr ) {
174241 return onoff_cancel_or_release (mgr , cli );
@@ -177,6 +244,36 @@ static int api_cancel_or_release_lfclk(const struct device *dev,
177244 return - EINVAL ;
178245}
179246
247+
248+ static int api_resolve (const struct device * dev ,
249+ const struct nrf_clock_spec * req_spec ,
250+ struct nrf_clock_spec * res_spec )
251+ {
252+ int idx ;
253+
254+ idx = lfclk_resolve_spec_to_idx (dev , req_spec );
255+ if (idx < 0 ) {
256+ return - EINVAL ;
257+ }
258+
259+ lfclk_get_spec_by_idx (dev , idx , res_spec );
260+ return 0 ;
261+ }
262+
263+ static int api_get_startup_time (const struct device * dev ,
264+ const struct nrf_clock_spec * spec ,
265+ uint32_t * startup_time_us )
266+ {
267+ int idx ;
268+
269+ idx = lfclk_resolve_spec_to_idx (dev , spec );
270+ if (idx < 0 ) {
271+ return - EINVAL ;
272+ }
273+
274+ return lfclk_get_startup_time_by_idx (dev , idx , startup_time_us );
275+ }
276+
180277static int api_get_rate_lfclk (const struct device * dev ,
181278 clock_control_subsys_t sys ,
182279 uint32_t * rate )
@@ -251,6 +348,19 @@ static int lfclk_init(const struct device *dev)
251348 LOG_ERR ("Unexpected LFOSC mode" );
252349 return - EINVAL ;
253350 }
351+
352+ dev_data -> lfxo_startup_time_us = nrf_bicr_lfosc_startup_time_ms_get (BICR )
353+ * USEC_PER_MSEC ;
354+ if (dev_data -> lfxo_startup_time_us == NRF_BICR_LFOSC_STARTUP_TIME_UNCONFIGURED ) {
355+ LOG_ERR ("BICR LFXO startup time invalid" );
356+ return - ENODEV ;
357+ }
358+ }
359+
360+ dev_data -> hfxo_startup_time_us = nrf_bicr_hfxo_startup_time_us_get (BICR );
361+ if (dev_data -> hfxo_startup_time_us == NRF_BICR_HFXO_STARTUP_TIME_UNCONFIGURED ) {
362+ LOG_ERR ("BICR HFXO startup time invalid" );
363+ return - ENODEV ;
254364 }
255365
256366 k_timer_init (& dev_data -> timer , lfclk_update_timeout_handler , NULL );
@@ -269,6 +379,8 @@ static DEVICE_API(nrf_clock_control, lfclk_drv_api) = {
269379 .request = api_request_lfclk ,
270380 .release = api_release_lfclk ,
271381 .cancel_or_release = api_cancel_or_release_lfclk ,
382+ .resolve = api_resolve ,
383+ .get_startup_time = api_get_startup_time ,
272384};
273385
274386static struct lfclk_dev_data lfclk_data ;
0 commit comments