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_rev2.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 	clock_name_t root;
17 	uint32_t root_rate;
18 	FLEXSPI_Type *flexspi;
19 	clock_root_t flexspi_clk;
20 	clock_ip_name_t clk_gate;
21 	uint32_t divider;
22 
23 	switch (clock_name) {
24 	case IMX_CCM_FLEXSPI_CLK:
25 		flexspi_clk = kCLOCK_Root_Flexspi1;
26 		flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi));
27 		clk_gate = kCLOCK_Flexspi1;
28 		break;
29 	case IMX_CCM_FLEXSPI2_CLK:
30 		flexspi_clk = kCLOCK_Root_Flexspi2;
31 		flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi2));
32 		clk_gate = kCLOCK_Flexspi2;
33 		break;
34 	default:
35 		return -ENOTSUP;
36 	}
37 	root = CLOCK_GetRootClockSource(flexspi_clk,
38 			CLOCK_GetRootClockMux(flexspi_clk));
39 	/* Get clock root frequency */
40 	root_rate = CLOCK_GetFreq(root);
41 	/* Select a divider based on root clock frequency. We round the
42 	 * divider up, so that the resulting clock frequency is lower than
43 	 * requested when we can't output the exact requested frequency
44 	 */
45 	divider = ((root_rate + (rate - 1)) / rate);
46 	/* Cap divider to max value */
47 	divider = MIN(divider, CCM_CLOCK_ROOT_CONTROL_DIV_MASK);
48 
49 	while (FLEXSPI_GetBusIdleStatus(flexspi) == false) {
50 		/* Spin */
51 	}
52 	FLEXSPI_Enable(flexspi, false);
53 
54 	CLOCK_DisableClock(clk_gate);
55 
56 	CLOCK_SetRootClockDiv(flexspi_clk, divider);
57 
58 	CLOCK_EnableClock(clk_gate);
59 
60 	FLEXSPI_Enable(flexspi, true);
61 
62 	FLEXSPI_SoftwareReset(flexspi);
63 
64 	return 0;
65 }
66