Загрузка данных


#include <zephyr/init.h>
#include <fsl_clock.h>
#include <fsl_iomuxc.h>

/* Retrieve the base memory address of the linked SAI instance dynamically from DTS */
#define CODEC_SAI_NODE        DT_PHANDLE(DT_DRV_INST(0), bus-sai)
#define CODEC_SAI_BASE_ADDR   DT_REG_ADDR(CODEC_SAI_NODE)
#define AUDIO_SAI_PERIPHERAL  ((I2S_Type *)CODEC_SAI_BASE_ADDR)

/**
 * @brief Early system hook to force MCLK generation for the SGTL5000 codec.
 *
 * This function dynamically determines which SAI instance (SAI1, SAI2, or SAI3)
 * is selected in the device tree, enables its clock gates via the NXP SDK HAL,
 * and sets up the required bit clock registers to un-block the codec's I2C engine.
 */
static int sgtl5000_force_mclk_init(void)
{
	/* 
	 * 1. Dynamic Clock and Pinmux configuration based on the selected SAI instance.
	 * This covers SAI1, SAI2, and SAI3 peripheral blocks for i.MX RT processors.
	 */
	if (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); /* Select PLL4 (Audio PLL) */
		CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3); 
		CLOCK_SetDiv(kCLOCK_Sai1Div, 7); 
		printk("SGTL5000 Patch: Target interface identified as SAI1\n");

	} else 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); /* Select PLL4 (Audio PLL) */
		CLOCK_SetDiv(kCLOCK_Sai2PreDiv, 3); 
		CLOCK_SetDiv(kCLOCK_Sai2Div, 7);    
		printk("SGTL5000 Patch: Target interface identified as SAI2\n");

	} else if (CODEC_SAI_BASE_ADDR == DT_REG_ADDR(DT_NODELABEL(sai3))) {
		/* SAI3 MCLK mapping on i.MX RT1024 / RT1020 standard pinmux allocation */
		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 Patch: Target interface identified as SAI3\n");

	} else {
		LOG_ERR("SGTL5000 Patch: Linked SAI base address (0x%08X) is invalid or unsupported", 
			CODEC_SAI_BASE_ADDR);
		return -EINVAL;
	}

	/* 
	 * 2. Force the Transmitter Bit Clock Enable (BCE) bit.
	 * This forces the selected SAI peripheral engine to continuously drive the MCLK pin 
	 * before Zephyr reaches the POST_KERNEL device discovery loops.
	 */
	AUDIO_SAI_PERIPHERAL->TCSR |= I2S_TCSR_BCE_MASK; 
	
	printk("SGTL5000 Patch: Continuous MCLK generation un-gated for hardware block at 0x%08X\n", 
	       CODEC_SAI_BASE_ADDR);
           
	return 0;
}

/* Execute during PRE_KERNEL_2 to un-freeze the codec hardware before I2C initialization */
SYS_INIT(sgtl5000_force_mclk_init, PRE_KERNEL_2, 50);