diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-07-30 12:09:04 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-07-30 12:09:04 -0400 |
commit | 03cb2dafcbde938ed7d01d4b952ea60e3c4e8532 (patch) | |
tree | f23bf4a9f5a45b174f891b472ac1f2c2e2c2c7cc /sound | |
parent | d195658bd785e9384d2f70937034ceb13d5e4bcc (diff) | |
parent | 3a38516750e176a18f76d605b401fbab2c72d648 (diff) |
Merge branch 'topic/hda-cirrus' into topic/hda
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/Kconfig | 13 | ||||
-rw-r--r-- | sound/pci/hda/Makefile | 4 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 1194 |
4 files changed, 1212 insertions, 0 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index b8a77f9b0827..55545e0818b5 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
@@ -148,6 +148,19 @@ config SND_HDA_ELD | |||
148 | def_bool y | 148 | def_bool y |
149 | depends on SND_HDA_CODEC_INTELHDMI | 149 | depends on SND_HDA_CODEC_INTELHDMI |
150 | 150 | ||
151 | config SND_HDA_CODEC_CIRRUS | ||
152 | bool "Build Cirrus Logic codec support" | ||
153 | depends on SND_HDA_INTEL | ||
154 | default y | ||
155 | help | ||
156 | Say Y here to include Cirrus Logic codec support in | ||
157 | snd-hda-intel driver, such as CS4206. | ||
158 | |||
159 | When the HD-audio driver is built as a module, the codec | ||
160 | support code is also built as another module, | ||
161 | snd-hda-codec-cirrus. | ||
162 | This module is automatically loaded at probing. | ||
163 | |||
151 | config SND_HDA_CODEC_CONEXANT | 164 | config SND_HDA_CODEC_CONEXANT |
152 | bool "Build Conexant HD-audio codec support" | 165 | bool "Build Conexant HD-audio codec support" |
153 | default y | 166 | default y |
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index e3081d4586cc..315a1c4f8998 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
@@ -13,6 +13,7 @@ snd-hda-codec-analog-objs := patch_analog.o | |||
13 | snd-hda-codec-idt-objs := patch_sigmatel.o | 13 | snd-hda-codec-idt-objs := patch_sigmatel.o |
14 | snd-hda-codec-si3054-objs := patch_si3054.o | 14 | snd-hda-codec-si3054-objs := patch_si3054.o |
15 | snd-hda-codec-atihdmi-objs := patch_atihdmi.o | 15 | snd-hda-codec-atihdmi-objs := patch_atihdmi.o |
16 | snd-hda-codec-cirrus-objs := patch_cirrus.o | ||
16 | snd-hda-codec-ca0110-objs := patch_ca0110.o | 17 | snd-hda-codec-ca0110-objs := patch_ca0110.o |
17 | snd-hda-codec-conexant-objs := patch_conexant.o | 18 | snd-hda-codec-conexant-objs := patch_conexant.o |
18 | snd-hda-codec-via-objs := patch_via.o | 19 | snd-hda-codec-via-objs := patch_via.o |
@@ -41,6 +42,9 @@ endif | |||
41 | ifdef CONFIG_SND_HDA_CODEC_ATIHDMI | 42 | ifdef CONFIG_SND_HDA_CODEC_ATIHDMI |
42 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o | 43 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o |
43 | endif | 44 | endif |
45 | ifdef CONFIG_SND_HDA_CODEC_CIRRUS | ||
46 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o | ||
47 | endif | ||
44 | ifdef CONFIG_SND_HDA_CODEC_CA0110 | 48 | ifdef CONFIG_SND_HDA_CODEC_CA0110 |
45 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o | 49 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o |
46 | endif | 50 | endif |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3a603cde8cc4..a23c27d2fb2f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -44,6 +44,7 @@ struct hda_vendor_id { | |||
44 | /* codec vendor labels */ | 44 | /* codec vendor labels */ |
45 | static struct hda_vendor_id hda_vendor_ids[] = { | 45 | static struct hda_vendor_id hda_vendor_ids[] = { |
46 | { 0x1002, "ATI" }, | 46 | { 0x1002, "ATI" }, |
47 | { 0x1013, "Cirrus Logic" }, | ||
47 | { 0x1057, "Motorola" }, | 48 | { 0x1057, "Motorola" }, |
48 | { 0x1095, "Silicon Image" }, | 49 | { 0x1095, "Silicon Image" }, |
49 | { 0x10de, "Nvidia" }, | 50 | { 0x10de, "Nvidia" }, |
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c new file mode 100644 index 000000000000..8ba306856d38 --- /dev/null +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -0,0 +1,1194 @@ | |||
1 | /* | ||
2 | * HD audio interface patch for Cirrus Logic CS420x chip | ||
3 | * | ||
4 | * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This driver is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This driver is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <sound/core.h> | ||
26 | #include "hda_codec.h" | ||
27 | #include "hda_local.h" | ||
28 | |||
29 | /* | ||
30 | */ | ||
31 | |||
32 | struct cs_spec { | ||
33 | int board_config; | ||
34 | struct auto_pin_cfg autocfg; | ||
35 | struct hda_multi_out multiout; | ||
36 | struct snd_kcontrol *vmaster_sw; | ||
37 | struct snd_kcontrol *vmaster_vol; | ||
38 | |||
39 | hda_nid_t dac_nid[AUTO_CFG_MAX_OUTS]; | ||
40 | hda_nid_t slave_dig_outs[2]; | ||
41 | |||
42 | unsigned int input_idx[AUTO_PIN_LAST]; | ||
43 | unsigned int capsrc_idx[AUTO_PIN_LAST]; | ||
44 | hda_nid_t adc_nid[AUTO_PIN_LAST]; | ||
45 | unsigned int adc_idx[AUTO_PIN_LAST]; | ||
46 | unsigned int num_inputs; | ||
47 | unsigned int cur_input; | ||
48 | unsigned int automic_idx; | ||
49 | hda_nid_t cur_adc; | ||
50 | unsigned int cur_adc_stream_tag; | ||
51 | unsigned int cur_adc_format; | ||
52 | hda_nid_t dig_in; | ||
53 | |||
54 | struct hda_bind_ctls *capture_bind[2]; | ||
55 | |||
56 | unsigned int gpio_mask; | ||
57 | unsigned int gpio_dir; | ||
58 | unsigned int gpio_data; | ||
59 | |||
60 | struct hda_pcm pcm_rec[2]; /* PCM information */ | ||
61 | |||
62 | unsigned int hp_detect:1; | ||
63 | unsigned int mic_detect:1; | ||
64 | }; | ||
65 | |||
66 | /* available models */ | ||
67 | enum { | ||
68 | CS420X_MBP55, | ||
69 | CS420X_AUTO, | ||
70 | CS420X_MODELS | ||
71 | }; | ||
72 | |||
73 | /* Vendor-specific processing widget */ | ||
74 | #define CS420X_VENDOR_NID 0x11 | ||
75 | #define CS_DIG_OUT1_PIN_NID 0x10 | ||
76 | #define CS_DIG_OUT2_PIN_NID 0x15 | ||
77 | #define CS_DMIC1_PIN_NID 0x12 | ||
78 | #define CS_DMIC2_PIN_NID 0x0e | ||
79 | |||
80 | /* coef indices */ | ||
81 | #define IDX_SPDIF_STAT 0x0000 | ||
82 | #define IDX_SPDIF_CTL 0x0001 | ||
83 | #define IDX_ADC_CFG 0x0002 | ||
84 | /* SZC bitmask, 4 modes below: | ||
85 | * 0 = immediate, | ||
86 | * 1 = digital immediate, analog zero-cross | ||
87 | * 2 = digtail & analog soft-ramp | ||
88 | * 3 = digital soft-ramp, analog zero-cross | ||
89 | */ | ||
90 | #define CS_COEF_ADC_SZC_MASK (3 << 0) | ||
91 | #define CS_COEF_ADC_MIC_SZC_MODE (3 << 0) /* SZC setup for mic */ | ||
92 | #define CS_COEF_ADC_LI_SZC_MODE (3 << 0) /* SZC setup for line-in */ | ||
93 | /* PGA mode: 0 = differential, 1 = signle-ended */ | ||
94 | #define CS_COEF_ADC_MIC_PGA_MODE (1 << 5) /* PGA setup for mic */ | ||
95 | #define CS_COEF_ADC_LI_PGA_MODE (1 << 6) /* PGA setup for line-in */ | ||
96 | #define IDX_DAC_CFG 0x0003 | ||
97 | /* SZC bitmask, 4 modes below: | ||
98 | * 0 = Immediate | ||
99 | * 1 = zero-cross | ||
100 | * 2 = soft-ramp | ||
101 | * 3 = soft-ramp on zero-cross | ||
102 | */ | ||
103 | #define CS_COEF_DAC_HP_SZC_MODE (3 << 0) /* nid 0x02 */ | ||
104 | #define CS_COEF_DAC_LO_SZC_MODE (3 << 2) /* nid 0x03 */ | ||
105 | #define CS_COEF_DAC_SPK_SZC_MODE (3 << 4) /* nid 0x04 */ | ||
106 | |||
107 | #define IDX_BEEP_CFG 0x0004 | ||
108 | /* 0x0008 - test reg key */ | ||
109 | /* 0x0009 - 0x0014 -> 12 test regs */ | ||
110 | /* 0x0015 - visibility reg */ | ||
111 | |||
112 | |||
113 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) | ||
114 | { | ||
115 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | ||
116 | AC_VERB_SET_COEF_INDEX, idx); | ||
117 | return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0, | ||
118 | AC_VERB_GET_PROC_COEF, 0); | ||
119 | } | ||
120 | |||
121 | static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, | ||
122 | unsigned int coef) | ||
123 | { | ||
124 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | ||
125 | AC_VERB_SET_COEF_INDEX, idx); | ||
126 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | ||
127 | AC_VERB_SET_PROC_COEF, coef); | ||
128 | } | ||
129 | |||
130 | |||
131 | #define HP_EVENT 1 | ||
132 | #define MIC_EVENT 2 | ||
133 | |||
134 | /* | ||
135 | * PCM callbacks | ||
136 | */ | ||
137 | static int cs_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
138 | struct hda_codec *codec, | ||
139 | struct snd_pcm_substream *substream) | ||
140 | { | ||
141 | struct cs_spec *spec = codec->spec; | ||
142 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, | ||
143 | hinfo); | ||
144 | } | ||
145 | |||
146 | static int cs_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
147 | struct hda_codec *codec, | ||
148 | unsigned int stream_tag, | ||
149 | unsigned int format, | ||
150 | struct snd_pcm_substream *substream) | ||
151 | { | ||
152 | struct cs_spec *spec = codec->spec; | ||
153 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, | ||
154 | stream_tag, format, substream); | ||
155 | } | ||
156 | |||
157 | static int cs_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
158 | struct hda_codec *codec, | ||
159 | struct snd_pcm_substream *substream) | ||
160 | { | ||
161 | struct cs_spec *spec = codec->spec; | ||
162 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Digital out | ||
167 | */ | ||
168 | static int cs_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
169 | struct hda_codec *codec, | ||
170 | struct snd_pcm_substream *substream) | ||
171 | { | ||
172 | struct cs_spec *spec = codec->spec; | ||
173 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
174 | } | ||
175 | |||
176 | static int cs_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
177 | struct hda_codec *codec, | ||
178 | struct snd_pcm_substream *substream) | ||
179 | { | ||
180 | struct cs_spec *spec = codec->spec; | ||
181 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
182 | } | ||
183 | |||
184 | static int cs_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
185 | struct hda_codec *codec, | ||
186 | unsigned int stream_tag, | ||
187 | unsigned int format, | ||
188 | struct snd_pcm_substream *substream) | ||
189 | { | ||
190 | struct cs_spec *spec = codec->spec; | ||
191 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | ||
192 | format, substream); | ||
193 | } | ||
194 | |||
195 | static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
196 | struct hda_codec *codec, | ||
197 | struct snd_pcm_substream *substream) | ||
198 | { | ||
199 | struct cs_spec *spec = codec->spec; | ||
200 | return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Analog capture | ||
205 | */ | ||
206 | static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
207 | struct hda_codec *codec, | ||
208 | unsigned int stream_tag, | ||
209 | unsigned int format, | ||
210 | struct snd_pcm_substream *substream) | ||
211 | { | ||
212 | struct cs_spec *spec = codec->spec; | ||
213 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | ||
214 | spec->cur_adc_stream_tag = stream_tag; | ||
215 | spec->cur_adc_format = format; | ||
216 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
221 | struct hda_codec *codec, | ||
222 | struct snd_pcm_substream *substream) | ||
223 | { | ||
224 | struct cs_spec *spec = codec->spec; | ||
225 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | ||
226 | spec->cur_adc = 0; | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | */ | ||
232 | static struct hda_pcm_stream cs_pcm_analog_playback = { | ||
233 | .substreams = 1, | ||
234 | .channels_min = 2, | ||
235 | .channels_max = 2, | ||
236 | .ops = { | ||
237 | .open = cs_playback_pcm_open, | ||
238 | .prepare = cs_playback_pcm_prepare, | ||
239 | .cleanup = cs_playback_pcm_cleanup | ||
240 | }, | ||
241 | }; | ||
242 | |||
243 | static struct hda_pcm_stream cs_pcm_analog_capture = { | ||
244 | .substreams = 1, | ||
245 | .channels_min = 2, | ||
246 | .channels_max = 2, | ||
247 | .ops = { | ||
248 | .prepare = cs_capture_pcm_prepare, | ||
249 | .cleanup = cs_capture_pcm_cleanup | ||
250 | }, | ||
251 | }; | ||
252 | |||
253 | static struct hda_pcm_stream cs_pcm_digital_playback = { | ||
254 | .substreams = 1, | ||
255 | .channels_min = 2, | ||
256 | .channels_max = 2, | ||
257 | .ops = { | ||
258 | .open = cs_dig_playback_pcm_open, | ||
259 | .close = cs_dig_playback_pcm_close, | ||
260 | .prepare = cs_dig_playback_pcm_prepare, | ||
261 | .cleanup = cs_dig_playback_pcm_cleanup | ||
262 | }, | ||
263 | }; | ||
264 | |||
265 | static struct hda_pcm_stream cs_pcm_digital_capture = { | ||
266 | .substreams = 1, | ||
267 | .channels_min = 2, | ||
268 | .channels_max = 2, | ||
269 | }; | ||
270 | |||
271 | static int cs_build_pcms(struct hda_codec *codec) | ||
272 | { | ||
273 | struct cs_spec *spec = codec->spec; | ||
274 | struct hda_pcm *info = spec->pcm_rec; | ||
275 | |||
276 | codec->pcm_info = info; | ||
277 | codec->num_pcms = 0; | ||
278 | |||
279 | info->name = "Cirrus Analog"; | ||
280 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cs_pcm_analog_playback; | ||
281 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dac_nid[0]; | ||
282 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = | ||
283 | spec->multiout.max_channels; | ||
284 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs_pcm_analog_capture; | ||
285 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = | ||
286 | spec->adc_nid[spec->cur_input]; | ||
287 | codec->num_pcms++; | ||
288 | |||
289 | if (!spec->multiout.dig_out_nid && !spec->dig_in) | ||
290 | return 0; | ||
291 | |||
292 | info++; | ||
293 | info->name = "Cirrus Digital"; | ||
294 | info->pcm_type = spec->autocfg.dig_out_type[0]; | ||
295 | if (!info->pcm_type) | ||
296 | info->pcm_type = HDA_PCM_TYPE_SPDIF; | ||
297 | if (spec->multiout.dig_out_nid) { | ||
298 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
299 | cs_pcm_digital_playback; | ||
300 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | ||
301 | spec->multiout.dig_out_nid; | ||
302 | } | ||
303 | if (spec->dig_in) { | ||
304 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
305 | cs_pcm_digital_capture; | ||
306 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; | ||
307 | } | ||
308 | codec->num_pcms++; | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * parse codec topology | ||
315 | */ | ||
316 | |||
317 | static hda_nid_t get_dac(struct hda_codec *codec, hda_nid_t pin) | ||
318 | { | ||
319 | hda_nid_t dac; | ||
320 | if (!pin) | ||
321 | return 0; | ||
322 | if (snd_hda_get_connections(codec, pin, &dac, 1) != 1) | ||
323 | return 0; | ||
324 | return dac; | ||
325 | } | ||
326 | |||
327 | static int is_ext_mic(struct hda_codec *codec, unsigned int idx) | ||
328 | { | ||
329 | struct cs_spec *spec = codec->spec; | ||
330 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
331 | hda_nid_t pin = cfg->input_pins[idx]; | ||
332 | unsigned int val = snd_hda_query_pin_caps(codec, pin); | ||
333 | if (!(val & AC_PINCAP_PRES_DETECT)) | ||
334 | return 0; | ||
335 | val = snd_hda_codec_get_pincfg(codec, pin); | ||
336 | return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX); | ||
337 | } | ||
338 | |||
339 | static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, | ||
340 | unsigned int *idxp) | ||
341 | { | ||
342 | int i; | ||
343 | hda_nid_t nid; | ||
344 | |||
345 | nid = codec->start_nid; | ||
346 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
347 | hda_nid_t pins[2]; | ||
348 | unsigned int type; | ||
349 | int j, nums; | ||
350 | type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) | ||
351 | >> AC_WCAP_TYPE_SHIFT; | ||
352 | if (type != AC_WID_AUD_IN) | ||
353 | continue; | ||
354 | nums = snd_hda_get_connections(codec, nid, pins, | ||
355 | ARRAY_SIZE(pins)); | ||
356 | if (nums <= 0) | ||
357 | continue; | ||
358 | for (j = 0; j < nums; j++) { | ||
359 | if (pins[j] == pin) { | ||
360 | *idxp = j; | ||
361 | return nid; | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static int is_active_pin(struct hda_codec *codec, hda_nid_t nid) | ||
369 | { | ||
370 | unsigned int val; | ||
371 | val = snd_hda_codec_get_pincfg(codec, nid); | ||
372 | return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); | ||
373 | } | ||
374 | |||
375 | static int parse_output(struct hda_codec *codec) | ||
376 | { | ||
377 | struct cs_spec *spec = codec->spec; | ||
378 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
379 | int i, extra_nids; | ||
380 | hda_nid_t dac; | ||
381 | |||
382 | for (i = 0; i < cfg->line_outs; i++) { | ||
383 | dac = get_dac(codec, cfg->line_out_pins[i]); | ||
384 | if (!dac) | ||
385 | break; | ||
386 | spec->dac_nid[i] = dac; | ||
387 | } | ||
388 | spec->multiout.num_dacs = i; | ||
389 | spec->multiout.dac_nids = spec->dac_nid; | ||
390 | spec->multiout.max_channels = i * 2; | ||
391 | |||
392 | /* add HP and speakers */ | ||
393 | extra_nids = 0; | ||
394 | for (i = 0; i < cfg->hp_outs; i++) { | ||
395 | dac = get_dac(codec, cfg->hp_pins[i]); | ||
396 | if (!dac) | ||
397 | break; | ||
398 | if (!i) | ||
399 | spec->multiout.hp_nid = dac; | ||
400 | else | ||
401 | spec->multiout.extra_out_nid[extra_nids++] = dac; | ||
402 | } | ||
403 | for (i = 0; i < cfg->speaker_outs; i++) { | ||
404 | dac = get_dac(codec, cfg->speaker_pins[i]); | ||
405 | if (!dac) | ||
406 | break; | ||
407 | spec->multiout.extra_out_nid[extra_nids++] = dac; | ||
408 | } | ||
409 | |||
410 | if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { | ||
411 | cfg->speaker_outs = cfg->line_outs; | ||
412 | memcpy(cfg->speaker_pins, cfg->line_out_pins, | ||
413 | sizeof(cfg->speaker_pins)); | ||
414 | cfg->line_outs = 0; | ||
415 | } | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static int parse_input(struct hda_codec *codec) | ||
421 | { | ||
422 | struct cs_spec *spec = codec->spec; | ||
423 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
424 | int i; | ||
425 | |||
426 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
427 | hda_nid_t pin = cfg->input_pins[i]; | ||
428 | if (!pin) | ||
429 | continue; | ||
430 | spec->input_idx[spec->num_inputs] = i; | ||
431 | spec->capsrc_idx[i] = spec->num_inputs++; | ||
432 | spec->cur_input = i; | ||
433 | spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); | ||
434 | } | ||
435 | if (!spec->num_inputs) | ||
436 | return 0; | ||
437 | |||
438 | /* check whether the automatic mic switch is available */ | ||
439 | if (spec->num_inputs == 2 && | ||
440 | spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) { | ||
441 | if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) { | ||
442 | if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { | ||
443 | spec->mic_detect = 1; | ||
444 | spec->automic_idx = AUTO_PIN_FRONT_MIC; | ||
445 | } | ||
446 | } else { | ||
447 | if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { | ||
448 | spec->mic_detect = 1; | ||
449 | spec->automic_idx = AUTO_PIN_MIC; | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | |||
457 | static int parse_digital_output(struct hda_codec *codec) | ||
458 | { | ||
459 | struct cs_spec *spec = codec->spec; | ||
460 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
461 | hda_nid_t nid; | ||
462 | |||
463 | if (!cfg->dig_outs) | ||
464 | return 0; | ||
465 | if (snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) < 1) | ||
466 | return 0; | ||
467 | spec->multiout.dig_out_nid = nid; | ||
468 | spec->multiout.share_spdif = 1; | ||
469 | if (cfg->dig_outs > 1 && | ||
470 | snd_hda_get_connections(codec, cfg->dig_out_pins[1], &nid, 1) > 0) { | ||
471 | spec->slave_dig_outs[0] = nid; | ||
472 | codec->slave_dig_outs = spec->slave_dig_outs; | ||
473 | } | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int parse_digital_input(struct hda_codec *codec) | ||
478 | { | ||
479 | struct cs_spec *spec = codec->spec; | ||
480 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
481 | int idx; | ||
482 | |||
483 | if (cfg->dig_in_pin) | ||
484 | spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * create mixer controls | ||
490 | */ | ||
491 | |||
492 | static const char *dir_sfx[2] = { "Playback", "Capture" }; | ||
493 | |||
494 | static int add_mute(struct hda_codec *codec, const char *name, int index, | ||
495 | unsigned int pval, int dir, struct snd_kcontrol **kctlp) | ||
496 | { | ||
497 | char tmp[44]; | ||
498 | struct snd_kcontrol_new knew = | ||
499 | HDA_CODEC_MUTE_IDX(tmp, index, 0, 0, HDA_OUTPUT); | ||
500 | knew.private_value = pval; | ||
501 | snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); | ||
502 | *kctlp = snd_ctl_new1(&knew, codec); | ||
503 | return snd_hda_ctl_add(codec, *kctlp); | ||
504 | } | ||
505 | |||
506 | static int add_volume(struct hda_codec *codec, const char *name, | ||
507 | int index, unsigned int pval, int dir, | ||
508 | struct snd_kcontrol **kctlp) | ||
509 | { | ||
510 | char tmp[32]; | ||
511 | struct snd_kcontrol_new knew = | ||
512 | HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT); | ||
513 | knew.private_value = pval; | ||
514 | snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); | ||
515 | *kctlp = snd_ctl_new1(&knew, codec); | ||
516 | return snd_hda_ctl_add(codec, *kctlp); | ||
517 | } | ||
518 | |||
519 | static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) | ||
520 | { | ||
521 | unsigned int caps; | ||
522 | |||
523 | /* set the upper-limit for mixer amp to 0dB */ | ||
524 | caps = query_amp_caps(codec, dac, HDA_OUTPUT); | ||
525 | caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); | ||
526 | caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) | ||
527 | << AC_AMPCAP_NUM_STEPS_SHIFT; | ||
528 | snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); | ||
529 | } | ||
530 | |||
531 | static int add_vmaster(struct hda_codec *codec, hda_nid_t dac) | ||
532 | { | ||
533 | struct cs_spec *spec = codec->spec; | ||
534 | unsigned int tlv[4]; | ||
535 | int err; | ||
536 | |||
537 | spec->vmaster_sw = | ||
538 | snd_ctl_make_virtual_master("Master Playback Switch", NULL); | ||
539 | err = snd_hda_ctl_add(codec, spec->vmaster_sw); | ||
540 | if (err < 0) | ||
541 | return err; | ||
542 | |||
543 | snd_hda_set_vmaster_tlv(codec, dac, HDA_OUTPUT, tlv); | ||
544 | spec->vmaster_vol = | ||
545 | snd_ctl_make_virtual_master("Master Playback Volume", tlv); | ||
546 | err = snd_hda_ctl_add(codec, spec->vmaster_vol); | ||
547 | if (err < 0) | ||
548 | return err; | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, | ||
553 | int num_ctls, int type) | ||
554 | { | ||
555 | struct cs_spec *spec = codec->spec; | ||
556 | const char *name; | ||
557 | int err, index; | ||
558 | struct snd_kcontrol *kctl; | ||
559 | static char *speakers[] = { | ||
560 | "Front Speaker", "Surround Speaker", "Bass Speaker" | ||
561 | }; | ||
562 | static char *line_outs[] = { | ||
563 | "Front Line-Out", "Surround Line-Out", "Bass Line-Out" | ||
564 | }; | ||
565 | |||
566 | fix_volume_caps(codec, dac); | ||
567 | if (!spec->vmaster_sw) { | ||
568 | err = add_vmaster(codec, dac); | ||
569 | if (err < 0) | ||
570 | return err; | ||
571 | } | ||
572 | |||
573 | index = 0; | ||
574 | switch (type) { | ||
575 | case AUTO_PIN_HP_OUT: | ||
576 | name = "Headphone"; | ||
577 | index = idx; | ||
578 | break; | ||
579 | case AUTO_PIN_SPEAKER_OUT: | ||
580 | if (num_ctls > 1) | ||
581 | name = speakers[idx]; | ||
582 | else | ||
583 | name = "Speaker"; | ||
584 | break; | ||
585 | default: | ||
586 | if (num_ctls > 1) | ||
587 | name = line_outs[idx]; | ||
588 | else | ||
589 | name = "Line-Out"; | ||
590 | break; | ||
591 | } | ||
592 | |||
593 | err = add_mute(codec, name, index, | ||
594 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); | ||
595 | if (err < 0) | ||
596 | return err; | ||
597 | err = snd_ctl_add_slave(spec->vmaster_sw, kctl); | ||
598 | if (err < 0) | ||
599 | return err; | ||
600 | |||
601 | err = add_volume(codec, name, index, | ||
602 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); | ||
603 | if (err < 0) | ||
604 | return err; | ||
605 | err = snd_ctl_add_slave(spec->vmaster_vol, kctl); | ||
606 | if (err < 0) | ||
607 | return err; | ||
608 | |||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int build_output(struct hda_codec *codec) | ||
613 | { | ||
614 | struct cs_spec *spec = codec->spec; | ||
615 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
616 | int i, err; | ||
617 | |||
618 | for (i = 0; i < cfg->line_outs; i++) { | ||
619 | err = add_output(codec, get_dac(codec, cfg->line_out_pins[i]), | ||
620 | i, cfg->line_outs, cfg->line_out_type); | ||
621 | if (err < 0) | ||
622 | return err; | ||
623 | } | ||
624 | for (i = 0; i < cfg->hp_outs; i++) { | ||
625 | err = add_output(codec, get_dac(codec, cfg->hp_pins[i]), | ||
626 | i, cfg->hp_outs, AUTO_PIN_HP_OUT); | ||
627 | if (err < 0) | ||
628 | return err; | ||
629 | } | ||
630 | for (i = 0; i < cfg->speaker_outs; i++) { | ||
631 | err = add_output(codec, get_dac(codec, cfg->speaker_pins[i]), | ||
632 | i, cfg->speaker_outs, AUTO_PIN_SPEAKER_OUT); | ||
633 | if (err < 0) | ||
634 | return err; | ||
635 | } | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | /* | ||
640 | */ | ||
641 | |||
642 | static struct snd_kcontrol_new cs_capture_ctls[] = { | ||
643 | HDA_BIND_SW("Capture Switch", 0), | ||
644 | HDA_BIND_VOL("Capture Volume", 0), | ||
645 | }; | ||
646 | |||
647 | static int change_cur_input(struct hda_codec *codec, unsigned int idx, | ||
648 | int force) | ||
649 | { | ||
650 | struct cs_spec *spec = codec->spec; | ||
651 | |||
652 | if (spec->cur_input == idx && !force) | ||
653 | return 0; | ||
654 | if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { | ||
655 | /* stream is running, let's swap the current ADC */ | ||
656 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | ||
657 | spec->cur_adc = spec->adc_nid[idx]; | ||
658 | snd_hda_codec_setup_stream(codec, spec->cur_adc, | ||
659 | spec->cur_adc_stream_tag, 0, | ||
660 | spec->cur_adc_format); | ||
661 | } | ||
662 | snd_hda_codec_write(codec, spec->cur_adc, 0, | ||
663 | AC_VERB_SET_CONNECT_SEL, | ||
664 | spec->adc_idx[idx]); | ||
665 | spec->cur_input = idx; | ||
666 | return 1; | ||
667 | } | ||
668 | |||
669 | static int cs_capture_source_info(struct snd_kcontrol *kcontrol, | ||
670 | struct snd_ctl_elem_info *uinfo) | ||
671 | { | ||
672 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
673 | struct cs_spec *spec = codec->spec; | ||
674 | unsigned int idx; | ||
675 | |||
676 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
677 | uinfo->count = 1; | ||
678 | uinfo->value.enumerated.items = spec->num_inputs; | ||
679 | if (uinfo->value.enumerated.item >= spec->num_inputs) | ||
680 | uinfo->value.enumerated.item = spec->num_inputs - 1; | ||
681 | idx = spec->input_idx[uinfo->value.enumerated.item]; | ||
682 | strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]); | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static int cs_capture_source_get(struct snd_kcontrol *kcontrol, | ||
687 | struct snd_ctl_elem_value *ucontrol) | ||
688 | { | ||
689 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
690 | struct cs_spec *spec = codec->spec; | ||
691 | ucontrol->value.enumerated.item[0] = spec->capsrc_idx[spec->cur_input]; | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int cs_capture_source_put(struct snd_kcontrol *kcontrol, | ||
696 | struct snd_ctl_elem_value *ucontrol) | ||
697 | { | ||
698 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
699 | struct cs_spec *spec = codec->spec; | ||
700 | unsigned int idx = ucontrol->value.enumerated.item[0]; | ||
701 | |||
702 | if (idx >= spec->num_inputs) | ||
703 | return -EINVAL; | ||
704 | idx = spec->input_idx[idx]; | ||
705 | return change_cur_input(codec, idx, 0); | ||
706 | } | ||
707 | |||
708 | static struct snd_kcontrol_new cs_capture_source = { | ||
709 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
710 | .name = "Capture Source", | ||
711 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
712 | .info = cs_capture_source_info, | ||
713 | .get = cs_capture_source_get, | ||
714 | .put = cs_capture_source_put, | ||
715 | }; | ||
716 | |||
717 | static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, | ||
718 | struct hda_ctl_ops *ops) | ||
719 | { | ||
720 | struct cs_spec *spec = codec->spec; | ||
721 | struct hda_bind_ctls *bind; | ||
722 | int i, n; | ||
723 | |||
724 | bind = kzalloc(sizeof(*bind) + sizeof(long) * (spec->num_inputs + 1), | ||
725 | GFP_KERNEL); | ||
726 | if (!bind) | ||
727 | return NULL; | ||
728 | bind->ops = ops; | ||
729 | n = 0; | ||
730 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
731 | if (!spec->adc_nid[i]) | ||
732 | continue; | ||
733 | bind->values[n++] = | ||
734 | HDA_COMPOSE_AMP_VAL(spec->adc_nid[i], 3, | ||
735 | spec->adc_idx[i], HDA_INPUT); | ||
736 | } | ||
737 | return bind; | ||
738 | } | ||
739 | |||
740 | static int build_input(struct hda_codec *codec) | ||
741 | { | ||
742 | struct cs_spec *spec = codec->spec; | ||
743 | int i, err; | ||
744 | |||
745 | if (!spec->num_inputs) | ||
746 | return 0; | ||
747 | |||
748 | /* make bind-capture */ | ||
749 | spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); | ||
750 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); | ||
751 | for (i = 0; i < 2; i++) { | ||
752 | struct snd_kcontrol *kctl; | ||
753 | if (!spec->capture_bind[i]) | ||
754 | return -ENOMEM; | ||
755 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); | ||
756 | if (!kctl) | ||
757 | return -ENOMEM; | ||
758 | kctl->private_value = (long)spec->capture_bind[i]; | ||
759 | err = snd_hda_ctl_add(codec, kctl); | ||
760 | if (err < 0) | ||
761 | return err; | ||
762 | } | ||
763 | |||
764 | if (spec->num_inputs > 1 && !spec->mic_detect) { | ||
765 | err = snd_hda_ctl_add(codec, | ||
766 | snd_ctl_new1(&cs_capture_source, codec)); | ||
767 | if (err < 0) | ||
768 | return err; | ||
769 | } | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | /* | ||
775 | */ | ||
776 | |||
777 | static int build_digital_output(struct hda_codec *codec) | ||
778 | { | ||
779 | struct cs_spec *spec = codec->spec; | ||
780 | int err; | ||
781 | |||
782 | if (!spec->multiout.dig_out_nid) | ||
783 | return 0; | ||
784 | |||
785 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | ||
786 | if (err < 0) | ||
787 | return err; | ||
788 | err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); | ||
789 | if (err < 0) | ||
790 | return err; | ||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int build_digital_input(struct hda_codec *codec) | ||
795 | { | ||
796 | struct cs_spec *spec = codec->spec; | ||
797 | if (spec->dig_in) | ||
798 | return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | /* | ||
803 | * auto-mute and auto-mic switching | ||
804 | */ | ||
805 | |||
806 | static void cs_automute(struct hda_codec *codec) | ||
807 | { | ||
808 | struct cs_spec *spec = codec->spec; | ||
809 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
810 | unsigned int caps, present, hp_present; | ||
811 | hda_nid_t nid; | ||
812 | int i; | ||
813 | |||
814 | hp_present = 0; | ||
815 | for (i = 0; i < cfg->hp_outs; i++) { | ||
816 | nid = cfg->hp_pins[i]; | ||
817 | caps = snd_hda_query_pin_caps(codec, nid); | ||
818 | if (!(caps & AC_PINCAP_PRES_DETECT)) | ||
819 | continue; | ||
820 | if (caps & AC_PINCAP_TRIG_REQ) | ||
821 | snd_hda_codec_read(codec, nid, 0, | ||
822 | AC_VERB_SET_PIN_SENSE, 0); | ||
823 | present = snd_hda_codec_read(codec, nid, 0, | ||
824 | AC_VERB_GET_PIN_SENSE, 0); | ||
825 | hp_present |= (present & AC_PINSENSE_PRESENCE) != 0; | ||
826 | if (hp_present) | ||
827 | break; | ||
828 | } | ||
829 | for (i = 0; i < cfg->speaker_outs; i++) { | ||
830 | nid = cfg->speaker_pins[i]; | ||
831 | snd_hda_codec_write(codec, nid, 0, | ||
832 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
833 | hp_present ? 0 : PIN_OUT); | ||
834 | } | ||
835 | if (spec->board_config == CS420X_MBP55) { | ||
836 | unsigned int gpio = hp_present ? 0x02 : 0x08; | ||
837 | snd_hda_codec_write(codec, 0x01, 0, | ||
838 | AC_VERB_SET_GPIO_DATA, gpio); | ||
839 | } | ||
840 | } | ||
841 | |||
842 | static void cs_automic(struct hda_codec *codec) | ||
843 | { | ||
844 | struct cs_spec *spec = codec->spec; | ||
845 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
846 | hda_nid_t nid; | ||
847 | unsigned int caps, present; | ||
848 | |||
849 | nid = cfg->input_pins[spec->automic_idx]; | ||
850 | caps = snd_hda_query_pin_caps(codec, nid); | ||
851 | if (caps & AC_PINCAP_TRIG_REQ) | ||
852 | snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
853 | present = snd_hda_codec_read(codec, nid, 0, | ||
854 | AC_VERB_GET_PIN_SENSE, 0); | ||
855 | if (present & AC_PINSENSE_PRESENCE) | ||
856 | change_cur_input(codec, spec->automic_idx, 0); | ||
857 | else { | ||
858 | unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? | ||
859 | AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC; | ||
860 | change_cur_input(codec, imic, 0); | ||
861 | } | ||
862 | } | ||
863 | |||
864 | /* | ||
865 | */ | ||
866 | |||
867 | static void init_output(struct hda_codec *codec) | ||
868 | { | ||
869 | struct cs_spec *spec = codec->spec; | ||
870 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
871 | int i; | ||
872 | |||
873 | /* mute first */ | ||
874 | for (i = 0; i < spec->multiout.num_dacs; i++) | ||
875 | snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, | ||
876 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
877 | if (spec->multiout.hp_nid) | ||
878 | snd_hda_codec_write(codec, spec->multiout.hp_nid, 0, | ||
879 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
880 | for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { | ||
881 | if (!spec->multiout.extra_out_nid[i]) | ||
882 | break; | ||
883 | snd_hda_codec_write(codec, spec->multiout.extra_out_nid[i], 0, | ||
884 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
885 | } | ||
886 | |||
887 | /* set appropriate pin controls */ | ||
888 | for (i = 0; i < cfg->line_outs; i++) | ||
889 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | ||
890 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
891 | for (i = 0; i < cfg->hp_outs; i++) { | ||
892 | hda_nid_t nid = cfg->hp_pins[i]; | ||
893 | snd_hda_codec_write(codec, nid, 0, | ||
894 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | ||
895 | if (!cfg->speaker_outs) | ||
896 | continue; | ||
897 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { | ||
898 | snd_hda_codec_write(codec, nid, 0, | ||
899 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
900 | AC_USRSP_EN | HP_EVENT); | ||
901 | spec->hp_detect = 1; | ||
902 | } | ||
903 | } | ||
904 | for (i = 0; i < cfg->speaker_outs; i++) | ||
905 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | ||
906 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
907 | if (spec->hp_detect) | ||
908 | cs_automute(codec); | ||
909 | } | ||
910 | |||
911 | static void init_input(struct hda_codec *codec) | ||
912 | { | ||
913 | struct cs_spec *spec = codec->spec; | ||
914 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
915 | unsigned int coef; | ||
916 | int i; | ||
917 | |||
918 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
919 | unsigned int ctl; | ||
920 | hda_nid_t pin = cfg->input_pins[i]; | ||
921 | if (!pin || !spec->adc_nid[i]) | ||
922 | continue; | ||
923 | /* set appropriate pin control and mute first */ | ||
924 | ctl = PIN_IN; | ||
925 | if (i <= AUTO_PIN_FRONT_MIC) { | ||
926 | unsigned int caps = snd_hda_query_pin_caps(codec, pin); | ||
927 | caps >>= AC_PINCAP_VREF_SHIFT; | ||
928 | if (caps & AC_PINCAP_VREF_80) | ||
929 | ctl = PIN_VREF80; | ||
930 | } | ||
931 | snd_hda_codec_write(codec, pin, 0, | ||
932 | AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); | ||
933 | snd_hda_codec_write(codec, spec->adc_nid[i], 0, | ||
934 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
935 | AMP_IN_MUTE(spec->adc_idx[i])); | ||
936 | if (spec->mic_detect && spec->automic_idx == i) | ||
937 | snd_hda_codec_write(codec, pin, 0, | ||
938 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
939 | AC_USRSP_EN | MIC_EVENT); | ||
940 | } | ||
941 | change_cur_input(codec, spec->cur_input, 1); | ||
942 | if (spec->mic_detect) | ||
943 | cs_automic(codec); | ||
944 | |||
945 | coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ | ||
946 | if (is_active_pin(codec, CS_DMIC2_PIN_NID)) | ||
947 | coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */ | ||
948 | if (is_active_pin(codec, CS_DMIC1_PIN_NID)) | ||
949 | coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 | ||
950 | * No effect if SPDIF_OUT2 is slected in | ||
951 | * IDX_SPDIF_CTL. | ||
952 | */ | ||
953 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); | ||
954 | } | ||
955 | |||
956 | static struct hda_verb cs_coef_init_verbs[] = { | ||
957 | {0x11, AC_VERB_SET_PROC_STATE, 1}, | ||
958 | {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, | ||
959 | {0x11, AC_VERB_SET_PROC_COEF, | ||
960 | (0x002a /* DAC1/2/3 SZCMode Soft Ramp */ | ||
961 | | 0x0040 /* Mute DACs on FIFO error */ | ||
962 | | 0x1000 /* Enable DACs High Pass Filter */ | ||
963 | | 0x0400 /* Disable Coefficient Auto increment */ | ||
964 | )}, | ||
965 | /* Beep */ | ||
966 | {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, | ||
967 | {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */ | ||
968 | |||
969 | {} /* terminator */ | ||
970 | }; | ||
971 | |||
972 | /* SPDIF setup */ | ||
973 | static void init_digital(struct hda_codec *codec) | ||
974 | { | ||
975 | unsigned int coef; | ||
976 | |||
977 | coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */ | ||
978 | coef |= 0x0008; /* Replace with mute on error */ | ||
979 | if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID)) | ||
980 | coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2 | ||
981 | * SPDIF_OUT2 is shared with GPIO1 and | ||
982 | * DMIC_SDA2. | ||
983 | */ | ||
984 | cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef); | ||
985 | } | ||
986 | |||
987 | static int cs_init(struct hda_codec *codec) | ||
988 | { | ||
989 | struct cs_spec *spec = codec->spec; | ||
990 | |||
991 | snd_hda_sequence_write(codec, cs_coef_init_verbs); | ||
992 | |||
993 | if (spec->gpio_mask) { | ||
994 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, | ||
995 | spec->gpio_mask); | ||
996 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, | ||
997 | spec->gpio_dir); | ||
998 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
999 | spec->gpio_data); | ||
1000 | } | ||
1001 | |||
1002 | init_output(codec); | ||
1003 | init_input(codec); | ||
1004 | init_digital(codec); | ||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static int cs_build_controls(struct hda_codec *codec) | ||
1009 | { | ||
1010 | int err; | ||
1011 | |||
1012 | err = build_output(codec); | ||
1013 | if (err < 0) | ||
1014 | return err; | ||
1015 | err = build_input(codec); | ||
1016 | if (err < 0) | ||
1017 | return err; | ||
1018 | err = build_digital_output(codec); | ||
1019 | if (err < 0) | ||
1020 | return err; | ||
1021 | err = build_digital_input(codec); | ||
1022 | if (err < 0) | ||
1023 | return err; | ||
1024 | return cs_init(codec); | ||
1025 | } | ||
1026 | |||
1027 | static void cs_free(struct hda_codec *codec) | ||
1028 | { | ||
1029 | struct cs_spec *spec = codec->spec; | ||
1030 | kfree(spec->capture_bind[0]); | ||
1031 | kfree(spec->capture_bind[1]); | ||
1032 | kfree(codec->spec); | ||
1033 | } | ||
1034 | |||
1035 | static void cs_unsol_event(struct hda_codec *codec, unsigned int res) | ||
1036 | { | ||
1037 | switch ((res >> 26) & 0x7f) { | ||
1038 | case HP_EVENT: | ||
1039 | cs_automute(codec); | ||
1040 | break; | ||
1041 | case MIC_EVENT: | ||
1042 | cs_automic(codec); | ||
1043 | break; | ||
1044 | } | ||
1045 | } | ||
1046 | |||
1047 | static struct hda_codec_ops cs_patch_ops = { | ||
1048 | .build_controls = cs_build_controls, | ||
1049 | .build_pcms = cs_build_pcms, | ||
1050 | .init = cs_init, | ||
1051 | .free = cs_free, | ||
1052 | .unsol_event = cs_unsol_event, | ||
1053 | }; | ||
1054 | |||
1055 | static int cs_parse_auto_config(struct hda_codec *codec) | ||
1056 | { | ||
1057 | struct cs_spec *spec = codec->spec; | ||
1058 | int err; | ||
1059 | |||
1060 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
1061 | if (err < 0) | ||
1062 | return err; | ||
1063 | |||
1064 | err = parse_output(codec); | ||
1065 | if (err < 0) | ||
1066 | return err; | ||
1067 | err = parse_input(codec); | ||
1068 | if (err < 0) | ||
1069 | return err; | ||
1070 | err = parse_digital_output(codec); | ||
1071 | if (err < 0) | ||
1072 | return err; | ||
1073 | err = parse_digital_input(codec); | ||
1074 | if (err < 0) | ||
1075 | return err; | ||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static const char *cs420x_models[CS420X_MODELS] = { | ||
1080 | [CS420X_MBP55] = "mbp55", | ||
1081 | [CS420X_AUTO] = "auto", | ||
1082 | }; | ||
1083 | |||
1084 | |||
1085 | static struct snd_pci_quirk cs420x_cfg_tbl[] = { | ||
1086 | SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), | ||
1087 | {} /* terminator */ | ||
1088 | }; | ||
1089 | |||
1090 | struct cs_pincfg { | ||
1091 | hda_nid_t nid; | ||
1092 | u32 val; | ||
1093 | }; | ||
1094 | |||
1095 | static struct cs_pincfg mbp55_pincfgs[] = { | ||
1096 | { 0x09, 0x012b4030 }, | ||
1097 | { 0x0a, 0x90100121 }, | ||
1098 | { 0x0b, 0x90100120 }, | ||
1099 | { 0x0c, 0x400000f0 }, | ||
1100 | { 0x0d, 0x90a00110 }, | ||
1101 | { 0x0e, 0x400000f0 }, | ||
1102 | { 0x0f, 0x400000f0 }, | ||
1103 | { 0x10, 0x014be040 }, | ||
1104 | { 0x12, 0x400000f0 }, | ||
1105 | { 0x15, 0x400000f0 }, | ||
1106 | {} /* terminator */ | ||
1107 | }; | ||
1108 | |||
1109 | static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { | ||
1110 | [CS420X_MBP55] = mbp55_pincfgs, | ||
1111 | }; | ||
1112 | |||
1113 | static void fix_pincfg(struct hda_codec *codec, int model) | ||
1114 | { | ||
1115 | const struct cs_pincfg *cfg = cs_pincfgs[model]; | ||
1116 | if (!cfg) | ||
1117 | return; | ||
1118 | for (; cfg->nid; cfg++) | ||
1119 | snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); | ||
1120 | } | ||
1121 | |||
1122 | |||
1123 | static int patch_cs420x(struct hda_codec *codec) | ||
1124 | { | ||
1125 | struct cs_spec *spec; | ||
1126 | int err; | ||
1127 | |||
1128 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1129 | if (!spec) | ||
1130 | return -ENOMEM; | ||
1131 | codec->spec = spec; | ||
1132 | |||
1133 | spec->board_config = | ||
1134 | snd_hda_check_board_config(codec, CS420X_MODELS, | ||
1135 | cs420x_models, cs420x_cfg_tbl); | ||
1136 | if (spec->board_config >= 0) | ||
1137 | fix_pincfg(codec, spec->board_config); | ||
1138 | |||
1139 | switch (spec->board_config) { | ||
1140 | case CS420X_MBP55: | ||
1141 | /* GPIO1 = headphones */ | ||
1142 | /* GPIO3 = speakers */ | ||
1143 | spec->gpio_mask = 0x0a; | ||
1144 | spec->gpio_dir = 0x0a; | ||
1145 | break; | ||
1146 | } | ||
1147 | |||
1148 | err = cs_parse_auto_config(codec); | ||
1149 | if (err < 0) | ||
1150 | goto error; | ||
1151 | |||
1152 | codec->patch_ops = cs_patch_ops; | ||
1153 | |||
1154 | return 0; | ||
1155 | |||
1156 | error: | ||
1157 | kfree(codec->spec); | ||
1158 | codec->spec = NULL; | ||
1159 | return err; | ||
1160 | } | ||
1161 | |||
1162 | |||
1163 | /* | ||
1164 | * patch entries | ||
1165 | */ | ||
1166 | static struct hda_codec_preset snd_hda_preset_cirrus[] = { | ||
1167 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, | ||
1168 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, | ||
1169 | {} /* terminator */ | ||
1170 | }; | ||
1171 | |||
1172 | MODULE_ALIAS("snd-hda-codec-id:10134206"); | ||
1173 | MODULE_ALIAS("snd-hda-codec-id:10134207"); | ||
1174 | |||
1175 | MODULE_LICENSE("GPL"); | ||
1176 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); | ||
1177 | |||
1178 | static struct hda_codec_preset_list cirrus_list = { | ||
1179 | .preset = snd_hda_preset_cirrus, | ||
1180 | .owner = THIS_MODULE, | ||
1181 | }; | ||
1182 | |||
1183 | static int __init patch_cirrus_init(void) | ||
1184 | { | ||
1185 | return snd_hda_add_codec_preset(&cirrus_list); | ||
1186 | } | ||
1187 | |||
1188 | static void __exit patch_cirrus_exit(void) | ||
1189 | { | ||
1190 | snd_hda_delete_codec_preset(&cirrus_list); | ||
1191 | } | ||
1192 | |||
1193 | module_init(patch_cirrus_init) | ||
1194 | module_exit(patch_cirrus_exit) | ||