1 /*
2  * Copyright (c) 2023, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <fsl_clock.h>
8 #include <fsl_flexspi.h>
9 #include <soc.h>
10 #include <errno.h>
11 #include <zephyr/irq.h>
12 #include <zephyr/dt-bindings/clock/imx_ccm.h>
13 
flexspi_clock_set_freq(uint32_t clock_name,uint32_t rate)14 uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate)
15 {
16 	uint8_t divider;
17 	uint32_t root_rate;
18 	FLEXSPI_Type *flexspi;
19 	clock_div_t div_sel;
20 	clock_ip_name_t clk_name;
21 
22 	switch (clock_name) {
23 	case IMX_CCM_FLEXSPI_CLK:
24 		/* Get clock root frequency */
25 		root_rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot) *
26 					(CLOCK_GetDiv(kCLOCK_FlexspiDiv) + 1);
27 		flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi));
28 		div_sel = kCLOCK_FlexspiDiv;
29 		clk_name = kCLOCK_FlexSpi;
30 		break;
31 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexspi2))
32 	case IMX_CCM_FLEXSPI2_CLK:
33 		/* Get clock root frequency */
34 		root_rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot) *
35 					(CLOCK_GetDiv(kCLOCK_Flexspi2Div) + 1);
36 		flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi2));
37 		div_sel = kCLOCK_Flexspi2Div;
38 		clk_name = kCLOCK_FlexSpi2;
39 		break;
40 #endif
41 	default:
42 		return -ENOTSUP;
43 	}
44 	/* Select a divider based on root frequency.
45 	 * if we can't get an exact divider, round down
46 	 */
47 	divider = ((root_rate + (rate - 1)) / rate) - 1;
48 	/* Cap divider to max value */
49 	divider = MIN(divider, kCLOCK_FlexspiDivBy8);
50 
51 	while (FLEXSPI_GetBusIdleStatus(flexspi) == false) {
52 		/* Spin */
53 	}
54 	FLEXSPI_Enable(flexspi, false);
55 
56 	CLOCK_DisableClock(clk_name);
57 
58 	CLOCK_SetDiv(div_sel, divider);
59 
60 	CLOCK_EnableClock(clk_name);
61 
62 	FLEXSPI_Enable(flexspi, true);
63 
64 	FLEXSPI_SoftwareReset(flexspi);
65 
66 	return 0;
67 }
68