1 /***************************************************************************//**
2 * \file cyhal_utils_psoc.c
3 *
4 * \brief
5 * Provides utility functions for working with the CAT1/CAT2 HAL implementation.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2021 Cypress Semiconductor Corporation (an Infineon company) or
10 * an affiliate of Cypress Semiconductor Corporation
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 *
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 *******************************************************************************/
26
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include "cyhal_utils.h"
30 #include "cyhal_utils_psoc.h"
31 #include "cyhal_hwmgr.h"
32 #include "cyhal_interconnect.h"
33 #include "cyhal_clock.h"
34
35 #if defined(__cplusplus)
36 extern "C"
37 {
38 #endif
39
40 #if !defined(SRSS_NUM_PLL)
41 #define SRSS_NUM_PLL (SRSS_NUM_PLL200M + SRSS_NUM_PLL400M)
42 #endif
43
44 #if defined(COMPONENT_CAT1B)
45 #define _CYHAL_MXSPERI_PCLK_DIV_CNT(gr) \
46 case CYHAL_CLOCK_BLOCK_PERIPHERAL##gr##_8BIT: return PERI_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_8_VECT; \
47 case CYHAL_CLOCK_BLOCK_PERIPHERAL##gr##_16BIT: return PERI_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_16_VECT; \
48 case CYHAL_CLOCK_BLOCK_PERIPHERAL##gr##_16_5BIT: return PERI_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_16_5_VECT; \
49 case CYHAL_CLOCK_BLOCK_PERIPHERAL##gr##_24_5BIT: return PERI_PERI_PCLK_PCLK_GROUP_NR##gr##_GR_DIV_24_5_VECT;
50 #endif
51
_cyhal_utils_reserve_and_connect(const cyhal_resource_pin_mapping_t * mapping,uint8_t drive_mode)52 cy_rslt_t _cyhal_utils_reserve_and_connect(const cyhal_resource_pin_mapping_t *mapping, uint8_t drive_mode)
53 {
54 cyhal_resource_inst_t pinRsc = _cyhal_utils_get_gpio_resource(mapping->pin);
55 cy_rslt_t status = cyhal_hwmgr_reserve(&pinRsc);
56 if (CY_RSLT_SUCCESS == status)
57 {
58 status = cyhal_connect_pin(mapping, drive_mode);
59 if (CY_RSLT_SUCCESS != status)
60 {
61 cyhal_hwmgr_free(&pinRsc);
62 }
63 }
64 return status;
65 }
66
_cyhal_utils_disconnect_and_free(cyhal_gpio_t pin)67 void _cyhal_utils_disconnect_and_free(cyhal_gpio_t pin)
68 {
69 cy_rslt_t rslt = cyhal_disconnect_pin(pin);
70 CY_UNUSED_PARAMETER(rslt); /* CY_ASSERT only processes in DEBUG, ignores for others */
71 CY_ASSERT(CY_RSLT_SUCCESS == rslt);
72 cyhal_resource_inst_t rsc = _cyhal_utils_get_gpio_resource(pin);
73 cyhal_hwmgr_free(&rsc);
74 }
75
_cyhal_utils_convert_haltopdl_pm_mode(cyhal_syspm_callback_mode_t mode)76 cy_en_syspm_callback_mode_t _cyhal_utils_convert_haltopdl_pm_mode(cyhal_syspm_callback_mode_t mode)
77 {
78 switch (mode)
79 {
80 case CYHAL_SYSPM_CHECK_READY:
81 return CY_SYSPM_CHECK_READY;
82 case CYHAL_SYSPM_CHECK_FAIL:
83 return CY_SYSPM_CHECK_FAIL;
84 case CYHAL_SYSPM_BEFORE_TRANSITION:
85 return CY_SYSPM_BEFORE_TRANSITION;
86 case CYHAL_SYSPM_AFTER_TRANSITION:
87 return CY_SYSPM_AFTER_TRANSITION;
88 default:
89 /* Should not get here */
90 CY_ASSERT(false);
91 return CY_SYSPM_CHECK_READY;
92 }
93 }
94
_cyhal_utils_convert_pdltohal_pm_mode(cy_en_syspm_callback_mode_t mode)95 cyhal_syspm_callback_mode_t _cyhal_utils_convert_pdltohal_pm_mode(cy_en_syspm_callback_mode_t mode)
96 {
97 switch (mode)
98 {
99 case CY_SYSPM_CHECK_READY:
100 return CYHAL_SYSPM_CHECK_READY;
101 case CY_SYSPM_CHECK_FAIL:
102 return CYHAL_SYSPM_CHECK_FAIL;
103 case CY_SYSPM_BEFORE_TRANSITION:
104 return CYHAL_SYSPM_BEFORE_TRANSITION;
105 case CY_SYSPM_AFTER_TRANSITION:
106 return CYHAL_SYSPM_AFTER_TRANSITION;
107 default:
108 /* Should not get here */
109 CY_ASSERT(false);
110 return CYHAL_SYSPM_CHECK_READY;
111 }
112 }
113
_cyhal_utils_calculate_tolerance(cyhal_clock_tolerance_unit_t type,uint32_t desired_hz,uint32_t actual_hz)114 int32_t _cyhal_utils_calculate_tolerance(cyhal_clock_tolerance_unit_t type, uint32_t desired_hz, uint32_t actual_hz)
115 {
116 switch (type)
117 {
118 case CYHAL_TOLERANCE_HZ:
119 return (int32_t)(desired_hz - actual_hz);
120 case CYHAL_TOLERANCE_PPM:
121 return (int32_t)(((int64_t)(desired_hz - actual_hz)) * 1000000) / ((int32_t)desired_hz);
122 case CYHAL_TOLERANCE_PERCENT:
123 return (int32_t)((((int64_t)desired_hz - actual_hz) * 100) / desired_hz);
124 default:
125 CY_ASSERT(false);
126 return 0;
127 }
128 }
129
_cyhal_utils_allocate_peri(cyhal_clock_t * clock,uint8_t peri_group,cyhal_clock_block_t div,bool accept_larger)130 static inline cy_rslt_t _cyhal_utils_allocate_peri(cyhal_clock_t *clock, uint8_t peri_group, cyhal_clock_block_t div, bool accept_larger)
131 {
132 static const cyhal_clock_block_t PERI_DIVIDERS[] =
133 {
134 CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT,
135 CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT,
136 CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT,
137 CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT
138 };
139
140 cy_rslt_t result = CYHAL_HWMGR_RSLT_ERR_NONE_FREE;
141 bool found_minimum = false;
142 #if defined(COMPONENT_CAT1B)
143 bool dividers_exist = false;
144 #endif
145 for(size_t i = 0; i < sizeof(PERI_DIVIDERS) / sizeof(PERI_DIVIDERS[0]); ++i)
146 {
147 if(PERI_DIVIDERS[i] == div)
148 {
149 found_minimum = true;
150 }
151
152 if(found_minimum)
153 {
154 #if defined(COMPONENT_CAT1A)
155 CY_UNUSED_PARAMETER(peri_group);
156 result = _cyhal_clock_allocate_peri(clock, PERI_DIVIDERS[i]);
157 #elif defined(COMPONENT_CAT1B)
158 cyhal_clock_block_t adjusted_div = (cyhal_clock_block_t)_CYHAL_PERIPHERAL_GROUP_ADJUST(peri_group, PERI_DIVIDERS[i]);
159 dividers_exist |= (_cyhal_utils_get_clock_count(adjusted_div) > 0);
160 result = _cyhal_clock_allocate_peri(clock, adjusted_div);
161 #elif defined(COMPONENT_CAT2)
162 CY_UNUSED_PARAMETER(peri_group);
163 result = cyhal_clock_allocate(clock, PERI_DIVIDERS[i]);
164 #endif
165
166 if(CY_RSLT_SUCCESS == result || !accept_larger)
167 {
168 break;
169 }
170 }
171 }
172
173 #if defined(COMPONENT_CAT1B)
174 // If no dividers exist, try to reserve the hfclk that drives the peri group
175 if(CY_RSLT_SUCCESS != result && false == dividers_exist)
176 {
177 uint8_t hfclk_idx = _cyhal_utils_get_hfclk_for_peri_group(peri_group);
178 result = cyhal_clock_reserve(clock, &CYHAL_CLOCK_HF[hfclk_idx]);
179 }
180 #endif
181 return result;
182 }
183
184 #if defined(COMPONENT_CAT1B)
_cyhal_utils_get_hfclk_for_peri_group(uint8_t peri_group)185 uint8_t _cyhal_utils_get_hfclk_for_peri_group(uint8_t peri_group)
186 {
187 switch (peri_group)
188 {
189 /* Peripheral groups are device specific. */
190 #if defined(CY_DEVICE_CYW20829)
191 case 0:
192 case 2:
193 return 0;
194 case 1:
195 case 3:
196 case 6:
197 return 1;
198 case 4:
199 return 2;
200 case 5:
201 return 3;
202 #else
203 #warning "Unsupported device"
204 #endif /* defined(CY_DEVICE_CYW20829) */
205 default:
206 CY_ASSERT(false); /* Use APIs provided by the clock driver */
207 break;
208 }
209 return 0;
210 }
_cyhal_utils_get_peri_group(const cyhal_resource_inst_t * clocked_item)211 uint8_t _cyhal_utils_get_peri_group(const cyhal_resource_inst_t *clocked_item)
212 {
213 switch (clocked_item->type)
214 {
215 /* Peripheral groups are device specific. */
216 #if defined(CY_DEVICE_CYW20829)
217 case CYHAL_RSC_CAN:
218 case CYHAL_RSC_LIN:
219 case CYHAL_RSC_SCB:
220 case CYHAL_RSC_TCPWM:
221 return 1;
222 case CYHAL_RSC_SMIF:
223 case CYHAL_RSC_CRYPTO:
224 return 2;
225 case CYHAL_RSC_I2S:
226 case CYHAL_RSC_TDM:
227 case CYHAL_RSC_PDM:
228 return 3;
229 case CYHAL_RSC_BLESS:
230 return 4;
231 case CYHAL_RSC_ADCMIC:
232 return 5;
233 #else
234 #warning "Unsupported device"
235 #endif
236 default:
237 CY_ASSERT(false); /* Use APIs provided by the clock driver */
238 break;
239 }
240 return 0;
241 }
242 #endif
243
_cyhal_utils_get_clock_count(cyhal_clock_block_t block)244 uint32_t _cyhal_utils_get_clock_count(cyhal_clock_block_t block)
245 {
246 //NOTE: This could potentially reuse the cyhal_hwmgr.c cyhal_block_offsets_clock array
247 switch (block)
248 {
249 #if defined(COMPONENT_CAT1)
250 #if defined(COMPONENT_CAT1A)
251 case CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT:
252 return PERI_DIV_8_NR;
253 case CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT:
254 return PERI_DIV_16_NR;
255 case CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT:
256 return PERI_DIV_16_5_NR;
257 case CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT:
258 return PERI_DIV_24_5_NR;
259 case CYHAL_CLOCK_BLOCK_PLL:
260 return SRSS_NUM_PLL;
261 #elif defined(COMPONENT_CAT1B)
262 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 0)
263 _CYHAL_MXSPERI_PCLK_DIV_CNT(0);
264 #endif
265 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 1)
266 _CYHAL_MXSPERI_PCLK_DIV_CNT(1);
267 #endif
268 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 2)
269 _CYHAL_MXSPERI_PCLK_DIV_CNT(2);
270 #endif
271 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 3)
272 _CYHAL_MXSPERI_PCLK_DIV_CNT(3);
273 #endif
274 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 4)
275 _CYHAL_MXSPERI_PCLK_DIV_CNT(4);
276 #endif
277 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 5)
278 _CYHAL_MXSPERI_PCLK_DIV_CNT(5);
279 #endif
280 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 6)
281 _CYHAL_MXSPERI_PCLK_DIV_CNT(6);
282 #endif
283 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 7)
284 _CYHAL_MXSPERI_PCLK_DIV_CNT(7);
285 #endif
286 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 8)
287 _CYHAL_MXSPERI_PCLK_DIV_CNT(8);
288 #endif
289 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 9)
290 _CYHAL_MXSPERI_PCLK_DIV_CNT(9);
291 #endif
292 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 10)
293 _CYHAL_MXSPERI_PCLK_DIV_CNT(10);
294 #endif
295 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 11)
296 _CYHAL_MXSPERI_PCLK_DIV_CNT(11);
297 #endif
298 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 12)
299 _CYHAL_MXSPERI_PCLK_DIV_CNT(12);
300 #endif
301 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 13)
302 _CYHAL_MXSPERI_PCLK_DIV_CNT(13);
303 #endif
304 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 14)
305 _CYHAL_MXSPERI_PCLK_DIV_CNT(14);
306 #endif
307 #if (PERI_PERI_PCLK_PCLK_GROUP_NR > 15)
308 _CYHAL_MXSPERI_PCLK_DIV_CNT(15);
309 #endif
310 case CYHAL_CLOCK_BLOCK_PERI:
311 return PERI_PCLK_GROUP_NR;
312 case CYHAL_CLOCK_BLOCK_PLL200:
313 return SRSS_NUM_PLL200M;
314 case CYHAL_CLOCK_BLOCK_PLL400:
315 return SRSS_NUM_PLL400M;
316 #endif /* defined(COMPONENT_CAT1B) */
317 case CYHAL_CLOCK_BLOCK_PATHMUX:
318 return SRSS_NUM_CLKPATH;
319 case CYHAL_CLOCK_BLOCK_HF:
320 return SRSS_NUM_HFROOT;
321 #elif defined(COMPONENT_CAT2) /* defined(COMPONENT_CAT1) */
322 case CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT:
323 return PERI_PCLK_DIV_8_NR;
324 case CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT:
325 return PERI_PCLK_DIV_16_NR;
326 case CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT:
327 return PERI_PCLK_DIV_16_5_NR;
328 case CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT:
329 return PERI_PCLK_DIV_24_5_NR;
330 #endif /* defined(COMPONENT_CAT2) */
331 default:
332 return 1;
333 }
334 }
335
336 #if defined(COMPONENT_CAT1A)
_cyhal_utils_allocate_clock(cyhal_clock_t * clock,const cyhal_resource_inst_t * clocked_item,cyhal_clock_block_t div,bool accept_larger)337 cy_rslt_t _cyhal_utils_allocate_clock(cyhal_clock_t *clock, const cyhal_resource_inst_t *clocked_item, cyhal_clock_block_t div, bool accept_larger)
338 {
339 CY_ASSERT(NULL != clocked_item);
340
341 cyhal_clock_t clock_rsc;
342 switch (clocked_item->type)
343 {
344 /* High frequency clock assignments are device specific. */
345 #if defined(CY_DEVICE_PSOC6ABLE2) || defined(CY_DEVICE_PSOC6A2M)
346 case CYHAL_RSC_I2S:
347 case CYHAL_RSC_PDM:
348 clock_rsc = CYHAL_CLOCK_HF[1];
349 break;
350 #endif
351 #if defined(CY_DEVICE_PSOC6ABLE2) || defined(CY_DEVICE_PSOC6A2M) || defined(CY_DEVICE_PSOC6A512K) || defined(CY_DEVICE_PSOC6A256K)
352 case CYHAL_RSC_SMIF:
353 clock_rsc = CYHAL_CLOCK_HF[2];
354 break;
355 case CYHAL_RSC_USB:
356 clock_rsc = CYHAL_CLOCK_HF[3];
357 break;
358 #endif
359 #if defined(CY_DEVICE_PSOC6A2M)
360 case CYHAL_RSC_SDHC:
361 clock_rsc = (clocked_item->block_num == 0)
362 ? CYHAL_CLOCK_HF[4]
363 : CYHAL_CLOCK_HF[2];
364 break;
365 #elif defined(CY_DEVICE_PSOC6A512K)
366 case CYHAL_RSC_SDHC:
367 clock_rsc = CYHAL_CLOCK_HF[4];
368 break;
369 #endif
370 case CYHAL_RSC_CLOCK:
371 CY_ASSERT(false); /* Use APIs provided by the clock driver */
372 return CYHAL_CLOCK_RSLT_ERR_NOT_SUPPORTED;
373 default:
374 return _cyhal_utils_allocate_peri(clock, 0, div, accept_larger);
375 }
376 return cyhal_clock_reserve(clock, &clock_rsc);
377 }
378 #elif defined(COMPONENT_CAT1B)
_cyhal_utils_allocate_clock(cyhal_clock_t * clock,const cyhal_resource_inst_t * clocked_item,cyhal_clock_block_t div,bool accept_larger)379 cy_rslt_t _cyhal_utils_allocate_clock(cyhal_clock_t *clock, const cyhal_resource_inst_t *clocked_item, cyhal_clock_block_t div, bool accept_larger)
380 {
381 CY_ASSERT(NULL != clocked_item);
382 uint8_t peri_group = _cyhal_utils_get_peri_group(clocked_item);
383 return _cyhal_utils_allocate_peri(clock, peri_group, div, accept_larger);
384 }
385 #elif defined(COMPONENT_CAT2)
_cyhal_utils_allocate_clock(cyhal_clock_t * clock,const cyhal_resource_inst_t * clocked_item,cyhal_clock_block_t div,bool accept_larger)386 cy_rslt_t _cyhal_utils_allocate_clock(cyhal_clock_t *clock, const cyhal_resource_inst_t *clocked_item, cyhal_clock_block_t div, bool accept_larger)
387 {
388 CY_ASSERT(NULL != clocked_item);
389 CY_UNUSED_PARAMETER(clocked_item);
390 return _cyhal_utils_allocate_peri(clock, 0, div, accept_larger);
391 }
392 #endif
393
_cyhal_utils_set_clock_frequency(cyhal_clock_t * clock,uint32_t hz,const cyhal_clock_tolerance_t * tolerance)394 cy_rslt_t _cyhal_utils_set_clock_frequency(cyhal_clock_t* clock, uint32_t hz, const cyhal_clock_tolerance_t *tolerance)
395 {
396 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
397 if(clock->block == CYHAL_CLOCK_BLOCK_HF)
398 {
399 uint32_t divider;
400 cy_en_clkhf_in_sources_t source = Cy_SysClk_ClkHfGetSource(clock->channel);
401 uint32_t source_hz = Cy_SysClk_ClkPathGetFrequency((uint32_t)source);
402 if (CY_RSLT_SUCCESS == _cyhal_utils_find_hf_clk_div(source_hz, hz, tolerance, false, ÷r))
403 {
404 return cyhal_clock_set_divider(clock, divider);
405 }
406 return CYHAL_CLOCK_RSLT_ERR_FREQ;
407 }
408 else
409 {
410 #endif
411 // Defer to the clock driver
412 return cyhal_clock_set_frequency(clock, hz, tolerance);
413 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
414 }
415 #endif
416 }
417
418 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
_cyhal_utils_find_hf_clk_div(uint32_t hz_src,uint32_t desired_hz,const cyhal_clock_tolerance_t * tolerance,bool only_below_desired,uint32_t * div)419 cy_rslt_t _cyhal_utils_find_hf_clk_div(uint32_t hz_src, uint32_t desired_hz, const cyhal_clock_tolerance_t *tolerance,
420 bool only_below_desired, uint32_t *div)
421 {
422 const uint8_t HFCLK_DIVIDERS[] = { 1, 2, 4, 8};
423 cy_rslt_t retval = CYHAL_CLOCK_RSLT_ERR_FREQ;
424 uint32_t tolerance_check_value = (NULL != tolerance) ? tolerance->value : 0xFFFFFFFFU;
425 cyhal_clock_tolerance_unit_t tolerance_type = (NULL != tolerance) ? tolerance->type : CYHAL_TOLERANCE_HZ;
426
427 for(uint8_t i = 0; i < sizeof(HFCLK_DIVIDERS) / sizeof(HFCLK_DIVIDERS[0]); ++i)
428 {
429 const uint32_t divider = HFCLK_DIVIDERS[i];
430 uint32_t actual_freq = hz_src / divider;
431 if ((actual_freq > desired_hz) && only_below_desired)
432 continue;
433 uint32_t achieved_tolerance = abs(_cyhal_utils_calculate_tolerance(tolerance_type, desired_hz, actual_freq));
434 if (achieved_tolerance < tolerance_check_value)
435 {
436 *div = divider;
437 retval = CY_RSLT_SUCCESS;
438 if ((NULL != tolerance) || (achieved_tolerance == 0))
439 break;
440 tolerance_check_value = achieved_tolerance;
441 }
442 else if (only_below_desired)
443 {
444 /* We are going from smallest divider, to highest. If we've not achieved better tolerance in
445 * this iteration, we will no achieve it in futher for sure. */
446 break;
447 }
448 }
449 return retval;
450 }
451
_cyhal_utils_find_hf_source_n_divider(cyhal_clock_t * clock,uint32_t hz,const cyhal_clock_tolerance_t * tolerance,_cyhal_utils_clk_div_func_t div_find_func,cyhal_clock_t * hf_source,uint32_t * div)452 cy_rslt_t _cyhal_utils_find_hf_source_n_divider(cyhal_clock_t *clock, uint32_t hz, const cyhal_clock_tolerance_t *tolerance,
453 _cyhal_utils_clk_div_func_t div_find_func, cyhal_clock_t *hf_source, uint32_t *div)
454 {
455 CY_ASSERT(NULL != clock);
456 CY_ASSERT(hz != 0);
457
458 uint32_t count;
459 const cyhal_resource_inst_t ** sources;
460 cy_rslt_t retval = cyhal_clock_get_sources(clock, &sources, &count);
461 if (CY_RSLT_SUCCESS != retval)
462 return retval;
463
464 uint32_t best_tolerance_hz = 0xFFFFFFFFU;
465 cyhal_clock_t best_clock;
466 uint32_t best_clock_freq = 0;
467 uint32_t best_divider = 1;
468 /* Go through all possible HFCLK clock sources and check what source fits best */
469 for (uint32_t i = 0; i < count; ++i)
470 {
471 cyhal_clock_t temp_clock;
472 if (CY_RSLT_SUCCESS == cyhal_clock_get(&temp_clock, sources[i]))
473 {
474 uint32_t cur_hf_source_freq = cyhal_clock_get_frequency(&temp_clock);
475 /* source frequency is much lower than desired, no reason to continue */
476 if ((0 == cur_hf_source_freq) ||
477 ((NULL != tolerance) && (_cyhal_utils_calculate_tolerance(tolerance->type, hz, cur_hf_source_freq) > (int32_t)tolerance->value)))
478 {
479 continue;
480 }
481 /* Covering situation when PATHMUX has enabled FLL / PLL on its way. In that case FLL / PLL frequency
482 is observed on PATHMUX which is covered in other iterations of the sources loop */
483 if (CYHAL_CLOCK_BLOCK_PATHMUX == temp_clock.block)
484 {
485 if (((sources[i]->channel_num == 0) && Cy_SysClk_FllIsEnabled()) ||
486 ((sources[i]->channel_num > 0) && (sources[i]->channel_num <= SRSS_NUM_PLL) &&
487 Cy_SysClk_PllIsEnabled(sources[i]->channel_num)))
488 {
489 continue;
490 }
491 }
492
493 uint32_t cur_clock_divider;
494 if (CY_RSLT_SUCCESS == div_find_func(cur_hf_source_freq, hz, NULL, true, &cur_clock_divider))
495 {
496 uint32_t cur_divided_freq = cur_hf_source_freq / cur_clock_divider;
497 uint32_t cur_clock_tolerance = abs(_cyhal_utils_calculate_tolerance(CYHAL_TOLERANCE_HZ, hz, cur_divided_freq));
498 if (cur_clock_tolerance < best_tolerance_hz)
499 {
500 best_clock = temp_clock;
501 best_tolerance_hz = cur_clock_tolerance;
502 best_clock_freq = cur_divided_freq;
503 best_divider = cur_clock_divider;
504 if (cur_divided_freq == hz)
505 break;
506 }
507 }
508 }
509 }
510
511 if (0 == best_clock_freq)
512 {
513 retval = CYHAL_CLOCK_RSLT_ERR_SOURCE;
514 }
515 else if (NULL != tolerance) /* Verify within tolerance if one was provided. */
516 {
517 uint32_t achieved_tolerance = abs(_cyhal_utils_calculate_tolerance(tolerance->type, hz, best_clock_freq));
518 if (achieved_tolerance > tolerance->value)
519 retval = CYHAL_CLOCK_RSLT_ERR_FREQ;
520 }
521
522 if (CY_RSLT_SUCCESS == retval)
523 {
524 *hf_source = best_clock;
525 *div = best_divider;
526 }
527
528 return retval;
529 }
530
_cyhal_utils_set_clock_frequency2(cyhal_clock_t * clock,uint32_t hz,const cyhal_clock_tolerance_t * tolerance)531 cy_rslt_t _cyhal_utils_set_clock_frequency2(cyhal_clock_t *clock, uint32_t hz, const cyhal_clock_tolerance_t *tolerance)
532 {
533 CY_ASSERT(NULL != clock);
534 CY_ASSERT(hz != 0);
535
536 cyhal_clock_t hf_source;
537 uint32_t divider = 0;
538 cy_rslt_t retval = _cyhal_utils_find_hf_source_n_divider(clock, hz, tolerance, _cyhal_utils_find_hf_clk_div,
539 &hf_source, ÷r);
540 if (CY_RSLT_SUCCESS == retval)
541 {
542 retval = cyhal_clock_set_source(clock, &hf_source);
543 }
544 if (CY_RSLT_SUCCESS == retval)
545 {
546 retval = cyhal_clock_set_divider(clock, divider);
547 }
548
549 return retval;
550 }
551 #endif
552
553 #if defined(__cplusplus)
554 }
555 #endif
556