Загрузка данных
static void wm8960_set_left_right_output(const struct device * dev, bool left, bool speaker)
{
/* Data route I2S_IN-> DAC-> HP */
if(left) {
/* Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB */
wm8960_write_reg(dev, WM8960_REG_LOUTMIX, 0x100);
} else {
/* Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB */
wm8960_write_reg(dev, WM8960_REG_ROUTMIX, 0x100);
}
wm8960_write_reg(dev, WM8960_REG_POWER3, 0x0C);
/* Set power for DAC */
wm8960_set_module(dev, kWM8960_ModuleDAC, true);
wm8960_set_module(dev, kWM8960_ModuleOMIX, true);
wm8960_set_module(dev, kWM8960_ModuleLineOut, !speaker);
wm8960_set_module(dev, kWM8960_ModuleSpeaker, speaker);
}
static int wm8960_route_output(const struct device *dev, audio_channel_t channel, uint32_t output)
{
/* Output MIXER */
switch (channel) {
case AUDIO_CHANNEL_HEADPHONE_LEFT:
wm8960_set_left_right_output(dev, true, false);
break;
case AUDIO_CHANNEL_HEADPHONE_RIGHT:
wm8960_set_left_right_output(dev, false, false);
break;
case AUDIO_CHANNEL_FRONT_LEFT:
case AUDIO_CHANNEL_REAR_LEFT:
case AUDIO_CHANNEL_SIDE_LEFT:
wm8960_set_left_right_output(dev, true, true);
break;
case AUDIO_CHANNEL_FRONT_RIGHT:
case AUDIO_CHANNEL_REAR_RIGHT:
case AUDIO_CHANNEL_SIDE_RIGHT:
wm8960_set_left_right_output(dev, false, true);
break;
default:
break;
}
return 0;
}
static int wm8960_configure(const struct device *dev, struct audio_codec_cfg *cfg)
{
uint32_t sysClk = 6144000U;
const struct wm8960_driver_config *const dev_cfg = DEV_CFG(dev);
if (cfg->dai_type >= AUDIO_DAI_TYPE_INVALID) {
LOG_ERR("dai_type not supported");
return -EINVAL;
}
if (dev_cfg->clock_source == kWM8960_SysClkSourceMclk) {
int err = clock_control_on(dev_cfg->mclk_dev, dev_cfg->mclk_name);
if (err < 0) {
LOG_ERR("MCLK clock source enable fail: %d", err);
}
err = clock_control_get_rate(dev_cfg->mclk_dev, dev_cfg->mclk_name,
&cfg->mclk_freq);
if (err < 0) {
LOG_ERR("MCLK clock source freq acquire fail: %d", err);
}
}
/* load wm8960 register map */
(void)memcpy(reg_cache, wm8960_reg, sizeof(wm8960_reg));
wm8960_soft_reset(dev);
if (cfg->dai_route == AUDIO_ROUTE_BYPASS) {
return 0;
}
/*VMID=50K, Enable VREF, AINL, AINR, ADCL and ADCR I2S_IN (bit 0), I2S_OUT (bit 1), DAP (bit 4), DAC (bit 5), ADC (bit 6) are powered on*/
wm8960_write_reg(dev, WM8960_REG_POWER1, 0xFE);
/* Enable DACL, DACR, LOUT1, ROUT1, PLL down, SPKL, SPKR */
wm8960_write_reg(dev, WM8960_REG_POWER2, 0x1F8);
/* Enable left and right channel input PGA, left and right output mixer */
wm8960_write_reg(dev, WM8960_REG_POWER3, 0x3C);
/* ADC and DAC uses same clock */
wm8960_write_reg(dev, WM8960_REG_IFACE2, 0x40);
wm8960_set_data_route(dev, cfg->dai_route);
wm8960_set_play(dev, kWM8960_PlaySourceDAC);
if (dev_cfg->clock_source == kWM8960_SysClkSourcePLL)
{
wm8960_set_internal_PllConfig(dev, sysClk, cfg->mclk_freq, cfg->dai_cfg.i2s.frame_clk_freq, cfg->dai_cfg.i2s.word_size);
}
sysClk = cfg->mclk_freq;
/* set master*/
if (cfg->dai_cfg.i2s.options & I2S_OPT_FRAME_CLK_MASTER)
{
wm8960_set_master_clock(dev, sysClk, cfg->dai_cfg.i2s.frame_clk_freq, cfg->dai_cfg.i2s.word_size);
}
/* set data protocol */
wm8960_protocol_config(dev, cfg->dai_type);
wm8960_set_master_slave(dev, (cfg->dai_cfg.i2s.options & I2S_OPT_FRAME_CLK_MASTER));
/* speaker power */
if (dev_cfg->enableSpeaker)
{
wm8960_set_module(dev, kWM8960_ModuleSpeaker, true);
}
#ifdef MY_CODE
wm8960_write_reg(dev, WM8960_REG_ADDCTL1, 0x0C0);
#else
wm8960_write_reg(dev, WM8960_REG_ADDCTL1, 0x0C4);
#endif
wm8960_write_reg(dev, WM8960_REG_ADDCTL4, 0x40);
wm8960_write_reg(dev, WM8960_REG_BYPASS1, 0x0);
wm8960_write_reg(dev, WM8960_REG_BYPASS2, 0x0);
/*
* ADC volume, 0dB
*/
wm8960_write_reg(dev, WM8960_REG_LADC, WM8960_ADC_DEFAULT_VOLUME_VALUE);
wm8960_write_reg(dev, WM8960_REG_RADC, WM8960_ADC_DEFAULT_VOLUME_VALUE);
/*
* Digital DAC volume, -15.5dB
*/
wm8960_write_reg(dev, WM8960_REG_LDAC, WM8960_DAC_DEFAULT_VOLUME_VALUE);
wm8960_write_reg(dev, WM8960_REG_RDAC, WM8960_DAC_DEFAULT_VOLUME_VALUE);
/* speaker volume 6dB */
wm8960_write_reg(dev, WM8960_REG_LOUT2, WM8960_SPEAKER_DEFAULT_VOLUME_VALUE);
wm8960_write_reg(dev, WM8960_REG_ROUT2, WM8960_SPEAKER_DEFAULT_VOLUME_VALUE);
/* input PGA volume */
wm8960_write_reg(dev, WM8960_REG_LINVOL, WM8960_LINEIN_DEFAULT_VOLUME_VALUE);
wm8960_write_reg(dev, WM8960_REG_RINVOL, WM8960_LINEIN_DEFAULT_VOLUME_VALUE);
/* Headphone volume */
wm8960_write_reg(dev, WM8960_REG_LOUT1, WM8960_HEADPHONE_DEFAULT_VOLUME_VALUE);
wm8960_write_reg(dev, WM8960_REG_ROUT1, WM8960_HEADPHONE_DEFAULT_VOLUME_VALUE);
/* enable class D output */
wm8960_write_reg(dev, WM8960_REG_CLASSD1, 0xf7);
/* Unmute DAC. */
wm8960_write_reg(dev, WM8960_REG_DACCTL1, 0x0000);
wm8960_audio_fmt_config(dev, &cfg->dai_cfg, sysClk);
switch (cfg->dai_route) {
case AUDIO_ROUTE_BYPASS:
break;
case AUDIO_ROUTE_PLAYBACK:
wm8960_configure_output(dev);
break;
case AUDIO_ROUTE_CAPTURE:
wm8960_configure_input(dev);
break;
case AUDIO_ROUTE_PLAYBACK_CAPTURE:
wm8960_configure_output(dev);
wm8960_configure_input(dev);
break;
default:
break;
}
return 0;
}
static void wm8960_start_output(const struct device *dev)
{
/* Not supported */
}
static void wm8960_stop_output(const struct device *dev)
{
/* Not supported */
}
static int wm8960_set_property(const struct device *dev, audio_property_t property,
audio_channel_t channel, audio_property_value_t val)
{
switch (property) {
case AUDIO_PROPERTY_OUTPUT_VOLUME:
return wm8960_out_volume_config(dev, channel, val.vol);
case AUDIO_PROPERTY_OUTPUT_MUTE:
return wm8960_out_mute_config(dev, channel, val.mute);
case AUDIO_PROPERTY_INPUT_VOLUME:
return wm8960_in_volume_config(dev, channel, val.vol);
case AUDIO_PROPERTY_INPUT_MUTE:
return wm8960_in_mute_config(dev, channel, val.mute);
default:
break;
}
return -EINVAL;
}