wm8960 linux codec 代码,修改过了,支持录音.doc_第1页
wm8960 linux codec 代码,修改过了,支持录音.doc_第2页
wm8960 linux codec 代码,修改过了,支持录音.doc_第3页
wm8960 linux codec 代码,修改过了,支持录音.doc_第4页
wm8960 linux codec 代码,修改过了,支持录音.doc_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

/* * wm8960.c - WM8960 ALSA SoC Audio driver * * Copyright 2007-11 Wolfson Microelectronics, plc * * Author: Liam Girdwood * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include wm8960.h/* R25 - Power 1 */#define WM8960_VMID_MASK 0x180#define WM8960_VREF 0x40/* R26 - Power 2 */#define WM8960_PWR2_LOUT10x40#define WM8960_PWR2_ROUT10x20#define WM8960_PWR2_OUT30x02/* R28 - Anti-pop 1 */#define WM8960_POBCTRL 0x80#define WM8960_BUFDCOPEN 0x10#define WM8960_BUFIOEN 0x08#define WM8960_SOFT_ST 0x04#define WM8960_HPSTBY 0x01/* R29 - Anti-pop 2 */#define WM8960_DISOP 0x40#define WM8960_DRES_MASK 0x30/* * wm8960 register cache * We cant read the WM8960 register space when we are * using 2 wire for device control, so we cache them instead. */static const u16 wm8960_regWM8960_CACHEREGNUM = 0x0097, 0x0097, 0x0000, 0x0000,0x0000, 0x0008, 0x0000, 0x000a,0x01c0, 0x0000, 0x00ff, 0x00ff,0x0000, 0x0000, 0x0000, 0x0000,0x0000, 0x007b, 0x0100, 0x0032,0x0000, 0x00c3, 0x00c3, 0x01c0,0x0000, 0x0000, 0x0000, 0x0000,0x0000, 0x0000, 0x0000, 0x0000,0x0100, 0x0100, 0x0050, 0x0050,0x0050, 0x0050, 0x0000, 0x0000,0x0000, 0x0000, 0x0040, 0x0000,0x0000, 0x0050, 0x0050, 0x0000,0x0002, 0x0037, 0x004d, 0x0080,0x0008, 0x0031, 0x0026, 0x00e9,;struct wm8960_priv enum snd_soc_control_type control_type;int (*set_bias_level)(struct snd_soc_codec *, enum snd_soc_bias_level level);struct snd_soc_dapm_widget *lout1;struct snd_soc_dapm_widget *rout1;struct snd_soc_dapm_widget *out3;bool deemph;int playback_fs;#define wm8960_reset(c)snd_soc_write(c, WM8960_RESET, 0)/* enumerated controls */static const char *wm8960_polarity = No Inversion, Left Inverted,Right Inverted, Stereo Inversion;static const char *wm8960_3d_upper_cutoff = High, Low;static const char *wm8960_3d_lower_cutoff = Low, High;static const char *wm8960_alcfunc = Off, Right, Left, Stereo;static const char *wm8960_alcmode = ALC, Limiter;static const struct soc_enum wm8960_enum = SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity),SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff),SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff),SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc),SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),;static const int deemph_settings = 0, 32000, 44100, 48000 ;static int wm8960_set_deemph(struct snd_soc_codec *codec)struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);int val, i, best;/* If were using deemphasis select the nearest available sample * rate. */if (wm8960-deemph) best = 1;for (i = 2; i playback_fs) playback_fs)best = i;val = best dev, Set deemphasis %dn, val);return snd_soc_update_bits(codec, WM8960_DACCTL1, 0x6, val);static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);ucontrol-value.enumerated.item0 = wm8960-deemph;return 0;static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);int deemph = ucontrol-value.enumerated.item0;if (deemph 1)return -EINVAL;wm8960-deemph = deemph;return wm8960_set_deemph(codec);static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);static const struct snd_kcontrol_new wm8960_snd_controls = SOC_DOUBLE_R_TLV(Capture Volume, WM8960_LINVOL, WM8960_RINVOL, 0, 63, 0, adc_tlv),SOC_DOUBLE_R(Capture Volume ZC Switch, WM8960_LINVOL, WM8960_RINVOL,6, 1, 0),SOC_DOUBLE_R(Capture Mute Switch, WM8960_LINVOL, WM8960_RINVOL,7, 1, 0),SOC_DOUBLE_R_TLV(Playback Volume, WM8960_LDAC, WM8960_RDAC, 0, 255, 0, dac_tlv),SOC_DOUBLE_R_TLV(ADC Digital Volume, WM8960_LADC, WM8960_RADC, 0, 255, 0, dac_tlv),SOC_DOUBLE_R_TLV(Headphone Playback Volume, WM8960_LOUT1, WM8960_ROUT1, 0, 127, 0, out_tlv),SOC_DOUBLE_R(Headphone Playback ZC Switch, WM8960_LOUT1, WM8960_ROUT1,7, 1, 0),SOC_DOUBLE_R_TLV(Speaker Playback Volume, WM8960_LOUT2, WM8960_ROUT2, 0, 127, 0, out_tlv),SOC_DOUBLE_R(Speaker Playback ZC Switch, WM8960_LOUT2, WM8960_ROUT2,7, 1, 0),SOC_SINGLE(Speaker DC Volume, WM8960_CLASSD3, 3, 5, 0),SOC_SINGLE(Speaker AC Volume, WM8960_CLASSD3, 0, 5, 0),SOC_SINGLE(PCM Playback -6dB Switch, WM8960_DACCTL1, 7, 1, 0),SOC_ENUM(ADC Polarity, wm8960_enum0),SOC_SINGLE(ADC High Pass Filter Switch, WM8960_DACCTL1, 0, 1, 0),SOC_ENUM(DAC Polarity, wm8960_enum2),SOC_SINGLE_BOOL_EXT(DAC Deemphasis Switch, 0, wm8960_get_deemph, wm8960_put_deemph),SOC_ENUM(3D Filter Upper Cut-Off, wm8960_enum2),SOC_ENUM(3D Filter Lower Cut-Off, wm8960_enum3),SOC_SINGLE(3D Volume, WM8960_3D, 1, 15, 0),SOC_SINGLE(3D Switch, WM8960_3D, 0, 1, 0),SOC_ENUM(ALC Function, wm8960_enum4),SOC_SINGLE(ALC Max Gain, WM8960_ALC1, 4, 7, 0),SOC_SINGLE(ALC Target, WM8960_ALC1, 0, 15, 1),SOC_SINGLE(ALC Min Gain, WM8960_ALC2, 4, 7, 0),SOC_SINGLE(ALC Hold Time, WM8960_ALC2, 0, 15, 0),SOC_ENUM(ALC Mode, wm8960_enum5),SOC_SINGLE(ALC Decay, WM8960_ALC3, 4, 15, 0),SOC_SINGLE(ALC Attack, WM8960_ALC3, 0, 15, 0),SOC_SINGLE(Noise Gate Threshold, WM8960_NOISEG, 3, 31, 0),SOC_SINGLE(Noise Gate Switch, WM8960_NOISEG, 0, 1, 0),SOC_DOUBLE_R(Mic Boot Gain, WM8960_LINPATH, WM8960_RINPATH,4, 3, 0),SOC_SINGLE_TLV(Left Output Mixer Boost Bypass Volume, WM8960_BYPASS1, 4, 7, 1, bypass_tlv),SOC_SINGLE_TLV(Left Output Mixer LINPUT3 Volume, WM8960_LOUTMIX, 4, 7, 1, bypass_tlv),SOC_SINGLE_TLV(Right Output Mixer Boost Bypass Volume, WM8960_BYPASS2, 4, 7, 1, bypass_tlv),SOC_SINGLE_TLV(Right Output Mixer RINPUT3 Volume, WM8960_ROUTMIX, 4, 7, 1, bypass_tlv),/add by lyqSOC_SINGLE(MICB Switch, WM8960_POWER1, 1, 1, 0),;static const struct snd_kcontrol_new wm8960_lin_boost = SOC_DAPM_SINGLE(LINPUT2 Switch, WM8960_LINPATH, 6, 1, 0),SOC_DAPM_SINGLE(LINPUT3 Switch, WM8960_LINPATH, 7, 1, 0),SOC_DAPM_SINGLE(LINPUT1 Switch, WM8960_LINPATH, 8, 1, 0),;static const struct snd_kcontrol_new wm8960_lin = SOC_DAPM_SINGLE(Boost Switch, WM8960_LINPATH, 3, 1, 0),;static const struct snd_kcontrol_new wm8960_rin_boost = SOC_DAPM_SINGLE(RINPUT2 Switch, WM8960_RINPATH, 6, 1, 0),SOC_DAPM_SINGLE(RINPUT3 Switch, WM8960_RINPATH, 7, 1, 0),SOC_DAPM_SINGLE(RINPUT1 Switch, WM8960_RINPATH, 8, 1, 0),;static const struct snd_kcontrol_new wm8960_rin = SOC_DAPM_SINGLE(Boost Switch, WM8960_RINPATH, 3, 1, 0),;static const struct snd_kcontrol_new wm8960_loutput_mixer = SOC_DAPM_SINGLE(PCM Playback Switch, WM8960_LOUTMIX, 8, 1, 0),SOC_DAPM_SINGLE(LINPUT3 Switch, WM8960_LOUTMIX, 7, 1, 0),SOC_DAPM_SINGLE(Boost Bypass Switch, WM8960_BYPASS1, 7, 1, 0),;static const struct snd_kcontrol_new wm8960_routput_mixer = SOC_DAPM_SINGLE(PCM Playback Switch, WM8960_ROUTMIX, 8, 1, 0),SOC_DAPM_SINGLE(RINPUT3 Switch, WM8960_ROUTMIX, 7, 1, 0),SOC_DAPM_SINGLE(Boost Bypass Switch, WM8960_BYPASS2, 7, 1, 0),;static const struct snd_kcontrol_new wm8960_mono_out = SOC_DAPM_SINGLE(Left Switch, WM8960_MONOMIX1, 7, 1, 0),SOC_DAPM_SINGLE(Right Switch, WM8960_MONOMIX2, 7, 1, 0),;static const struct snd_soc_dapm_widget wm8960_dapm_widgets = SND_SOC_DAPM_INPUT(LINPUT1),SND_SOC_DAPM_INPUT(RINPUT1),SND_SOC_DAPM_INPUT(LINPUT2),SND_SOC_DAPM_INPUT(RINPUT2),SND_SOC_DAPM_INPUT(LINPUT3),SND_SOC_DAPM_INPUT(RINPUT3),SND_SOC_DAPM_SUPPLY(MICB, WM8960_POWER1, 1, 0, NULL, 0),SND_SOC_DAPM_MIXER(Left Boost Mixer, WM8960_POWER1, 5, 0, wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost),SND_SOC_DAPM_MIXER(Right Boost Mixer, WM8960_POWER1, 4, 0, wm8960_rin_boost, ARRAY_SIZE(wm8960_rin_boost),SND_SOC_DAPM_MIXER(Left Input Mixer, WM8960_POWER3, 5, 0, wm8960_lin, ARRAY_SIZE(wm8960_lin),SND_SOC_DAPM_MIXER(Right Input Mixer, WM8960_POWER3, 4, 0, wm8960_rin, ARRAY_SIZE(wm8960_rin),SND_SOC_DAPM_ADC(Left ADC, Capture, WM8960_POWER1, 3, 0),SND_SOC_DAPM_ADC(Right ADC, Capture, WM8960_POWER1, 2, 0),SND_SOC_DAPM_DAC(Left DAC, Playback, WM8960_POWER2, 8, 0),SND_SOC_DAPM_DAC(Right DAC, Playback, WM8960_POWER2, 7, 0),SND_SOC_DAPM_MIXER(Left Output Mixer, WM8960_POWER3, 3, 0,&wm8960_loutput_mixer0,ARRAY_SIZE(wm8960_loutput_mixer),SND_SOC_DAPM_MIXER(Right Output Mixer, WM8960_POWER3, 2, 0,&wm8960_routput_mixer0,ARRAY_SIZE(wm8960_routput_mixer),SND_SOC_DAPM_PGA(LOUT1 PGA, WM8960_POWER2, 6, 0, NULL, 0),SND_SOC_DAPM_PGA(ROUT1 PGA, WM8960_POWER2, 5, 0, NULL, 0),SND_SOC_DAPM_PGA(Left Speaker PGA, WM8960_POWER2, 4, 0, NULL, 0),SND_SOC_DAPM_PGA(Right Speaker PGA, WM8960_POWER2, 3, 0, NULL, 0),SND_SOC_DAPM_PGA(Right Speaker Output, WM8960_CLASSD1, 7, 0, NULL, 0),SND_SOC_DAPM_PGA(Left Speaker Output, WM8960_CLASSD1, 6, 0, NULL, 0),SND_SOC_DAPM_OUTPUT(SPK_LP),SND_SOC_DAPM_OUTPUT(SPK_LN),SND_SOC_DAPM_OUTPUT(HP_L),SND_SOC_DAPM_OUTPUT(HP_R),SND_SOC_DAPM_OUTPUT(SPK_RP),SND_SOC_DAPM_OUTPUT(SPK_RN),SND_SOC_DAPM_OUTPUT(OUT3),;static const struct snd_soc_dapm_widget wm8960_dapm_widgets_out3 = SND_SOC_DAPM_MIXER(Mono Output Mixer, WM8960_POWER2, 1, 0,&wm8960_mono_out0,ARRAY_SIZE(wm8960_mono_out),;/* Represent OUT3 as a PGA so that it gets turned on with LOUT1/ROUT1 */static const struct snd_soc_dapm_widget wm8960_dapm_widgets_capless = SND_SOC_DAPM_PGA(OUT3 VMID, WM8960_POWER2, 1, 0, NULL, 0),;static const struct snd_soc_dapm_route audio_paths = Left Boost Mixer, LINPUT1 Switch, LINPUT1 , Left Boost Mixer, LINPUT2 Switch, LINPUT2 , Left Boost Mixer, LINPUT3 Switch, LINPUT3 , Left Input Mixer, Boost Switch, Left Boost Mixer, , Left Input Mixer, NULL, LINPUT1, , /* Really Boost Switch */ Left Input Mixer, NULL, LINPUT2 , Left Input Mixer, NULL, LINPUT3 , Right Boost Mixer, RINPUT1 Switch, RINPUT1 , Right Boost Mixer, RINPUT2 Switch, RINPUT2 , Right Boost Mixer, RINPUT3 Switch, RINPUT3 , Right Input Mixer, Boost Switch, Right Boost Mixer, , Right Input Mixer, NULL, RINPUT1, , /* Really Boost Switch */ Right Input Mixer, NULL, RINPUT2 , Right Input Mixer, NULL, LINPUT3 , Left ADC, NULL, Left Input Mixer , Right ADC, NULL, Right Input Mixer , Left Output Mixer, LINPUT3 Switch, LINPUT3 , Left Output Mixer, Boost Bypass Switch, Left Boost Mixer , Left Output Mixer, PCM Playback Switch, Left DAC , Right Output Mixer, RINPUT3 Switch, RINPUT3 , Right Output Mixer, Boost Bypass Switch, Right Boost Mixer , Right Output Mixer, PCM Playback Switch, Right DAC , LOUT1 PGA, NULL, Left Output Mixer , ROUT1 PGA, NULL, Right Output Mixer , HP_L, NULL, LOUT1 PGA , HP_R, NULL, ROUT1 PGA , Left Speaker PGA, NULL, Left Output Mixer , Right Speaker PGA, NULL, Right Output Mixer , Left Speaker Output, NULL, Left Speaker PGA , Right Speaker Output, NULL, Right Speaker PGA , SPK_LN, NULL, Left Speaker Output , SPK_LP, NULL, Left Speaker Output , SPK_RN, NULL, Right Speaker Output , SPK_RP, NULL, Right Speaker Output ,;static const struct snd_soc_dapm_route audio_paths_out3 = Mono Output Mixer, Left Switch, Left Output Mixer , Mono Output Mixer, Right Switch, Right Output Mixer , OUT3, NULL, Mono Output Mixer, ;static const struct snd_soc_dapm_route audio_paths_capless = HP_L, NULL, OUT3 VMID , HP_R, NULL, OUT3 VMID , OUT3 VMID, NULL, Left Output Mixer , OUT3 VMID, NULL, Right Output Mixer ,;static int wm8960_add_widgets(struct snd_soc_codec *codec)struct wm8960_data *pdata = codec-dev-platform_data;struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);struct snd_soc_dapm_context *dapm = &codec-dapm;struct snd_soc_dapm_widget *w;snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets, ARRAY_SIZE(wm8960_dapm_widgets);snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths);/* In capless mode OUT3 is used to provide VMID for the * headphone outputs, otherwise it is used as a mono mixer. */if (pdata & pdata-capless) snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets_capless, ARRAY_SIZE(wm8960_dapm_widgets_capless);snd_soc_dapm_add_routes(dapm, audio_paths_capless,ARRAY_SIZE(audio_paths_capless); else snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets_out3, ARRAY_SIZE(wm8960_dapm_widgets_out3);snd_soc_dapm_add_routes(dapm, audio_paths_out3,ARRAY_SIZE(audio_paths_out3);/* We need to power up the headphone output stage out of * sequence for capless mode. To save scanning the widget * list each time to find the desired power state do so now * and save the result. */list_for_each_entry(w, &codec-card-widgets, list) if (w-dapm != &codec-dapm)continue;if (strcmp(w-name, LOUT1 PGA) = 0)wm8960-lout1 = w;if (strcmp(w-name, ROUT1 PGA) = 0)wm8960-rout1 = w;if (strcmp(w-name, OUT3 VMID) = 0)wm8960-out3 = w;return 0;static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,unsigned int fmt)struct snd_soc_codec *codec = codec_dai-codec;u16 iface = 0;/* set master/slave audio interface */switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) case SND_SOC_DAIFMT_CBM_CFM:iface |= 0x0040;break;case SND_SOC_DAIFMT_CBS_CFS:break;default:return -EINVAL;/* interface format */switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) case SND_SOC_DAIFMT_I2S:iface |= 0x0002;break;case SND_SOC_DAIFMT_RIGHT_J:break;case SND_SOC_DAIFMT_LEFT_J:iface |= 0x0001;break;case SND_SOC_DAIFMT_DSP_A:iface |= 0x0003;break;case SND_SOC_DAIFMT_DSP_B:iface |= 0x0013;break;default:return -EINVAL;/* clock inversion */switch (fmt & SND_SOC_DAIFMT_INV_MASK) case SND_SOC_DAIFMT_NB_NF:break;case SND_SOC_DAIFMT_IB_IF:iface |= 0x0090;break;case SND_SOC_DAIFMT_IB_NF:iface |= 0x0080;break;case SND_SOC_DAIFMT_NB_IF:iface |= 0x0010;break;default:return -EINVAL;/* set iface */snd_soc_write(codec, WM8960_IFACE1, iface);return 0;static struct int rate;unsigned int val; alc_rates = 48000, 0 , 44100, 0 , 32000, 1 , 22050, 2 , 24000, 2 , 16000, 3 , 11250, 4 , 12000, 4 , 8000, 5 ,;static int wm8960_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)struct snd_soc_codec *codec = dai-codec;struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;int i;/* bit size */switch (params_format(params) case SNDRV_PCM_FORMAT_S16_LE:break;case SNDRV_PCM_FORMAT_S20_3LE:iface |= 0x0004;break;case SNDRV_PCM_FORMAT_S24_LE:iface |= 0x0008;break;/* Update filters for the new rate */if (substream-stream = SNDRV_PCM_STREAM_PLAYBACK) wm8960-playback_fs = params_rate(params);wm8960_set_deemph(codec); else for (i = 0; i codec;if (mute)snd_soc_update_bits(codec, WM8960_DACCTL1, 0x8, 0x8);elsesnd_soc_update_bits(codec, WM8960_DACCTL1, 0x8, 0);return 0;static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, enum snd_soc_bias_level level)switch (level) case SND_SOC_BIAS_ON:break;case SND_SOC_BIAS_PREPARE:/* Set VMID to 2x50k */snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);break;case SND_S

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论