diff options
Diffstat (limited to 'sound/soc/codecs/wm9713.c')
-rw-r--r-- | sound/soc/codecs/wm9713.c | 230 |
1 files changed, 131 insertions, 99 deletions
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index bddee30a4bc7..5df7f6d12bef 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -30,7 +30,10 @@ | |||
30 | #include "wm9713.h" | 30 | #include "wm9713.h" |
31 | 31 | ||
32 | struct wm9713_priv { | 32 | struct wm9713_priv { |
33 | struct snd_ac97 *ac97; | ||
33 | u32 pll_in; /* PLL input frequency */ | 34 | u32 pll_in; /* PLL input frequency */ |
35 | unsigned int hp_mixer[2]; | ||
36 | struct mutex lock; | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 39 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
@@ -59,13 +62,10 @@ static const u16 wm9713_reg[] = { | |||
59 | 0x0000, 0x0000, 0x0000, 0x0000, | 62 | 0x0000, 0x0000, 0x0000, 0x0000, |
60 | 0x0000, 0x0000, 0x0000, 0x0006, | 63 | 0x0000, 0x0000, 0x0000, 0x0006, |
61 | 0x0001, 0x0000, 0x574d, 0x4c13, | 64 | 0x0001, 0x0000, 0x574d, 0x4c13, |
62 | 0x0000, 0x0000, 0x0000 | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | /* virtual HP mixers regs */ | 67 | #define HPL_MIXER 0 |
66 | #define HPL_MIXER 0x80 | 68 | #define HPR_MIXER 1 |
67 | #define HPR_MIXER 0x82 | ||
68 | #define MICB_MUX 0x82 | ||
69 | 69 | ||
70 | static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; | 70 | static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; |
71 | static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; | 71 | static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; |
@@ -110,7 +110,7 @@ SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 10, 8, wm9713_dac_inv), /* dac invert 2 15 */ | |||
110 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */ | 110 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */ |
111 | SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */ | 111 | SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */ |
112 | SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */ | 112 | SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */ |
113 | SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */ | 113 | SOC_ENUM_SINGLE_VIRT(2, wm9713_micb_select), /* mic selection 19 */ |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); | 116 | static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); |
@@ -234,6 +234,14 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, | |||
234 | return 0; | 234 | return 0; |
235 | } | 235 | } |
236 | 236 | ||
237 | static const unsigned int wm9713_mixer_mute_regs[] = { | ||
238 | AC97_PC_BEEP, | ||
239 | AC97_MASTER_TONE, | ||
240 | AC97_PHONE, | ||
241 | AC97_REC_SEL, | ||
242 | AC97_PCM, | ||
243 | AC97_AUX, | ||
244 | }; | ||
237 | 245 | ||
238 | /* We have to create a fake left and right HP mixers because | 246 | /* We have to create a fake left and right HP mixers because |
239 | * the codec only has a single control that is shared by both channels. | 247 | * the codec only has a single control that is shared by both channels. |
@@ -241,73 +249,95 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, | |||
241 | * register map, thus we add a new (virtual) register to help determine the | 249 | * register map, thus we add a new (virtual) register to help determine the |
242 | * audio route within the device. | 250 | * audio route within the device. |
243 | */ | 251 | */ |
244 | static int mixer_event(struct snd_soc_dapm_widget *w, | 252 | static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, |
245 | struct snd_kcontrol *kcontrol, int event) | 253 | struct snd_ctl_elem_value *ucontrol) |
246 | { | 254 | { |
247 | u16 l, r, beep, tone, phone, rec, pcm, aux; | 255 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
248 | 256 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | |
249 | l = ac97_read(w->codec, HPL_MIXER); | 257 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
250 | r = ac97_read(w->codec, HPR_MIXER); | 258 | unsigned int val = ucontrol->value.enumerated.item[0]; |
251 | beep = ac97_read(w->codec, AC97_PC_BEEP); | 259 | struct soc_mixer_control *mc = |
252 | tone = ac97_read(w->codec, AC97_MASTER_TONE); | 260 | (struct soc_mixer_control *)kcontrol->private_value; |
253 | phone = ac97_read(w->codec, AC97_PHONE); | 261 | unsigned int mixer, mask, shift, old; |
254 | rec = ac97_read(w->codec, AC97_REC_SEL); | 262 | struct snd_soc_dapm_update update; |
255 | pcm = ac97_read(w->codec, AC97_PCM); | 263 | bool change; |
256 | aux = ac97_read(w->codec, AC97_AUX); | 264 | |
257 | 265 | mixer = mc->shift >> 8; | |
258 | if (event & SND_SOC_DAPM_PRE_REG) | 266 | shift = mc->shift & 0xff; |
259 | return 0; | 267 | mask = (1 << shift); |
260 | if ((l & 0x1) || (r & 0x1)) | 268 | |
261 | ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); | 269 | mutex_lock(&wm9713->lock); |
270 | old = wm9713->hp_mixer[mixer]; | ||
271 | if (ucontrol->value.enumerated.item[0]) | ||
272 | wm9713->hp_mixer[mixer] |= mask; | ||
262 | else | 273 | else |
263 | ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); | 274 | wm9713->hp_mixer[mixer] &= ~mask; |
275 | |||
276 | change = old != wm9713->hp_mixer[mixer]; | ||
277 | if (change) { | ||
278 | update.kcontrol = kcontrol; | ||
279 | update.reg = wm9713_mixer_mute_regs[shift]; | ||
280 | update.mask = 0x8000; | ||
281 | if ((wm9713->hp_mixer[0] & mask) || | ||
282 | (wm9713->hp_mixer[1] & mask)) | ||
283 | update.val = 0x0; | ||
284 | else | ||
285 | update.val = 0x8000; | ||
286 | |||
287 | snd_soc_dapm_mixer_update_power(dapm, kcontrol, val, | ||
288 | &update); | ||
289 | } | ||
264 | 290 | ||
265 | if ((l & 0x2) || (r & 0x2)) | 291 | mutex_unlock(&wm9713->lock); |
266 | ac97_write(w->codec, AC97_MASTER_TONE, tone & 0x7fff); | ||
267 | else | ||
268 | ac97_write(w->codec, AC97_MASTER_TONE, tone | 0x8000); | ||
269 | 292 | ||
270 | if ((l & 0x4) || (r & 0x4)) | 293 | return change; |
271 | ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); | 294 | } |
272 | else | ||
273 | ac97_write(w->codec, AC97_PHONE, phone | 0x8000); | ||
274 | 295 | ||
275 | if ((l & 0x8) || (r & 0x8)) | 296 | static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol, |
276 | ac97_write(w->codec, AC97_REC_SEL, rec & 0x7fff); | 297 | struct snd_ctl_elem_value *ucontrol) |
277 | else | 298 | { |
278 | ac97_write(w->codec, AC97_REC_SEL, rec | 0x8000); | 299 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
300 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | ||
301 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
302 | struct soc_mixer_control *mc = | ||
303 | (struct soc_mixer_control *)kcontrol->private_value; | ||
304 | unsigned int mixer, shift; | ||
279 | 305 | ||
280 | if ((l & 0x10) || (r & 0x10)) | 306 | mixer = mc->shift >> 8; |
281 | ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); | 307 | shift = mc->shift & 0xff; |
282 | else | ||
283 | ac97_write(w->codec, AC97_PCM, pcm | 0x8000); | ||
284 | 308 | ||
285 | if ((l & 0x20) || (r & 0x20)) | 309 | ucontrol->value.enumerated.item[0] = |
286 | ac97_write(w->codec, AC97_AUX, aux & 0x7fff); | 310 | (wm9713->hp_mixer[mixer] >> shift) & 1; |
287 | else | ||
288 | ac97_write(w->codec, AC97_AUX, aux | 0x8000); | ||
289 | 311 | ||
290 | return 0; | 312 | return 0; |
291 | } | 313 | } |
292 | 314 | ||
315 | #define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \ | ||
316 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
317 | .info = snd_soc_info_volsw, \ | ||
318 | .get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \ | ||
319 | .private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \ | ||
320 | xshift, xmixer, 1, 0, 0) \ | ||
321 | } | ||
322 | |||
293 | /* Left Headphone Mixers */ | 323 | /* Left Headphone Mixers */ |
294 | static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { | 324 | static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { |
295 | SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0), | 325 | WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPL_MIXER, 5), |
296 | SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0), | 326 | WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPL_MIXER, 4), |
297 | SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0), | 327 | WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 3), |
298 | SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0), | 328 | WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 2), |
299 | SOC_DAPM_SINGLE("MonoIn Playback Switch", HPL_MIXER, 1, 1, 0), | 329 | WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPL_MIXER, 1), |
300 | SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0), | 330 | WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPL_MIXER, 0), |
301 | }; | 331 | }; |
302 | 332 | ||
303 | /* Right Headphone Mixers */ | 333 | /* Right Headphone Mixers */ |
304 | static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { | 334 | static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { |
305 | SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0), | 335 | WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPR_MIXER, 5), |
306 | SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0), | 336 | WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPR_MIXER, 4), |
307 | SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0), | 337 | WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 3), |
308 | SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0), | 338 | WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 2), |
309 | SOC_DAPM_SINGLE("MonoIn Playback Switch", HPR_MIXER, 1, 1, 0), | 339 | WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPR_MIXER, 1), |
310 | SOC_DAPM_SINGLE("Bypass Playback Switch", HPR_MIXER, 0, 1, 0), | 340 | WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPR_MIXER, 0), |
311 | }; | 341 | }; |
312 | 342 | ||
313 | /* headphone capture mux */ | 343 | /* headphone capture mux */ |
@@ -429,12 +459,10 @@ SND_SOC_DAPM_MUX("Mic A Source", SND_SOC_NOPM, 0, 0, | |||
429 | &wm9713_mic_sel_mux_controls), | 459 | &wm9713_mic_sel_mux_controls), |
430 | SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0, | 460 | SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0, |
431 | &wm9713_micb_sel_mux_controls), | 461 | &wm9713_micb_sel_mux_controls), |
432 | SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, | 462 | SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, |
433 | &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls), | 463 | &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls)), |
434 | mixer_event, SND_SOC_DAPM_POST_REG), | 464 | SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, |
435 | SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, | 465 | &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls)), |
436 | &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls), | ||
437 | mixer_event, SND_SOC_DAPM_POST_REG), | ||
438 | SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1, | 466 | SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1, |
439 | &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)), | 467 | &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)), |
440 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1, | 468 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1, |
@@ -647,12 +675,13 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = { | |||
647 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 675 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
648 | unsigned int reg) | 676 | unsigned int reg) |
649 | { | 677 | { |
678 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
650 | u16 *cache = codec->reg_cache; | 679 | u16 *cache = codec->reg_cache; |
651 | 680 | ||
652 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | 681 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || |
653 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | 682 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || |
654 | reg == AC97_CD) | 683 | reg == AC97_CD) |
655 | return soc_ac97_ops->read(codec->ac97, reg); | 684 | return soc_ac97_ops->read(wm9713->ac97, reg); |
656 | else { | 685 | else { |
657 | reg = reg >> 1; | 686 | reg = reg >> 1; |
658 | 687 | ||
@@ -666,9 +695,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
666 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 695 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
667 | unsigned int val) | 696 | unsigned int val) |
668 | { | 697 | { |
698 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
699 | |||
669 | u16 *cache = codec->reg_cache; | 700 | u16 *cache = codec->reg_cache; |
670 | if (reg < 0x7c) | 701 | soc_ac97_ops->write(wm9713->ac97, reg, val); |
671 | soc_ac97_ops->write(codec->ac97, reg, val); | ||
672 | reg = reg >> 1; | 702 | reg = reg >> 1; |
673 | if (reg < (ARRAY_SIZE(wm9713_reg))) | 703 | if (reg < (ARRAY_SIZE(wm9713_reg))) |
674 | cache[reg] = val; | 704 | cache[reg] = val; |
@@ -689,7 +719,8 @@ struct _pll_div { | |||
689 | * to allow rounding later */ | 719 | * to allow rounding later */ |
690 | #define FIXED_PLL_SIZE ((1 << 22) * 10) | 720 | #define FIXED_PLL_SIZE ((1 << 22) * 10) |
691 | 721 | ||
692 | static void pll_factors(struct _pll_div *pll_div, unsigned int source) | 722 | static void pll_factors(struct snd_soc_codec *codec, |
723 | struct _pll_div *pll_div, unsigned int source) | ||
693 | { | 724 | { |
694 | u64 Kpart; | 725 | u64 Kpart; |
695 | unsigned int K, Ndiv, Nmod, target; | 726 | unsigned int K, Ndiv, Nmod, target; |
@@ -724,7 +755,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source) | |||
724 | 755 | ||
725 | Ndiv = target / source; | 756 | Ndiv = target / source; |
726 | if ((Ndiv < 5) || (Ndiv > 12)) | 757 | if ((Ndiv < 5) || (Ndiv > 12)) |
727 | printk(KERN_WARNING | 758 | dev_warn(codec->dev, |
728 | "WM9713 PLL N value %u out of recommended range!\n", | 759 | "WM9713 PLL N value %u out of recommended range!\n", |
729 | Ndiv); | 760 | Ndiv); |
730 | 761 | ||
@@ -768,7 +799,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
768 | return 0; | 799 | return 0; |
769 | } | 800 | } |
770 | 801 | ||
771 | pll_factors(&pll_div, freq_in); | 802 | pll_factors(codec, &pll_div, freq_in); |
772 | 803 | ||
773 | if (pll_div.k == 0) { | 804 | if (pll_div.k == 0) { |
774 | reg = (pll_div.n << 12) | (pll_div.lf << 11) | | 805 | reg = (pll_div.n << 12) | (pll_div.lf << 11) | |
@@ -1049,7 +1080,6 @@ static const struct snd_soc_dai_ops wm9713_dai_ops_voice = { | |||
1049 | static struct snd_soc_dai_driver wm9713_dai[] = { | 1080 | static struct snd_soc_dai_driver wm9713_dai[] = { |
1050 | { | 1081 | { |
1051 | .name = "wm9713-hifi", | 1082 | .name = "wm9713-hifi", |
1052 | .ac97_control = 1, | ||
1053 | .playback = { | 1083 | .playback = { |
1054 | .stream_name = "HiFi Playback", | 1084 | .stream_name = "HiFi Playback", |
1055 | .channels_min = 1, | 1085 | .channels_min = 1, |
@@ -1095,17 +1125,22 @@ static struct snd_soc_dai_driver wm9713_dai[] = { | |||
1095 | 1125 | ||
1096 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm) | 1126 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm) |
1097 | { | 1127 | { |
1128 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
1129 | |||
1098 | if (try_warm && soc_ac97_ops->warm_reset) { | 1130 | if (try_warm && soc_ac97_ops->warm_reset) { |
1099 | soc_ac97_ops->warm_reset(codec->ac97); | 1131 | soc_ac97_ops->warm_reset(wm9713->ac97); |
1100 | if (ac97_read(codec, 0) == wm9713_reg[0]) | 1132 | if (ac97_read(codec, 0) == wm9713_reg[0]) |
1101 | return 1; | 1133 | return 1; |
1102 | } | 1134 | } |
1103 | 1135 | ||
1104 | soc_ac97_ops->reset(codec->ac97); | 1136 | soc_ac97_ops->reset(wm9713->ac97); |
1105 | if (soc_ac97_ops->warm_reset) | 1137 | if (soc_ac97_ops->warm_reset) |
1106 | soc_ac97_ops->warm_reset(codec->ac97); | 1138 | soc_ac97_ops->warm_reset(wm9713->ac97); |
1107 | if (ac97_read(codec, 0) != wm9713_reg[0]) | 1139 | if (ac97_read(codec, 0) != wm9713_reg[0]) { |
1140 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); | ||
1108 | return -EIO; | 1141 | return -EIO; |
1142 | } | ||
1143 | |||
1109 | return 0; | 1144 | return 0; |
1110 | } | 1145 | } |
1111 | EXPORT_SYMBOL_GPL(wm9713_reset); | 1146 | EXPORT_SYMBOL_GPL(wm9713_reset); |
@@ -1163,10 +1198,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1163 | u16 *cache = codec->reg_cache; | 1198 | u16 *cache = codec->reg_cache; |
1164 | 1199 | ||
1165 | ret = wm9713_reset(codec, 1); | 1200 | ret = wm9713_reset(codec, 1); |
1166 | if (ret < 0) { | 1201 | if (ret < 0) |
1167 | printk(KERN_ERR "could not reset AC97 codec\n"); | ||
1168 | return ret; | 1202 | return ret; |
1169 | } | ||
1170 | 1203 | ||
1171 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1204 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1172 | 1205 | ||
@@ -1180,7 +1213,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1180 | if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || | 1213 | if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || |
1181 | i == AC97_EXTENDED_MSTATUS || i > 0x66) | 1214 | i == AC97_EXTENDED_MSTATUS || i > 0x66) |
1182 | continue; | 1215 | continue; |
1183 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); | 1216 | soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]); |
1184 | } | 1217 | } |
1185 | } | 1218 | } |
1186 | 1219 | ||
@@ -1189,50 +1222,36 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1189 | 1222 | ||
1190 | static int wm9713_soc_probe(struct snd_soc_codec *codec) | 1223 | static int wm9713_soc_probe(struct snd_soc_codec *codec) |
1191 | { | 1224 | { |
1192 | struct wm9713_priv *wm9713; | 1225 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
1193 | int ret = 0, reg; | 1226 | int ret = 0, reg; |
1194 | 1227 | ||
1195 | wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL); | 1228 | wm9713->ac97 = snd_soc_new_ac97_codec(codec); |
1196 | if (wm9713 == NULL) | 1229 | if (IS_ERR(wm9713->ac97)) |
1197 | return -ENOMEM; | 1230 | return PTR_ERR(wm9713->ac97); |
1198 | snd_soc_codec_set_drvdata(codec, wm9713); | ||
1199 | |||
1200 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | ||
1201 | if (ret < 0) | ||
1202 | goto codec_err; | ||
1203 | 1231 | ||
1204 | /* do a cold reset for the controller and then try | 1232 | /* do a cold reset for the controller and then try |
1205 | * a warm reset followed by an optional cold reset for codec */ | 1233 | * a warm reset followed by an optional cold reset for codec */ |
1206 | wm9713_reset(codec, 0); | 1234 | wm9713_reset(codec, 0); |
1207 | ret = wm9713_reset(codec, 1); | 1235 | ret = wm9713_reset(codec, 1); |
1208 | if (ret < 0) { | 1236 | if (ret < 0) |
1209 | printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n"); | ||
1210 | goto reset_err; | 1237 | goto reset_err; |
1211 | } | ||
1212 | |||
1213 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1214 | 1238 | ||
1215 | /* unmute the adc - move to kcontrol */ | 1239 | /* unmute the adc - move to kcontrol */ |
1216 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1240 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
1217 | ac97_write(codec, AC97_CD, reg); | 1241 | ac97_write(codec, AC97_CD, reg); |
1218 | 1242 | ||
1219 | snd_soc_add_codec_controls(codec, wm9713_snd_ac97_controls, | ||
1220 | ARRAY_SIZE(wm9713_snd_ac97_controls)); | ||
1221 | |||
1222 | return 0; | 1243 | return 0; |
1223 | 1244 | ||
1224 | reset_err: | 1245 | reset_err: |
1225 | snd_soc_free_ac97_codec(codec); | 1246 | snd_soc_free_ac97_codec(wm9713->ac97); |
1226 | codec_err: | ||
1227 | kfree(wm9713); | ||
1228 | return ret; | 1247 | return ret; |
1229 | } | 1248 | } |
1230 | 1249 | ||
1231 | static int wm9713_soc_remove(struct snd_soc_codec *codec) | 1250 | static int wm9713_soc_remove(struct snd_soc_codec *codec) |
1232 | { | 1251 | { |
1233 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | 1252 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
1234 | snd_soc_free_ac97_codec(codec); | 1253 | |
1235 | kfree(wm9713); | 1254 | snd_soc_free_ac97_codec(wm9713->ac97); |
1236 | return 0; | 1255 | return 0; |
1237 | } | 1256 | } |
1238 | 1257 | ||
@@ -1248,6 +1267,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { | |||
1248 | .reg_word_size = sizeof(u16), | 1267 | .reg_word_size = sizeof(u16), |
1249 | .reg_cache_step = 2, | 1268 | .reg_cache_step = 2, |
1250 | .reg_cache_default = wm9713_reg, | 1269 | .reg_cache_default = wm9713_reg, |
1270 | |||
1271 | .controls = wm9713_snd_ac97_controls, | ||
1272 | .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls), | ||
1251 | .dapm_widgets = wm9713_dapm_widgets, | 1273 | .dapm_widgets = wm9713_dapm_widgets, |
1252 | .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), | 1274 | .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), |
1253 | .dapm_routes = wm9713_audio_map, | 1275 | .dapm_routes = wm9713_audio_map, |
@@ -1256,6 +1278,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { | |||
1256 | 1278 | ||
1257 | static int wm9713_probe(struct platform_device *pdev) | 1279 | static int wm9713_probe(struct platform_device *pdev) |
1258 | { | 1280 | { |
1281 | struct wm9713_priv *wm9713; | ||
1282 | |||
1283 | wm9713 = devm_kzalloc(&pdev->dev, sizeof(*wm9713), GFP_KERNEL); | ||
1284 | if (wm9713 == NULL) | ||
1285 | return -ENOMEM; | ||
1286 | |||
1287 | mutex_init(&wm9713->lock); | ||
1288 | |||
1289 | platform_set_drvdata(pdev, wm9713); | ||
1290 | |||
1259 | return snd_soc_register_codec(&pdev->dev, | 1291 | return snd_soc_register_codec(&pdev->dev, |
1260 | &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai)); | 1292 | &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai)); |
1261 | } | 1293 | } |