static int sgtl5000_configure(const struct device *dev, struct audio_codec_cfg *cfg)
{
int ret;
bool is_master = (cfg->dai_cfg.i2s.options & I2S_OPT_FRAME_CLK_MASTER);
if (cfg->dai_type >= AUDIO_DAI_TYPE_INVALID) {
return -EINVAL;
}
/* --------------------------------------------------------------------- */
/* DYNAMIC BIT WIDTH & SCLK RATIO CONFIGURATION (LINUX PORTED) */
/* --------------------------------------------------------------------- */
uint16_t i2s_ctl = 0;
switch (cfg->dai_cfg.i2s.word_size) {
case 16:
/* 16-bit data length uses 32*FS clock frequency ratio configuration */
i2s_ctl |= SGTL5000_I2S_DLEN_16 << SGTL5000_I2S_DLEN_SHIFT;
i2s_ctl |= SGTL5000_I2S_SCLKFREQ_32FS << SGTL5000_I2S_SCLKFREQ_SHIFT;
break;
case 20:
i2s_ctl |= SGTL5000_I2S_DLEN_20 << SGTL5000_I2S_DLEN_SHIFT;
i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS << SGTL5000_I2S_SCLKFREQ_SHIFT;
break;
case 24:
i2s_ctl |= SGTL5000_I2S_DLEN_24 << SGTL5000_I2S_DLEN_SHIFT;
i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS << SGTL5000_I2S_SCLKFREQ_SHIFT;
break;
case 32:
i2s_ctl |= SGTL5000_I2S_DLEN_32 << SGTL5000_I2S_DLEN_SHIFT;
i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS << SGTL5000_I2S_SCLKFREQ_SHIFT;
break;
default:
LOG_ERR("SGTL5000: Unsupported hardware bit width %d", cfg->dai_cfg.i2s.word_size);
return -EINVAL;
}
/*
* Mask and update only the dynamic bit width (DLEN) and bit clock speed (SCLKFREQ) fields.
* This prevents destroying the Master/Slave states or frame format fields.
*/
ret = sgtl5000_update_reg(dev, SGTL5000_CHIP_I2S_CTRL,
SGTL5000_I2S_DLEN_MASK | SGTL5000_I2S_SCLKFREQ_MASK,
i2s_ctl);
if (ret != 0) return ret;
LOG_INF("SGTL5000: Applied Linux port for %d-bit data (I2S_CTRL update mask payload: 0x%04X)",
cfg->dai_cfg.i2s.word_size, i2s_ctl);
/* --------------------------------------------------------------------- */
/* CORE HARDWARE CLOCKS & ROUTING CONFIGURATION */
/* --------------------------------------------------------------------- */
/* Configure core clock configuration trees and internal PLL multiplier */
ret = sgtl5000_set_clock(dev, cfg->mclk_freq, cfg->dai_cfg.i2s.frame_clk_freq, is_master);
if (ret != 0) return ret;
/* Program Data Bus Protocol Routing (Applies Master/Slave or custom alignment switches) */
ret = sgtl5000_protocol_config(dev, cfg->dai_type, is_master);
if (ret != 0) return ret;
/* Map analog power paths and states based on target route definitions */
switch (cfg->dai_route) {
case AUDIO_ROUTE_PLAYBACK:
sgtl5000_set_power(dev, true, false, true, false);
sgtl5000_set_route_state(dev, AUDIO_ROUTE_PLAYBACK);
break;
case AUDIO_ROUTE_CAPTURE:
sgtl5000_set_power(dev, false, true, false, false);
sgtl5000_set_route_state(dev, AUDIO_ROUTE_CAPTURE);
break;
case AUDIO_ROUTE_PLAYBACK_CAPTURE:
sgtl5000_set_power(dev, true, true, true, true);
sgtl5000_set_route_state(dev, AUDIO_ROUTE_PLAYBACK_CAPTURE);
break;
default:
sgtl5000_set_power(dev, false, false, false, false);
sgtl5000_set_route_state(dev, AUDIO_ROUTE_BYPASS);
break;
}
return 0;
}