summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_conexant.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r--sound/pci/hda/patch_conexant.c142
1 files changed, 96 insertions, 46 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 7bbc5f237a5..7696d05b935 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -155,6 +155,10 @@ struct conexant_spec {
unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
unsigned int beep_amp;
+
+ /* extra EAPD pins */
+ unsigned int num_eapds;
+ hda_nid_t eapds[4];
};
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -442,6 +446,19 @@ static int conexant_init_jacks(struct hda_codec *codec)
return 0;
}
+static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state)
+{
+ if (power_state == AC_PWRST_D3)
+ msleep(100);
+ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+ power_state);
+ /* partial workaround for "azx_get_response timeout" */
+ if (power_state == AC_PWRST_D0)
+ msleep(10);
+ snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+}
+
static int conexant_init(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
@@ -510,6 +527,7 @@ static int conexant_build_controls(struct hda_codec *codec)
}
if (spec->multiout.dig_out_nid) {
err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid,
spec->multiout.dig_out_nid);
if (err < 0)
return err;
@@ -583,6 +601,7 @@ static const struct hda_codec_ops conexant_patch_ops = {
.build_pcms = conexant_build_pcms,
.init = conexant_init,
.free = conexant_free,
+ .set_power_state = conexant_set_power,
#ifdef CONFIG_SND_HDA_POWER_SAVE
.suspend = conexant_suspend,
#endif
@@ -1123,10 +1142,8 @@ static int patch_cxt5045(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
cxt5045_models,
cxt5045_cfg_tbl);
-#if 0 /* use the old method just for safety */
if (board_config < 0)
- board_config = CXT5045_AUTO;
-#endif
+ board_config = CXT5045_AUTO; /* model=auto as default */
if (board_config == CXT5045_AUTO)
return patch_conexant_auto(codec);
@@ -1564,10 +1581,8 @@ static int patch_cxt5047(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
cxt5047_models,
cxt5047_cfg_tbl);
-#if 0 /* not enabled as default, as BIOS often broken for this codec */
if (board_config < 0)
- board_config = CXT5047_AUTO;
-#endif
+ board_config = CXT5047_AUTO; /* model=auto as default */
if (board_config == CXT5047_AUTO)
return patch_conexant_auto(codec);
@@ -1993,10 +2008,8 @@ static int patch_cxt5051(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
cxt5051_models,
cxt5051_cfg_tbl);
-#if 0 /* use the old method just for safety */
if (board_config < 0)
- board_config = CXT5051_AUTO;
-#endif
+ board_config = CXT5051_AUTO; /* model=auto as default */
if (board_config == CXT5051_AUTO)
return patch_conexant_auto(codec);
@@ -3114,10 +3127,8 @@ static int patch_cxt5066(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
cxt5066_models, cxt5066_cfg_tbl);
-#if 0 /* use the old method just for safety */
if (board_config < 0)
- board_config = CXT5066_AUTO;
-#endif
+ board_config = CXT5066_AUTO; /* model=auto as default */
if (board_config == CXT5066_AUTO)
return patch_conexant_auto(codec);
@@ -3308,19 +3319,8 @@ static const struct hda_pcm_stream cx_auto_pcm_analog_capture = {
static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
-/* get the connection index of @nid in the widget @mux */
-static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
- hda_nid_t nid)
-{
- hda_nid_t conn[HDA_MAX_NUM_INPUTS];
- int i, nums;
-
- nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
- for (i = 0; i < nums; i++)
- if (conn[i] == nid)
- return i;
- return -1;
-}
+#define get_connection_index(codec, mux, nid)\
+ snd_hda_get_conn_index(codec, mux, nid, 0)
/* get an unassigned DAC from the given list.
* Return the nid if found and reduce the DAC list, or return zero if
@@ -3348,6 +3348,8 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
#define MAX_AUTO_DACS 5
+#define DAC_SLAVE_FLAG 0x8000 /* filled dac is a slave */
+
/* fill analog DAC list from the widget tree */
static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
{
@@ -3370,16 +3372,26 @@ static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
/* fill pin_dac_pair list from the pin and dac list */
static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
int num_pins, hda_nid_t *dacs, int *rest,
- struct pin_dac_pair *filled, int type)
+ struct pin_dac_pair *filled, int nums,
+ int type)
{
- int i, nums;
+ int i, start = nums;
- nums = 0;
- for (i = 0; i < num_pins; i++) {
+ for (i = 0; i < num_pins; i++, nums++) {
filled[nums].pin = pins[i];
filled[nums].type = type;
filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
- nums++;
+ if (filled[nums].dac)
+ continue;
+ if (filled[start].dac && get_connection_index(codec, pins[i], filled[start].dac) >= 0) {
+ filled[nums].dac = filled[start].dac | DAC_SLAVE_FLAG;
+ continue;
+ }
+ if (filled[0].dac && get_connection_index(codec, pins[i], filled[0].dac) >= 0) {
+ filled[nums].dac = filled[0].dac | DAC_SLAVE_FLAG;
+ continue;
+ }
+ snd_printdd("Failed to find a DAC for pin 0x%x", pins[i]);
}
return nums;
}
@@ -3395,19 +3407,19 @@ static void cx_auto_parse_output(struct hda_codec *codec)
rest = fill_cx_auto_dacs(codec, dacs);
/* parse all analog output pins */
nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
- dacs, &rest, spec->dac_info,
- AUTO_PIN_LINE_OUT);
- nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
- dacs, &rest, spec->dac_info + nums,
- AUTO_PIN_HP_OUT);
- nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
- dacs, &rest, spec->dac_info + nums,
- AUTO_PIN_SPEAKER_OUT);
+ dacs, &rest, spec->dac_info, 0,
+ AUTO_PIN_LINE_OUT);
+ nums = fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
+ dacs, &rest, spec->dac_info, nums,
+ AUTO_PIN_HP_OUT);
+ nums = fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
+ dacs, &rest, spec->dac_info, nums,
+ AUTO_PIN_SPEAKER_OUT);
spec->dac_info_filled = nums;
/* fill multiout struct */
for (i = 0; i < nums; i++) {
hda_nid_t dac = spec->dac_info[i].dac;
- if (!dac)
+ if (!dac || (dac & DAC_SLAVE_FLAG))
continue;
switch (spec->dac_info[i].type) {
case AUTO_PIN_LINE_OUT:
@@ -3862,7 +3874,7 @@ static void cx_auto_parse_input(struct hda_codec *codec)
}
if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items)
cx_auto_check_auto_mic(codec);
- if (imux->num_items > 1 && !spec->auto_mic) {
+ if (imux->num_items > 1) {
for (i = 1; i < imux->num_items; i++) {
if (spec->imux_info[i].adc != spec->imux_info[0].adc) {
spec->adc_switching = 1;
@@ -3919,6 +3931,38 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
#define cx_auto_parse_beep(codec)
#endif
+static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+ int i;
+ for (i = 0; i < nums; i++)
+ if (list[i] == nid)
+ return true;
+ return false;
+}
+
+/* parse extra-EAPD that aren't assigned to any pins */
+static void cx_auto_parse_eapd(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t nid, end_nid;
+
+ end_nid = codec->start_nid + codec->num_nodes;
+ for (nid = codec->start_nid; nid < end_nid; nid++) {
+ if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+ continue;
+ if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
+ continue;
+ if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
+ found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
+ found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs))
+ continue;
+ spec->eapds[spec->num_eapds++] = nid;
+ if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
+ break;
+ }
+}
+
static int cx_auto_parse_auto_config(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
@@ -3932,6 +3976,7 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec)
cx_auto_parse_input(codec);
cx_auto_parse_digital(codec);
cx_auto_parse_beep(codec);
+ cx_auto_parse_eapd(codec);
return 0;
}
@@ -4002,6 +4047,8 @@ static void cx_auto_init_output(struct hda_codec *codec)
nid = spec->dac_info[i].dac;
if (!nid)
nid = spec->multiout.dac_nids[0];
+ else if (nid & DAC_SLAVE_FLAG)
+ nid &= ~DAC_SLAVE_FLAG;
select_connection(codec, spec->dac_info[i].pin, nid);
}
if (spec->auto_mute) {
@@ -4019,6 +4066,8 @@ static void cx_auto_init_output(struct hda_codec *codec)
}
}
cx_auto_update_speakers(codec);
+ /* turn on/off extra EAPDs, too */
+ cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
}
static void cx_auto_init_input(struct hda_codec *codec)
@@ -4132,9 +4181,11 @@ static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac,
hda_nid_t pin, const char *name, int idx)
{
unsigned int caps;
- caps = query_amp_caps(codec, dac, HDA_OUTPUT);
- if (caps & AC_AMPCAP_NUM_STEPS)
- return cx_auto_add_pb_volume(codec, dac, name, idx);
+ if (dac && !(dac & DAC_SLAVE_FLAG)) {
+ caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+ if (caps & AC_AMPCAP_NUM_STEPS)
+ return cx_auto_add_pb_volume(codec, dac, name, idx);
+ }
caps = query_amp_caps(codec, pin, HDA_OUTPUT);
if (caps & AC_AMPCAP_NUM_STEPS)
return cx_auto_add_pb_volume(codec, pin, name, idx);
@@ -4156,8 +4207,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
for (i = 0; i < spec->dac_info_filled; i++) {
const char *label;
int idx, type;
- if (!spec->dac_info[i].dac)
- continue;
+ hda_nid_t dac = spec->dac_info[i].dac;
type = spec->dac_info[i].type;
if (type == AUTO_PIN_LINE_OUT)
type = spec->autocfg.line_out_type;
@@ -4176,7 +4226,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
idx = num_spk++;
break;
}
- err = try_add_pb_volume(codec, spec->dac_info[i].dac,
+ err = try_add_pb_volume(codec, dac,
spec->dac_info[i].pin,
label, idx);
if (err < 0)