提交 433e8327 编写于 作者: T Takashi Iwai

Merge branch 'topic/hda' into for-linus

......@@ -29,6 +29,7 @@
#include <sound/asoundef.h>
#include <sound/tlv.h>
#include <sound/initval.h>
#include <sound/jack.h>
#include "hda_local.h"
#include "hda_beep.h"
#include <sound/hda_hwdep.h>
......@@ -4959,5 +4960,109 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen)
}
EXPORT_SYMBOL_HDA(snd_print_pcm_bits);
#ifdef CONFIG_SND_HDA_INPUT_JACK
/*
* Input-jack notification support
*/
struct hda_jack_item {
hda_nid_t nid;
int type;
struct snd_jack *jack;
};
static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
int type)
{
switch (type) {
case SND_JACK_HEADPHONE:
return "Headphone";
case SND_JACK_MICROPHONE:
return "Mic";
case SND_JACK_LINEOUT:
return "Line-out";
case SND_JACK_HEADSET:
return "Headset";
default:
return "Misc";
}
}
static void hda_free_jack_priv(struct snd_jack *jack)
{
struct hda_jack_item *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}
int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
const char *name)
{
struct hda_jack_item *jack;
int err;
snd_array_init(&codec->jacks, sizeof(*jack), 32);
jack = snd_array_new(&codec->jacks);
if (!jack)
return -ENOMEM;
jack->nid = nid;
jack->type = type;
if (!name)
name = get_jack_default_name(codec, nid, type);
err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
if (err < 0) {
jack->nid = 0;
return err;
}
jack->jack->private_data = jack;
jack->jack->private_free = hda_free_jack_priv;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_add);
void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_jack_item *jacks = codec->jacks.list;
int i;
if (!jacks)
return;
for (i = 0; i < codec->jacks.used; i++, jacks++) {
unsigned int pin_ctl;
unsigned int present;
int type;
if (jacks->nid != nid)
continue;
present = snd_hda_jack_detect(codec, nid);
type = jacks->type;
if (type == (SND_JACK_HEADPHONE | SND_JACK_LINEOUT)) {
pin_ctl = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
type = (pin_ctl & AC_PINCTL_HP_EN) ?
SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
}
snd_jack_report(jacks->jack, present ? type : 0);
}
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_report);
/* free jack instances manually when clearing/reconfiguring */
void snd_hda_input_jack_free(struct hda_codec *codec)
{
if (!codec->bus->shutdown && codec->jacks.list) {
struct hda_jack_item *jacks = codec->jacks.list;
int i;
for (i = 0; i < codec->jacks.used; i++, jacks++) {
if (jacks->jack)
snd_device_free(codec->bus->card, jacks->jack);
}
}
snd_array_free(&codec->jacks);
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_free);
#endif /* CONFIG_SND_HDA_INPUT_JACK */
MODULE_DESCRIPTION("HDA codec core");
MODULE_LICENSE("GPL");
......@@ -866,6 +866,11 @@ struct hda_codec {
/* codec-specific additional proc output */
void (*proc_widget_hook)(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid);
#ifdef CONFIG_SND_HDA_INPUT_JACK
/* jack detection */
struct snd_array jacks;
#endif
};
/* direction */
......
......@@ -1052,9 +1052,12 @@ static void azx_init_pci(struct azx *chip)
/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
* TCSEL == Traffic Class Select Register, which sets PCI express QOS
* Ensuring these bits are 0 clears playback static on some HD Audio
* codecs
* codecs.
* The PCI register TCSEL is defined in the Intel manuals.
*/
update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
if (chip->driver_type != AZX_DRIVER_ATI &&
chip->driver_type != AZX_DRIVER_ATIHDMI)
update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
switch (chip->driver_type) {
case AZX_DRIVER_ATI:
......
......@@ -656,4 +656,28 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
/*
* Input-jack notification support
*/
#ifdef CONFIG_SND_HDA_INPUT_JACK
int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
const char *name);
void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid);
void snd_hda_input_jack_free(struct hda_codec *codec);
#else /* CONFIG_SND_HDA_INPUT_JACK */
static inline int snd_hda_input_jack_add(struct hda_codec *codec,
hda_nid_t nid, int type,
const char *name)
{
return 0;
}
static inline void snd_hda_input_jack_report(struct hda_codec *codec,
hda_nid_t nid)
{
}
static inline void snd_hda_input_jack_free(struct hda_codec *codec)
{
}
#endif /* CONFIG_SND_HDA_INPUT_JACK */
#endif /* __SOUND_HDA_LOCAL_H */
......@@ -30,10 +30,10 @@
#include "hda_beep.h"
struct ad198x_spec {
struct snd_kcontrol_new *mixers[5];
struct snd_kcontrol_new *mixers[6];
int num_mixers;
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
const struct hda_verb *init_verbs[5]; /* initialization verbs
const struct hda_verb *init_verbs[6]; /* initialization verbs
* don't forget NULL termination!
*/
unsigned int num_init_verbs;
......@@ -331,36 +331,11 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
}
static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct ad198x_spec *spec = codec->spec;
snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag,
0, format);
return 0;
}
static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ad198x_spec *spec = codec->spec;
snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]);
return 0;
}
static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
/* NID is set in ad198x_build_pcms */
.ops = {
.prepare = ad198x_alt_playback_pcm_prepare,
.cleanup = ad198x_alt_playback_pcm_cleanup
},
};
/*
......@@ -2239,29 +2214,6 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
{ } /* end */
};
......@@ -2545,11 +2497,6 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
};
static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
/* Front, Surround, CLFE, side DAC; unmute as default */
{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Headphone; unmute as default */
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Port-A front headphon path */
......@@ -2558,50 +2505,6 @@ static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
/* Port-D line-out path */
{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* Port-F surround path */
{0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* Port-G CLFE path */
{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* Port-H side path */
{0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* Mono out path */
{0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
/* Port-B front mic-in path */
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
/* Port-C line-in path */
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
{0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
/* Port-E mic-in path */
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
/* Analog CD Input */
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
/* Analog Mix output amp */
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
{ }
};
......@@ -3316,20 +3219,20 @@ static int patch_ad1988(struct hda_codec *codec)
spec->mixers[0] = ad1988_6stack_mixers1_rev2;
else
spec->mixers[0] = ad1988_6stack_mixers1;
spec->mixers[1] = ad1988_6stack_mixers2;
spec->num_init_verbs = 1;
spec->init_verbs[0] = ad1988_6stack_init_verbs;
if (board_config == AD1988_6STACK_DIG_FP) {
spec->mixers[1] = ad1988_6stack_fp_mixers;
spec->num_mixers++;
spec->mixers[2] = ad1988_6stack_fp_mixers;
spec->num_init_verbs++;
spec->init_verbs[1] = ad1988_6stack_fp_init_verbs;
spec->slave_vols = ad1988_6stack_fp_slave_vols;
spec->slave_sws = ad1988_6stack_fp_slave_sws;
spec->alt_dac_nid = ad1988_alt_dac_nid;
spec->stream_analog_alt_playback =
&ad198x_pcm_analog_alt_playback;
} else
spec->mixers[1] = ad1988_6stack_mixers2;
spec->num_init_verbs = 1;
if (board_config == AD1988_6STACK_DIG_FP)
spec->init_verbs[0] = ad1988_6stack_fp_init_verbs;
else
spec->init_verbs[0] = ad1988_6stack_init_verbs;
}
if ((board_config == AD1988_6STACK_DIG) ||
(board_config == AD1988_6STACK_DIG_FP)) {
spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
......
......@@ -49,14 +49,6 @@
#define AUTO_MIC_PORTB (1 << 1)
#define AUTO_MIC_PORTC (1 << 2)
struct conexant_jack {
hda_nid_t nid;
int type;
struct snd_jack *jack;
};
struct pin_dac_pair {
hda_nid_t pin;
hda_nid_t dac;
......@@ -111,9 +103,6 @@ struct conexant_spec {
unsigned int spdif_route;
/* jack detection */
struct snd_array jacks;
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct hda_input_mux private_imux;
......@@ -393,71 +382,9 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
&spec->cur_mux[adc_idx]);
}
#ifdef CONFIG_SND_HDA_INPUT_JACK
static void conexant_free_jack_priv(struct snd_jack *jack)
{
struct conexant_jack *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}
static int conexant_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
struct conexant_spec *spec;
struct conexant_jack *jack;
const char *name;
int i, err;
spec = codec->spec;
snd_array_init(&spec->jacks, sizeof(*jack), 32);
jack = spec->jacks.list;
for (i = 0; i < spec->jacks.used; i++, jack++)
if (jack->nid == nid)
return 0 ; /* already present */
jack = snd_array_new(&spec->jacks);
name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
if (!jack)
return -ENOMEM;
jack->nid = nid;
jack->type = type;
err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
if (err < 0)
return err;
jack->jack->private_data = jack;
jack->jack->private_free = conexant_free_jack_priv;
return 0;
}
static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
struct conexant_spec *spec = codec->spec;
struct conexant_jack *jacks = spec->jacks.list;
if (jacks) {
int i;
for (i = 0; i < spec->jacks.used; i++) {
if (jacks->nid == nid) {
unsigned int present;
present = snd_hda_jack_detect(codec, nid);
present = (present) ? jacks->type : 0 ;
snd_jack_report(jacks->jack,
present);
}
jacks++;
}
}
}
static int conexant_init_jacks(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
struct conexant_spec *spec = codec->spec;
int i;
......@@ -469,15 +396,15 @@ static int conexant_init_jacks(struct hda_codec *codec)
int err = 0;
switch (hv->param ^ AC_USRSP_EN) {
case CONEXANT_HP_EVENT:
err = conexant_add_jack(codec, hv->nid,
SND_JACK_HEADPHONE);
conexant_report_jack(codec, hv->nid);
err = snd_hda_input_jack_add(codec, hv->nid,
SND_JACK_HEADPHONE, NULL);
snd_hda_input_jack_report(codec, hv->nid);
break;
case CXT5051_PORTC_EVENT:
case CONEXANT_MIC_EVENT:
err = conexant_add_jack(codec, hv->nid,
SND_JACK_MICROPHONE);
conexant_report_jack(codec, hv->nid);
err = snd_hda_input_jack_add(codec, hv->nid,
SND_JACK_MICROPHONE, NULL);
snd_hda_input_jack_report(codec, hv->nid);
break;
}
if (err < 0)
......@@ -485,19 +412,9 @@ static int conexant_init_jacks(struct hda_codec *codec)
++hv;
}
}
return 0;
}
#else
static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
}
static inline int conexant_init_jacks(struct hda_codec *codec)
{
#endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0;
}
#endif
static int conexant_init(struct hda_codec *codec)
{
......@@ -511,18 +428,7 @@ static int conexant_init(struct hda_codec *codec)
static void conexant_free(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
struct conexant_spec *spec = codec->spec;
if (spec->jacks.list) {
struct conexant_jack *jacks = spec->jacks.list;
int i;
for (i = 0; i < spec->jacks.used; i++, jacks++) {
if (jacks->jack)
snd_device_free(codec->bus->card, jacks->jack);
}
snd_array_free(&spec->jacks);
}
#endif
snd_hda_input_jack_free(codec);
snd_hda_detach_beep_device(codec);
kfree(codec->spec);
}
......@@ -1787,7 +1693,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
cxt5051_portc_automic(codec);
break;
}
conexant_report_jack(codec, nid);
snd_hda_input_jack_report(codec, nid);
}
static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
......@@ -1959,10 +1865,8 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | event);
#ifdef CONFIG_SND_HDA_INPUT_JACK
conexant_add_jack(codec, nid, SND_JACK_MICROPHONE);
conexant_report_jack(codec, nid);
#endif
snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL);
snd_hda_input_jack_report(codec, nid);
}
static struct hda_verb cxt5051_ideapad_init_verbs[] = {
......@@ -3477,11 +3381,11 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
switch (res >> 26) {
case CONEXANT_HP_EVENT:
cx_auto_hp_automute(codec);
conexant_report_jack(codec, nid);
snd_hda_input_jack_report(codec, nid);
break;
case CONEXANT_MIC_EVENT:
cx_auto_automic(codec);
conexant_report_jack(codec, nid);
snd_hda_input_jack_report(codec, nid);
break;
}
}
......
......@@ -110,6 +110,12 @@ struct dp_audio_infoframe {
u8 LFEPBL01_LSV36_DM_INH7;
};
union audio_infoframe {
struct hdmi_audio_infoframe hdmi;
struct dp_audio_infoframe dp;
u8 bytes[0];
};
/*
* CEA speaker placement:
*
......@@ -620,8 +626,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
int channels = substream->runtime->channels;
int ca;
int i;
u8 ai[max(sizeof(struct hdmi_audio_infoframe),
sizeof(struct dp_audio_infoframe))];
union audio_infoframe ai;
ca = hdmi_channel_allocation(codec, nid, channels);
......@@ -633,11 +638,10 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
pin_nid = spec->pin[i];
memset(ai, 0, sizeof(ai));
memset(&ai, 0, sizeof(ai));
if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
struct hdmi_audio_infoframe *hdmi_ai;
struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
hdmi_ai = (struct hdmi_audio_infoframe *)ai;
hdmi_ai->type = 0x84;
hdmi_ai->ver = 0x01;
hdmi_ai->len = 0x0a;
......@@ -645,9 +649,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
hdmi_ai->CA = ca;
hdmi_checksum_audio_infoframe(hdmi_ai);
} else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
struct dp_audio_infoframe *dp_ai;
struct dp_audio_infoframe *dp_ai = &ai.dp;
dp_ai = (struct dp_audio_infoframe *)ai;
dp_ai->type = 0x84;
dp_ai->len = 0x1b;
dp_ai->ver = 0x11 << 2;
......@@ -664,7 +667,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
* sizeof(*dp_ai) to avoid partial match/update problems when
* the user switches between HDMI/DP monitors.
*/
if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) {
if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
sizeof(ai))) {
snd_printdd("hdmi_setup_audio_infoframe: "
"cvt=%d pin=%d channels=%d\n",
nid, pin_nid,
......@@ -672,7 +676,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
hdmi_setup_channel_mapping(codec, pin_nid, ca);
hdmi_stop_infoframe_trans(codec, pin_nid);
hdmi_fill_audio_infoframe(codec, pin_nid,
ai, sizeof(ai));
ai.bytes, sizeof(ai));
hdmi_start_infoframe_trans(codec, pin_nid);
}
}
......
......@@ -282,12 +282,6 @@ struct alc_mic_route {
unsigned char amix_idx;
};
struct alc_jack {
hda_nid_t nid;
int type;
struct snd_jack *jack;
};
#define MUX_IDX_UNDEF ((unsigned char)-1)
struct alc_customize_define {
......@@ -366,9 +360,6 @@ struct alc_spec {
/* PCM information */
struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
/* jack detection */
struct snd_array jacks;
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct alc_customize_define cdefine;
......@@ -394,6 +385,7 @@ struct alc_spec {
/* other flags */
unsigned int no_analog :1; /* digital I/O only */
unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
unsigned int single_input_src:1;
int init_amp;
int codec_variant; /* flag for other variants */
......@@ -1032,94 +1024,32 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
alc_fix_pll(codec);
}
#ifdef CONFIG_SND_HDA_INPUT_JACK
static void alc_free_jack_priv(struct snd_jack *jack)
{
struct alc_jack *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}
static int alc_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
struct alc_spec *spec;
struct alc_jack *jack;
const char *name;
int err;
spec = codec->spec;
snd_array_init(&spec->jacks, sizeof(*jack), 32);
jack = snd_array_new(&spec->jacks);
if (!jack)
return -ENOMEM;
jack->nid = nid;
jack->type = type;
name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
if (err < 0)
return err;
jack->jack->private_data = jack;
jack->jack->private_free = alc_free_jack_priv;
return 0;
}
static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
struct alc_spec *spec = codec->spec;
struct alc_jack *jacks = spec->jacks.list;
if (jacks) {
int i;
for (i = 0; i < spec->jacks.used; i++) {
if (jacks->nid == nid) {
unsigned int present;
present = snd_hda_jack_detect(codec, nid);
present = (present) ? jacks->type : 0;
snd_jack_report(jacks->jack, present);
}
jacks++;
}
}
}
static int alc_init_jacks(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
struct alc_spec *spec = codec->spec;
int err;
unsigned int hp_nid = spec->autocfg.hp_pins[0];
unsigned int mic_nid = spec->ext_mic.pin;
if (hp_nid) {
err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
err = snd_hda_input_jack_add(codec, hp_nid,
SND_JACK_HEADPHONE, NULL);
if (err < 0)
return err;
alc_report_jack(codec, hp_nid);
snd_hda_input_jack_report(codec, hp_nid);
}
if (mic_nid) {
err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
err = snd_hda_input_jack_add(codec, mic_nid,
SND_JACK_MICROPHONE, NULL);
if (err < 0)
return err;
alc_report_jack(codec, mic_nid);
snd_hda_input_jack_report(codec, mic_nid);
}
return 0;
}
#else
static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
}
static inline int alc_init_jacks(struct hda_codec *codec)
{
#endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0;
}
#endif
static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
{
......@@ -1133,7 +1063,7 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
nid = spec->autocfg.hp_pins[i];
if (!nid)
break;
alc_report_jack(codec, nid);
snd_hda_input_jack_report(codec, nid);
spec->jack_present |= snd_hda_jack_detect(codec, nid);
}
......@@ -1240,7 +1170,7 @@ static void alc_mic_automute(struct hda_codec *codec)
AC_VERB_SET_CONNECT_SEL,
alive->mux_idx);
}
alc_report_jack(codec, spec->ext_mic.pin);
snd_hda_input_jack_report(codec, spec->ext_mic.pin);
/* FIXME: analog mixer */
}
......@@ -2292,13 +2222,13 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0f, 2, 0x0,
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
HDA_OUTPUT),
HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0f, 2, 2, HDA_INPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Side Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Side Playback Switch", 0x0e, 2, HDA_INPUT),
HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
......@@ -2309,7 +2239,6 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
{ } /* end */
};
static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
......@@ -3919,6 +3848,8 @@ static struct hda_amp_list alc880_lg_loopbacks[] = {
* Common callbacks
*/
static void alc_init_special_input_src(struct hda_codec *codec);
static int alc_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
......@@ -3929,6 +3860,7 @@ static int alc_init(struct hda_codec *codec)
for (i = 0; i < spec->num_init_verbs; i++)
snd_hda_sequence_write(codec, spec->init_verbs[i]);
alc_init_special_input_src(codec);
if (spec->init_hook)
spec->init_hook(codec);
......@@ -4284,6 +4216,7 @@ static void alc_free(struct hda_codec *codec)
return;
alc_shutup(codec);
snd_hda_input_jack_free(codec);
alc_free_kctls(codec);
kfree(spec);
snd_hda_detach_beep_device(codec);
......@@ -5151,7 +5084,9 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
switch (cfg->line_out_type) {
case AUTO_PIN_SPEAKER_OUT:
return "Speaker";
if (cfg->line_outs == 1)
return "Speaker";
break;
case AUTO_PIN_HP_OUT:
return "Headphone";
default:
......@@ -5205,16 +5140,19 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
return err;
} else {
const char *name = pfx;
if (!name)
int index = i;
if (!name) {
name = chname[i];
index = 0;
}
err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
name, i,
name, index,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
name, i,
name, index,
HDA_COMPOSE_AMP_VAL(nid, 3, 2,
HDA_INPUT));
if (err < 0)
......@@ -5585,6 +5523,7 @@ static void fixup_single_adc(struct hda_codec *codec)
spec->capsrc_nids += i;
spec->adc_nids += i;
spec->num_adc_nids = 1;
spec->single_input_src = 1;
}
}
......@@ -5596,6 +5535,16 @@ static void fixup_dual_adc_switch(struct hda_codec *codec)
init_capsrc_for_pin(codec, spec->int_mic.pin);
}
/* initialize some special cases for input sources */
static void alc_init_special_input_src(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
if (spec->dual_adc_switch)
fixup_dual_adc_switch(codec);
else if (spec->single_input_src)
init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
}
static void set_capture_mixer(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
......@@ -5611,7 +5560,7 @@ static void set_capture_mixer(struct hda_codec *codec)
int mux = 0;
int num_adcs = spec->num_adc_nids;
if (spec->dual_adc_switch)
fixup_dual_adc_switch(codec);
num_adcs = 1;
else if (spec->auto_mic)
fixup_automic_adc(codec);
else if (spec->input_mux) {
......@@ -5620,8 +5569,6 @@ static void set_capture_mixer(struct hda_codec *codec)
else if (spec->input_mux->num_items == 1)
fixup_single_adc(codec);
}
if (spec->dual_adc_switch)
num_adcs = 1;
spec->cap_mixer = caps[mux][num_adcs - 1];
}
}
......@@ -10748,6 +10695,7 @@ static struct alc_config_preset alc882_presets[] = {
*/
enum {
PINFIX_ABIT_AW9D_MAX,
PINFIX_LENOVO_Y530,
PINFIX_PB_M5210,
PINFIX_ACER_ASPIRE_7736,
};
......@@ -10762,6 +10710,14 @@ static const struct alc_fixup alc882_fixups[] = {
{ }
}
},
[PINFIX_LENOVO_Y530] = {
.type = ALC_FIXUP_PINS,
.v.pins = (const struct alc_pincfg[]) {
{ 0x15, 0x99130112 }, /* rear int speakers */
{ 0x16, 0x99130111 }, /* subwoofer */
{ }
}
},
[PINFIX_PB_M5210] = {
.type = ALC_FIXUP_VERBS,
.v.verbs = (const struct hda_verb[]) {
......@@ -10777,6 +10733,7 @@ static const struct alc_fixup alc882_fixups[] = {
static struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
{}
......@@ -10829,23 +10786,28 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
hda_nid_t pin, dac;
int i;
for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
pin = spec->autocfg.hp_pins[i];
if (!pin)
break;
dac = spec->multiout.hp_nid;
if (!dac)
dac = spec->multiout.dac_nids[0]; /* to front */
alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) {
for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
pin = spec->autocfg.hp_pins[i];
if (!pin)
break;
dac = spec->multiout.hp_nid;
if (!dac)
dac = spec->multiout.dac_nids[0]; /* to front */
alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
}
}
for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
pin = spec->autocfg.speaker_pins[i];
if (!pin)
break;
dac = spec->multiout.extra_out_nid[0];
if (!dac)
dac = spec->multiout.dac_nids[0]; /* to front */
alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) {
for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
pin = spec->autocfg.speaker_pins[i];
if (!pin)
break;
dac = spec->multiout.extra_out_nid[0];
if (!dac)
dac = spec->multiout.dac_nids[0]; /* to front */
alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
}
}
}
......@@ -13796,6 +13758,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
}
#define alc268_auto_init_analog_input alc882_auto_init_analog_input
#define alc268_auto_init_input_src alc882_auto_init_input_src
/* init callback for auto-configuration model -- overriding the default init */
static void alc268_auto_init(struct hda_codec *codec)
......@@ -13805,6 +13768,7 @@ static void alc268_auto_init(struct hda_codec *codec)
alc268_auto_init_hp_out(codec);
alc268_auto_init_mono_speaker_out(codec);
alc268_auto_init_analog_input(codec);
alc268_auto_init_input_src(codec);
alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
......@@ -14092,7 +14056,6 @@ static int patch_alc268(struct hda_codec *codec)
if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
/* check whether NID 0x07 is valid */
unsigned int wcap = get_wcaps(codec, 0x07);
int i;
spec->capsrc_nids = alc268_capsrc_nids;
/* get type */
......@@ -14112,13 +14075,6 @@ static int patch_alc268(struct hda_codec *codec)
spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
add_mixer(spec, alc268_capture_mixer);
}
/* set default input source */
for (i = 0; i < spec->num_adc_nids; i++)
snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
0, AC_VERB_SET_CONNECT_SEL,
i < spec->num_mux_defs ?
spec->input_mux[i].items[0].index :
spec->input_mux->items[0].index);
}
spec->vmaster_nid = 0x02;
......@@ -14495,7 +14451,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
HDA_AMP_MUTE, bits);
snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
HDA_AMP_MUTE, bits);
alc_report_jack(codec, nid);
snd_hda_input_jack_report(codec, nid);
}
/* unsolicited event for HP jack sensing */
......@@ -14807,11 +14763,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
fillup_priv_adc_nids(codec, alc269_adc_candidates,
sizeof(alc269_adc_candidates));
/* set default input source */
if (!spec->dual_adc_switch)
select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
spec->input_mux->items[0].index);
err = alc_auto_add_mic_boost(codec);
if (err < 0)
return err;
......@@ -14825,6 +14776,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
#define alc269_auto_init_multi_out alc268_auto_init_multi_out
#define alc269_auto_init_hp_out alc268_auto_init_hp_out
#define alc269_auto_init_analog_input alc882_auto_init_analog_input
#define alc269_auto_init_input_src alc882_auto_init_input_src
/* init callback for auto-configuration model -- overriding the default init */
......@@ -14834,6 +14786,8 @@ static void alc269_auto_init(struct hda_codec *codec)
alc269_auto_init_multi_out(codec);
alc269_auto_init_hp_out(codec);
alc269_auto_init_analog_input(codec);
if (!spec->dual_adc_switch)
alc269_auto_init_input_src(codec);
alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
......
......@@ -180,18 +180,16 @@ struct sigmatel_event {
int data;
};
struct sigmatel_jack {
hda_nid_t nid;
int type;
struct snd_jack *jack;
};
struct sigmatel_mic_route {
hda_nid_t pin;
signed char mux_idx;
signed char dmux_idx;
};
#define MAX_PINS_NUM 16
#define MAX_ADCS_NUM 4
#define MAX_DMICS_NUM 4
struct sigmatel_spec {
struct snd_kcontrol_new *mixers[4];
unsigned int num_mixers;
......@@ -229,9 +227,6 @@ struct sigmatel_spec {
hda_nid_t *pwr_nids;
hda_nid_t *dac_list;
/* jack detection */
struct snd_array jacks;
/* events */
struct snd_array events;
......@@ -309,6 +304,17 @@ struct sigmatel_spec {
struct hda_input_mux private_imux;
struct hda_input_mux private_smux;
struct hda_input_mux private_mono_mux;
/* auto spec */
unsigned auto_pin_cnt;
hda_nid_t auto_pin_nids[MAX_PINS_NUM];
unsigned auto_adc_cnt;
hda_nid_t auto_adc_nids[MAX_ADCS_NUM];
hda_nid_t auto_mux_nids[MAX_ADCS_NUM];
hda_nid_t auto_dmux_nids[MAX_ADCS_NUM];
unsigned long auto_capvols[MAX_ADCS_NUM];
unsigned auto_dmic_cnt;
hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
};
static hda_nid_t stac9200_adc_nids[1] = {
......@@ -364,14 +370,6 @@ static unsigned long stac92hd73xx_capvols[] = {
#define STAC92HD83_DAC_COUNT 3
static hda_nid_t stac92hd83xxx_mux_nids[2] = {
0x17, 0x18,
};
static hda_nid_t stac92hd83xxx_adc_nids[2] = {
0x15, 0x16,
};
static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
0xa, 0xb, 0xd, 0xe,
};
......@@ -384,25 +382,9 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = {
0x03, 0x0c, 0x20, 0x40,
};
#define STAC92HD83XXX_NUM_DMICS 2
static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
0x11, 0x20, 0
};
#define STAC92HD88XXX_NUM_DMICS STAC92HD83XXX_NUM_DMICS
#define stac92hd88xxx_dmic_nids stac92hd83xxx_dmic_nids
#define STAC92HD87B_NUM_DMICS 1
static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
0x11, 0
};
#define STAC92HD83XXX_NUM_CAPS 2
static unsigned long stac92hd83xxx_capvols[] = {
HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT),
static hda_nid_t stac92hd83xxx_dmic_nids[] = {
0x11, 0x20,
};
#define stac92hd83xxx_capsws stac92hd83xxx_capvols
static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
0x0a, 0x0d, 0x0f
......@@ -581,21 +563,6 @@ static hda_nid_t stac92hd73xx_pin_nids[13] = {
0x14, 0x22, 0x23
};
static hda_nid_t stac92hd83xxx_pin_nids[10] = {
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x1f, 0x20,
};
static hda_nid_t stac92hd87xxx_pin_nids[6] = {
0x0a, 0x0b, 0x0c, 0x0d,
0x0f, 0x11,
};
static hda_nid_t stac92hd88xxx_pin_nids[8] = {
0x0a, 0x0b, 0x0c, 0x0d,
0x0f, 0x11, 0x1f, 0x20,
};
#define STAC92HD71BXX_NUM_PINS 13
static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
0x0a, 0x0b, 0x0c, 0x0d, 0x00,
......@@ -757,7 +724,7 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
struct sigmatel_spec *spec = codec->spec;
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
const struct hda_input_mux *imux = spec->input_mux;
unsigned int idx, prev_idx;
unsigned int idx, prev_idx, didx;
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items)
......@@ -769,7 +736,8 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0,
AC_VERB_SET_CONNECT_SEL,
imux->items[idx].index);
if (prev_idx >= spec->num_analog_muxes) {
if (prev_idx >= spec->num_analog_muxes &&
spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) {
imux = spec->dinput_mux;
/* 0 = analog */
snd_hda_codec_write_cache(codec,
......@@ -779,9 +747,13 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
}
} else {
imux = spec->dinput_mux;
/* first dimux item is hardcoded to select analog imux,
* so lets skip it
*/
didx = idx - spec->num_analog_muxes + 1;
snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0,
AC_VERB_SET_CONNECT_SEL,
imux->items[idx - 1].index);
imux->items[didx].index);
}
spec->cur_mux[adc_idx] = idx;
return 1;
......@@ -3419,6 +3391,17 @@ static const char * const stac92xx_dmic_labels[5] = {
"Digital Mic 3", "Digital Mic 4"
};
static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux,
int idx)
{
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
int nums;
nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
if (idx >= 0 && idx < nums)
return conn[idx];
return 0;
}
static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
hda_nid_t nid)
{
......@@ -3429,6 +3412,15 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
for (i = 0; i < nums; i++)
if (conn[i] == nid)
return i;
for (i = 0; i < nums; i++) {
unsigned int wid_caps = get_wcaps(codec, conn[i]);
unsigned int wid_type = get_wcaps_type(wid_caps);
if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX)
if (get_connection_index(codec, conn[i], nid) >= 0)
return i;
}
return -1;
}
......@@ -3501,6 +3493,16 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
type_idx, HDA_OUTPUT);
if (err < 0)
return err;
if (!err) {
nid = get_connected_node(codec,
spec->dmux_nids[0], index);
if (nid)
err = create_elem_capture_vol(codec,
nid, label,
type_idx, HDA_INPUT);
if (err < 0)
return err;
}
}
}
......@@ -4054,21 +4056,10 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
}
#ifdef CONFIG_SND_HDA_INPUT_JACK
static void stac92xx_free_jack_priv(struct snd_jack *jack)
{
struct sigmatel_jack *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}
#endif
static int stac92xx_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
struct sigmatel_spec *spec = codec->spec;
struct sigmatel_jack *jack;
int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int connectivity = get_defcfg_connect(def_conf);
char name[32];
......@@ -4077,26 +4068,15 @@ static int stac92xx_add_jack(struct hda_codec *codec,
if (connectivity && connectivity != AC_JACK_PORT_FIXED)
return 0;
snd_array_init(&spec->jacks, sizeof(*jack), 32);
jack = snd_array_new(&spec->jacks);
if (!jack)
return -ENOMEM;
jack->nid = nid;
jack->type = type;
snprintf(name, sizeof(name), "%s at %s %s Jack",
snd_hda_get_jack_type(def_conf),
snd_hda_get_jack_connectivity(def_conf),
snd_hda_get_jack_location(def_conf));
err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
if (err < 0) {
jack->nid = 0;
err = snd_hda_input_jack_add(codec, nid, type, name);
if (err < 0)
return err;
}
jack->jack->private_data = jack;
jack->jack->private_free = stac92xx_free_jack_priv;
#endif
#endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0;
}
......@@ -4399,23 +4379,6 @@ static int stac92xx_init(struct hda_codec *codec)
return 0;
}
static void stac92xx_free_jacks(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
/* free jack instances manually when clearing/reconfiguring */
struct sigmatel_spec *spec = codec->spec;
if (!codec->bus->shutdown && spec->jacks.list) {
struct sigmatel_jack *jacks = spec->jacks.list;
int i;
for (i = 0; i < spec->jacks.used; i++, jacks++) {
if (jacks->jack)
snd_device_free(codec->bus->card, jacks->jack);
}
}
snd_array_free(&spec->jacks);
#endif
}
static void stac92xx_free_kctls(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
......@@ -4449,7 +4412,7 @@ static void stac92xx_free(struct hda_codec *codec)
return;
stac92xx_shutup(codec);
stac92xx_free_jacks(codec);
snd_hda_input_jack_free(codec);
snd_array_free(&spec->events);
kfree(spec);
......@@ -4667,33 +4630,6 @@ static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
}
static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
struct sigmatel_spec *spec = codec->spec;
struct sigmatel_jack *jacks = spec->jacks.list;
if (jacks) {
int i;
for (i = 0; i < spec->jacks.used; i++) {
if (jacks->nid == nid) {
unsigned int pin_ctl =
snd_hda_codec_read(codec, nid,
0, AC_VERB_GET_PIN_WIDGET_CONTROL,
0x00);
int type = jacks->type;
if (type == (SND_JACK_LINEOUT
| SND_JACK_HEADPHONE))
type = (pin_ctl & AC_PINCTL_HP_EN)
? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
snd_jack_report(jacks->jack,
get_pin_presence(codec, nid)
? type : 0);
}
jacks++;
}
}
}
/* get the pin connection (fixed, none, etc) */
static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
{
......@@ -4782,7 +4718,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
case STAC_PWR_EVENT:
if (spec->num_pwrs > 0)
stac92xx_pin_sense(codec, event->nid);
stac92xx_report_jack(codec, event->nid);
snd_hda_input_jack_report(codec, event->nid);
switch (codec->subsystem_id) {
case 0x103c308f:
......@@ -5378,6 +5314,105 @@ static int hp_bnb2011_with_dock(struct hda_codec *codec)
return 0;
}
static void stac92hd8x_add_pin(struct hda_codec *codec, hda_nid_t nid)
{
struct sigmatel_spec *spec = codec->spec;
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int i;
spec->auto_pin_nids[spec->auto_pin_cnt] = nid;
spec->auto_pin_cnt++;
if (get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) {
for (i = 0; i < ARRAY_SIZE(stac92hd83xxx_dmic_nids); i++) {
if (nid == stac92hd83xxx_dmic_nids[i]) {
spec->auto_dmic_nids[spec->auto_dmic_cnt] = nid;
spec->auto_dmic_cnt++;
}
}
}
}
static void stac92hd8x_add_adc(struct hda_codec *codec, hda_nid_t nid)
{
struct sigmatel_spec *spec = codec->spec;
spec->auto_adc_nids[spec->auto_adc_cnt] = nid;
spec->auto_adc_cnt++;
}
static void stac92hd8x_add_mux(struct hda_codec *codec, hda_nid_t nid)
{
int i, j;
struct sigmatel_spec *spec = codec->spec;
for (i = 0; i < spec->auto_adc_cnt; i++) {
if (get_connection_index(codec,
spec->auto_adc_nids[i], nid) >= 0) {
/* mux and volume for adc_nids[i] */
if (!spec->auto_mux_nids[i]) {
spec->auto_mux_nids[i] = nid;
/* 92hd codecs capture volume is in mux */
spec->auto_capvols[i] = HDA_COMPOSE_AMP_VAL(nid,
3, 0, HDA_OUTPUT);
}
for (j = 0; j < spec->auto_dmic_cnt; j++) {
if (get_connection_index(codec, nid,
spec->auto_dmic_nids[j]) >= 0) {
/* dmux for adc_nids[i] */
if (!spec->auto_dmux_nids[i])
spec->auto_dmux_nids[i] = nid;
break;
}
}
break;
}
}
}
static void stac92hd8x_fill_auto_spec(struct hda_codec *codec)
{
hda_nid_t nid, end_nid;
unsigned int wid_caps, wid_type;
struct sigmatel_spec *spec = codec->spec;
end_nid = codec->start_nid + codec->num_nodes;
for (nid = codec->start_nid; nid < end_nid; nid++) {
wid_caps = get_wcaps(codec, nid);
wid_type = get_wcaps_type(wid_caps);
if (wid_type == AC_WID_PIN)
stac92hd8x_add_pin(codec, nid);
if (wid_type == AC_WID_AUD_IN && !(wid_caps & AC_WCAP_DIGITAL))
stac92hd8x_add_adc(codec, nid);
}
for (nid = codec->start_nid; nid < end_nid; nid++) {
wid_caps = get_wcaps(codec, nid);
wid_type = get_wcaps_type(wid_caps);
if (wid_type == AC_WID_AUD_SEL)
stac92hd8x_add_mux(codec, nid);
}
spec->pin_nids = spec->auto_pin_nids;
spec->num_pins = spec->auto_pin_cnt;
spec->adc_nids = spec->auto_adc_nids;
spec->num_adcs = spec->auto_adc_cnt;
spec->capvols = spec->auto_capvols;
spec->capsws = spec->auto_capvols;
spec->num_caps = spec->auto_adc_cnt;
spec->mux_nids = spec->auto_mux_nids;
spec->num_muxes = spec->auto_adc_cnt;
spec->dmux_nids = spec->auto_dmux_nids;
spec->num_dmuxes = spec->auto_adc_cnt;
spec->dmic_nids = spec->auto_dmic_nids;
spec->num_dmics = spec->auto_dmic_cnt;
}
static int patch_stac92hd83xxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
......@@ -5399,26 +5434,17 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
codec->no_trigger_sense = 1;
codec->spec = spec;
stac92hd8x_fill_auto_spec(codec);
spec->linear_tone_beep = 0;
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
spec->digbeep_nid = 0x21;
spec->dmic_nids = stac92hd83xxx_dmic_nids;
spec->dmux_nids = stac92hd83xxx_mux_nids;
spec->mux_nids = stac92hd83xxx_mux_nids;
spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
spec->adc_nids = stac92hd83xxx_adc_nids;
spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
spec->pwr_nids = stac92hd83xxx_pwr_nids;
spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
spec->multiout.dac_nids = spec->dac_nids;
spec->init = stac92hd83xxx_core_init;
spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
spec->pin_nids = stac92hd83xxx_pin_nids;
spec->num_caps = STAC92HD83XXX_NUM_CAPS;
spec->capvols = stac92hd83xxx_capvols;
spec->capsws = stac92hd83xxx_capsws;
spec->board_config = snd_hda_check_board_config(codec,
STAC_92HD83XXX_MODELS,
......@@ -5436,28 +5462,11 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
case 0x111d76d1:
case 0x111d76d9:
case 0x111d76e5:
spec->dmic_nids = stac92hd87b_dmic_nids;
spec->num_dmics = stac92xx_connected_ports(codec,
stac92hd87b_dmic_nids,
STAC92HD87B_NUM_DMICS);
spec->num_pins = ARRAY_SIZE(stac92hd87xxx_pin_nids);
spec->pin_nids = stac92hd87xxx_pin_nids;
spec->mono_nid = 0;
spec->num_pwrs = 0;
break;
case 0x111d7666:
case 0x111d7667:
case 0x111d7668:
case 0x111d7669:
case 0x111d76e3:
spec->num_dmics = stac92xx_connected_ports(codec,
stac92hd88xxx_dmic_nids,
STAC92HD88XXX_NUM_DMICS);
spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
spec->pin_nids = stac92hd88xxx_pin_nids;
spec->mono_nid = 0;
spec->num_pwrs = 0;
break;
case 0x111d7604:
case 0x111d76d4:
case 0x111d7605:
......@@ -5466,9 +5475,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
if (spec->board_config == STAC_92HD83XXX_PWR_REF)
break;
spec->num_pwrs = 0;
spec->num_dmics = stac92xx_connected_ports(codec,
stac92hd83xxx_dmic_nids,
STAC92HD83XXX_NUM_DMICS);
break;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册