2 * Universal Interface for Intel High Definition Audio Codec
4 * HD audio interface patch for SigmaTel STAC92xx
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
7 * <matt@embeddedalley.com>
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sound/driver.h>
28 #include <linux/init.h>
29 #include <linux/delay.h>
30 #include <linux/slab.h>
31 #include <linux/pci.h>
32 #include <sound/core.h>
33 #include "hda_codec.h"
34 #include "hda_local.h"
38 struct sigmatel_spec
{
40 struct hda_multi_out multiout
;
41 hda_nid_t playback_nid
;
45 unsigned int num_adcs
;
47 unsigned int num_muxes
;
48 hda_nid_t capture_nid
;
52 hda_nid_t
*pstate_nids
;
53 unsigned int num_pstates
;
57 unsigned int num_pins
;
59 unsigned int *pin_configs
;
62 /* codec specific stuff */
63 struct hda_verb
*init
;
64 snd_kcontrol_new_t
*mixer
;
67 struct hda_input_mux input_mux
;
68 char input_labels
[HDA_MAX_NUM_INPUTS
][16];
69 unsigned int cur_mux
[2];
72 unsigned int num_ch_modes
;
73 unsigned int cur_ch_mode
;
74 const struct sigmatel_channel_mode
*channel_modes
;
76 struct hda_pcm pcm_rec
[1]; /* PCM information */
79 static hda_nid_t stac9200_adc_nids
[1] = {
83 static hda_nid_t stac9200_mux_nids
[1] = {
87 static hda_nid_t stac9200_dac_nids
[1] = {
91 static hda_nid_t stac9200_pstate_nids
[3] = {
95 static hda_nid_t stac9200_pin_nids
[8] = {
96 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
99 static hda_nid_t stac922x_adc_nids
[2] = {
103 static hda_nid_t stac922x_mux_nids
[2] = {
107 static hda_nid_t stac922x_dac_nids
[4] = {
108 0x02, 0x03, 0x04, 0x05,
111 static hda_nid_t stac922x_pstate_nids
[8] = {
112 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11,
115 static hda_nid_t stac922x_pin_nids
[10] = {
116 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
117 0x0f, 0x10, 0x11, 0x15, 0x1b,
120 static int stac92xx_mux_enum_info(snd_kcontrol_t
*kcontrol
, snd_ctl_elem_info_t
*uinfo
)
122 struct hda_codec
*codec
= snd_kcontrol_chip(kcontrol
);
123 struct sigmatel_spec
*spec
= codec
->spec
;
124 return snd_hda_input_mux_info(&spec
->input_mux
, uinfo
);
127 static int stac92xx_mux_enum_get(snd_kcontrol_t
*kcontrol
, snd_ctl_elem_value_t
*ucontrol
)
129 struct hda_codec
*codec
= snd_kcontrol_chip(kcontrol
);
130 struct sigmatel_spec
*spec
= codec
->spec
;
131 unsigned int adc_idx
= snd_ctl_get_ioffidx(kcontrol
, &ucontrol
->id
);
133 ucontrol
->value
.enumerated
.item
[0] = spec
->cur_mux
[adc_idx
];
137 static int stac92xx_mux_enum_put(snd_kcontrol_t
*kcontrol
, snd_ctl_elem_value_t
*ucontrol
)
139 struct hda_codec
*codec
= snd_kcontrol_chip(kcontrol
);
140 struct sigmatel_spec
*spec
= codec
->spec
;
141 unsigned int adc_idx
= snd_ctl_get_ioffidx(kcontrol
, &ucontrol
->id
);
143 return snd_hda_input_mux_put(codec
, &spec
->input_mux
, ucontrol
,
144 spec
->mux_nids
[adc_idx
], &spec
->cur_mux
[adc_idx
]);
147 static struct hda_verb stac9200_ch2_init
[] = {
148 /* set dac0mux for dac converter */
149 { 0x07, 0x701, 0x00},
153 static struct hda_verb stac922x_ch2_init
[] = {
154 /* set master volume and direct control */
155 { 0x16, 0x70f, 0xff},
159 struct sigmatel_channel_mode
{
160 unsigned int channels
;
161 const struct hda_verb
*sequence
;
164 static snd_kcontrol_new_t stac9200_mixer
[] = {
165 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT
),
166 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT
),
168 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
169 .name
= "Input Source",
171 .info
= stac92xx_mux_enum_info
,
172 .get
= stac92xx_mux_enum_get
,
173 .put
= stac92xx_mux_enum_put
,
175 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT
),
176 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT
),
177 HDA_CODEC_VOLUME("Input Mux Volume", 0x0c, 0, HDA_OUTPUT
),
181 static snd_kcontrol_new_t stac922x_mixer
[] = {
182 HDA_CODEC_VOLUME("PCM Playback Volume", 0x2, 0x0, HDA_OUTPUT
),
183 HDA_CODEC_MUTE("PCM Playback Switch", 0x2, 0x0, HDA_OUTPUT
),
185 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
186 .name
= "Input Source",
188 .info
= stac92xx_mux_enum_info
,
189 .get
= stac92xx_mux_enum_get
,
190 .put
= stac92xx_mux_enum_put
,
192 HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT
),
193 HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT
),
194 HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT
),
198 static int stac92xx_build_controls(struct hda_codec
*codec
)
200 struct sigmatel_spec
*spec
= codec
->spec
;
203 err
= snd_hda_add_new_ctls(codec
, spec
->mixer
);
206 if (spec
->multiout
.dig_out_nid
) {
207 err
= snd_hda_create_spdif_out_ctls(codec
, spec
->multiout
.dig_out_nid
);
211 if (spec
->dig_in_nid
) {
212 err
= snd_hda_create_spdif_in_ctls(codec
, spec
->dig_in_nid
);
220 static unsigned int stac9200_pin_configs
[8] = {
221 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
222 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
225 static unsigned int stac922x_pin_configs
[14] = {
226 0x40000100, 0x40000100, 0x40000100, 0x01114010,
227 0x01813122, 0x40000100, 0x01447010, 0x01c47010,
228 0x40000100, 0x40000100,
231 static void stac92xx_set_config_regs(struct hda_codec
*codec
)
234 struct sigmatel_spec
*spec
= codec
->spec
;
235 unsigned int pin_cfg
;
237 for (i
=0; i
< spec
->num_pins
; i
++) {
238 snd_hda_codec_write(codec
, spec
->pin_nids
[i
], 0,
239 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0
,
240 spec
->pin_configs
[i
] & 0x000000ff);
241 snd_hda_codec_write(codec
, spec
->pin_nids
[i
], 0,
242 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1
,
243 (spec
->pin_configs
[i
] & 0x0000ff00) >> 8);
244 snd_hda_codec_write(codec
, spec
->pin_nids
[i
], 0,
245 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2
,
246 (spec
->pin_configs
[i
] & 0x00ff0000) >> 16);
247 snd_hda_codec_write(codec
, spec
->pin_nids
[i
], 0,
248 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3
,
249 spec
->pin_configs
[i
] >> 24);
250 pin_cfg
= snd_hda_codec_read(codec
, spec
->pin_nids
[i
], 0,
251 AC_VERB_GET_CONFIG_DEFAULT
,
253 printk("pin nid %2.2x pin config %8.8x\n", spec
->pin_nids
[i
], pin_cfg
);
258 static int stac92xx_set_pinctl(struct hda_codec
*codec
, hda_nid_t nid
, unsigned int value
)
260 unsigned int pin_ctl
;
262 pin_ctl
= snd_hda_codec_read(codec
, nid
, 0,
263 AC_VERB_GET_PIN_WIDGET_CONTROL
,
265 snd_hda_codec_write(codec
, nid
, 0, AC_VERB_SET_PIN_WIDGET_CONTROL
,
271 static int stac92xx_set_vref(struct hda_codec
*codec
, hda_nid_t nid
)
273 unsigned int vref_caps
= snd_hda_param_read(codec
, nid
, AC_PAR_PIN_CAP
) >> AC_PINCAP_VREF_SHIFT
;
274 unsigned int vref_ctl
= AC_PINCTL_VREF_HIZ
;
276 if (vref_caps
& AC_PINCAP_VREF_100
)
277 vref_ctl
= AC_PINCTL_VREF_100
;
278 else if (vref_caps
& AC_PINCAP_VREF_80
)
279 vref_ctl
= AC_PINCTL_VREF_80
;
280 else if (vref_caps
& AC_PINCAP_VREF_50
)
281 vref_ctl
= AC_PINCTL_VREF_50
;
282 else if (vref_caps
& AC_PINCAP_VREF_GRD
)
283 vref_ctl
= AC_PINCTL_VREF_GRD
;
285 stac92xx_set_pinctl(codec
, nid
, vref_ctl
);
291 * retrieve the default device type from the default config value
293 #define get_defcfg_type(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
294 #define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
296 static int stac92xx_config_pin(struct hda_codec
*codec
, hda_nid_t nid
, unsigned int pin_cfg
)
298 struct sigmatel_spec
*spec
= codec
->spec
;
299 u32 location
= get_defcfg_location(pin_cfg
);
301 const char *type
= NULL
;
304 switch(get_defcfg_type(pin_cfg
)) {
307 stac92xx_set_pinctl(codec
, nid
, AC_PINCTL_HP_EN
);
309 case AC_JACK_SPDIF_OUT
:
310 case AC_JACK_LINE_OUT
:
311 case AC_JACK_SPEAKER
:
313 stac92xx_set_pinctl(codec
, nid
, AC_PINCTL_OUT_EN
);
315 case AC_JACK_SPDIF_IN
:
316 stac92xx_set_pinctl(codec
, nid
, AC_PINCTL_IN_EN
);
319 if ((location
& 0x0f) == AC_JACK_LOC_FRONT
)
325 stac92xx_set_vref(codec
, nid
);
326 stac92xx_set_pinctl(codec
, nid
, AC_PINCTL_IN_EN
);
331 stac92xx_set_pinctl(codec
, nid
, AC_PINCTL_IN_EN
);
333 case AC_JACK_LINE_IN
:
334 if ((location
& 0x0f) == AC_JACK_LOC_FRONT
)
339 stac92xx_set_pinctl(codec
, nid
, AC_PINCTL_IN_EN
);
342 if ((location
& 0x0f) == AC_JACK_LOC_FRONT
)
347 stac92xx_set_pinctl(codec
, nid
, AC_PINCTL_IN_EN
);
352 hda_nid_t con_lst
[HDA_MAX_NUM_INPUTS
];
353 int i
, j
, num_cons
, index
= -1;
356 label
= spec
->input_labels
[spec
->input_mux
.num_items
];
358 spec
->input_mux
.items
[spec
->input_mux
.num_items
].label
= label
;
359 for (i
=0; i
<spec
->num_muxes
; i
++) {
360 num_cons
= snd_hda_get_connections(codec
, spec
->mux_nids
[i
], con_lst
, HDA_MAX_NUM_INPUTS
);
361 for (j
=0; j
<num_cons
; j
++)
362 if (con_lst
[j
] == nid
) {
369 spec
->input_mux
.items
[spec
->input_mux
.num_items
].index
= index
;
370 spec
->input_mux
.num_items
++;
376 static int stac92xx_config_pins(struct hda_codec
*codec
)
378 struct sigmatel_spec
*spec
= codec
->spec
;
380 unsigned int pin_cfg
;
382 for (i
=0; i
< spec
->num_pins
; i
++) {
383 /* Default to disabled */
384 snd_hda_codec_write(codec
, spec
->pin_nids
[i
], 0,
385 AC_VERB_SET_PIN_WIDGET_CONTROL
,
388 pin_cfg
= snd_hda_codec_read(codec
, spec
->pin_nids
[i
], 0,
389 AC_VERB_GET_CONFIG_DEFAULT
,
391 if (((pin_cfg
& AC_DEFCFG_PORT_CONN
) >> AC_DEFCFG_PORT_CONN_SHIFT
) == AC_JACK_PORT_NONE
)
392 continue; /* Move on */
394 stac92xx_config_pin(codec
, spec
->pin_nids
[i
], pin_cfg
);
400 static int stac92xx_init(struct hda_codec
*codec
)
402 struct sigmatel_spec
*spec
= codec
->spec
;
405 for (i
=0; i
< spec
->num_pstates
; i
++)
406 snd_hda_codec_write(codec
, spec
->pstate_nids
[i
], 0,
407 AC_VERB_SET_POWER_STATE
, 0x00);
411 snd_hda_sequence_write(codec
, spec
->init
);
414 stac92xx_set_config_regs(codec
);
417 stac92xx_config_pins(codec
);
423 * Analog playback callbacks
425 static int stac92xx_playback_pcm_open(struct hda_pcm_stream
*hinfo
,
426 struct hda_codec
*codec
,
427 snd_pcm_substream_t
*substream
)
429 struct sigmatel_spec
*spec
= codec
->spec
;
430 return snd_hda_multi_out_analog_open(codec
, &spec
->multiout
, substream
);
433 static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream
*hinfo
,
434 struct hda_codec
*codec
,
435 unsigned int stream_tag
,
437 snd_pcm_substream_t
*substream
)
439 struct sigmatel_spec
*spec
= codec
->spec
;
440 return snd_hda_multi_out_analog_prepare(codec
, &spec
->multiout
, stream_tag
,
444 static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream
*hinfo
,
445 struct hda_codec
*codec
,
446 snd_pcm_substream_t
*substream
)
448 struct sigmatel_spec
*spec
= codec
->spec
;
449 return snd_hda_multi_out_analog_cleanup(codec
, &spec
->multiout
);
453 * Digital playback callbacks
455 static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream
*hinfo
,
456 struct hda_codec
*codec
,
457 snd_pcm_substream_t
*substream
)
459 struct sigmatel_spec
*spec
= codec
->spec
;
460 return snd_hda_multi_out_dig_open(codec
, &spec
->multiout
);
463 static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream
*hinfo
,
464 struct hda_codec
*codec
,
465 snd_pcm_substream_t
*substream
)
467 struct sigmatel_spec
*spec
= codec
->spec
;
468 return snd_hda_multi_out_dig_close(codec
, &spec
->multiout
);
473 * Analog capture callbacks
475 static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream
*hinfo
,
476 struct hda_codec
*codec
,
477 unsigned int stream_tag
,
479 snd_pcm_substream_t
*substream
)
481 struct sigmatel_spec
*spec
= codec
->spec
;
483 snd_hda_codec_setup_stream(codec
, spec
->adc_nids
[substream
->number
],
484 stream_tag
, 0, format
);
488 static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream
*hinfo
,
489 struct hda_codec
*codec
,
490 snd_pcm_substream_t
*substream
)
492 struct sigmatel_spec
*spec
= codec
->spec
;
494 snd_hda_codec_setup_stream(codec
, spec
->adc_nids
[substream
->number
], 0, 0, 0);
498 static struct hda_pcm_stream stac92xx_pcm_digital_playback
= {
502 /* NID is set in stac92xx_build_pcms */
504 .open
= stac92xx_dig_playback_pcm_open
,
505 .close
= stac92xx_dig_playback_pcm_close
509 static struct hda_pcm_stream stac92xx_pcm_digital_capture
= {
513 /* NID is set in stac92xx_build_pcms */
516 static struct hda_pcm_stream stac92xx_pcm_analog_playback
= {
520 .nid
= 0x02, /* NID to query formats and rates */
522 .open
= stac92xx_playback_pcm_open
,
523 .prepare
= stac92xx_playback_pcm_prepare
,
524 .cleanup
= stac92xx_playback_pcm_cleanup
528 static struct hda_pcm_stream stac92xx_pcm_analog_capture
= {
532 .nid
= 0x06, /* NID to query formats and rates */
534 .prepare
= stac92xx_capture_pcm_prepare
,
535 .cleanup
= stac92xx_capture_pcm_cleanup
539 static int stac92xx_build_pcms(struct hda_codec
*codec
)
541 struct sigmatel_spec
*spec
= codec
->spec
;
542 struct hda_pcm
*info
= spec
->pcm_rec
;
545 codec
->pcm_info
= info
;
547 info
->name
= "STAC92xx";
548 info
->stream
[SNDRV_PCM_STREAM_PLAYBACK
] = stac92xx_pcm_analog_playback
;
549 info
->stream
[SNDRV_PCM_STREAM_PLAYBACK
].nid
= spec
->playback_nid
;
550 info
->stream
[SNDRV_PCM_STREAM_CAPTURE
] = stac92xx_pcm_analog_capture
;
551 info
->stream
[SNDRV_PCM_STREAM_CAPTURE
].nid
= spec
->capture_nid
;
553 if (spec
->multiout
.dig_out_nid
|| spec
->dig_in_nid
) {
556 info
->name
= "STAC92xx Digital";
557 if (spec
->multiout
.dig_out_nid
) {
558 info
->stream
[SNDRV_PCM_STREAM_PLAYBACK
] = stac92xx_pcm_digital_playback
;
559 info
->stream
[SNDRV_PCM_STREAM_PLAYBACK
].nid
= spec
->multiout
.dig_out_nid
;
561 if (spec
->dig_in_nid
) {
562 info
->stream
[SNDRV_PCM_STREAM_CAPTURE
] = stac92xx_pcm_digital_capture
;
563 info
->stream
[SNDRV_PCM_STREAM_CAPTURE
].nid
= spec
->dig_in_nid
;
570 static void stac92xx_free(struct hda_codec
*codec
)
575 static struct hda_codec_ops stac92xx_patch_ops
= {
576 .build_controls
= stac92xx_build_controls
,
577 .build_pcms
= stac92xx_build_pcms
,
578 .init
= stac92xx_init
,
579 .free
= stac92xx_free
,
582 static int patch_stac9200(struct hda_codec
*codec
)
584 struct sigmatel_spec
*spec
;
586 spec
= kcalloc(1, sizeof(*spec
), GFP_KERNEL
);
592 spec
->multiout
.max_channels
= 2;
593 spec
->multiout
.num_dacs
= 1;
594 spec
->multiout
.dac_nids
= stac9200_dac_nids
;
595 spec
->multiout
.dig_out_nid
= 0x05;
596 spec
->dig_in_nid
= 0x04;
597 spec
->adc_nids
= stac9200_adc_nids
;
598 spec
->mux_nids
= stac9200_mux_nids
;
600 spec
->input_mux
.num_items
= 0;
601 spec
->pstate_nids
= stac9200_pstate_nids
;
602 spec
->num_pstates
= 3;
603 spec
->pin_nids
= stac9200_pin_nids
;
605 spec
->pin_configs
= stac9200_pin_configs
;
608 spec
->init
= stac9200_ch2_init
;
609 spec
->mixer
= stac9200_mixer
;
610 spec
->playback_nid
= 0x02;
611 spec
->capture_nid
= 0x03;
613 codec
->patch_ops
= stac92xx_patch_ops
;
618 static int patch_stac922x(struct hda_codec
*codec
)
620 struct sigmatel_spec
*spec
;
622 spec
= kcalloc(1, sizeof(*spec
), GFP_KERNEL
);
628 spec
->multiout
.max_channels
= 2;
629 spec
->multiout
.num_dacs
= 4;
630 spec
->multiout
.dac_nids
= stac922x_dac_nids
;
631 spec
->multiout
.dig_out_nid
= 0x08;
632 spec
->dig_in_nid
= 0x09;
633 spec
->adc_nids
= stac922x_adc_nids
;
634 spec
->mux_nids
= stac922x_mux_nids
;
636 spec
->input_mux
.num_items
= 0;
637 spec
->pstate_nids
= stac922x_pstate_nids
;
638 spec
->num_pstates
= 8;
639 spec
->pin_nids
= stac922x_pin_nids
;
641 spec
->pin_configs
= stac922x_pin_configs
;
644 spec
->init
= stac922x_ch2_init
;
645 spec
->mixer
= stac922x_mixer
;
646 spec
->playback_nid
= 0x02;
647 spec
->capture_nid
= 0x06;
649 codec
->patch_ops
= stac92xx_patch_ops
;
657 struct hda_codec_preset snd_hda_preset_sigmatel
[] = {
658 { .id
= 0x83847690, .name
= "STAC9200", .patch
= patch_stac9200
},
659 { .id
= 0x83847882, .name
= "STAC9220 A1", .patch
= patch_stac922x
},
660 { .id
= 0x83847680, .name
= "STAC9221 A1", .patch
= patch_stac922x
},
661 { .id
= 0x83847880, .name
= "STAC9220 A2", .patch
= patch_stac922x
},
662 { .id
= 0x83847681, .name
= "STAC9220D/9223D A2", .patch
= patch_stac922x
},
663 { .id
= 0x83847682, .name
= "STAC9221 A2", .patch
= patch_stac922x
},
664 { .id
= 0x83847683, .name
= "STAC9221D A2", .patch
= patch_stac922x
},