#include <zephyr/init.h>
#include <fsl_clock.h>
#include <fsl_iomuxc.h>
/**
* @brief Universal hardware clock configuration logic for an individual SAI block.
*/
static void sgtl5000_activate_sai_mclk(uint32_t base_addr)
{
if (base_addr == DT_REG_ADDR(DT_NODELABEL(sai1))) {
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 0x10B0U);
CLOCK_EnableClock(kCLOCK_Sai1);
CLOCK_SetMux(kCLOCK_Sai1Mux, 0); /* Select PLL4 (Audio PLL) */
CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3);
CLOCK_SetDiv(kCLOCK_Sai1Div, 7);
printk("SGTL5000 Dynamic Patch: Started clock configuration for SAI1\n");
} else if (base_addr == DT_REG_ADDR(DT_NODELABEL(sai2))) {
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B0_00_SAI2_MCLK, 0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_00_SAI2_MCLK, 0x10B0U);
CLOCK_EnableClock(kCLOCK_Sai2);
CLOCK_SetMux(kCLOCK_Sai2Mux, 0); /* Select PLL4 (Audio PLL) */
CLOCK_SetDiv(kCLOCK_Sai2PreDiv, 3);
CLOCK_SetDiv(kCLOCK_Sai2Div, 7);
printk("SGTL5000 Dynamic Patch: Started clock configuration for SAI2\n");
} else if (base_addr == DT_REG_ADDR(DT_NODELABEL(sai3))) {
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_SAI3_MCLK, 0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_SAI3_MCLK, 0x10B0U);
CLOCK_EnableClock(kCLOCK_Sai3);
CLOCK_SetMux(kCLOCK_Sai3Mux, 0); /* Select PLL4 (Audio PLL) */
CLOCK_SetDiv(kCLOCK_Sai3PreDiv, 3);
CLOCK_SetDiv(kCLOCK_Sai3Div, 7);
printk("SGTL5000 Dynamic Patch: Started clock configuration for SAI3\n");
} else {
printk("SGTL5000 Dynamic Patch ERROR: Unknown SAI base 0x%08X\n", base_addr);
return;
}
/* Trigger continuous bit clock output stream on the active registers address */
((I2S_Type *)base_addr)->TCSR |= I2S_TCSR_BCE_MASK;
printk("SGTL5000 Dynamic Patch: Continuous MCLK un-gated for block at 0x%08X\n", base_addr);
}
/**
* @brief Multi-instance loop framework wrapper.
*
* This macro handles metadata substitution for every discovered active
* "nxp,sgtl5000" node declared inside the device tree overlay at compile-time.
*/
#define CONFIGURE_MCLK_FOR_INSTANCE(inst) \
sgtl5000_activate_sai_mclk(DT_REG_ADDR(DT_PHANDLE(DT_DRV_INST(inst), bus_sai)));
static int sgtl5000_global_force_mclk_init(void)
{
/* Automatically execute the clock un-gating code for ALL defined active codecs */
DT_INST_FOREACH_STATUS_OKAY(CONFIGURE_MCLK_FOR_INSTANCE)
return 0;
}
/* Run at PRE_KERNEL_2 phase to unlock all codecs I2C state engines simultaneously */
SYS_INIT(sgtl5000_global_force_mclk_init, PRE_KERNEL_2, 50);