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


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;
}