#include <zephyr/init.h>
#include <fsl_clock.h>
#include <fsl_iomuxc.h>
/* Retrieve the base memory address of the linked SAI instance directly from DTS */
#define CODEC_SAI_BASE_ADDR DT_REG_ADDR(DT_PHANDLE(DT_DRV_INST(0), bus-sai))
#define AUDIO_SAI_PERIPHERAL ((I2S_Type *)CODEC_SAI_BASE_ADDR)
/**
* @brief Early system hook to force MCLK generation for the SGTL5000 codec.
*
* This function automatically detects which SAI instance is selected in the
* device tree, maps its hardware registers, and enables continuous MCLK generation.
*/
static int sgtl5000_force_mclk_init(void)
{
/*
* 1. Configure the physical pinmux allocation for the SAI MCLK signal line.
* NOTE: Pinmux settings are board-dependent and usually handled by the pinctrl driver.
* If your pinctrl driver runs later, we force the configuration here:
*/
#if (CODEC_SAI_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);
CLOCK_SetDiv(kCLOCK_Sai2PreDiv, 3);
CLOCK_SetDiv(kCLOCK_Sai2Div, 7);
#elif (CODEC_SAI_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);
CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3);
CLOCK_SetDiv(kCLOCK_Sai1Div, 7);
#endif
/*
* 2. Dynamically access the selected SAI peripheral registers.
* This un-gates the master clock generation engine for whichever SAI is active.
*/
AUDIO_SAI_PERIPHERAL->TCSR |= I2S_TCSR_BCE_MASK;
printk("SGTL5000 Patch: Dynamic MCLK generation enabled for SAI register block 0x%08X\n",
CODEC_SAI_BASE_ADDR);
return 0;
}
/* Run during PRE_KERNEL_2 phase to unlock I2C state machine before device discovery loops */
SYS_INIT(sgtl5000_force_mclk_init, PRE_KERNEL_2, 50);