⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wm8753.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		voice |= 0x0003;		break;	case SND_SOC_DAIFMT_DSP_B:		voice |= 0x0013;		break;	default:		return -EINVAL;	}	wm8753_write(codec, WM8753_PCM, voice);	return 0;}/* * Set PCM DAI bit size and sample rate. */static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,	struct snd_pcm_hw_params *params){	struct snd_soc_pcm_runtime *rtd = substream->private_data;	struct snd_soc_device *socdev = rtd->socdev;	struct snd_soc_codec *codec = socdev->codec;	struct wm8753_priv *wm8753 = codec->private_data;	u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;	u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;	/* bit size */	switch (params_format(params)) {	case SNDRV_PCM_FORMAT_S16_LE:		break;	case SNDRV_PCM_FORMAT_S20_3LE:		voice |= 0x0004;		break;	case SNDRV_PCM_FORMAT_S24_LE:		voice |= 0x0008;		break;	case SNDRV_PCM_FORMAT_S32_LE:		voice |= 0x000c;		break;	}	/* sample rate */	if (params_rate(params) * 384 == wm8753->pcmclk)		srate |= 0x80;	wm8753_write(codec, WM8753_SRATE1, srate);	wm8753_write(codec, WM8753_PCM, voice);	return 0;}/* * Set's PCM dai fmt and BCLK. */static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,		unsigned int fmt){	struct snd_soc_codec *codec = codec_dai->codec;	u16 voice, ioctl;	voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x011f;	ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x015d;	/* set master/slave audio interface */	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {	case SND_SOC_DAIFMT_CBS_CFS:		break;	case SND_SOC_DAIFMT_CBM_CFM:		ioctl |= 0x2;	case SND_SOC_DAIFMT_CBM_CFS:		voice |= 0x0040;		break;	default:		return -EINVAL;	}	/* clock inversion */	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {	case SND_SOC_DAIFMT_DSP_A:	case SND_SOC_DAIFMT_DSP_B:		/* frame inversion not valid for DSP modes */		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {		case SND_SOC_DAIFMT_NB_NF:			break;		case SND_SOC_DAIFMT_IB_NF:			voice |= 0x0080;			break;		default:			return -EINVAL;		}		break;	case SND_SOC_DAIFMT_I2S:	case SND_SOC_DAIFMT_RIGHT_J:	case SND_SOC_DAIFMT_LEFT_J:		voice &= ~0x0010;		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {		case SND_SOC_DAIFMT_NB_NF:			break;		case SND_SOC_DAIFMT_IB_IF:			voice |= 0x0090;			break;		case SND_SOC_DAIFMT_IB_NF:			voice |= 0x0080;			break;		case SND_SOC_DAIFMT_NB_IF:			voice |= 0x0010;			break;		default:			return -EINVAL;		}		break;	default:		return -EINVAL;	}	wm8753_write(codec, WM8753_PCM, voice);	wm8753_write(codec, WM8753_IOCTL, ioctl);	return 0;}static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,		int div_id, int div){	struct snd_soc_codec *codec = codec_dai->codec;	u16 reg;	switch (div_id) {	case WM8753_PCMDIV:		reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0x003f;		wm8753_write(codec, WM8753_CLOCK, reg | div);		break;	case WM8753_BCLKDIV:		reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x01c7;		wm8753_write(codec, WM8753_SRATE2, reg | div);		break;	case WM8753_VXCLKDIV:		reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x003f;		wm8753_write(codec, WM8753_SRATE2, reg | div);		break;	default:		return -EINVAL;	}	return 0;}/* * Set's HiFi DAC format. */static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,		unsigned int fmt){	struct snd_soc_codec *codec = codec_dai->codec;	u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01e0;	/* interface format */	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {	case SND_SOC_DAIFMT_I2S:		hifi |= 0x0002;		break;	case SND_SOC_DAIFMT_RIGHT_J:		break;	case SND_SOC_DAIFMT_LEFT_J:		hifi |= 0x0001;		break;	case SND_SOC_DAIFMT_DSP_A:		hifi |= 0x0003;		break;	case SND_SOC_DAIFMT_DSP_B:		hifi |= 0x0013;		break;	default:		return -EINVAL;	}	wm8753_write(codec, WM8753_HIFI, hifi);	return 0;}/* * Set's I2S DAI format. */static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,		unsigned int fmt){	struct snd_soc_codec *codec = codec_dai->codec;	u16 ioctl, hifi;	hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x011f;	ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x00ae;	/* set master/slave audio interface */	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {	case SND_SOC_DAIFMT_CBS_CFS:		break;	case SND_SOC_DAIFMT_CBM_CFM:		ioctl |= 0x1;	case SND_SOC_DAIFMT_CBM_CFS:		hifi |= 0x0040;		break;	default:		return -EINVAL;	}	/* clock inversion */	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {	case SND_SOC_DAIFMT_DSP_A:	case SND_SOC_DAIFMT_DSP_B:		/* frame inversion not valid for DSP modes */		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {		case SND_SOC_DAIFMT_NB_NF:			break;		case SND_SOC_DAIFMT_IB_NF:			hifi |= 0x0080;			break;		default:			return -EINVAL;		}		break;	case SND_SOC_DAIFMT_I2S:	case SND_SOC_DAIFMT_RIGHT_J:	case SND_SOC_DAIFMT_LEFT_J:		hifi &= ~0x0010;		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {		case SND_SOC_DAIFMT_NB_NF:			break;		case SND_SOC_DAIFMT_IB_IF:			hifi |= 0x0090;			break;		case SND_SOC_DAIFMT_IB_NF:			hifi |= 0x0080;			break;		case SND_SOC_DAIFMT_NB_IF:			hifi |= 0x0010;			break;		default:			return -EINVAL;		}		break;	default:		return -EINVAL;	}	wm8753_write(codec, WM8753_HIFI, hifi);	wm8753_write(codec, WM8753_IOCTL, ioctl);	return 0;}/* * Set PCM DAI bit size and sample rate. */static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,	struct snd_pcm_hw_params *params){	struct snd_soc_pcm_runtime *rtd = substream->private_data;	struct snd_soc_device *socdev = rtd->socdev;	struct snd_soc_codec *codec = socdev->codec;	struct wm8753_priv *wm8753 = codec->private_data;	u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;	u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;	int coeff;	/* is digital filter coefficient valid ? */	coeff = get_coeff(wm8753->sysclk, params_rate(params));	if (coeff < 0) {		printk(KERN_ERR "wm8753 invalid MCLK or rate\n");		return coeff;	}	wm8753_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |		coeff_div[coeff].usb);	/* bit size */	switch (params_format(params)) {	case SNDRV_PCM_FORMAT_S16_LE:		break;	case SNDRV_PCM_FORMAT_S20_3LE:		hifi |= 0x0004;		break;	case SNDRV_PCM_FORMAT_S24_LE:		hifi |= 0x0008;		break;	case SNDRV_PCM_FORMAT_S32_LE:		hifi |= 0x000c;		break;	}	wm8753_write(codec, WM8753_HIFI, hifi);	return 0;}static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,		unsigned int fmt){	struct snd_soc_codec *codec = codec_dai->codec;	u16 clock;	/* set clk source as pcmclk */	clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;	wm8753_write(codec, WM8753_CLOCK, clock);	if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)		return -EINVAL;	return wm8753_pcm_set_dai_fmt(codec_dai, fmt);}static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,		unsigned int fmt){	if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)		return -EINVAL;	return wm8753_i2s_set_dai_fmt(codec_dai, fmt);}static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,		unsigned int fmt){	struct snd_soc_codec *codec = codec_dai->codec;	u16 clock;	/* set clk source as pcmclk */	clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;	wm8753_write(codec, WM8753_CLOCK, clock);	if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)		return -EINVAL;	return wm8753_i2s_set_dai_fmt(codec_dai, fmt);}static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,		unsigned int fmt){	struct snd_soc_codec *codec = codec_dai->codec;	u16 clock;	/* set clk source as mclk */	clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;	wm8753_write(codec, WM8753_CLOCK, clock | 0x4);	if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)		return -EINVAL;	if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)		return -EINVAL;	return wm8753_i2s_set_dai_fmt(codec_dai, fmt);}static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute){	struct snd_soc_codec *codec = dai->codec;	u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;	/* the digital mute covers the HiFi and Voice DAC's on the WM8753.	 * make sure we check if they are not both active when we mute */	if (mute && dai->id == 1) {		if (!wm8753_dai[WM8753_DAI_VOICE].playback.active ||			!wm8753_dai[WM8753_DAI_HIFI].playback.active)			wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);	} else {		if (mute)			wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);		else			wm8753_write(codec, WM8753_DAC, mute_reg);	}	return 0;}static int wm8753_dapm_event(struct snd_soc_codec *codec, int event){	u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e;	switch (event) {	case SNDRV_CTL_POWER_D0: /* full On */		/* set vmid to 50k and unmute dac */		wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);		break;	case SNDRV_CTL_POWER_D1: /* partial On */	case SNDRV_CTL_POWER_D2: /* partial On */		/* set vmid to 5k for quick power up */		wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);		break;	case SNDRV_CTL_POWER_D3hot: /* Off, with power */		/* mute dac and set vmid to 500k, enable VREF */		wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141);		break;	case SNDRV_CTL_POWER_D3cold: /* Off, without power */		wm8753_write(codec, WM8753_PWR1, 0x0001);		break;	}	codec->dapm_state = event;	return 0;}#define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)#define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\	SNDRV_PCM_FMTBIT_S24_LE)/* * The WM8753 supports upto 4 different and mutually exclusive DAI * configurations. This gives 2 PCM's available for use, hifi and voice. * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI * is connected between the wm8753 and a BT codec or GSM modem. * * 1. Voice over PCM DAI - HIFI DAC over HIFI DAI * 2. Voice over HIFI DAI - HIFI disabled * 3. Voice disabled - HIFI over HIFI * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture */static const struct snd_soc_codec_dai wm8753_all_dai[] = {/* DAI HiFi mode 1 */{	.name = "WM8753 HiFi",	.id = 1,	.playback = {		.stream_name = "HiFi Playback",		.channels_min = 1,		.channels_max = 2,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.capture = { /* dummy for fast DAI switching */		.stream_name = "Capture",		.channels_min = 1,		.channels_max = 2,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.ops = {		.hw_params = wm8753_i2s_hw_params,},	.dai_ops = {		.digital_mute = wm8753_mute,		.set_fmt = wm8753_mode1h_set_dai_fmt,		.set_clkdiv = wm8753_set_dai_clkdiv,		.set_pll = wm8753_set_dai_pll,		.set_sysclk = wm8753_set_dai_sysclk,	},},/* DAI Voice mode 1 */{	.name = "WM8753 Voice",	.id = 1,	.playback = {		.stream_name = "Voice Playback",		.channels_min = 1,		.channels_max = 1,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.capture = {		.stream_name = "Capture",		.channels_min = 1,		.channels_max = 2,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.ops = {		.hw_params = wm8753_pcm_hw_params,},	.dai_ops = {		.digital_mute = wm8753_mute,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -