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 + -
显示快捷键?