Fix for compiling i2s drivers on the NXP mimxrt1010_evk board. For mimxrt1011, the defines kCLOCK_Sai2... are not defined as the sai2 peripheral does not exist. Trying to compile gives error. Fixed by adding check for device tree node around code that uses the defines. Also added same for sai1 and sai3. Thanks @lucien-nxp, @ZhaoxiangJin from NXP. Signed-off-by: Imran Sajjad <imran.sajjad@iconfitness.com>
644 lines
16 KiB
C
644 lines
16 KiB
C
/*
|
|
* Copyright 2017, 2024-2025 NXP
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT nxp_imx_ccm
|
|
#include <errno.h>
|
|
#include <zephyr/arch/cpu.h>
|
|
#include <zephyr/sys/util.h>
|
|
#include <zephyr/drivers/clock_control.h>
|
|
#include <zephyr/dt-bindings/clock/imx_ccm.h>
|
|
#include <fsl_clock.h>
|
|
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
#include <main/ipc.h>
|
|
#endif
|
|
|
|
#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(clock_control);
|
|
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
#define AUD_PLL_DIV_CLK0_LPCG UINT_TO_POINTER(0x59D20000)
|
|
static sc_ipc_t ipc_handle;
|
|
#endif
|
|
|
|
#ifdef CONFIG_SPI_NXP_LPSPI
|
|
static const clock_name_t lpspi_clocks[] = {
|
|
kCLOCK_Usb1PllPfd1Clk,
|
|
kCLOCK_Usb1PllPfd0Clk,
|
|
kCLOCK_SysPllClk,
|
|
kCLOCK_SysPllPfd2Clk,
|
|
};
|
|
#endif
|
|
#ifdef CONFIG_UART_MCUX_IUART
|
|
static const clock_root_control_t uart_clk_root[] = {
|
|
kCLOCK_RootUart1,
|
|
kCLOCK_RootUart2,
|
|
kCLOCK_RootUart3,
|
|
kCLOCK_RootUart4,
|
|
};
|
|
|
|
static const clock_ip_name_t uart_clocks[] = {
|
|
kCLOCK_Uart1,
|
|
kCLOCK_Uart2,
|
|
kCLOCK_Uart3,
|
|
kCLOCK_Uart4,
|
|
};
|
|
#endif
|
|
|
|
#ifdef CONFIG_UART_MCUX_LPUART
|
|
|
|
#ifdef CONFIG_SOC_MIMX8QM6_ADSP
|
|
static const clock_ip_name_t lpuart_clocks[] = {
|
|
kCLOCK_DMA_Lpuart0,
|
|
kCLOCK_DMA_Lpuart1,
|
|
kCLOCK_DMA_Lpuart2,
|
|
kCLOCK_DMA_Lpuart3,
|
|
kCLOCK_DMA_Lpuart4,
|
|
};
|
|
|
|
static const uint32_t lpuart_rate = MHZ(80);
|
|
#endif /* CONFIG_SOC_MIMX8QM6_ADSP */
|
|
|
|
#ifdef CONFIG_SOC_MIMX8QX6_ADSP
|
|
static const clock_ip_name_t lpuart_clocks[] = {
|
|
kCLOCK_DMA_Lpuart0,
|
|
kCLOCK_DMA_Lpuart1,
|
|
kCLOCK_DMA_Lpuart2,
|
|
kCLOCK_DMA_Lpuart3,
|
|
};
|
|
|
|
static const uint32_t lpuart_rate = MHZ(80);
|
|
#endif /* CONFIG_SOC_MIMX8QX6_ADSP */
|
|
|
|
#endif /* CONFIG_UART_MCUX_LPUART */
|
|
|
|
#ifdef CONFIG_DAI_NXP_SAI
|
|
#if defined(CONFIG_SOC_MIMX8QX6_ADSP) || defined(CONFIG_SOC_MIMX8QM6_ADSP)
|
|
static const clock_ip_name_t sai_clocks[] = {
|
|
kCLOCK_AUDIO_Sai1,
|
|
kCLOCK_AUDIO_Sai2,
|
|
kCLOCK_AUDIO_Sai3,
|
|
};
|
|
#endif
|
|
#endif /* CONFIG_DAI_NXP_SAI */
|
|
|
|
#ifdef CONFIG_DAI_NXP_ESAI
|
|
#if defined(CONFIG_SOC_MIMX8QX6_ADSP) || defined(CONFIG_SOC_MIMX8QM6_ADSP)
|
|
static const clock_ip_name_t esai_clocks[] = {
|
|
kCLOCK_AUDIO_Esai0,
|
|
kCLOCK_AUDIO_Esai1,
|
|
};
|
|
#endif
|
|
#endif /* CONFIG_DAI_NXP_ESAI */
|
|
|
|
#if defined(CONFIG_I2C_NXP_II2C)
|
|
static const clock_ip_name_t i2c_clk_root[] = {
|
|
kCLOCK_RootI2c1,
|
|
kCLOCK_RootI2c2,
|
|
kCLOCK_RootI2c3,
|
|
kCLOCK_RootI2c4,
|
|
#ifdef CONFIG_SOC_MIMX8ML8
|
|
kCLOCK_RootI2c5,
|
|
kCLOCK_RootI2c6,
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
#if defined(CONFIG_CAN_MCUX_FLEXCAN) && defined(CONFIG_SOC_MIMX8ML8)
|
|
static const clock_ip_name_t flexcan_clk_root[] = {
|
|
kCLOCK_RootFlexCan1,
|
|
kCLOCK_RootFlexCan2,
|
|
};
|
|
#endif
|
|
|
|
static int mcux_ccm_on(const struct device *dev,
|
|
clock_control_subsys_t sub_system)
|
|
{
|
|
uint32_t clock_name = (uintptr_t)sub_system;
|
|
uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
|
|
|
|
switch (clock_name) {
|
|
#ifdef CONFIG_UART_MCUX_IUART
|
|
case IMX_CCM_UART1_CLK:
|
|
case IMX_CCM_UART2_CLK:
|
|
case IMX_CCM_UART3_CLK:
|
|
case IMX_CCM_UART4_CLK:
|
|
CLOCK_EnableClock(uart_clocks[instance]);
|
|
return 0;
|
|
#endif
|
|
|
|
#if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX8QM6_ADSP)
|
|
case IMX_CCM_LPUART1_CLK:
|
|
case IMX_CCM_LPUART2_CLK:
|
|
case IMX_CCM_LPUART3_CLK:
|
|
case IMX_CCM_LPUART4_CLK:
|
|
case IMX_CCM_LPUART5_CLK:
|
|
CLOCK_EnableClock(lpuart_clocks[instance]);
|
|
return 0;
|
|
#endif
|
|
|
|
#if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
case IMX_CCM_LPUART1_CLK:
|
|
case IMX_CCM_LPUART2_CLK:
|
|
case IMX_CCM_LPUART3_CLK:
|
|
case IMX_CCM_LPUART4_CLK:
|
|
CLOCK_EnableClock(lpuart_clocks[instance]);
|
|
return 0;
|
|
#endif
|
|
|
|
#ifdef CONFIG_DAI_NXP_SAI
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
case IMX_CCM_SAI1_CLK:
|
|
case IMX_CCM_SAI2_CLK:
|
|
case IMX_CCM_SAI3_CLK:
|
|
CLOCK_EnableClock(sai_clocks[instance]);
|
|
return 0;
|
|
#endif
|
|
#endif /* CONFIG_DAI_NXP_SAI */
|
|
|
|
#ifdef CONFIG_DAI_NXP_ESAI
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
case IMX_CCM_ESAI0_CLK:
|
|
case IMX_CCM_ESAI1_CLK:
|
|
CLOCK_EnableClock(esai_clocks[instance]);
|
|
return 0;
|
|
#endif
|
|
#endif /* CONFIG_DAI_NXP_ESAI */
|
|
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
case IMX_CCM_AUD_PLL_DIV_CLK0:
|
|
/* ungate PLL parent */
|
|
sc_pm_clock_enable(ipc_handle, SC_R_AUDIO_PLL_0,
|
|
SC_PM_CLK_MISC0, true, false);
|
|
|
|
/* ungate the clock itself */
|
|
CLOCK_SetLpcgGate(AUD_PLL_DIV_CLK0_LPCG, true, false, 0xa);
|
|
|
|
return 0;
|
|
#endif
|
|
|
|
#if defined(CONFIG_ETH_NXP_ENET)
|
|
#ifdef CONFIG_SOC_SERIES_IMX8M
|
|
#define ENET_CLOCK kCLOCK_Enet1
|
|
#else
|
|
#define ENET_CLOCK kCLOCK_Enet
|
|
#endif
|
|
case IMX_CCM_ENET_CLK:
|
|
CLOCK_EnableClock(ENET_CLOCK);
|
|
return 0;
|
|
#endif
|
|
default:
|
|
(void)instance;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int mcux_ccm_off(const struct device *dev,
|
|
clock_control_subsys_t sub_system)
|
|
{
|
|
uint32_t clock_name = (uintptr_t)sub_system;
|
|
uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
|
|
|
|
switch (clock_name) {
|
|
#ifdef CONFIG_UART_MCUX_IUART
|
|
case IMX_CCM_UART1_CLK:
|
|
case IMX_CCM_UART2_CLK:
|
|
case IMX_CCM_UART3_CLK:
|
|
case IMX_CCM_UART4_CLK:
|
|
CLOCK_DisableClock(uart_clocks[instance]);
|
|
return 0;
|
|
#endif
|
|
|
|
#ifdef CONFIG_DAI_NXP_SAI
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
case IMX_CCM_SAI1_CLK:
|
|
case IMX_CCM_SAI2_CLK:
|
|
case IMX_CCM_SAI3_CLK:
|
|
CLOCK_DisableClock(sai_clocks[instance]);
|
|
return 0;
|
|
#endif
|
|
#endif /* CONFIG_DAI_NXP_SAI */
|
|
|
|
#ifdef CONFIG_DAI_NXP_ESAI
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
case IMX_CCM_ESAI0_CLK:
|
|
case IMX_CCM_ESAI1_CLK:
|
|
CLOCK_DisableClock(esai_clocks[instance]);
|
|
return 0;
|
|
#endif
|
|
#endif /* CONFIG_DAI_NXP_ESAI */
|
|
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
case IMX_CCM_AUD_PLL_DIV_CLK0:
|
|
/* gate the clock itself */
|
|
CLOCK_SetLpcgGate(AUD_PLL_DIV_CLK0_LPCG, false, false, 0xa);
|
|
|
|
/* gate PLL parent */
|
|
sc_pm_clock_enable(ipc_handle, SC_R_AUDIO_PLL_0,
|
|
SC_PM_CLK_MISC0, false, false);
|
|
|
|
return 0;
|
|
#endif
|
|
default:
|
|
(void)instance;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int mcux_ccm_get_subsys_rate(const struct device *dev,
|
|
clock_control_subsys_t sub_system,
|
|
uint32_t *rate)
|
|
{
|
|
uint32_t clock_name = (uintptr_t)sub_system;
|
|
|
|
switch (clock_name) {
|
|
|
|
#ifdef CONFIG_I2C_MCUX_LPI2C
|
|
case IMX_CCM_LPI2C_CLK:
|
|
if (CLOCK_GetMux(kCLOCK_Lpi2cMux) == 0) {
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 8
|
|
/ (CLOCK_GetDiv(kCLOCK_Lpi2cDiv) + 1);
|
|
} else {
|
|
*rate = CLOCK_GetOscFreq()
|
|
/ (CLOCK_GetDiv(kCLOCK_Lpi2cDiv) + 1);
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
|
|
#ifdef CONFIG_SPI_NXP_LPSPI
|
|
case IMX_CCM_LPSPI_CLK:
|
|
{
|
|
uint32_t lpspi_mux = CLOCK_GetMux(kCLOCK_LpspiMux);
|
|
clock_name_t lpspi_clock = lpspi_clocks[lpspi_mux];
|
|
|
|
*rate = CLOCK_GetFreq(lpspi_clock)
|
|
/ (CLOCK_GetDiv(kCLOCK_LpspiDiv) + 1);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_UART_MCUX_LPUART
|
|
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP)
|
|
case IMX_CCM_LPUART1_CLK:
|
|
case IMX_CCM_LPUART2_CLK:
|
|
case IMX_CCM_LPUART3_CLK:
|
|
case IMX_CCM_LPUART4_CLK:
|
|
case IMX_CCM_LPUART5_CLK:
|
|
uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
|
|
|
|
CLOCK_SetIpFreq(lpuart_clocks[instance], lpuart_rate);
|
|
*rate = CLOCK_GetIpFreq(lpuart_clocks[instance]);
|
|
break;
|
|
|
|
#elif defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
case IMX_CCM_LPUART1_CLK:
|
|
case IMX_CCM_LPUART2_CLK:
|
|
case IMX_CCM_LPUART3_CLK:
|
|
case IMX_CCM_LPUART4_CLK:
|
|
uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
|
|
|
|
CLOCK_SetIpFreq(lpuart_clocks[instance], lpuart_rate);
|
|
*rate = CLOCK_GetIpFreq(lpuart_clocks[instance]);
|
|
break;
|
|
|
|
#else
|
|
case IMX_CCM_LPUART_CLK:
|
|
if (CLOCK_GetMux(kCLOCK_UartMux) == 0) {
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6
|
|
/ (CLOCK_GetDiv(kCLOCK_UartDiv) + 1);
|
|
} else {
|
|
*rate = CLOCK_GetOscFreq()
|
|
/ (CLOCK_GetDiv(kCLOCK_UartDiv) + 1);
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
#endif
|
|
|
|
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usdhc1)) && CONFIG_IMX_USDHC
|
|
case IMX_CCM_USDHC1_CLK:
|
|
*rate = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0) /
|
|
(CLOCK_GetDiv(kCLOCK_Usdhc1Div) + 1U);
|
|
break;
|
|
#endif
|
|
|
|
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usdhc2)) && CONFIG_IMX_USDHC
|
|
case IMX_CCM_USDHC2_CLK:
|
|
*rate = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0) /
|
|
(CLOCK_GetDiv(kCLOCK_Usdhc2Div) + 1U);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef CONFIG_DMA_MCUX_EDMA
|
|
case IMX_CCM_EDMA_CLK:
|
|
*rate = CLOCK_GetIpgFreq();
|
|
break;
|
|
#endif
|
|
|
|
#ifdef CONFIG_PWM_MCUX
|
|
case IMX_CCM_PWM_CLK:
|
|
*rate = CLOCK_GetIpgFreq();
|
|
break;
|
|
#endif
|
|
|
|
#ifdef CONFIG_ETH_NXP_ENET
|
|
case IMX_CCM_ENET_CLK:
|
|
#ifdef CONFIG_SOC_SERIES_IMX8M
|
|
*rate = CLOCK_GetFreq(kCLOCK_EnetIpgClk);
|
|
#else
|
|
*rate = CLOCK_GetIpgFreq();
|
|
#endif
|
|
#endif
|
|
break;
|
|
|
|
#ifdef CONFIG_PTP_CLOCK_NXP_ENET
|
|
case IMX_CCM_ENET_PLL:
|
|
#if defined(CONFIG_SOC_SERIES_IMXRT10XX)
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_PllEnet25M);
|
|
#else
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_PllEnet);
|
|
#endif
|
|
break;
|
|
#endif
|
|
|
|
#ifdef CONFIG_UART_MCUX_IUART
|
|
case IMX_CCM_UART1_CLK:
|
|
case IMX_CCM_UART2_CLK:
|
|
case IMX_CCM_UART3_CLK:
|
|
case IMX_CCM_UART4_CLK:
|
|
{
|
|
uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
|
|
clock_root_control_t clk_root = uart_clk_root[instance];
|
|
uint32_t uart_mux = CLOCK_GetRootMux(clk_root);
|
|
|
|
if (uart_mux == 0) {
|
|
*rate = MHZ(24);
|
|
} else if (uart_mux == 1) {
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
|
|
(CLOCK_GetRootPreDivider(clk_root)) /
|
|
(CLOCK_GetRootPostDivider(clk_root)) /
|
|
10;
|
|
}
|
|
|
|
} break;
|
|
#endif
|
|
|
|
#ifdef CONFIG_CAN_MCUX_FLEXCAN
|
|
#ifdef CONFIG_SOC_MIMX8ML8
|
|
case IMX_CCM_CAN1_CLK:
|
|
case IMX_CCM_CAN2_CLK:
|
|
{
|
|
uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
|
|
uint32_t can_mux = CLOCK_GetRootMux(flexcan_clk_root[instance]);
|
|
|
|
if (can_mux == 0) {
|
|
*rate = MHZ(24);
|
|
} else if (can_mux == 4) { /* SYSTEM_PLL1_CLK */
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
|
|
(CLOCK_GetRootPreDivider(flexcan_clk_root[instance])) /
|
|
(CLOCK_GetRootPostDivider(flexcan_clk_root[instance]));
|
|
}
|
|
} break;
|
|
#else
|
|
case IMX_CCM_CAN_CLK:
|
|
{
|
|
uint32_t can_mux = CLOCK_GetMux(kCLOCK_CanMux);
|
|
|
|
if (can_mux == 0) {
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 8
|
|
/ (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
|
|
} else if (can_mux == 1) {
|
|
*rate = CLOCK_GetOscFreq()
|
|
/ (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
|
|
} else {
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6
|
|
/ (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
|
|
}
|
|
} break;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef CONFIG_COUNTER_MCUX_GPT
|
|
case IMX_CCM_GPT_CLK:
|
|
*rate = CLOCK_GetFreq(kCLOCK_PerClk);
|
|
break;
|
|
#ifdef CONFIG_SOC_SERIES_IMX8M
|
|
case IMX_CCM_GPT_IPG_CLK:
|
|
{
|
|
uint32_t mux = CLOCK_GetRootMux(kCLOCK_RootGpt1);
|
|
|
|
if (mux == 0) {
|
|
*rate = OSC24M_CLK_FREQ;
|
|
} else {
|
|
*rate = 0;
|
|
}
|
|
} break;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef CONFIG_COUNTER_MCUX_QTMR
|
|
case IMX_CCM_QTMR_CLK:
|
|
*rate = CLOCK_GetIpgFreq();
|
|
break;
|
|
#endif
|
|
|
|
#ifdef CONFIG_I2S_MCUX_SAI
|
|
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai1))
|
|
case IMX_CCM_SAI1_CLK:
|
|
*rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
|
|
/ (CLOCK_GetDiv(kCLOCK_Sai1PreDiv) + 1)
|
|
/ (CLOCK_GetDiv(kCLOCK_Sai1Div) + 1);
|
|
break;
|
|
#endif
|
|
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai2))
|
|
case IMX_CCM_SAI2_CLK:
|
|
*rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
|
|
/ (CLOCK_GetDiv(kCLOCK_Sai2PreDiv) + 1)
|
|
/ (CLOCK_GetDiv(kCLOCK_Sai2Div) + 1);
|
|
break;
|
|
#endif
|
|
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai3))
|
|
case IMX_CCM_SAI3_CLK:
|
|
*rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
|
|
/ (CLOCK_GetDiv(kCLOCK_Sai3PreDiv) + 1)
|
|
/ (CLOCK_GetDiv(kCLOCK_Sai3Div) + 1);
|
|
break;
|
|
#endif
|
|
#endif
|
|
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexspi))
|
|
case IMX_CCM_FLEXSPI_CLK:
|
|
*rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot);
|
|
break;
|
|
#endif
|
|
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexspi2))
|
|
case IMX_CCM_FLEXSPI2_CLK:
|
|
*rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot);
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_COUNTER_NXP_PIT
|
|
case IMX_CCM_PIT_CLK:
|
|
*rate = CLOCK_GetFreq(kCLOCK_PerClk);
|
|
break;
|
|
#endif
|
|
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio1)) && CONFIG_MCUX_FLEXIO
|
|
case IMX_CCM_FLEXIO1_CLK:
|
|
{
|
|
uint32_t flexio_mux = CLOCK_GetMux(kCLOCK_Flexio1Mux);
|
|
uint32_t source_clk_freq = 0;
|
|
|
|
if (flexio_mux == 0) {
|
|
source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
|
|
} else if (flexio_mux == 1) {
|
|
source_clk_freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
|
|
#ifdef PLL_VIDEO_OFFSET /* fsl_clock.h */
|
|
} else if (flexio_mux == 2) {
|
|
source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);
|
|
#endif
|
|
} else {
|
|
source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
|
|
}
|
|
|
|
*rate = source_clk_freq / (CLOCK_GetDiv(kCLOCK_Flexio1PreDiv) + 1)
|
|
/ (CLOCK_GetDiv(kCLOCK_Flexio1Div) + 1);
|
|
} break;
|
|
#endif
|
|
#if (DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio2)) \
|
|
|| DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio3))) && CONFIG_MCUX_FLEXIO
|
|
case IMX_CCM_FLEXIO2_3_CLK:
|
|
{
|
|
uint32_t flexio_mux = CLOCK_GetMux(kCLOCK_Flexio2Mux);
|
|
uint32_t source_clk_freq = 0;
|
|
|
|
if (flexio_mux == 0) {
|
|
source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
|
|
} else if (flexio_mux == 1) {
|
|
source_clk_freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
|
|
#ifdef PLL_VIDEO_OFFSET /* fsl_clock.h */
|
|
} else if (flexio_mux == 2) {
|
|
source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);
|
|
#endif
|
|
} else {
|
|
source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
|
|
}
|
|
|
|
*rate = source_clk_freq / (CLOCK_GetDiv(kCLOCK_Flexio2PreDiv) + 1)
|
|
/ (CLOCK_GetDiv(kCLOCK_Flexio2Div) + 1);
|
|
} break;
|
|
#endif
|
|
|
|
#ifdef CONFIG_SPI_MCUX_ECSPI
|
|
case IMX_CCM_ECSPI1_CLK:
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
|
|
(CLOCK_GetRootPreDivider(kCLOCK_RootEcspi1)) /
|
|
(CLOCK_GetRootPostDivider(kCLOCK_RootEcspi1));
|
|
break;
|
|
case IMX_CCM_ECSPI2_CLK:
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
|
|
(CLOCK_GetRootPreDivider(kCLOCK_RootEcspi2)) /
|
|
(CLOCK_GetRootPostDivider(kCLOCK_RootEcspi2));
|
|
break;
|
|
case IMX_CCM_ECSPI3_CLK:
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
|
|
(CLOCK_GetRootPreDivider(kCLOCK_RootEcspi3)) /
|
|
(CLOCK_GetRootPostDivider(kCLOCK_RootEcspi3));
|
|
break;
|
|
#endif /* CONFIG_SPI_MCUX_ECSPI */
|
|
|
|
#if defined(CONFIG_I2C_NXP_II2C)
|
|
case IMX_CCM_I2C1_CLK:
|
|
case IMX_CCM_I2C2_CLK:
|
|
case IMX_CCM_I2C3_CLK:
|
|
case IMX_CCM_I2C4_CLK:
|
|
#ifdef CONFIG_SOC_MIMX8ML8
|
|
case IMX_CCM_I2C5_CLK:
|
|
case IMX_CCM_I2C6_CLK:
|
|
#endif
|
|
{
|
|
uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
|
|
uint32_t i2c_mux = CLOCK_GetRootMux(i2c_clk_root[instance]);
|
|
|
|
if (i2c_mux == 0) {
|
|
*rate = MHZ(24);
|
|
} else if (i2c_mux == 1) {
|
|
*rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
|
|
(CLOCK_GetRootPreDivider(i2c_clk_root[instance])) /
|
|
(CLOCK_GetRootPostDivider(i2c_clk_root[instance])) /
|
|
5; /* SYSTEM PLL1 DIV5 */
|
|
}
|
|
|
|
} break;
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Since this function is used to reclock the FlexSPI when running in
|
|
* XIP, it must be located in RAM when MEMC Flexspi driver is enabled.
|
|
*/
|
|
#ifdef CONFIG_MEMC_MCUX_FLEXSPI
|
|
#define CCM_SET_FUNC_ATTR __ramfunc
|
|
#else
|
|
#define CCM_SET_FUNC_ATTR
|
|
#endif
|
|
|
|
static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev,
|
|
clock_control_subsys_t subsys,
|
|
clock_control_subsys_rate_t rate)
|
|
{
|
|
uint32_t clock_name = (uintptr_t)subsys;
|
|
uint32_t clock_rate = (uintptr_t)rate;
|
|
|
|
switch (clock_name) {
|
|
case IMX_CCM_FLEXSPI_CLK:
|
|
__fallthrough;
|
|
case IMX_CCM_FLEXSPI2_CLK:
|
|
#if defined(CONFIG_SOC_SERIES_IMXRT10XX) && defined(CONFIG_MEMC_MCUX_FLEXSPI)
|
|
/* The SOC is using the FlexSPI for XIP. Therefore,
|
|
* the FlexSPI itself must be managed within the function,
|
|
* which is SOC specific.
|
|
*/
|
|
return flexspi_clock_set_freq(clock_name, clock_rate);
|
|
#endif
|
|
default:
|
|
/* Silence unused variable warning */
|
|
ARG_UNUSED(clock_rate);
|
|
return -ENOTSUP;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static DEVICE_API(clock_control, mcux_ccm_driver_api) = {
|
|
.on = mcux_ccm_on,
|
|
.off = mcux_ccm_off,
|
|
.get_rate = mcux_ccm_get_subsys_rate,
|
|
.set_rate = mcux_ccm_set_subsys_rate,
|
|
};
|
|
|
|
static int mcux_ccm_init(const struct device *dev)
|
|
{
|
|
#if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
|
|
int ret;
|
|
|
|
ret = sc_ipc_open(&ipc_handle, DT_REG_ADDR(DT_NODELABEL(scu_mu)));
|
|
if (ret != SC_ERR_NONE) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
CLOCK_Init(ipc_handle);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
DEVICE_DT_INST_DEFINE(0, mcux_ccm_init, NULL, NULL, NULL,
|
|
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
|
|
&mcux_ccm_driver_api);
|