xref: /openbmc/linux/sound/pci/hda/hda_generic.c (revision 7504b6cd)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Universal Interface for Intel High Definition Audio Codec
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Generic widget tree parser
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *  This driver is free software; you can redistribute it and/or modify
91da177e4SLinus Torvalds  *  it under the terms of the GNU General Public License as published by
101da177e4SLinus Torvalds  *  the Free Software Foundation; either version 2 of the License, or
111da177e4SLinus Torvalds  *  (at your option) any later version.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  *  This driver is distributed in the hope that it will be useful,
141da177e4SLinus Torvalds  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
151da177e4SLinus Torvalds  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161da177e4SLinus Torvalds  *  GNU General Public License for more details.
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  *  You should have received a copy of the GNU General Public License
191da177e4SLinus Torvalds  *  along with this program; if not, write to the Free Software
201da177e4SLinus Torvalds  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
211da177e4SLinus Torvalds  */
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include <linux/init.h>
241da177e4SLinus Torvalds #include <linux/slab.h>
25d81a6d71SPaul Gortmaker #include <linux/export.h>
26352f7f91STakashi Iwai #include <linux/sort.h>
2755196fffSTakashi Iwai #include <linux/delay.h>
28f873e536STakashi Iwai #include <linux/ctype.h>
29f873e536STakashi Iwai #include <linux/string.h>
3029476558STakashi Iwai #include <linux/bitops.h>
311da177e4SLinus Torvalds #include <sound/core.h>
32352f7f91STakashi Iwai #include <sound/jack.h>
331da177e4SLinus Torvalds #include "hda_codec.h"
341da177e4SLinus Torvalds #include "hda_local.h"
35352f7f91STakashi Iwai #include "hda_auto_parser.h"
36352f7f91STakashi Iwai #include "hda_jack.h"
377504b6cdSTakashi Iwai #include "hda_beep.h"
38352f7f91STakashi Iwai #include "hda_generic.h"
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds 
41352f7f91STakashi Iwai /* initialize hda_gen_spec struct */
42352f7f91STakashi Iwai int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
431da177e4SLinus Torvalds {
44352f7f91STakashi Iwai 	snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
45352f7f91STakashi Iwai 	snd_array_init(&spec->paths, sizeof(struct nid_path), 8);
460186f4f4STakashi Iwai 	snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8);
4738cf6f1aSTakashi Iwai 	mutex_init(&spec->pcm_mutex);
48352f7f91STakashi Iwai 	return 0;
49352f7f91STakashi Iwai }
50352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init);
511da177e4SLinus Torvalds 
5212c93df6STakashi Iwai struct snd_kcontrol_new *
5312c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
54352f7f91STakashi Iwai 		     const struct snd_kcontrol_new *temp)
55352f7f91STakashi Iwai {
56352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
57352f7f91STakashi Iwai 	if (!knew)
58352f7f91STakashi Iwai 		return NULL;
59352f7f91STakashi Iwai 	*knew = *temp;
60352f7f91STakashi Iwai 	if (name)
61352f7f91STakashi Iwai 		knew->name = kstrdup(name, GFP_KERNEL);
62352f7f91STakashi Iwai 	else if (knew->name)
63352f7f91STakashi Iwai 		knew->name = kstrdup(knew->name, GFP_KERNEL);
64352f7f91STakashi Iwai 	if (!knew->name)
65352f7f91STakashi Iwai 		return NULL;
66352f7f91STakashi Iwai 	return knew;
67352f7f91STakashi Iwai }
6812c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl);
69352f7f91STakashi Iwai 
70352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec)
71352f7f91STakashi Iwai {
72352f7f91STakashi Iwai 	if (spec->kctls.list) {
73352f7f91STakashi Iwai 		struct snd_kcontrol_new *kctl = spec->kctls.list;
74352f7f91STakashi Iwai 		int i;
75352f7f91STakashi Iwai 		for (i = 0; i < spec->kctls.used; i++)
76352f7f91STakashi Iwai 			kfree(kctl[i].name);
77352f7f91STakashi Iwai 	}
78352f7f91STakashi Iwai 	snd_array_free(&spec->kctls);
79352f7f91STakashi Iwai }
80352f7f91STakashi Iwai 
81352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
82352f7f91STakashi Iwai {
831da177e4SLinus Torvalds 	if (!spec)
841da177e4SLinus Torvalds 		return;
85352f7f91STakashi Iwai 	free_kctls(spec);
86352f7f91STakashi Iwai 	snd_array_free(&spec->paths);
870186f4f4STakashi Iwai 	snd_array_free(&spec->loopback_list);
881da177e4SLinus Torvalds }
89352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free);
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds /*
921c70a583STakashi Iwai  * store user hints
931c70a583STakashi Iwai  */
941c70a583STakashi Iwai static void parse_user_hints(struct hda_codec *codec)
951c70a583STakashi Iwai {
961c70a583STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
971c70a583STakashi Iwai 	int val;
981c70a583STakashi Iwai 
991c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "jack_detect");
1001c70a583STakashi Iwai 	if (val >= 0)
1011c70a583STakashi Iwai 		codec->no_jack_detect = !val;
1021c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "inv_jack_detect");
1031c70a583STakashi Iwai 	if (val >= 0)
1041c70a583STakashi Iwai 		codec->inv_jack_detect = !!val;
1051c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "trigger_sense");
1061c70a583STakashi Iwai 	if (val >= 0)
1071c70a583STakashi Iwai 		codec->no_trigger_sense = !val;
1081c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "inv_eapd");
1091c70a583STakashi Iwai 	if (val >= 0)
1101c70a583STakashi Iwai 		codec->inv_eapd = !!val;
1111c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "pcm_format_first");
1121c70a583STakashi Iwai 	if (val >= 0)
1131c70a583STakashi Iwai 		codec->pcm_format_first = !!val;
1141c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "sticky_stream");
1151c70a583STakashi Iwai 	if (val >= 0)
1161c70a583STakashi Iwai 		codec->no_sticky_stream = !val;
1171c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "spdif_status_reset");
1181c70a583STakashi Iwai 	if (val >= 0)
1191c70a583STakashi Iwai 		codec->spdif_status_reset = !!val;
1201c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "pin_amp_workaround");
1211c70a583STakashi Iwai 	if (val >= 0)
1221c70a583STakashi Iwai 		codec->pin_amp_workaround = !!val;
1231c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "single_adc_amp");
1241c70a583STakashi Iwai 	if (val >= 0)
1251c70a583STakashi Iwai 		codec->single_adc_amp = !!val;
1261c70a583STakashi Iwai 
127f72706beSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "auto_mute");
128f72706beSTakashi Iwai 	if (val >= 0)
129f72706beSTakashi Iwai 		spec->suppress_auto_mute = !val;
1301c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "auto_mic");
1311c70a583STakashi Iwai 	if (val >= 0)
1321c70a583STakashi Iwai 		spec->suppress_auto_mic = !val;
1331c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
1341c70a583STakashi Iwai 	if (val >= 0)
1351c70a583STakashi Iwai 		spec->line_in_auto_switch = !!val;
1361c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "need_dac_fix");
1371c70a583STakashi Iwai 	if (val >= 0)
1381c70a583STakashi Iwai 		spec->need_dac_fix = !!val;
1391c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "primary_hp");
1401c70a583STakashi Iwai 	if (val >= 0)
1411c70a583STakashi Iwai 		spec->no_primary_hp = !val;
1421c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
1431c70a583STakashi Iwai 	if (val >= 0)
1441c70a583STakashi Iwai 		spec->multi_cap_vol = !!val;
1451c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "inv_dmic_split");
1461c70a583STakashi Iwai 	if (val >= 0)
1471c70a583STakashi Iwai 		spec->inv_dmic_split = !!val;
1481c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "indep_hp");
1491c70a583STakashi Iwai 	if (val >= 0)
1501c70a583STakashi Iwai 		spec->indep_hp = !!val;
1511c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input");
1521c70a583STakashi Iwai 	if (val >= 0)
1531c70a583STakashi Iwai 		spec->add_stereo_mix_input = !!val;
154f811c3cfSTakashi Iwai 	/* the following two are just for compatibility */
1551c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_out_jack_modes");
1561c70a583STakashi Iwai 	if (val >= 0)
157f811c3cfSTakashi Iwai 		spec->add_jack_modes = !!val;
15829476558STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
15929476558STakashi Iwai 	if (val >= 0)
160f811c3cfSTakashi Iwai 		spec->add_jack_modes = !!val;
161f811c3cfSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_jack_modes");
162f811c3cfSTakashi Iwai 	if (val >= 0)
163f811c3cfSTakashi Iwai 		spec->add_jack_modes = !!val;
16455196fffSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "power_down_unused");
16555196fffSTakashi Iwai 	if (val >= 0)
16655196fffSTakashi Iwai 		spec->power_down_unused = !!val;
167967303daSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_hp_mic");
168967303daSTakashi Iwai 	if (val >= 0)
169967303daSTakashi Iwai 		spec->hp_mic = !!val;
170967303daSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
171967303daSTakashi Iwai 	if (val >= 0)
172967303daSTakashi Iwai 		spec->suppress_hp_mic_detect = !val;
1731c70a583STakashi Iwai 
1741c70a583STakashi Iwai 	if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
1751c70a583STakashi Iwai 		spec->mixer_nid = val;
1761c70a583STakashi Iwai }
1771c70a583STakashi Iwai 
1781c70a583STakashi Iwai /*
1792c12c30dSTakashi Iwai  * pin control value accesses
1802c12c30dSTakashi Iwai  */
1812c12c30dSTakashi Iwai 
1822c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \
1832c12c30dSTakashi Iwai 	snd_hda_codec_update_cache(codec, pin, 0, \
1842c12c30dSTakashi Iwai 				   AC_VERB_SET_PIN_WIDGET_CONTROL, val)
1852c12c30dSTakashi Iwai 
1862c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */
1872c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin)
1882c12c30dSTakashi Iwai {
1892c12c30dSTakashi Iwai 	update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin));
1902c12c30dSTakashi Iwai }
1912c12c30dSTakashi Iwai 
1922c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */
1932c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin,
1942c12c30dSTakashi Iwai 			   unsigned int val, bool do_write)
1952c12c30dSTakashi Iwai {
1962c12c30dSTakashi Iwai 	if (!pin)
1972c12c30dSTakashi Iwai 		return;
1982c12c30dSTakashi Iwai 	val = snd_hda_correct_pin_ctl(codec, pin, val);
1992c12c30dSTakashi Iwai 	snd_hda_codec_set_pin_target(codec, pin, val);
2002c12c30dSTakashi Iwai 	if (do_write)
2012c12c30dSTakashi Iwai 		update_pin_ctl(codec, pin, val);
2022c12c30dSTakashi Iwai }
2032c12c30dSTakashi Iwai 
2042c12c30dSTakashi Iwai /* set pinctl target values for all given pins */
2052c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins,
2062c12c30dSTakashi Iwai 			    hda_nid_t *pins, unsigned int val)
2072c12c30dSTakashi Iwai {
2082c12c30dSTakashi Iwai 	int i;
2092c12c30dSTakashi Iwai 	for (i = 0; i < num_pins; i++)
2102c12c30dSTakashi Iwai 		set_pin_target(codec, pins[i], val, false);
2112c12c30dSTakashi Iwai }
2122c12c30dSTakashi Iwai 
2132c12c30dSTakashi Iwai /*
214352f7f91STakashi Iwai  * parsing paths
2151da177e4SLinus Torvalds  */
2161da177e4SLinus Torvalds 
2173ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */
2183ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
2193ca529d3STakashi Iwai {
2203ca529d3STakashi Iwai 	int i;
2213ca529d3STakashi Iwai 	for (i = 0; i < nums; i++)
2223ca529d3STakashi Iwai 		if (list[i] == nid)
2233ca529d3STakashi Iwai 			return i;
2243ca529d3STakashi Iwai 	return -1;
2253ca529d3STakashi Iwai }
2263ca529d3STakashi Iwai 
2273ca529d3STakashi Iwai /* return true if the given NID is contained in the path */
2283ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid)
2293ca529d3STakashi Iwai {
2303ca529d3STakashi Iwai 	return find_idx_in_nid_list(nid, path->path, path->depth) >= 0;
2313ca529d3STakashi Iwai }
2323ca529d3STakashi Iwai 
233f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec,
234f5172a7eSTakashi Iwai 				     hda_nid_t from_nid, hda_nid_t to_nid,
2353ca529d3STakashi Iwai 				     int anchor_nid)
2361da177e4SLinus Torvalds {
237352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
238352f7f91STakashi Iwai 	int i;
2391da177e4SLinus Torvalds 
240352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
241352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
242352f7f91STakashi Iwai 		if (path->depth <= 0)
243352f7f91STakashi Iwai 			continue;
244352f7f91STakashi Iwai 		if ((!from_nid || path->path[0] == from_nid) &&
245f5172a7eSTakashi Iwai 		    (!to_nid || path->path[path->depth - 1] == to_nid)) {
2463ca529d3STakashi Iwai 			if (!anchor_nid ||
2473ca529d3STakashi Iwai 			    (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) ||
2483ca529d3STakashi Iwai 			    (anchor_nid < 0 && !is_nid_contained(path, anchor_nid)))
249352f7f91STakashi Iwai 				return path;
2501da177e4SLinus Torvalds 		}
251f5172a7eSTakashi Iwai 	}
2521da177e4SLinus Torvalds 	return NULL;
2531da177e4SLinus Torvalds }
254f5172a7eSTakashi Iwai 
255f5172a7eSTakashi Iwai /* get the path between the given NIDs;
256f5172a7eSTakashi Iwai  * passing 0 to either @pin or @dac behaves as a wildcard
257f5172a7eSTakashi Iwai  */
258f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
259f5172a7eSTakashi Iwai 				      hda_nid_t from_nid, hda_nid_t to_nid)
260f5172a7eSTakashi Iwai {
2613ca529d3STakashi Iwai 	return get_nid_path(codec, from_nid, to_nid, 0);
262f5172a7eSTakashi Iwai }
263352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path);
2641da177e4SLinus Torvalds 
265196c1766STakashi Iwai /* get the index number corresponding to the path instance;
266196c1766STakashi Iwai  * the index starts from 1, for easier checking the invalid value
267196c1766STakashi Iwai  */
268196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
269196c1766STakashi Iwai {
270196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
271196c1766STakashi Iwai 	struct nid_path *array = spec->paths.list;
272196c1766STakashi Iwai 	ssize_t idx;
273196c1766STakashi Iwai 
274196c1766STakashi Iwai 	if (!spec->paths.used)
275196c1766STakashi Iwai 		return 0;
276196c1766STakashi Iwai 	idx = path - array;
277196c1766STakashi Iwai 	if (idx < 0 || idx >= spec->paths.used)
278196c1766STakashi Iwai 		return 0;
279196c1766STakashi Iwai 	return idx + 1;
280196c1766STakashi Iwai }
2814bd01e93STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_path_idx);
282196c1766STakashi Iwai 
283196c1766STakashi Iwai /* get the path instance corresponding to the given index number */
284196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
285196c1766STakashi Iwai {
286196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
287196c1766STakashi Iwai 
288196c1766STakashi Iwai 	if (idx <= 0 || idx > spec->paths.used)
289196c1766STakashi Iwai 		return NULL;
290196c1766STakashi Iwai 	return snd_array_elem(&spec->paths, idx - 1);
291196c1766STakashi Iwai }
2924bd01e93STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_path_from_idx);
293196c1766STakashi Iwai 
294352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */
295352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
2961da177e4SLinus Torvalds {
297352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
298352f7f91STakashi Iwai 	int i;
299352f7f91STakashi Iwai 
300352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
301352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
302352f7f91STakashi Iwai 		if (path->path[0] == nid)
303352f7f91STakashi Iwai 			return true;
304352f7f91STakashi Iwai 	}
305352f7f91STakashi Iwai 	return false;
3061da177e4SLinus Torvalds }
3071da177e4SLinus Torvalds 
308352f7f91STakashi Iwai /* check whether the given two widgets can be connected */
309352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec,
310352f7f91STakashi Iwai 			      hda_nid_t from_nid, hda_nid_t to_nid)
3111da177e4SLinus Torvalds {
312352f7f91STakashi Iwai 	if (!from_nid || !to_nid)
313352f7f91STakashi Iwai 		return false;
314352f7f91STakashi Iwai 	return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
3151da177e4SLinus Torvalds }
3161da177e4SLinus Torvalds 
317352f7f91STakashi Iwai /* nid, dir and idx */
318352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK	(0xffff | (1U << 18) | (0x0f << 19))
319352f7f91STakashi Iwai 
320352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */
321352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
3221da177e4SLinus Torvalds {
323352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
324352f7f91STakashi Iwai 	int i;
325352f7f91STakashi Iwai 
326352f7f91STakashi Iwai 	val &= AMP_VAL_COMPARE_MASK;
327352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
328352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
329352f7f91STakashi Iwai 		if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val)
330352f7f91STakashi Iwai 			return true;
331352f7f91STakashi Iwai 	}
332352f7f91STakashi Iwai 	return false;
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
335352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */
336352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
3378999bf0aSTakashi Iwai 			      int dir, int idx, int type)
338cb53c626STakashi Iwai {
339352f7f91STakashi Iwai 	unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
3408999bf0aSTakashi Iwai 	return is_ctl_used(codec, val, type);
341cb53c626STakashi Iwai }
342352f7f91STakashi Iwai 
3430c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path)
3440c8c0f56STakashi Iwai {
3450c8c0f56STakashi Iwai 	char buf[40];
3460c8c0f56STakashi Iwai 	int i;
3470c8c0f56STakashi Iwai 
3480c8c0f56STakashi Iwai 
3490c8c0f56STakashi Iwai 	buf[0] = 0;
3500c8c0f56STakashi Iwai 	for (i = 0; i < path->depth; i++) {
3510c8c0f56STakashi Iwai 		char tmp[4];
3520c8c0f56STakashi Iwai 		sprintf(tmp, ":%02x", path->path[i]);
3530c8c0f56STakashi Iwai 		strlcat(buf, tmp, sizeof(buf));
3540c8c0f56STakashi Iwai 	}
3550c8c0f56STakashi Iwai 	snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf);
3560c8c0f56STakashi Iwai }
3570c8c0f56STakashi Iwai 
358352f7f91STakashi Iwai /* called recursively */
359352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec,
360352f7f91STakashi Iwai 			     hda_nid_t from_nid, hda_nid_t to_nid,
3613ca529d3STakashi Iwai 			     int anchor_nid, struct nid_path *path,
3623ca529d3STakashi Iwai 			     int depth)
363352f7f91STakashi Iwai {
364ee8e765bSTakashi Iwai 	const hda_nid_t *conn;
365352f7f91STakashi Iwai 	int i, nums;
366352f7f91STakashi Iwai 
3673ca529d3STakashi Iwai 	if (to_nid == anchor_nid)
3683ca529d3STakashi Iwai 		anchor_nid = 0; /* anchor passed */
3693ca529d3STakashi Iwai 	else if (to_nid == (hda_nid_t)(-anchor_nid))
3703ca529d3STakashi Iwai 		return false; /* hit the exclusive nid */
371352f7f91STakashi Iwai 
372ee8e765bSTakashi Iwai 	nums = snd_hda_get_conn_list(codec, to_nid, &conn);
373352f7f91STakashi Iwai 	for (i = 0; i < nums; i++) {
374352f7f91STakashi Iwai 		if (conn[i] != from_nid) {
375352f7f91STakashi Iwai 			/* special case: when from_nid is 0,
376352f7f91STakashi Iwai 			 * try to find an empty DAC
377352f7f91STakashi Iwai 			 */
378352f7f91STakashi Iwai 			if (from_nid ||
379352f7f91STakashi Iwai 			    get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
380352f7f91STakashi Iwai 			    is_dac_already_used(codec, conn[i]))
381352f7f91STakashi Iwai 				continue;
382352f7f91STakashi Iwai 		}
3833ca529d3STakashi Iwai 		/* anchor is not requested or already passed? */
3843ca529d3STakashi Iwai 		if (anchor_nid <= 0)
385352f7f91STakashi Iwai 			goto found;
386352f7f91STakashi Iwai 	}
387352f7f91STakashi Iwai 	if (depth >= MAX_NID_PATH_DEPTH)
388352f7f91STakashi Iwai 		return false;
389352f7f91STakashi Iwai 	for (i = 0; i < nums; i++) {
390352f7f91STakashi Iwai 		unsigned int type;
391352f7f91STakashi Iwai 		type = get_wcaps_type(get_wcaps(codec, conn[i]));
392352f7f91STakashi Iwai 		if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
393352f7f91STakashi Iwai 		    type == AC_WID_PIN)
394352f7f91STakashi Iwai 			continue;
395352f7f91STakashi Iwai 		if (__parse_nid_path(codec, from_nid, conn[i],
3963ca529d3STakashi Iwai 				     anchor_nid, path, depth + 1))
397352f7f91STakashi Iwai 			goto found;
398352f7f91STakashi Iwai 	}
399352f7f91STakashi Iwai 	return false;
400352f7f91STakashi Iwai 
401352f7f91STakashi Iwai  found:
402352f7f91STakashi Iwai 	path->path[path->depth] = conn[i];
403352f7f91STakashi Iwai 	path->idx[path->depth + 1] = i;
404352f7f91STakashi Iwai 	if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
405352f7f91STakashi Iwai 		path->multi[path->depth + 1] = 1;
406352f7f91STakashi Iwai 	path->depth++;
407352f7f91STakashi Iwai 	return true;
408352f7f91STakashi Iwai }
409352f7f91STakashi Iwai 
410352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid;
411352f7f91STakashi Iwai  * when @from_nid is 0, try to find an empty DAC;
4123ca529d3STakashi Iwai  * when @anchor_nid is set to a positive value, only paths through the widget
4133ca529d3STakashi Iwai  * with the given value are evaluated.
4143ca529d3STakashi Iwai  * when @anchor_nid is set to a negative value, paths through the widget
4153ca529d3STakashi Iwai  * with the negative of given value are excluded, only other paths are chosen.
4163ca529d3STakashi Iwai  * when @anchor_nid is zero, no special handling about path selection.
417352f7f91STakashi Iwai  */
418352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
4193ca529d3STakashi Iwai 			    hda_nid_t to_nid, int anchor_nid,
420352f7f91STakashi Iwai 			    struct nid_path *path)
421352f7f91STakashi Iwai {
4223ca529d3STakashi Iwai 	if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) {
423352f7f91STakashi Iwai 		path->path[path->depth] = to_nid;
424352f7f91STakashi Iwai 		path->depth++;
425352f7f91STakashi Iwai 		return true;
426352f7f91STakashi Iwai 	}
427352f7f91STakashi Iwai 	return false;
428352f7f91STakashi Iwai }
429352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path);
430352f7f91STakashi Iwai 
431352f7f91STakashi Iwai /*
432352f7f91STakashi Iwai  * parse the path between the given NIDs and add to the path list.
433352f7f91STakashi Iwai  * if no valid path is found, return NULL
434352f7f91STakashi Iwai  */
435352f7f91STakashi Iwai struct nid_path *
436352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
4373ca529d3STakashi Iwai 		     hda_nid_t to_nid, int anchor_nid)
438352f7f91STakashi Iwai {
439352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
440352f7f91STakashi Iwai 	struct nid_path *path;
441352f7f91STakashi Iwai 
442352f7f91STakashi Iwai 	if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
443352f7f91STakashi Iwai 		return NULL;
444352f7f91STakashi Iwai 
445f5172a7eSTakashi Iwai 	/* check whether the path has been already added */
4463ca529d3STakashi Iwai 	path = get_nid_path(codec, from_nid, to_nid, anchor_nid);
447f5172a7eSTakashi Iwai 	if (path)
448f5172a7eSTakashi Iwai 		return path;
449f5172a7eSTakashi Iwai 
450352f7f91STakashi Iwai 	path = snd_array_new(&spec->paths);
451352f7f91STakashi Iwai 	if (!path)
452352f7f91STakashi Iwai 		return NULL;
453352f7f91STakashi Iwai 	memset(path, 0, sizeof(*path));
4543ca529d3STakashi Iwai 	if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path))
455352f7f91STakashi Iwai 		return path;
456352f7f91STakashi Iwai 	/* push back */
457352f7f91STakashi Iwai 	spec->paths.used--;
458352f7f91STakashi Iwai 	return NULL;
459352f7f91STakashi Iwai }
460352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path);
461352f7f91STakashi Iwai 
462980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */
463980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx)
464980428ceSTakashi Iwai {
465980428ceSTakashi Iwai 	struct nid_path *path = snd_hda_get_path_from_idx(codec, idx);
466980428ceSTakashi Iwai 	if (!path)
467980428ceSTakashi Iwai 		return;
468980428ceSTakashi Iwai 	memset(path, 0, sizeof(*path));
469980428ceSTakashi Iwai }
470980428ceSTakashi Iwai 
471352f7f91STakashi Iwai /* look for an empty DAC slot */
472352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
473352f7f91STakashi Iwai 			      bool is_digital)
474352f7f91STakashi Iwai {
475352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
476352f7f91STakashi Iwai 	bool cap_digital;
477352f7f91STakashi Iwai 	int i;
478352f7f91STakashi Iwai 
479352f7f91STakashi Iwai 	for (i = 0; i < spec->num_all_dacs; i++) {
480352f7f91STakashi Iwai 		hda_nid_t nid = spec->all_dacs[i];
481352f7f91STakashi Iwai 		if (!nid || is_dac_already_used(codec, nid))
482352f7f91STakashi Iwai 			continue;
483352f7f91STakashi Iwai 		cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
484352f7f91STakashi Iwai 		if (is_digital != cap_digital)
485352f7f91STakashi Iwai 			continue;
486352f7f91STakashi Iwai 		if (is_reachable_path(codec, nid, pin))
487352f7f91STakashi Iwai 			return nid;
488352f7f91STakashi Iwai 	}
489352f7f91STakashi Iwai 	return 0;
490352f7f91STakashi Iwai }
491352f7f91STakashi Iwai 
492352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */
493352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
494352f7f91STakashi Iwai {
495352f7f91STakashi Iwai 	val &= ~(0x3U << 16);
496352f7f91STakashi Iwai 	val |= chs << 16;
497352f7f91STakashi Iwai 	return val;
498352f7f91STakashi Iwai }
499352f7f91STakashi Iwai 
500352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */
501352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
502352f7f91STakashi Iwai 			   int dir, unsigned int bits)
503352f7f91STakashi Iwai {
504352f7f91STakashi Iwai 	if (!nid)
505352f7f91STakashi Iwai 		return false;
506352f7f91STakashi Iwai 	if (get_wcaps(codec, nid) & (1 << (dir + 1)))
507352f7f91STakashi Iwai 		if (query_amp_caps(codec, nid, dir) & bits)
508352f7f91STakashi Iwai 			return true;
509352f7f91STakashi Iwai 	return false;
510352f7f91STakashi Iwai }
511352f7f91STakashi Iwai 
51299a5592dSDavid Henningsson static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
51399a5592dSDavid Henningsson 			  hda_nid_t nid2, int dir)
51499a5592dSDavid Henningsson {
51599a5592dSDavid Henningsson 	if (!(get_wcaps(codec, nid1) & (1 << (dir + 1))))
51699a5592dSDavid Henningsson 		return !(get_wcaps(codec, nid2) & (1 << (dir + 1)));
51799a5592dSDavid Henningsson 	return (query_amp_caps(codec, nid1, dir) ==
51899a5592dSDavid Henningsson 		query_amp_caps(codec, nid2, dir));
51999a5592dSDavid Henningsson }
52099a5592dSDavid Henningsson 
521352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \
522352f7f91STakashi Iwai 	check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
523352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \
524352f7f91STakashi Iwai 	check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
525352f7f91STakashi Iwai 
526352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */
527352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
528352f7f91STakashi Iwai 				       struct nid_path *path)
529352f7f91STakashi Iwai {
530352f7f91STakashi Iwai 	int i;
531352f7f91STakashi Iwai 
532352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
533352f7f91STakashi Iwai 		if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
534352f7f91STakashi Iwai 			return path->path[i];
535352f7f91STakashi Iwai 		if (i != path->depth - 1 && i != 0 &&
536352f7f91STakashi Iwai 		    nid_has_mute(codec, path->path[i], HDA_INPUT))
537352f7f91STakashi Iwai 			return path->path[i];
538352f7f91STakashi Iwai 	}
539352f7f91STakashi Iwai 	return 0;
540352f7f91STakashi Iwai }
541352f7f91STakashi Iwai 
542352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */
543352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
544352f7f91STakashi Iwai 				      struct nid_path *path)
545352f7f91STakashi Iwai {
546352f7f91STakashi Iwai 	int i;
547352f7f91STakashi Iwai 
548352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
549352f7f91STakashi Iwai 		if (nid_has_volume(codec, path->path[i], HDA_OUTPUT))
550352f7f91STakashi Iwai 			return path->path[i];
551352f7f91STakashi Iwai 	}
552352f7f91STakashi Iwai 	return 0;
553352f7f91STakashi Iwai }
554352f7f91STakashi Iwai 
555352f7f91STakashi Iwai /*
556352f7f91STakashi Iwai  * path activation / deactivation
557352f7f91STakashi Iwai  */
558352f7f91STakashi Iwai 
559352f7f91STakashi Iwai /* can have the amp-in capability? */
560352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
561352f7f91STakashi Iwai {
562352f7f91STakashi Iwai 	hda_nid_t nid = path->path[idx];
563352f7f91STakashi Iwai 	unsigned int caps = get_wcaps(codec, nid);
564352f7f91STakashi Iwai 	unsigned int type = get_wcaps_type(caps);
565352f7f91STakashi Iwai 
566352f7f91STakashi Iwai 	if (!(caps & AC_WCAP_IN_AMP))
567352f7f91STakashi Iwai 		return false;
568352f7f91STakashi Iwai 	if (type == AC_WID_PIN && idx > 0) /* only for input pins */
569352f7f91STakashi Iwai 		return false;
570352f7f91STakashi Iwai 	return true;
571352f7f91STakashi Iwai }
572352f7f91STakashi Iwai 
573352f7f91STakashi Iwai /* can have the amp-out capability? */
574352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
575352f7f91STakashi Iwai {
576352f7f91STakashi Iwai 	hda_nid_t nid = path->path[idx];
577352f7f91STakashi Iwai 	unsigned int caps = get_wcaps(codec, nid);
578352f7f91STakashi Iwai 	unsigned int type = get_wcaps_type(caps);
579352f7f91STakashi Iwai 
580352f7f91STakashi Iwai 	if (!(caps & AC_WCAP_OUT_AMP))
581352f7f91STakashi Iwai 		return false;
582352f7f91STakashi Iwai 	if (type == AC_WID_PIN && !idx) /* only for output pins */
583352f7f91STakashi Iwai 		return false;
584352f7f91STakashi Iwai 	return true;
585352f7f91STakashi Iwai }
586352f7f91STakashi Iwai 
587352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */
588352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
5897dddf2aeSTakashi Iwai 			  unsigned int dir, unsigned int idx)
590352f7f91STakashi Iwai {
591352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
592352f7f91STakashi Iwai 	int i, n;
593352f7f91STakashi Iwai 
594352f7f91STakashi Iwai 	for (n = 0; n < spec->paths.used; n++) {
595352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, n);
596352f7f91STakashi Iwai 		if (!path->active)
597352f7f91STakashi Iwai 			continue;
598352f7f91STakashi Iwai 		for (i = 0; i < path->depth; i++) {
599352f7f91STakashi Iwai 			if (path->path[i] == nid) {
600352f7f91STakashi Iwai 				if (dir == HDA_OUTPUT || path->idx[i] == idx)
601352f7f91STakashi Iwai 					return true;
602352f7f91STakashi Iwai 				break;
603352f7f91STakashi Iwai 			}
604352f7f91STakashi Iwai 		}
605352f7f91STakashi Iwai 	}
606352f7f91STakashi Iwai 	return false;
607352f7f91STakashi Iwai }
608352f7f91STakashi Iwai 
609352f7f91STakashi Iwai /* get the default amp value for the target state */
610352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
6118999bf0aSTakashi Iwai 				   int dir, unsigned int caps, bool enable)
612352f7f91STakashi Iwai {
613352f7f91STakashi Iwai 	unsigned int val = 0;
614352f7f91STakashi Iwai 
615352f7f91STakashi Iwai 	if (caps & AC_AMPCAP_NUM_STEPS) {
616352f7f91STakashi Iwai 		/* set to 0dB */
617352f7f91STakashi Iwai 		if (enable)
618352f7f91STakashi Iwai 			val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
619352f7f91STakashi Iwai 	}
620352f7f91STakashi Iwai 	if (caps & AC_AMPCAP_MUTE) {
621352f7f91STakashi Iwai 		if (!enable)
622352f7f91STakashi Iwai 			val |= HDA_AMP_MUTE;
623352f7f91STakashi Iwai 	}
624352f7f91STakashi Iwai 	return val;
625352f7f91STakashi Iwai }
626352f7f91STakashi Iwai 
627352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */
628352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
629352f7f91STakashi Iwai {
6308999bf0aSTakashi Iwai 	unsigned int caps = query_amp_caps(codec, nid, dir);
6318999bf0aSTakashi Iwai 	int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
632352f7f91STakashi Iwai 	snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
633352f7f91STakashi Iwai }
634352f7f91STakashi Iwai 
6358999bf0aSTakashi Iwai /* calculate amp value mask we can modify;
6368999bf0aSTakashi Iwai  * if the given amp is controlled by mixers, don't touch it
6378999bf0aSTakashi Iwai  */
6388999bf0aSTakashi Iwai static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
6398999bf0aSTakashi Iwai 					   hda_nid_t nid, int dir, int idx,
6408999bf0aSTakashi Iwai 					   unsigned int caps)
641352f7f91STakashi Iwai {
6428999bf0aSTakashi Iwai 	unsigned int mask = 0xff;
6438999bf0aSTakashi Iwai 
6448999bf0aSTakashi Iwai 	if (caps & AC_AMPCAP_MUTE) {
6458999bf0aSTakashi Iwai 		if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
6468999bf0aSTakashi Iwai 			mask &= ~0x80;
6478999bf0aSTakashi Iwai 	}
6488999bf0aSTakashi Iwai 	if (caps & AC_AMPCAP_NUM_STEPS) {
6498999bf0aSTakashi Iwai 		if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
6508999bf0aSTakashi Iwai 		    is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
6518999bf0aSTakashi Iwai 			mask &= ~0x7f;
6528999bf0aSTakashi Iwai 	}
6538999bf0aSTakashi Iwai 	return mask;
6548999bf0aSTakashi Iwai }
6558999bf0aSTakashi Iwai 
6568999bf0aSTakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
6578999bf0aSTakashi Iwai 			 int idx, int idx_to_check, bool enable)
6588999bf0aSTakashi Iwai {
6598999bf0aSTakashi Iwai 	unsigned int caps;
6608999bf0aSTakashi Iwai 	unsigned int mask, val;
6618999bf0aSTakashi Iwai 
6627dddf2aeSTakashi Iwai 	if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
663352f7f91STakashi Iwai 		return;
6648999bf0aSTakashi Iwai 
6658999bf0aSTakashi Iwai 	caps = query_amp_caps(codec, nid, dir);
6668999bf0aSTakashi Iwai 	val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
6678999bf0aSTakashi Iwai 	mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
6688999bf0aSTakashi Iwai 	if (!mask)
6698999bf0aSTakashi Iwai 		return;
6708999bf0aSTakashi Iwai 
6718999bf0aSTakashi Iwai 	val &= mask;
6728999bf0aSTakashi Iwai 	snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val);
673352f7f91STakashi Iwai }
674352f7f91STakashi Iwai 
675352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
676352f7f91STakashi Iwai 			     int i, bool enable)
677352f7f91STakashi Iwai {
678352f7f91STakashi Iwai 	hda_nid_t nid = path->path[i];
679352f7f91STakashi Iwai 	init_amp(codec, nid, HDA_OUTPUT, 0);
6808999bf0aSTakashi Iwai 	activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
681352f7f91STakashi Iwai }
682352f7f91STakashi Iwai 
683352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
684352f7f91STakashi Iwai 			    int i, bool enable, bool add_aamix)
685352f7f91STakashi Iwai {
686352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
687ee8e765bSTakashi Iwai 	const hda_nid_t *conn;
688352f7f91STakashi Iwai 	int n, nums, idx;
689352f7f91STakashi Iwai 	int type;
690352f7f91STakashi Iwai 	hda_nid_t nid = path->path[i];
691352f7f91STakashi Iwai 
692ee8e765bSTakashi Iwai 	nums = snd_hda_get_conn_list(codec, nid, &conn);
693352f7f91STakashi Iwai 	type = get_wcaps_type(get_wcaps(codec, nid));
694352f7f91STakashi Iwai 	if (type == AC_WID_PIN ||
695352f7f91STakashi Iwai 	    (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
696352f7f91STakashi Iwai 		nums = 1;
697352f7f91STakashi Iwai 		idx = 0;
698352f7f91STakashi Iwai 	} else
699352f7f91STakashi Iwai 		idx = path->idx[i];
700352f7f91STakashi Iwai 
701352f7f91STakashi Iwai 	for (n = 0; n < nums; n++)
702352f7f91STakashi Iwai 		init_amp(codec, nid, HDA_INPUT, n);
703352f7f91STakashi Iwai 
704352f7f91STakashi Iwai 	/* here is a little bit tricky in comparison with activate_amp_out();
705352f7f91STakashi Iwai 	 * when aa-mixer is available, we need to enable the path as well
706352f7f91STakashi Iwai 	 */
707352f7f91STakashi Iwai 	for (n = 0; n < nums; n++) {
708e4a395e7STakashi Iwai 		if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid))
709352f7f91STakashi Iwai 			continue;
7108999bf0aSTakashi Iwai 		activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
711352f7f91STakashi Iwai 	}
712352f7f91STakashi Iwai }
713352f7f91STakashi Iwai 
714352f7f91STakashi Iwai /* activate or deactivate the given path
715352f7f91STakashi Iwai  * if @add_aamix is set, enable the input from aa-mix NID as well (if any)
716352f7f91STakashi Iwai  */
717352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
718352f7f91STakashi Iwai 			   bool enable, bool add_aamix)
719352f7f91STakashi Iwai {
72055196fffSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
721352f7f91STakashi Iwai 	int i;
722352f7f91STakashi Iwai 
723352f7f91STakashi Iwai 	if (!enable)
724352f7f91STakashi Iwai 		path->active = false;
725352f7f91STakashi Iwai 
726352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
72755196fffSTakashi Iwai 		hda_nid_t nid = path->path[i];
72855196fffSTakashi Iwai 		if (enable && spec->power_down_unused) {
72955196fffSTakashi Iwai 			/* make sure the widget is powered up */
73055196fffSTakashi Iwai 			if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0))
73155196fffSTakashi Iwai 				snd_hda_codec_write(codec, nid, 0,
73255196fffSTakashi Iwai 						    AC_VERB_SET_POWER_STATE,
73355196fffSTakashi Iwai 						    AC_PWRST_D0);
73455196fffSTakashi Iwai 		}
735352f7f91STakashi Iwai 		if (enable && path->multi[i])
73655196fffSTakashi Iwai 			snd_hda_codec_write_cache(codec, nid, 0,
737352f7f91STakashi Iwai 					    AC_VERB_SET_CONNECT_SEL,
738352f7f91STakashi Iwai 					    path->idx[i]);
739352f7f91STakashi Iwai 		if (has_amp_in(codec, path, i))
740352f7f91STakashi Iwai 			activate_amp_in(codec, path, i, enable, add_aamix);
741352f7f91STakashi Iwai 		if (has_amp_out(codec, path, i))
742352f7f91STakashi Iwai 			activate_amp_out(codec, path, i, enable);
743352f7f91STakashi Iwai 	}
744352f7f91STakashi Iwai 
745352f7f91STakashi Iwai 	if (enable)
746352f7f91STakashi Iwai 		path->active = true;
747352f7f91STakashi Iwai }
748352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path);
749352f7f91STakashi Iwai 
75055196fffSTakashi Iwai /* if the given path is inactive, put widgets into D3 (only if suitable) */
75155196fffSTakashi Iwai static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
75255196fffSTakashi Iwai {
75355196fffSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
75455196fffSTakashi Iwai 	bool changed;
75555196fffSTakashi Iwai 	int i;
75655196fffSTakashi Iwai 
75755196fffSTakashi Iwai 	if (!spec->power_down_unused || path->active)
75855196fffSTakashi Iwai 		return;
75955196fffSTakashi Iwai 
76055196fffSTakashi Iwai 	for (i = 0; i < path->depth; i++) {
76155196fffSTakashi Iwai 		hda_nid_t nid = path->path[i];
76255196fffSTakashi Iwai 		if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3)) {
76355196fffSTakashi Iwai 			snd_hda_codec_write(codec, nid, 0,
76455196fffSTakashi Iwai 					    AC_VERB_SET_POWER_STATE,
76555196fffSTakashi Iwai 					    AC_PWRST_D3);
76655196fffSTakashi Iwai 			changed = true;
76755196fffSTakashi Iwai 		}
76855196fffSTakashi Iwai 	}
76955196fffSTakashi Iwai 
77055196fffSTakashi Iwai 	if (changed) {
77155196fffSTakashi Iwai 		msleep(10);
77255196fffSTakashi Iwai 		snd_hda_codec_read(codec, path->path[0], 0,
77355196fffSTakashi Iwai 				   AC_VERB_GET_POWER_STATE, 0);
77455196fffSTakashi Iwai 	}
77555196fffSTakashi Iwai }
77655196fffSTakashi Iwai 
777d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */
778d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
779d5a9f1bbSTakashi Iwai {
780d5a9f1bbSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
781d5a9f1bbSTakashi Iwai 	if (spec->own_eapd_ctl ||
782d5a9f1bbSTakashi Iwai 	    !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
783d5a9f1bbSTakashi Iwai 		return;
784ecac3ed1STakashi Iwai 	if (codec->inv_eapd)
785ecac3ed1STakashi Iwai 		enable = !enable;
786d5a9f1bbSTakashi Iwai 	snd_hda_codec_update_cache(codec, pin, 0,
787d5a9f1bbSTakashi Iwai 				   AC_VERB_SET_EAPD_BTLENABLE,
788d5a9f1bbSTakashi Iwai 				   enable ? 0x02 : 0x00);
789d5a9f1bbSTakashi Iwai }
790d5a9f1bbSTakashi Iwai 
7913e367f15STakashi Iwai /* re-initialize the path specified by the given path index */
7923e367f15STakashi Iwai static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
7933e367f15STakashi Iwai {
7943e367f15STakashi Iwai 	struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
7953e367f15STakashi Iwai 	if (path)
7963e367f15STakashi Iwai 		snd_hda_activate_path(codec, path, path->active, false);
7973e367f15STakashi Iwai }
7983e367f15STakashi Iwai 
799352f7f91STakashi Iwai 
800352f7f91STakashi Iwai /*
801352f7f91STakashi Iwai  * Helper functions for creating mixer ctl elements
802352f7f91STakashi Iwai  */
803352f7f91STakashi Iwai 
804352f7f91STakashi Iwai enum {
805352f7f91STakashi Iwai 	HDA_CTL_WIDGET_VOL,
806352f7f91STakashi Iwai 	HDA_CTL_WIDGET_MUTE,
807352f7f91STakashi Iwai 	HDA_CTL_BIND_MUTE,
808352f7f91STakashi Iwai };
809352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = {
810352f7f91STakashi Iwai 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
811352f7f91STakashi Iwai 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
812352f7f91STakashi Iwai 	HDA_BIND_MUTE(NULL, 0, 0, 0),
813352f7f91STakashi Iwai };
814352f7f91STakashi Iwai 
815352f7f91STakashi Iwai /* add dynamic controls from template */
816a35bd1e3STakashi Iwai static struct snd_kcontrol_new *
817a35bd1e3STakashi Iwai add_control(struct hda_gen_spec *spec, int type, const char *name,
818352f7f91STakashi Iwai 		       int cidx, unsigned long val)
819352f7f91STakashi Iwai {
820352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew;
821352f7f91STakashi Iwai 
82212c93df6STakashi Iwai 	knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
823352f7f91STakashi Iwai 	if (!knew)
824a35bd1e3STakashi Iwai 		return NULL;
825352f7f91STakashi Iwai 	knew->index = cidx;
826352f7f91STakashi Iwai 	if (get_amp_nid_(val))
827352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
828352f7f91STakashi Iwai 	knew->private_value = val;
829a35bd1e3STakashi Iwai 	return knew;
830352f7f91STakashi Iwai }
831352f7f91STakashi Iwai 
832352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
833352f7f91STakashi Iwai 				const char *pfx, const char *dir,
834352f7f91STakashi Iwai 				const char *sfx, int cidx, unsigned long val)
835352f7f91STakashi Iwai {
836352f7f91STakashi Iwai 	char name[32];
837352f7f91STakashi Iwai 	snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
838a35bd1e3STakashi Iwai 	if (!add_control(spec, type, name, cidx, val))
839a35bd1e3STakashi Iwai 		return -ENOMEM;
840a35bd1e3STakashi Iwai 	return 0;
841352f7f91STakashi Iwai }
842352f7f91STakashi Iwai 
843352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val)			\
844352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
845352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val)			\
846352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
847352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)			\
848352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
849352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)			\
850352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
851352f7f91STakashi Iwai 
852352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx,
853352f7f91STakashi Iwai 		       unsigned int chs, struct nid_path *path)
854352f7f91STakashi Iwai {
855352f7f91STakashi Iwai 	unsigned int val;
856352f7f91STakashi Iwai 	if (!path)
857352f7f91STakashi Iwai 		return 0;
858352f7f91STakashi Iwai 	val = path->ctls[NID_PATH_VOL_CTL];
859352f7f91STakashi Iwai 	if (!val)
860352f7f91STakashi Iwai 		return 0;
861352f7f91STakashi Iwai 	val = amp_val_replace_channels(val, chs);
862352f7f91STakashi Iwai 	return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val);
863352f7f91STakashi Iwai }
864352f7f91STakashi Iwai 
865352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */
866352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
867352f7f91STakashi Iwai 			       int type)
868352f7f91STakashi Iwai {
869352f7f91STakashi Iwai 	int chs = 1; /* mono (left only) */
870352f7f91STakashi Iwai 	if (path) {
871352f7f91STakashi Iwai 		hda_nid_t nid = get_amp_nid_(path->ctls[type]);
872352f7f91STakashi Iwai 		if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
873352f7f91STakashi Iwai 			chs = 3; /* stereo */
874352f7f91STakashi Iwai 	}
875352f7f91STakashi Iwai 	return chs;
876352f7f91STakashi Iwai }
877352f7f91STakashi Iwai 
878352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx,
879352f7f91STakashi Iwai 			  struct nid_path *path)
880352f7f91STakashi Iwai {
881352f7f91STakashi Iwai 	int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
882352f7f91STakashi Iwai 	return add_vol_ctl(codec, pfx, cidx, chs, path);
883352f7f91STakashi Iwai }
884352f7f91STakashi Iwai 
885352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget;
886352f7f91STakashi Iwai  * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
887352f7f91STakashi Iwai  */
888352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx,
889352f7f91STakashi Iwai 		      unsigned int chs, struct nid_path *path)
890352f7f91STakashi Iwai {
891352f7f91STakashi Iwai 	unsigned int val;
892352f7f91STakashi Iwai 	int type = HDA_CTL_WIDGET_MUTE;
893352f7f91STakashi Iwai 
894352f7f91STakashi Iwai 	if (!path)
895352f7f91STakashi Iwai 		return 0;
896352f7f91STakashi Iwai 	val = path->ctls[NID_PATH_MUTE_CTL];
897352f7f91STakashi Iwai 	if (!val)
898352f7f91STakashi Iwai 		return 0;
899352f7f91STakashi Iwai 	val = amp_val_replace_channels(val, chs);
900352f7f91STakashi Iwai 	if (get_amp_direction_(val) == HDA_INPUT) {
901352f7f91STakashi Iwai 		hda_nid_t nid = get_amp_nid_(val);
902352f7f91STakashi Iwai 		int nums = snd_hda_get_num_conns(codec, nid);
903352f7f91STakashi Iwai 		if (nums > 1) {
904352f7f91STakashi Iwai 			type = HDA_CTL_BIND_MUTE;
905352f7f91STakashi Iwai 			val |= nums << 19;
906352f7f91STakashi Iwai 		}
907352f7f91STakashi Iwai 	}
908352f7f91STakashi Iwai 	return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
909352f7f91STakashi Iwai }
910352f7f91STakashi Iwai 
911352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
912352f7f91STakashi Iwai 				  int cidx, struct nid_path *path)
913352f7f91STakashi Iwai {
914352f7f91STakashi Iwai 	int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
915352f7f91STakashi Iwai 	return add_sw_ctl(codec, pfx, cidx, chs, path);
916352f7f91STakashi Iwai }
917352f7f91STakashi Iwai 
918247d85eeSTakashi Iwai /* any ctl assigned to the path with the given index? */
919247d85eeSTakashi Iwai static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
920247d85eeSTakashi Iwai {
921247d85eeSTakashi Iwai 	struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
922247d85eeSTakashi Iwai 	return path && path->ctls[ctl_type];
923247d85eeSTakashi Iwai }
924247d85eeSTakashi Iwai 
925352f7f91STakashi Iwai static const char * const channel_name[4] = {
926352f7f91STakashi Iwai 	"Front", "Surround", "CLFE", "Side"
927352f7f91STakashi Iwai };
928352f7f91STakashi Iwai 
929352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */
930247d85eeSTakashi Iwai static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
931247d85eeSTakashi Iwai 				    int *index, int ctl_type)
932352f7f91STakashi Iwai {
933247d85eeSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
934352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
935352f7f91STakashi Iwai 
936352f7f91STakashi Iwai 	*index = 0;
937352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && !spec->multi_ios &&
938247d85eeSTakashi Iwai 	    !cfg->hp_outs && !cfg->speaker_outs)
939352f7f91STakashi Iwai 		return spec->vmaster_mute.hook ? "PCM" : "Master";
940352f7f91STakashi Iwai 
941352f7f91STakashi Iwai 	/* if there is really a single DAC used in the whole output paths,
942352f7f91STakashi Iwai 	 * use it master (or "PCM" if a vmaster hook is present)
943352f7f91STakashi Iwai 	 */
944352f7f91STakashi Iwai 	if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
945352f7f91STakashi Iwai 	    !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
946352f7f91STakashi Iwai 		return spec->vmaster_mute.hook ? "PCM" : "Master";
947352f7f91STakashi Iwai 
948247d85eeSTakashi Iwai 	/* multi-io channels */
949247d85eeSTakashi Iwai 	if (ch >= cfg->line_outs)
950247d85eeSTakashi Iwai 		return channel_name[ch];
951247d85eeSTakashi Iwai 
952352f7f91STakashi Iwai 	switch (cfg->line_out_type) {
953352f7f91STakashi Iwai 	case AUTO_PIN_SPEAKER_OUT:
954247d85eeSTakashi Iwai 		/* if the primary channel vol/mute is shared with HP volume,
955247d85eeSTakashi Iwai 		 * don't name it as Speaker
956247d85eeSTakashi Iwai 		 */
957247d85eeSTakashi Iwai 		if (!ch && cfg->hp_outs &&
958247d85eeSTakashi Iwai 		    !path_has_mixer(codec, spec->hp_paths[0], ctl_type))
959247d85eeSTakashi Iwai 			break;
960352f7f91STakashi Iwai 		if (cfg->line_outs == 1)
961352f7f91STakashi Iwai 			return "Speaker";
962352f7f91STakashi Iwai 		if (cfg->line_outs == 2)
963352f7f91STakashi Iwai 			return ch ? "Bass Speaker" : "Speaker";
964352f7f91STakashi Iwai 		break;
965352f7f91STakashi Iwai 	case AUTO_PIN_HP_OUT:
966247d85eeSTakashi Iwai 		/* if the primary channel vol/mute is shared with spk volume,
967247d85eeSTakashi Iwai 		 * don't name it as Headphone
968247d85eeSTakashi Iwai 		 */
969247d85eeSTakashi Iwai 		if (!ch && cfg->speaker_outs &&
970247d85eeSTakashi Iwai 		    !path_has_mixer(codec, spec->speaker_paths[0], ctl_type))
971247d85eeSTakashi Iwai 			break;
972352f7f91STakashi Iwai 		/* for multi-io case, only the primary out */
973352f7f91STakashi Iwai 		if (ch && spec->multi_ios)
974352f7f91STakashi Iwai 			break;
975352f7f91STakashi Iwai 		*index = ch;
976352f7f91STakashi Iwai 		return "Headphone";
977247d85eeSTakashi Iwai 	}
978247d85eeSTakashi Iwai 
979247d85eeSTakashi Iwai 	/* for a single channel output, we don't have to name the channel */
980352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && !spec->multi_ios)
981352f7f91STakashi Iwai 		return "PCM";
982247d85eeSTakashi Iwai 
983352f7f91STakashi Iwai 	if (ch >= ARRAY_SIZE(channel_name)) {
984352f7f91STakashi Iwai 		snd_BUG();
985352f7f91STakashi Iwai 		return "PCM";
986352f7f91STakashi Iwai 	}
987352f7f91STakashi Iwai 
988352f7f91STakashi Iwai 	return channel_name[ch];
989352f7f91STakashi Iwai }
990352f7f91STakashi Iwai 
991352f7f91STakashi Iwai /*
992352f7f91STakashi Iwai  * Parse output paths
993352f7f91STakashi Iwai  */
994352f7f91STakashi Iwai 
995352f7f91STakashi Iwai /* badness definition */
996352f7f91STakashi Iwai enum {
997352f7f91STakashi Iwai 	/* No primary DAC is found for the main output */
998352f7f91STakashi Iwai 	BAD_NO_PRIMARY_DAC = 0x10000,
999352f7f91STakashi Iwai 	/* No DAC is found for the extra output */
1000352f7f91STakashi Iwai 	BAD_NO_DAC = 0x4000,
1001352f7f91STakashi Iwai 	/* No possible multi-ios */
10021d739066STakashi Iwai 	BAD_MULTI_IO = 0x120,
1003352f7f91STakashi Iwai 	/* No individual DAC for extra output */
1004352f7f91STakashi Iwai 	BAD_NO_EXTRA_DAC = 0x102,
1005352f7f91STakashi Iwai 	/* No individual DAC for extra surrounds */
1006352f7f91STakashi Iwai 	BAD_NO_EXTRA_SURR_DAC = 0x101,
1007352f7f91STakashi Iwai 	/* Primary DAC shared with main surrounds */
1008352f7f91STakashi Iwai 	BAD_SHARED_SURROUND = 0x100,
1009352f7f91STakashi Iwai 	/* Primary DAC shared with main CLFE */
1010352f7f91STakashi Iwai 	BAD_SHARED_CLFE = 0x10,
1011352f7f91STakashi Iwai 	/* Primary DAC shared with extra surrounds */
1012352f7f91STakashi Iwai 	BAD_SHARED_EXTRA_SURROUND = 0x10,
1013352f7f91STakashi Iwai 	/* Volume widget is shared */
1014352f7f91STakashi Iwai 	BAD_SHARED_VOL = 0x10,
1015352f7f91STakashi Iwai };
1016352f7f91STakashi Iwai 
10170e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for
1018352f7f91STakashi Iwai  * volume and mute controls, and assign the values to ctls[].
1019352f7f91STakashi Iwai  *
1020352f7f91STakashi Iwai  * When no appropriate widget is found in the path, the badness value
1021352f7f91STakashi Iwai  * is incremented depending on the situation.  The function returns the
1022352f7f91STakashi Iwai  * total badness for both volume and mute controls.
1023352f7f91STakashi Iwai  */
10240e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
1025352f7f91STakashi Iwai {
1026352f7f91STakashi Iwai 	hda_nid_t nid;
1027352f7f91STakashi Iwai 	unsigned int val;
1028352f7f91STakashi Iwai 	int badness = 0;
1029352f7f91STakashi Iwai 
1030352f7f91STakashi Iwai 	if (!path)
1031352f7f91STakashi Iwai 		return BAD_SHARED_VOL * 2;
10320e614dd0STakashi Iwai 
10330e614dd0STakashi Iwai 	if (path->ctls[NID_PATH_VOL_CTL] ||
10340e614dd0STakashi Iwai 	    path->ctls[NID_PATH_MUTE_CTL])
10350e614dd0STakashi Iwai 		return 0; /* already evaluated */
10360e614dd0STakashi Iwai 
1037352f7f91STakashi Iwai 	nid = look_for_out_vol_nid(codec, path);
1038352f7f91STakashi Iwai 	if (nid) {
1039352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
1040352f7f91STakashi Iwai 		if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
1041352f7f91STakashi Iwai 			badness += BAD_SHARED_VOL;
1042352f7f91STakashi Iwai 		else
1043352f7f91STakashi Iwai 			path->ctls[NID_PATH_VOL_CTL] = val;
1044352f7f91STakashi Iwai 	} else
1045352f7f91STakashi Iwai 		badness += BAD_SHARED_VOL;
1046352f7f91STakashi Iwai 	nid = look_for_out_mute_nid(codec, path);
1047352f7f91STakashi Iwai 	if (nid) {
1048352f7f91STakashi Iwai 		unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
1049352f7f91STakashi Iwai 		if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
1050352f7f91STakashi Iwai 		    nid_has_mute(codec, nid, HDA_OUTPUT))
1051352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
1052352f7f91STakashi Iwai 		else
1053352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
1054352f7f91STakashi Iwai 		if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
1055352f7f91STakashi Iwai 			badness += BAD_SHARED_VOL;
1056352f7f91STakashi Iwai 		else
1057352f7f91STakashi Iwai 			path->ctls[NID_PATH_MUTE_CTL] = val;
1058352f7f91STakashi Iwai 	} else
1059352f7f91STakashi Iwai 		badness += BAD_SHARED_VOL;
1060352f7f91STakashi Iwai 	return badness;
1061352f7f91STakashi Iwai }
1062352f7f91STakashi Iwai 
1063352f7f91STakashi Iwai struct badness_table {
1064352f7f91STakashi Iwai 	int no_primary_dac;	/* no primary DAC */
1065352f7f91STakashi Iwai 	int no_dac;		/* no secondary DACs */
1066352f7f91STakashi Iwai 	int shared_primary;	/* primary DAC is shared with main output */
1067352f7f91STakashi Iwai 	int shared_surr;	/* secondary DAC shared with main or primary */
1068352f7f91STakashi Iwai 	int shared_clfe;	/* third DAC shared with main or primary */
1069352f7f91STakashi Iwai 	int shared_surr_main;	/* secondary DAC sahred with main/DAC0 */
1070352f7f91STakashi Iwai };
1071352f7f91STakashi Iwai 
1072352f7f91STakashi Iwai static struct badness_table main_out_badness = {
1073352f7f91STakashi Iwai 	.no_primary_dac = BAD_NO_PRIMARY_DAC,
1074352f7f91STakashi Iwai 	.no_dac = BAD_NO_DAC,
1075352f7f91STakashi Iwai 	.shared_primary = BAD_NO_PRIMARY_DAC,
1076352f7f91STakashi Iwai 	.shared_surr = BAD_SHARED_SURROUND,
1077352f7f91STakashi Iwai 	.shared_clfe = BAD_SHARED_CLFE,
1078352f7f91STakashi Iwai 	.shared_surr_main = BAD_SHARED_SURROUND,
1079352f7f91STakashi Iwai };
1080352f7f91STakashi Iwai 
1081352f7f91STakashi Iwai static struct badness_table extra_out_badness = {
1082352f7f91STakashi Iwai 	.no_primary_dac = BAD_NO_DAC,
1083352f7f91STakashi Iwai 	.no_dac = BAD_NO_DAC,
1084352f7f91STakashi Iwai 	.shared_primary = BAD_NO_EXTRA_DAC,
1085352f7f91STakashi Iwai 	.shared_surr = BAD_SHARED_EXTRA_SURROUND,
1086352f7f91STakashi Iwai 	.shared_clfe = BAD_SHARED_EXTRA_SURROUND,
1087352f7f91STakashi Iwai 	.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
1088352f7f91STakashi Iwai };
1089352f7f91STakashi Iwai 
10907385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */
10917385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
10927385df61STakashi Iwai {
10937385df61STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
10947385df61STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
10957385df61STakashi Iwai 
10967385df61STakashi Iwai 	if (cfg->line_outs > idx)
10977385df61STakashi Iwai 		return spec->private_dac_nids[idx];
10987385df61STakashi Iwai 	idx -= cfg->line_outs;
10997385df61STakashi Iwai 	if (spec->multi_ios > idx)
11007385df61STakashi Iwai 		return spec->multi_io[idx].dac;
11017385df61STakashi Iwai 	return 0;
11027385df61STakashi Iwai }
11037385df61STakashi Iwai 
11047385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */
11057385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec,
11067385df61STakashi Iwai 				hda_nid_t dac, hda_nid_t pin)
11077385df61STakashi Iwai {
11087385df61STakashi Iwai 	return is_reachable_path(codec, dac, pin) ? dac : 0;
11097385df61STakashi Iwai }
11107385df61STakashi Iwai 
1111352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */
1112352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs,
1113352f7f91STakashi Iwai 			   const hda_nid_t *pins, hda_nid_t *dacs,
1114196c1766STakashi Iwai 			   int *path_idx,
1115352f7f91STakashi Iwai 			   const struct badness_table *bad)
1116352f7f91STakashi Iwai {
1117352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1118352f7f91STakashi Iwai 	int i, j;
1119352f7f91STakashi Iwai 	int badness = 0;
1120352f7f91STakashi Iwai 	hda_nid_t dac;
1121352f7f91STakashi Iwai 
1122352f7f91STakashi Iwai 	if (!num_outs)
1123352f7f91STakashi Iwai 		return 0;
1124352f7f91STakashi Iwai 
1125352f7f91STakashi Iwai 	for (i = 0; i < num_outs; i++) {
11260c8c0f56STakashi Iwai 		struct nid_path *path;
1127352f7f91STakashi Iwai 		hda_nid_t pin = pins[i];
11281e0b5286STakashi Iwai 
11290e614dd0STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, path_idx[i]);
11300e614dd0STakashi Iwai 		if (path) {
11310e614dd0STakashi Iwai 			badness += assign_out_path_ctls(codec, path);
11321e0b5286STakashi Iwai 			continue;
11331e0b5286STakashi Iwai 		}
11341e0b5286STakashi Iwai 
1135352f7f91STakashi Iwai 		dacs[i] = look_for_dac(codec, pin, false);
1136352f7f91STakashi Iwai 		if (!dacs[i] && !i) {
1137980428ceSTakashi Iwai 			/* try to steal the DAC of surrounds for the front */
1138352f7f91STakashi Iwai 			for (j = 1; j < num_outs; j++) {
1139352f7f91STakashi Iwai 				if (is_reachable_path(codec, dacs[j], pin)) {
1140352f7f91STakashi Iwai 					dacs[0] = dacs[j];
1141352f7f91STakashi Iwai 					dacs[j] = 0;
1142980428ceSTakashi Iwai 					invalidate_nid_path(codec, path_idx[j]);
1143196c1766STakashi Iwai 					path_idx[j] = 0;
1144352f7f91STakashi Iwai 					break;
1145352f7f91STakashi Iwai 				}
1146352f7f91STakashi Iwai 			}
1147352f7f91STakashi Iwai 		}
1148352f7f91STakashi Iwai 		dac = dacs[i];
1149352f7f91STakashi Iwai 		if (!dac) {
11507385df61STakashi Iwai 			if (num_outs > 2)
11517385df61STakashi Iwai 				dac = try_dac(codec, get_primary_out(codec, i), pin);
11527385df61STakashi Iwai 			if (!dac)
11537385df61STakashi Iwai 				dac = try_dac(codec, dacs[0], pin);
11547385df61STakashi Iwai 			if (!dac)
11557385df61STakashi Iwai 				dac = try_dac(codec, get_primary_out(codec, i), pin);
1156352f7f91STakashi Iwai 			if (dac) {
1157352f7f91STakashi Iwai 				if (!i)
1158352f7f91STakashi Iwai 					badness += bad->shared_primary;
1159352f7f91STakashi Iwai 				else if (i == 1)
1160352f7f91STakashi Iwai 					badness += bad->shared_surr;
1161352f7f91STakashi Iwai 				else
1162352f7f91STakashi Iwai 					badness += bad->shared_clfe;
1163352f7f91STakashi Iwai 			} else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) {
1164352f7f91STakashi Iwai 				dac = spec->private_dac_nids[0];
1165352f7f91STakashi Iwai 				badness += bad->shared_surr_main;
1166352f7f91STakashi Iwai 			} else if (!i)
1167352f7f91STakashi Iwai 				badness += bad->no_primary_dac;
1168352f7f91STakashi Iwai 			else
1169352f7f91STakashi Iwai 				badness += bad->no_dac;
1170352f7f91STakashi Iwai 		}
11711fa335b0STakashi Iwai 		if (!dac)
11721fa335b0STakashi Iwai 			continue;
11733ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid);
1174117688a9STakashi Iwai 		if (!path && !i && spec->mixer_nid) {
1175b3a8c745STakashi Iwai 			/* try with aamix */
11763ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pin, 0);
1177b3a8c745STakashi Iwai 		}
11781fa335b0STakashi Iwai 		if (!path) {
1179352f7f91STakashi Iwai 			dac = dacs[i] = 0;
11801fa335b0STakashi Iwai 			badness += bad->no_dac;
11811fa335b0STakashi Iwai 		} else {
1182a769409cSTakashi Iwai 			/* print_nid_path("output", path); */
1183e1284af7STakashi Iwai 			path->active = true;
1184196c1766STakashi Iwai 			path_idx[i] = snd_hda_get_path_idx(codec, path);
11850e614dd0STakashi Iwai 			badness += assign_out_path_ctls(codec, path);
1186e1284af7STakashi Iwai 		}
1187352f7f91STakashi Iwai 	}
1188352f7f91STakashi Iwai 
1189352f7f91STakashi Iwai 	return badness;
1190352f7f91STakashi Iwai }
1191352f7f91STakashi Iwai 
1192352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */
1193352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
1194352f7f91STakashi Iwai {
1195352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1196352f7f91STakashi Iwai 	int i;
1197352f7f91STakashi Iwai 	hda_nid_t nid_found = 0;
1198352f7f91STakashi Iwai 
1199352f7f91STakashi Iwai 	for (i = 0; i < spec->num_all_dacs; i++) {
1200352f7f91STakashi Iwai 		hda_nid_t nid = spec->all_dacs[i];
1201352f7f91STakashi Iwai 		if (!nid || is_dac_already_used(codec, nid))
1202352f7f91STakashi Iwai 			continue;
1203352f7f91STakashi Iwai 		if (is_reachable_path(codec, nid, pin)) {
1204352f7f91STakashi Iwai 			if (nid_found)
1205352f7f91STakashi Iwai 				return 0;
1206352f7f91STakashi Iwai 			nid_found = nid;
1207352f7f91STakashi Iwai 		}
1208352f7f91STakashi Iwai 	}
1209352f7f91STakashi Iwai 	return nid_found;
1210352f7f91STakashi Iwai }
1211352f7f91STakashi Iwai 
1212352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */
1213352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec,
1214352f7f91STakashi Iwai 			       unsigned int location, hda_nid_t nid)
1215352f7f91STakashi Iwai {
1216352f7f91STakashi Iwai 	unsigned int defcfg, caps;
1217352f7f91STakashi Iwai 
1218352f7f91STakashi Iwai 	defcfg = snd_hda_codec_get_pincfg(codec, nid);
1219352f7f91STakashi Iwai 	if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
1220352f7f91STakashi Iwai 		return false;
1221352f7f91STakashi Iwai 	if (location && get_defcfg_location(defcfg) != location)
1222352f7f91STakashi Iwai 		return false;
1223352f7f91STakashi Iwai 	caps = snd_hda_query_pin_caps(codec, nid);
1224352f7f91STakashi Iwai 	if (!(caps & AC_PINCAP_OUT))
1225352f7f91STakashi Iwai 		return false;
1226352f7f91STakashi Iwai 	return true;
1227352f7f91STakashi Iwai }
1228352f7f91STakashi Iwai 
1229e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */
1230e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin)
1231e22aab7dSTakashi Iwai {
1232e22aab7dSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1233e22aab7dSTakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1234e22aab7dSTakashi Iwai 	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1235e22aab7dSTakashi Iwai 	unsigned int location = get_defcfg_location(defcfg);
1236e22aab7dSTakashi Iwai 	int type, i;
1237e22aab7dSTakashi Iwai 	int num_pins = 0;
1238e22aab7dSTakashi Iwai 
1239e22aab7dSTakashi Iwai 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1240e22aab7dSTakashi Iwai 		for (i = 0; i < cfg->num_inputs; i++) {
1241e22aab7dSTakashi Iwai 			if (cfg->inputs[i].type != type)
1242e22aab7dSTakashi Iwai 				continue;
1243e22aab7dSTakashi Iwai 			if (can_be_multiio_pin(codec, location,
1244e22aab7dSTakashi Iwai 					       cfg->inputs[i].pin))
1245e22aab7dSTakashi Iwai 				num_pins++;
1246e22aab7dSTakashi Iwai 		}
1247e22aab7dSTakashi Iwai 	}
1248e22aab7dSTakashi Iwai 	return num_pins;
1249e22aab7dSTakashi Iwai }
1250e22aab7dSTakashi Iwai 
1251352f7f91STakashi Iwai /*
1252352f7f91STakashi Iwai  * multi-io helper
1253352f7f91STakashi Iwai  *
1254352f7f91STakashi Iwai  * When hardwired is set, try to fill ony hardwired pins, and returns
1255352f7f91STakashi Iwai  * zero if any pins are filled, non-zero if nothing found.
1256352f7f91STakashi Iwai  * When hardwired is off, try to fill possible input pins, and returns
1257352f7f91STakashi Iwai  * the badness value.
1258352f7f91STakashi Iwai  */
1259352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec,
1260352f7f91STakashi Iwai 			  hda_nid_t reference_pin,
1261e22aab7dSTakashi Iwai 			  bool hardwired)
1262352f7f91STakashi Iwai {
1263352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1264352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1265e22aab7dSTakashi Iwai 	int type, i, j, num_pins, old_pins;
1266352f7f91STakashi Iwai 	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1267352f7f91STakashi Iwai 	unsigned int location = get_defcfg_location(defcfg);
1268352f7f91STakashi Iwai 	int badness = 0;
12690e614dd0STakashi Iwai 	struct nid_path *path;
1270352f7f91STakashi Iwai 
1271352f7f91STakashi Iwai 	old_pins = spec->multi_ios;
1272352f7f91STakashi Iwai 	if (old_pins >= 2)
1273352f7f91STakashi Iwai 		goto end_fill;
1274352f7f91STakashi Iwai 
1275e22aab7dSTakashi Iwai 	num_pins = count_multiio_pins(codec, reference_pin);
1276352f7f91STakashi Iwai 	if (num_pins < 2)
1277352f7f91STakashi Iwai 		goto end_fill;
1278352f7f91STakashi Iwai 
1279352f7f91STakashi Iwai 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1280352f7f91STakashi Iwai 		for (i = 0; i < cfg->num_inputs; i++) {
1281352f7f91STakashi Iwai 			hda_nid_t nid = cfg->inputs[i].pin;
1282352f7f91STakashi Iwai 			hda_nid_t dac = 0;
1283352f7f91STakashi Iwai 
1284352f7f91STakashi Iwai 			if (cfg->inputs[i].type != type)
1285352f7f91STakashi Iwai 				continue;
1286352f7f91STakashi Iwai 			if (!can_be_multiio_pin(codec, location, nid))
1287352f7f91STakashi Iwai 				continue;
1288352f7f91STakashi Iwai 			for (j = 0; j < spec->multi_ios; j++) {
1289352f7f91STakashi Iwai 				if (nid == spec->multi_io[j].pin)
1290352f7f91STakashi Iwai 					break;
1291352f7f91STakashi Iwai 			}
1292352f7f91STakashi Iwai 			if (j < spec->multi_ios)
1293352f7f91STakashi Iwai 				continue;
1294352f7f91STakashi Iwai 
1295352f7f91STakashi Iwai 			if (hardwired)
1296352f7f91STakashi Iwai 				dac = get_dac_if_single(codec, nid);
1297352f7f91STakashi Iwai 			else if (!dac)
1298352f7f91STakashi Iwai 				dac = look_for_dac(codec, nid, false);
1299352f7f91STakashi Iwai 			if (!dac) {
1300352f7f91STakashi Iwai 				badness++;
1301352f7f91STakashi Iwai 				continue;
1302352f7f91STakashi Iwai 			}
13033ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, nid,
13043ca529d3STakashi Iwai 						    -spec->mixer_nid);
13050c8c0f56STakashi Iwai 			if (!path) {
1306352f7f91STakashi Iwai 				badness++;
1307352f7f91STakashi Iwai 				continue;
1308352f7f91STakashi Iwai 			}
1309a769409cSTakashi Iwai 			/* print_nid_path("multiio", path); */
1310352f7f91STakashi Iwai 			spec->multi_io[spec->multi_ios].pin = nid;
1311352f7f91STakashi Iwai 			spec->multi_io[spec->multi_ios].dac = dac;
1312196c1766STakashi Iwai 			spec->out_paths[cfg->line_outs + spec->multi_ios] =
1313196c1766STakashi Iwai 				snd_hda_get_path_idx(codec, path);
1314352f7f91STakashi Iwai 			spec->multi_ios++;
1315352f7f91STakashi Iwai 			if (spec->multi_ios >= 2)
1316352f7f91STakashi Iwai 				break;
1317352f7f91STakashi Iwai 		}
1318352f7f91STakashi Iwai 	}
1319352f7f91STakashi Iwai  end_fill:
1320352f7f91STakashi Iwai 	if (badness)
1321352f7f91STakashi Iwai 		badness = BAD_MULTI_IO;
1322352f7f91STakashi Iwai 	if (old_pins == spec->multi_ios) {
1323352f7f91STakashi Iwai 		if (hardwired)
1324352f7f91STakashi Iwai 			return 1; /* nothing found */
1325352f7f91STakashi Iwai 		else
1326352f7f91STakashi Iwai 			return badness; /* no badness if nothing found */
1327352f7f91STakashi Iwai 	}
1328352f7f91STakashi Iwai 	if (!hardwired && spec->multi_ios < 2) {
1329352f7f91STakashi Iwai 		/* cancel newly assigned paths */
1330352f7f91STakashi Iwai 		spec->paths.used -= spec->multi_ios - old_pins;
1331352f7f91STakashi Iwai 		spec->multi_ios = old_pins;
1332352f7f91STakashi Iwai 		return badness;
1333352f7f91STakashi Iwai 	}
1334352f7f91STakashi Iwai 
1335352f7f91STakashi Iwai 	/* assign volume and mute controls */
13360e614dd0STakashi Iwai 	for (i = old_pins; i < spec->multi_ios; i++) {
13370e614dd0STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]);
13380e614dd0STakashi Iwai 		badness += assign_out_path_ctls(codec, path);
13390e614dd0STakashi Iwai 	}
1340352f7f91STakashi Iwai 
1341352f7f91STakashi Iwai 	return badness;
1342352f7f91STakashi Iwai }
1343352f7f91STakashi Iwai 
1344352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */
1345352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs,
1346196c1766STakashi Iwai 			const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx)
1347352f7f91STakashi Iwai {
1348b3a8c745STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1349352f7f91STakashi Iwai 	int i;
1350352f7f91STakashi Iwai 	bool found = false;
1351352f7f91STakashi Iwai 	for (i = 0; i < outs; i++) {
13520c8c0f56STakashi Iwai 		struct nid_path *path;
1353352f7f91STakashi Iwai 		hda_nid_t dac;
1354352f7f91STakashi Iwai 		if (dacs[i])
1355352f7f91STakashi Iwai 			continue;
1356352f7f91STakashi Iwai 		dac = get_dac_if_single(codec, pins[i]);
1357352f7f91STakashi Iwai 		if (!dac)
1358352f7f91STakashi Iwai 			continue;
13593ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dac, pins[i],
13603ca529d3STakashi Iwai 					    -spec->mixer_nid);
1361117688a9STakashi Iwai 		if (!path && !i && spec->mixer_nid)
13623ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pins[i], 0);
13630c8c0f56STakashi Iwai 		if (path) {
1364352f7f91STakashi Iwai 			dacs[i] = dac;
1365352f7f91STakashi Iwai 			found = true;
1366a769409cSTakashi Iwai 			/* print_nid_path("output", path); */
1367e1284af7STakashi Iwai 			path->active = true;
1368196c1766STakashi Iwai 			path_idx[i] = snd_hda_get_path_idx(codec, path);
1369352f7f91STakashi Iwai 		}
1370352f7f91STakashi Iwai 	}
1371352f7f91STakashi Iwai 	return found;
1372352f7f91STakashi Iwai }
1373352f7f91STakashi Iwai 
1374c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */
1375c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
1376c30aa7b2STakashi Iwai {
13773ca529d3STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1378c30aa7b2STakashi Iwai 	struct nid_path *path;
1379f87498b6STakashi Iwai 	hda_nid_t dac, pin;
1380c30aa7b2STakashi Iwai 
1381c30aa7b2STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
13823ca529d3STakashi Iwai 	if (!path || !path->depth ||
13833ca529d3STakashi Iwai 	    is_nid_contained(path, spec->mixer_nid))
1384c30aa7b2STakashi Iwai 		return 0;
1385f87498b6STakashi Iwai 	dac = path->path[0];
1386f87498b6STakashi Iwai 	pin = path->path[path->depth - 1];
1387f87498b6STakashi Iwai 	path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid);
1388f87498b6STakashi Iwai 	if (!path) {
1389f87498b6STakashi Iwai 		if (dac != spec->multiout.dac_nids[0])
1390f87498b6STakashi Iwai 			dac = spec->multiout.dac_nids[0];
1391f87498b6STakashi Iwai 		else if (spec->multiout.hp_out_nid[0])
1392f87498b6STakashi Iwai 			dac = spec->multiout.hp_out_nid[0];
1393f87498b6STakashi Iwai 		else if (spec->multiout.extra_out_nid[0])
1394f87498b6STakashi Iwai 			dac = spec->multiout.extra_out_nid[0];
1395f87498b6STakashi Iwai 		if (dac)
1396f87498b6STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pin,
13973ca529d3STakashi Iwai 						    spec->mixer_nid);
1398f87498b6STakashi Iwai 	}
1399c30aa7b2STakashi Iwai 	if (!path)
1400c30aa7b2STakashi Iwai 		return 0;
1401a769409cSTakashi Iwai 	/* print_nid_path("output-aamix", path); */
1402c30aa7b2STakashi Iwai 	path->active = false; /* unused as default */
1403c30aa7b2STakashi Iwai 	return snd_hda_get_path_idx(codec, path);
1404c30aa7b2STakashi Iwai }
1405c30aa7b2STakashi Iwai 
1406a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the
1407a07a949bSTakashi Iwai  * shared dac pointed by the paths
1408a07a949bSTakashi Iwai  */
1409a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs,
1410a07a949bSTakashi Iwai 			       hda_nid_t *dacs, int *path_idx)
1411a07a949bSTakashi Iwai {
1412a07a949bSTakashi Iwai 	struct nid_path *path;
1413a07a949bSTakashi Iwai 	int i;
1414a07a949bSTakashi Iwai 
1415a07a949bSTakashi Iwai 	for (i = 0; i < num_outs; i++) {
1416a07a949bSTakashi Iwai 		if (dacs[i])
1417a07a949bSTakashi Iwai 			continue;
1418a07a949bSTakashi Iwai 		path = snd_hda_get_path_from_idx(codec, path_idx[i]);
1419a07a949bSTakashi Iwai 		if (!path)
1420a07a949bSTakashi Iwai 			continue;
1421a07a949bSTakashi Iwai 		dacs[i] = path->path[0];
1422a07a949bSTakashi Iwai 	}
1423a07a949bSTakashi Iwai }
1424a07a949bSTakashi Iwai 
1425352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */
1426352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec,
1427352f7f91STakashi Iwai 			      bool fill_hardwired,
1428352f7f91STakashi Iwai 			      bool fill_mio_first)
1429352f7f91STakashi Iwai {
1430352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1431352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1432352f7f91STakashi Iwai 	int i, err, badness;
1433352f7f91STakashi Iwai 
1434352f7f91STakashi Iwai 	/* set num_dacs once to full for look_for_dac() */
1435352f7f91STakashi Iwai 	spec->multiout.num_dacs = cfg->line_outs;
1436352f7f91STakashi Iwai 	spec->multiout.dac_nids = spec->private_dac_nids;
1437352f7f91STakashi Iwai 	memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
1438352f7f91STakashi Iwai 	memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
1439352f7f91STakashi Iwai 	memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
1440352f7f91STakashi Iwai 	spec->multi_ios = 0;
1441352f7f91STakashi Iwai 	snd_array_free(&spec->paths);
1442cd5be3f9STakashi Iwai 
1443cd5be3f9STakashi Iwai 	/* clear path indices */
1444cd5be3f9STakashi Iwai 	memset(spec->out_paths, 0, sizeof(spec->out_paths));
1445cd5be3f9STakashi Iwai 	memset(spec->hp_paths, 0, sizeof(spec->hp_paths));
1446cd5be3f9STakashi Iwai 	memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths));
1447cd5be3f9STakashi Iwai 	memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths));
1448cd5be3f9STakashi Iwai 	memset(spec->digout_paths, 0, sizeof(spec->digout_paths));
1449c697b716STakashi Iwai 	memset(spec->input_paths, 0, sizeof(spec->input_paths));
1450cd5be3f9STakashi Iwai 	memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths));
1451cd5be3f9STakashi Iwai 	memset(&spec->digin_path, 0, sizeof(spec->digin_path));
1452cd5be3f9STakashi Iwai 
1453352f7f91STakashi Iwai 	badness = 0;
1454352f7f91STakashi Iwai 
1455352f7f91STakashi Iwai 	/* fill hard-wired DACs first */
1456352f7f91STakashi Iwai 	if (fill_hardwired) {
1457352f7f91STakashi Iwai 		bool mapped;
1458352f7f91STakashi Iwai 		do {
1459352f7f91STakashi Iwai 			mapped = map_singles(codec, cfg->line_outs,
1460352f7f91STakashi Iwai 					     cfg->line_out_pins,
1461196c1766STakashi Iwai 					     spec->private_dac_nids,
1462196c1766STakashi Iwai 					     spec->out_paths);
1463352f7f91STakashi Iwai 			mapped |= map_singles(codec, cfg->hp_outs,
1464352f7f91STakashi Iwai 					      cfg->hp_pins,
1465196c1766STakashi Iwai 					      spec->multiout.hp_out_nid,
1466196c1766STakashi Iwai 					      spec->hp_paths);
1467352f7f91STakashi Iwai 			mapped |= map_singles(codec, cfg->speaker_outs,
1468352f7f91STakashi Iwai 					      cfg->speaker_pins,
1469196c1766STakashi Iwai 					      spec->multiout.extra_out_nid,
1470196c1766STakashi Iwai 					      spec->speaker_paths);
1471352f7f91STakashi Iwai 			if (fill_mio_first && cfg->line_outs == 1 &&
1472352f7f91STakashi Iwai 			    cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1473e22aab7dSTakashi Iwai 				err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
1474352f7f91STakashi Iwai 				if (!err)
1475352f7f91STakashi Iwai 					mapped = true;
1476352f7f91STakashi Iwai 			}
1477352f7f91STakashi Iwai 		} while (mapped);
1478352f7f91STakashi Iwai 	}
1479352f7f91STakashi Iwai 
1480352f7f91STakashi Iwai 	badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
1481196c1766STakashi Iwai 				   spec->private_dac_nids, spec->out_paths,
1482352f7f91STakashi Iwai 				   &main_out_badness);
1483352f7f91STakashi Iwai 
1484352f7f91STakashi Iwai 	if (fill_mio_first &&
1485352f7f91STakashi Iwai 	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1486352f7f91STakashi Iwai 		/* try to fill multi-io first */
1487e22aab7dSTakashi Iwai 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1488352f7f91STakashi Iwai 		if (err < 0)
1489352f7f91STakashi Iwai 			return err;
1490352f7f91STakashi Iwai 		/* we don't count badness at this stage yet */
1491352f7f91STakashi Iwai 	}
1492352f7f91STakashi Iwai 
1493352f7f91STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
1494352f7f91STakashi Iwai 		err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
1495352f7f91STakashi Iwai 				      spec->multiout.hp_out_nid,
1496196c1766STakashi Iwai 				      spec->hp_paths,
1497352f7f91STakashi Iwai 				      &extra_out_badness);
1498352f7f91STakashi Iwai 		if (err < 0)
1499352f7f91STakashi Iwai 			return err;
1500352f7f91STakashi Iwai 		badness += err;
1501352f7f91STakashi Iwai 	}
1502352f7f91STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1503352f7f91STakashi Iwai 		err = try_assign_dacs(codec, cfg->speaker_outs,
1504352f7f91STakashi Iwai 				      cfg->speaker_pins,
1505352f7f91STakashi Iwai 				      spec->multiout.extra_out_nid,
1506196c1766STakashi Iwai 				      spec->speaker_paths,
1507352f7f91STakashi Iwai 				      &extra_out_badness);
1508352f7f91STakashi Iwai 		if (err < 0)
1509352f7f91STakashi Iwai 			return err;
1510352f7f91STakashi Iwai 		badness += err;
1511352f7f91STakashi Iwai 	}
1512352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1513e22aab7dSTakashi Iwai 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1514352f7f91STakashi Iwai 		if (err < 0)
1515352f7f91STakashi Iwai 			return err;
1516352f7f91STakashi Iwai 		badness += err;
1517352f7f91STakashi Iwai 	}
1518e22aab7dSTakashi Iwai 
1519c30aa7b2STakashi Iwai 	if (spec->mixer_nid) {
1520c30aa7b2STakashi Iwai 		spec->aamix_out_paths[0] =
1521c30aa7b2STakashi Iwai 			check_aamix_out_path(codec, spec->out_paths[0]);
1522c30aa7b2STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1523c30aa7b2STakashi Iwai 			spec->aamix_out_paths[1] =
1524c30aa7b2STakashi Iwai 				check_aamix_out_path(codec, spec->hp_paths[0]);
1525c30aa7b2STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1526c30aa7b2STakashi Iwai 			spec->aamix_out_paths[2] =
1527c30aa7b2STakashi Iwai 				check_aamix_out_path(codec, spec->speaker_paths[0]);
1528c30aa7b2STakashi Iwai 	}
1529c30aa7b2STakashi Iwai 
1530e22aab7dSTakashi Iwai 	if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
1531e22aab7dSTakashi Iwai 		if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
1532e22aab7dSTakashi Iwai 			spec->multi_ios = 1; /* give badness */
1533352f7f91STakashi Iwai 
1534a07a949bSTakashi Iwai 	/* re-count num_dacs and squash invalid entries */
1535a07a949bSTakashi Iwai 	spec->multiout.num_dacs = 0;
1536a07a949bSTakashi Iwai 	for (i = 0; i < cfg->line_outs; i++) {
1537a07a949bSTakashi Iwai 		if (spec->private_dac_nids[i])
1538a07a949bSTakashi Iwai 			spec->multiout.num_dacs++;
1539a07a949bSTakashi Iwai 		else {
1540a07a949bSTakashi Iwai 			memmove(spec->private_dac_nids + i,
1541a07a949bSTakashi Iwai 				spec->private_dac_nids + i + 1,
1542a07a949bSTakashi Iwai 				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
1543a07a949bSTakashi Iwai 			spec->private_dac_nids[cfg->line_outs - 1] = 0;
1544a07a949bSTakashi Iwai 		}
1545a07a949bSTakashi Iwai 	}
1546a07a949bSTakashi Iwai 
1547a07a949bSTakashi Iwai 	spec->ext_channel_count = spec->min_channel_count =
1548c0f3b216SDavid Henningsson 		spec->multiout.num_dacs * 2;
1549a07a949bSTakashi Iwai 
1550352f7f91STakashi Iwai 	if (spec->multi_ios == 2) {
1551352f7f91STakashi Iwai 		for (i = 0; i < 2; i++)
1552352f7f91STakashi Iwai 			spec->private_dac_nids[spec->multiout.num_dacs++] =
1553352f7f91STakashi Iwai 				spec->multi_io[i].dac;
1554352f7f91STakashi Iwai 	} else if (spec->multi_ios) {
1555352f7f91STakashi Iwai 		spec->multi_ios = 0;
1556352f7f91STakashi Iwai 		badness += BAD_MULTI_IO;
1557352f7f91STakashi Iwai 	}
1558352f7f91STakashi Iwai 
1559a07a949bSTakashi Iwai 	/* re-fill the shared DAC for speaker / headphone */
1560a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1561a07a949bSTakashi Iwai 		refill_shared_dacs(codec, cfg->hp_outs,
1562a07a949bSTakashi Iwai 				   spec->multiout.hp_out_nid,
1563a07a949bSTakashi Iwai 				   spec->hp_paths);
1564a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1565a07a949bSTakashi Iwai 		refill_shared_dacs(codec, cfg->speaker_outs,
1566a07a949bSTakashi Iwai 				   spec->multiout.extra_out_nid,
1567a07a949bSTakashi Iwai 				   spec->speaker_paths);
1568a07a949bSTakashi Iwai 
1569352f7f91STakashi Iwai 	return badness;
1570352f7f91STakashi Iwai }
1571352f7f91STakashi Iwai 
1572352f7f91STakashi Iwai #define DEBUG_BADNESS
1573352f7f91STakashi Iwai 
1574352f7f91STakashi Iwai #ifdef DEBUG_BADNESS
1575352f7f91STakashi Iwai #define debug_badness	snd_printdd
1576352f7f91STakashi Iwai #else
1577352f7f91STakashi Iwai #define debug_badness(...)
1578352f7f91STakashi Iwai #endif
1579352f7f91STakashi Iwai 
1580a769409cSTakashi Iwai #ifdef DEBUG_BADNESS
1581a769409cSTakashi Iwai static inline void print_nid_path_idx(struct hda_codec *codec,
1582a769409cSTakashi Iwai 				      const char *pfx, int idx)
1583352f7f91STakashi Iwai {
1584a769409cSTakashi Iwai 	struct nid_path *path;
1585a769409cSTakashi Iwai 
1586a769409cSTakashi Iwai 	path = snd_hda_get_path_from_idx(codec, idx);
1587a769409cSTakashi Iwai 	if (path)
1588a769409cSTakashi Iwai 		print_nid_path(pfx, path);
1589a769409cSTakashi Iwai }
1590a769409cSTakashi Iwai 
1591a769409cSTakashi Iwai static void debug_show_configs(struct hda_codec *codec,
1592a769409cSTakashi Iwai 			       struct auto_pin_cfg *cfg)
1593a769409cSTakashi Iwai {
1594a769409cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1595a769409cSTakashi Iwai 	static const char * const lo_type[3] = { "LO", "SP", "HP" };
1596a769409cSTakashi Iwai 	int i;
1597a769409cSTakashi Iwai 
1598a769409cSTakashi Iwai 	debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n",
1599352f7f91STakashi Iwai 		      cfg->line_out_pins[0], cfg->line_out_pins[1],
1600708122e8STakashi Iwai 		      cfg->line_out_pins[2], cfg->line_out_pins[3],
1601352f7f91STakashi Iwai 		      spec->multiout.dac_nids[0],
1602352f7f91STakashi Iwai 		      spec->multiout.dac_nids[1],
1603352f7f91STakashi Iwai 		      spec->multiout.dac_nids[2],
1604a769409cSTakashi Iwai 		      spec->multiout.dac_nids[3],
1605a769409cSTakashi Iwai 		      lo_type[cfg->line_out_type]);
1606a769409cSTakashi Iwai 	for (i = 0; i < cfg->line_outs; i++)
1607a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  out", spec->out_paths[i]);
1608352f7f91STakashi Iwai 	if (spec->multi_ios > 0)
1609352f7f91STakashi Iwai 		debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
1610352f7f91STakashi Iwai 			      spec->multi_ios,
1611352f7f91STakashi Iwai 			      spec->multi_io[0].pin, spec->multi_io[1].pin,
1612352f7f91STakashi Iwai 			      spec->multi_io[0].dac, spec->multi_io[1].dac);
1613a769409cSTakashi Iwai 	for (i = 0; i < spec->multi_ios; i++)
1614a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  mio",
1615a769409cSTakashi Iwai 				   spec->out_paths[cfg->line_outs + i]);
1616a769409cSTakashi Iwai 	if (cfg->hp_outs)
1617352f7f91STakashi Iwai 		debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1618352f7f91STakashi Iwai 		      cfg->hp_pins[0], cfg->hp_pins[1],
1619708122e8STakashi Iwai 		      cfg->hp_pins[2], cfg->hp_pins[3],
1620352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[0],
1621352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[1],
1622352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[2],
1623352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[3]);
1624a769409cSTakashi Iwai 	for (i = 0; i < cfg->hp_outs; i++)
1625a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  hp ", spec->hp_paths[i]);
1626a769409cSTakashi Iwai 	if (cfg->speaker_outs)
1627352f7f91STakashi Iwai 		debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1628352f7f91STakashi Iwai 		      cfg->speaker_pins[0], cfg->speaker_pins[1],
1629352f7f91STakashi Iwai 		      cfg->speaker_pins[2], cfg->speaker_pins[3],
1630352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[0],
1631352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[1],
1632352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[2],
1633352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[3]);
1634a769409cSTakashi Iwai 	for (i = 0; i < cfg->speaker_outs; i++)
1635a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  spk", spec->speaker_paths[i]);
1636a769409cSTakashi Iwai 	for (i = 0; i < 3; i++)
1637a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  mix", spec->aamix_out_paths[i]);
1638352f7f91STakashi Iwai }
1639a769409cSTakashi Iwai #else
1640a769409cSTakashi Iwai #define debug_show_configs(codec, cfg) /* NOP */
1641a769409cSTakashi Iwai #endif
1642352f7f91STakashi Iwai 
1643352f7f91STakashi Iwai /* find all available DACs of the codec */
1644352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec)
1645352f7f91STakashi Iwai {
1646352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1647352f7f91STakashi Iwai 	int i;
1648352f7f91STakashi Iwai 	hda_nid_t nid = codec->start_nid;
1649352f7f91STakashi Iwai 
1650352f7f91STakashi Iwai 	spec->num_all_dacs = 0;
1651352f7f91STakashi Iwai 	memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
1652352f7f91STakashi Iwai 	for (i = 0; i < codec->num_nodes; i++, nid++) {
1653352f7f91STakashi Iwai 		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
1654352f7f91STakashi Iwai 			continue;
1655352f7f91STakashi Iwai 		if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
1656352f7f91STakashi Iwai 			snd_printk(KERN_ERR "hda: Too many DACs!\n");
1657352f7f91STakashi Iwai 			break;
1658352f7f91STakashi Iwai 		}
1659352f7f91STakashi Iwai 		spec->all_dacs[spec->num_all_dacs++] = nid;
1660352f7f91STakashi Iwai 	}
1661352f7f91STakashi Iwai }
1662352f7f91STakashi Iwai 
1663352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec)
1664352f7f91STakashi Iwai {
1665352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1666352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1667352f7f91STakashi Iwai 	struct auto_pin_cfg *best_cfg;
16689314a581STakashi Iwai 	unsigned int val;
1669352f7f91STakashi Iwai 	int best_badness = INT_MAX;
1670352f7f91STakashi Iwai 	int badness;
1671352f7f91STakashi Iwai 	bool fill_hardwired = true, fill_mio_first = true;
1672352f7f91STakashi Iwai 	bool best_wired = true, best_mio = true;
1673352f7f91STakashi Iwai 	bool hp_spk_swapped = false;
1674352f7f91STakashi Iwai 
1675352f7f91STakashi Iwai 	best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
1676352f7f91STakashi Iwai 	if (!best_cfg)
1677352f7f91STakashi Iwai 		return -ENOMEM;
1678352f7f91STakashi Iwai 	*best_cfg = *cfg;
1679352f7f91STakashi Iwai 
1680352f7f91STakashi Iwai 	for (;;) {
1681352f7f91STakashi Iwai 		badness = fill_and_eval_dacs(codec, fill_hardwired,
1682352f7f91STakashi Iwai 					     fill_mio_first);
1683352f7f91STakashi Iwai 		if (badness < 0) {
1684352f7f91STakashi Iwai 			kfree(best_cfg);
1685352f7f91STakashi Iwai 			return badness;
1686352f7f91STakashi Iwai 		}
1687352f7f91STakashi Iwai 		debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
1688352f7f91STakashi Iwai 			      cfg->line_out_type, fill_hardwired, fill_mio_first,
1689352f7f91STakashi Iwai 			      badness);
1690a769409cSTakashi Iwai 		debug_show_configs(codec, cfg);
1691352f7f91STakashi Iwai 		if (badness < best_badness) {
1692352f7f91STakashi Iwai 			best_badness = badness;
1693352f7f91STakashi Iwai 			*best_cfg = *cfg;
1694352f7f91STakashi Iwai 			best_wired = fill_hardwired;
1695352f7f91STakashi Iwai 			best_mio = fill_mio_first;
1696352f7f91STakashi Iwai 		}
1697352f7f91STakashi Iwai 		if (!badness)
1698352f7f91STakashi Iwai 			break;
1699352f7f91STakashi Iwai 		fill_mio_first = !fill_mio_first;
1700352f7f91STakashi Iwai 		if (!fill_mio_first)
1701352f7f91STakashi Iwai 			continue;
1702352f7f91STakashi Iwai 		fill_hardwired = !fill_hardwired;
1703352f7f91STakashi Iwai 		if (!fill_hardwired)
1704352f7f91STakashi Iwai 			continue;
1705352f7f91STakashi Iwai 		if (hp_spk_swapped)
1706352f7f91STakashi Iwai 			break;
1707352f7f91STakashi Iwai 		hp_spk_swapped = true;
1708352f7f91STakashi Iwai 		if (cfg->speaker_outs > 0 &&
1709352f7f91STakashi Iwai 		    cfg->line_out_type == AUTO_PIN_HP_OUT) {
1710352f7f91STakashi Iwai 			cfg->hp_outs = cfg->line_outs;
1711352f7f91STakashi Iwai 			memcpy(cfg->hp_pins, cfg->line_out_pins,
1712352f7f91STakashi Iwai 			       sizeof(cfg->hp_pins));
1713352f7f91STakashi Iwai 			cfg->line_outs = cfg->speaker_outs;
1714352f7f91STakashi Iwai 			memcpy(cfg->line_out_pins, cfg->speaker_pins,
1715352f7f91STakashi Iwai 			       sizeof(cfg->speaker_pins));
1716352f7f91STakashi Iwai 			cfg->speaker_outs = 0;
1717352f7f91STakashi Iwai 			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
1718352f7f91STakashi Iwai 			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
1719352f7f91STakashi Iwai 			fill_hardwired = true;
1720352f7f91STakashi Iwai 			continue;
1721352f7f91STakashi Iwai 		}
1722352f7f91STakashi Iwai 		if (cfg->hp_outs > 0 &&
1723352f7f91STakashi Iwai 		    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
1724352f7f91STakashi Iwai 			cfg->speaker_outs = cfg->line_outs;
1725352f7f91STakashi Iwai 			memcpy(cfg->speaker_pins, cfg->line_out_pins,
1726352f7f91STakashi Iwai 			       sizeof(cfg->speaker_pins));
1727352f7f91STakashi Iwai 			cfg->line_outs = cfg->hp_outs;
1728352f7f91STakashi Iwai 			memcpy(cfg->line_out_pins, cfg->hp_pins,
1729352f7f91STakashi Iwai 			       sizeof(cfg->hp_pins));
1730352f7f91STakashi Iwai 			cfg->hp_outs = 0;
1731352f7f91STakashi Iwai 			memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
1732352f7f91STakashi Iwai 			cfg->line_out_type = AUTO_PIN_HP_OUT;
1733352f7f91STakashi Iwai 			fill_hardwired = true;
1734352f7f91STakashi Iwai 			continue;
1735352f7f91STakashi Iwai 		}
1736352f7f91STakashi Iwai 		break;
1737352f7f91STakashi Iwai 	}
1738352f7f91STakashi Iwai 
1739352f7f91STakashi Iwai 	if (badness) {
17400c8c0f56STakashi Iwai 		debug_badness("==> restoring best_cfg\n");
1741352f7f91STakashi Iwai 		*cfg = *best_cfg;
1742352f7f91STakashi Iwai 		fill_and_eval_dacs(codec, best_wired, best_mio);
1743352f7f91STakashi Iwai 	}
1744352f7f91STakashi Iwai 	debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
1745352f7f91STakashi Iwai 		      cfg->line_out_type, best_wired, best_mio);
1746a769409cSTakashi Iwai 	debug_show_configs(codec, cfg);
1747352f7f91STakashi Iwai 
1748352f7f91STakashi Iwai 	if (cfg->line_out_pins[0]) {
1749352f7f91STakashi Iwai 		struct nid_path *path;
1750196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
1751352f7f91STakashi Iwai 		if (path)
1752352f7f91STakashi Iwai 			spec->vmaster_nid = look_for_out_vol_nid(codec, path);
17537a71bbf3STakashi Iwai 		if (spec->vmaster_nid)
17547a71bbf3STakashi Iwai 			snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
17557a71bbf3STakashi Iwai 						HDA_OUTPUT, spec->vmaster_tlv);
1756352f7f91STakashi Iwai 	}
1757352f7f91STakashi Iwai 
17589314a581STakashi Iwai 	/* set initial pinctl targets */
17599314a581STakashi Iwai 	if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT)
17609314a581STakashi Iwai 		val = PIN_HP;
17619314a581STakashi Iwai 	else
17629314a581STakashi Iwai 		val = PIN_OUT;
17639314a581STakashi Iwai 	set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val);
17649314a581STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
17659314a581STakashi Iwai 		set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
17669314a581STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
17679314a581STakashi Iwai 		val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT;
17689314a581STakashi Iwai 		set_pin_targets(codec, cfg->speaker_outs,
17699314a581STakashi Iwai 				cfg->speaker_pins, val);
17709314a581STakashi Iwai 	}
17719314a581STakashi Iwai 
1772352f7f91STakashi Iwai 	kfree(best_cfg);
1773352f7f91STakashi Iwai 	return 0;
1774352f7f91STakashi Iwai }
1775352f7f91STakashi Iwai 
1776352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */
1777352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec,
1778352f7f91STakashi Iwai 				 const struct auto_pin_cfg *cfg)
1779352f7f91STakashi Iwai {
1780352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1781352f7f91STakashi Iwai 	int i, err, noutputs;
1782352f7f91STakashi Iwai 
1783352f7f91STakashi Iwai 	noutputs = cfg->line_outs;
1784352f7f91STakashi Iwai 	if (spec->multi_ios > 0 && cfg->line_outs < 3)
1785352f7f91STakashi Iwai 		noutputs += spec->multi_ios;
1786352f7f91STakashi Iwai 
1787352f7f91STakashi Iwai 	for (i = 0; i < noutputs; i++) {
1788352f7f91STakashi Iwai 		const char *name;
1789352f7f91STakashi Iwai 		int index;
1790352f7f91STakashi Iwai 		struct nid_path *path;
1791352f7f91STakashi Iwai 
1792196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
1793352f7f91STakashi Iwai 		if (!path)
1794352f7f91STakashi Iwai 			continue;
1795247d85eeSTakashi Iwai 
1796247d85eeSTakashi Iwai 		name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL);
1797352f7f91STakashi Iwai 		if (!name || !strcmp(name, "CLFE")) {
1798352f7f91STakashi Iwai 			/* Center/LFE */
1799352f7f91STakashi Iwai 			err = add_vol_ctl(codec, "Center", 0, 1, path);
1800352f7f91STakashi Iwai 			if (err < 0)
1801352f7f91STakashi Iwai 				return err;
1802352f7f91STakashi Iwai 			err = add_vol_ctl(codec, "LFE", 0, 2, path);
1803352f7f91STakashi Iwai 			if (err < 0)
1804352f7f91STakashi Iwai 				return err;
1805247d85eeSTakashi Iwai 		} else {
1806247d85eeSTakashi Iwai 			err = add_stereo_vol(codec, name, index, path);
1807247d85eeSTakashi Iwai 			if (err < 0)
1808247d85eeSTakashi Iwai 				return err;
1809247d85eeSTakashi Iwai 		}
1810247d85eeSTakashi Iwai 
1811247d85eeSTakashi Iwai 		name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL);
1812247d85eeSTakashi Iwai 		if (!name || !strcmp(name, "CLFE")) {
1813352f7f91STakashi Iwai 			err = add_sw_ctl(codec, "Center", 0, 1, path);
1814352f7f91STakashi Iwai 			if (err < 0)
1815352f7f91STakashi Iwai 				return err;
1816352f7f91STakashi Iwai 			err = add_sw_ctl(codec, "LFE", 0, 2, path);
1817352f7f91STakashi Iwai 			if (err < 0)
1818352f7f91STakashi Iwai 				return err;
1819352f7f91STakashi Iwai 		} else {
1820352f7f91STakashi Iwai 			err = add_stereo_sw(codec, name, index, path);
1821352f7f91STakashi Iwai 			if (err < 0)
1822352f7f91STakashi Iwai 				return err;
1823352f7f91STakashi Iwai 		}
1824352f7f91STakashi Iwai 	}
1825352f7f91STakashi Iwai 	return 0;
1826352f7f91STakashi Iwai }
1827352f7f91STakashi Iwai 
1828c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx,
1829196c1766STakashi Iwai 			    const char *pfx, int cidx)
1830352f7f91STakashi Iwai {
1831352f7f91STakashi Iwai 	struct nid_path *path;
1832352f7f91STakashi Iwai 	int err;
1833352f7f91STakashi Iwai 
1834196c1766STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
1835352f7f91STakashi Iwai 	if (!path)
1836352f7f91STakashi Iwai 		return 0;
1837352f7f91STakashi Iwai 	err = add_stereo_vol(codec, pfx, cidx, path);
1838352f7f91STakashi Iwai 	if (err < 0)
1839352f7f91STakashi Iwai 		return err;
1840352f7f91STakashi Iwai 	err = add_stereo_sw(codec, pfx, cidx, path);
1841352f7f91STakashi Iwai 	if (err < 0)
1842352f7f91STakashi Iwai 		return err;
1843352f7f91STakashi Iwai 	return 0;
1844352f7f91STakashi Iwai }
1845352f7f91STakashi Iwai 
1846352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */
1847352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins,
1848196c1766STakashi Iwai 			     const int *paths, const char *pfx)
1849352f7f91STakashi Iwai {
1850c2c80383STakashi Iwai 	int i;
1851352f7f91STakashi Iwai 
1852352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
1853c2c80383STakashi Iwai 		const char *name;
1854c2c80383STakashi Iwai 		char tmp[44];
1855c2c80383STakashi Iwai 		int err, idx = 0;
1856c2c80383STakashi Iwai 
1857c2c80383STakashi Iwai 		if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
1858c2c80383STakashi Iwai 			name = "Bass Speaker";
1859c2c80383STakashi Iwai 		else if (num_pins >= 3) {
1860c2c80383STakashi Iwai 			snprintf(tmp, sizeof(tmp), "%s %s",
1861352f7f91STakashi Iwai 				 pfx, channel_name[i]);
1862c2c80383STakashi Iwai 			name = tmp;
1863352f7f91STakashi Iwai 		} else {
1864c2c80383STakashi Iwai 			name = pfx;
1865c2c80383STakashi Iwai 			idx = i;
1866352f7f91STakashi Iwai 		}
1867c2c80383STakashi Iwai 		err = create_extra_out(codec, paths[i], name, idx);
1868352f7f91STakashi Iwai 		if (err < 0)
1869352f7f91STakashi Iwai 			return err;
1870352f7f91STakashi Iwai 	}
1871352f7f91STakashi Iwai 	return 0;
1872352f7f91STakashi Iwai }
1873352f7f91STakashi Iwai 
1874352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec)
1875352f7f91STakashi Iwai {
1876352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1877352f7f91STakashi Iwai 	return create_extra_outs(codec, spec->autocfg.hp_outs,
1878196c1766STakashi Iwai 				 spec->hp_paths,
1879352f7f91STakashi Iwai 				 "Headphone");
1880352f7f91STakashi Iwai }
1881352f7f91STakashi Iwai 
1882352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec)
1883352f7f91STakashi Iwai {
1884352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1885352f7f91STakashi Iwai 	return create_extra_outs(codec, spec->autocfg.speaker_outs,
1886196c1766STakashi Iwai 				 spec->speaker_paths,
1887352f7f91STakashi Iwai 				 "Speaker");
1888352f7f91STakashi Iwai }
1889352f7f91STakashi Iwai 
1890352f7f91STakashi Iwai /*
189138cf6f1aSTakashi Iwai  * independent HP controls
189238cf6f1aSTakashi Iwai  */
189338cf6f1aSTakashi Iwai 
18948ba955ceSTakashi Iwai /* update HP auto-mute state too */
18958ba955ceSTakashi Iwai static void update_hp_automute_hook(struct hda_codec *codec)
18968ba955ceSTakashi Iwai {
18978ba955ceSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
18988ba955ceSTakashi Iwai 
18998ba955ceSTakashi Iwai 	if (spec->hp_automute_hook)
19008ba955ceSTakashi Iwai 		spec->hp_automute_hook(codec, NULL);
19018ba955ceSTakashi Iwai 	else
19028ba955ceSTakashi Iwai 		snd_hda_gen_hp_automute(codec, NULL);
19038ba955ceSTakashi Iwai }
19048ba955ceSTakashi Iwai 
190538cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol,
190638cf6f1aSTakashi Iwai 			 struct snd_ctl_elem_info *uinfo)
190738cf6f1aSTakashi Iwai {
190838cf6f1aSTakashi Iwai 	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
190938cf6f1aSTakashi Iwai }
191038cf6f1aSTakashi Iwai 
191138cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol,
191238cf6f1aSTakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
191338cf6f1aSTakashi Iwai {
191438cf6f1aSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
191538cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
191638cf6f1aSTakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled;
191738cf6f1aSTakashi Iwai 	return 0;
191838cf6f1aSTakashi Iwai }
191938cf6f1aSTakashi Iwai 
1920a1e908edSTakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
1921a1e908edSTakashi Iwai 			       int nomix_path_idx, int mix_path_idx,
1922a1e908edSTakashi Iwai 			       int out_type);
1923a1e908edSTakashi Iwai 
192438cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol,
192538cf6f1aSTakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
192638cf6f1aSTakashi Iwai {
192738cf6f1aSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
192838cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
192938cf6f1aSTakashi Iwai 	unsigned int select = ucontrol->value.enumerated.item[0];
193038cf6f1aSTakashi Iwai 	int ret = 0;
193138cf6f1aSTakashi Iwai 
193238cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
193338cf6f1aSTakashi Iwai 	if (spec->active_streams) {
193438cf6f1aSTakashi Iwai 		ret = -EBUSY;
193538cf6f1aSTakashi Iwai 		goto unlock;
193638cf6f1aSTakashi Iwai 	}
193738cf6f1aSTakashi Iwai 
193838cf6f1aSTakashi Iwai 	if (spec->indep_hp_enabled != select) {
1939a1e908edSTakashi Iwai 		hda_nid_t *dacp;
1940a1e908edSTakashi Iwai 		if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
1941a1e908edSTakashi Iwai 			dacp = &spec->private_dac_nids[0];
1942a1e908edSTakashi Iwai 		else
1943a1e908edSTakashi Iwai 			dacp = &spec->multiout.hp_out_nid[0];
1944a1e908edSTakashi Iwai 
1945a1e908edSTakashi Iwai 		/* update HP aamix paths in case it conflicts with indep HP */
1946a1e908edSTakashi Iwai 		if (spec->have_aamix_ctl) {
1947a1e908edSTakashi Iwai 			if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
1948a1e908edSTakashi Iwai 				update_aamix_paths(codec, spec->aamix_mode,
1949a1e908edSTakashi Iwai 						   spec->out_paths[0],
1950a1e908edSTakashi Iwai 						   spec->aamix_out_paths[0],
1951a1e908edSTakashi Iwai 						   spec->autocfg.line_out_type);
1952a1e908edSTakashi Iwai 			else
1953a1e908edSTakashi Iwai 				update_aamix_paths(codec, spec->aamix_mode,
1954a1e908edSTakashi Iwai 						   spec->hp_paths[0],
1955a1e908edSTakashi Iwai 						   spec->aamix_out_paths[1],
1956a1e908edSTakashi Iwai 						   AUTO_PIN_HP_OUT);
1957a1e908edSTakashi Iwai 		}
1958a1e908edSTakashi Iwai 
195938cf6f1aSTakashi Iwai 		spec->indep_hp_enabled = select;
196038cf6f1aSTakashi Iwai 		if (spec->indep_hp_enabled)
1961a1e908edSTakashi Iwai 			*dacp = 0;
196238cf6f1aSTakashi Iwai 		else
1963a1e908edSTakashi Iwai 			*dacp = spec->alt_dac_nid;
196492603c59STakashi Iwai 
19658ba955ceSTakashi Iwai 		update_hp_automute_hook(codec);
196638cf6f1aSTakashi Iwai 		ret = 1;
196738cf6f1aSTakashi Iwai 	}
196838cf6f1aSTakashi Iwai  unlock:
196938cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
197038cf6f1aSTakashi Iwai 	return ret;
197138cf6f1aSTakashi Iwai }
197238cf6f1aSTakashi Iwai 
197338cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = {
197438cf6f1aSTakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
197538cf6f1aSTakashi Iwai 	.name = "Independent HP",
197638cf6f1aSTakashi Iwai 	.info = indep_hp_info,
197738cf6f1aSTakashi Iwai 	.get = indep_hp_get,
197838cf6f1aSTakashi Iwai 	.put = indep_hp_put,
197938cf6f1aSTakashi Iwai };
198038cf6f1aSTakashi Iwai 
198138cf6f1aSTakashi Iwai 
198238cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec)
198338cf6f1aSTakashi Iwai {
198438cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1985a1e908edSTakashi Iwai 	hda_nid_t dac;
198638cf6f1aSTakashi Iwai 
198738cf6f1aSTakashi Iwai 	if (!spec->indep_hp)
198838cf6f1aSTakashi Iwai 		return 0;
1989a1e908edSTakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
1990a1e908edSTakashi Iwai 		dac = spec->multiout.dac_nids[0];
1991a1e908edSTakashi Iwai 	else
1992a1e908edSTakashi Iwai 		dac = spec->multiout.hp_out_nid[0];
1993a1e908edSTakashi Iwai 	if (!dac) {
199438cf6f1aSTakashi Iwai 		spec->indep_hp = 0;
199538cf6f1aSTakashi Iwai 		return 0;
199638cf6f1aSTakashi Iwai 	}
199738cf6f1aSTakashi Iwai 
199838cf6f1aSTakashi Iwai 	spec->indep_hp_enabled = false;
1999a1e908edSTakashi Iwai 	spec->alt_dac_nid = dac;
200038cf6f1aSTakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl))
200138cf6f1aSTakashi Iwai 		return -ENOMEM;
200238cf6f1aSTakashi Iwai 	return 0;
200338cf6f1aSTakashi Iwai }
200438cf6f1aSTakashi Iwai 
200538cf6f1aSTakashi Iwai /*
2006352f7f91STakashi Iwai  * channel mode enum control
2007352f7f91STakashi Iwai  */
2008352f7f91STakashi Iwai 
2009352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol,
2010352f7f91STakashi Iwai 			struct snd_ctl_elem_info *uinfo)
2011352f7f91STakashi Iwai {
2012352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2013352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2014a07a949bSTakashi Iwai 	int chs;
2015352f7f91STakashi Iwai 
2016352f7f91STakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2017352f7f91STakashi Iwai 	uinfo->count = 1;
2018352f7f91STakashi Iwai 	uinfo->value.enumerated.items = spec->multi_ios + 1;
2019352f7f91STakashi Iwai 	if (uinfo->value.enumerated.item > spec->multi_ios)
2020352f7f91STakashi Iwai 		uinfo->value.enumerated.item = spec->multi_ios;
2021a07a949bSTakashi Iwai 	chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count;
2022a07a949bSTakashi Iwai 	sprintf(uinfo->value.enumerated.name, "%dch", chs);
2023352f7f91STakashi Iwai 	return 0;
2024352f7f91STakashi Iwai }
2025352f7f91STakashi Iwai 
2026352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol,
2027352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
2028352f7f91STakashi Iwai {
2029352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2030352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2031a07a949bSTakashi Iwai 	ucontrol->value.enumerated.item[0] =
2032a07a949bSTakashi Iwai 		(spec->ext_channel_count - spec->min_channel_count) / 2;
2033352f7f91STakashi Iwai 	return 0;
2034352f7f91STakashi Iwai }
2035352f7f91STakashi Iwai 
2036196c1766STakashi Iwai static inline struct nid_path *
2037196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx)
2038196c1766STakashi Iwai {
2039196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2040196c1766STakashi Iwai 	return snd_hda_get_path_from_idx(codec,
2041196c1766STakashi Iwai 		spec->out_paths[spec->autocfg.line_outs + idx]);
2042196c1766STakashi Iwai }
2043196c1766STakashi Iwai 
2044a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec);
2045a5cc2509STakashi Iwai 
2046352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output)
2047352f7f91STakashi Iwai {
2048352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2049352f7f91STakashi Iwai 	hda_nid_t nid = spec->multi_io[idx].pin;
2050352f7f91STakashi Iwai 	struct nid_path *path;
2051352f7f91STakashi Iwai 
2052196c1766STakashi Iwai 	path = get_multiio_path(codec, idx);
2053352f7f91STakashi Iwai 	if (!path)
2054352f7f91STakashi Iwai 		return -EINVAL;
2055352f7f91STakashi Iwai 
2056352f7f91STakashi Iwai 	if (path->active == output)
2057352f7f91STakashi Iwai 		return 0;
2058352f7f91STakashi Iwai 
2059352f7f91STakashi Iwai 	if (output) {
20602c12c30dSTakashi Iwai 		set_pin_target(codec, nid, PIN_OUT, true);
2061352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, true, true);
2062d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, true);
2063352f7f91STakashi Iwai 	} else {
2064d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, false);
2065352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, false, true);
20662c12c30dSTakashi Iwai 		set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
206755196fffSTakashi Iwai 		path_power_down_sync(codec, path);
2068352f7f91STakashi Iwai 	}
2069a365fed9STakashi Iwai 
2070a365fed9STakashi Iwai 	/* update jack retasking in case it modifies any of them */
2071a5cc2509STakashi Iwai 	update_automute_all(codec);
2072a365fed9STakashi Iwai 
2073352f7f91STakashi Iwai 	return 0;
2074352f7f91STakashi Iwai }
2075352f7f91STakashi Iwai 
2076352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol,
2077352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
2078352f7f91STakashi Iwai {
2079352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2080352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2081352f7f91STakashi Iwai 	int i, ch;
2082352f7f91STakashi Iwai 
2083352f7f91STakashi Iwai 	ch = ucontrol->value.enumerated.item[0];
2084352f7f91STakashi Iwai 	if (ch < 0 || ch > spec->multi_ios)
2085352f7f91STakashi Iwai 		return -EINVAL;
2086a07a949bSTakashi Iwai 	if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2)
2087352f7f91STakashi Iwai 		return 0;
2088a07a949bSTakashi Iwai 	spec->ext_channel_count = ch * 2 + spec->min_channel_count;
2089352f7f91STakashi Iwai 	for (i = 0; i < spec->multi_ios; i++)
2090352f7f91STakashi Iwai 		set_multi_io(codec, i, i < ch);
2091352f7f91STakashi Iwai 	spec->multiout.max_channels = max(spec->ext_channel_count,
2092352f7f91STakashi Iwai 					  spec->const_channel_count);
2093352f7f91STakashi Iwai 	if (spec->need_dac_fix)
2094352f7f91STakashi Iwai 		spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2095352f7f91STakashi Iwai 	return 1;
2096352f7f91STakashi Iwai }
2097352f7f91STakashi Iwai 
2098352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = {
2099352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2100352f7f91STakashi Iwai 	.name = "Channel Mode",
2101352f7f91STakashi Iwai 	.info = ch_mode_info,
2102352f7f91STakashi Iwai 	.get = ch_mode_get,
2103352f7f91STakashi Iwai 	.put = ch_mode_put,
2104352f7f91STakashi Iwai };
2105352f7f91STakashi Iwai 
2106352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec)
2107352f7f91STakashi Iwai {
2108352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2109352f7f91STakashi Iwai 
2110352f7f91STakashi Iwai 	if (spec->multi_ios > 0) {
211112c93df6STakashi Iwai 		if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum))
2112352f7f91STakashi Iwai 			return -ENOMEM;
2113352f7f91STakashi Iwai 	}
2114352f7f91STakashi Iwai 	return 0;
2115352f7f91STakashi Iwai }
2116352f7f91STakashi Iwai 
2117352f7f91STakashi Iwai /*
2118c30aa7b2STakashi Iwai  * aamix loopback enable/disable switch
2119c30aa7b2STakashi Iwai  */
2120c30aa7b2STakashi Iwai 
2121c30aa7b2STakashi Iwai #define loopback_mixing_info	indep_hp_info
2122c30aa7b2STakashi Iwai 
2123c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
2124c30aa7b2STakashi Iwai 			       struct snd_ctl_elem_value *ucontrol)
2125c30aa7b2STakashi Iwai {
2126c30aa7b2STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2127c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2128c30aa7b2STakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->aamix_mode;
2129c30aa7b2STakashi Iwai 	return 0;
2130c30aa7b2STakashi Iwai }
2131c30aa7b2STakashi Iwai 
2132c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
2133a1e908edSTakashi Iwai 			       int nomix_path_idx, int mix_path_idx,
2134a1e908edSTakashi Iwai 			       int out_type)
2135c30aa7b2STakashi Iwai {
2136a1e908edSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2137c30aa7b2STakashi Iwai 	struct nid_path *nomix_path, *mix_path;
2138c30aa7b2STakashi Iwai 
2139c30aa7b2STakashi Iwai 	nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
2140c30aa7b2STakashi Iwai 	mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
2141c30aa7b2STakashi Iwai 	if (!nomix_path || !mix_path)
2142c30aa7b2STakashi Iwai 		return;
2143a1e908edSTakashi Iwai 
2144a1e908edSTakashi Iwai 	/* if HP aamix path is driven from a different DAC and the
2145a1e908edSTakashi Iwai 	 * independent HP mode is ON, can't turn on aamix path
2146a1e908edSTakashi Iwai 	 */
2147a1e908edSTakashi Iwai 	if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled &&
2148a1e908edSTakashi Iwai 	    mix_path->path[0] != spec->alt_dac_nid)
2149a1e908edSTakashi Iwai 		do_mix = false;
2150a1e908edSTakashi Iwai 
2151c30aa7b2STakashi Iwai 	if (do_mix) {
2152c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, nomix_path, false, true);
2153c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, mix_path, true, true);
215455196fffSTakashi Iwai 		path_power_down_sync(codec, nomix_path);
2155c30aa7b2STakashi Iwai 	} else {
2156c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, mix_path, false, true);
2157c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, nomix_path, true, true);
215855196fffSTakashi Iwai 		path_power_down_sync(codec, mix_path);
2159c30aa7b2STakashi Iwai 	}
2160c30aa7b2STakashi Iwai }
2161c30aa7b2STakashi Iwai 
2162c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
2163c30aa7b2STakashi Iwai 			       struct snd_ctl_elem_value *ucontrol)
2164c30aa7b2STakashi Iwai {
2165c30aa7b2STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2166c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2167c30aa7b2STakashi Iwai 	unsigned int val = ucontrol->value.enumerated.item[0];
2168c30aa7b2STakashi Iwai 
2169c30aa7b2STakashi Iwai 	if (val == spec->aamix_mode)
2170c30aa7b2STakashi Iwai 		return 0;
2171c30aa7b2STakashi Iwai 	spec->aamix_mode = val;
2172c30aa7b2STakashi Iwai 	update_aamix_paths(codec, val, spec->out_paths[0],
2173a1e908edSTakashi Iwai 			   spec->aamix_out_paths[0],
2174a1e908edSTakashi Iwai 			   spec->autocfg.line_out_type);
2175c30aa7b2STakashi Iwai 	update_aamix_paths(codec, val, spec->hp_paths[0],
2176a1e908edSTakashi Iwai 			   spec->aamix_out_paths[1],
2177a1e908edSTakashi Iwai 			   AUTO_PIN_HP_OUT);
2178c30aa7b2STakashi Iwai 	update_aamix_paths(codec, val, spec->speaker_paths[0],
2179a1e908edSTakashi Iwai 			   spec->aamix_out_paths[2],
2180a1e908edSTakashi Iwai 			   AUTO_PIN_SPEAKER_OUT);
2181c30aa7b2STakashi Iwai 	return 1;
2182c30aa7b2STakashi Iwai }
2183c30aa7b2STakashi Iwai 
2184c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = {
2185c30aa7b2STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2186c30aa7b2STakashi Iwai 	.name = "Loopback Mixing",
2187c30aa7b2STakashi Iwai 	.info = loopback_mixing_info,
2188c30aa7b2STakashi Iwai 	.get = loopback_mixing_get,
2189c30aa7b2STakashi Iwai 	.put = loopback_mixing_put,
2190c30aa7b2STakashi Iwai };
2191c30aa7b2STakashi Iwai 
2192c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec)
2193c30aa7b2STakashi Iwai {
2194c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2195c30aa7b2STakashi Iwai 
2196c30aa7b2STakashi Iwai 	if (!spec->mixer_nid)
2197c30aa7b2STakashi Iwai 		return 0;
2198c30aa7b2STakashi Iwai 	if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
2199c30aa7b2STakashi Iwai 	      spec->aamix_out_paths[2]))
2200c30aa7b2STakashi Iwai 		return 0;
2201c30aa7b2STakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
2202c30aa7b2STakashi Iwai 		return -ENOMEM;
2203a1e908edSTakashi Iwai 	spec->have_aamix_ctl = 1;
2204c30aa7b2STakashi Iwai 	return 0;
2205c30aa7b2STakashi Iwai }
2206c30aa7b2STakashi Iwai 
2207c30aa7b2STakashi Iwai /*
2208352f7f91STakashi Iwai  * shared headphone/mic handling
2209352f7f91STakashi Iwai  */
2210352f7f91STakashi Iwai 
2211352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec);
2212352f7f91STakashi Iwai 
2213352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */
2214967303daSTakashi Iwai static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force)
2215352f7f91STakashi Iwai {
2216352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2217967303daSTakashi Iwai 	bool as_mic;
2218352f7f91STakashi Iwai 	unsigned int val;
2219967303daSTakashi Iwai 	hda_nid_t pin;
2220967303daSTakashi Iwai 
2221967303daSTakashi Iwai 	pin = spec->hp_mic_pin;
2222967303daSTakashi Iwai 	as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx;
2223967303daSTakashi Iwai 
2224967303daSTakashi Iwai 	if (!force) {
2225967303daSTakashi Iwai 		val = snd_hda_codec_get_pin_target(codec, pin);
2226967303daSTakashi Iwai 		if (as_mic) {
2227967303daSTakashi Iwai 			if (val & PIN_IN)
2228967303daSTakashi Iwai 				return;
2229967303daSTakashi Iwai 		} else {
2230967303daSTakashi Iwai 			if (val & PIN_OUT)
2231967303daSTakashi Iwai 				return;
2232967303daSTakashi Iwai 		}
2233967303daSTakashi Iwai 	}
2234352f7f91STakashi Iwai 
2235352f7f91STakashi Iwai 	val = snd_hda_get_default_vref(codec, pin);
2236967303daSTakashi Iwai 	/* if the HP pin doesn't support VREF and the codec driver gives an
2237967303daSTakashi Iwai 	 * alternative pin, set up the VREF on that pin instead
2238967303daSTakashi Iwai 	 */
2239352f7f91STakashi Iwai 	if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
2240352f7f91STakashi Iwai 		const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
2241352f7f91STakashi Iwai 		unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
2242352f7f91STakashi Iwai 		if (vref_val != AC_PINCTL_VREF_HIZ)
22437594aa33STakashi Iwai 			snd_hda_set_pin_ctl_cache(codec, vref_pin,
2244967303daSTakashi Iwai 						  PIN_IN | (as_mic ? vref_val : 0));
2245352f7f91STakashi Iwai 	}
2246352f7f91STakashi Iwai 
22478ba955ceSTakashi Iwai 	if (!spec->hp_mic_jack_modes) {
2248967303daSTakashi Iwai 		if (as_mic)
2249967303daSTakashi Iwai 			val |= PIN_IN;
2250967303daSTakashi Iwai 		else
2251967303daSTakashi Iwai 			val = PIN_HP;
22522c12c30dSTakashi Iwai 		set_pin_target(codec, pin, val, true);
22538ba955ceSTakashi Iwai 		update_hp_automute_hook(codec);
22548ba955ceSTakashi Iwai 	}
2255352f7f91STakashi Iwai }
2256352f7f91STakashi Iwai 
2257352f7f91STakashi Iwai /* create a shared input with the headphone out */
2258967303daSTakashi Iwai static int create_hp_mic(struct hda_codec *codec)
2259352f7f91STakashi Iwai {
2260352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2261352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
2262352f7f91STakashi Iwai 	unsigned int defcfg;
2263352f7f91STakashi Iwai 	hda_nid_t nid;
2264352f7f91STakashi Iwai 
2265967303daSTakashi Iwai 	if (!spec->hp_mic) {
2266967303daSTakashi Iwai 		if (spec->suppress_hp_mic_detect)
2267352f7f91STakashi Iwai 			return 0;
2268967303daSTakashi Iwai 		/* automatic detection: only if no input or a single internal
2269967303daSTakashi Iwai 		 * input pin is found, try to detect the shared hp/mic
2270967303daSTakashi Iwai 		 */
2271967303daSTakashi Iwai 		if (cfg->num_inputs > 1)
2272967303daSTakashi Iwai 			return 0;
2273967303daSTakashi Iwai 		else if (cfg->num_inputs == 1) {
2274352f7f91STakashi Iwai 			defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
2275352f7f91STakashi Iwai 			if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
2276352f7f91STakashi Iwai 				return 0;
2277967303daSTakashi Iwai 		}
2278967303daSTakashi Iwai 	}
2279352f7f91STakashi Iwai 
2280967303daSTakashi Iwai 	spec->hp_mic = 0; /* clear once */
2281967303daSTakashi Iwai 	if (cfg->num_inputs >= AUTO_CFG_MAX_INS)
2282967303daSTakashi Iwai 		return 0;
2283967303daSTakashi Iwai 
2284967303daSTakashi Iwai 	nid = 0;
2285967303daSTakashi Iwai 	if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0)
2286967303daSTakashi Iwai 		nid = cfg->line_out_pins[0];
2287967303daSTakashi Iwai 	else if (cfg->hp_outs > 0)
2288967303daSTakashi Iwai 		nid = cfg->hp_pins[0];
2289967303daSTakashi Iwai 	if (!nid)
2290967303daSTakashi Iwai 		return 0;
2291352f7f91STakashi Iwai 
2292352f7f91STakashi Iwai 	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
2293352f7f91STakashi Iwai 		return 0; /* no input */
2294352f7f91STakashi Iwai 
2295967303daSTakashi Iwai 	cfg->inputs[cfg->num_inputs].pin = nid;
2296967303daSTakashi Iwai 	cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC;
2297967303daSTakashi Iwai 	cfg->num_inputs++;
2298967303daSTakashi Iwai 	spec->hp_mic = 1;
2299967303daSTakashi Iwai 	spec->hp_mic_pin = nid;
2300967303daSTakashi Iwai 	/* we can't handle auto-mic together with HP-mic */
2301967303daSTakashi Iwai 	spec->suppress_auto_mic = 1;
2302352f7f91STakashi Iwai 	snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid);
2303352f7f91STakashi Iwai 	return 0;
2304352f7f91STakashi Iwai }
2305352f7f91STakashi Iwai 
2306978e77e7STakashi Iwai /*
2307978e77e7STakashi Iwai  * output jack mode
2308978e77e7STakashi Iwai  */
23095f171baaSTakashi Iwai 
23105f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin);
23115f171baaSTakashi Iwai 
23125f171baaSTakashi Iwai static const char * const out_jack_texts[] = {
23135f171baaSTakashi Iwai 	"Line Out", "Headphone Out",
23145f171baaSTakashi Iwai };
23155f171baaSTakashi Iwai 
2316978e77e7STakashi Iwai static int out_jack_mode_info(struct snd_kcontrol *kcontrol,
2317978e77e7STakashi Iwai 			      struct snd_ctl_elem_info *uinfo)
2318978e77e7STakashi Iwai {
23195f171baaSTakashi Iwai 	return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts);
2320978e77e7STakashi Iwai }
2321978e77e7STakashi Iwai 
2322978e77e7STakashi Iwai static int out_jack_mode_get(struct snd_kcontrol *kcontrol,
2323978e77e7STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
2324978e77e7STakashi Iwai {
2325978e77e7STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2326978e77e7STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
2327978e77e7STakashi Iwai 	if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP)
2328978e77e7STakashi Iwai 		ucontrol->value.enumerated.item[0] = 1;
2329978e77e7STakashi Iwai 	else
2330978e77e7STakashi Iwai 		ucontrol->value.enumerated.item[0] = 0;
2331978e77e7STakashi Iwai 	return 0;
2332978e77e7STakashi Iwai }
2333978e77e7STakashi Iwai 
2334978e77e7STakashi Iwai static int out_jack_mode_put(struct snd_kcontrol *kcontrol,
2335978e77e7STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
2336978e77e7STakashi Iwai {
2337978e77e7STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2338978e77e7STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
2339978e77e7STakashi Iwai 	unsigned int val;
2340978e77e7STakashi Iwai 
2341978e77e7STakashi Iwai 	val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT;
2342978e77e7STakashi Iwai 	if (snd_hda_codec_get_pin_target(codec, nid) == val)
2343978e77e7STakashi Iwai 		return 0;
2344978e77e7STakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, nid, val);
2345978e77e7STakashi Iwai 	return 1;
2346978e77e7STakashi Iwai }
2347978e77e7STakashi Iwai 
2348978e77e7STakashi Iwai static const struct snd_kcontrol_new out_jack_mode_enum = {
2349978e77e7STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2350978e77e7STakashi Iwai 	.info = out_jack_mode_info,
2351978e77e7STakashi Iwai 	.get = out_jack_mode_get,
2352978e77e7STakashi Iwai 	.put = out_jack_mode_put,
2353978e77e7STakashi Iwai };
2354978e77e7STakashi Iwai 
2355978e77e7STakashi Iwai static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx)
2356978e77e7STakashi Iwai {
2357978e77e7STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2358978e77e7STakashi Iwai 	int i;
2359978e77e7STakashi Iwai 
2360978e77e7STakashi Iwai 	for (i = 0; i < spec->kctls.used; i++) {
2361978e77e7STakashi Iwai 		struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i);
2362978e77e7STakashi Iwai 		if (!strcmp(kctl->name, name) && kctl->index == idx)
2363978e77e7STakashi Iwai 			return true;
2364978e77e7STakashi Iwai 	}
2365978e77e7STakashi Iwai 	return false;
2366978e77e7STakashi Iwai }
2367978e77e7STakashi Iwai 
2368978e77e7STakashi Iwai static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
2369978e77e7STakashi Iwai 			       char *name, size_t name_len)
2370978e77e7STakashi Iwai {
2371978e77e7STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2372978e77e7STakashi Iwai 	int idx = 0;
2373978e77e7STakashi Iwai 
2374978e77e7STakashi Iwai 	snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx);
2375978e77e7STakashi Iwai 	strlcat(name, " Jack Mode", name_len);
2376978e77e7STakashi Iwai 
2377978e77e7STakashi Iwai 	for (; find_kctl_name(codec, name, idx); idx++)
2378978e77e7STakashi Iwai 		;
2379978e77e7STakashi Iwai }
2380978e77e7STakashi Iwai 
23815f171baaSTakashi Iwai static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
23825f171baaSTakashi Iwai {
23835f171baaSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2384f811c3cfSTakashi Iwai 	if (spec->add_jack_modes) {
23855f171baaSTakashi Iwai 		unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
23865f171baaSTakashi Iwai 		if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV))
23875f171baaSTakashi Iwai 			return 2;
23885f171baaSTakashi Iwai 	}
23895f171baaSTakashi Iwai 	return 1;
23905f171baaSTakashi Iwai }
23915f171baaSTakashi Iwai 
2392978e77e7STakashi Iwai static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
2393978e77e7STakashi Iwai 				 hda_nid_t *pins)
2394978e77e7STakashi Iwai {
2395978e77e7STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2396978e77e7STakashi Iwai 	int i;
2397978e77e7STakashi Iwai 
2398978e77e7STakashi Iwai 	for (i = 0; i < num_pins; i++) {
2399978e77e7STakashi Iwai 		hda_nid_t pin = pins[i];
24005f171baaSTakashi Iwai 		if (pin == spec->hp_mic_pin) {
24015f171baaSTakashi Iwai 			int ret = create_hp_mic_jack_mode(codec, pin);
24025f171baaSTakashi Iwai 			if (ret < 0)
24035f171baaSTakashi Iwai 				return ret;
24045f171baaSTakashi Iwai 			continue;
24055f171baaSTakashi Iwai 		}
24065f171baaSTakashi Iwai 		if (get_out_jack_num_items(codec, pin) > 1) {
2407978e77e7STakashi Iwai 			struct snd_kcontrol_new *knew;
2408978e77e7STakashi Iwai 			char name[44];
2409978e77e7STakashi Iwai 			get_jack_mode_name(codec, pin, name, sizeof(name));
2410978e77e7STakashi Iwai 			knew = snd_hda_gen_add_kctl(spec, name,
2411978e77e7STakashi Iwai 						    &out_jack_mode_enum);
2412978e77e7STakashi Iwai 			if (!knew)
2413978e77e7STakashi Iwai 				return -ENOMEM;
2414978e77e7STakashi Iwai 			knew->private_value = pin;
2415978e77e7STakashi Iwai 		}
2416978e77e7STakashi Iwai 	}
2417978e77e7STakashi Iwai 
2418978e77e7STakashi Iwai 	return 0;
2419978e77e7STakashi Iwai }
2420978e77e7STakashi Iwai 
242129476558STakashi Iwai /*
242229476558STakashi Iwai  * input jack mode
242329476558STakashi Iwai  */
242429476558STakashi Iwai 
242529476558STakashi Iwai /* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */
242629476558STakashi Iwai #define NUM_VREFS	6
242729476558STakashi Iwai 
242829476558STakashi Iwai static const char * const vref_texts[NUM_VREFS] = {
242929476558STakashi Iwai 	"Line In", "Mic 50pc Bias", "Mic 0V Bias",
243029476558STakashi Iwai 	"", "Mic 80pc Bias", "Mic 100pc Bias"
243129476558STakashi Iwai };
243229476558STakashi Iwai 
243329476558STakashi Iwai static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin)
243429476558STakashi Iwai {
243529476558STakashi Iwai 	unsigned int pincap;
243629476558STakashi Iwai 
243729476558STakashi Iwai 	pincap = snd_hda_query_pin_caps(codec, pin);
243829476558STakashi Iwai 	pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
243929476558STakashi Iwai 	/* filter out unusual vrefs */
244029476558STakashi Iwai 	pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100);
244129476558STakashi Iwai 	return pincap;
244229476558STakashi Iwai }
244329476558STakashi Iwai 
244429476558STakashi Iwai /* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */
244529476558STakashi Iwai static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx)
244629476558STakashi Iwai {
244729476558STakashi Iwai 	unsigned int i, n = 0;
244829476558STakashi Iwai 
244929476558STakashi Iwai 	for (i = 0; i < NUM_VREFS; i++) {
245029476558STakashi Iwai 		if (vref_caps & (1 << i)) {
245129476558STakashi Iwai 			if (n == item_idx)
245229476558STakashi Iwai 				return i;
245329476558STakashi Iwai 			n++;
245429476558STakashi Iwai 		}
245529476558STakashi Iwai 	}
245629476558STakashi Iwai 	return 0;
245729476558STakashi Iwai }
245829476558STakashi Iwai 
245929476558STakashi Iwai /* convert back from the vref ctl index to the enum item index */
246029476558STakashi Iwai static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx)
246129476558STakashi Iwai {
246229476558STakashi Iwai 	unsigned int i, n = 0;
246329476558STakashi Iwai 
246429476558STakashi Iwai 	for (i = 0; i < NUM_VREFS; i++) {
246529476558STakashi Iwai 		if (i == idx)
246629476558STakashi Iwai 			return n;
246729476558STakashi Iwai 		if (vref_caps & (1 << i))
246829476558STakashi Iwai 			n++;
246929476558STakashi Iwai 	}
247029476558STakashi Iwai 	return 0;
247129476558STakashi Iwai }
247229476558STakashi Iwai 
247329476558STakashi Iwai static int in_jack_mode_info(struct snd_kcontrol *kcontrol,
247429476558STakashi Iwai 			     struct snd_ctl_elem_info *uinfo)
247529476558STakashi Iwai {
247629476558STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
247729476558STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
247829476558STakashi Iwai 	unsigned int vref_caps = get_vref_caps(codec, nid);
247929476558STakashi Iwai 
248029476558STakashi Iwai 	snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps),
248129476558STakashi Iwai 				 vref_texts);
248229476558STakashi Iwai 	/* set the right text */
248329476558STakashi Iwai 	strcpy(uinfo->value.enumerated.name,
248429476558STakashi Iwai 	       vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]);
248529476558STakashi Iwai 	return 0;
248629476558STakashi Iwai }
248729476558STakashi Iwai 
248829476558STakashi Iwai static int in_jack_mode_get(struct snd_kcontrol *kcontrol,
248929476558STakashi Iwai 			    struct snd_ctl_elem_value *ucontrol)
249029476558STakashi Iwai {
249129476558STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
249229476558STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
249329476558STakashi Iwai 	unsigned int vref_caps = get_vref_caps(codec, nid);
249429476558STakashi Iwai 	unsigned int idx;
249529476558STakashi Iwai 
249629476558STakashi Iwai 	idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN;
249729476558STakashi Iwai 	ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx);
249829476558STakashi Iwai 	return 0;
249929476558STakashi Iwai }
250029476558STakashi Iwai 
250129476558STakashi Iwai static int in_jack_mode_put(struct snd_kcontrol *kcontrol,
250229476558STakashi Iwai 			    struct snd_ctl_elem_value *ucontrol)
250329476558STakashi Iwai {
250429476558STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
250529476558STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
250629476558STakashi Iwai 	unsigned int vref_caps = get_vref_caps(codec, nid);
250729476558STakashi Iwai 	unsigned int val, idx;
250829476558STakashi Iwai 
250929476558STakashi Iwai 	val = snd_hda_codec_get_pin_target(codec, nid);
251029476558STakashi Iwai 	idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN);
251129476558STakashi Iwai 	if (idx == ucontrol->value.enumerated.item[0])
251229476558STakashi Iwai 		return 0;
251329476558STakashi Iwai 
251429476558STakashi Iwai 	val &= ~AC_PINCTL_VREFEN;
251529476558STakashi Iwai 	val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]);
251629476558STakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, nid, val);
251729476558STakashi Iwai 	return 1;
251829476558STakashi Iwai }
251929476558STakashi Iwai 
252029476558STakashi Iwai static const struct snd_kcontrol_new in_jack_mode_enum = {
252129476558STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
252229476558STakashi Iwai 	.info = in_jack_mode_info,
252329476558STakashi Iwai 	.get = in_jack_mode_get,
252429476558STakashi Iwai 	.put = in_jack_mode_put,
252529476558STakashi Iwai };
252629476558STakashi Iwai 
25275f171baaSTakashi Iwai static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
25285f171baaSTakashi Iwai {
25295f171baaSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
25305f171baaSTakashi Iwai 	int nitems = 0;
2531f811c3cfSTakashi Iwai 	if (spec->add_jack_modes)
25325f171baaSTakashi Iwai 		nitems = hweight32(get_vref_caps(codec, pin));
25335f171baaSTakashi Iwai 	return nitems ? nitems : 1;
25345f171baaSTakashi Iwai }
25355f171baaSTakashi Iwai 
253629476558STakashi Iwai static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
253729476558STakashi Iwai {
253829476558STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
253929476558STakashi Iwai 	struct snd_kcontrol_new *knew;
254029476558STakashi Iwai 	char name[44];
25415f171baaSTakashi Iwai 	unsigned int defcfg;
25425f171baaSTakashi Iwai 
2543f811c3cfSTakashi Iwai 	if (pin == spec->hp_mic_pin)
2544f811c3cfSTakashi Iwai 		return 0; /* already done in create_out_jack_mode() */
254529476558STakashi Iwai 
254629476558STakashi Iwai 	/* no jack mode for fixed pins */
254729476558STakashi Iwai 	defcfg = snd_hda_codec_get_pincfg(codec, pin);
254829476558STakashi Iwai 	if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
254929476558STakashi Iwai 		return 0;
255029476558STakashi Iwai 
255129476558STakashi Iwai 	/* no multiple vref caps? */
25525f171baaSTakashi Iwai 	if (get_in_jack_num_items(codec, pin) <= 1)
255329476558STakashi Iwai 		return 0;
255429476558STakashi Iwai 
255529476558STakashi Iwai 	get_jack_mode_name(codec, pin, name, sizeof(name));
255629476558STakashi Iwai 	knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum);
255729476558STakashi Iwai 	if (!knew)
255829476558STakashi Iwai 		return -ENOMEM;
255929476558STakashi Iwai 	knew->private_value = pin;
256029476558STakashi Iwai 	return 0;
256129476558STakashi Iwai }
256229476558STakashi Iwai 
25635f171baaSTakashi Iwai /*
25645f171baaSTakashi Iwai  * HP/mic shared jack mode
25655f171baaSTakashi Iwai  */
25665f171baaSTakashi Iwai static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol,
25675f171baaSTakashi Iwai 				 struct snd_ctl_elem_info *uinfo)
25685f171baaSTakashi Iwai {
25695f171baaSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
25705f171baaSTakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
25715f171baaSTakashi Iwai 	int out_jacks = get_out_jack_num_items(codec, nid);
25725f171baaSTakashi Iwai 	int in_jacks = get_in_jack_num_items(codec, nid);
25735f171baaSTakashi Iwai 	const char *text = NULL;
25745f171baaSTakashi Iwai 	int idx;
25755f171baaSTakashi Iwai 
25765f171baaSTakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
25775f171baaSTakashi Iwai 	uinfo->count = 1;
25785f171baaSTakashi Iwai 	uinfo->value.enumerated.items = out_jacks + in_jacks;
25795f171baaSTakashi Iwai 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
25805f171baaSTakashi Iwai 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
25815f171baaSTakashi Iwai 	idx = uinfo->value.enumerated.item;
25825f171baaSTakashi Iwai 	if (idx < out_jacks) {
25835f171baaSTakashi Iwai 		if (out_jacks > 1)
25845f171baaSTakashi Iwai 			text = out_jack_texts[idx];
25855f171baaSTakashi Iwai 		else
25865f171baaSTakashi Iwai 			text = "Headphone Out";
25875f171baaSTakashi Iwai 	} else {
25885f171baaSTakashi Iwai 		idx -= out_jacks;
25895f171baaSTakashi Iwai 		if (in_jacks > 1) {
25905f171baaSTakashi Iwai 			unsigned int vref_caps = get_vref_caps(codec, nid);
25915f171baaSTakashi Iwai 			text = vref_texts[get_vref_idx(vref_caps, idx)];
25925f171baaSTakashi Iwai 		} else
25935f171baaSTakashi Iwai 			text = "Mic In";
25945f171baaSTakashi Iwai 	}
25955f171baaSTakashi Iwai 
25965f171baaSTakashi Iwai 	strcpy(uinfo->value.enumerated.name, text);
25975f171baaSTakashi Iwai 	return 0;
25985f171baaSTakashi Iwai }
25995f171baaSTakashi Iwai 
26005f171baaSTakashi Iwai static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid)
26015f171baaSTakashi Iwai {
26025f171baaSTakashi Iwai 	int out_jacks = get_out_jack_num_items(codec, nid);
26035f171baaSTakashi Iwai 	int in_jacks = get_in_jack_num_items(codec, nid);
26045f171baaSTakashi Iwai 	unsigned int val = snd_hda_codec_get_pin_target(codec, nid);
26055f171baaSTakashi Iwai 	int idx = 0;
26065f171baaSTakashi Iwai 
26075f171baaSTakashi Iwai 	if (val & PIN_OUT) {
26085f171baaSTakashi Iwai 		if (out_jacks > 1 && val == PIN_HP)
26095f171baaSTakashi Iwai 			idx = 1;
26105f171baaSTakashi Iwai 	} else if (val & PIN_IN) {
26115f171baaSTakashi Iwai 		idx = out_jacks;
26125f171baaSTakashi Iwai 		if (in_jacks > 1) {
26135f171baaSTakashi Iwai 			unsigned int vref_caps = get_vref_caps(codec, nid);
26145f171baaSTakashi Iwai 			val &= AC_PINCTL_VREFEN;
26155f171baaSTakashi Iwai 			idx += cvt_from_vref_idx(vref_caps, val);
26165f171baaSTakashi Iwai 		}
26175f171baaSTakashi Iwai 	}
26185f171baaSTakashi Iwai 	return idx;
26195f171baaSTakashi Iwai }
26205f171baaSTakashi Iwai 
26215f171baaSTakashi Iwai static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol,
26225f171baaSTakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
26235f171baaSTakashi Iwai {
26245f171baaSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
26255f171baaSTakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
26265f171baaSTakashi Iwai 	ucontrol->value.enumerated.item[0] =
26275f171baaSTakashi Iwai 		get_cur_hp_mic_jack_mode(codec, nid);
26285f171baaSTakashi Iwai 	return 0;
26295f171baaSTakashi Iwai }
26305f171baaSTakashi Iwai 
26315f171baaSTakashi Iwai static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
26325f171baaSTakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
26335f171baaSTakashi Iwai {
26345f171baaSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
26355f171baaSTakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
26365f171baaSTakashi Iwai 	int out_jacks = get_out_jack_num_items(codec, nid);
26375f171baaSTakashi Iwai 	int in_jacks = get_in_jack_num_items(codec, nid);
26385f171baaSTakashi Iwai 	unsigned int val, oldval, idx;
26395f171baaSTakashi Iwai 
26405f171baaSTakashi Iwai 	oldval = get_cur_hp_mic_jack_mode(codec, nid);
26415f171baaSTakashi Iwai 	idx = ucontrol->value.enumerated.item[0];
26425f171baaSTakashi Iwai 	if (oldval == idx)
26435f171baaSTakashi Iwai 		return 0;
26445f171baaSTakashi Iwai 
26455f171baaSTakashi Iwai 	if (idx < out_jacks) {
26465f171baaSTakashi Iwai 		if (out_jacks > 1)
26475f171baaSTakashi Iwai 			val = idx ? PIN_HP : PIN_OUT;
26485f171baaSTakashi Iwai 		else
26495f171baaSTakashi Iwai 			val = PIN_HP;
26505f171baaSTakashi Iwai 	} else {
26515f171baaSTakashi Iwai 		idx -= out_jacks;
26525f171baaSTakashi Iwai 		if (in_jacks > 1) {
26535f171baaSTakashi Iwai 			unsigned int vref_caps = get_vref_caps(codec, nid);
26545f171baaSTakashi Iwai 			val = snd_hda_codec_get_pin_target(codec, nid);
26553f550e32STakashi Iwai 			val &= ~(AC_PINCTL_VREFEN | PIN_HP);
26563f550e32STakashi Iwai 			val |= get_vref_idx(vref_caps, idx) | PIN_IN;
26575f171baaSTakashi Iwai 		} else
26585f171baaSTakashi Iwai 			val = snd_hda_get_default_vref(codec, nid);
26595f171baaSTakashi Iwai 	}
26605f171baaSTakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, nid, val);
26618ba955ceSTakashi Iwai 	update_hp_automute_hook(codec);
26628ba955ceSTakashi Iwai 
26635f171baaSTakashi Iwai 	return 1;
26645f171baaSTakashi Iwai }
26655f171baaSTakashi Iwai 
26665f171baaSTakashi Iwai static const struct snd_kcontrol_new hp_mic_jack_mode_enum = {
26675f171baaSTakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
26685f171baaSTakashi Iwai 	.info = hp_mic_jack_mode_info,
26695f171baaSTakashi Iwai 	.get = hp_mic_jack_mode_get,
26705f171baaSTakashi Iwai 	.put = hp_mic_jack_mode_put,
26715f171baaSTakashi Iwai };
26725f171baaSTakashi Iwai 
26735f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
26745f171baaSTakashi Iwai {
26755f171baaSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
26765f171baaSTakashi Iwai 	struct snd_kcontrol_new *knew;
26775f171baaSTakashi Iwai 
26785f171baaSTakashi Iwai 	if (get_out_jack_num_items(codec, pin) <= 1 &&
26795f171baaSTakashi Iwai 	    get_in_jack_num_items(codec, pin) <= 1)
26805f171baaSTakashi Iwai 		return 0; /* no need */
26815f171baaSTakashi Iwai 	knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
26825f171baaSTakashi Iwai 				    &hp_mic_jack_mode_enum);
26835f171baaSTakashi Iwai 	if (!knew)
26845f171baaSTakashi Iwai 		return -ENOMEM;
26855f171baaSTakashi Iwai 	knew->private_value = pin;
26868ba955ceSTakashi Iwai 	spec->hp_mic_jack_modes = 1;
26875f171baaSTakashi Iwai 	return 0;
26885f171baaSTakashi Iwai }
2689352f7f91STakashi Iwai 
2690352f7f91STakashi Iwai /*
2691352f7f91STakashi Iwai  * Parse input paths
2692352f7f91STakashi Iwai  */
2693352f7f91STakashi Iwai 
2694352f7f91STakashi Iwai /* add the powersave loopback-list entry */
26950186f4f4STakashi Iwai static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
2696352f7f91STakashi Iwai {
2697352f7f91STakashi Iwai 	struct hda_amp_list *list;
2698352f7f91STakashi Iwai 
26990186f4f4STakashi Iwai 	list = snd_array_new(&spec->loopback_list);
27000186f4f4STakashi Iwai 	if (!list)
27010186f4f4STakashi Iwai 		return -ENOMEM;
2702352f7f91STakashi Iwai 	list->nid = mix;
2703352f7f91STakashi Iwai 	list->dir = HDA_INPUT;
2704352f7f91STakashi Iwai 	list->idx = idx;
27050186f4f4STakashi Iwai 	spec->loopback.amplist = spec->loopback_list.list;
27060186f4f4STakashi Iwai 	return 0;
2707cb53c626STakashi Iwai }
2708cb53c626STakashi Iwai 
2709352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */
2710196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx,
2711196c1766STakashi Iwai 			    hda_nid_t pin, const char *ctlname, int ctlidx,
2712352f7f91STakashi Iwai 			    hda_nid_t mix_nid)
27131da177e4SLinus Torvalds {
2714352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2715352f7f91STakashi Iwai 	struct nid_path *path;
2716352f7f91STakashi Iwai 	unsigned int val;
2717352f7f91STakashi Iwai 	int err, idx;
27181da177e4SLinus Torvalds 
2719352f7f91STakashi Iwai 	if (!nid_has_volume(codec, mix_nid, HDA_INPUT) &&
2720352f7f91STakashi Iwai 	    !nid_has_mute(codec, mix_nid, HDA_INPUT))
2721352f7f91STakashi Iwai 		return 0; /* no need for analog loopback */
2722352f7f91STakashi Iwai 
27233ca529d3STakashi Iwai 	path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
2724352f7f91STakashi Iwai 	if (!path)
2725352f7f91STakashi Iwai 		return -EINVAL;
27260c8c0f56STakashi Iwai 	print_nid_path("loopback", path);
2727196c1766STakashi Iwai 	spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
2728352f7f91STakashi Iwai 
2729352f7f91STakashi Iwai 	idx = path->idx[path->depth - 1];
2730352f7f91STakashi Iwai 	if (nid_has_volume(codec, mix_nid, HDA_INPUT)) {
2731352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
2732352f7f91STakashi Iwai 		err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val);
2733d13bd412STakashi Iwai 		if (err < 0)
27341da177e4SLinus Torvalds 			return err;
2735352f7f91STakashi Iwai 		path->ctls[NID_PATH_VOL_CTL] = val;
27361da177e4SLinus Torvalds 	}
27371da177e4SLinus Torvalds 
2738352f7f91STakashi Iwai 	if (nid_has_mute(codec, mix_nid, HDA_INPUT)) {
2739352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
2740352f7f91STakashi Iwai 		err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val);
2741d13bd412STakashi Iwai 		if (err < 0)
27421da177e4SLinus Torvalds 			return err;
2743352f7f91STakashi Iwai 		path->ctls[NID_PATH_MUTE_CTL] = val;
27441da177e4SLinus Torvalds 	}
27451da177e4SLinus Torvalds 
2746352f7f91STakashi Iwai 	path->active = true;
27470186f4f4STakashi Iwai 	err = add_loopback_list(spec, mix_nid, idx);
27480186f4f4STakashi Iwai 	if (err < 0)
27490186f4f4STakashi Iwai 		return err;
2750e4a395e7STakashi Iwai 
2751e4a395e7STakashi Iwai 	if (spec->mixer_nid != spec->mixer_merge_nid &&
2752e4a395e7STakashi Iwai 	    !spec->loopback_merge_path) {
2753e4a395e7STakashi Iwai 		path = snd_hda_add_new_path(codec, spec->mixer_nid,
2754e4a395e7STakashi Iwai 					    spec->mixer_merge_nid, 0);
2755e4a395e7STakashi Iwai 		if (path) {
2756e4a395e7STakashi Iwai 			print_nid_path("loopback-merge", path);
2757e4a395e7STakashi Iwai 			path->active = true;
2758e4a395e7STakashi Iwai 			spec->loopback_merge_path =
2759e4a395e7STakashi Iwai 				snd_hda_get_path_idx(codec, path);
2760e4a395e7STakashi Iwai 		}
2761e4a395e7STakashi Iwai 	}
2762e4a395e7STakashi Iwai 
2763352f7f91STakashi Iwai 	return 0;
27641da177e4SLinus Torvalds }
27651da177e4SLinus Torvalds 
2766352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid)
27671da177e4SLinus Torvalds {
2768352f7f91STakashi Iwai 	unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
2769352f7f91STakashi Iwai 	return (pincap & AC_PINCAP_IN) != 0;
2770352f7f91STakashi Iwai }
2771352f7f91STakashi Iwai 
2772352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */
2773352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec)
2774352f7f91STakashi Iwai {
2775352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2776352f7f91STakashi Iwai 	hda_nid_t nid;
2777352f7f91STakashi Iwai 	hda_nid_t *adc_nids = spec->adc_nids;
2778352f7f91STakashi Iwai 	int max_nums = ARRAY_SIZE(spec->adc_nids);
2779352f7f91STakashi Iwai 	int i, nums = 0;
2780352f7f91STakashi Iwai 
2781352f7f91STakashi Iwai 	nid = codec->start_nid;
2782352f7f91STakashi Iwai 	for (i = 0; i < codec->num_nodes; i++, nid++) {
2783352f7f91STakashi Iwai 		unsigned int caps = get_wcaps(codec, nid);
2784352f7f91STakashi Iwai 		int type = get_wcaps_type(caps);
2785352f7f91STakashi Iwai 
2786352f7f91STakashi Iwai 		if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
2787352f7f91STakashi Iwai 			continue;
2788352f7f91STakashi Iwai 		adc_nids[nums] = nid;
2789352f7f91STakashi Iwai 		if (++nums >= max_nums)
2790352f7f91STakashi Iwai 			break;
2791352f7f91STakashi Iwai 	}
2792352f7f91STakashi Iwai 	spec->num_adc_nids = nums;
27930ffd534eSTakashi Iwai 
27940ffd534eSTakashi Iwai 	/* copy the detected ADCs to all_adcs[] */
27950ffd534eSTakashi Iwai 	spec->num_all_adcs = nums;
27960ffd534eSTakashi Iwai 	memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t));
27970ffd534eSTakashi Iwai 
2798352f7f91STakashi Iwai 	return nums;
2799352f7f91STakashi Iwai }
2800352f7f91STakashi Iwai 
2801352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins;
2802352f7f91STakashi Iwai  * if needed, check whether dynamic ADC-switching is available
2803352f7f91STakashi Iwai  */
2804352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec)
2805352f7f91STakashi Iwai {
2806352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2807352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
28083a65bcdcSTakashi Iwai 	unsigned int ok_bits;
2809352f7f91STakashi Iwai 	int i, n, nums;
2810352f7f91STakashi Iwai 
2811352f7f91STakashi Iwai 	nums = 0;
28123a65bcdcSTakashi Iwai 	ok_bits = 0;
2813352f7f91STakashi Iwai 	for (n = 0; n < spec->num_adc_nids; n++) {
2814352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
28153a65bcdcSTakashi Iwai 			if (!spec->input_paths[i][n])
2816352f7f91STakashi Iwai 				break;
2817352f7f91STakashi Iwai 		}
28183a65bcdcSTakashi Iwai 		if (i >= imux->num_items) {
28193a65bcdcSTakashi Iwai 			ok_bits |= (1 << n);
28203a65bcdcSTakashi Iwai 			nums++;
28213a65bcdcSTakashi Iwai 		}
2822352f7f91STakashi Iwai 	}
2823352f7f91STakashi Iwai 
28243a65bcdcSTakashi Iwai 	if (!ok_bits) {
2825352f7f91STakashi Iwai 		/* check whether ADC-switch is possible */
2826352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
2827352f7f91STakashi Iwai 			for (n = 0; n < spec->num_adc_nids; n++) {
28283a65bcdcSTakashi Iwai 				if (spec->input_paths[i][n]) {
2829352f7f91STakashi Iwai 					spec->dyn_adc_idx[i] = n;
2830352f7f91STakashi Iwai 					break;
2831352f7f91STakashi Iwai 				}
2832352f7f91STakashi Iwai 			}
2833352f7f91STakashi Iwai 		}
2834352f7f91STakashi Iwai 
2835352f7f91STakashi Iwai 		snd_printdd("hda-codec: enabling ADC switching\n");
2836352f7f91STakashi Iwai 		spec->dyn_adc_switch = 1;
2837352f7f91STakashi Iwai 	} else if (nums != spec->num_adc_nids) {
28383a65bcdcSTakashi Iwai 		/* shrink the invalid adcs and input paths */
28393a65bcdcSTakashi Iwai 		nums = 0;
28403a65bcdcSTakashi Iwai 		for (n = 0; n < spec->num_adc_nids; n++) {
28413a65bcdcSTakashi Iwai 			if (!(ok_bits & (1 << n)))
28423a65bcdcSTakashi Iwai 				continue;
28433a65bcdcSTakashi Iwai 			if (n != nums) {
28443a65bcdcSTakashi Iwai 				spec->adc_nids[nums] = spec->adc_nids[n];
2845980428ceSTakashi Iwai 				for (i = 0; i < imux->num_items; i++) {
2846980428ceSTakashi Iwai 					invalidate_nid_path(codec,
2847980428ceSTakashi Iwai 						spec->input_paths[i][nums]);
28483a65bcdcSTakashi Iwai 					spec->input_paths[i][nums] =
28493a65bcdcSTakashi Iwai 						spec->input_paths[i][n];
28503a65bcdcSTakashi Iwai 				}
2851980428ceSTakashi Iwai 			}
28523a65bcdcSTakashi Iwai 			nums++;
28533a65bcdcSTakashi Iwai 		}
2854352f7f91STakashi Iwai 		spec->num_adc_nids = nums;
2855352f7f91STakashi Iwai 	}
2856352f7f91STakashi Iwai 
2857967303daSTakashi Iwai 	if (imux->num_items == 1 ||
2858967303daSTakashi Iwai 	    (imux->num_items == 2 && spec->hp_mic)) {
2859352f7f91STakashi Iwai 		snd_printdd("hda-codec: reducing to a single ADC\n");
2860352f7f91STakashi Iwai 		spec->num_adc_nids = 1; /* reduce to a single ADC */
2861352f7f91STakashi Iwai 	}
2862352f7f91STakashi Iwai 
2863352f7f91STakashi Iwai 	/* single index for individual volumes ctls */
2864352f7f91STakashi Iwai 	if (!spec->dyn_adc_switch && spec->multi_cap_vol)
2865352f7f91STakashi Iwai 		spec->num_adc_nids = 1;
2866352f7f91STakashi Iwai 
28671da177e4SLinus Torvalds 	return 0;
28681da177e4SLinus Torvalds }
28691da177e4SLinus Torvalds 
2870f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */
2871f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
28729dba205bSTakashi Iwai 				int cfg_idx, int num_adcs,
28739dba205bSTakashi Iwai 				const char *label, int anchor)
2874f3fc0b0bSTakashi Iwai {
2875f3fc0b0bSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2876f3fc0b0bSTakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
2877f3fc0b0bSTakashi Iwai 	int imux_idx = imux->num_items;
2878f3fc0b0bSTakashi Iwai 	bool imux_added = false;
2879f3fc0b0bSTakashi Iwai 	int c;
2880f3fc0b0bSTakashi Iwai 
2881f3fc0b0bSTakashi Iwai 	for (c = 0; c < num_adcs; c++) {
2882f3fc0b0bSTakashi Iwai 		struct nid_path *path;
2883f3fc0b0bSTakashi Iwai 		hda_nid_t adc = spec->adc_nids[c];
2884f3fc0b0bSTakashi Iwai 
2885f3fc0b0bSTakashi Iwai 		if (!is_reachable_path(codec, pin, adc))
2886f3fc0b0bSTakashi Iwai 			continue;
2887f3fc0b0bSTakashi Iwai 		path = snd_hda_add_new_path(codec, pin, adc, anchor);
2888f3fc0b0bSTakashi Iwai 		if (!path)
2889f3fc0b0bSTakashi Iwai 			continue;
2890f3fc0b0bSTakashi Iwai 		print_nid_path("input", path);
2891f3fc0b0bSTakashi Iwai 		spec->input_paths[imux_idx][c] =
2892f3fc0b0bSTakashi Iwai 			snd_hda_get_path_idx(codec, path);
2893f3fc0b0bSTakashi Iwai 
2894f3fc0b0bSTakashi Iwai 		if (!imux_added) {
2895967303daSTakashi Iwai 			if (spec->hp_mic_pin == pin)
2896967303daSTakashi Iwai 				spec->hp_mic_mux_idx = imux->num_items;
2897f3fc0b0bSTakashi Iwai 			spec->imux_pins[imux->num_items] = pin;
28989dba205bSTakashi Iwai 			snd_hda_add_imux_item(imux, label, cfg_idx, NULL);
2899f3fc0b0bSTakashi Iwai 			imux_added = true;
2900f3fc0b0bSTakashi Iwai 		}
2901f3fc0b0bSTakashi Iwai 	}
2902f3fc0b0bSTakashi Iwai 
2903f3fc0b0bSTakashi Iwai 	return 0;
2904f3fc0b0bSTakashi Iwai }
2905f3fc0b0bSTakashi Iwai 
29061da177e4SLinus Torvalds /*
2907352f7f91STakashi Iwai  * create playback/capture controls for input pins
29081da177e4SLinus Torvalds  */
29099dba205bSTakashi Iwai 
2910c970042cSTakashi Iwai /* fill the label for each input at first */
2911c970042cSTakashi Iwai static int fill_input_pin_labels(struct hda_codec *codec)
2912c970042cSTakashi Iwai {
2913c970042cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2914c970042cSTakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
2915c970042cSTakashi Iwai 	int i;
2916c970042cSTakashi Iwai 
2917c970042cSTakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
2918c970042cSTakashi Iwai 		hda_nid_t pin = cfg->inputs[i].pin;
2919c970042cSTakashi Iwai 		const char *label;
2920c970042cSTakashi Iwai 		int j, idx;
2921c970042cSTakashi Iwai 
2922c970042cSTakashi Iwai 		if (!is_input_pin(codec, pin))
2923c970042cSTakashi Iwai 			continue;
2924c970042cSTakashi Iwai 
2925c970042cSTakashi Iwai 		label = hda_get_autocfg_input_label(codec, cfg, i);
2926c970042cSTakashi Iwai 		idx = 0;
29278e8db7f1SDavid Henningsson 		for (j = i - 1; j >= 0; j--) {
2928c970042cSTakashi Iwai 			if (spec->input_labels[j] &&
2929c970042cSTakashi Iwai 			    !strcmp(spec->input_labels[j], label)) {
2930c970042cSTakashi Iwai 				idx = spec->input_label_idxs[j] + 1;
2931c970042cSTakashi Iwai 				break;
2932c970042cSTakashi Iwai 			}
2933c970042cSTakashi Iwai 		}
2934c970042cSTakashi Iwai 
2935c970042cSTakashi Iwai 		spec->input_labels[i] = label;
2936c970042cSTakashi Iwai 		spec->input_label_idxs[i] = idx;
2937c970042cSTakashi Iwai 	}
2938c970042cSTakashi Iwai 
2939c970042cSTakashi Iwai 	return 0;
2940c970042cSTakashi Iwai }
2941c970042cSTakashi Iwai 
29429dba205bSTakashi Iwai #define CFG_IDX_MIX	99	/* a dummy cfg->input idx for stereo mix */
29439dba205bSTakashi Iwai 
2944352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec)
2945a7da6ce5STakashi Iwai {
2946352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2947352f7f91STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
2948352f7f91STakashi Iwai 	hda_nid_t mixer = spec->mixer_nid;
2949352f7f91STakashi Iwai 	int num_adcs;
2950c970042cSTakashi Iwai 	int i, err;
29512c12c30dSTakashi Iwai 	unsigned int val;
2952a7da6ce5STakashi Iwai 
2953352f7f91STakashi Iwai 	num_adcs = fill_adc_nids(codec);
2954352f7f91STakashi Iwai 	if (num_adcs < 0)
2955352f7f91STakashi Iwai 		return 0;
2956352f7f91STakashi Iwai 
2957c970042cSTakashi Iwai 	err = fill_input_pin_labels(codec);
2958c970042cSTakashi Iwai 	if (err < 0)
2959c970042cSTakashi Iwai 		return err;
2960c970042cSTakashi Iwai 
2961352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
2962352f7f91STakashi Iwai 		hda_nid_t pin;
2963352f7f91STakashi Iwai 
2964352f7f91STakashi Iwai 		pin = cfg->inputs[i].pin;
2965352f7f91STakashi Iwai 		if (!is_input_pin(codec, pin))
2966352f7f91STakashi Iwai 			continue;
2967352f7f91STakashi Iwai 
29682c12c30dSTakashi Iwai 		val = PIN_IN;
29692c12c30dSTakashi Iwai 		if (cfg->inputs[i].type == AUTO_PIN_MIC)
29702c12c30dSTakashi Iwai 			val |= snd_hda_get_default_vref(codec, pin);
297193c9d8aeSTakashi Iwai 		if (pin != spec->hp_mic_pin)
29722c12c30dSTakashi Iwai 			set_pin_target(codec, pin, val, false);
29732c12c30dSTakashi Iwai 
2974352f7f91STakashi Iwai 		if (mixer) {
2975352f7f91STakashi Iwai 			if (is_reachable_path(codec, pin, mixer)) {
2976196c1766STakashi Iwai 				err = new_analog_input(codec, i, pin,
2977c970042cSTakashi Iwai 						       spec->input_labels[i],
2978c970042cSTakashi Iwai 						       spec->input_label_idxs[i],
2979c970042cSTakashi Iwai 						       mixer);
2980a7da6ce5STakashi Iwai 				if (err < 0)
2981a7da6ce5STakashi Iwai 					return err;
2982a7da6ce5STakashi Iwai 			}
2983352f7f91STakashi Iwai 		}
2984352f7f91STakashi Iwai 
2985c970042cSTakashi Iwai 		err = parse_capture_source(codec, pin, i, num_adcs,
2986c970042cSTakashi Iwai 					   spec->input_labels[i], -mixer);
2987f3fc0b0bSTakashi Iwai 		if (err < 0)
2988f3fc0b0bSTakashi Iwai 			return err;
298929476558STakashi Iwai 
2990f811c3cfSTakashi Iwai 		if (spec->add_jack_modes) {
299129476558STakashi Iwai 			err = create_in_jack_mode(codec, pin);
299229476558STakashi Iwai 			if (err < 0)
299329476558STakashi Iwai 				return err;
299429476558STakashi Iwai 		}
2995352f7f91STakashi Iwai 	}
2996f3fc0b0bSTakashi Iwai 
2997f3fc0b0bSTakashi Iwai 	if (mixer && spec->add_stereo_mix_input) {
29989dba205bSTakashi Iwai 		err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
2999f3fc0b0bSTakashi Iwai 					   "Stereo Mix", 0);
3000f3fc0b0bSTakashi Iwai 		if (err < 0)
3001f3fc0b0bSTakashi Iwai 			return err;
3002352f7f91STakashi Iwai 	}
3003352f7f91STakashi Iwai 
3004a7da6ce5STakashi Iwai 	return 0;
3005a7da6ce5STakashi Iwai }
3006a7da6ce5STakashi Iwai 
30071da177e4SLinus Torvalds 
3008352f7f91STakashi Iwai /*
3009352f7f91STakashi Iwai  * input source mux
3010352f7f91STakashi Iwai  */
3011352f7f91STakashi Iwai 
3012c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */
3013c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx)
3014352f7f91STakashi Iwai {
3015352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3016b56fa1edSDavid Henningsson 	if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) {
3017b56fa1edSDavid Henningsson 		snd_BUG();
3018b56fa1edSDavid Henningsson 		return NULL;
3019b56fa1edSDavid Henningsson 	}
3020352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
3021352f7f91STakashi Iwai 		adc_idx = spec->dyn_adc_idx[imux_idx];
3022d3d982f7SDavid Henningsson 	if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) {
3023b56fa1edSDavid Henningsson 		snd_BUG();
3024b56fa1edSDavid Henningsson 		return NULL;
3025b56fa1edSDavid Henningsson 	}
3026c697b716STakashi Iwai 	return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]);
302797ec558aSTakashi Iwai }
3028352f7f91STakashi Iwai 
3029352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
3030352f7f91STakashi Iwai 		      unsigned int idx);
3031352f7f91STakashi Iwai 
3032352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol,
3033352f7f91STakashi Iwai 			 struct snd_ctl_elem_info *uinfo)
3034352f7f91STakashi Iwai {
3035352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3036352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3037352f7f91STakashi Iwai 	return snd_hda_input_mux_info(&spec->input_mux, uinfo);
3038352f7f91STakashi Iwai }
3039352f7f91STakashi Iwai 
3040352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol,
3041352f7f91STakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
3042352f7f91STakashi Iwai {
3043352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3044352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
30452a8d5391STakashi Iwai 	/* the ctls are created at once with multiple counts */
30462a8d5391STakashi Iwai 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3047352f7f91STakashi Iwai 
3048352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
30491da177e4SLinus Torvalds 	return 0;
30501da177e4SLinus Torvalds }
30511da177e4SLinus Torvalds 
3052352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol,
3053352f7f91STakashi Iwai 			    struct snd_ctl_elem_value *ucontrol)
30541da177e4SLinus Torvalds {
3055352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
30562a8d5391STakashi Iwai 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3057352f7f91STakashi Iwai 	return mux_select(codec, adc_idx,
3058352f7f91STakashi Iwai 			  ucontrol->value.enumerated.item[0]);
3059352f7f91STakashi Iwai }
3060352f7f91STakashi Iwai 
3061352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = {
30621da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3063352f7f91STakashi Iwai 	.name = "Input Source",
3064352f7f91STakashi Iwai 	.info = mux_enum_info,
3065352f7f91STakashi Iwai 	.get = mux_enum_get,
3066352f7f91STakashi Iwai 	.put = mux_enum_put,
30671da177e4SLinus Torvalds };
3068071c73adSTakashi Iwai 
306947d46abbSTakashi Iwai /*
307047d46abbSTakashi Iwai  * capture volume and capture switch ctls
307147d46abbSTakashi Iwai  */
307247d46abbSTakashi Iwai 
3073352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol,
3074352f7f91STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol);
3075071c73adSTakashi Iwai 
307647d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */
3077352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol,
3078352f7f91STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol,
3079352f7f91STakashi Iwai 			  put_call_t func, int type)
3080352f7f91STakashi Iwai {
3081352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3082352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3083352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
3084352f7f91STakashi Iwai 	struct nid_path *path;
3085352f7f91STakashi Iwai 	int i, adc_idx, err = 0;
3086071c73adSTakashi Iwai 
3087352f7f91STakashi Iwai 	imux = &spec->input_mux;
3088a053d1e3SDavid Henningsson 	adc_idx = kcontrol->id.index;
3089352f7f91STakashi Iwai 	mutex_lock(&codec->control_mutex);
309047d46abbSTakashi Iwai 	/* we use the cache-only update at first since multiple input paths
309147d46abbSTakashi Iwai 	 * may shared the same amp; by updating only caches, the redundant
309247d46abbSTakashi Iwai 	 * writes to hardware can be reduced.
309347d46abbSTakashi Iwai 	 */
3094352f7f91STakashi Iwai 	codec->cached_write = 1;
3095352f7f91STakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
3096c697b716STakashi Iwai 		path = get_input_path(codec, adc_idx, i);
3097c697b716STakashi Iwai 		if (!path || !path->ctls[type])
3098352f7f91STakashi Iwai 			continue;
3099352f7f91STakashi Iwai 		kcontrol->private_value = path->ctls[type];
3100352f7f91STakashi Iwai 		err = func(kcontrol, ucontrol);
3101352f7f91STakashi Iwai 		if (err < 0)
3102352f7f91STakashi Iwai 			goto error;
3103352f7f91STakashi Iwai 	}
3104352f7f91STakashi Iwai  error:
3105352f7f91STakashi Iwai 	codec->cached_write = 0;
3106352f7f91STakashi Iwai 	mutex_unlock(&codec->control_mutex);
3107dc870f38STakashi Iwai 	snd_hda_codec_flush_cache(codec); /* flush the updates */
3108352f7f91STakashi Iwai 	if (err >= 0 && spec->cap_sync_hook)
3109a90229e0STakashi Iwai 		spec->cap_sync_hook(codec, ucontrol);
3110352f7f91STakashi Iwai 	return err;
3111352f7f91STakashi Iwai }
3112352f7f91STakashi Iwai 
3113352f7f91STakashi Iwai /* capture volume ctl callbacks */
3114352f7f91STakashi Iwai #define cap_vol_info		snd_hda_mixer_amp_volume_info
3115352f7f91STakashi Iwai #define cap_vol_get		snd_hda_mixer_amp_volume_get
3116352f7f91STakashi Iwai #define cap_vol_tlv		snd_hda_mixer_amp_tlv
3117352f7f91STakashi Iwai 
3118352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol,
3119352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
3120352f7f91STakashi Iwai {
3121352f7f91STakashi Iwai 	return cap_put_caller(kcontrol, ucontrol,
3122352f7f91STakashi Iwai 			      snd_hda_mixer_amp_volume_put,
3123352f7f91STakashi Iwai 			      NID_PATH_VOL_CTL);
3124352f7f91STakashi Iwai }
3125352f7f91STakashi Iwai 
3126352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = {
3127352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3128352f7f91STakashi Iwai 	.name = "Capture Volume",
3129352f7f91STakashi Iwai 	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
3130352f7f91STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_READ |
3131352f7f91STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
3132352f7f91STakashi Iwai 	.info = cap_vol_info,
3133352f7f91STakashi Iwai 	.get = cap_vol_get,
3134352f7f91STakashi Iwai 	.put = cap_vol_put,
3135352f7f91STakashi Iwai 	.tlv = { .c = cap_vol_tlv },
3136352f7f91STakashi Iwai };
3137352f7f91STakashi Iwai 
3138352f7f91STakashi Iwai /* capture switch ctl callbacks */
3139352f7f91STakashi Iwai #define cap_sw_info		snd_ctl_boolean_stereo_info
3140352f7f91STakashi Iwai #define cap_sw_get		snd_hda_mixer_amp_switch_get
3141352f7f91STakashi Iwai 
3142352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol,
3143352f7f91STakashi Iwai 		      struct snd_ctl_elem_value *ucontrol)
3144352f7f91STakashi Iwai {
3145a90229e0STakashi Iwai 	return cap_put_caller(kcontrol, ucontrol,
3146352f7f91STakashi Iwai 			      snd_hda_mixer_amp_switch_put,
3147352f7f91STakashi Iwai 			      NID_PATH_MUTE_CTL);
3148352f7f91STakashi Iwai }
3149352f7f91STakashi Iwai 
3150352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = {
3151352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3152352f7f91STakashi Iwai 	.name = "Capture Switch",
3153352f7f91STakashi Iwai 	.info = cap_sw_info,
3154352f7f91STakashi Iwai 	.get = cap_sw_get,
3155352f7f91STakashi Iwai 	.put = cap_sw_put,
3156352f7f91STakashi Iwai };
3157352f7f91STakashi Iwai 
3158352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path)
3159352f7f91STakashi Iwai {
3160352f7f91STakashi Iwai 	hda_nid_t nid;
3161352f7f91STakashi Iwai 	int i, depth;
3162352f7f91STakashi Iwai 
3163352f7f91STakashi Iwai 	path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0;
3164352f7f91STakashi Iwai 	for (depth = 0; depth < 3; depth++) {
3165352f7f91STakashi Iwai 		if (depth >= path->depth)
3166352f7f91STakashi Iwai 			return -EINVAL;
3167352f7f91STakashi Iwai 		i = path->depth - depth - 1;
3168352f7f91STakashi Iwai 		nid = path->path[i];
3169352f7f91STakashi Iwai 		if (!path->ctls[NID_PATH_VOL_CTL]) {
3170352f7f91STakashi Iwai 			if (nid_has_volume(codec, nid, HDA_OUTPUT))
3171352f7f91STakashi Iwai 				path->ctls[NID_PATH_VOL_CTL] =
3172352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
3173352f7f91STakashi Iwai 			else if (nid_has_volume(codec, nid, HDA_INPUT)) {
3174352f7f91STakashi Iwai 				int idx = path->idx[i];
3175352f7f91STakashi Iwai 				if (!depth && codec->single_adc_amp)
3176352f7f91STakashi Iwai 					idx = 0;
3177352f7f91STakashi Iwai 				path->ctls[NID_PATH_VOL_CTL] =
3178352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
3179352f7f91STakashi Iwai 			}
3180352f7f91STakashi Iwai 		}
3181352f7f91STakashi Iwai 		if (!path->ctls[NID_PATH_MUTE_CTL]) {
3182352f7f91STakashi Iwai 			if (nid_has_mute(codec, nid, HDA_OUTPUT))
3183352f7f91STakashi Iwai 				path->ctls[NID_PATH_MUTE_CTL] =
3184352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
3185352f7f91STakashi Iwai 			else if (nid_has_mute(codec, nid, HDA_INPUT)) {
3186352f7f91STakashi Iwai 				int idx = path->idx[i];
3187352f7f91STakashi Iwai 				if (!depth && codec->single_adc_amp)
3188352f7f91STakashi Iwai 					idx = 0;
3189352f7f91STakashi Iwai 				path->ctls[NID_PATH_MUTE_CTL] =
3190352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
3191352f7f91STakashi Iwai 			}
3192352f7f91STakashi Iwai 		}
3193352f7f91STakashi Iwai 	}
3194352f7f91STakashi Iwai 	return 0;
3195352f7f91STakashi Iwai }
3196352f7f91STakashi Iwai 
3197352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid)
3198352f7f91STakashi Iwai {
3199352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3200352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
3201352f7f91STakashi Iwai 	unsigned int val;
3202352f7f91STakashi Iwai 	int i;
3203352f7f91STakashi Iwai 
3204352f7f91STakashi Iwai 	if (!spec->inv_dmic_split)
3205352f7f91STakashi Iwai 		return false;
3206352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
3207352f7f91STakashi Iwai 		if (cfg->inputs[i].pin != nid)
3208352f7f91STakashi Iwai 			continue;
3209352f7f91STakashi Iwai 		if (cfg->inputs[i].type != AUTO_PIN_MIC)
3210352f7f91STakashi Iwai 			return false;
3211352f7f91STakashi Iwai 		val = snd_hda_codec_get_pincfg(codec, nid);
3212352f7f91STakashi Iwai 		return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT;
3213352f7f91STakashi Iwai 	}
3214352f7f91STakashi Iwai 	return false;
3215352f7f91STakashi Iwai }
3216352f7f91STakashi Iwai 
3217a90229e0STakashi Iwai /* capture switch put callback for a single control with hook call */
3218a35bd1e3STakashi Iwai static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
3219a35bd1e3STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
3220a35bd1e3STakashi Iwai {
3221a35bd1e3STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3222a35bd1e3STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3223a35bd1e3STakashi Iwai 	int ret;
3224a35bd1e3STakashi Iwai 
3225a35bd1e3STakashi Iwai 	ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3226a35bd1e3STakashi Iwai 	if (ret < 0)
3227a35bd1e3STakashi Iwai 		return ret;
3228a35bd1e3STakashi Iwai 
3229a90229e0STakashi Iwai 	if (spec->cap_sync_hook)
3230a90229e0STakashi Iwai 		spec->cap_sync_hook(codec, ucontrol);
3231a35bd1e3STakashi Iwai 
3232a35bd1e3STakashi Iwai 	return ret;
3233a35bd1e3STakashi Iwai }
3234a35bd1e3STakashi Iwai 
3235352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
3236352f7f91STakashi Iwai 			      int idx, bool is_switch, unsigned int ctl,
3237352f7f91STakashi Iwai 			      bool inv_dmic)
3238352f7f91STakashi Iwai {
3239352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3240352f7f91STakashi Iwai 	char tmpname[44];
3241352f7f91STakashi Iwai 	int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
3242352f7f91STakashi Iwai 	const char *sfx = is_switch ? "Switch" : "Volume";
3243352f7f91STakashi Iwai 	unsigned int chs = inv_dmic ? 1 : 3;
3244a35bd1e3STakashi Iwai 	struct snd_kcontrol_new *knew;
3245352f7f91STakashi Iwai 
3246352f7f91STakashi Iwai 	if (!ctl)
3247352f7f91STakashi Iwai 		return 0;
3248352f7f91STakashi Iwai 
3249352f7f91STakashi Iwai 	if (label)
3250352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
3251352f7f91STakashi Iwai 			 "%s Capture %s", label, sfx);
3252352f7f91STakashi Iwai 	else
3253352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
3254352f7f91STakashi Iwai 			 "Capture %s", sfx);
3255a35bd1e3STakashi Iwai 	knew = add_control(spec, type, tmpname, idx,
3256352f7f91STakashi Iwai 			   amp_val_replace_channels(ctl, chs));
3257a35bd1e3STakashi Iwai 	if (!knew)
3258a35bd1e3STakashi Iwai 		return -ENOMEM;
3259a90229e0STakashi Iwai 	if (is_switch)
3260a35bd1e3STakashi Iwai 		knew->put = cap_single_sw_put;
3261a35bd1e3STakashi Iwai 	if (!inv_dmic)
3262a35bd1e3STakashi Iwai 		return 0;
3263352f7f91STakashi Iwai 
3264352f7f91STakashi Iwai 	/* Make independent right kcontrol */
3265352f7f91STakashi Iwai 	if (label)
3266352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
3267352f7f91STakashi Iwai 			 "Inverted %s Capture %s", label, sfx);
3268352f7f91STakashi Iwai 	else
3269352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
3270352f7f91STakashi Iwai 			 "Inverted Capture %s", sfx);
3271a35bd1e3STakashi Iwai 	knew = add_control(spec, type, tmpname, idx,
3272352f7f91STakashi Iwai 			   amp_val_replace_channels(ctl, 2));
3273a35bd1e3STakashi Iwai 	if (!knew)
3274a35bd1e3STakashi Iwai 		return -ENOMEM;
3275a90229e0STakashi Iwai 	if (is_switch)
3276a35bd1e3STakashi Iwai 		knew->put = cap_single_sw_put;
3277a35bd1e3STakashi Iwai 	return 0;
3278352f7f91STakashi Iwai }
3279352f7f91STakashi Iwai 
3280352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */
3281352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx,
3282352f7f91STakashi Iwai 				     unsigned int vol_ctl, unsigned int sw_ctl,
3283352f7f91STakashi Iwai 				     bool inv_dmic)
3284352f7f91STakashi Iwai {
3285352f7f91STakashi Iwai 	int err;
3286352f7f91STakashi Iwai 	err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic);
3287352f7f91STakashi Iwai 	if (err < 0)
3288352f7f91STakashi Iwai 		return err;
3289352f7f91STakashi Iwai 	err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic);
3290071c73adSTakashi Iwai 	if (err < 0)
3291071c73adSTakashi Iwai 		return err;
3292071c73adSTakashi Iwai 	return 0;
32931da177e4SLinus Torvalds }
3294071c73adSTakashi Iwai 
3295352f7f91STakashi Iwai /* create bound capture volume and switch controls */
3296352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
3297352f7f91STakashi Iwai 				   unsigned int vol_ctl, unsigned int sw_ctl)
3298352f7f91STakashi Iwai {
3299352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3300352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew;
3301352f7f91STakashi Iwai 
3302352f7f91STakashi Iwai 	if (vol_ctl) {
330312c93df6STakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp);
3304352f7f91STakashi Iwai 		if (!knew)
3305352f7f91STakashi Iwai 			return -ENOMEM;
3306352f7f91STakashi Iwai 		knew->index = idx;
3307352f7f91STakashi Iwai 		knew->private_value = vol_ctl;
3308352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
3309352f7f91STakashi Iwai 	}
3310352f7f91STakashi Iwai 	if (sw_ctl) {
331112c93df6STakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp);
3312352f7f91STakashi Iwai 		if (!knew)
3313352f7f91STakashi Iwai 			return -ENOMEM;
3314352f7f91STakashi Iwai 		knew->index = idx;
3315352f7f91STakashi Iwai 		knew->private_value = sw_ctl;
3316352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
3317352f7f91STakashi Iwai 	}
3318352f7f91STakashi Iwai 	return 0;
3319352f7f91STakashi Iwai }
3320352f7f91STakashi Iwai 
3321352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */
3322352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type)
3323352f7f91STakashi Iwai {
3324352f7f91STakashi Iwai 	struct nid_path *path;
3325352f7f91STakashi Iwai 	unsigned int ctl;
3326352f7f91STakashi Iwai 	int i;
3327352f7f91STakashi Iwai 
3328c697b716STakashi Iwai 	path = get_input_path(codec, 0, idx);
3329352f7f91STakashi Iwai 	if (!path)
3330352f7f91STakashi Iwai 		return 0;
3331352f7f91STakashi Iwai 	ctl = path->ctls[type];
3332352f7f91STakashi Iwai 	if (!ctl)
3333352f7f91STakashi Iwai 		return 0;
3334352f7f91STakashi Iwai 	for (i = 0; i < idx - 1; i++) {
3335c697b716STakashi Iwai 		path = get_input_path(codec, 0, i);
3336352f7f91STakashi Iwai 		if (path && path->ctls[type] == ctl)
3337352f7f91STakashi Iwai 			return 0;
3338352f7f91STakashi Iwai 	}
3339352f7f91STakashi Iwai 	return ctl;
3340352f7f91STakashi Iwai }
3341352f7f91STakashi Iwai 
3342352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */
3343352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec)
3344352f7f91STakashi Iwai {
3345352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3346352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3347c970042cSTakashi Iwai 	int i, err, type;
3348352f7f91STakashi Iwai 
3349352f7f91STakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
3350352f7f91STakashi Iwai 		bool inv_dmic;
3351c970042cSTakashi Iwai 		int idx;
33529dba205bSTakashi Iwai 
3353c970042cSTakashi Iwai 		idx = imux->items[i].index;
3354c970042cSTakashi Iwai 		if (idx >= spec->autocfg.num_inputs)
33559dba205bSTakashi Iwai 			continue;
3356352f7f91STakashi Iwai 		inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]);
3357352f7f91STakashi Iwai 
3358352f7f91STakashi Iwai 		for (type = 0; type < 2; type++) {
3359c970042cSTakashi Iwai 			err = add_single_cap_ctl(codec,
3360c970042cSTakashi Iwai 						 spec->input_labels[idx],
3361c970042cSTakashi Iwai 						 spec->input_label_idxs[idx],
3362c970042cSTakashi Iwai 						 type,
3363352f7f91STakashi Iwai 						 get_first_cap_ctl(codec, i, type),
3364352f7f91STakashi Iwai 						 inv_dmic);
3365d13bd412STakashi Iwai 			if (err < 0)
3366071c73adSTakashi Iwai 				return err;
3367352f7f91STakashi Iwai 		}
3368352f7f91STakashi Iwai 	}
3369071c73adSTakashi Iwai 	return 0;
3370352f7f91STakashi Iwai }
3371071c73adSTakashi Iwai 
3372352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec)
3373352f7f91STakashi Iwai {
3374352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3375352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3376352f7f91STakashi Iwai 	int i, n, nums, err;
3377352f7f91STakashi Iwai 
3378352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
3379352f7f91STakashi Iwai 		nums = 1;
3380352f7f91STakashi Iwai 	else
3381352f7f91STakashi Iwai 		nums = spec->num_adc_nids;
3382352f7f91STakashi Iwai 
3383352f7f91STakashi Iwai 	if (!spec->auto_mic && imux->num_items > 1) {
3384352f7f91STakashi Iwai 		struct snd_kcontrol_new *knew;
3385624d914dSTakashi Iwai 		const char *name;
3386624d914dSTakashi Iwai 		name = nums > 1 ? "Input Source" : "Capture Source";
3387624d914dSTakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp);
3388352f7f91STakashi Iwai 		if (!knew)
3389352f7f91STakashi Iwai 			return -ENOMEM;
3390352f7f91STakashi Iwai 		knew->count = nums;
3391352f7f91STakashi Iwai 	}
3392352f7f91STakashi Iwai 
3393352f7f91STakashi Iwai 	for (n = 0; n < nums; n++) {
3394352f7f91STakashi Iwai 		bool multi = false;
339599a5592dSDavid Henningsson 		bool multi_cap_vol = spec->multi_cap_vol;
3396352f7f91STakashi Iwai 		bool inv_dmic = false;
3397352f7f91STakashi Iwai 		int vol, sw;
3398352f7f91STakashi Iwai 
3399352f7f91STakashi Iwai 		vol = sw = 0;
3400352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
3401352f7f91STakashi Iwai 			struct nid_path *path;
3402c697b716STakashi Iwai 			path = get_input_path(codec, n, i);
3403352f7f91STakashi Iwai 			if (!path)
3404352f7f91STakashi Iwai 				continue;
3405352f7f91STakashi Iwai 			parse_capvol_in_path(codec, path);
3406352f7f91STakashi Iwai 			if (!vol)
3407352f7f91STakashi Iwai 				vol = path->ctls[NID_PATH_VOL_CTL];
340899a5592dSDavid Henningsson 			else if (vol != path->ctls[NID_PATH_VOL_CTL]) {
3409352f7f91STakashi Iwai 				multi = true;
341099a5592dSDavid Henningsson 				if (!same_amp_caps(codec, vol,
341199a5592dSDavid Henningsson 				    path->ctls[NID_PATH_VOL_CTL], HDA_INPUT))
341299a5592dSDavid Henningsson 					multi_cap_vol = true;
341399a5592dSDavid Henningsson 			}
3414352f7f91STakashi Iwai 			if (!sw)
3415352f7f91STakashi Iwai 				sw = path->ctls[NID_PATH_MUTE_CTL];
341699a5592dSDavid Henningsson 			else if (sw != path->ctls[NID_PATH_MUTE_CTL]) {
3417352f7f91STakashi Iwai 				multi = true;
341899a5592dSDavid Henningsson 				if (!same_amp_caps(codec, sw,
341999a5592dSDavid Henningsson 				    path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT))
342099a5592dSDavid Henningsson 					multi_cap_vol = true;
342199a5592dSDavid Henningsson 			}
3422352f7f91STakashi Iwai 			if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
3423352f7f91STakashi Iwai 				inv_dmic = true;
3424352f7f91STakashi Iwai 		}
3425352f7f91STakashi Iwai 
3426352f7f91STakashi Iwai 		if (!multi)
3427352f7f91STakashi Iwai 			err = create_single_cap_vol_ctl(codec, n, vol, sw,
3428352f7f91STakashi Iwai 							inv_dmic);
342999a5592dSDavid Henningsson 		else if (!multi_cap_vol)
3430352f7f91STakashi Iwai 			err = create_bind_cap_vol_ctl(codec, n, vol, sw);
3431352f7f91STakashi Iwai 		else
3432352f7f91STakashi Iwai 			err = create_multi_cap_vol_ctl(codec);
3433d13bd412STakashi Iwai 		if (err < 0)
3434071c73adSTakashi Iwai 			return err;
3435071c73adSTakashi Iwai 	}
3436071c73adSTakashi Iwai 
34371da177e4SLinus Torvalds 	return 0;
34381da177e4SLinus Torvalds }
34391da177e4SLinus Torvalds 
3440352f7f91STakashi Iwai /*
3441352f7f91STakashi Iwai  * add mic boosts if needed
3442352f7f91STakashi Iwai  */
34436f7c83afSTakashi Iwai 
34446f7c83afSTakashi Iwai /* check whether the given amp is feasible as a boost volume */
34456f7c83afSTakashi Iwai static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid,
34466f7c83afSTakashi Iwai 			    int dir, int idx)
34476f7c83afSTakashi Iwai {
34486f7c83afSTakashi Iwai 	unsigned int step;
34496f7c83afSTakashi Iwai 
34506f7c83afSTakashi Iwai 	if (!nid_has_volume(codec, nid, dir) ||
34516f7c83afSTakashi Iwai 	    is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
34526f7c83afSTakashi Iwai 	    is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
34536f7c83afSTakashi Iwai 		return false;
34546f7c83afSTakashi Iwai 
34556f7c83afSTakashi Iwai 	step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE)
34566f7c83afSTakashi Iwai 		>> AC_AMPCAP_STEP_SIZE_SHIFT;
34576f7c83afSTakashi Iwai 	if (step < 0x20)
34586f7c83afSTakashi Iwai 		return false;
34596f7c83afSTakashi Iwai 	return true;
34606f7c83afSTakashi Iwai }
34616f7c83afSTakashi Iwai 
34626f7c83afSTakashi Iwai /* look for a boost amp in a widget close to the pin */
34636f7c83afSTakashi Iwai static unsigned int look_for_boost_amp(struct hda_codec *codec,
34646f7c83afSTakashi Iwai 				       struct nid_path *path)
34656f7c83afSTakashi Iwai {
34666f7c83afSTakashi Iwai 	unsigned int val = 0;
34676f7c83afSTakashi Iwai 	hda_nid_t nid;
34686f7c83afSTakashi Iwai 	int depth;
34696f7c83afSTakashi Iwai 
34706f7c83afSTakashi Iwai 	for (depth = 0; depth < 3; depth++) {
34716f7c83afSTakashi Iwai 		if (depth >= path->depth - 1)
34726f7c83afSTakashi Iwai 			break;
34736f7c83afSTakashi Iwai 		nid = path->path[depth];
34746f7c83afSTakashi Iwai 		if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) {
34756f7c83afSTakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
34766f7c83afSTakashi Iwai 			break;
34776f7c83afSTakashi Iwai 		} else if (check_boost_vol(codec, nid, HDA_INPUT,
34786f7c83afSTakashi Iwai 					   path->idx[depth])) {
34796f7c83afSTakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth],
34806f7c83afSTakashi Iwai 						  HDA_INPUT);
34816f7c83afSTakashi Iwai 			break;
34826f7c83afSTakashi Iwai 		}
34836f7c83afSTakashi Iwai 	}
34846f7c83afSTakashi Iwai 
34856f7c83afSTakashi Iwai 	return val;
34866f7c83afSTakashi Iwai }
34876f7c83afSTakashi Iwai 
3488352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec)
3489352f7f91STakashi Iwai {
3490352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3491352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
34926f7c83afSTakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3493a35bd1e3STakashi Iwai 	int i;
3494352f7f91STakashi Iwai 
34956f7c83afSTakashi Iwai 	if (!spec->num_adc_nids)
34966f7c83afSTakashi Iwai 		return 0;
34976f7c83afSTakashi Iwai 
34986f7c83afSTakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
3499352f7f91STakashi Iwai 		struct nid_path *path;
3500352f7f91STakashi Iwai 		unsigned int val;
35016f7c83afSTakashi Iwai 		int idx;
35026f7c83afSTakashi Iwai 		char boost_label[44];
3503352f7f91STakashi Iwai 
35046f7c83afSTakashi Iwai 		idx = imux->items[i].index;
35056f7c83afSTakashi Iwai 		if (idx >= imux->num_items)
350602aba550SDavid Henningsson 			continue;
350702aba550SDavid Henningsson 
35086f7c83afSTakashi Iwai 		/* check only line-in and mic pins */
35091799cdd5STakashi Iwai 		if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
35106f7c83afSTakashi Iwai 			continue;
35116f7c83afSTakashi Iwai 
35126f7c83afSTakashi Iwai 		path = get_input_path(codec, 0, i);
35136f7c83afSTakashi Iwai 		if (!path)
35146f7c83afSTakashi Iwai 			continue;
35156f7c83afSTakashi Iwai 
35166f7c83afSTakashi Iwai 		val = look_for_boost_amp(codec, path);
35176f7c83afSTakashi Iwai 		if (!val)
35186f7c83afSTakashi Iwai 			continue;
35196f7c83afSTakashi Iwai 
35206f7c83afSTakashi Iwai 		/* create a boost control */
3521352f7f91STakashi Iwai 		snprintf(boost_label, sizeof(boost_label),
35226f7c83afSTakashi Iwai 			 "%s Boost Volume", spec->input_labels[idx]);
3523a35bd1e3STakashi Iwai 		if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label,
3524a35bd1e3STakashi Iwai 				 spec->input_label_idxs[idx], val))
3525a35bd1e3STakashi Iwai 			return -ENOMEM;
3526352f7f91STakashi Iwai 
3527352f7f91STakashi Iwai 		path->ctls[NID_PATH_BOOST_CTL] = val;
3528352f7f91STakashi Iwai 	}
3529352f7f91STakashi Iwai 	return 0;
3530352f7f91STakashi Iwai }
3531352f7f91STakashi Iwai 
3532352f7f91STakashi Iwai /*
3533352f7f91STakashi Iwai  * parse digital I/Os and set up NIDs in BIOS auto-parse mode
3534352f7f91STakashi Iwai  */
3535352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec)
3536352f7f91STakashi Iwai {
3537352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
35380c8c0f56STakashi Iwai 	struct nid_path *path;
3539352f7f91STakashi Iwai 	int i, nums;
35402c12c30dSTakashi Iwai 	hda_nid_t dig_nid, pin;
3541352f7f91STakashi Iwai 
3542352f7f91STakashi Iwai 	/* support multiple SPDIFs; the secondary is set up as a slave */
3543352f7f91STakashi Iwai 	nums = 0;
3544352f7f91STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++) {
35452c12c30dSTakashi Iwai 		pin = spec->autocfg.dig_out_pins[i];
3546352f7f91STakashi Iwai 		dig_nid = look_for_dac(codec, pin, true);
3547352f7f91STakashi Iwai 		if (!dig_nid)
3548352f7f91STakashi Iwai 			continue;
35493ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
35500c8c0f56STakashi Iwai 		if (!path)
3551352f7f91STakashi Iwai 			continue;
35520c8c0f56STakashi Iwai 		print_nid_path("digout", path);
3553e1284af7STakashi Iwai 		path->active = true;
3554196c1766STakashi Iwai 		spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
35552c12c30dSTakashi Iwai 		set_pin_target(codec, pin, PIN_OUT, false);
3556352f7f91STakashi Iwai 		if (!nums) {
3557352f7f91STakashi Iwai 			spec->multiout.dig_out_nid = dig_nid;
3558352f7f91STakashi Iwai 			spec->dig_out_type = spec->autocfg.dig_out_type[0];
3559352f7f91STakashi Iwai 		} else {
3560352f7f91STakashi Iwai 			spec->multiout.slave_dig_outs = spec->slave_dig_outs;
3561352f7f91STakashi Iwai 			if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
3562352f7f91STakashi Iwai 			break;
3563352f7f91STakashi Iwai 			spec->slave_dig_outs[nums - 1] = dig_nid;
3564352f7f91STakashi Iwai 		}
3565352f7f91STakashi Iwai 		nums++;
3566352f7f91STakashi Iwai 	}
3567352f7f91STakashi Iwai 
3568352f7f91STakashi Iwai 	if (spec->autocfg.dig_in_pin) {
35692c12c30dSTakashi Iwai 		pin = spec->autocfg.dig_in_pin;
3570352f7f91STakashi Iwai 		dig_nid = codec->start_nid;
3571352f7f91STakashi Iwai 		for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
3572352f7f91STakashi Iwai 			unsigned int wcaps = get_wcaps(codec, dig_nid);
3573352f7f91STakashi Iwai 			if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
3574352f7f91STakashi Iwai 				continue;
3575352f7f91STakashi Iwai 			if (!(wcaps & AC_WCAP_DIGITAL))
3576352f7f91STakashi Iwai 				continue;
35772c12c30dSTakashi Iwai 			path = snd_hda_add_new_path(codec, pin, dig_nid, 0);
3578352f7f91STakashi Iwai 			if (path) {
35790c8c0f56STakashi Iwai 				print_nid_path("digin", path);
3580352f7f91STakashi Iwai 				path->active = true;
3581352f7f91STakashi Iwai 				spec->dig_in_nid = dig_nid;
35822430d7b7STakashi Iwai 				spec->digin_path = snd_hda_get_path_idx(codec, path);
35832c12c30dSTakashi Iwai 				set_pin_target(codec, pin, PIN_IN, false);
3584352f7f91STakashi Iwai 				break;
3585352f7f91STakashi Iwai 			}
3586352f7f91STakashi Iwai 		}
3587352f7f91STakashi Iwai 	}
3588352f7f91STakashi Iwai }
3589352f7f91STakashi Iwai 
35901da177e4SLinus Torvalds 
35911da177e4SLinus Torvalds /*
3592352f7f91STakashi Iwai  * input MUX handling
35931da177e4SLinus Torvalds  */
35941da177e4SLinus Torvalds 
3595352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur);
3596352f7f91STakashi Iwai 
3597352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */
3598352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
3599352f7f91STakashi Iwai 		      unsigned int idx)
3600352f7f91STakashi Iwai {
3601352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3602352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
360355196fffSTakashi Iwai 	struct nid_path *old_path, *path;
3604352f7f91STakashi Iwai 
3605352f7f91STakashi Iwai 	imux = &spec->input_mux;
3606352f7f91STakashi Iwai 	if (!imux->num_items)
36071da177e4SLinus Torvalds 		return 0;
36081da177e4SLinus Torvalds 
3609352f7f91STakashi Iwai 	if (idx >= imux->num_items)
3610352f7f91STakashi Iwai 		idx = imux->num_items - 1;
3611352f7f91STakashi Iwai 	if (spec->cur_mux[adc_idx] == idx)
3612352f7f91STakashi Iwai 		return 0;
3613352f7f91STakashi Iwai 
361455196fffSTakashi Iwai 	old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]);
361555196fffSTakashi Iwai 	if (!old_path)
3616352f7f91STakashi Iwai 		return 0;
361755196fffSTakashi Iwai 	if (old_path->active)
361855196fffSTakashi Iwai 		snd_hda_activate_path(codec, old_path, false, false);
3619352f7f91STakashi Iwai 
3620352f7f91STakashi Iwai 	spec->cur_mux[adc_idx] = idx;
3621352f7f91STakashi Iwai 
3622967303daSTakashi Iwai 	if (spec->hp_mic)
3623967303daSTakashi Iwai 		update_hp_mic(codec, adc_idx, false);
3624352f7f91STakashi Iwai 
3625352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
3626352f7f91STakashi Iwai 		dyn_adc_pcm_resetup(codec, idx);
3627352f7f91STakashi Iwai 
3628c697b716STakashi Iwai 	path = get_input_path(codec, adc_idx, idx);
3629352f7f91STakashi Iwai 	if (!path)
3630352f7f91STakashi Iwai 		return 0;
3631352f7f91STakashi Iwai 	if (path->active)
3632352f7f91STakashi Iwai 		return 0;
3633352f7f91STakashi Iwai 	snd_hda_activate_path(codec, path, true, false);
3634352f7f91STakashi Iwai 	if (spec->cap_sync_hook)
3635a90229e0STakashi Iwai 		spec->cap_sync_hook(codec, NULL);
363655196fffSTakashi Iwai 	path_power_down_sync(codec, old_path);
36371da177e4SLinus Torvalds 	return 1;
36381da177e4SLinus Torvalds }
36391da177e4SLinus Torvalds 
36401da177e4SLinus Torvalds 
36411da177e4SLinus Torvalds /*
3642352f7f91STakashi Iwai  * Jack detections for HP auto-mute and mic-switch
36431da177e4SLinus Torvalds  */
3644352f7f91STakashi Iwai 
3645352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */
3646352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
36471da177e4SLinus Torvalds {
3648352f7f91STakashi Iwai 	int i, present = 0;
36491da177e4SLinus Torvalds 
3650352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
3651352f7f91STakashi Iwai 		hda_nid_t nid = pins[i];
3652352f7f91STakashi Iwai 		if (!nid)
3653352f7f91STakashi Iwai 			break;
36540b4df931STakashi Iwai 		/* don't detect pins retasked as inputs */
36550b4df931STakashi Iwai 		if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
36560b4df931STakashi Iwai 			continue;
3657352f7f91STakashi Iwai 		present |= snd_hda_jack_detect(codec, nid);
36581da177e4SLinus Torvalds 	}
3659352f7f91STakashi Iwai 	return present;
36601da177e4SLinus Torvalds }
36611da177e4SLinus Torvalds 
3662352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */
3663352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
36642c12c30dSTakashi Iwai 			bool mute)
36651da177e4SLinus Torvalds {
3666352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3667352f7f91STakashi Iwai 	int i;
36681da177e4SLinus Torvalds 
3669352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
3670352f7f91STakashi Iwai 		hda_nid_t nid = pins[i];
3671967303daSTakashi Iwai 		unsigned int val, oldval;
3672352f7f91STakashi Iwai 		if (!nid)
3673352f7f91STakashi Iwai 			break;
3674967303daSTakashi Iwai 		oldval = snd_hda_codec_get_pin_target(codec, nid);
3675967303daSTakashi Iwai 		if (oldval & PIN_IN)
3676967303daSTakashi Iwai 			continue; /* no mute for inputs */
3677352f7f91STakashi Iwai 		/* don't reset VREF value in case it's controlling
3678352f7f91STakashi Iwai 		 * the amp (see alc861_fixup_asus_amp_vref_0f())
3679352f7f91STakashi Iwai 		 */
36802c12c30dSTakashi Iwai 		if (spec->keep_vref_in_automute)
3681967303daSTakashi Iwai 			val = oldval & ~PIN_HP;
36822c12c30dSTakashi Iwai 		else
3683352f7f91STakashi Iwai 			val = 0;
36842c12c30dSTakashi Iwai 		if (!mute)
3685967303daSTakashi Iwai 			val |= oldval;
36862c12c30dSTakashi Iwai 		/* here we call update_pin_ctl() so that the pinctl is changed
36872c12c30dSTakashi Iwai 		 * without changing the pinctl target value;
36882c12c30dSTakashi Iwai 		 * the original target value will be still referred at the
36892c12c30dSTakashi Iwai 		 * init / resume again
36902c12c30dSTakashi Iwai 		 */
36912c12c30dSTakashi Iwai 		update_pin_ctl(codec, nid, val);
3692d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, !mute);
3693352f7f91STakashi Iwai 	}
3694352f7f91STakashi Iwai }
36951da177e4SLinus Torvalds 
3696352f7f91STakashi Iwai /* Toggle outputs muting */
36975d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec)
3698352f7f91STakashi Iwai {
3699352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3700352f7f91STakashi Iwai 	int on;
3701352f7f91STakashi Iwai 
3702352f7f91STakashi Iwai 	/* Control HP pins/amps depending on master_mute state;
3703352f7f91STakashi Iwai 	 * in general, HP pins/amps control should be enabled in all cases,
3704352f7f91STakashi Iwai 	 * but currently set only for master_mute, just to be safe
3705352f7f91STakashi Iwai 	 */
3706352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
37072c12c30dSTakashi Iwai 		    spec->autocfg.hp_pins, spec->master_mute);
3708352f7f91STakashi Iwai 
3709352f7f91STakashi Iwai 	if (!spec->automute_speaker)
3710352f7f91STakashi Iwai 		on = 0;
3711352f7f91STakashi Iwai 	else
3712352f7f91STakashi Iwai 		on = spec->hp_jack_present | spec->line_jack_present;
3713352f7f91STakashi Iwai 	on |= spec->master_mute;
371447b9ddb8STakashi Iwai 	spec->speaker_muted = on;
3715352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
37162c12c30dSTakashi Iwai 		    spec->autocfg.speaker_pins, on);
3717352f7f91STakashi Iwai 
3718352f7f91STakashi Iwai 	/* toggle line-out mutes if needed, too */
3719352f7f91STakashi Iwai 	/* if LO is a copy of either HP or Speaker, don't need to handle it */
3720352f7f91STakashi Iwai 	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
3721352f7f91STakashi Iwai 	    spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
3722352f7f91STakashi Iwai 		return;
3723352f7f91STakashi Iwai 	if (!spec->automute_lo)
3724352f7f91STakashi Iwai 		on = 0;
3725352f7f91STakashi Iwai 	else
3726352f7f91STakashi Iwai 		on = spec->hp_jack_present;
3727352f7f91STakashi Iwai 	on |= spec->master_mute;
372847b9ddb8STakashi Iwai 	spec->line_out_muted = on;
3729352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
37302c12c30dSTakashi Iwai 		    spec->autocfg.line_out_pins, on);
3731352f7f91STakashi Iwai }
37325d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs);
3733352f7f91STakashi Iwai 
3734352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec)
3735352f7f91STakashi Iwai {
3736352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3737352f7f91STakashi Iwai 	if (spec->automute_hook)
3738352f7f91STakashi Iwai 		spec->automute_hook(codec);
3739352f7f91STakashi Iwai 	else
37405d550e15STakashi Iwai 		snd_hda_gen_update_outputs(codec);
3741352f7f91STakashi Iwai }
3742352f7f91STakashi Iwai 
3743352f7f91STakashi Iwai /* standard HP-automute helper */
37445d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
3745352f7f91STakashi Iwai {
3746352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
374792603c59STakashi Iwai 	hda_nid_t *pins = spec->autocfg.hp_pins;
374892603c59STakashi Iwai 	int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins);
3749352f7f91STakashi Iwai 
375092603c59STakashi Iwai 	/* No detection for the first HP jack during indep-HP mode */
375192603c59STakashi Iwai 	if (spec->indep_hp_enabled) {
375292603c59STakashi Iwai 		pins++;
375392603c59STakashi Iwai 		num_pins--;
375492603c59STakashi Iwai 	}
375592603c59STakashi Iwai 
375692603c59STakashi Iwai 	spec->hp_jack_present = detect_jacks(codec, num_pins, pins);
3757352f7f91STakashi Iwai 	if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
3758352f7f91STakashi Iwai 		return;
3759352f7f91STakashi Iwai 	call_update_outputs(codec);
3760352f7f91STakashi Iwai }
37615d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute);
3762352f7f91STakashi Iwai 
3763352f7f91STakashi Iwai /* standard line-out-automute helper */
37645d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
3765352f7f91STakashi Iwai {
3766352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3767352f7f91STakashi Iwai 
3768352f7f91STakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
3769352f7f91STakashi Iwai 		return;
3770352f7f91STakashi Iwai 	/* check LO jack only when it's different from HP */
3771352f7f91STakashi Iwai 	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
3772352f7f91STakashi Iwai 		return;
3773352f7f91STakashi Iwai 
3774352f7f91STakashi Iwai 	spec->line_jack_present =
3775352f7f91STakashi Iwai 		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
3776352f7f91STakashi Iwai 			     spec->autocfg.line_out_pins);
3777352f7f91STakashi Iwai 	if (!spec->automute_speaker || !spec->detect_lo)
3778352f7f91STakashi Iwai 		return;
3779352f7f91STakashi Iwai 	call_update_outputs(codec);
3780352f7f91STakashi Iwai }
37815d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute);
3782352f7f91STakashi Iwai 
3783352f7f91STakashi Iwai /* standard mic auto-switch helper */
37845d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack)
3785352f7f91STakashi Iwai {
3786352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3787352f7f91STakashi Iwai 	int i;
3788352f7f91STakashi Iwai 
3789352f7f91STakashi Iwai 	if (!spec->auto_mic)
3790352f7f91STakashi Iwai 		return;
3791352f7f91STakashi Iwai 
3792352f7f91STakashi Iwai 	for (i = spec->am_num_entries - 1; i > 0; i--) {
37930b4df931STakashi Iwai 		hda_nid_t pin = spec->am_entry[i].pin;
37940b4df931STakashi Iwai 		/* don't detect pins retasked as outputs */
37950b4df931STakashi Iwai 		if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
37960b4df931STakashi Iwai 			continue;
37970b4df931STakashi Iwai 		if (snd_hda_jack_detect(codec, pin)) {
3798352f7f91STakashi Iwai 			mux_select(codec, 0, spec->am_entry[i].idx);
3799352f7f91STakashi Iwai 			return;
3800352f7f91STakashi Iwai 		}
3801352f7f91STakashi Iwai 	}
3802352f7f91STakashi Iwai 	mux_select(codec, 0, spec->am_entry[0].idx);
38031da177e4SLinus Torvalds }
38045d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch);
38051da177e4SLinus Torvalds 
3806a5cc2509STakashi Iwai /* update jack retasking */
3807a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec)
3808a5cc2509STakashi Iwai {
3809a5cc2509STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3810a5cc2509STakashi Iwai 
38118ba955ceSTakashi Iwai 	update_hp_automute_hook(codec);
3812a5cc2509STakashi Iwai 	if (spec->line_automute_hook)
3813a5cc2509STakashi Iwai 		spec->line_automute_hook(codec, NULL);
3814a5cc2509STakashi Iwai 	else
3815a5cc2509STakashi Iwai 		snd_hda_gen_line_automute(codec, NULL);
3816a5cc2509STakashi Iwai 	if (spec->mic_autoswitch_hook)
3817a5cc2509STakashi Iwai 		spec->mic_autoswitch_hook(codec, NULL);
3818a5cc2509STakashi Iwai 	else
3819a5cc2509STakashi Iwai 		snd_hda_gen_mic_autoswitch(codec, NULL);
3820a5cc2509STakashi Iwai }
3821a5cc2509STakashi Iwai 
38221da177e4SLinus Torvalds /*
3823352f7f91STakashi Iwai  * Auto-Mute mode mixer enum support
38241da177e4SLinus Torvalds  */
3825352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol,
3826352f7f91STakashi Iwai 			      struct snd_ctl_elem_info *uinfo)
3827352f7f91STakashi Iwai {
3828352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3829352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3830352f7f91STakashi Iwai 	static const char * const texts3[] = {
3831352f7f91STakashi Iwai 		"Disabled", "Speaker Only", "Line Out+Speaker"
38321da177e4SLinus Torvalds 	};
38331da177e4SLinus Torvalds 
3834352f7f91STakashi Iwai 	if (spec->automute_speaker_possible && spec->automute_lo_possible)
3835352f7f91STakashi Iwai 		return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
3836352f7f91STakashi Iwai 	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
3837352f7f91STakashi Iwai }
3838352f7f91STakashi Iwai 
3839352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol,
3840352f7f91STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
3841352f7f91STakashi Iwai {
3842352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3843352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3844352f7f91STakashi Iwai 	unsigned int val = 0;
3845352f7f91STakashi Iwai 	if (spec->automute_speaker)
3846352f7f91STakashi Iwai 		val++;
3847352f7f91STakashi Iwai 	if (spec->automute_lo)
3848352f7f91STakashi Iwai 		val++;
3849352f7f91STakashi Iwai 
3850352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = val;
3851352f7f91STakashi Iwai 	return 0;
3852352f7f91STakashi Iwai }
3853352f7f91STakashi Iwai 
3854352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol,
3855352f7f91STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
3856352f7f91STakashi Iwai {
3857352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3858352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3859352f7f91STakashi Iwai 
3860352f7f91STakashi Iwai 	switch (ucontrol->value.enumerated.item[0]) {
3861352f7f91STakashi Iwai 	case 0:
3862352f7f91STakashi Iwai 		if (!spec->automute_speaker && !spec->automute_lo)
3863352f7f91STakashi Iwai 			return 0;
3864352f7f91STakashi Iwai 		spec->automute_speaker = 0;
3865352f7f91STakashi Iwai 		spec->automute_lo = 0;
3866352f7f91STakashi Iwai 		break;
3867352f7f91STakashi Iwai 	case 1:
3868352f7f91STakashi Iwai 		if (spec->automute_speaker_possible) {
3869352f7f91STakashi Iwai 			if (!spec->automute_lo && spec->automute_speaker)
3870352f7f91STakashi Iwai 				return 0;
3871352f7f91STakashi Iwai 			spec->automute_speaker = 1;
3872352f7f91STakashi Iwai 			spec->automute_lo = 0;
3873352f7f91STakashi Iwai 		} else if (spec->automute_lo_possible) {
3874352f7f91STakashi Iwai 			if (spec->automute_lo)
3875352f7f91STakashi Iwai 				return 0;
3876352f7f91STakashi Iwai 			spec->automute_lo = 1;
3877352f7f91STakashi Iwai 		} else
3878352f7f91STakashi Iwai 			return -EINVAL;
3879352f7f91STakashi Iwai 		break;
3880352f7f91STakashi Iwai 	case 2:
3881352f7f91STakashi Iwai 		if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
3882352f7f91STakashi Iwai 			return -EINVAL;
3883352f7f91STakashi Iwai 		if (spec->automute_speaker && spec->automute_lo)
3884352f7f91STakashi Iwai 			return 0;
3885352f7f91STakashi Iwai 		spec->automute_speaker = 1;
3886352f7f91STakashi Iwai 		spec->automute_lo = 1;
3887352f7f91STakashi Iwai 		break;
3888352f7f91STakashi Iwai 	default:
3889352f7f91STakashi Iwai 		return -EINVAL;
3890352f7f91STakashi Iwai 	}
3891352f7f91STakashi Iwai 	call_update_outputs(codec);
3892352f7f91STakashi Iwai 	return 1;
3893352f7f91STakashi Iwai }
3894352f7f91STakashi Iwai 
3895352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = {
3896352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3897352f7f91STakashi Iwai 	.name = "Auto-Mute Mode",
3898352f7f91STakashi Iwai 	.info = automute_mode_info,
3899352f7f91STakashi Iwai 	.get = automute_mode_get,
3900352f7f91STakashi Iwai 	.put = automute_mode_put,
3901352f7f91STakashi Iwai };
3902352f7f91STakashi Iwai 
3903352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec)
3904352f7f91STakashi Iwai {
3905352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3906352f7f91STakashi Iwai 
390712c93df6STakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum))
3908352f7f91STakashi Iwai 		return -ENOMEM;
3909352f7f91STakashi Iwai 	return 0;
3910352f7f91STakashi Iwai }
3911352f7f91STakashi Iwai 
3912352f7f91STakashi Iwai /*
3913352f7f91STakashi Iwai  * Check the availability of HP/line-out auto-mute;
3914352f7f91STakashi Iwai  * Set up appropriately if really supported
3915352f7f91STakashi Iwai  */
3916352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec)
3917352f7f91STakashi Iwai {
3918352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3919352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
3920352f7f91STakashi Iwai 	int present = 0;
3921352f7f91STakashi Iwai 	int i, err;
3922352f7f91STakashi Iwai 
3923f72706beSTakashi Iwai 	if (spec->suppress_auto_mute)
3924f72706beSTakashi Iwai 		return 0;
3925f72706beSTakashi Iwai 
3926352f7f91STakashi Iwai 	if (cfg->hp_pins[0])
3927352f7f91STakashi Iwai 		present++;
3928352f7f91STakashi Iwai 	if (cfg->line_out_pins[0])
3929352f7f91STakashi Iwai 		present++;
3930352f7f91STakashi Iwai 	if (cfg->speaker_pins[0])
3931352f7f91STakashi Iwai 		present++;
3932352f7f91STakashi Iwai 	if (present < 2) /* need two different output types */
3933352f7f91STakashi Iwai 		return 0;
3934352f7f91STakashi Iwai 
3935352f7f91STakashi Iwai 	if (!cfg->speaker_pins[0] &&
3936352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
3937352f7f91STakashi Iwai 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
3938352f7f91STakashi Iwai 		       sizeof(cfg->speaker_pins));
3939352f7f91STakashi Iwai 		cfg->speaker_outs = cfg->line_outs;
3940352f7f91STakashi Iwai 	}
3941352f7f91STakashi Iwai 
3942352f7f91STakashi Iwai 	if (!cfg->hp_pins[0] &&
3943352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_HP_OUT) {
3944352f7f91STakashi Iwai 		memcpy(cfg->hp_pins, cfg->line_out_pins,
3945352f7f91STakashi Iwai 		       sizeof(cfg->hp_pins));
3946352f7f91STakashi Iwai 		cfg->hp_outs = cfg->line_outs;
3947352f7f91STakashi Iwai 	}
3948352f7f91STakashi Iwai 
3949352f7f91STakashi Iwai 	for (i = 0; i < cfg->hp_outs; i++) {
3950352f7f91STakashi Iwai 		hda_nid_t nid = cfg->hp_pins[i];
3951352f7f91STakashi Iwai 		if (!is_jack_detectable(codec, nid))
3952352f7f91STakashi Iwai 			continue;
3953352f7f91STakashi Iwai 		snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n",
3954352f7f91STakashi Iwai 			    nid);
3955352f7f91STakashi Iwai 		snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT,
39562e03e952STakashi Iwai 						    spec->hp_automute_hook ?
39572e03e952STakashi Iwai 						    spec->hp_automute_hook :
39585d550e15STakashi Iwai 						    snd_hda_gen_hp_automute);
3959352f7f91STakashi Iwai 		spec->detect_hp = 1;
3960352f7f91STakashi Iwai 	}
3961352f7f91STakashi Iwai 
3962352f7f91STakashi Iwai 	if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
3963352f7f91STakashi Iwai 		if (cfg->speaker_outs)
3964352f7f91STakashi Iwai 			for (i = 0; i < cfg->line_outs; i++) {
3965352f7f91STakashi Iwai 				hda_nid_t nid = cfg->line_out_pins[i];
3966352f7f91STakashi Iwai 				if (!is_jack_detectable(codec, nid))
3967352f7f91STakashi Iwai 					continue;
3968352f7f91STakashi Iwai 				snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid);
3969352f7f91STakashi Iwai 				snd_hda_jack_detect_enable_callback(codec, nid,
3970352f7f91STakashi Iwai 								    HDA_GEN_FRONT_EVENT,
39712e03e952STakashi Iwai 								    spec->line_automute_hook ?
39722e03e952STakashi Iwai 								    spec->line_automute_hook :
39735d550e15STakashi Iwai 								    snd_hda_gen_line_automute);
3974352f7f91STakashi Iwai 				spec->detect_lo = 1;
3975352f7f91STakashi Iwai 			}
3976352f7f91STakashi Iwai 		spec->automute_lo_possible = spec->detect_hp;
3977352f7f91STakashi Iwai 	}
3978352f7f91STakashi Iwai 
3979352f7f91STakashi Iwai 	spec->automute_speaker_possible = cfg->speaker_outs &&
3980352f7f91STakashi Iwai 		(spec->detect_hp || spec->detect_lo);
3981352f7f91STakashi Iwai 
3982352f7f91STakashi Iwai 	spec->automute_lo = spec->automute_lo_possible;
3983352f7f91STakashi Iwai 	spec->automute_speaker = spec->automute_speaker_possible;
3984352f7f91STakashi Iwai 
3985352f7f91STakashi Iwai 	if (spec->automute_speaker_possible || spec->automute_lo_possible) {
3986352f7f91STakashi Iwai 		/* create a control for automute mode */
3987352f7f91STakashi Iwai 		err = add_automute_mode_enum(codec);
3988352f7f91STakashi Iwai 		if (err < 0)
3989352f7f91STakashi Iwai 			return err;
3990352f7f91STakashi Iwai 	}
3991352f7f91STakashi Iwai 	return 0;
3992352f7f91STakashi Iwai }
3993352f7f91STakashi Iwai 
3994352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */
3995352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec)
3996352f7f91STakashi Iwai {
3997352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3998352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
3999352f7f91STakashi Iwai 	int i;
4000352f7f91STakashi Iwai 
4001352f7f91STakashi Iwai 	imux = &spec->input_mux;
4002352f7f91STakashi Iwai 	for (i = 0; i < spec->am_num_entries; i++) {
4003352f7f91STakashi Iwai 		spec->am_entry[i].idx =
4004352f7f91STakashi Iwai 			find_idx_in_nid_list(spec->am_entry[i].pin,
4005352f7f91STakashi Iwai 					     spec->imux_pins, imux->num_items);
4006352f7f91STakashi Iwai 		if (spec->am_entry[i].idx < 0)
4007352f7f91STakashi Iwai 			return false; /* no corresponding imux */
4008352f7f91STakashi Iwai 	}
4009352f7f91STakashi Iwai 
4010352f7f91STakashi Iwai 	/* we don't need the jack detection for the first pin */
4011352f7f91STakashi Iwai 	for (i = 1; i < spec->am_num_entries; i++)
4012352f7f91STakashi Iwai 		snd_hda_jack_detect_enable_callback(codec,
4013352f7f91STakashi Iwai 						    spec->am_entry[i].pin,
4014352f7f91STakashi Iwai 						    HDA_GEN_MIC_EVENT,
40152e03e952STakashi Iwai 						    spec->mic_autoswitch_hook ?
40162e03e952STakashi Iwai 						    spec->mic_autoswitch_hook :
40175d550e15STakashi Iwai 						    snd_hda_gen_mic_autoswitch);
4018352f7f91STakashi Iwai 	return true;
4019352f7f91STakashi Iwai }
4020352f7f91STakashi Iwai 
4021352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp)
4022352f7f91STakashi Iwai {
4023352f7f91STakashi Iwai 	const struct automic_entry *a = ap;
4024352f7f91STakashi Iwai 	const struct automic_entry *b = bp;
4025352f7f91STakashi Iwai 	return (int)(a->attr - b->attr);
4026352f7f91STakashi Iwai }
4027352f7f91STakashi Iwai 
4028352f7f91STakashi Iwai /*
4029352f7f91STakashi Iwai  * Check the availability of auto-mic switch;
4030352f7f91STakashi Iwai  * Set up if really supported
4031352f7f91STakashi Iwai  */
4032352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec)
4033352f7f91STakashi Iwai {
4034352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4035352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
4036352f7f91STakashi Iwai 	unsigned int types;
4037352f7f91STakashi Iwai 	int i, num_pins;
4038352f7f91STakashi Iwai 
4039d12daf6fSTakashi Iwai 	if (spec->suppress_auto_mic)
4040d12daf6fSTakashi Iwai 		return 0;
4041d12daf6fSTakashi Iwai 
4042352f7f91STakashi Iwai 	types = 0;
4043352f7f91STakashi Iwai 	num_pins = 0;
4044352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
4045352f7f91STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
4046352f7f91STakashi Iwai 		unsigned int attr;
4047352f7f91STakashi Iwai 		attr = snd_hda_codec_get_pincfg(codec, nid);
4048352f7f91STakashi Iwai 		attr = snd_hda_get_input_pin_attr(attr);
4049352f7f91STakashi Iwai 		if (types & (1 << attr))
4050352f7f91STakashi Iwai 			return 0; /* already occupied */
4051352f7f91STakashi Iwai 		switch (attr) {
4052352f7f91STakashi Iwai 		case INPUT_PIN_ATTR_INT:
4053352f7f91STakashi Iwai 			if (cfg->inputs[i].type != AUTO_PIN_MIC)
4054352f7f91STakashi Iwai 				return 0; /* invalid type */
4055352f7f91STakashi Iwai 			break;
4056352f7f91STakashi Iwai 		case INPUT_PIN_ATTR_UNUSED:
4057352f7f91STakashi Iwai 			return 0; /* invalid entry */
4058352f7f91STakashi Iwai 		default:
4059352f7f91STakashi Iwai 			if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
4060352f7f91STakashi Iwai 				return 0; /* invalid type */
4061352f7f91STakashi Iwai 			if (!spec->line_in_auto_switch &&
4062352f7f91STakashi Iwai 			    cfg->inputs[i].type != AUTO_PIN_MIC)
4063352f7f91STakashi Iwai 				return 0; /* only mic is allowed */
4064352f7f91STakashi Iwai 			if (!is_jack_detectable(codec, nid))
4065352f7f91STakashi Iwai 				return 0; /* no unsol support */
4066352f7f91STakashi Iwai 			break;
4067352f7f91STakashi Iwai 		}
4068352f7f91STakashi Iwai 		if (num_pins >= MAX_AUTO_MIC_PINS)
4069352f7f91STakashi Iwai 			return 0;
4070352f7f91STakashi Iwai 		types |= (1 << attr);
4071352f7f91STakashi Iwai 		spec->am_entry[num_pins].pin = nid;
4072352f7f91STakashi Iwai 		spec->am_entry[num_pins].attr = attr;
4073352f7f91STakashi Iwai 		num_pins++;
4074352f7f91STakashi Iwai 	}
4075352f7f91STakashi Iwai 
4076352f7f91STakashi Iwai 	if (num_pins < 2)
4077352f7f91STakashi Iwai 		return 0;
4078352f7f91STakashi Iwai 
4079352f7f91STakashi Iwai 	spec->am_num_entries = num_pins;
4080352f7f91STakashi Iwai 	/* sort the am_entry in the order of attr so that the pin with a
4081352f7f91STakashi Iwai 	 * higher attr will be selected when the jack is plugged.
4082352f7f91STakashi Iwai 	 */
4083352f7f91STakashi Iwai 	sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]),
4084352f7f91STakashi Iwai 	     compare_attr, NULL);
4085352f7f91STakashi Iwai 
4086352f7f91STakashi Iwai 	if (!auto_mic_check_imux(codec))
4087352f7f91STakashi Iwai 		return 0;
4088352f7f91STakashi Iwai 
4089352f7f91STakashi Iwai 	spec->auto_mic = 1;
4090352f7f91STakashi Iwai 	spec->num_adc_nids = 1;
4091352f7f91STakashi Iwai 	spec->cur_mux[0] = spec->am_entry[0].idx;
4092352f7f91STakashi Iwai 	snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
4093352f7f91STakashi Iwai 		    spec->am_entry[0].pin,
4094352f7f91STakashi Iwai 		    spec->am_entry[1].pin,
4095352f7f91STakashi Iwai 		    spec->am_entry[2].pin);
4096352f7f91STakashi Iwai 
4097352f7f91STakashi Iwai 	return 0;
4098352f7f91STakashi Iwai }
4099352f7f91STakashi Iwai 
410055196fffSTakashi Iwai /* power_filter hook; make inactive widgets into power down */
410155196fffSTakashi Iwai static unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
410255196fffSTakashi Iwai 						  hda_nid_t nid,
410355196fffSTakashi Iwai 						  unsigned int power_state)
410455196fffSTakashi Iwai {
410555196fffSTakashi Iwai 	if (power_state != AC_PWRST_D0)
410655196fffSTakashi Iwai 		return power_state;
410755196fffSTakashi Iwai 	if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
410855196fffSTakashi Iwai 		return power_state;
410955196fffSTakashi Iwai 	if (is_active_nid(codec, nid, HDA_OUTPUT, 0))
411055196fffSTakashi Iwai 		return power_state;
411155196fffSTakashi Iwai 	return AC_PWRST_D3;
411255196fffSTakashi Iwai }
411355196fffSTakashi Iwai 
4114352f7f91STakashi Iwai 
41159eb413e5STakashi Iwai /*
41169eb413e5STakashi Iwai  * Parse the given BIOS configuration and set up the hda_gen_spec
41179eb413e5STakashi Iwai  *
41189eb413e5STakashi Iwai  * return 1 if successful, 0 if the proper config is not found,
4119352f7f91STakashi Iwai  * or a negative error code
4120352f7f91STakashi Iwai  */
4121352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
41229eb413e5STakashi Iwai 				  struct auto_pin_cfg *cfg)
4123352f7f91STakashi Iwai {
4124352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4125352f7f91STakashi Iwai 	int err;
4126352f7f91STakashi Iwai 
41271c70a583STakashi Iwai 	parse_user_hints(codec);
41281c70a583STakashi Iwai 
4129e4a395e7STakashi Iwai 	if (spec->mixer_nid && !spec->mixer_merge_nid)
4130e4a395e7STakashi Iwai 		spec->mixer_merge_nid = spec->mixer_nid;
4131e4a395e7STakashi Iwai 
41329eb413e5STakashi Iwai 	if (cfg != &spec->autocfg) {
41339eb413e5STakashi Iwai 		spec->autocfg = *cfg;
41349eb413e5STakashi Iwai 		cfg = &spec->autocfg;
41359eb413e5STakashi Iwai 	}
41369eb413e5STakashi Iwai 
41376fc4cb97SDavid Henningsson 	fill_all_dac_nids(codec);
41386fc4cb97SDavid Henningsson 
4139352f7f91STakashi Iwai 	if (!cfg->line_outs) {
4140352f7f91STakashi Iwai 		if (cfg->dig_outs || cfg->dig_in_pin) {
4141352f7f91STakashi Iwai 			spec->multiout.max_channels = 2;
4142352f7f91STakashi Iwai 			spec->no_analog = 1;
4143352f7f91STakashi Iwai 			goto dig_only;
4144352f7f91STakashi Iwai 		}
4145352f7f91STakashi Iwai 		return 0; /* can't find valid BIOS pin config */
4146352f7f91STakashi Iwai 	}
4147352f7f91STakashi Iwai 
4148352f7f91STakashi Iwai 	if (!spec->no_primary_hp &&
4149352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
4150352f7f91STakashi Iwai 	    cfg->line_outs <= cfg->hp_outs) {
4151352f7f91STakashi Iwai 		/* use HP as primary out */
4152352f7f91STakashi Iwai 		cfg->speaker_outs = cfg->line_outs;
4153352f7f91STakashi Iwai 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
4154352f7f91STakashi Iwai 		       sizeof(cfg->speaker_pins));
4155352f7f91STakashi Iwai 		cfg->line_outs = cfg->hp_outs;
4156352f7f91STakashi Iwai 		memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
4157352f7f91STakashi Iwai 		cfg->hp_outs = 0;
4158352f7f91STakashi Iwai 		memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
4159352f7f91STakashi Iwai 		cfg->line_out_type = AUTO_PIN_HP_OUT;
4160352f7f91STakashi Iwai 	}
4161352f7f91STakashi Iwai 
4162352f7f91STakashi Iwai 	err = parse_output_paths(codec);
4163352f7f91STakashi Iwai 	if (err < 0)
4164352f7f91STakashi Iwai 		return err;
4165352f7f91STakashi Iwai 	err = create_multi_channel_mode(codec);
4166352f7f91STakashi Iwai 	if (err < 0)
4167352f7f91STakashi Iwai 		return err;
4168352f7f91STakashi Iwai 	err = create_multi_out_ctls(codec, cfg);
4169352f7f91STakashi Iwai 	if (err < 0)
4170352f7f91STakashi Iwai 		return err;
4171352f7f91STakashi Iwai 	err = create_hp_out_ctls(codec);
4172352f7f91STakashi Iwai 	if (err < 0)
4173352f7f91STakashi Iwai 		return err;
4174352f7f91STakashi Iwai 	err = create_speaker_out_ctls(codec);
4175352f7f91STakashi Iwai 	if (err < 0)
4176352f7f91STakashi Iwai 		return err;
417738cf6f1aSTakashi Iwai 	err = create_indep_hp_ctls(codec);
417838cf6f1aSTakashi Iwai 	if (err < 0)
417938cf6f1aSTakashi Iwai 		return err;
4180c30aa7b2STakashi Iwai 	err = create_loopback_mixing_ctl(codec);
4181c30aa7b2STakashi Iwai 	if (err < 0)
4182c30aa7b2STakashi Iwai 		return err;
4183967303daSTakashi Iwai 	err = create_hp_mic(codec);
4184352f7f91STakashi Iwai 	if (err < 0)
4185352f7f91STakashi Iwai 		return err;
4186352f7f91STakashi Iwai 	err = create_input_ctls(codec);
4187352f7f91STakashi Iwai 	if (err < 0)
4188352f7f91STakashi Iwai 		return err;
4189352f7f91STakashi Iwai 
4190a07a949bSTakashi Iwai 	spec->const_channel_count = spec->ext_channel_count;
4191a07a949bSTakashi Iwai 	/* check the multiple speaker and headphone pins */
4192a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
4193a07a949bSTakashi Iwai 		spec->const_channel_count = max(spec->const_channel_count,
4194a07a949bSTakashi Iwai 						cfg->speaker_outs * 2);
4195a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
4196a07a949bSTakashi Iwai 		spec->const_channel_count = max(spec->const_channel_count,
4197a07a949bSTakashi Iwai 						cfg->hp_outs * 2);
4198352f7f91STakashi Iwai 	spec->multiout.max_channels = max(spec->ext_channel_count,
4199352f7f91STakashi Iwai 					  spec->const_channel_count);
4200352f7f91STakashi Iwai 
4201352f7f91STakashi Iwai 	err = check_auto_mute_availability(codec);
4202352f7f91STakashi Iwai 	if (err < 0)
4203352f7f91STakashi Iwai 		return err;
4204352f7f91STakashi Iwai 
4205352f7f91STakashi Iwai 	err = check_dyn_adc_switch(codec);
4206352f7f91STakashi Iwai 	if (err < 0)
4207352f7f91STakashi Iwai 		return err;
4208352f7f91STakashi Iwai 
4209352f7f91STakashi Iwai 	err = check_auto_mic_availability(codec);
4210352f7f91STakashi Iwai 	if (err < 0)
4211352f7f91STakashi Iwai 		return err;
4212352f7f91STakashi Iwai 
4213352f7f91STakashi Iwai 	err = create_capture_mixers(codec);
4214352f7f91STakashi Iwai 	if (err < 0)
4215352f7f91STakashi Iwai 		return err;
4216352f7f91STakashi Iwai 
4217352f7f91STakashi Iwai 	err = parse_mic_boost(codec);
4218352f7f91STakashi Iwai 	if (err < 0)
4219352f7f91STakashi Iwai 		return err;
4220352f7f91STakashi Iwai 
4221f811c3cfSTakashi Iwai 	if (spec->add_jack_modes) {
4222978e77e7STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
4223978e77e7STakashi Iwai 			err = create_out_jack_modes(codec, cfg->line_outs,
4224978e77e7STakashi Iwai 						    cfg->line_out_pins);
4225978e77e7STakashi Iwai 			if (err < 0)
4226978e77e7STakashi Iwai 				return err;
4227978e77e7STakashi Iwai 		}
4228978e77e7STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
4229978e77e7STakashi Iwai 			err = create_out_jack_modes(codec, cfg->hp_outs,
4230978e77e7STakashi Iwai 						    cfg->hp_pins);
4231978e77e7STakashi Iwai 			if (err < 0)
4232978e77e7STakashi Iwai 				return err;
4233978e77e7STakashi Iwai 		}
4234978e77e7STakashi Iwai 	}
4235978e77e7STakashi Iwai 
4236352f7f91STakashi Iwai  dig_only:
4237352f7f91STakashi Iwai 	parse_digital(codec);
4238352f7f91STakashi Iwai 
423955196fffSTakashi Iwai 	if (spec->power_down_unused)
424055196fffSTakashi Iwai 		codec->power_filter = snd_hda_gen_path_power_filter;
424155196fffSTakashi Iwai 
42427504b6cdSTakashi Iwai 	if (!spec->no_analog && spec->beep_nid) {
42437504b6cdSTakashi Iwai 		err = snd_hda_attach_beep_device(codec, spec->beep_nid);
42447504b6cdSTakashi Iwai 		if (err < 0)
42457504b6cdSTakashi Iwai 			return err;
42467504b6cdSTakashi Iwai 	}
42477504b6cdSTakashi Iwai 
4248352f7f91STakashi Iwai 	return 1;
4249352f7f91STakashi Iwai }
4250352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config);
4251352f7f91STakashi Iwai 
4252352f7f91STakashi Iwai 
4253352f7f91STakashi Iwai /*
4254352f7f91STakashi Iwai  * Build control elements
4255352f7f91STakashi Iwai  */
4256352f7f91STakashi Iwai 
4257352f7f91STakashi Iwai /* slave controls for virtual master */
4258352f7f91STakashi Iwai static const char * const slave_pfxs[] = {
4259352f7f91STakashi Iwai 	"Front", "Surround", "Center", "LFE", "Side",
4260352f7f91STakashi Iwai 	"Headphone", "Speaker", "Mono", "Line Out",
4261352f7f91STakashi Iwai 	"CLFE", "Bass Speaker", "PCM",
4262ee79c69aSTakashi Iwai 	"Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
4263ee79c69aSTakashi Iwai 	"Headphone Front", "Headphone Surround", "Headphone CLFE",
4264ee79c69aSTakashi Iwai 	"Headphone Side",
4265352f7f91STakashi Iwai 	NULL,
4266352f7f91STakashi Iwai };
4267352f7f91STakashi Iwai 
4268352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec)
4269352f7f91STakashi Iwai {
4270352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4271352f7f91STakashi Iwai 	int err;
4272352f7f91STakashi Iwai 
427336502d02STakashi Iwai 	if (spec->kctls.used) {
4274352f7f91STakashi Iwai 		err = snd_hda_add_new_ctls(codec, spec->kctls.list);
4275352f7f91STakashi Iwai 		if (err < 0)
4276352f7f91STakashi Iwai 			return err;
427736502d02STakashi Iwai 	}
4278352f7f91STakashi Iwai 
4279352f7f91STakashi Iwai 	if (spec->multiout.dig_out_nid) {
4280352f7f91STakashi Iwai 		err = snd_hda_create_dig_out_ctls(codec,
4281352f7f91STakashi Iwai 						  spec->multiout.dig_out_nid,
4282352f7f91STakashi Iwai 						  spec->multiout.dig_out_nid,
4283352f7f91STakashi Iwai 						  spec->pcm_rec[1].pcm_type);
4284352f7f91STakashi Iwai 		if (err < 0)
4285352f7f91STakashi Iwai 			return err;
4286352f7f91STakashi Iwai 		if (!spec->no_analog) {
4287352f7f91STakashi Iwai 			err = snd_hda_create_spdif_share_sw(codec,
4288352f7f91STakashi Iwai 							    &spec->multiout);
4289352f7f91STakashi Iwai 			if (err < 0)
4290352f7f91STakashi Iwai 				return err;
4291352f7f91STakashi Iwai 			spec->multiout.share_spdif = 1;
4292352f7f91STakashi Iwai 		}
4293352f7f91STakashi Iwai 	}
4294352f7f91STakashi Iwai 	if (spec->dig_in_nid) {
4295352f7f91STakashi Iwai 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
4296352f7f91STakashi Iwai 		if (err < 0)
4297352f7f91STakashi Iwai 			return err;
4298352f7f91STakashi Iwai 	}
4299352f7f91STakashi Iwai 
4300352f7f91STakashi Iwai 	/* if we have no master control, let's create it */
4301352f7f91STakashi Iwai 	if (!spec->no_analog &&
4302352f7f91STakashi Iwai 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
4303352f7f91STakashi Iwai 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
43047a71bbf3STakashi Iwai 					  spec->vmaster_tlv, slave_pfxs,
4305352f7f91STakashi Iwai 					  "Playback Volume");
4306352f7f91STakashi Iwai 		if (err < 0)
4307352f7f91STakashi Iwai 			return err;
4308352f7f91STakashi Iwai 	}
4309352f7f91STakashi Iwai 	if (!spec->no_analog &&
4310352f7f91STakashi Iwai 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
4311352f7f91STakashi Iwai 		err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
4312352f7f91STakashi Iwai 					    NULL, slave_pfxs,
4313352f7f91STakashi Iwai 					    "Playback Switch",
4314352f7f91STakashi Iwai 					    true, &spec->vmaster_mute.sw_kctl);
4315352f7f91STakashi Iwai 		if (err < 0)
4316352f7f91STakashi Iwai 			return err;
4317352f7f91STakashi Iwai 		if (spec->vmaster_mute.hook)
4318fd25a97aSTakashi Iwai 			snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
4319fd25a97aSTakashi Iwai 						 spec->vmaster_mute_enum);
4320352f7f91STakashi Iwai 	}
4321352f7f91STakashi Iwai 
4322352f7f91STakashi Iwai 	free_kctls(spec); /* no longer needed */
4323352f7f91STakashi Iwai 
4324967303daSTakashi Iwai 	if (spec->hp_mic_pin) {
4325352f7f91STakashi Iwai 		int err;
4326967303daSTakashi Iwai 		int nid = spec->hp_mic_pin;
4327352f7f91STakashi Iwai 		err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0);
4328352f7f91STakashi Iwai 		if (err < 0)
4329352f7f91STakashi Iwai 			return err;
4330352f7f91STakashi Iwai 		err = snd_hda_jack_detect_enable(codec, nid, 0);
4331352f7f91STakashi Iwai 		if (err < 0)
4332352f7f91STakashi Iwai 			return err;
4333352f7f91STakashi Iwai 	}
4334352f7f91STakashi Iwai 
4335352f7f91STakashi Iwai 	err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
4336352f7f91STakashi Iwai 	if (err < 0)
4337352f7f91STakashi Iwai 		return err;
4338352f7f91STakashi Iwai 
4339352f7f91STakashi Iwai 	return 0;
4340352f7f91STakashi Iwai }
4341352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls);
4342352f7f91STakashi Iwai 
4343352f7f91STakashi Iwai 
4344352f7f91STakashi Iwai /*
4345352f7f91STakashi Iwai  * PCM definitions
4346352f7f91STakashi Iwai  */
4347352f7f91STakashi Iwai 
4348e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo,
4349e6b85f3cSTakashi Iwai 				   struct hda_codec *codec,
4350e6b85f3cSTakashi Iwai 				   struct snd_pcm_substream *substream,
4351e6b85f3cSTakashi Iwai 				   int action)
4352e6b85f3cSTakashi Iwai {
4353e6b85f3cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4354e6b85f3cSTakashi Iwai 	if (spec->pcm_playback_hook)
4355e6b85f3cSTakashi Iwai 		spec->pcm_playback_hook(hinfo, codec, substream, action);
4356e6b85f3cSTakashi Iwai }
4357e6b85f3cSTakashi Iwai 
4358ac2e8736STakashi Iwai static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo,
4359ac2e8736STakashi Iwai 				  struct hda_codec *codec,
4360ac2e8736STakashi Iwai 				  struct snd_pcm_substream *substream,
4361ac2e8736STakashi Iwai 				  int action)
4362ac2e8736STakashi Iwai {
4363ac2e8736STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4364ac2e8736STakashi Iwai 	if (spec->pcm_capture_hook)
4365ac2e8736STakashi Iwai 		spec->pcm_capture_hook(hinfo, codec, substream, action);
4366ac2e8736STakashi Iwai }
4367ac2e8736STakashi Iwai 
4368352f7f91STakashi Iwai /*
4369352f7f91STakashi Iwai  * Analog playback callbacks
4370352f7f91STakashi Iwai  */
4371352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo,
4372352f7f91STakashi Iwai 			     struct hda_codec *codec,
4373352f7f91STakashi Iwai 			     struct snd_pcm_substream *substream)
4374352f7f91STakashi Iwai {
4375352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
437638cf6f1aSTakashi Iwai 	int err;
437738cf6f1aSTakashi Iwai 
437838cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
437938cf6f1aSTakashi Iwai 	err = snd_hda_multi_out_analog_open(codec,
438038cf6f1aSTakashi Iwai 					    &spec->multiout, substream,
4381352f7f91STakashi Iwai 					     hinfo);
4382e6b85f3cSTakashi Iwai 	if (!err) {
438338cf6f1aSTakashi Iwai 		spec->active_streams |= 1 << STREAM_MULTI_OUT;
4384e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
4385e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_OPEN);
4386e6b85f3cSTakashi Iwai 	}
438738cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
438838cf6f1aSTakashi Iwai 	return err;
4389352f7f91STakashi Iwai }
4390352f7f91STakashi Iwai 
4391352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
439297ec558aSTakashi Iwai 				struct hda_codec *codec,
439397ec558aSTakashi Iwai 				unsigned int stream_tag,
439497ec558aSTakashi Iwai 				unsigned int format,
439597ec558aSTakashi Iwai 				struct snd_pcm_substream *substream)
439697ec558aSTakashi Iwai {
4397352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4398e6b85f3cSTakashi Iwai 	int err;
4399e6b85f3cSTakashi Iwai 
4400e6b85f3cSTakashi Iwai 	err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
4401352f7f91STakashi Iwai 					       stream_tag, format, substream);
4402e6b85f3cSTakashi Iwai 	if (!err)
4403e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
4404e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_PREPARE);
4405e6b85f3cSTakashi Iwai 	return err;
4406352f7f91STakashi Iwai }
440797ec558aSTakashi Iwai 
4408352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4409352f7f91STakashi Iwai 				struct hda_codec *codec,
4410352f7f91STakashi Iwai 				struct snd_pcm_substream *substream)
4411352f7f91STakashi Iwai {
4412352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4413e6b85f3cSTakashi Iwai 	int err;
4414e6b85f3cSTakashi Iwai 
4415e6b85f3cSTakashi Iwai 	err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
4416e6b85f3cSTakashi Iwai 	if (!err)
4417e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
4418e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_CLEANUP);
4419e6b85f3cSTakashi Iwai 	return err;
4420352f7f91STakashi Iwai }
4421352f7f91STakashi Iwai 
442238cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo,
442338cf6f1aSTakashi Iwai 			      struct hda_codec *codec,
442438cf6f1aSTakashi Iwai 			      struct snd_pcm_substream *substream)
442538cf6f1aSTakashi Iwai {
442638cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
442738cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
442838cf6f1aSTakashi Iwai 	spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
4429e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
4430e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLOSE);
443138cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
443238cf6f1aSTakashi Iwai 	return 0;
443338cf6f1aSTakashi Iwai }
443438cf6f1aSTakashi Iwai 
4435ac2e8736STakashi Iwai static int capture_pcm_open(struct hda_pcm_stream *hinfo,
4436ac2e8736STakashi Iwai 			    struct hda_codec *codec,
4437ac2e8736STakashi Iwai 			    struct snd_pcm_substream *substream)
4438ac2e8736STakashi Iwai {
4439ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN);
4440ac2e8736STakashi Iwai 	return 0;
4441ac2e8736STakashi Iwai }
4442ac2e8736STakashi Iwai 
4443ac2e8736STakashi Iwai static int capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4444ac2e8736STakashi Iwai 			       struct hda_codec *codec,
4445ac2e8736STakashi Iwai 			       unsigned int stream_tag,
4446ac2e8736STakashi Iwai 			       unsigned int format,
4447ac2e8736STakashi Iwai 			       struct snd_pcm_substream *substream)
4448ac2e8736STakashi Iwai {
4449ac2e8736STakashi Iwai 	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
4450ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream,
4451ac2e8736STakashi Iwai 			      HDA_GEN_PCM_ACT_PREPARE);
4452ac2e8736STakashi Iwai 	return 0;
4453ac2e8736STakashi Iwai }
4454ac2e8736STakashi Iwai 
4455ac2e8736STakashi Iwai static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
4456ac2e8736STakashi Iwai 			       struct hda_codec *codec,
4457ac2e8736STakashi Iwai 			       struct snd_pcm_substream *substream)
4458ac2e8736STakashi Iwai {
4459ac2e8736STakashi Iwai 	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
4460ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream,
4461ac2e8736STakashi Iwai 			      HDA_GEN_PCM_ACT_CLEANUP);
4462ac2e8736STakashi Iwai 	return 0;
4463ac2e8736STakashi Iwai }
4464ac2e8736STakashi Iwai 
4465ac2e8736STakashi Iwai static int capture_pcm_close(struct hda_pcm_stream *hinfo,
4466ac2e8736STakashi Iwai 			     struct hda_codec *codec,
4467ac2e8736STakashi Iwai 			     struct snd_pcm_substream *substream)
4468ac2e8736STakashi Iwai {
4469ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE);
4470ac2e8736STakashi Iwai 	return 0;
4471ac2e8736STakashi Iwai }
4472ac2e8736STakashi Iwai 
447338cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
447438cf6f1aSTakashi Iwai 				 struct hda_codec *codec,
447538cf6f1aSTakashi Iwai 				 struct snd_pcm_substream *substream)
447638cf6f1aSTakashi Iwai {
447738cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
447838cf6f1aSTakashi Iwai 	int err = 0;
447938cf6f1aSTakashi Iwai 
448038cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
448138cf6f1aSTakashi Iwai 	if (!spec->indep_hp_enabled)
448238cf6f1aSTakashi Iwai 		err = -EBUSY;
448338cf6f1aSTakashi Iwai 	else
448438cf6f1aSTakashi Iwai 		spec->active_streams |= 1 << STREAM_INDEP_HP;
4485e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
4486e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_OPEN);
448738cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
448838cf6f1aSTakashi Iwai 	return err;
448938cf6f1aSTakashi Iwai }
449038cf6f1aSTakashi Iwai 
449138cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
449238cf6f1aSTakashi Iwai 				  struct hda_codec *codec,
449338cf6f1aSTakashi Iwai 				  struct snd_pcm_substream *substream)
449438cf6f1aSTakashi Iwai {
449538cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
449638cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
449738cf6f1aSTakashi Iwai 	spec->active_streams &= ~(1 << STREAM_INDEP_HP);
4498e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
4499e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLOSE);
450038cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
450138cf6f1aSTakashi Iwai 	return 0;
450238cf6f1aSTakashi Iwai }
450338cf6f1aSTakashi Iwai 
4504e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4505e6b85f3cSTakashi Iwai 				    struct hda_codec *codec,
4506e6b85f3cSTakashi Iwai 				    unsigned int stream_tag,
4507e6b85f3cSTakashi Iwai 				    unsigned int format,
4508e6b85f3cSTakashi Iwai 				    struct snd_pcm_substream *substream)
4509e6b85f3cSTakashi Iwai {
4510e6b85f3cSTakashi Iwai 	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
4511e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
4512e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_PREPARE);
4513e6b85f3cSTakashi Iwai 	return 0;
4514e6b85f3cSTakashi Iwai }
4515e6b85f3cSTakashi Iwai 
4516e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4517e6b85f3cSTakashi Iwai 				    struct hda_codec *codec,
4518e6b85f3cSTakashi Iwai 				    struct snd_pcm_substream *substream)
4519e6b85f3cSTakashi Iwai {
4520e6b85f3cSTakashi Iwai 	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
4521e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
4522e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLEANUP);
4523e6b85f3cSTakashi Iwai 	return 0;
4524e6b85f3cSTakashi Iwai }
4525e6b85f3cSTakashi Iwai 
4526352f7f91STakashi Iwai /*
4527352f7f91STakashi Iwai  * Digital out
4528352f7f91STakashi Iwai  */
4529352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
4530352f7f91STakashi Iwai 				 struct hda_codec *codec,
4531352f7f91STakashi Iwai 				 struct snd_pcm_substream *substream)
4532352f7f91STakashi Iwai {
4533352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4534352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
4535352f7f91STakashi Iwai }
4536352f7f91STakashi Iwai 
4537352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4538352f7f91STakashi Iwai 				    struct hda_codec *codec,
4539352f7f91STakashi Iwai 				    unsigned int stream_tag,
4540352f7f91STakashi Iwai 				    unsigned int format,
4541352f7f91STakashi Iwai 				    struct snd_pcm_substream *substream)
4542352f7f91STakashi Iwai {
4543352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4544352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
4545352f7f91STakashi Iwai 					     stream_tag, format, substream);
4546352f7f91STakashi Iwai }
4547352f7f91STakashi Iwai 
4548352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4549352f7f91STakashi Iwai 				    struct hda_codec *codec,
4550352f7f91STakashi Iwai 				    struct snd_pcm_substream *substream)
4551352f7f91STakashi Iwai {
4552352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4553352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
4554352f7f91STakashi Iwai }
4555352f7f91STakashi Iwai 
4556352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
4557352f7f91STakashi Iwai 				  struct hda_codec *codec,
4558352f7f91STakashi Iwai 				  struct snd_pcm_substream *substream)
4559352f7f91STakashi Iwai {
4560352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4561352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
4562352f7f91STakashi Iwai }
4563352f7f91STakashi Iwai 
4564352f7f91STakashi Iwai /*
4565352f7f91STakashi Iwai  * Analog capture
4566352f7f91STakashi Iwai  */
4567ac2e8736STakashi Iwai #define alt_capture_pcm_open	capture_pcm_open
4568ac2e8736STakashi Iwai #define alt_capture_pcm_close	capture_pcm_close
4569ac2e8736STakashi Iwai 
4570352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4571352f7f91STakashi Iwai 				   struct hda_codec *codec,
4572352f7f91STakashi Iwai 				   unsigned int stream_tag,
4573352f7f91STakashi Iwai 				   unsigned int format,
4574352f7f91STakashi Iwai 				   struct snd_pcm_substream *substream)
4575352f7f91STakashi Iwai {
4576352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4577352f7f91STakashi Iwai 
4578352f7f91STakashi Iwai 	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
457997ec558aSTakashi Iwai 				   stream_tag, 0, format);
4580ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream,
4581ac2e8736STakashi Iwai 			      HDA_GEN_PCM_ACT_PREPARE);
458297ec558aSTakashi Iwai 	return 0;
458397ec558aSTakashi Iwai }
458497ec558aSTakashi Iwai 
4585352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
458697ec558aSTakashi Iwai 				   struct hda_codec *codec,
458797ec558aSTakashi Iwai 				   struct snd_pcm_substream *substream)
458897ec558aSTakashi Iwai {
4589352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
459097ec558aSTakashi Iwai 
4591352f7f91STakashi Iwai 	snd_hda_codec_cleanup_stream(codec,
4592352f7f91STakashi Iwai 				     spec->adc_nids[substream->number + 1]);
4593ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream,
4594ac2e8736STakashi Iwai 			      HDA_GEN_PCM_ACT_CLEANUP);
459597ec558aSTakashi Iwai 	return 0;
459697ec558aSTakashi Iwai }
459797ec558aSTakashi Iwai 
4598352f7f91STakashi Iwai /*
4599352f7f91STakashi Iwai  */
4600352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = {
4601352f7f91STakashi Iwai 	.substreams = 1,
4602352f7f91STakashi Iwai 	.channels_min = 2,
4603352f7f91STakashi Iwai 	.channels_max = 8,
4604352f7f91STakashi Iwai 	/* NID is set in build_pcms */
4605352f7f91STakashi Iwai 	.ops = {
4606352f7f91STakashi Iwai 		.open = playback_pcm_open,
460738cf6f1aSTakashi Iwai 		.close = playback_pcm_close,
4608352f7f91STakashi Iwai 		.prepare = playback_pcm_prepare,
4609352f7f91STakashi Iwai 		.cleanup = playback_pcm_cleanup
4610352f7f91STakashi Iwai 	},
4611352f7f91STakashi Iwai };
4612352f7f91STakashi Iwai 
4613352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = {
4614352f7f91STakashi Iwai 	.substreams = 1,
4615352f7f91STakashi Iwai 	.channels_min = 2,
4616352f7f91STakashi Iwai 	.channels_max = 2,
4617352f7f91STakashi Iwai 	/* NID is set in build_pcms */
4618ac2e8736STakashi Iwai 	.ops = {
4619ac2e8736STakashi Iwai 		.open = capture_pcm_open,
4620ac2e8736STakashi Iwai 		.close = capture_pcm_close,
4621ac2e8736STakashi Iwai 		.prepare = capture_pcm_prepare,
4622ac2e8736STakashi Iwai 		.cleanup = capture_pcm_cleanup
4623ac2e8736STakashi Iwai 	},
4624352f7f91STakashi Iwai };
4625352f7f91STakashi Iwai 
4626352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = {
4627352f7f91STakashi Iwai 	.substreams = 1,
4628352f7f91STakashi Iwai 	.channels_min = 2,
4629352f7f91STakashi Iwai 	.channels_max = 2,
4630352f7f91STakashi Iwai 	/* NID is set in build_pcms */
463138cf6f1aSTakashi Iwai 	.ops = {
463238cf6f1aSTakashi Iwai 		.open = alt_playback_pcm_open,
4633e6b85f3cSTakashi Iwai 		.close = alt_playback_pcm_close,
4634e6b85f3cSTakashi Iwai 		.prepare = alt_playback_pcm_prepare,
4635e6b85f3cSTakashi Iwai 		.cleanup = alt_playback_pcm_cleanup
463638cf6f1aSTakashi Iwai 	},
4637352f7f91STakashi Iwai };
4638352f7f91STakashi Iwai 
4639352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = {
4640352f7f91STakashi Iwai 	.substreams = 2, /* can be overridden */
4641352f7f91STakashi Iwai 	.channels_min = 2,
4642352f7f91STakashi Iwai 	.channels_max = 2,
4643352f7f91STakashi Iwai 	/* NID is set in build_pcms */
4644352f7f91STakashi Iwai 	.ops = {
4645ac2e8736STakashi Iwai 		.open = alt_capture_pcm_open,
4646ac2e8736STakashi Iwai 		.close = alt_capture_pcm_close,
4647352f7f91STakashi Iwai 		.prepare = alt_capture_pcm_prepare,
4648352f7f91STakashi Iwai 		.cleanup = alt_capture_pcm_cleanup
4649352f7f91STakashi Iwai 	},
4650352f7f91STakashi Iwai };
4651352f7f91STakashi Iwai 
4652352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = {
4653352f7f91STakashi Iwai 	.substreams = 1,
4654352f7f91STakashi Iwai 	.channels_min = 2,
4655352f7f91STakashi Iwai 	.channels_max = 2,
4656352f7f91STakashi Iwai 	/* NID is set in build_pcms */
4657352f7f91STakashi Iwai 	.ops = {
4658352f7f91STakashi Iwai 		.open = dig_playback_pcm_open,
4659352f7f91STakashi Iwai 		.close = dig_playback_pcm_close,
4660352f7f91STakashi Iwai 		.prepare = dig_playback_pcm_prepare,
4661352f7f91STakashi Iwai 		.cleanup = dig_playback_pcm_cleanup
4662352f7f91STakashi Iwai 	},
4663352f7f91STakashi Iwai };
4664352f7f91STakashi Iwai 
4665352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = {
4666352f7f91STakashi Iwai 	.substreams = 1,
4667352f7f91STakashi Iwai 	.channels_min = 2,
4668352f7f91STakashi Iwai 	.channels_max = 2,
4669352f7f91STakashi Iwai 	/* NID is set in build_pcms */
4670352f7f91STakashi Iwai };
4671352f7f91STakashi Iwai 
4672352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */
4673352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = {
4674352f7f91STakashi Iwai 	.substreams = 0,
4675352f7f91STakashi Iwai 	.channels_min = 0,
4676352f7f91STakashi Iwai 	.channels_max = 0,
4677352f7f91STakashi Iwai };
4678352f7f91STakashi Iwai 
4679352f7f91STakashi Iwai /*
4680352f7f91STakashi Iwai  * dynamic changing ADC PCM streams
4681352f7f91STakashi Iwai  */
4682352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
46831da177e4SLinus Torvalds {
4684352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4685352f7f91STakashi Iwai 	hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
46861da177e4SLinus Torvalds 
4687352f7f91STakashi Iwai 	if (spec->cur_adc && spec->cur_adc != new_adc) {
4688352f7f91STakashi Iwai 		/* stream is running, let's swap the current ADC */
4689352f7f91STakashi Iwai 		__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
4690352f7f91STakashi Iwai 		spec->cur_adc = new_adc;
4691352f7f91STakashi Iwai 		snd_hda_codec_setup_stream(codec, new_adc,
4692352f7f91STakashi Iwai 					   spec->cur_adc_stream_tag, 0,
4693352f7f91STakashi Iwai 					   spec->cur_adc_format);
4694352f7f91STakashi Iwai 		return true;
4695352f7f91STakashi Iwai 	}
4696352f7f91STakashi Iwai 	return false;
4697352f7f91STakashi Iwai }
4698352f7f91STakashi Iwai 
4699352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */
4700352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4701352f7f91STakashi Iwai 				       struct hda_codec *codec,
4702352f7f91STakashi Iwai 				       unsigned int stream_tag,
4703352f7f91STakashi Iwai 				       unsigned int format,
4704352f7f91STakashi Iwai 				       struct snd_pcm_substream *substream)
4705352f7f91STakashi Iwai {
4706352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4707352f7f91STakashi Iwai 	spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
4708352f7f91STakashi Iwai 	spec->cur_adc_stream_tag = stream_tag;
4709352f7f91STakashi Iwai 	spec->cur_adc_format = format;
4710352f7f91STakashi Iwai 	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
47111da177e4SLinus Torvalds 	return 0;
47121da177e4SLinus Torvalds }
47131da177e4SLinus Torvalds 
4714352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
4715352f7f91STakashi Iwai 				       struct hda_codec *codec,
4716352f7f91STakashi Iwai 				       struct snd_pcm_substream *substream)
4717352f7f91STakashi Iwai {
4718352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4719352f7f91STakashi Iwai 	snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4720352f7f91STakashi Iwai 	spec->cur_adc = 0;
4721352f7f91STakashi Iwai 	return 0;
4722352f7f91STakashi Iwai }
4723352f7f91STakashi Iwai 
4724352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
4725352f7f91STakashi Iwai 	.substreams = 1,
4726352f7f91STakashi Iwai 	.channels_min = 2,
4727352f7f91STakashi Iwai 	.channels_max = 2,
4728352f7f91STakashi Iwai 	.nid = 0, /* fill later */
4729352f7f91STakashi Iwai 	.ops = {
4730352f7f91STakashi Iwai 		.prepare = dyn_adc_capture_pcm_prepare,
4731352f7f91STakashi Iwai 		.cleanup = dyn_adc_capture_pcm_cleanup
4732352f7f91STakashi Iwai 	},
4733352f7f91STakashi Iwai };
4734352f7f91STakashi Iwai 
4735f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
4736f873e536STakashi Iwai 				 const char *chip_name)
4737f873e536STakashi Iwai {
4738f873e536STakashi Iwai 	char *p;
4739f873e536STakashi Iwai 
4740f873e536STakashi Iwai 	if (*str)
4741f873e536STakashi Iwai 		return;
4742f873e536STakashi Iwai 	strlcpy(str, chip_name, len);
4743f873e536STakashi Iwai 
4744f873e536STakashi Iwai 	/* drop non-alnum chars after a space */
4745f873e536STakashi Iwai 	for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) {
4746f873e536STakashi Iwai 		if (!isalnum(p[1])) {
4747f873e536STakashi Iwai 			*p = 0;
4748f873e536STakashi Iwai 			break;
4749f873e536STakashi Iwai 		}
4750f873e536STakashi Iwai 	}
4751f873e536STakashi Iwai 	strlcat(str, sfx, len);
4752f873e536STakashi Iwai }
4753f873e536STakashi Iwai 
4754352f7f91STakashi Iwai /* build PCM streams based on the parsed results */
4755352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec)
4756352f7f91STakashi Iwai {
4757352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4758352f7f91STakashi Iwai 	struct hda_pcm *info = spec->pcm_rec;
4759352f7f91STakashi Iwai 	const struct hda_pcm_stream *p;
4760352f7f91STakashi Iwai 	bool have_multi_adcs;
4761352f7f91STakashi Iwai 
47621da177e4SLinus Torvalds 	codec->num_pcms = 1;
47631da177e4SLinus Torvalds 	codec->pcm_info = info;
47641da177e4SLinus Torvalds 
4765352f7f91STakashi Iwai 	if (spec->no_analog)
4766352f7f91STakashi Iwai 		goto skip_analog;
4767352f7f91STakashi Iwai 
4768f873e536STakashi Iwai 	fill_pcm_stream_name(spec->stream_name_analog,
4769f873e536STakashi Iwai 			     sizeof(spec->stream_name_analog),
4770f873e536STakashi Iwai 			     " Analog", codec->chip_name);
4771352f7f91STakashi Iwai 	info->name = spec->stream_name_analog;
4772352f7f91STakashi Iwai 
4773352f7f91STakashi Iwai 	if (spec->multiout.num_dacs > 0) {
4774352f7f91STakashi Iwai 		p = spec->stream_analog_playback;
4775352f7f91STakashi Iwai 		if (!p)
4776352f7f91STakashi Iwai 			p = &pcm_analog_playback;
4777352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
4778352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4779352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
4780352f7f91STakashi Iwai 			spec->multiout.max_channels;
4781352f7f91STakashi Iwai 		if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
4782352f7f91STakashi Iwai 		    spec->autocfg.line_outs == 2)
4783352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
4784352f7f91STakashi Iwai 				snd_pcm_2_1_chmaps;
4785352f7f91STakashi Iwai 	}
4786352f7f91STakashi Iwai 	if (spec->num_adc_nids) {
4787352f7f91STakashi Iwai 		p = spec->stream_analog_capture;
4788352f7f91STakashi Iwai 		if (!p) {
4789352f7f91STakashi Iwai 			if (spec->dyn_adc_switch)
4790352f7f91STakashi Iwai 				p = &dyn_adc_pcm_analog_capture;
4791352f7f91STakashi Iwai 			else
4792352f7f91STakashi Iwai 				p = &pcm_analog_capture;
4793352f7f91STakashi Iwai 		}
4794352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
4795352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4796352f7f91STakashi Iwai 	}
4797352f7f91STakashi Iwai 
4798352f7f91STakashi Iwai  skip_analog:
4799352f7f91STakashi Iwai 	/* SPDIF for stream index #1 */
4800352f7f91STakashi Iwai 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
4801f873e536STakashi Iwai 		fill_pcm_stream_name(spec->stream_name_digital,
4802352f7f91STakashi Iwai 				     sizeof(spec->stream_name_digital),
4803f873e536STakashi Iwai 				     " Digital", codec->chip_name);
4804352f7f91STakashi Iwai 		codec->num_pcms = 2;
4805352f7f91STakashi Iwai 		codec->slave_dig_outs = spec->multiout.slave_dig_outs;
4806352f7f91STakashi Iwai 		info = spec->pcm_rec + 1;
4807352f7f91STakashi Iwai 		info->name = spec->stream_name_digital;
4808352f7f91STakashi Iwai 		if (spec->dig_out_type)
4809352f7f91STakashi Iwai 			info->pcm_type = spec->dig_out_type;
4810352f7f91STakashi Iwai 		else
4811352f7f91STakashi Iwai 			info->pcm_type = HDA_PCM_TYPE_SPDIF;
4812352f7f91STakashi Iwai 		if (spec->multiout.dig_out_nid) {
4813352f7f91STakashi Iwai 			p = spec->stream_digital_playback;
4814352f7f91STakashi Iwai 			if (!p)
4815352f7f91STakashi Iwai 				p = &pcm_digital_playback;
4816352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
4817352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4818352f7f91STakashi Iwai 		}
4819352f7f91STakashi Iwai 		if (spec->dig_in_nid) {
4820352f7f91STakashi Iwai 			p = spec->stream_digital_capture;
4821352f7f91STakashi Iwai 			if (!p)
4822352f7f91STakashi Iwai 				p = &pcm_digital_capture;
4823352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
4824352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4825352f7f91STakashi Iwai 		}
4826352f7f91STakashi Iwai 	}
4827352f7f91STakashi Iwai 
4828352f7f91STakashi Iwai 	if (spec->no_analog)
4829352f7f91STakashi Iwai 		return 0;
4830352f7f91STakashi Iwai 
4831352f7f91STakashi Iwai 	/* If the use of more than one ADC is requested for the current
4832352f7f91STakashi Iwai 	 * model, configure a second analog capture-only PCM.
4833352f7f91STakashi Iwai 	 */
4834352f7f91STakashi Iwai 	have_multi_adcs = (spec->num_adc_nids > 1) &&
4835352f7f91STakashi Iwai 		!spec->dyn_adc_switch && !spec->auto_mic;
4836352f7f91STakashi Iwai 	/* Additional Analaog capture for index #2 */
4837352f7f91STakashi Iwai 	if (spec->alt_dac_nid || have_multi_adcs) {
4838a607148fSTakashi Iwai 		fill_pcm_stream_name(spec->stream_name_alt_analog,
4839a607148fSTakashi Iwai 				     sizeof(spec->stream_name_alt_analog),
4840a607148fSTakashi Iwai 			     " Alt Analog", codec->chip_name);
4841352f7f91STakashi Iwai 		codec->num_pcms = 3;
4842352f7f91STakashi Iwai 		info = spec->pcm_rec + 2;
4843a607148fSTakashi Iwai 		info->name = spec->stream_name_alt_analog;
4844352f7f91STakashi Iwai 		if (spec->alt_dac_nid) {
4845352f7f91STakashi Iwai 			p = spec->stream_analog_alt_playback;
4846352f7f91STakashi Iwai 			if (!p)
4847352f7f91STakashi Iwai 				p = &pcm_analog_alt_playback;
4848352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
4849352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4850352f7f91STakashi Iwai 				spec->alt_dac_nid;
4851352f7f91STakashi Iwai 		} else {
4852352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4853352f7f91STakashi Iwai 				pcm_null_stream;
4854352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4855352f7f91STakashi Iwai 		}
4856352f7f91STakashi Iwai 		if (have_multi_adcs) {
4857352f7f91STakashi Iwai 			p = spec->stream_analog_alt_capture;
4858352f7f91STakashi Iwai 			if (!p)
4859352f7f91STakashi Iwai 				p = &pcm_analog_alt_capture;
4860352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
4861352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4862352f7f91STakashi Iwai 				spec->adc_nids[1];
4863352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4864352f7f91STakashi Iwai 				spec->num_adc_nids - 1;
4865352f7f91STakashi Iwai 		} else {
4866352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4867352f7f91STakashi Iwai 				pcm_null_stream;
4868352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
4869352f7f91STakashi Iwai 		}
48701da177e4SLinus Torvalds 	}
48711da177e4SLinus Torvalds 
48721da177e4SLinus Torvalds 	return 0;
48731da177e4SLinus Torvalds }
4874352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms);
4875352f7f91STakashi Iwai 
4876352f7f91STakashi Iwai 
4877352f7f91STakashi Iwai /*
4878352f7f91STakashi Iwai  * Standard auto-parser initializations
4879352f7f91STakashi Iwai  */
4880352f7f91STakashi Iwai 
4881d4156930STakashi Iwai /* configure the given path as a proper output */
48822c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx)
4883352f7f91STakashi Iwai {
4884352f7f91STakashi Iwai 	struct nid_path *path;
4885d4156930STakashi Iwai 	hda_nid_t pin;
4886352f7f91STakashi Iwai 
4887196c1766STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
4888d4156930STakashi Iwai 	if (!path || !path->depth)
4889352f7f91STakashi Iwai 		return;
4890d4156930STakashi Iwai 	pin = path->path[path->depth - 1];
48912c12c30dSTakashi Iwai 	restore_pin_ctl(codec, pin);
4892e1284af7STakashi Iwai 	snd_hda_activate_path(codec, path, path->active, true);
4893e1284af7STakashi Iwai 	set_pin_eapd(codec, pin, path->active);
4894352f7f91STakashi Iwai }
4895352f7f91STakashi Iwai 
4896352f7f91STakashi Iwai /* initialize primary output paths */
4897352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec)
4898352f7f91STakashi Iwai {
4899352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4900352f7f91STakashi Iwai 	int i;
4901352f7f91STakashi Iwai 
4902d4156930STakashi Iwai 	for (i = 0; i < spec->autocfg.line_outs; i++)
49032c12c30dSTakashi Iwai 		set_output_and_unmute(codec, spec->out_paths[i]);
4904352f7f91STakashi Iwai }
4905352f7f91STakashi Iwai 
4906db23fd19STakashi Iwai 
49072c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths)
4908352f7f91STakashi Iwai {
4909352f7f91STakashi Iwai 	int i;
4910352f7f91STakashi Iwai 
4911d4156930STakashi Iwai 	for (i = 0; i < num_outs; i++)
49122c12c30dSTakashi Iwai 		set_output_and_unmute(codec, paths[i]);
4913352f7f91STakashi Iwai }
4914db23fd19STakashi Iwai 
4915db23fd19STakashi Iwai /* initialize hp and speaker paths */
4916db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec)
4917db23fd19STakashi Iwai {
4918db23fd19STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4919db23fd19STakashi Iwai 
4920db23fd19STakashi Iwai 	if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT)
49212c12c30dSTakashi Iwai 		__init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths);
4922db23fd19STakashi Iwai 	if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT)
4923db23fd19STakashi Iwai 		__init_extra_out(codec, spec->autocfg.speaker_outs,
49242c12c30dSTakashi Iwai 				 spec->speaker_paths);
4925352f7f91STakashi Iwai }
4926352f7f91STakashi Iwai 
4927352f7f91STakashi Iwai /* initialize multi-io paths */
4928352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec)
4929352f7f91STakashi Iwai {
4930352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4931352f7f91STakashi Iwai 	int i;
4932352f7f91STakashi Iwai 
4933352f7f91STakashi Iwai 	for (i = 0; i < spec->multi_ios; i++) {
4934352f7f91STakashi Iwai 		hda_nid_t pin = spec->multi_io[i].pin;
4935352f7f91STakashi Iwai 		struct nid_path *path;
4936196c1766STakashi Iwai 		path = get_multiio_path(codec, i);
4937352f7f91STakashi Iwai 		if (!path)
4938352f7f91STakashi Iwai 			continue;
4939352f7f91STakashi Iwai 		if (!spec->multi_io[i].ctl_in)
4940352f7f91STakashi Iwai 			spec->multi_io[i].ctl_in =
49412c12c30dSTakashi Iwai 				snd_hda_codec_get_pin_target(codec, pin);
4942352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, path->active, true);
4943352f7f91STakashi Iwai 	}
4944352f7f91STakashi Iwai }
4945352f7f91STakashi Iwai 
4946352f7f91STakashi Iwai /* set up input pins and loopback paths */
4947352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec)
4948352f7f91STakashi Iwai {
4949352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4950352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
4951352f7f91STakashi Iwai 	int i;
4952352f7f91STakashi Iwai 
4953352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
4954352f7f91STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
4955352f7f91STakashi Iwai 		if (is_input_pin(codec, nid))
49562c12c30dSTakashi Iwai 			restore_pin_ctl(codec, nid);
4957352f7f91STakashi Iwai 
4958352f7f91STakashi Iwai 		/* init loopback inputs */
4959352f7f91STakashi Iwai 		if (spec->mixer_nid) {
49603e367f15STakashi Iwai 			resume_path_from_idx(codec, spec->loopback_paths[i]);
49613e367f15STakashi Iwai 			resume_path_from_idx(codec, spec->loopback_merge_path);
4962352f7f91STakashi Iwai 		}
4963352f7f91STakashi Iwai 	}
4964352f7f91STakashi Iwai }
4965352f7f91STakashi Iwai 
4966352f7f91STakashi Iwai /* initialize ADC paths */
4967352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec)
4968352f7f91STakashi Iwai {
4969352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4970352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
4971352f7f91STakashi Iwai 	struct nid_path *path;
4972352f7f91STakashi Iwai 	int i, c, nums;
4973352f7f91STakashi Iwai 
4974352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
4975352f7f91STakashi Iwai 		nums = 1;
4976352f7f91STakashi Iwai 	else
4977352f7f91STakashi Iwai 		nums = spec->num_adc_nids;
4978352f7f91STakashi Iwai 
4979352f7f91STakashi Iwai 	for (c = 0; c < nums; c++) {
4980352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
4981c697b716STakashi Iwai 			path = get_input_path(codec, c, i);
4982352f7f91STakashi Iwai 			if (path) {
4983352f7f91STakashi Iwai 				bool active = path->active;
4984352f7f91STakashi Iwai 				if (i == spec->cur_mux[c])
4985352f7f91STakashi Iwai 					active = true;
4986352f7f91STakashi Iwai 				snd_hda_activate_path(codec, path, active, false);
4987352f7f91STakashi Iwai 			}
4988352f7f91STakashi Iwai 		}
4989967303daSTakashi Iwai 		if (spec->hp_mic)
4990967303daSTakashi Iwai 			update_hp_mic(codec, c, true);
4991352f7f91STakashi Iwai 	}
4992352f7f91STakashi Iwai 
4993352f7f91STakashi Iwai 	if (spec->cap_sync_hook)
4994a90229e0STakashi Iwai 		spec->cap_sync_hook(codec, NULL);
4995352f7f91STakashi Iwai }
4996352f7f91STakashi Iwai 
4997352f7f91STakashi Iwai /* set right pin controls for digital I/O */
4998352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec)
4999352f7f91STakashi Iwai {
5000352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5001352f7f91STakashi Iwai 	int i;
5002352f7f91STakashi Iwai 	hda_nid_t pin;
5003352f7f91STakashi Iwai 
5004d4156930STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++)
50052c12c30dSTakashi Iwai 		set_output_and_unmute(codec, spec->digout_paths[i]);
5006352f7f91STakashi Iwai 	pin = spec->autocfg.dig_in_pin;
50072430d7b7STakashi Iwai 	if (pin) {
50082c12c30dSTakashi Iwai 		restore_pin_ctl(codec, pin);
50093e367f15STakashi Iwai 		resume_path_from_idx(codec, spec->digin_path);
50102430d7b7STakashi Iwai 	}
5011352f7f91STakashi Iwai }
5012352f7f91STakashi Iwai 
5013973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave
5014973e4972STakashi Iwai  * invalid unsol tags by some reason
5015973e4972STakashi Iwai  */
5016973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec)
5017973e4972STakashi Iwai {
5018973e4972STakashi Iwai 	int i;
5019973e4972STakashi Iwai 
5020973e4972STakashi Iwai 	for (i = 0; i < codec->init_pins.used; i++) {
5021973e4972STakashi Iwai 		struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
5022973e4972STakashi Iwai 		hda_nid_t nid = pin->nid;
5023973e4972STakashi Iwai 		if (is_jack_detectable(codec, nid) &&
5024973e4972STakashi Iwai 		    !snd_hda_jack_tbl_get(codec, nid))
5025973e4972STakashi Iwai 			snd_hda_codec_update_cache(codec, nid, 0,
5026973e4972STakashi Iwai 					AC_VERB_SET_UNSOLICITED_ENABLE, 0);
5027973e4972STakashi Iwai 	}
5028973e4972STakashi Iwai }
5029973e4972STakashi Iwai 
50305187ac16STakashi Iwai /*
50315187ac16STakashi Iwai  * initialize the generic spec;
50325187ac16STakashi Iwai  * this can be put as patch_ops.init function
50335187ac16STakashi Iwai  */
5034352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec)
5035352f7f91STakashi Iwai {
5036352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5037352f7f91STakashi Iwai 
5038352f7f91STakashi Iwai 	if (spec->init_hook)
5039352f7f91STakashi Iwai 		spec->init_hook(codec);
5040352f7f91STakashi Iwai 
5041352f7f91STakashi Iwai 	snd_hda_apply_verbs(codec);
5042352f7f91STakashi Iwai 
50433bbcd274STakashi Iwai 	codec->cached_write = 1;
50443bbcd274STakashi Iwai 
5045352f7f91STakashi Iwai 	init_multi_out(codec);
5046352f7f91STakashi Iwai 	init_extra_out(codec);
5047352f7f91STakashi Iwai 	init_multi_io(codec);
5048352f7f91STakashi Iwai 	init_analog_input(codec);
5049352f7f91STakashi Iwai 	init_input_src(codec);
5050352f7f91STakashi Iwai 	init_digital(codec);
5051352f7f91STakashi Iwai 
5052973e4972STakashi Iwai 	clear_unsol_on_unused_pins(codec);
5053973e4972STakashi Iwai 
5054352f7f91STakashi Iwai 	/* call init functions of standard auto-mute helpers */
5055a5cc2509STakashi Iwai 	update_automute_all(codec);
5056352f7f91STakashi Iwai 
5057dc870f38STakashi Iwai 	snd_hda_codec_flush_cache(codec);
50583bbcd274STakashi Iwai 
5059352f7f91STakashi Iwai 	if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
5060352f7f91STakashi Iwai 		snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
5061352f7f91STakashi Iwai 
5062352f7f91STakashi Iwai 	hda_call_check_power_status(codec, 0x01);
5063352f7f91STakashi Iwai 	return 0;
5064352f7f91STakashi Iwai }
5065fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_init);
5066fce52a3bSTakashi Iwai 
50675187ac16STakashi Iwai /*
50685187ac16STakashi Iwai  * free the generic spec;
50695187ac16STakashi Iwai  * this can be put as patch_ops.free function
50705187ac16STakashi Iwai  */
5071fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec)
5072fce52a3bSTakashi Iwai {
50737504b6cdSTakashi Iwai 	snd_hda_detach_beep_device(codec);
5074fce52a3bSTakashi Iwai 	snd_hda_gen_spec_free(codec->spec);
5075fce52a3bSTakashi Iwai 	kfree(codec->spec);
5076fce52a3bSTakashi Iwai 	codec->spec = NULL;
5077fce52a3bSTakashi Iwai }
5078fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_free);
5079fce52a3bSTakashi Iwai 
5080fce52a3bSTakashi Iwai #ifdef CONFIG_PM
50815187ac16STakashi Iwai /*
50825187ac16STakashi Iwai  * check the loopback power save state;
50835187ac16STakashi Iwai  * this can be put as patch_ops.check_power_status function
50845187ac16STakashi Iwai  */
5085fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
5086fce52a3bSTakashi Iwai {
5087fce52a3bSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5088fce52a3bSTakashi Iwai 	return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
5089fce52a3bSTakashi Iwai }
5090fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status);
5091fce52a3bSTakashi Iwai #endif
5092352f7f91STakashi Iwai 
5093352f7f91STakashi Iwai 
5094352f7f91STakashi Iwai /*
5095352f7f91STakashi Iwai  * the generic codec support
5096352f7f91STakashi Iwai  */
50971da177e4SLinus Torvalds 
5098352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = {
5099352f7f91STakashi Iwai 	.build_controls = snd_hda_gen_build_controls,
5100352f7f91STakashi Iwai 	.build_pcms = snd_hda_gen_build_pcms,
5101352f7f91STakashi Iwai 	.init = snd_hda_gen_init,
5102fce52a3bSTakashi Iwai 	.free = snd_hda_gen_free,
5103352f7f91STakashi Iwai 	.unsol_event = snd_hda_jack_unsol_event,
510483012a7cSTakashi Iwai #ifdef CONFIG_PM
5105fce52a3bSTakashi Iwai 	.check_power_status = snd_hda_gen_check_power_status,
5106cb53c626STakashi Iwai #endif
51071da177e4SLinus Torvalds };
51081da177e4SLinus Torvalds 
51091da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec)
51101da177e4SLinus Torvalds {
5111352f7f91STakashi Iwai 	struct hda_gen_spec *spec;
51121da177e4SLinus Torvalds 	int err;
51131da177e4SLinus Torvalds 
5114e560d8d8STakashi Iwai 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5115352f7f91STakashi Iwai 	if (!spec)
51161da177e4SLinus Torvalds 		return -ENOMEM;
5117352f7f91STakashi Iwai 	snd_hda_gen_spec_init(spec);
51181da177e4SLinus Torvalds 	codec->spec = spec;
51191da177e4SLinus Torvalds 
51209eb413e5STakashi Iwai 	err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
51219eb413e5STakashi Iwai 	if (err < 0)
51229eb413e5STakashi Iwai 		return err;
51239eb413e5STakashi Iwai 
51249eb413e5STakashi Iwai 	err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
5125352f7f91STakashi Iwai 	if (err < 0)
51261da177e4SLinus Torvalds 		goto error;
51271da177e4SLinus Torvalds 
51281da177e4SLinus Torvalds 	codec->patch_ops = generic_patch_ops;
51291da177e4SLinus Torvalds 	return 0;
51301da177e4SLinus Torvalds 
51311da177e4SLinus Torvalds error:
5132fce52a3bSTakashi Iwai 	snd_hda_gen_free(codec);
51331da177e4SLinus Torvalds 	return err;
51341da177e4SLinus Torvalds }
5135fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec);
5136