13 #include <linux/module.h>
18 #include <linux/i2c.h>
19 #include <linux/slab.h>
31 #define WM8960_VMID_MASK 0x180
32 #define WM8960_VREF 0x40
35 #define WM8960_PWR2_LOUT1 0x40
36 #define WM8960_PWR2_ROUT1 0x20
37 #define WM8960_PWR2_OUT3 0x02
40 #define WM8960_POBCTRL 0x80
41 #define WM8960_BUFDCOPEN 0x10
42 #define WM8960_BUFIOEN 0x08
43 #define WM8960_SOFT_ST 0x04
44 #define WM8960_HPSTBY 0x01
47 #define WM8960_DISOP 0x40
48 #define WM8960_DRES_MASK 0x30
55 static const struct reg_default wm8960_reg_defaults[] = {
109 static bool wm8960_volatile(
struct device *
dev,
unsigned int reg)
130 #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0)
133 static const char *wm8960_polarity[] = {
"No Inversion",
"Left Inverted",
134 "Right Inverted",
"Stereo Inversion"};
135 static const char *wm8960_3d_upper_cutoff[] = {
"High",
"Low"};
136 static const char *wm8960_3d_lower_cutoff[] = {
"Low",
"High"};
137 static const char *wm8960_alcfunc[] = {
"Off",
"Right",
"Left",
"Stereo"};
138 static const char *wm8960_alcmode[] = {
"ALC",
"Limiter"};
140 static const struct soc_enum wm8960_enum[] = {
149 static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
153 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
161 for (i = 2; i <
ARRAY_SIZE(deemph_settings); i++) {
172 dev_dbg(codec->
dev,
"Set deemphasis %d\n", val);
178 static int wm8960_get_deemph(
struct snd_kcontrol *kcontrol,
182 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
184 ucontrol->
value.enumerated.item[0] = wm8960->
deemph;
188 static int wm8960_put_deemph(
struct snd_kcontrol *kcontrol,
192 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
200 return wm8960_set_deemph(codec);
232 SOC_ENUM(
"ADC Polarity", wm8960_enum[0]),
235 SOC_ENUM(
"DAC Polarity", wm8960_enum[2]),
237 wm8960_get_deemph, wm8960_put_deemph),
239 SOC_ENUM(
"3D Filter Upper Cut-Off", wm8960_enum[2]),
240 SOC_ENUM(
"3D Filter Lower Cut-Off", wm8960_enum[3]),
244 SOC_ENUM(
"ALC Function", wm8960_enum[4]),
249 SOC_ENUM(
"ALC Mode", wm8960_enum[5]),
317 wm8960_lin_boost,
ARRAY_SIZE(wm8960_lin_boost)),
319 wm8960_rin_boost,
ARRAY_SIZE(wm8960_rin_boost)),
333 &wm8960_loutput_mixer[0],
336 &wm8960_routput_mixer[0],
369 {
"Left Boost Mixer",
"LINPUT1 Switch",
"LINPUT1" },
370 {
"Left Boost Mixer",
"LINPUT2 Switch",
"LINPUT2" },
371 {
"Left Boost Mixer",
"LINPUT3 Switch",
"LINPUT3" },
373 {
"Left Input Mixer",
"Boost Switch",
"Left Boost Mixer", },
374 {
"Left Input Mixer",
NULL,
"LINPUT1", },
375 {
"Left Input Mixer",
NULL,
"LINPUT2" },
376 {
"Left Input Mixer",
NULL,
"LINPUT3" },
378 {
"Right Boost Mixer",
"RINPUT1 Switch",
"RINPUT1" },
379 {
"Right Boost Mixer",
"RINPUT2 Switch",
"RINPUT2" },
380 {
"Right Boost Mixer",
"RINPUT3 Switch",
"RINPUT3" },
382 {
"Right Input Mixer",
"Boost Switch",
"Right Boost Mixer", },
383 {
"Right Input Mixer",
NULL,
"RINPUT1", },
384 {
"Right Input Mixer",
NULL,
"RINPUT2" },
385 {
"Right Input Mixer",
NULL,
"LINPUT3" },
387 {
"Left ADC",
NULL,
"Left Input Mixer" },
388 {
"Right ADC",
NULL,
"Right Input Mixer" },
390 {
"Left Output Mixer",
"LINPUT3 Switch",
"LINPUT3" },
391 {
"Left Output Mixer",
"Boost Bypass Switch",
"Left Boost Mixer"} ,
392 {
"Left Output Mixer",
"PCM Playback Switch",
"Left DAC" },
394 {
"Right Output Mixer",
"RINPUT3 Switch",
"RINPUT3" },
395 {
"Right Output Mixer",
"Boost Bypass Switch",
"Right Boost Mixer" } ,
396 {
"Right Output Mixer",
"PCM Playback Switch",
"Right DAC" },
398 {
"LOUT1 PGA",
NULL,
"Left Output Mixer" },
399 {
"ROUT1 PGA",
NULL,
"Right Output Mixer" },
401 {
"HP_L",
NULL,
"LOUT1 PGA" },
402 {
"HP_R",
NULL,
"ROUT1 PGA" },
404 {
"Left Speaker PGA",
NULL,
"Left Output Mixer" },
405 {
"Right Speaker PGA",
NULL,
"Right Output Mixer" },
407 {
"Left Speaker Output",
NULL,
"Left Speaker PGA" },
408 {
"Right Speaker Output",
NULL,
"Right Speaker PGA" },
410 {
"SPK_LN",
NULL,
"Left Speaker Output" },
411 {
"SPK_LP",
NULL,
"Left Speaker Output" },
412 {
"SPK_RN",
NULL,
"Right Speaker Output" },
413 {
"SPK_RP",
NULL,
"Right Speaker Output" },
417 {
"Mono Output Mixer",
"Left Switch",
"Left Output Mixer" },
418 {
"Mono Output Mixer",
"Right Switch",
"Right Output Mixer" },
420 {
"OUT3",
NULL,
"Mono Output Mixer", }
424 {
"HP_L",
NULL,
"OUT3 VMID" },
425 {
"HP_R",
NULL,
"OUT3 VMID" },
427 {
"OUT3 VMID",
NULL,
"Left Output Mixer" },
428 {
"OUT3 VMID",
NULL,
"Right Output Mixer" },
434 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
479 static int wm8960_set_dai_fmt(
struct snd_soc_dai *codec_dai,
558 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
577 dev_err(codec->
dev,
"unsupported format %i\n", format);
584 wm8960_set_deemph(codec);
609 static int wm8960_set_bias_level_out3(
struct snd_soc_codec *codec,
612 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
665 static int wm8960_set_bias_level_capless(
struct snd_soc_codec *codec,
668 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
676 switch (codec->
dapm.bias_level) {
691 if (wm8960->
out3 && wm8960->
out3->power)
734 switch (codec->
dapm.bias_level) {
772 #define FIXED_PLL_SIZE ((1 << 24) * 10)
777 unsigned long long Kpart;
778 unsigned int K, Ndiv, Nmod;
780 pr_debug(
"WM8960 PLL: setting %dHz->%dHz\n", source, target);
793 if ((Ndiv < 6) || (Ndiv > 12)) {
794 pr_err(
"WM8960 PLL: Unsupported N=%d\n", Ndiv);
804 K = Kpart & 0xFFFFFFFF;
815 pr_debug(
"WM8960 PLL: N=%x K=%x pre_div=%d\n",
816 pll_div->
n, pll_div->
k, pll_div->
pre_div);
821 static int wm8960_set_dai_pll(
struct snd_soc_dai *codec_dai,
int pll_id,
822 int source,
unsigned int freq_in,
unsigned int freq_out)
829 if (freq_in && freq_out) {
840 if (!freq_in || !freq_out)
864 static int wm8960_set_dai_clkdiv(
struct snd_soc_dai *codec_dai,
898 static int wm8960_set_bias_level(
struct snd_soc_codec *codec,
901 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
906 #define WM8960_RATES SNDRV_PCM_RATE_8000_48000
908 #define WM8960_FORMATS \
909 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
910 SNDRV_PCM_FMTBIT_S24_LE)
913 .hw_params = wm8960_hw_params,
914 .digital_mute = wm8960_mute,
915 .set_fmt = wm8960_set_dai_fmt,
916 .set_clkdiv = wm8960_set_dai_clkdiv,
917 .set_pll = wm8960_set_dai_pll,
921 .name =
"wm8960-hifi",
923 .stream_name =
"Playback",
929 .stream_name =
"Capture",
934 .ops = &wm8960_dai_ops,
935 .symmetric_rates = 1,
940 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
948 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
956 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
963 dev_warn(codec->
dev,
"No platform data supplied\n");
971 dev_err(codec->
dev,
"Failed to set cache I/O: %d\n", ret);
977 dev_err(codec->
dev,
"Failed to issue reset\n");
997 wm8960_add_widgets(codec);
1005 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
1012 .probe = wm8960_probe,
1013 .remove = wm8960_remove,
1014 .suspend = wm8960_suspend,
1015 .resume = wm8960_resume,
1016 .set_bias_level = wm8960_set_bias_level,
1019 static const struct regmap_config wm8960_regmap = {
1024 .reg_defaults = wm8960_reg_defaults,
1025 .num_reg_defaults =
ARRAY_SIZE(wm8960_reg_defaults),
1028 .volatile_reg = wm8960_volatile,
1044 if (IS_ERR(wm8960->
regmap))
1045 return PTR_ERR(wm8960->
regmap);
1051 dev_err(&i2c->
dev,
"Failed to enable LRCM: %d\n",
1057 i2c_set_clientdata(i2c, wm8960);
1060 &soc_codec_dev_wm8960, &wm8960_dai, 1);
1077 static struct i2c_driver wm8960_i2c_driver = {
1082 .probe = wm8960_i2c_probe,
1084 .id_table = wm8960_i2c_id,