24 #include <linux/module.h>
26 #include <linux/kernel.h>
30 #include <linux/i2c.h>
32 #include <linux/slab.h>
58 static u16 wm8940_reg_defaults[] = {
118 static const char *wm8940_companding[] = {
"Off",
"NC",
"u-law",
"A-law" };
119 static const struct soc_enum wm8940_adc_companding_enum
121 static const struct soc_enum wm8940_dac_companding_enum
124 static const char *wm8940_alc_mode_text[] = {
"ALC",
"Limiter"};
125 static const struct soc_enum wm8940_alc_mode_enum
128 static const char *wm8940_mic_bias_level_text[] = {
"0.9",
"0.65"};
129 static const struct soc_enum wm8940_mic_bias_level_enum
132 static const char *wm8940_filter_mode_text[] = {
"Audio",
"Application"};
133 static const struct soc_enum wm8940_filter_mode_enum
150 SOC_ENUM(
"DAC Companding", wm8940_dac_companding_enum),
151 SOC_ENUM(
"ADC Companding", wm8940_adc_companding_enum),
153 SOC_ENUM(
"ALC Mode", wm8940_alc_mode_enum),
156 3, 7, 1, wm8940_alc_max_tlv),
158 0, 7, 0, wm8940_alc_min_tlv),
160 0, 14, 0, wm8940_alc_tar_tlv),
174 4, 9, 1, wm8940_lim_thresh_tlv),
176 0, 12, 0, wm8940_lim_boost_tlv),
180 0, 63, 0, wm8940_pga_vol_tlv),
182 0, 255, 0, wm8940_adc_tlv),
184 0, 255, 0, wm8940_adc_tlv),
185 SOC_ENUM(
"Mic Bias Level", wm8940_mic_bias_level_enum),
187 8, 1, 0, wm8940_capture_boost_vol_tlv),
189 0, 63, 0, wm8940_spk_vol_tlv),
193 8, 1, 1, wm8940_att_tlv),
198 7, 1, 1, wm8940_att_tlv),
201 SOC_ENUM(
"High Pass Filter Mode", wm8940_filter_mode_enum),
225 0, 7, 0, wm8940_boost_vol_tlv),
227 4, 7, 0, wm8940_boost_vol_tlv),
238 &wm8940_speaker_mixer_controls[0],
241 &wm8940_mono_mixer_controls[0],
255 &wm8940_micpga_controls[0],
258 &wm8940_input_boost_controls[0],
269 {
"Mono Mixer",
"PCM Playback Switch",
"DAC"},
270 {
"Mono Mixer",
"Aux Playback Switch",
"Aux Input"},
271 {
"Mono Mixer",
"Line Bypass Switch",
"Boost Mixer"},
274 {
"Speaker Mixer",
"PCM Playback Switch",
"DAC"},
275 {
"Speaker Mixer",
"Aux Playback Switch",
"Aux Input"},
276 {
"Speaker Mixer",
"Line Bypass Switch",
"Boost Mixer"},
279 {
"Mono Out",
NULL,
"Mono Mixer"},
280 {
"MONOOUT",
NULL,
"Mono Out"},
281 {
"SpkN Out",
NULL,
"Speaker Mixer"},
282 {
"SpkP Out",
NULL,
"Speaker Mixer"},
283 {
"SPKOUTN",
NULL,
"SpkN Out"},
284 {
"SPKOUTP",
NULL,
"SpkP Out"},
287 {
"Mic PGA",
"MICN Switch",
"MICN"},
288 {
"Mic PGA",
"MICP Switch",
"MICP"},
289 {
"Mic PGA",
"AUX Switch",
"AUX"},
292 {
"Boost Mixer",
"Mic PGA Switch",
"Mic PGA"},
293 {
"Boost Mixer",
"Mic Volume",
"MICP"},
294 {
"Boost Mixer",
"Aux Volume",
"Aux Input"},
296 {
"ADC",
NULL,
"Boost Mixer"},
314 #define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
316 static int wm8940_set_dai_fmt(
struct snd_soc_dai *codec_dai,
347 iface |= (3 << 3) | (1 << 7);
361 iface |= (1 << 8) | (1 << 7);
388 addcntrl |= (0x5 << 1);
391 addcntrl |= (0x4 << 1);
394 addcntrl |= (0x3 << 1);
397 addcntrl |= (0x2 << 1);
400 addcntrl |= (0x1 << 1);
412 companding = companding | (1 << 5);
446 static int wm8940_set_bias_level(
struct snd_soc_codec *codec,
456 pwr_reg |= (1 << 2) | (1 << 3);
467 pwr_reg |= (1 << 2) | (1 << 3);
474 dev_err(codec->
dev,
"Failed to sync cache: %d\n", ret);
480 pwr_reg |= (1 << 2) | (1 << 3);
504 #define FIXED_PLL_SIZE ((1 << 24) * 10)
507 unsigned long long Kpart;
508 unsigned int K, Ndiv, Nmod;
517 }
else if (Ndiv < 3) {
522 }
else if (Ndiv < 6) {
530 if ((Ndiv < 6) || (Ndiv > 12))
532 "WM8940 N value %d outwith recommended range!d\n",
541 K = Kpart & 0xFFFFFFFF;
554 static int wm8940_set_dai_pll(
struct snd_soc_dai *codec_dai,
int pll_id,
555 int source,
unsigned int freq_in,
unsigned int freq_out)
564 if (freq_in == 0 || freq_out == 0) {
595 static int wm8940_set_dai_sysclk(
struct snd_soc_dai *codec_dai,
596 int clk_id,
unsigned int freq,
int dir)
599 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
613 static int wm8940_set_dai_clkdiv(
struct snd_soc_dai *codec_dai,
637 #define WM8940_RATES SNDRV_PCM_RATE_8000_48000
639 #define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
640 SNDRV_PCM_FMTBIT_S16_LE | \
641 SNDRV_PCM_FMTBIT_S20_3LE | \
642 SNDRV_PCM_FMTBIT_S24_LE | \
643 SNDRV_PCM_FMTBIT_S32_LE)
646 .hw_params = wm8940_i2s_hw_params,
647 .set_sysclk = wm8940_set_dai_sysclk,
648 .digital_mute = wm8940_mute,
649 .set_fmt = wm8940_set_dai_fmt,
650 .set_clkdiv = wm8940_set_dai_clkdiv,
651 .set_pll = wm8940_set_dai_pll,
655 .name =
"wm8940-hifi",
657 .stream_name =
"Playback",
664 .stream_name =
"Capture",
670 .ops = &wm8940_dai_ops,
671 .symmetric_rates = 1,
687 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
694 dev_err(codec->
dev,
"Failed to set cache I/O: %d\n", ret);
700 dev_err(codec->
dev,
"Failed to issue reset\n");
711 dev_warn(codec->
dev,
"No platform data supplied\n");
723 ret = wm8940_add_widgets(codec);
734 .probe = wm8940_probe,
735 .remove = wm8940_remove,
736 .suspend = wm8940_suspend,
737 .resume = wm8940_resume,
738 .set_bias_level = wm8940_set_bias_level,
739 .reg_cache_size =
ARRAY_SIZE(wm8940_reg_defaults),
740 .reg_word_size =
sizeof(
u16),
756 i2c_set_clientdata(i2c, wm8940);
760 &soc_codec_dev_wm8940, &wm8940_dai, 1);
778 static struct i2c_driver wm8940_i2c_driver = {
783 .probe = wm8940_i2c_probe,
785 .id_table = wm8940_i2c_id,