wm8753.c

来自「linux 内核源代码」· C语言 代码 · 共 1,812 行 · 第 1/4 页

C
1,812
字号
SND_SOC_DAPM_PGA("Right Out 1", WM8753_PWR3, 7, 0, NULL, 0),SND_SOC_DAPM_PGA("Right Out 2", WM8753_PWR3, 5, 0, NULL, 0),SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", WM8753_PWR1, 2, 0),SND_SOC_DAPM_OUTPUT("ROUT1"),SND_SOC_DAPM_OUTPUT("ROUT2"),SND_SOC_DAPM_MIXER("Mono Mixer", WM8753_PWR4, 2, 0,	&wm8753_mono_mixer_controls[0], ARRAY_SIZE(wm8753_mono_mixer_controls)),SND_SOC_DAPM_PGA("Mono Out 1", WM8753_PWR3, 2, 0, NULL, 0),SND_SOC_DAPM_PGA("Mono Out 2", WM8753_PWR3, 1, 0, NULL, 0),SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", WM8753_PWR1, 4, 0),SND_SOC_DAPM_OUTPUT("MONO1"),SND_SOC_DAPM_MUX("Mono 2 Mux", SND_SOC_NOPM, 0, 0, &wm8753_mono2_controls),SND_SOC_DAPM_OUTPUT("MONO2"),SND_SOC_DAPM_MIXER("Out3 Left + Right", -1, 0, 0, NULL, 0),SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out3_controls),SND_SOC_DAPM_PGA("Out 3", WM8753_PWR3, 4, 0, NULL, 0),SND_SOC_DAPM_OUTPUT("OUT3"),SND_SOC_DAPM_MUX("Out4 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out4_controls),SND_SOC_DAPM_PGA("Out 4", WM8753_PWR3, 3, 0, NULL, 0),SND_SOC_DAPM_OUTPUT("OUT4"),SND_SOC_DAPM_MIXER("Playback Mixer", WM8753_PWR4, 3, 0,	&wm8753_record_mixer_controls[0],	ARRAY_SIZE(wm8753_record_mixer_controls)),SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8753_PWR2, 3, 0),SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8753_PWR2, 2, 0),SND_SOC_DAPM_MUX("Capture Left Mixer", SND_SOC_NOPM, 0, 0,	&wm8753_adc_mono_controls),SND_SOC_DAPM_MUX("Capture Right Mixer", SND_SOC_NOPM, 0, 0,	&wm8753_adc_mono_controls),SND_SOC_DAPM_MUX("Capture Left Mux", SND_SOC_NOPM, 0, 0,	&wm8753_adc_left_controls),SND_SOC_DAPM_MUX("Capture Right Mux", SND_SOC_NOPM, 0, 0,	&wm8753_adc_right_controls),SND_SOC_DAPM_MUX("Mic Sidetone Mux", SND_SOC_NOPM, 0, 0,	&wm8753_mic_mux_controls),SND_SOC_DAPM_PGA("Left Capture Volume", WM8753_PWR2, 5, 0, NULL, 0),SND_SOC_DAPM_PGA("Right Capture Volume", WM8753_PWR2, 4, 0, NULL, 0),SND_SOC_DAPM_MIXER("ALC Mixer", WM8753_PWR2, 6, 0,	&wm8753_alc_mixer_controls[0], ARRAY_SIZE(wm8753_alc_mixer_controls)),SND_SOC_DAPM_MUX("Line Left Mux", SND_SOC_NOPM, 0, 0,	&wm8753_line_left_controls),SND_SOC_DAPM_MUX("Line Right Mux", SND_SOC_NOPM, 0, 0,	&wm8753_line_right_controls),SND_SOC_DAPM_MUX("Line Mono Mux", SND_SOC_NOPM, 0, 0,	&wm8753_line_mono_controls),SND_SOC_DAPM_MUX("Line Mixer", WM8753_PWR2, 0, 0,	&wm8753_line_mux_mix_controls),SND_SOC_DAPM_MUX("Rx Mixer", WM8753_PWR2, 1, 0,	&wm8753_rx_mux_mix_controls),SND_SOC_DAPM_PGA("Mic 1 Volume", WM8753_PWR2, 8, 0, NULL, 0),SND_SOC_DAPM_PGA("Mic 2 Volume", WM8753_PWR2, 7, 0, NULL, 0),SND_SOC_DAPM_MUX("Mic Selection Mux", SND_SOC_NOPM, 0, 0,	&wm8753_mic_sel_mux_controls),SND_SOC_DAPM_INPUT("LINE1"),SND_SOC_DAPM_INPUT("LINE2"),SND_SOC_DAPM_INPUT("RXP"),SND_SOC_DAPM_INPUT("RXN"),SND_SOC_DAPM_INPUT("ACIN"),SND_SOC_DAPM_OUTPUT("ACOP"),SND_SOC_DAPM_INPUT("MIC1N"),SND_SOC_DAPM_INPUT("MIC1"),SND_SOC_DAPM_INPUT("MIC2N"),SND_SOC_DAPM_INPUT("MIC2"),SND_SOC_DAPM_VMID("VREF"),};static const char *audio_map[][3] = {	/* left mixer */	{"Left Mixer", "Left Playback Switch", "Left DAC"},	{"Left Mixer", "Voice Playback Switch", "Voice DAC"},	{"Left Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},	{"Left Mixer", "Bypass Playback Switch", "Line Left Mux"},	/* right mixer */	{"Right Mixer", "Right Playback Switch", "Right DAC"},	{"Right Mixer", "Voice Playback Switch", "Voice DAC"},	{"Right Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},	{"Right Mixer", "Bypass Playback Switch", "Line Right Mux"},	/* mono mixer */	{"Mono Mixer", "Voice Playback Switch", "Voice DAC"},	{"Mono Mixer", "Left Playback Switch", "Left DAC"},	{"Mono Mixer", "Right Playback Switch", "Right DAC"},	{"Mono Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},	{"Mono Mixer", "Bypass Playback Switch", "Line Mono Mux"},	/* left out */	{"Left Out 1", NULL, "Left Mixer"},	{"Left Out 2", NULL, "Left Mixer"},	{"LOUT1", NULL, "Left Out 1"},	{"LOUT2", NULL, "Left Out 2"},	/* right out */	{"Right Out 1", NULL, "Right Mixer"},	{"Right Out 2", NULL, "Right Mixer"},	{"ROUT1", NULL, "Right Out 1"},	{"ROUT2", NULL, "Right Out 2"},	/* mono 1 out */	{"Mono Out 1", NULL, "Mono Mixer"},	{"MONO1", NULL, "Mono Out 1"},	/* mono 2 out */	{"Mono 2 Mux", "Left + Right", "Out3 Left + Right"},	{"Mono 2 Mux", "Inverted Mono 1", "MONO1"},	{"Mono 2 Mux", "Left", "Left Mixer"},	{"Mono 2 Mux", "Right", "Right Mixer"},	{"Mono Out 2", NULL, "Mono 2 Mux"},	{"MONO2", NULL, "Mono Out 2"},	/* out 3 */	{"Out3 Left + Right", NULL, "Left Mixer"},	{"Out3 Left + Right", NULL, "Right Mixer"},	{"Out3 Mux", "VREF", "VREF"},	{"Out3 Mux", "Left + Right", "Out3 Left + Right"},	{"Out3 Mux", "ROUT2", "ROUT2"},	{"Out 3", NULL, "Out3 Mux"},	{"OUT3", NULL, "Out 3"},	/* out 4 */	{"Out4 Mux", "VREF", "VREF"},	{"Out4 Mux", "Capture ST", "Capture ST Mixer"},	{"Out4 Mux", "LOUT2", "LOUT2"},	{"Out 4", NULL, "Out4 Mux"},	{"OUT4", NULL, "Out 4"},	/* record mixer  */	{"Playback Mixer", "Left Capture Switch", "Left Mixer"},	{"Playback Mixer", "Voice Capture Switch", "Mono Mixer"},	{"Playback Mixer", "Right Capture Switch", "Right Mixer"},	/* Mic/SideTone Mux */	{"Mic Sidetone Mux", "Left PGA", "Left Capture Volume"},	{"Mic Sidetone Mux", "Right PGA", "Right Capture Volume"},	{"Mic Sidetone Mux", "Mic 1", "Mic 1 Volume"},	{"Mic Sidetone Mux", "Mic 2", "Mic 2 Volume"},	/* Capture Left Mux */	{"Capture Left Mux", "PGA", "Left Capture Volume"},	{"Capture Left Mux", "Line or RXP-RXN", "Line Left Mux"},	{"Capture Left Mux", "Line", "LINE1"},	/* Capture Right Mux */	{"Capture Right Mux", "PGA", "Right Capture Volume"},	{"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"},	{"Capture Right Mux", "Sidetone", "Capture ST Mixer"},	/* Mono Capture mixer-mux */	{"Capture Right Mixer", "Stereo", "Capture Right Mux"},	{"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"},	{"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"},	{"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"},	{"Capture Right Mixer", "Analogue Mix Right", "Capture Right Mux"},	{"Capture Left Mixer", "Digital Mono Mix", "Capture Left Mux"},	{"Capture Left Mixer", "Digital Mono Mix", "Capture Right Mux"},	{"Capture Right Mixer", "Digital Mono Mix", "Capture Left Mux"},	{"Capture Right Mixer", "Digital Mono Mix", "Capture Right Mux"},	/* ADC */	{"Left ADC", NULL, "Capture Left Mixer"},	{"Right ADC", NULL, "Capture Right Mixer"},	/* Left Capture Volume */	{"Left Capture Volume", NULL, "ACIN"},	/* Right Capture Volume */	{"Right Capture Volume", NULL, "Mic 2 Volume"},	/* ALC Mixer */	{"ALC Mixer", "Line Capture Switch", "Line Mixer"},	{"ALC Mixer", "Mic2 Capture Switch", "Mic 2 Volume"},	{"ALC Mixer", "Mic1 Capture Switch", "Mic 1 Volume"},	{"ALC Mixer", "Rx Capture Switch", "Rx Mixer"},	/* Line Left Mux */	{"Line Left Mux", "Line 1", "LINE1"},	{"Line Left Mux", "Rx Mix", "Rx Mixer"},	/* Line Right Mux */	{"Line Right Mux", "Line 2", "LINE2"},	{"Line Right Mux", "Rx Mix", "Rx Mixer"},	/* Line Mono Mux */	{"Line Mono Mux", "Line Mix", "Line Mixer"},	{"Line Mono Mux", "Rx Mix", "Rx Mixer"},	/* Line Mixer/Mux */	{"Line Mixer", "Line 1 + 2", "LINE1"},	{"Line Mixer", "Line 1 - 2", "LINE1"},	{"Line Mixer", "Line 1 + 2", "LINE2"},	{"Line Mixer", "Line 1 - 2", "LINE2"},	{"Line Mixer", "Line 1", "LINE1"},	{"Line Mixer", "Line 2", "LINE2"},	/* Rx Mixer/Mux */	{"Rx Mixer", "RXP - RXN", "RXP"},	{"Rx Mixer", "RXP + RXN", "RXP"},	{"Rx Mixer", "RXP - RXN", "RXN"},	{"Rx Mixer", "RXP + RXN", "RXN"},	{"Rx Mixer", "RXP", "RXP"},	{"Rx Mixer", "RXN", "RXN"},	/* Mic 1 Volume */	{"Mic 1 Volume", NULL, "MIC1N"},	{"Mic 1 Volume", NULL, "Mic Selection Mux"},	/* Mic 2 Volume */	{"Mic 2 Volume", NULL, "MIC2N"},	{"Mic 2 Volume", NULL, "MIC2"},	/* Mic Selector Mux */	{"Mic Selection Mux", "Mic 1", "MIC1"},	{"Mic Selection Mux", "Mic 2", "MIC2N"},	{"Mic Selection Mux", "Mic 3", "MIC2"},	/* ACOP */	{"ACOP", NULL, "ALC Mixer"},	/* terminator */	{NULL, NULL, NULL},};static int wm8753_add_widgets(struct snd_soc_codec *codec){	int i;	for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++)		snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]);	/* set up the WM8753 audio map */	for (i = 0; audio_map[i][0] != NULL; i++) {		snd_soc_dapm_connect_input(codec, audio_map[i][0],			audio_map[i][1], audio_map[i][2]);	}	snd_soc_dapm_new_widgets(codec);	return 0;}/* PLL divisors */struct _pll_div {	u32 div2:1;	u32 n:4;	u32 k:24;};/* The size in bits of the pll divide multiplied by 10 * to allow rounding later */#define FIXED_PLL_SIZE ((1 << 22) * 10)static void pll_factors(struct _pll_div *pll_div, unsigned int target,	unsigned int source){	u64 Kpart;	unsigned int K, Ndiv, Nmod;	Ndiv = target / source;	if (Ndiv < 6) {		source >>= 1;		pll_div->div2 = 1;		Ndiv = target / source;	} else		pll_div->div2 = 0;	if ((Ndiv < 6) || (Ndiv > 12))		printk(KERN_WARNING			"WM8753 N value outwith recommended range! N = %d\n",Ndiv);	pll_div->n = Ndiv;	Nmod = target % source;	Kpart = FIXED_PLL_SIZE * (long long)Nmod;	do_div(Kpart, source);	K = Kpart & 0xFFFFFFFF;	/* Check if we need to round */	if ((K % 10) >= 5)		K += 5;	/* Move down to proper range now rounding is done */	K /= 10;	pll_div->k = K;}static int wm8753_set_dai_pll(struct snd_soc_codec_dai *codec_dai,		int pll_id, unsigned int freq_in, unsigned int freq_out){	u16 reg, enable;	int offset;	struct snd_soc_codec *codec = codec_dai->codec;	if (pll_id < WM8753_PLL1 || pll_id > WM8753_PLL2)		return -ENODEV;	if (pll_id == WM8753_PLL1) {		offset = 0;		enable = 0x10;		reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xffef;	} else {		offset = 4;		enable = 0x8;		reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfff7;	}	if (!freq_in || !freq_out) {		/* disable PLL  */		wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0026);		wm8753_write(codec, WM8753_CLOCK, reg);		return 0;	} else {		u16 value = 0;		struct _pll_div pll_div;		pll_factors(&pll_div, freq_out * 8, freq_in);		/* set up N and K PLL divisor ratios */		/* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */		value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18);		wm8753_write(codec, WM8753_PLL1CTL2 + offset, value);		/* bits 8:0 = PLL_K[17:9] */		value = (pll_div.k & 0x03fe00) >> 9;		wm8753_write(codec, WM8753_PLL1CTL3 + offset, value);		/* bits 8:0 = PLL_K[8:0] */		value = pll_div.k & 0x0001ff;		wm8753_write(codec, WM8753_PLL1CTL4 + offset, value);		/* set PLL as input and enable */		wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 |			(pll_div.div2 << 3));		wm8753_write(codec, WM8753_CLOCK, reg | enable);	}	return 0;}struct _coeff_div {	u32 mclk;	u32 rate;	u8 sr:5;	u8 usb:1;};/* codec hifi mclk (after PLL) clock divider coefficients */static const struct _coeff_div coeff_div[] = {	/* 8k */	{12288000, 8000, 0x6, 0x0},	{11289600, 8000, 0x16, 0x0},	{18432000, 8000, 0x7, 0x0},	{16934400, 8000, 0x17, 0x0},	{12000000, 8000, 0x6, 0x1},	/* 11.025k */	{11289600, 11025, 0x18, 0x0},	{16934400, 11025, 0x19, 0x0},	{12000000, 11025, 0x19, 0x1},	/* 16k */	{12288000, 16000, 0xa, 0x0},	{18432000, 16000, 0xb, 0x0},	{12000000, 16000, 0xa, 0x1},	/* 22.05k */	{11289600, 22050, 0x1a, 0x0},	{16934400, 22050, 0x1b, 0x0},	{12000000, 22050, 0x1b, 0x1},	/* 32k */	{12288000, 32000, 0xc, 0x0},	{18432000, 32000, 0xd, 0x0},	{12000000, 32000, 0xa, 0x1},	/* 44.1k */	{11289600, 44100, 0x10, 0x0},	{16934400, 44100, 0x11, 0x0},	{12000000, 44100, 0x11, 0x1},	/* 48k */	{12288000, 48000, 0x0, 0x0},	{18432000, 48000, 0x1, 0x0},	{12000000, 48000, 0x0, 0x1},	/* 88.2k */	{11289600, 88200, 0x1e, 0x0},	{16934400, 88200, 0x1f, 0x0},	{12000000, 88200, 0x1f, 0x1},	/* 96k */	{12288000, 96000, 0xe, 0x0},	{18432000, 96000, 0xf, 0x0},	{12000000, 96000, 0xe, 0x1},};static int get_coeff(int mclk, int rate){	int i;	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)			return i;	}	return -EINVAL;}/* * Clock after PLL and dividers */static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,		int clk_id, unsigned int freq, int dir){	struct snd_soc_codec *codec = codec_dai->codec;	struct wm8753_priv *wm8753 = codec->private_data;	switch (freq) {	case 11289600:	case 12000000:	case 12288000:	case 16934400:	case 18432000:		if (clk_id == WM8753_MCLK) {			wm8753->sysclk = freq;			return 0;		} else if (clk_id == WM8753_PCMCLK) {			wm8753->pcmclk = freq;			return 0;		}		break;	}	return -EINVAL;}/* * Set's ADC and Voice DAC format. */static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,		unsigned int fmt){	struct snd_soc_codec *codec = codec_dai->codec;	u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01ec;	/* interface format */	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {	case SND_SOC_DAIFMT_I2S:		voice |= 0x0002;		break;	case SND_SOC_DAIFMT_RIGHT_J:		break;	case SND_SOC_DAIFMT_LEFT_J:		voice |= 0x0001;		break;	case SND_SOC_DAIFMT_DSP_A:

⌨️ 快捷键说明

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