xref: /openbmc/linux/sound/pci/hda/hda_generic.c (revision 5f6af005)
1d0fa1179SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Universal Interface for Intel High Definition Audio Codec
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Generic widget tree parser
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include <linux/init.h>
111da177e4SLinus Torvalds #include <linux/slab.h>
12d81a6d71SPaul Gortmaker #include <linux/export.h>
13352f7f91STakashi Iwai #include <linux/sort.h>
1455196fffSTakashi Iwai #include <linux/delay.h>
15f873e536STakashi Iwai #include <linux/ctype.h>
16f873e536STakashi Iwai #include <linux/string.h>
1729476558STakashi Iwai #include <linux/bitops.h>
18b21bdd0dSTakashi Iwai #include <linux/module.h>
19b3802783STakashi Iwai #include <linux/leds.h>
201da177e4SLinus Torvalds #include <sound/core.h>
21352f7f91STakashi Iwai #include <sound/jack.h>
22d89c6c0cSTakashi Iwai #include <sound/tlv.h>
23be57bfffSPierre-Louis Bossart #include <sound/hda_codec.h>
241da177e4SLinus Torvalds #include "hda_local.h"
25352f7f91STakashi Iwai #include "hda_auto_parser.h"
26352f7f91STakashi Iwai #include "hda_jack.h"
277504b6cdSTakashi Iwai #include "hda_beep.h"
28352f7f91STakashi Iwai #include "hda_generic.h"
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds 
31dda42bd0STakashi Iwai /**
32dda42bd0STakashi Iwai  * snd_hda_gen_spec_init - initialize hda_gen_spec struct
33dda42bd0STakashi Iwai  * @spec: hda_gen_spec object to initialize
34dda42bd0STakashi Iwai  *
35dda42bd0STakashi Iwai  * Initialize the given hda_gen_spec object.
36dda42bd0STakashi Iwai  */
snd_hda_gen_spec_init(struct hda_gen_spec * spec)37352f7f91STakashi Iwai int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
381da177e4SLinus Torvalds {
39352f7f91STakashi Iwai 	snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
40352f7f91STakashi Iwai 	snd_array_init(&spec->paths, sizeof(struct nid_path), 8);
410186f4f4STakashi Iwai 	snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8);
4238cf6f1aSTakashi Iwai 	mutex_init(&spec->pcm_mutex);
43352f7f91STakashi Iwai 	return 0;
44352f7f91STakashi Iwai }
452698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init);
461da177e4SLinus Torvalds 
47dda42bd0STakashi Iwai /**
48dda42bd0STakashi Iwai  * snd_hda_gen_add_kctl - Add a new kctl_new struct from the template
49dda42bd0STakashi Iwai  * @spec: hda_gen_spec object
50dda42bd0STakashi Iwai  * @name: name string to override the template, NULL if unchanged
51dda42bd0STakashi Iwai  * @temp: template for the new kctl
52dda42bd0STakashi Iwai  *
53dda42bd0STakashi Iwai  * Add a new kctl (actually snd_kcontrol_new to be instantiated later)
54dda42bd0STakashi Iwai  * element based on the given snd_kcontrol_new template @temp and the
55dda42bd0STakashi Iwai  * name string @name to the list in @spec.
56dda42bd0STakashi Iwai  * Returns the newly created object or NULL as error.
57dda42bd0STakashi Iwai  */
5812c93df6STakashi Iwai struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec * spec,const char * name,const struct snd_kcontrol_new * temp)5912c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
60352f7f91STakashi Iwai 		     const struct snd_kcontrol_new *temp)
61352f7f91STakashi Iwai {
62352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
63352f7f91STakashi Iwai 	if (!knew)
64352f7f91STakashi Iwai 		return NULL;
65352f7f91STakashi Iwai 	*knew = *temp;
66352f7f91STakashi Iwai 	if (name)
67352f7f91STakashi Iwai 		knew->name = kstrdup(name, GFP_KERNEL);
68352f7f91STakashi Iwai 	else if (knew->name)
69352f7f91STakashi Iwai 		knew->name = kstrdup(knew->name, GFP_KERNEL);
70352f7f91STakashi Iwai 	if (!knew->name)
71352f7f91STakashi Iwai 		return NULL;
72352f7f91STakashi Iwai 	return knew;
73352f7f91STakashi Iwai }
742698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_kctl);
75352f7f91STakashi Iwai 
free_kctls(struct hda_gen_spec * spec)76352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec)
77352f7f91STakashi Iwai {
78352f7f91STakashi Iwai 	if (spec->kctls.list) {
79352f7f91STakashi Iwai 		struct snd_kcontrol_new *kctl = spec->kctls.list;
80352f7f91STakashi Iwai 		int i;
81352f7f91STakashi Iwai 		for (i = 0; i < spec->kctls.used; i++)
82352f7f91STakashi Iwai 			kfree(kctl[i].name);
83352f7f91STakashi Iwai 	}
84352f7f91STakashi Iwai 	snd_array_free(&spec->kctls);
85352f7f91STakashi Iwai }
86352f7f91STakashi Iwai 
snd_hda_gen_spec_free(struct hda_gen_spec * spec)87a8dca460STakashi Iwai static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
88352f7f91STakashi Iwai {
891da177e4SLinus Torvalds 	if (!spec)
901da177e4SLinus Torvalds 		return;
91352f7f91STakashi Iwai 	free_kctls(spec);
92352f7f91STakashi Iwai 	snd_array_free(&spec->paths);
930186f4f4STakashi Iwai 	snd_array_free(&spec->loopback_list);
94549f8ffcSTakashi Iwai #ifdef CONFIG_SND_HDA_GENERIC_LEDS
95549f8ffcSTakashi Iwai 	if (spec->led_cdevs[LED_AUDIO_MUTE])
96549f8ffcSTakashi Iwai 		led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
97549f8ffcSTakashi Iwai 	if (spec->led_cdevs[LED_AUDIO_MICMUTE])
98549f8ffcSTakashi Iwai 		led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
99549f8ffcSTakashi Iwai #endif
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds /*
1031c70a583STakashi Iwai  * store user hints
1041c70a583STakashi Iwai  */
parse_user_hints(struct hda_codec * codec)1051c70a583STakashi Iwai static void parse_user_hints(struct hda_codec *codec)
1061c70a583STakashi Iwai {
1071c70a583STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1081c70a583STakashi Iwai 	int val;
1091c70a583STakashi Iwai 
1101c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "jack_detect");
1111c70a583STakashi Iwai 	if (val >= 0)
1121c70a583STakashi Iwai 		codec->no_jack_detect = !val;
1131c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "inv_jack_detect");
1141c70a583STakashi Iwai 	if (val >= 0)
1151c70a583STakashi Iwai 		codec->inv_jack_detect = !!val;
1161c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "trigger_sense");
1171c70a583STakashi Iwai 	if (val >= 0)
1181c70a583STakashi Iwai 		codec->no_trigger_sense = !val;
1191c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "inv_eapd");
1201c70a583STakashi Iwai 	if (val >= 0)
1211c70a583STakashi Iwai 		codec->inv_eapd = !!val;
1221c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "pcm_format_first");
1231c70a583STakashi Iwai 	if (val >= 0)
1241c70a583STakashi Iwai 		codec->pcm_format_first = !!val;
1251c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "sticky_stream");
1261c70a583STakashi Iwai 	if (val >= 0)
1271c70a583STakashi Iwai 		codec->no_sticky_stream = !val;
1281c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "spdif_status_reset");
1291c70a583STakashi Iwai 	if (val >= 0)
1301c70a583STakashi Iwai 		codec->spdif_status_reset = !!val;
1311c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "pin_amp_workaround");
1321c70a583STakashi Iwai 	if (val >= 0)
1331c70a583STakashi Iwai 		codec->pin_amp_workaround = !!val;
1341c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "single_adc_amp");
1351c70a583STakashi Iwai 	if (val >= 0)
1361c70a583STakashi Iwai 		codec->single_adc_amp = !!val;
137967b1307STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "power_save_node");
138e6feb5d0STakashi Iwai 	if (val >= 0)
139967b1307STakashi Iwai 		codec->power_save_node = !!val;
1401c70a583STakashi Iwai 
141f72706beSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "auto_mute");
142f72706beSTakashi Iwai 	if (val >= 0)
143f72706beSTakashi Iwai 		spec->suppress_auto_mute = !val;
1441c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "auto_mic");
1451c70a583STakashi Iwai 	if (val >= 0)
1461c70a583STakashi Iwai 		spec->suppress_auto_mic = !val;
1471c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
1481c70a583STakashi Iwai 	if (val >= 0)
1491c70a583STakashi Iwai 		spec->line_in_auto_switch = !!val;
1507eebffd3STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp");
1517eebffd3STakashi Iwai 	if (val >= 0)
1527eebffd3STakashi Iwai 		spec->auto_mute_via_amp = !!val;
1531c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "need_dac_fix");
1541c70a583STakashi Iwai 	if (val >= 0)
1551c70a583STakashi Iwai 		spec->need_dac_fix = !!val;
1561c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "primary_hp");
1571c70a583STakashi Iwai 	if (val >= 0)
1581c70a583STakashi Iwai 		spec->no_primary_hp = !val;
159da96fb5bSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "multi_io");
160da96fb5bSTakashi Iwai 	if (val >= 0)
161da96fb5bSTakashi Iwai 		spec->no_multi_io = !val;
1621c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
1631c70a583STakashi Iwai 	if (val >= 0)
1641c70a583STakashi Iwai 		spec->multi_cap_vol = !!val;
1651c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "inv_dmic_split");
1661c70a583STakashi Iwai 	if (val >= 0)
1671c70a583STakashi Iwai 		spec->inv_dmic_split = !!val;
1681c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "indep_hp");
1691c70a583STakashi Iwai 	if (val >= 0)
1701c70a583STakashi Iwai 		spec->indep_hp = !!val;
1711c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input");
1721c70a583STakashi Iwai 	if (val >= 0)
1731c70a583STakashi Iwai 		spec->add_stereo_mix_input = !!val;
174f811c3cfSTakashi Iwai 	/* the following two are just for compatibility */
1751c70a583STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_out_jack_modes");
1761c70a583STakashi Iwai 	if (val >= 0)
177f811c3cfSTakashi Iwai 		spec->add_jack_modes = !!val;
17829476558STakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
17929476558STakashi Iwai 	if (val >= 0)
180f811c3cfSTakashi Iwai 		spec->add_jack_modes = !!val;
181f811c3cfSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_jack_modes");
182f811c3cfSTakashi Iwai 	if (val >= 0)
183f811c3cfSTakashi Iwai 		spec->add_jack_modes = !!val;
18455196fffSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "power_down_unused");
18555196fffSTakashi Iwai 	if (val >= 0)
18655196fffSTakashi Iwai 		spec->power_down_unused = !!val;
187967303daSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "add_hp_mic");
188967303daSTakashi Iwai 	if (val >= 0)
189967303daSTakashi Iwai 		spec->hp_mic = !!val;
190967303daSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
191967303daSTakashi Iwai 	if (val >= 0)
192967303daSTakashi Iwai 		spec->suppress_hp_mic_detect = !val;
1937480316cSTakashi Iwai 	val = snd_hda_get_bool_hint(codec, "vmaster");
1947480316cSTakashi Iwai 	if (val >= 0)
1957480316cSTakashi Iwai 		spec->suppress_vmaster = !val;
1961c70a583STakashi Iwai 
1971c70a583STakashi Iwai 	if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
1981c70a583STakashi Iwai 		spec->mixer_nid = val;
1991c70a583STakashi Iwai }
2001c70a583STakashi Iwai 
2011c70a583STakashi Iwai /*
2022c12c30dSTakashi Iwai  * pin control value accesses
2032c12c30dSTakashi Iwai  */
2042c12c30dSTakashi Iwai 
2052c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \
206401caff7STakashi Iwai 	snd_hda_codec_write_cache(codec, pin, 0, \
2072c12c30dSTakashi Iwai 				   AC_VERB_SET_PIN_WIDGET_CONTROL, val)
2082c12c30dSTakashi Iwai 
2092c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */
restore_pin_ctl(struct hda_codec * codec,hda_nid_t pin)2102c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin)
2112c12c30dSTakashi Iwai {
2122c12c30dSTakashi Iwai 	update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin));
2132c12c30dSTakashi Iwai }
2142c12c30dSTakashi Iwai 
2152c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */
set_pin_target(struct hda_codec * codec,hda_nid_t pin,unsigned int val,bool do_write)2162c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin,
2172c12c30dSTakashi Iwai 			   unsigned int val, bool do_write)
2182c12c30dSTakashi Iwai {
2192c12c30dSTakashi Iwai 	if (!pin)
2202c12c30dSTakashi Iwai 		return;
2212c12c30dSTakashi Iwai 	val = snd_hda_correct_pin_ctl(codec, pin, val);
2222c12c30dSTakashi Iwai 	snd_hda_codec_set_pin_target(codec, pin, val);
2232c12c30dSTakashi Iwai 	if (do_write)
2242c12c30dSTakashi Iwai 		update_pin_ctl(codec, pin, val);
2252c12c30dSTakashi Iwai }
2262c12c30dSTakashi Iwai 
2272c12c30dSTakashi Iwai /* set pinctl target values for all given pins */
set_pin_targets(struct hda_codec * codec,int num_pins,hda_nid_t * pins,unsigned int val)2282c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins,
2292c12c30dSTakashi Iwai 			    hda_nid_t *pins, unsigned int val)
2302c12c30dSTakashi Iwai {
2312c12c30dSTakashi Iwai 	int i;
2322c12c30dSTakashi Iwai 	for (i = 0; i < num_pins; i++)
2332c12c30dSTakashi Iwai 		set_pin_target(codec, pins[i], val, false);
2342c12c30dSTakashi Iwai }
2352c12c30dSTakashi Iwai 
2362c12c30dSTakashi Iwai /*
237352f7f91STakashi Iwai  * parsing paths
2381da177e4SLinus Torvalds  */
2391da177e4SLinus Torvalds 
2403ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */
find_idx_in_nid_list(hda_nid_t nid,const hda_nid_t * list,int nums)2413ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
2423ca529d3STakashi Iwai {
2433ca529d3STakashi Iwai 	int i;
2443ca529d3STakashi Iwai 	for (i = 0; i < nums; i++)
2453ca529d3STakashi Iwai 		if (list[i] == nid)
2463ca529d3STakashi Iwai 			return i;
2473ca529d3STakashi Iwai 	return -1;
2483ca529d3STakashi Iwai }
2493ca529d3STakashi Iwai 
2503ca529d3STakashi Iwai /* return true if the given NID is contained in the path */
is_nid_contained(struct nid_path * path,hda_nid_t nid)2513ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid)
2523ca529d3STakashi Iwai {
2533ca529d3STakashi Iwai 	return find_idx_in_nid_list(nid, path->path, path->depth) >= 0;
2543ca529d3STakashi Iwai }
2553ca529d3STakashi Iwai 
get_nid_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid,int anchor_nid)256f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec,
257f5172a7eSTakashi Iwai 				     hda_nid_t from_nid, hda_nid_t to_nid,
2583ca529d3STakashi Iwai 				     int anchor_nid)
2591da177e4SLinus Torvalds {
260352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
261a9c2dfc8STakashi Iwai 	struct nid_path *path;
262352f7f91STakashi Iwai 	int i;
2631da177e4SLinus Torvalds 
264a9c2dfc8STakashi Iwai 	snd_array_for_each(&spec->paths, i, path) {
265352f7f91STakashi Iwai 		if (path->depth <= 0)
266352f7f91STakashi Iwai 			continue;
267352f7f91STakashi Iwai 		if ((!from_nid || path->path[0] == from_nid) &&
268f5172a7eSTakashi Iwai 		    (!to_nid || path->path[path->depth - 1] == to_nid)) {
2693ca529d3STakashi Iwai 			if (!anchor_nid ||
2703ca529d3STakashi Iwai 			    (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) ||
2713ca529d3STakashi Iwai 			    (anchor_nid < 0 && !is_nid_contained(path, anchor_nid)))
272352f7f91STakashi Iwai 				return path;
2731da177e4SLinus Torvalds 		}
274f5172a7eSTakashi Iwai 	}
2751da177e4SLinus Torvalds 	return NULL;
2761da177e4SLinus Torvalds }
277f5172a7eSTakashi Iwai 
278dda42bd0STakashi Iwai /**
279dda42bd0STakashi Iwai  * snd_hda_get_path_idx - get the index number corresponding to the path
280dda42bd0STakashi Iwai  * instance
281dda42bd0STakashi Iwai  * @codec: the HDA codec
282dda42bd0STakashi Iwai  * @path: nid_path object
283dda42bd0STakashi Iwai  *
284dda42bd0STakashi Iwai  * The returned index starts from 1, i.e. the actual array index with offset 1,
285dda42bd0STakashi Iwai  * and zero is handled as an invalid path
286196c1766STakashi Iwai  */
snd_hda_get_path_idx(struct hda_codec * codec,struct nid_path * path)287196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
288196c1766STakashi Iwai {
289196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
290196c1766STakashi Iwai 	struct nid_path *array = spec->paths.list;
291196c1766STakashi Iwai 	ssize_t idx;
292196c1766STakashi Iwai 
293196c1766STakashi Iwai 	if (!spec->paths.used)
294196c1766STakashi Iwai 		return 0;
295196c1766STakashi Iwai 	idx = path - array;
296196c1766STakashi Iwai 	if (idx < 0 || idx >= spec->paths.used)
297196c1766STakashi Iwai 		return 0;
298196c1766STakashi Iwai 	return idx + 1;
299196c1766STakashi Iwai }
3002698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_path_idx);
301196c1766STakashi Iwai 
302dda42bd0STakashi Iwai /**
303dda42bd0STakashi Iwai  * snd_hda_get_path_from_idx - get the path instance corresponding to the
304dda42bd0STakashi Iwai  * given index number
305dda42bd0STakashi Iwai  * @codec: the HDA codec
306dda42bd0STakashi Iwai  * @idx: the path index
307dda42bd0STakashi Iwai  */
snd_hda_get_path_from_idx(struct hda_codec * codec,int idx)308196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
309196c1766STakashi Iwai {
310196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
311196c1766STakashi Iwai 
312196c1766STakashi Iwai 	if (idx <= 0 || idx > spec->paths.used)
313196c1766STakashi Iwai 		return NULL;
314196c1766STakashi Iwai 	return snd_array_elem(&spec->paths, idx - 1);
315196c1766STakashi Iwai }
3162698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx);
317196c1766STakashi Iwai 
318352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */
is_dac_already_used(struct hda_codec * codec,hda_nid_t nid)319352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
3201da177e4SLinus Torvalds {
321352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
322a9c2dfc8STakashi Iwai 	const struct nid_path *path;
323352f7f91STakashi Iwai 	int i;
324352f7f91STakashi Iwai 
325a9c2dfc8STakashi Iwai 	snd_array_for_each(&spec->paths, i, path) {
326352f7f91STakashi Iwai 		if (path->path[0] == nid)
327352f7f91STakashi Iwai 			return true;
328352f7f91STakashi Iwai 	}
329352f7f91STakashi Iwai 	return false;
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
332352f7f91STakashi Iwai /* check whether the given two widgets can be connected */
is_reachable_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid)333352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec,
334352f7f91STakashi Iwai 			      hda_nid_t from_nid, hda_nid_t to_nid)
3351da177e4SLinus Torvalds {
336352f7f91STakashi Iwai 	if (!from_nid || !to_nid)
337352f7f91STakashi Iwai 		return false;
338352f7f91STakashi Iwai 	return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
3391da177e4SLinus Torvalds }
3401da177e4SLinus Torvalds 
341352f7f91STakashi Iwai /* nid, dir and idx */
342352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK	(0xffff | (1U << 18) | (0x0f << 19))
343352f7f91STakashi Iwai 
344352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */
is_ctl_used(struct hda_codec * codec,unsigned int val,int type)345352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
3461da177e4SLinus Torvalds {
347352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
348a9c2dfc8STakashi Iwai 	const struct nid_path *path;
349352f7f91STakashi Iwai 	int i;
350352f7f91STakashi Iwai 
351352f7f91STakashi Iwai 	val &= AMP_VAL_COMPARE_MASK;
352a9c2dfc8STakashi Iwai 	snd_array_for_each(&spec->paths, i, path) {
353352f7f91STakashi Iwai 		if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val)
354352f7f91STakashi Iwai 			return true;
355352f7f91STakashi Iwai 	}
356352f7f91STakashi Iwai 	return false;
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds 
359352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */
is_ctl_associated(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,int type)360352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
3618999bf0aSTakashi Iwai 			      int dir, int idx, int type)
362cb53c626STakashi Iwai {
363352f7f91STakashi Iwai 	unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
3648999bf0aSTakashi Iwai 	return is_ctl_used(codec, val, type);
365cb53c626STakashi Iwai }
366352f7f91STakashi Iwai 
print_nid_path(struct hda_codec * codec,const char * pfx,struct nid_path * path)3674e76a883STakashi Iwai static void print_nid_path(struct hda_codec *codec,
3684e76a883STakashi Iwai 			   const char *pfx, struct nid_path *path)
3690c8c0f56STakashi Iwai {
3700c8c0f56STakashi Iwai 	char buf[40];
371d82353e5SJoe Perches 	char *pos = buf;
3720c8c0f56STakashi Iwai 	int i;
3730c8c0f56STakashi Iwai 
374d82353e5SJoe Perches 	*pos = 0;
375d82353e5SJoe Perches 	for (i = 0; i < path->depth; i++)
376d82353e5SJoe Perches 		pos += scnprintf(pos, sizeof(buf) - (pos - buf), "%s%02x",
377d82353e5SJoe Perches 				 pos != buf ? ":" : "",
378d82353e5SJoe Perches 				 path->path[i]);
3790c8c0f56STakashi Iwai 
380d82353e5SJoe Perches 	codec_dbg(codec, "%s path: depth=%d '%s'\n", pfx, path->depth, buf);
3810c8c0f56STakashi Iwai }
3820c8c0f56STakashi Iwai 
383352f7f91STakashi Iwai /* called recursively */
__parse_nid_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid,int anchor_nid,struct nid_path * path,int depth)384352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec,
385352f7f91STakashi Iwai 			     hda_nid_t from_nid, hda_nid_t to_nid,
3863ca529d3STakashi Iwai 			     int anchor_nid, struct nid_path *path,
3873ca529d3STakashi Iwai 			     int depth)
388352f7f91STakashi Iwai {
389ee8e765bSTakashi Iwai 	const hda_nid_t *conn;
390352f7f91STakashi Iwai 	int i, nums;
391352f7f91STakashi Iwai 
3923ca529d3STakashi Iwai 	if (to_nid == anchor_nid)
3933ca529d3STakashi Iwai 		anchor_nid = 0; /* anchor passed */
3943ca529d3STakashi Iwai 	else if (to_nid == (hda_nid_t)(-anchor_nid))
3953ca529d3STakashi Iwai 		return false; /* hit the exclusive nid */
396352f7f91STakashi Iwai 
397ee8e765bSTakashi Iwai 	nums = snd_hda_get_conn_list(codec, to_nid, &conn);
398352f7f91STakashi Iwai 	for (i = 0; i < nums; i++) {
399352f7f91STakashi Iwai 		if (conn[i] != from_nid) {
400352f7f91STakashi Iwai 			/* special case: when from_nid is 0,
401352f7f91STakashi Iwai 			 * try to find an empty DAC
402352f7f91STakashi Iwai 			 */
403352f7f91STakashi Iwai 			if (from_nid ||
404352f7f91STakashi Iwai 			    get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
405352f7f91STakashi Iwai 			    is_dac_already_used(codec, conn[i]))
406352f7f91STakashi Iwai 				continue;
407352f7f91STakashi Iwai 		}
4083ca529d3STakashi Iwai 		/* anchor is not requested or already passed? */
4093ca529d3STakashi Iwai 		if (anchor_nid <= 0)
410352f7f91STakashi Iwai 			goto found;
411352f7f91STakashi Iwai 	}
412352f7f91STakashi Iwai 	if (depth >= MAX_NID_PATH_DEPTH)
413352f7f91STakashi Iwai 		return false;
414352f7f91STakashi Iwai 	for (i = 0; i < nums; i++) {
415352f7f91STakashi Iwai 		unsigned int type;
416352f7f91STakashi Iwai 		type = get_wcaps_type(get_wcaps(codec, conn[i]));
417352f7f91STakashi Iwai 		if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
418352f7f91STakashi Iwai 		    type == AC_WID_PIN)
419352f7f91STakashi Iwai 			continue;
420352f7f91STakashi Iwai 		if (__parse_nid_path(codec, from_nid, conn[i],
4213ca529d3STakashi Iwai 				     anchor_nid, path, depth + 1))
422352f7f91STakashi Iwai 			goto found;
423352f7f91STakashi Iwai 	}
424352f7f91STakashi Iwai 	return false;
425352f7f91STakashi Iwai 
426352f7f91STakashi Iwai  found:
427352f7f91STakashi Iwai 	path->path[path->depth] = conn[i];
428352f7f91STakashi Iwai 	path->idx[path->depth + 1] = i;
429352f7f91STakashi Iwai 	if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
430352f7f91STakashi Iwai 		path->multi[path->depth + 1] = 1;
431352f7f91STakashi Iwai 	path->depth++;
432352f7f91STakashi Iwai 	return true;
433352f7f91STakashi Iwai }
434352f7f91STakashi Iwai 
435c4a58c30STakashi Iwai /*
436dda42bd0STakashi Iwai  * snd_hda_parse_nid_path - parse the widget path from the given nid to
437dda42bd0STakashi Iwai  * the target nid
438dda42bd0STakashi Iwai  * @codec: the HDA codec
439dda42bd0STakashi Iwai  * @from_nid: the NID where the path start from
440dda42bd0STakashi Iwai  * @to_nid: the NID where the path ends at
441dda42bd0STakashi Iwai  * @anchor_nid: the anchor indication
442dda42bd0STakashi Iwai  * @path: the path object to store the result
443dda42bd0STakashi Iwai  *
444dda42bd0STakashi Iwai  * Returns true if a matching path is found.
445dda42bd0STakashi Iwai  *
446dda42bd0STakashi Iwai  * The parsing behavior depends on parameters:
447352f7f91STakashi Iwai  * when @from_nid is 0, try to find an empty DAC;
4483ca529d3STakashi Iwai  * when @anchor_nid is set to a positive value, only paths through the widget
4493ca529d3STakashi Iwai  * with the given value are evaluated.
4503ca529d3STakashi Iwai  * when @anchor_nid is set to a negative value, paths through the widget
4513ca529d3STakashi Iwai  * with the negative of given value are excluded, only other paths are chosen.
4523ca529d3STakashi Iwai  * when @anchor_nid is zero, no special handling about path selection.
453352f7f91STakashi Iwai  */
snd_hda_parse_nid_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid,int anchor_nid,struct nid_path * path)454c4a58c30STakashi Iwai static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
4553ca529d3STakashi Iwai 			    hda_nid_t to_nid, int anchor_nid,
456352f7f91STakashi Iwai 			    struct nid_path *path)
457352f7f91STakashi Iwai {
4583ca529d3STakashi Iwai 	if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) {
459352f7f91STakashi Iwai 		path->path[path->depth] = to_nid;
460352f7f91STakashi Iwai 		path->depth++;
461352f7f91STakashi Iwai 		return true;
462352f7f91STakashi Iwai 	}
463352f7f91STakashi Iwai 	return false;
464352f7f91STakashi Iwai }
465352f7f91STakashi Iwai 
466dda42bd0STakashi Iwai /**
467dda42bd0STakashi Iwai  * snd_hda_add_new_path - parse the path between the given NIDs and
468dda42bd0STakashi Iwai  * add to the path list
469dda42bd0STakashi Iwai  * @codec: the HDA codec
470dda42bd0STakashi Iwai  * @from_nid: the NID where the path start from
471dda42bd0STakashi Iwai  * @to_nid: the NID where the path ends at
472dda42bd0STakashi Iwai  * @anchor_nid: the anchor indication, see snd_hda_parse_nid_path()
473dda42bd0STakashi Iwai  *
474dda42bd0STakashi Iwai  * If no valid path is found, returns NULL.
475352f7f91STakashi Iwai  */
476352f7f91STakashi Iwai struct nid_path *
snd_hda_add_new_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid,int anchor_nid)477352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
4783ca529d3STakashi Iwai 		     hda_nid_t to_nid, int anchor_nid)
479352f7f91STakashi Iwai {
480352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
481352f7f91STakashi Iwai 	struct nid_path *path;
482352f7f91STakashi Iwai 
483352f7f91STakashi Iwai 	if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
484352f7f91STakashi Iwai 		return NULL;
485352f7f91STakashi Iwai 
486f5172a7eSTakashi Iwai 	/* check whether the path has been already added */
4873ca529d3STakashi Iwai 	path = get_nid_path(codec, from_nid, to_nid, anchor_nid);
488f5172a7eSTakashi Iwai 	if (path)
489f5172a7eSTakashi Iwai 		return path;
490f5172a7eSTakashi Iwai 
491352f7f91STakashi Iwai 	path = snd_array_new(&spec->paths);
492352f7f91STakashi Iwai 	if (!path)
493352f7f91STakashi Iwai 		return NULL;
494352f7f91STakashi Iwai 	memset(path, 0, sizeof(*path));
4953ca529d3STakashi Iwai 	if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path))
496352f7f91STakashi Iwai 		return path;
497352f7f91STakashi Iwai 	/* push back */
498352f7f91STakashi Iwai 	spec->paths.used--;
499352f7f91STakashi Iwai 	return NULL;
500352f7f91STakashi Iwai }
5012698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_add_new_path);
502352f7f91STakashi Iwai 
503980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */
invalidate_nid_path(struct hda_codec * codec,int idx)504980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx)
505980428ceSTakashi Iwai {
506980428ceSTakashi Iwai 	struct nid_path *path = snd_hda_get_path_from_idx(codec, idx);
507980428ceSTakashi Iwai 	if (!path)
508980428ceSTakashi Iwai 		return;
509980428ceSTakashi Iwai 	memset(path, 0, sizeof(*path));
510980428ceSTakashi Iwai }
511980428ceSTakashi Iwai 
5123690739bSTakashi Iwai /* return a DAC if paired to the given pin by codec driver */
get_preferred_dac(struct hda_codec * codec,hda_nid_t pin)5133690739bSTakashi Iwai static hda_nid_t get_preferred_dac(struct hda_codec *codec, hda_nid_t pin)
5143690739bSTakashi Iwai {
5153690739bSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5163690739bSTakashi Iwai 	const hda_nid_t *list = spec->preferred_dacs;
5173690739bSTakashi Iwai 
5183690739bSTakashi Iwai 	if (!list)
5193690739bSTakashi Iwai 		return 0;
5203690739bSTakashi Iwai 	for (; *list; list += 2)
5213690739bSTakashi Iwai 		if (*list == pin)
5223690739bSTakashi Iwai 			return list[1];
5233690739bSTakashi Iwai 	return 0;
5243690739bSTakashi Iwai }
5253690739bSTakashi Iwai 
526352f7f91STakashi Iwai /* look for an empty DAC slot */
look_for_dac(struct hda_codec * codec,hda_nid_t pin,bool is_digital)527352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
528352f7f91STakashi Iwai 			      bool is_digital)
529352f7f91STakashi Iwai {
530352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
531352f7f91STakashi Iwai 	bool cap_digital;
532352f7f91STakashi Iwai 	int i;
533352f7f91STakashi Iwai 
534352f7f91STakashi Iwai 	for (i = 0; i < spec->num_all_dacs; i++) {
535352f7f91STakashi Iwai 		hda_nid_t nid = spec->all_dacs[i];
536352f7f91STakashi Iwai 		if (!nid || is_dac_already_used(codec, nid))
537352f7f91STakashi Iwai 			continue;
538352f7f91STakashi Iwai 		cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
539352f7f91STakashi Iwai 		if (is_digital != cap_digital)
540352f7f91STakashi Iwai 			continue;
541352f7f91STakashi Iwai 		if (is_reachable_path(codec, nid, pin))
542352f7f91STakashi Iwai 			return nid;
543352f7f91STakashi Iwai 	}
544352f7f91STakashi Iwai 	return 0;
545352f7f91STakashi Iwai }
546352f7f91STakashi Iwai 
547352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */
amp_val_replace_channels(unsigned int val,unsigned int chs)548352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
549352f7f91STakashi Iwai {
550352f7f91STakashi Iwai 	val &= ~(0x3U << 16);
551352f7f91STakashi Iwai 	val |= chs << 16;
552352f7f91STakashi Iwai 	return val;
553352f7f91STakashi Iwai }
554352f7f91STakashi Iwai 
same_amp_caps(struct hda_codec * codec,hda_nid_t nid1,hda_nid_t nid2,int dir)55599a5592dSDavid Henningsson static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
55699a5592dSDavid Henningsson 			  hda_nid_t nid2, int dir)
55799a5592dSDavid Henningsson {
55899a5592dSDavid Henningsson 	if (!(get_wcaps(codec, nid1) & (1 << (dir + 1))))
55999a5592dSDavid Henningsson 		return !(get_wcaps(codec, nid2) & (1 << (dir + 1)));
56099a5592dSDavid Henningsson 	return (query_amp_caps(codec, nid1, dir) ==
56199a5592dSDavid Henningsson 		query_amp_caps(codec, nid2, dir));
56299a5592dSDavid Henningsson }
56399a5592dSDavid Henningsson 
564352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */
look_for_out_mute_nid(struct hda_codec * codec,struct nid_path * path)565352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
566352f7f91STakashi Iwai 				       struct nid_path *path)
567352f7f91STakashi Iwai {
568352f7f91STakashi Iwai 	int i;
569352f7f91STakashi Iwai 
570352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
571352f7f91STakashi Iwai 		if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
572352f7f91STakashi Iwai 			return path->path[i];
573352f7f91STakashi Iwai 		if (i != path->depth - 1 && i != 0 &&
574352f7f91STakashi Iwai 		    nid_has_mute(codec, path->path[i], HDA_INPUT))
575352f7f91STakashi Iwai 			return path->path[i];
576352f7f91STakashi Iwai 	}
577352f7f91STakashi Iwai 	return 0;
578352f7f91STakashi Iwai }
579352f7f91STakashi Iwai 
580352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */
look_for_out_vol_nid(struct hda_codec * codec,struct nid_path * path)581352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
582352f7f91STakashi Iwai 				      struct nid_path *path)
583352f7f91STakashi Iwai {
584a1114a8cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
585352f7f91STakashi Iwai 	int i;
586352f7f91STakashi Iwai 
587352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
588a1114a8cSTakashi Iwai 		hda_nid_t nid = path->path[i];
589a1114a8cSTakashi Iwai 		if ((spec->out_vol_mask >> nid) & 1)
590a1114a8cSTakashi Iwai 			continue;
591a1114a8cSTakashi Iwai 		if (nid_has_volume(codec, nid, HDA_OUTPUT))
592a1114a8cSTakashi Iwai 			return nid;
593352f7f91STakashi Iwai 	}
594352f7f91STakashi Iwai 	return 0;
595352f7f91STakashi Iwai }
596352f7f91STakashi Iwai 
597352f7f91STakashi Iwai /*
598352f7f91STakashi Iwai  * path activation / deactivation
599352f7f91STakashi Iwai  */
600352f7f91STakashi Iwai 
601352f7f91STakashi Iwai /* can have the amp-in capability? */
has_amp_in(struct hda_codec * codec,struct nid_path * path,int idx)602352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
603352f7f91STakashi Iwai {
604352f7f91STakashi Iwai 	hda_nid_t nid = path->path[idx];
605352f7f91STakashi Iwai 	unsigned int caps = get_wcaps(codec, nid);
606352f7f91STakashi Iwai 	unsigned int type = get_wcaps_type(caps);
607352f7f91STakashi Iwai 
608352f7f91STakashi Iwai 	if (!(caps & AC_WCAP_IN_AMP))
609352f7f91STakashi Iwai 		return false;
610352f7f91STakashi Iwai 	if (type == AC_WID_PIN && idx > 0) /* only for input pins */
611352f7f91STakashi Iwai 		return false;
612352f7f91STakashi Iwai 	return true;
613352f7f91STakashi Iwai }
614352f7f91STakashi Iwai 
615352f7f91STakashi Iwai /* can have the amp-out capability? */
has_amp_out(struct hda_codec * codec,struct nid_path * path,int idx)616352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
617352f7f91STakashi Iwai {
618352f7f91STakashi Iwai 	hda_nid_t nid = path->path[idx];
619352f7f91STakashi Iwai 	unsigned int caps = get_wcaps(codec, nid);
620352f7f91STakashi Iwai 	unsigned int type = get_wcaps_type(caps);
621352f7f91STakashi Iwai 
622352f7f91STakashi Iwai 	if (!(caps & AC_WCAP_OUT_AMP))
623352f7f91STakashi Iwai 		return false;
624352f7f91STakashi Iwai 	if (type == AC_WID_PIN && !idx) /* only for output pins */
625352f7f91STakashi Iwai 		return false;
626352f7f91STakashi Iwai 	return true;
627352f7f91STakashi Iwai }
628352f7f91STakashi Iwai 
629352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */
is_active_nid(struct hda_codec * codec,hda_nid_t nid,unsigned int dir,unsigned int idx)630352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
6317dddf2aeSTakashi Iwai 			  unsigned int dir, unsigned int idx)
632352f7f91STakashi Iwai {
633352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
634e6feb5d0STakashi Iwai 	int type = get_wcaps_type(get_wcaps(codec, nid));
635a9c2dfc8STakashi Iwai 	const struct nid_path *path;
636352f7f91STakashi Iwai 	int i, n;
637352f7f91STakashi Iwai 
6387639a06cSTakashi Iwai 	if (nid == codec->core.afg)
6395ccf835cSTakashi Iwai 		return true;
6405ccf835cSTakashi Iwai 
641a9c2dfc8STakashi Iwai 	snd_array_for_each(&spec->paths, n, path) {
642352f7f91STakashi Iwai 		if (!path->active)
643352f7f91STakashi Iwai 			continue;
644967b1307STakashi Iwai 		if (codec->power_save_node) {
645e6feb5d0STakashi Iwai 			if (!path->stream_enabled)
646e6feb5d0STakashi Iwai 				continue;
647e6feb5d0STakashi Iwai 			/* ignore unplugged paths except for DAC/ADC */
6486b275b14STakashi Iwai 			if (!(path->pin_enabled || path->pin_fixed) &&
649e6feb5d0STakashi Iwai 			    type != AC_WID_AUD_OUT && type != AC_WID_AUD_IN)
650e6feb5d0STakashi Iwai 				continue;
651e6feb5d0STakashi Iwai 		}
652352f7f91STakashi Iwai 		for (i = 0; i < path->depth; i++) {
653352f7f91STakashi Iwai 			if (path->path[i] == nid) {
6549d2b48f7STakashi Iwai 				if (dir == HDA_OUTPUT || idx == -1 ||
6559d2b48f7STakashi Iwai 				    path->idx[i] == idx)
656352f7f91STakashi Iwai 					return true;
657352f7f91STakashi Iwai 				break;
658352f7f91STakashi Iwai 			}
659352f7f91STakashi Iwai 		}
660352f7f91STakashi Iwai 	}
661352f7f91STakashi Iwai 	return false;
662352f7f91STakashi Iwai }
663352f7f91STakashi Iwai 
664b1b9fbd0STakashi Iwai /* check whether the NID is referred by any active paths */
665b1b9fbd0STakashi Iwai #define is_active_nid_for_any(codec, nid) \
6669d2b48f7STakashi Iwai 	is_active_nid(codec, nid, HDA_OUTPUT, -1)
667b1b9fbd0STakashi Iwai 
668352f7f91STakashi Iwai /* get the default amp value for the target state */
get_amp_val_to_activate(struct hda_codec * codec,hda_nid_t nid,int dir,unsigned int caps,bool enable)669352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
6708999bf0aSTakashi Iwai 				   int dir, unsigned int caps, bool enable)
671352f7f91STakashi Iwai {
672352f7f91STakashi Iwai 	unsigned int val = 0;
673352f7f91STakashi Iwai 
674352f7f91STakashi Iwai 	if (caps & AC_AMPCAP_NUM_STEPS) {
675352f7f91STakashi Iwai 		/* set to 0dB */
676352f7f91STakashi Iwai 		if (enable)
677352f7f91STakashi Iwai 			val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
678352f7f91STakashi Iwai 	}
679f69910ddSTakashi Iwai 	if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
680352f7f91STakashi Iwai 		if (!enable)
681352f7f91STakashi Iwai 			val |= HDA_AMP_MUTE;
682352f7f91STakashi Iwai 	}
683352f7f91STakashi Iwai 	return val;
684352f7f91STakashi Iwai }
685352f7f91STakashi Iwai 
686cc261738STakashi Iwai /* is this a stereo widget or a stereo-to-mono mix? */
is_stereo_amps(struct hda_codec * codec,hda_nid_t nid,int dir)687cc261738STakashi Iwai static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
688cc261738STakashi Iwai {
689cc261738STakashi Iwai 	unsigned int wcaps = get_wcaps(codec, nid);
690cc261738STakashi Iwai 	hda_nid_t conn;
691cc261738STakashi Iwai 
692cc261738STakashi Iwai 	if (wcaps & AC_WCAP_STEREO)
693cc261738STakashi Iwai 		return true;
694cc261738STakashi Iwai 	if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
695cc261738STakashi Iwai 		return false;
696cc261738STakashi Iwai 	if (snd_hda_get_num_conns(codec, nid) != 1)
697cc261738STakashi Iwai 		return false;
698cc261738STakashi Iwai 	if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
699cc261738STakashi Iwai 		return false;
700cc261738STakashi Iwai 	return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
701cc261738STakashi Iwai }
702cc261738STakashi Iwai 
703352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */
init_amp(struct hda_codec * codec,hda_nid_t nid,int dir,int idx)704352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
705352f7f91STakashi Iwai {
7068999bf0aSTakashi Iwai 	unsigned int caps = query_amp_caps(codec, nid, dir);
7078999bf0aSTakashi Iwai 	int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
708ef403edbSTakashi Iwai 
709cc261738STakashi Iwai 	if (is_stereo_amps(codec, nid, dir))
710352f7f91STakashi Iwai 		snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
711ef403edbSTakashi Iwai 	else
712ef403edbSTakashi Iwai 		snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
713ef403edbSTakashi Iwai }
714ef403edbSTakashi Iwai 
715ef403edbSTakashi Iwai /* update the amp, doing in stereo or mono depending on NID */
update_amp(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,unsigned int mask,unsigned int val)716ef403edbSTakashi Iwai static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
717ef403edbSTakashi Iwai 		      unsigned int mask, unsigned int val)
718ef403edbSTakashi Iwai {
719cc261738STakashi Iwai 	if (is_stereo_amps(codec, nid, dir))
720ef403edbSTakashi Iwai 		return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
721ef403edbSTakashi Iwai 						mask, val);
722ef403edbSTakashi Iwai 	else
723ef403edbSTakashi Iwai 		return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
724ef403edbSTakashi Iwai 						mask, val);
725352f7f91STakashi Iwai }
726352f7f91STakashi Iwai 
7278999bf0aSTakashi Iwai /* calculate amp value mask we can modify;
7288999bf0aSTakashi Iwai  * if the given amp is controlled by mixers, don't touch it
7298999bf0aSTakashi Iwai  */
get_amp_mask_to_modify(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,unsigned int caps)7308999bf0aSTakashi Iwai static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
7318999bf0aSTakashi Iwai 					   hda_nid_t nid, int dir, int idx,
7328999bf0aSTakashi Iwai 					   unsigned int caps)
733352f7f91STakashi Iwai {
7348999bf0aSTakashi Iwai 	unsigned int mask = 0xff;
7358999bf0aSTakashi Iwai 
736f69910ddSTakashi Iwai 	if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
7378999bf0aSTakashi Iwai 		if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
7388999bf0aSTakashi Iwai 			mask &= ~0x80;
7398999bf0aSTakashi Iwai 	}
7408999bf0aSTakashi Iwai 	if (caps & AC_AMPCAP_NUM_STEPS) {
7418999bf0aSTakashi Iwai 		if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
7428999bf0aSTakashi Iwai 		    is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
7438999bf0aSTakashi Iwai 			mask &= ~0x7f;
7448999bf0aSTakashi Iwai 	}
7458999bf0aSTakashi Iwai 	return mask;
7468999bf0aSTakashi Iwai }
7478999bf0aSTakashi Iwai 
activate_amp(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,int idx_to_check,bool enable)7488999bf0aSTakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
7498999bf0aSTakashi Iwai 			 int idx, int idx_to_check, bool enable)
7508999bf0aSTakashi Iwai {
7518999bf0aSTakashi Iwai 	unsigned int caps;
7528999bf0aSTakashi Iwai 	unsigned int mask, val;
7538999bf0aSTakashi Iwai 
7548999bf0aSTakashi Iwai 	caps = query_amp_caps(codec, nid, dir);
7558999bf0aSTakashi Iwai 	val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
7568999bf0aSTakashi Iwai 	mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
7578999bf0aSTakashi Iwai 	if (!mask)
7588999bf0aSTakashi Iwai 		return;
7598999bf0aSTakashi Iwai 
7608999bf0aSTakashi Iwai 	val &= mask;
761ef403edbSTakashi Iwai 	update_amp(codec, nid, dir, idx, mask, val);
762352f7f91STakashi Iwai }
763352f7f91STakashi Iwai 
check_and_activate_amp(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,int idx_to_check,bool enable)764e7fdd527STakashi Iwai static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid,
765e7fdd527STakashi Iwai 				   int dir, int idx, int idx_to_check,
766e7fdd527STakashi Iwai 				   bool enable)
767e7fdd527STakashi Iwai {
768e7fdd527STakashi Iwai 	/* check whether the given amp is still used by others */
769e7fdd527STakashi Iwai 	if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
770e7fdd527STakashi Iwai 		return;
771e7fdd527STakashi Iwai 	activate_amp(codec, nid, dir, idx, idx_to_check, enable);
772e7fdd527STakashi Iwai }
773e7fdd527STakashi Iwai 
activate_amp_out(struct hda_codec * codec,struct nid_path * path,int i,bool enable)774352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
775352f7f91STakashi Iwai 			     int i, bool enable)
776352f7f91STakashi Iwai {
777352f7f91STakashi Iwai 	hda_nid_t nid = path->path[i];
778352f7f91STakashi Iwai 	init_amp(codec, nid, HDA_OUTPUT, 0);
779e7fdd527STakashi Iwai 	check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
780352f7f91STakashi Iwai }
781352f7f91STakashi Iwai 
activate_amp_in(struct hda_codec * codec,struct nid_path * path,int i,bool enable,bool add_aamix)782352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
783352f7f91STakashi Iwai 			    int i, bool enable, bool add_aamix)
784352f7f91STakashi Iwai {
785352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
786ee8e765bSTakashi Iwai 	const hda_nid_t *conn;
787352f7f91STakashi Iwai 	int n, nums, idx;
788352f7f91STakashi Iwai 	int type;
789352f7f91STakashi Iwai 	hda_nid_t nid = path->path[i];
790352f7f91STakashi Iwai 
791ee8e765bSTakashi Iwai 	nums = snd_hda_get_conn_list(codec, nid, &conn);
7920de7d835SDan Carpenter 	if (nums < 0)
7930de7d835SDan Carpenter 		return;
794352f7f91STakashi Iwai 	type = get_wcaps_type(get_wcaps(codec, nid));
795352f7f91STakashi Iwai 	if (type == AC_WID_PIN ||
796352f7f91STakashi Iwai 	    (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
797352f7f91STakashi Iwai 		nums = 1;
798352f7f91STakashi Iwai 		idx = 0;
799352f7f91STakashi Iwai 	} else
800352f7f91STakashi Iwai 		idx = path->idx[i];
801352f7f91STakashi Iwai 
802352f7f91STakashi Iwai 	for (n = 0; n < nums; n++)
803352f7f91STakashi Iwai 		init_amp(codec, nid, HDA_INPUT, n);
804352f7f91STakashi Iwai 
805352f7f91STakashi Iwai 	/* here is a little bit tricky in comparison with activate_amp_out();
806352f7f91STakashi Iwai 	 * when aa-mixer is available, we need to enable the path as well
807352f7f91STakashi Iwai 	 */
808352f7f91STakashi Iwai 	for (n = 0; n < nums; n++) {
809e7fdd527STakashi Iwai 		if (n != idx) {
810e7fdd527STakashi Iwai 			if (conn[n] != spec->mixer_merge_nid)
811352f7f91STakashi Iwai 				continue;
812e7fdd527STakashi Iwai 			/* when aamix is disabled, force to off */
813e7fdd527STakashi Iwai 			if (!add_aamix) {
814e7fdd527STakashi Iwai 				activate_amp(codec, nid, HDA_INPUT, n, n, false);
815e7fdd527STakashi Iwai 				continue;
816e7fdd527STakashi Iwai 			}
817e7fdd527STakashi Iwai 		}
818e7fdd527STakashi Iwai 		check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
819352f7f91STakashi Iwai 	}
820352f7f91STakashi Iwai }
821352f7f91STakashi Iwai 
822c7fabbc5SRandy Dunlap /* sync power of each widget in the given path */
path_power_update(struct hda_codec * codec,struct nid_path * path,bool allow_powerdown)823e6feb5d0STakashi Iwai static hda_nid_t path_power_update(struct hda_codec *codec,
824e6feb5d0STakashi Iwai 				   struct nid_path *path,
825e6feb5d0STakashi Iwai 				   bool allow_powerdown)
826e6feb5d0STakashi Iwai {
827e6feb5d0STakashi Iwai 	hda_nid_t nid, changed = 0;
82850fd4987STakashi Iwai 	int i, state, power;
829e6feb5d0STakashi Iwai 
830e6feb5d0STakashi Iwai 	for (i = 0; i < path->depth; i++) {
831e6feb5d0STakashi Iwai 		nid = path->path[i];
8322206dc94STakashi Iwai 		if (!(get_wcaps(codec, nid) & AC_WCAP_POWER))
8332206dc94STakashi Iwai 			continue;
8347639a06cSTakashi Iwai 		if (nid == codec->core.afg)
8355ccf835cSTakashi Iwai 			continue;
836e6feb5d0STakashi Iwai 		if (!allow_powerdown || is_active_nid_for_any(codec, nid))
837e6feb5d0STakashi Iwai 			state = AC_PWRST_D0;
838e6feb5d0STakashi Iwai 		else
839e6feb5d0STakashi Iwai 			state = AC_PWRST_D3;
84050fd4987STakashi Iwai 		power = snd_hda_codec_read(codec, nid, 0,
84150fd4987STakashi Iwai 					   AC_VERB_GET_POWER_STATE, 0);
84250fd4987STakashi Iwai 		if (power != (state | (state << 4))) {
843e6feb5d0STakashi Iwai 			snd_hda_codec_write(codec, nid, 0,
844e6feb5d0STakashi Iwai 					    AC_VERB_SET_POWER_STATE, state);
845e6feb5d0STakashi Iwai 			changed = nid;
84648f4b3a2STakashi Iwai 			/* all known codecs seem to be capable to handl
84748f4b3a2STakashi Iwai 			 * widgets state even in D3, so far.
84848f4b3a2STakashi Iwai 			 * if any new codecs need to restore the widget
84948f4b3a2STakashi Iwai 			 * states after D0 transition, call the function
85048f4b3a2STakashi Iwai 			 * below.
85148f4b3a2STakashi Iwai 			 */
85248f4b3a2STakashi Iwai #if 0 /* disabled */
853d545a57cSTakashi Iwai 			if (state == AC_PWRST_D0)
854d545a57cSTakashi Iwai 				snd_hdac_regmap_sync_node(&codec->core, nid);
85548f4b3a2STakashi Iwai #endif
856e6feb5d0STakashi Iwai 		}
857e6feb5d0STakashi Iwai 	}
858e6feb5d0STakashi Iwai 	return changed;
859e6feb5d0STakashi Iwai }
860e6feb5d0STakashi Iwai 
861e6feb5d0STakashi Iwai /* do sync with the last power state change */
sync_power_state_change(struct hda_codec * codec,hda_nid_t nid)862e6feb5d0STakashi Iwai static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid)
863e6feb5d0STakashi Iwai {
864e6feb5d0STakashi Iwai 	if (nid) {
865e6feb5d0STakashi Iwai 		msleep(10);
866e6feb5d0STakashi Iwai 		snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
867e6feb5d0STakashi Iwai 	}
868e6feb5d0STakashi Iwai }
869e6feb5d0STakashi Iwai 
870dda42bd0STakashi Iwai /**
871dda42bd0STakashi Iwai  * snd_hda_activate_path - activate or deactivate the given path
872dda42bd0STakashi Iwai  * @codec: the HDA codec
873dda42bd0STakashi Iwai  * @path: the path to activate/deactivate
874dda42bd0STakashi Iwai  * @enable: flag to activate or not
875dda42bd0STakashi Iwai  * @add_aamix: enable the input from aamix NID
876dda42bd0STakashi Iwai  *
877dda42bd0STakashi Iwai  * If @add_aamix is set, enable the input from aa-mix NID as well (if any).
878352f7f91STakashi Iwai  */
snd_hda_activate_path(struct hda_codec * codec,struct nid_path * path,bool enable,bool add_aamix)879352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
880352f7f91STakashi Iwai 			   bool enable, bool add_aamix)
881352f7f91STakashi Iwai {
88255196fffSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
883352f7f91STakashi Iwai 	int i;
884352f7f91STakashi Iwai 
885c7cd0ef6STakashi Iwai 	path->active = enable;
886352f7f91STakashi Iwai 
887e6feb5d0STakashi Iwai 	/* make sure the widget is powered up */
888967b1307STakashi Iwai 	if (enable && (spec->power_down_unused || codec->power_save_node))
889967b1307STakashi Iwai 		path_power_update(codec, path, codec->power_save_node);
890e6feb5d0STakashi Iwai 
891352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
89255196fffSTakashi Iwai 		hda_nid_t nid = path->path[i];
893e6feb5d0STakashi Iwai 
894352f7f91STakashi Iwai 		if (enable && path->multi[i])
895401caff7STakashi Iwai 			snd_hda_codec_write_cache(codec, nid, 0,
896352f7f91STakashi Iwai 					    AC_VERB_SET_CONNECT_SEL,
897352f7f91STakashi Iwai 					    path->idx[i]);
898352f7f91STakashi Iwai 		if (has_amp_in(codec, path, i))
899352f7f91STakashi Iwai 			activate_amp_in(codec, path, i, enable, add_aamix);
900352f7f91STakashi Iwai 		if (has_amp_out(codec, path, i))
901352f7f91STakashi Iwai 			activate_amp_out(codec, path, i, enable);
902352f7f91STakashi Iwai 	}
903352f7f91STakashi Iwai }
9042698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_activate_path);
905352f7f91STakashi Iwai 
90655196fffSTakashi Iwai /* if the given path is inactive, put widgets into D3 (only if suitable) */
path_power_down_sync(struct hda_codec * codec,struct nid_path * path)90755196fffSTakashi Iwai static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
90855196fffSTakashi Iwai {
90955196fffSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
91055196fffSTakashi Iwai 
911967b1307STakashi Iwai 	if (!(spec->power_down_unused || codec->power_save_node) || path->active)
91255196fffSTakashi Iwai 		return;
913e6feb5d0STakashi Iwai 	sync_power_state_change(codec, path_power_update(codec, path, true));
91455196fffSTakashi Iwai }
91555196fffSTakashi Iwai 
916d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */
set_pin_eapd(struct hda_codec * codec,hda_nid_t pin,bool enable)917d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
918d5a9f1bbSTakashi Iwai {
919d5a9f1bbSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
920d5a9f1bbSTakashi Iwai 	if (spec->own_eapd_ctl ||
921d5a9f1bbSTakashi Iwai 	    !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
922d5a9f1bbSTakashi Iwai 		return;
92305909d5cSTakashi Iwai 	if (spec->keep_eapd_on && !enable)
92405909d5cSTakashi Iwai 		return;
925468ac413STakashi Iwai 	if (codec->inv_eapd)
926468ac413STakashi Iwai 		enable = !enable;
927401caff7STakashi Iwai 	snd_hda_codec_write_cache(codec, pin, 0,
928d5a9f1bbSTakashi Iwai 				   AC_VERB_SET_EAPD_BTLENABLE,
929d5a9f1bbSTakashi Iwai 				   enable ? 0x02 : 0x00);
930d5a9f1bbSTakashi Iwai }
931d5a9f1bbSTakashi Iwai 
9323e367f15STakashi Iwai /* re-initialize the path specified by the given path index */
resume_path_from_idx(struct hda_codec * codec,int path_idx)9333e367f15STakashi Iwai static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
9343e367f15STakashi Iwai {
9353e367f15STakashi Iwai 	struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
9363e367f15STakashi Iwai 	if (path)
9373e367f15STakashi Iwai 		snd_hda_activate_path(codec, path, path->active, false);
9383e367f15STakashi Iwai }
9393e367f15STakashi Iwai 
940352f7f91STakashi Iwai 
941352f7f91STakashi Iwai /*
942352f7f91STakashi Iwai  * Helper functions for creating mixer ctl elements
943352f7f91STakashi Iwai  */
944352f7f91STakashi Iwai 
9457eebffd3STakashi Iwai static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
9467eebffd3STakashi Iwai 				  struct snd_ctl_elem_value *ucontrol);
947698f5ee3STakashi Iwai static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
948698f5ee3STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol);
949bc2eee29STakashi Iwai static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
950bc2eee29STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol);
9517eebffd3STakashi Iwai 
952352f7f91STakashi Iwai enum {
953352f7f91STakashi Iwai 	HDA_CTL_WIDGET_VOL,
954352f7f91STakashi Iwai 	HDA_CTL_WIDGET_MUTE,
955352f7f91STakashi Iwai 	HDA_CTL_BIND_MUTE,
956352f7f91STakashi Iwai };
957352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = {
958352f7f91STakashi Iwai 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
9597eebffd3STakashi Iwai 	/* only the put callback is replaced for handling the special mute */
9607eebffd3STakashi Iwai 	{
9617eebffd3STakashi Iwai 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9627eebffd3STakashi Iwai 		.subdevice = HDA_SUBDEV_AMP_FLAG,
9637eebffd3STakashi Iwai 		.info = snd_hda_mixer_amp_switch_info,
9647eebffd3STakashi Iwai 		.get = snd_hda_mixer_amp_switch_get,
9657eebffd3STakashi Iwai 		.put = hda_gen_mixer_mute_put, /* replaced */
9667eebffd3STakashi Iwai 		.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
9677eebffd3STakashi Iwai 	},
968bc2eee29STakashi Iwai 	{
969bc2eee29STakashi Iwai 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
970bc2eee29STakashi Iwai 		.info = snd_hda_mixer_amp_switch_info,
971698f5ee3STakashi Iwai 		.get = hda_gen_bind_mute_get,
972bc2eee29STakashi Iwai 		.put = hda_gen_bind_mute_put, /* replaced */
973bc2eee29STakashi Iwai 		.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
974bc2eee29STakashi Iwai 	},
975352f7f91STakashi Iwai };
976352f7f91STakashi Iwai 
977352f7f91STakashi Iwai /* add dynamic controls from template */
978a35bd1e3STakashi Iwai static struct snd_kcontrol_new *
add_control(struct hda_gen_spec * spec,int type,const char * name,int cidx,unsigned long val)979a35bd1e3STakashi Iwai add_control(struct hda_gen_spec *spec, int type, const char *name,
980352f7f91STakashi Iwai 		       int cidx, unsigned long val)
981352f7f91STakashi Iwai {
982352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew;
983352f7f91STakashi Iwai 
98412c93df6STakashi Iwai 	knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
985352f7f91STakashi Iwai 	if (!knew)
986a35bd1e3STakashi Iwai 		return NULL;
987352f7f91STakashi Iwai 	knew->index = cidx;
988352f7f91STakashi Iwai 	if (get_amp_nid_(val))
989352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
990e65bf997SJaroslav Kysela 	if (knew->access == 0)
991e65bf997SJaroslav Kysela 		knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
992352f7f91STakashi Iwai 	knew->private_value = val;
993a35bd1e3STakashi Iwai 	return knew;
994352f7f91STakashi Iwai }
995352f7f91STakashi Iwai 
add_control_with_pfx(struct hda_gen_spec * spec,int type,const char * pfx,const char * dir,const char * sfx,int cidx,unsigned long val)996352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
997352f7f91STakashi Iwai 				const char *pfx, const char *dir,
998352f7f91STakashi Iwai 				const char *sfx, int cidx, unsigned long val)
999352f7f91STakashi Iwai {
1000975cc02aSTakashi Iwai 	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1001*5f6af005STakashi Iwai 	int len;
1002*5f6af005STakashi Iwai 
1003*5f6af005STakashi Iwai 	len = snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
1004*5f6af005STakashi Iwai 	if (snd_BUG_ON(len >= sizeof(name)))
1005*5f6af005STakashi Iwai 		return -EINVAL;
1006a35bd1e3STakashi Iwai 	if (!add_control(spec, type, name, cidx, val))
1007a35bd1e3STakashi Iwai 		return -ENOMEM;
1008a35bd1e3STakashi Iwai 	return 0;
1009352f7f91STakashi Iwai }
1010352f7f91STakashi Iwai 
1011352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val)			\
1012352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
1013352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val)			\
1014352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
1015352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)			\
1016352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
1017352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)			\
1018352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
1019352f7f91STakashi Iwai 
add_vol_ctl(struct hda_codec * codec,const char * pfx,int cidx,unsigned int chs,struct nid_path * path)1020352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx,
1021352f7f91STakashi Iwai 		       unsigned int chs, struct nid_path *path)
1022352f7f91STakashi Iwai {
1023352f7f91STakashi Iwai 	unsigned int val;
1024352f7f91STakashi Iwai 	if (!path)
1025352f7f91STakashi Iwai 		return 0;
1026352f7f91STakashi Iwai 	val = path->ctls[NID_PATH_VOL_CTL];
1027352f7f91STakashi Iwai 	if (!val)
1028352f7f91STakashi Iwai 		return 0;
1029352f7f91STakashi Iwai 	val = amp_val_replace_channels(val, chs);
1030352f7f91STakashi Iwai 	return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val);
1031352f7f91STakashi Iwai }
1032352f7f91STakashi Iwai 
1033352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */
get_default_ch_nums(struct hda_codec * codec,struct nid_path * path,int type)1034352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
1035352f7f91STakashi Iwai 			       int type)
1036352f7f91STakashi Iwai {
1037352f7f91STakashi Iwai 	int chs = 1; /* mono (left only) */
1038352f7f91STakashi Iwai 	if (path) {
1039352f7f91STakashi Iwai 		hda_nid_t nid = get_amp_nid_(path->ctls[type]);
1040352f7f91STakashi Iwai 		if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
1041352f7f91STakashi Iwai 			chs = 3; /* stereo */
1042352f7f91STakashi Iwai 	}
1043352f7f91STakashi Iwai 	return chs;
1044352f7f91STakashi Iwai }
1045352f7f91STakashi Iwai 
add_stereo_vol(struct hda_codec * codec,const char * pfx,int cidx,struct nid_path * path)1046352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx,
1047352f7f91STakashi Iwai 			  struct nid_path *path)
1048352f7f91STakashi Iwai {
1049352f7f91STakashi Iwai 	int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
1050352f7f91STakashi Iwai 	return add_vol_ctl(codec, pfx, cidx, chs, path);
1051352f7f91STakashi Iwai }
1052352f7f91STakashi Iwai 
1053352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget;
1054352f7f91STakashi Iwai  * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
1055352f7f91STakashi Iwai  */
add_sw_ctl(struct hda_codec * codec,const char * pfx,int cidx,unsigned int chs,struct nid_path * path)1056352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx,
1057352f7f91STakashi Iwai 		      unsigned int chs, struct nid_path *path)
1058352f7f91STakashi Iwai {
1059352f7f91STakashi Iwai 	unsigned int val;
1060352f7f91STakashi Iwai 	int type = HDA_CTL_WIDGET_MUTE;
1061352f7f91STakashi Iwai 
1062352f7f91STakashi Iwai 	if (!path)
1063352f7f91STakashi Iwai 		return 0;
1064352f7f91STakashi Iwai 	val = path->ctls[NID_PATH_MUTE_CTL];
1065352f7f91STakashi Iwai 	if (!val)
1066352f7f91STakashi Iwai 		return 0;
1067352f7f91STakashi Iwai 	val = amp_val_replace_channels(val, chs);
1068352f7f91STakashi Iwai 	if (get_amp_direction_(val) == HDA_INPUT) {
1069352f7f91STakashi Iwai 		hda_nid_t nid = get_amp_nid_(val);
1070352f7f91STakashi Iwai 		int nums = snd_hda_get_num_conns(codec, nid);
1071352f7f91STakashi Iwai 		if (nums > 1) {
1072352f7f91STakashi Iwai 			type = HDA_CTL_BIND_MUTE;
1073352f7f91STakashi Iwai 			val |= nums << 19;
1074352f7f91STakashi Iwai 		}
1075352f7f91STakashi Iwai 	}
1076352f7f91STakashi Iwai 	return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
1077352f7f91STakashi Iwai }
1078352f7f91STakashi Iwai 
add_stereo_sw(struct hda_codec * codec,const char * pfx,int cidx,struct nid_path * path)1079352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
1080352f7f91STakashi Iwai 				  int cidx, struct nid_path *path)
1081352f7f91STakashi Iwai {
1082352f7f91STakashi Iwai 	int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
1083352f7f91STakashi Iwai 	return add_sw_ctl(codec, pfx, cidx, chs, path);
1084352f7f91STakashi Iwai }
1085352f7f91STakashi Iwai 
10867eebffd3STakashi Iwai /* playback mute control with the software mute bit check */
sync_auto_mute_bits(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1087bc2eee29STakashi Iwai static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol,
10887eebffd3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
10897eebffd3STakashi Iwai {
10907eebffd3STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10917eebffd3STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
10927eebffd3STakashi Iwai 
10937eebffd3STakashi Iwai 	if (spec->auto_mute_via_amp) {
10947eebffd3STakashi Iwai 		hda_nid_t nid = get_amp_nid(kcontrol);
10957eebffd3STakashi Iwai 		bool enabled = !((spec->mute_bits >> nid) & 1);
10967eebffd3STakashi Iwai 		ucontrol->value.integer.value[0] &= enabled;
10977eebffd3STakashi Iwai 		ucontrol->value.integer.value[1] &= enabled;
10987eebffd3STakashi Iwai 	}
1099bc2eee29STakashi Iwai }
11007eebffd3STakashi Iwai 
hda_gen_mixer_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1101bc2eee29STakashi Iwai static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
1102bc2eee29STakashi Iwai 				  struct snd_ctl_elem_value *ucontrol)
1103bc2eee29STakashi Iwai {
1104bc2eee29STakashi Iwai 	sync_auto_mute_bits(kcontrol, ucontrol);
11057eebffd3STakashi Iwai 	return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
11067eebffd3STakashi Iwai }
11077eebffd3STakashi Iwai 
1108698f5ee3STakashi Iwai /*
1109698f5ee3STakashi Iwai  * Bound mute controls
1110698f5ee3STakashi Iwai  */
1111698f5ee3STakashi Iwai #define AMP_VAL_IDX_SHIFT	19
1112698f5ee3STakashi Iwai #define AMP_VAL_IDX_MASK	(0x0f<<19)
1113698f5ee3STakashi Iwai 
hda_gen_bind_mute_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1114698f5ee3STakashi Iwai static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
1115698f5ee3STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
1116698f5ee3STakashi Iwai {
1117698f5ee3STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1118698f5ee3STakashi Iwai 	unsigned long pval;
1119698f5ee3STakashi Iwai 	int err;
1120698f5ee3STakashi Iwai 
1121698f5ee3STakashi Iwai 	mutex_lock(&codec->control_mutex);
1122698f5ee3STakashi Iwai 	pval = kcontrol->private_value;
1123698f5ee3STakashi Iwai 	kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
1124698f5ee3STakashi Iwai 	err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
1125698f5ee3STakashi Iwai 	kcontrol->private_value = pval;
1126698f5ee3STakashi Iwai 	mutex_unlock(&codec->control_mutex);
1127698f5ee3STakashi Iwai 	return err;
1128698f5ee3STakashi Iwai }
1129698f5ee3STakashi Iwai 
hda_gen_bind_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1130bc2eee29STakashi Iwai static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
1131bc2eee29STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
1132bc2eee29STakashi Iwai {
1133698f5ee3STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1134698f5ee3STakashi Iwai 	unsigned long pval;
1135698f5ee3STakashi Iwai 	int i, indices, err = 0, change = 0;
1136698f5ee3STakashi Iwai 
1137bc2eee29STakashi Iwai 	sync_auto_mute_bits(kcontrol, ucontrol);
1138698f5ee3STakashi Iwai 
1139698f5ee3STakashi Iwai 	mutex_lock(&codec->control_mutex);
1140698f5ee3STakashi Iwai 	pval = kcontrol->private_value;
1141698f5ee3STakashi Iwai 	indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
1142698f5ee3STakashi Iwai 	for (i = 0; i < indices; i++) {
1143698f5ee3STakashi Iwai 		kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) |
1144698f5ee3STakashi Iwai 			(i << AMP_VAL_IDX_SHIFT);
1145698f5ee3STakashi Iwai 		err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
1146698f5ee3STakashi Iwai 		if (err < 0)
1147698f5ee3STakashi Iwai 			break;
1148698f5ee3STakashi Iwai 		change |= err;
1149698f5ee3STakashi Iwai 	}
1150698f5ee3STakashi Iwai 	kcontrol->private_value = pval;
1151698f5ee3STakashi Iwai 	mutex_unlock(&codec->control_mutex);
1152698f5ee3STakashi Iwai 	return err < 0 ? err : change;
1153bc2eee29STakashi Iwai }
1154bc2eee29STakashi Iwai 
1155247d85eeSTakashi Iwai /* any ctl assigned to the path with the given index? */
path_has_mixer(struct hda_codec * codec,int path_idx,int ctl_type)1156247d85eeSTakashi Iwai static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
1157247d85eeSTakashi Iwai {
1158247d85eeSTakashi Iwai 	struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
1159247d85eeSTakashi Iwai 	return path && path->ctls[ctl_type];
1160247d85eeSTakashi Iwai }
1161247d85eeSTakashi Iwai 
11623b44ec8cSTakashi Iwai static const char * const channel_name[] = {
11633b44ec8cSTakashi Iwai 	"Front", "Surround", "CLFE", "Side", "Back",
1164352f7f91STakashi Iwai };
1165352f7f91STakashi Iwai 
1166352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */
get_line_out_pfx(struct hda_codec * codec,int ch,int * index,int ctl_type)1167247d85eeSTakashi Iwai static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
1168247d85eeSTakashi Iwai 				    int *index, int ctl_type)
1169352f7f91STakashi Iwai {
1170247d85eeSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1171352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1172352f7f91STakashi Iwai 
1173352f7f91STakashi Iwai 	*index = 0;
1174352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && !spec->multi_ios &&
11759f3dadb1STakashi Iwai 	    !codec->force_pin_prefix &&
1176247d85eeSTakashi Iwai 	    !cfg->hp_outs && !cfg->speaker_outs)
1177352f7f91STakashi Iwai 		return spec->vmaster_mute.hook ? "PCM" : "Master";
1178352f7f91STakashi Iwai 
1179352f7f91STakashi Iwai 	/* if there is really a single DAC used in the whole output paths,
1180352f7f91STakashi Iwai 	 * use it master (or "PCM" if a vmaster hook is present)
1181352f7f91STakashi Iwai 	 */
1182352f7f91STakashi Iwai 	if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
11839f3dadb1STakashi Iwai 	    !codec->force_pin_prefix &&
1184352f7f91STakashi Iwai 	    !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
1185352f7f91STakashi Iwai 		return spec->vmaster_mute.hook ? "PCM" : "Master";
1186352f7f91STakashi Iwai 
1187247d85eeSTakashi Iwai 	/* multi-io channels */
1188247d85eeSTakashi Iwai 	if (ch >= cfg->line_outs)
11893b44ec8cSTakashi Iwai 		goto fixed_name;
1190247d85eeSTakashi Iwai 
1191352f7f91STakashi Iwai 	switch (cfg->line_out_type) {
1192352f7f91STakashi Iwai 	case AUTO_PIN_SPEAKER_OUT:
1193247d85eeSTakashi Iwai 		/* if the primary channel vol/mute is shared with HP volume,
1194247d85eeSTakashi Iwai 		 * don't name it as Speaker
1195247d85eeSTakashi Iwai 		 */
1196247d85eeSTakashi Iwai 		if (!ch && cfg->hp_outs &&
1197247d85eeSTakashi Iwai 		    !path_has_mixer(codec, spec->hp_paths[0], ctl_type))
1198247d85eeSTakashi Iwai 			break;
1199352f7f91STakashi Iwai 		if (cfg->line_outs == 1)
1200352f7f91STakashi Iwai 			return "Speaker";
1201352f7f91STakashi Iwai 		if (cfg->line_outs == 2)
1202352f7f91STakashi Iwai 			return ch ? "Bass Speaker" : "Speaker";
1203352f7f91STakashi Iwai 		break;
1204352f7f91STakashi Iwai 	case AUTO_PIN_HP_OUT:
1205247d85eeSTakashi Iwai 		/* if the primary channel vol/mute is shared with spk volume,
1206247d85eeSTakashi Iwai 		 * don't name it as Headphone
1207247d85eeSTakashi Iwai 		 */
1208247d85eeSTakashi Iwai 		if (!ch && cfg->speaker_outs &&
1209247d85eeSTakashi Iwai 		    !path_has_mixer(codec, spec->speaker_paths[0], ctl_type))
1210247d85eeSTakashi Iwai 			break;
1211352f7f91STakashi Iwai 		/* for multi-io case, only the primary out */
1212352f7f91STakashi Iwai 		if (ch && spec->multi_ios)
1213352f7f91STakashi Iwai 			break;
1214352f7f91STakashi Iwai 		*index = ch;
1215352f7f91STakashi Iwai 		return "Headphone";
121603ad6a8cSDavid Henningsson 	case AUTO_PIN_LINE_OUT:
1217f48652bbSHui Wang 		/* This deals with the case where one HP or one Speaker or
1218f48652bbSHui Wang 		 * one HP + one Speaker need to share the DAC with LO
1219f48652bbSHui Wang 		 */
1220f48652bbSHui Wang 		if (!ch) {
1221f48652bbSHui Wang 			bool hp_lo_shared = false, spk_lo_shared = false;
1222f48652bbSHui Wang 
1223f48652bbSHui Wang 			if (cfg->speaker_outs)
1224f48652bbSHui Wang 				spk_lo_shared = !path_has_mixer(codec,
1225f48652bbSHui Wang 								spec->speaker_paths[0],	ctl_type);
1226f48652bbSHui Wang 			if (cfg->hp_outs)
1227f48652bbSHui Wang 				hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type);
122803ad6a8cSDavid Henningsson 			if (hp_lo_shared && spk_lo_shared)
122903ad6a8cSDavid Henningsson 				return spec->vmaster_mute.hook ? "PCM" : "Master";
123003ad6a8cSDavid Henningsson 			if (hp_lo_shared)
123103ad6a8cSDavid Henningsson 				return "Headphone+LO";
123203ad6a8cSDavid Henningsson 			if (spk_lo_shared)
123303ad6a8cSDavid Henningsson 				return "Speaker+LO";
123403ad6a8cSDavid Henningsson 		}
1235247d85eeSTakashi Iwai 	}
1236247d85eeSTakashi Iwai 
1237247d85eeSTakashi Iwai 	/* for a single channel output, we don't have to name the channel */
1238352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && !spec->multi_ios)
12393abb4f4dSDavid Henningsson 		return "Line Out";
1240247d85eeSTakashi Iwai 
12413b44ec8cSTakashi Iwai  fixed_name:
1242352f7f91STakashi Iwai 	if (ch >= ARRAY_SIZE(channel_name)) {
1243352f7f91STakashi Iwai 		snd_BUG();
1244352f7f91STakashi Iwai 		return "PCM";
1245352f7f91STakashi Iwai 	}
1246352f7f91STakashi Iwai 
1247352f7f91STakashi Iwai 	return channel_name[ch];
1248352f7f91STakashi Iwai }
1249352f7f91STakashi Iwai 
1250352f7f91STakashi Iwai /*
1251352f7f91STakashi Iwai  * Parse output paths
1252352f7f91STakashi Iwai  */
1253352f7f91STakashi Iwai 
1254352f7f91STakashi Iwai /* badness definition */
1255352f7f91STakashi Iwai enum {
1256352f7f91STakashi Iwai 	/* No primary DAC is found for the main output */
1257352f7f91STakashi Iwai 	BAD_NO_PRIMARY_DAC = 0x10000,
1258352f7f91STakashi Iwai 	/* No DAC is found for the extra output */
1259352f7f91STakashi Iwai 	BAD_NO_DAC = 0x4000,
1260352f7f91STakashi Iwai 	/* No possible multi-ios */
12611d739066STakashi Iwai 	BAD_MULTI_IO = 0x120,
1262352f7f91STakashi Iwai 	/* No individual DAC for extra output */
1263352f7f91STakashi Iwai 	BAD_NO_EXTRA_DAC = 0x102,
1264352f7f91STakashi Iwai 	/* No individual DAC for extra surrounds */
1265352f7f91STakashi Iwai 	BAD_NO_EXTRA_SURR_DAC = 0x101,
1266352f7f91STakashi Iwai 	/* Primary DAC shared with main surrounds */
1267352f7f91STakashi Iwai 	BAD_SHARED_SURROUND = 0x100,
126855a63d4dSTakashi Iwai 	/* No independent HP possible */
1269bec8e680STakashi Iwai 	BAD_NO_INDEP_HP = 0x10,
1270352f7f91STakashi Iwai 	/* Primary DAC shared with main CLFE */
1271352f7f91STakashi Iwai 	BAD_SHARED_CLFE = 0x10,
1272352f7f91STakashi Iwai 	/* Primary DAC shared with extra surrounds */
1273352f7f91STakashi Iwai 	BAD_SHARED_EXTRA_SURROUND = 0x10,
1274352f7f91STakashi Iwai 	/* Volume widget is shared */
1275352f7f91STakashi Iwai 	BAD_SHARED_VOL = 0x10,
1276352f7f91STakashi Iwai };
1277352f7f91STakashi Iwai 
12780e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for
1279352f7f91STakashi Iwai  * volume and mute controls, and assign the values to ctls[].
1280352f7f91STakashi Iwai  *
1281352f7f91STakashi Iwai  * When no appropriate widget is found in the path, the badness value
1282352f7f91STakashi Iwai  * is incremented depending on the situation.  The function returns the
1283352f7f91STakashi Iwai  * total badness for both volume and mute controls.
1284352f7f91STakashi Iwai  */
assign_out_path_ctls(struct hda_codec * codec,struct nid_path * path)12850e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
1286352f7f91STakashi Iwai {
1287d89c6c0cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1288352f7f91STakashi Iwai 	hda_nid_t nid;
1289352f7f91STakashi Iwai 	unsigned int val;
1290352f7f91STakashi Iwai 	int badness = 0;
1291352f7f91STakashi Iwai 
1292352f7f91STakashi Iwai 	if (!path)
1293352f7f91STakashi Iwai 		return BAD_SHARED_VOL * 2;
12940e614dd0STakashi Iwai 
12950e614dd0STakashi Iwai 	if (path->ctls[NID_PATH_VOL_CTL] ||
12960e614dd0STakashi Iwai 	    path->ctls[NID_PATH_MUTE_CTL])
12970e614dd0STakashi Iwai 		return 0; /* already evaluated */
12980e614dd0STakashi Iwai 
1299352f7f91STakashi Iwai 	nid = look_for_out_vol_nid(codec, path);
1300352f7f91STakashi Iwai 	if (nid) {
1301352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
1302d89c6c0cSTakashi Iwai 		if (spec->dac_min_mute)
1303d89c6c0cSTakashi Iwai 			val |= HDA_AMP_VAL_MIN_MUTE;
1304352f7f91STakashi Iwai 		if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
1305352f7f91STakashi Iwai 			badness += BAD_SHARED_VOL;
1306352f7f91STakashi Iwai 		else
1307352f7f91STakashi Iwai 			path->ctls[NID_PATH_VOL_CTL] = val;
1308352f7f91STakashi Iwai 	} else
1309352f7f91STakashi Iwai 		badness += BAD_SHARED_VOL;
1310352f7f91STakashi Iwai 	nid = look_for_out_mute_nid(codec, path);
1311352f7f91STakashi Iwai 	if (nid) {
1312352f7f91STakashi Iwai 		unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
1313352f7f91STakashi Iwai 		if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
1314352f7f91STakashi Iwai 		    nid_has_mute(codec, nid, HDA_OUTPUT))
1315352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
1316352f7f91STakashi Iwai 		else
1317352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
1318352f7f91STakashi Iwai 		if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
1319352f7f91STakashi Iwai 			badness += BAD_SHARED_VOL;
1320352f7f91STakashi Iwai 		else
1321352f7f91STakashi Iwai 			path->ctls[NID_PATH_MUTE_CTL] = val;
1322352f7f91STakashi Iwai 	} else
1323352f7f91STakashi Iwai 		badness += BAD_SHARED_VOL;
1324352f7f91STakashi Iwai 	return badness;
1325352f7f91STakashi Iwai }
1326352f7f91STakashi Iwai 
132798bd1115STakashi Iwai const struct badness_table hda_main_out_badness = {
1328352f7f91STakashi Iwai 	.no_primary_dac = BAD_NO_PRIMARY_DAC,
1329352f7f91STakashi Iwai 	.no_dac = BAD_NO_DAC,
1330352f7f91STakashi Iwai 	.shared_primary = BAD_NO_PRIMARY_DAC,
1331352f7f91STakashi Iwai 	.shared_surr = BAD_SHARED_SURROUND,
1332352f7f91STakashi Iwai 	.shared_clfe = BAD_SHARED_CLFE,
1333352f7f91STakashi Iwai 	.shared_surr_main = BAD_SHARED_SURROUND,
1334352f7f91STakashi Iwai };
13352698ea98STakashi Iwai EXPORT_SYMBOL_GPL(hda_main_out_badness);
1336352f7f91STakashi Iwai 
133798bd1115STakashi Iwai const struct badness_table hda_extra_out_badness = {
1338352f7f91STakashi Iwai 	.no_primary_dac = BAD_NO_DAC,
1339352f7f91STakashi Iwai 	.no_dac = BAD_NO_DAC,
1340352f7f91STakashi Iwai 	.shared_primary = BAD_NO_EXTRA_DAC,
1341352f7f91STakashi Iwai 	.shared_surr = BAD_SHARED_EXTRA_SURROUND,
1342352f7f91STakashi Iwai 	.shared_clfe = BAD_SHARED_EXTRA_SURROUND,
1343352f7f91STakashi Iwai 	.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
1344352f7f91STakashi Iwai };
13452698ea98STakashi Iwai EXPORT_SYMBOL_GPL(hda_extra_out_badness);
1346352f7f91STakashi Iwai 
13477385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */
get_primary_out(struct hda_codec * codec,int idx)13487385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
13497385df61STakashi Iwai {
13507385df61STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
13517385df61STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
13527385df61STakashi Iwai 
13537385df61STakashi Iwai 	if (cfg->line_outs > idx)
13547385df61STakashi Iwai 		return spec->private_dac_nids[idx];
13557385df61STakashi Iwai 	idx -= cfg->line_outs;
13567385df61STakashi Iwai 	if (spec->multi_ios > idx)
13577385df61STakashi Iwai 		return spec->multi_io[idx].dac;
13587385df61STakashi Iwai 	return 0;
13597385df61STakashi Iwai }
13607385df61STakashi Iwai 
13617385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */
try_dac(struct hda_codec * codec,hda_nid_t dac,hda_nid_t pin)13627385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec,
13637385df61STakashi Iwai 				hda_nid_t dac, hda_nid_t pin)
13647385df61STakashi Iwai {
13657385df61STakashi Iwai 	return is_reachable_path(codec, dac, pin) ? dac : 0;
13667385df61STakashi Iwai }
13677385df61STakashi Iwai 
1368352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */
try_assign_dacs(struct hda_codec * codec,int num_outs,const hda_nid_t * pins,hda_nid_t * dacs,int * path_idx,const struct badness_table * bad)1369352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs,
1370352f7f91STakashi Iwai 			   const hda_nid_t *pins, hda_nid_t *dacs,
1371196c1766STakashi Iwai 			   int *path_idx,
1372352f7f91STakashi Iwai 			   const struct badness_table *bad)
1373352f7f91STakashi Iwai {
1374352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1375352f7f91STakashi Iwai 	int i, j;
1376352f7f91STakashi Iwai 	int badness = 0;
1377352f7f91STakashi Iwai 	hda_nid_t dac;
1378352f7f91STakashi Iwai 
1379352f7f91STakashi Iwai 	if (!num_outs)
1380352f7f91STakashi Iwai 		return 0;
1381352f7f91STakashi Iwai 
1382352f7f91STakashi Iwai 	for (i = 0; i < num_outs; i++) {
13830c8c0f56STakashi Iwai 		struct nid_path *path;
1384352f7f91STakashi Iwai 		hda_nid_t pin = pins[i];
13851e0b5286STakashi Iwai 
1386242d990cSTakashi Iwai 		if (!spec->obey_preferred_dacs) {
13870e614dd0STakashi Iwai 			path = snd_hda_get_path_from_idx(codec, path_idx[i]);
13880e614dd0STakashi Iwai 			if (path) {
13890e614dd0STakashi Iwai 				badness += assign_out_path_ctls(codec, path);
13901e0b5286STakashi Iwai 				continue;
13911e0b5286STakashi Iwai 			}
1392242d990cSTakashi Iwai 		}
13931e0b5286STakashi Iwai 
13943690739bSTakashi Iwai 		dacs[i] = get_preferred_dac(codec, pin);
13953690739bSTakashi Iwai 		if (dacs[i]) {
13963690739bSTakashi Iwai 			if (is_dac_already_used(codec, dacs[i]))
13973690739bSTakashi Iwai 				badness += bad->shared_primary;
1398242d990cSTakashi Iwai 		} else if (spec->obey_preferred_dacs) {
1399242d990cSTakashi Iwai 			badness += BAD_NO_PRIMARY_DAC;
14003690739bSTakashi Iwai 		}
14013690739bSTakashi Iwai 
14023690739bSTakashi Iwai 		if (!dacs[i])
1403352f7f91STakashi Iwai 			dacs[i] = look_for_dac(codec, pin, false);
1404352f7f91STakashi Iwai 		if (!dacs[i] && !i) {
1405980428ceSTakashi Iwai 			/* try to steal the DAC of surrounds for the front */
1406352f7f91STakashi Iwai 			for (j = 1; j < num_outs; j++) {
1407352f7f91STakashi Iwai 				if (is_reachable_path(codec, dacs[j], pin)) {
1408352f7f91STakashi Iwai 					dacs[0] = dacs[j];
1409352f7f91STakashi Iwai 					dacs[j] = 0;
1410980428ceSTakashi Iwai 					invalidate_nid_path(codec, path_idx[j]);
1411196c1766STakashi Iwai 					path_idx[j] = 0;
1412352f7f91STakashi Iwai 					break;
1413352f7f91STakashi Iwai 				}
1414352f7f91STakashi Iwai 			}
1415352f7f91STakashi Iwai 		}
1416352f7f91STakashi Iwai 		dac = dacs[i];
1417352f7f91STakashi Iwai 		if (!dac) {
14187385df61STakashi Iwai 			if (num_outs > 2)
14197385df61STakashi Iwai 				dac = try_dac(codec, get_primary_out(codec, i), pin);
14207385df61STakashi Iwai 			if (!dac)
14217385df61STakashi Iwai 				dac = try_dac(codec, dacs[0], pin);
14227385df61STakashi Iwai 			if (!dac)
14237385df61STakashi Iwai 				dac = try_dac(codec, get_primary_out(codec, i), pin);
1424352f7f91STakashi Iwai 			if (dac) {
1425352f7f91STakashi Iwai 				if (!i)
1426352f7f91STakashi Iwai 					badness += bad->shared_primary;
1427352f7f91STakashi Iwai 				else if (i == 1)
1428352f7f91STakashi Iwai 					badness += bad->shared_surr;
1429352f7f91STakashi Iwai 				else
1430352f7f91STakashi Iwai 					badness += bad->shared_clfe;
1431352f7f91STakashi Iwai 			} else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) {
1432352f7f91STakashi Iwai 				dac = spec->private_dac_nids[0];
1433352f7f91STakashi Iwai 				badness += bad->shared_surr_main;
1434352f7f91STakashi Iwai 			} else if (!i)
1435352f7f91STakashi Iwai 				badness += bad->no_primary_dac;
1436352f7f91STakashi Iwai 			else
1437352f7f91STakashi Iwai 				badness += bad->no_dac;
1438352f7f91STakashi Iwai 		}
14391fa335b0STakashi Iwai 		if (!dac)
14401fa335b0STakashi Iwai 			continue;
14413ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid);
1442117688a9STakashi Iwai 		if (!path && !i && spec->mixer_nid) {
1443b3a8c745STakashi Iwai 			/* try with aamix */
14443ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pin, 0);
1445b3a8c745STakashi Iwai 		}
14461fa335b0STakashi Iwai 		if (!path) {
1447e73b4c9eSJiapeng Chong 			dacs[i] = 0;
14481fa335b0STakashi Iwai 			badness += bad->no_dac;
14491fa335b0STakashi Iwai 		} else {
14504e76a883STakashi Iwai 			/* print_nid_path(codec, "output", path); */
1451e1284af7STakashi Iwai 			path->active = true;
1452196c1766STakashi Iwai 			path_idx[i] = snd_hda_get_path_idx(codec, path);
14530e614dd0STakashi Iwai 			badness += assign_out_path_ctls(codec, path);
1454e1284af7STakashi Iwai 		}
1455352f7f91STakashi Iwai 	}
1456352f7f91STakashi Iwai 
1457352f7f91STakashi Iwai 	return badness;
1458352f7f91STakashi Iwai }
1459352f7f91STakashi Iwai 
1460352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */
get_dac_if_single(struct hda_codec * codec,hda_nid_t pin)1461352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
1462352f7f91STakashi Iwai {
1463352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1464352f7f91STakashi Iwai 	int i;
1465352f7f91STakashi Iwai 	hda_nid_t nid_found = 0;
1466352f7f91STakashi Iwai 
1467352f7f91STakashi Iwai 	for (i = 0; i < spec->num_all_dacs; i++) {
1468352f7f91STakashi Iwai 		hda_nid_t nid = spec->all_dacs[i];
1469352f7f91STakashi Iwai 		if (!nid || is_dac_already_used(codec, nid))
1470352f7f91STakashi Iwai 			continue;
1471352f7f91STakashi Iwai 		if (is_reachable_path(codec, nid, pin)) {
1472352f7f91STakashi Iwai 			if (nid_found)
1473352f7f91STakashi Iwai 				return 0;
1474352f7f91STakashi Iwai 			nid_found = nid;
1475352f7f91STakashi Iwai 		}
1476352f7f91STakashi Iwai 	}
1477352f7f91STakashi Iwai 	return nid_found;
1478352f7f91STakashi Iwai }
1479352f7f91STakashi Iwai 
1480352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */
can_be_multiio_pin(struct hda_codec * codec,unsigned int location,hda_nid_t nid)1481352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec,
1482352f7f91STakashi Iwai 			       unsigned int location, hda_nid_t nid)
1483352f7f91STakashi Iwai {
1484352f7f91STakashi Iwai 	unsigned int defcfg, caps;
1485352f7f91STakashi Iwai 
1486352f7f91STakashi Iwai 	defcfg = snd_hda_codec_get_pincfg(codec, nid);
1487352f7f91STakashi Iwai 	if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
1488352f7f91STakashi Iwai 		return false;
1489352f7f91STakashi Iwai 	if (location && get_defcfg_location(defcfg) != location)
1490352f7f91STakashi Iwai 		return false;
1491352f7f91STakashi Iwai 	caps = snd_hda_query_pin_caps(codec, nid);
1492352f7f91STakashi Iwai 	if (!(caps & AC_PINCAP_OUT))
1493352f7f91STakashi Iwai 		return false;
1494352f7f91STakashi Iwai 	return true;
1495352f7f91STakashi Iwai }
1496352f7f91STakashi Iwai 
1497e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */
count_multiio_pins(struct hda_codec * codec,hda_nid_t reference_pin)1498e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin)
1499e22aab7dSTakashi Iwai {
1500e22aab7dSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1501e22aab7dSTakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1502e22aab7dSTakashi Iwai 	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1503e22aab7dSTakashi Iwai 	unsigned int location = get_defcfg_location(defcfg);
1504e22aab7dSTakashi Iwai 	int type, i;
1505e22aab7dSTakashi Iwai 	int num_pins = 0;
1506e22aab7dSTakashi Iwai 
1507e22aab7dSTakashi Iwai 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1508e22aab7dSTakashi Iwai 		for (i = 0; i < cfg->num_inputs; i++) {
1509e22aab7dSTakashi Iwai 			if (cfg->inputs[i].type != type)
1510e22aab7dSTakashi Iwai 				continue;
1511e22aab7dSTakashi Iwai 			if (can_be_multiio_pin(codec, location,
1512e22aab7dSTakashi Iwai 					       cfg->inputs[i].pin))
1513e22aab7dSTakashi Iwai 				num_pins++;
1514e22aab7dSTakashi Iwai 		}
1515e22aab7dSTakashi Iwai 	}
1516e22aab7dSTakashi Iwai 	return num_pins;
1517e22aab7dSTakashi Iwai }
1518e22aab7dSTakashi Iwai 
1519352f7f91STakashi Iwai /*
1520352f7f91STakashi Iwai  * multi-io helper
1521352f7f91STakashi Iwai  *
1522352f7f91STakashi Iwai  * When hardwired is set, try to fill ony hardwired pins, and returns
1523352f7f91STakashi Iwai  * zero if any pins are filled, non-zero if nothing found.
1524352f7f91STakashi Iwai  * When hardwired is off, try to fill possible input pins, and returns
1525352f7f91STakashi Iwai  * the badness value.
1526352f7f91STakashi Iwai  */
fill_multi_ios(struct hda_codec * codec,hda_nid_t reference_pin,bool hardwired)1527352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec,
1528352f7f91STakashi Iwai 			  hda_nid_t reference_pin,
1529e22aab7dSTakashi Iwai 			  bool hardwired)
1530352f7f91STakashi Iwai {
1531352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1532352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1533e22aab7dSTakashi Iwai 	int type, i, j, num_pins, old_pins;
1534352f7f91STakashi Iwai 	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1535352f7f91STakashi Iwai 	unsigned int location = get_defcfg_location(defcfg);
1536352f7f91STakashi Iwai 	int badness = 0;
15370e614dd0STakashi Iwai 	struct nid_path *path;
1538352f7f91STakashi Iwai 
1539352f7f91STakashi Iwai 	old_pins = spec->multi_ios;
1540352f7f91STakashi Iwai 	if (old_pins >= 2)
1541352f7f91STakashi Iwai 		goto end_fill;
1542352f7f91STakashi Iwai 
1543e22aab7dSTakashi Iwai 	num_pins = count_multiio_pins(codec, reference_pin);
1544352f7f91STakashi Iwai 	if (num_pins < 2)
1545352f7f91STakashi Iwai 		goto end_fill;
1546352f7f91STakashi Iwai 
1547352f7f91STakashi Iwai 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1548352f7f91STakashi Iwai 		for (i = 0; i < cfg->num_inputs; i++) {
1549352f7f91STakashi Iwai 			hda_nid_t nid = cfg->inputs[i].pin;
1550352f7f91STakashi Iwai 			hda_nid_t dac = 0;
1551352f7f91STakashi Iwai 
1552352f7f91STakashi Iwai 			if (cfg->inputs[i].type != type)
1553352f7f91STakashi Iwai 				continue;
1554352f7f91STakashi Iwai 			if (!can_be_multiio_pin(codec, location, nid))
1555352f7f91STakashi Iwai 				continue;
1556352f7f91STakashi Iwai 			for (j = 0; j < spec->multi_ios; j++) {
1557352f7f91STakashi Iwai 				if (nid == spec->multi_io[j].pin)
1558352f7f91STakashi Iwai 					break;
1559352f7f91STakashi Iwai 			}
1560352f7f91STakashi Iwai 			if (j < spec->multi_ios)
1561352f7f91STakashi Iwai 				continue;
1562352f7f91STakashi Iwai 
1563352f7f91STakashi Iwai 			if (hardwired)
1564352f7f91STakashi Iwai 				dac = get_dac_if_single(codec, nid);
1565352f7f91STakashi Iwai 			else if (!dac)
1566352f7f91STakashi Iwai 				dac = look_for_dac(codec, nid, false);
1567352f7f91STakashi Iwai 			if (!dac) {
1568352f7f91STakashi Iwai 				badness++;
1569352f7f91STakashi Iwai 				continue;
1570352f7f91STakashi Iwai 			}
15713ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, nid,
15723ca529d3STakashi Iwai 						    -spec->mixer_nid);
15730c8c0f56STakashi Iwai 			if (!path) {
1574352f7f91STakashi Iwai 				badness++;
1575352f7f91STakashi Iwai 				continue;
1576352f7f91STakashi Iwai 			}
15774e76a883STakashi Iwai 			/* print_nid_path(codec, "multiio", path); */
1578352f7f91STakashi Iwai 			spec->multi_io[spec->multi_ios].pin = nid;
1579352f7f91STakashi Iwai 			spec->multi_io[spec->multi_ios].dac = dac;
1580196c1766STakashi Iwai 			spec->out_paths[cfg->line_outs + spec->multi_ios] =
1581196c1766STakashi Iwai 				snd_hda_get_path_idx(codec, path);
1582352f7f91STakashi Iwai 			spec->multi_ios++;
1583352f7f91STakashi Iwai 			if (spec->multi_ios >= 2)
1584352f7f91STakashi Iwai 				break;
1585352f7f91STakashi Iwai 		}
1586352f7f91STakashi Iwai 	}
1587352f7f91STakashi Iwai  end_fill:
1588352f7f91STakashi Iwai 	if (badness)
1589352f7f91STakashi Iwai 		badness = BAD_MULTI_IO;
1590352f7f91STakashi Iwai 	if (old_pins == spec->multi_ios) {
1591352f7f91STakashi Iwai 		if (hardwired)
1592352f7f91STakashi Iwai 			return 1; /* nothing found */
1593352f7f91STakashi Iwai 		else
1594352f7f91STakashi Iwai 			return badness; /* no badness if nothing found */
1595352f7f91STakashi Iwai 	}
1596352f7f91STakashi Iwai 	if (!hardwired && spec->multi_ios < 2) {
1597352f7f91STakashi Iwai 		/* cancel newly assigned paths */
1598352f7f91STakashi Iwai 		spec->paths.used -= spec->multi_ios - old_pins;
1599352f7f91STakashi Iwai 		spec->multi_ios = old_pins;
1600352f7f91STakashi Iwai 		return badness;
1601352f7f91STakashi Iwai 	}
1602352f7f91STakashi Iwai 
1603352f7f91STakashi Iwai 	/* assign volume and mute controls */
16040e614dd0STakashi Iwai 	for (i = old_pins; i < spec->multi_ios; i++) {
16050e614dd0STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]);
16060e614dd0STakashi Iwai 		badness += assign_out_path_ctls(codec, path);
16070e614dd0STakashi Iwai 	}
1608352f7f91STakashi Iwai 
1609352f7f91STakashi Iwai 	return badness;
1610352f7f91STakashi Iwai }
1611352f7f91STakashi Iwai 
1612352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */
map_singles(struct hda_codec * codec,int outs,const hda_nid_t * pins,hda_nid_t * dacs,int * path_idx)1613352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs,
1614196c1766STakashi Iwai 			const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx)
1615352f7f91STakashi Iwai {
1616b3a8c745STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1617352f7f91STakashi Iwai 	int i;
1618352f7f91STakashi Iwai 	bool found = false;
1619352f7f91STakashi Iwai 	for (i = 0; i < outs; i++) {
16200c8c0f56STakashi Iwai 		struct nid_path *path;
1621352f7f91STakashi Iwai 		hda_nid_t dac;
1622352f7f91STakashi Iwai 		if (dacs[i])
1623352f7f91STakashi Iwai 			continue;
1624352f7f91STakashi Iwai 		dac = get_dac_if_single(codec, pins[i]);
1625352f7f91STakashi Iwai 		if (!dac)
1626352f7f91STakashi Iwai 			continue;
16273ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dac, pins[i],
16283ca529d3STakashi Iwai 					    -spec->mixer_nid);
1629117688a9STakashi Iwai 		if (!path && !i && spec->mixer_nid)
16303ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pins[i], 0);
16310c8c0f56STakashi Iwai 		if (path) {
1632352f7f91STakashi Iwai 			dacs[i] = dac;
1633352f7f91STakashi Iwai 			found = true;
16344e76a883STakashi Iwai 			/* print_nid_path(codec, "output", path); */
1635e1284af7STakashi Iwai 			path->active = true;
1636196c1766STakashi Iwai 			path_idx[i] = snd_hda_get_path_idx(codec, path);
1637352f7f91STakashi Iwai 		}
1638352f7f91STakashi Iwai 	}
1639352f7f91STakashi Iwai 	return found;
1640352f7f91STakashi Iwai }
1641352f7f91STakashi Iwai 
has_aamix_out_paths(struct hda_gen_spec * spec)1642e7fdd527STakashi Iwai static inline bool has_aamix_out_paths(struct hda_gen_spec *spec)
1643e7fdd527STakashi Iwai {
1644e7fdd527STakashi Iwai 	return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
1645e7fdd527STakashi Iwai 		spec->aamix_out_paths[2];
1646e7fdd527STakashi Iwai }
1647e7fdd527STakashi Iwai 
1648c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */
check_aamix_out_path(struct hda_codec * codec,int path_idx)1649c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
1650c30aa7b2STakashi Iwai {
16513ca529d3STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1652c30aa7b2STakashi Iwai 	struct nid_path *path;
16535ead56f2STakashi Iwai 	hda_nid_t path_dac, dac, pin;
1654c30aa7b2STakashi Iwai 
1655c30aa7b2STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
16563ca529d3STakashi Iwai 	if (!path || !path->depth ||
16573ca529d3STakashi Iwai 	    is_nid_contained(path, spec->mixer_nid))
1658c30aa7b2STakashi Iwai 		return 0;
16595ead56f2STakashi Iwai 	path_dac = path->path[0];
16605ead56f2STakashi Iwai 	dac = spec->private_dac_nids[0];
1661f87498b6STakashi Iwai 	pin = path->path[path->depth - 1];
1662f87498b6STakashi Iwai 	path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid);
1663f87498b6STakashi Iwai 	if (!path) {
16645ead56f2STakashi Iwai 		if (dac != path_dac)
16655ead56f2STakashi Iwai 			dac = path_dac;
1666f87498b6STakashi Iwai 		else if (spec->multiout.hp_out_nid[0])
1667f87498b6STakashi Iwai 			dac = spec->multiout.hp_out_nid[0];
1668f87498b6STakashi Iwai 		else if (spec->multiout.extra_out_nid[0])
1669f87498b6STakashi Iwai 			dac = spec->multiout.extra_out_nid[0];
16705ead56f2STakashi Iwai 		else
16715ead56f2STakashi Iwai 			dac = 0;
1672f87498b6STakashi Iwai 		if (dac)
1673f87498b6STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pin,
16743ca529d3STakashi Iwai 						    spec->mixer_nid);
1675f87498b6STakashi Iwai 	}
1676c30aa7b2STakashi Iwai 	if (!path)
1677c30aa7b2STakashi Iwai 		return 0;
16784e76a883STakashi Iwai 	/* print_nid_path(codec, "output-aamix", path); */
1679c30aa7b2STakashi Iwai 	path->active = false; /* unused as default */
16806b275b14STakashi Iwai 	path->pin_fixed = true; /* static route */
1681c30aa7b2STakashi Iwai 	return snd_hda_get_path_idx(codec, path);
1682c30aa7b2STakashi Iwai }
1683c30aa7b2STakashi Iwai 
168455a63d4dSTakashi Iwai /* check whether the independent HP is available with the current config */
indep_hp_possible(struct hda_codec * codec)168555a63d4dSTakashi Iwai static bool indep_hp_possible(struct hda_codec *codec)
168655a63d4dSTakashi Iwai {
168755a63d4dSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
168855a63d4dSTakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
168955a63d4dSTakashi Iwai 	struct nid_path *path;
169055a63d4dSTakashi Iwai 	int i, idx;
169155a63d4dSTakashi Iwai 
169255a63d4dSTakashi Iwai 	if (cfg->line_out_type == AUTO_PIN_HP_OUT)
169355a63d4dSTakashi Iwai 		idx = spec->out_paths[0];
169455a63d4dSTakashi Iwai 	else
169555a63d4dSTakashi Iwai 		idx = spec->hp_paths[0];
169655a63d4dSTakashi Iwai 	path = snd_hda_get_path_from_idx(codec, idx);
169755a63d4dSTakashi Iwai 	if (!path)
169855a63d4dSTakashi Iwai 		return false;
169955a63d4dSTakashi Iwai 
170055a63d4dSTakashi Iwai 	/* assume no path conflicts unless aamix is involved */
170155a63d4dSTakashi Iwai 	if (!spec->mixer_nid || !is_nid_contained(path, spec->mixer_nid))
170255a63d4dSTakashi Iwai 		return true;
170355a63d4dSTakashi Iwai 
170455a63d4dSTakashi Iwai 	/* check whether output paths contain aamix */
170555a63d4dSTakashi Iwai 	for (i = 0; i < cfg->line_outs; i++) {
170655a63d4dSTakashi Iwai 		if (spec->out_paths[i] == idx)
170755a63d4dSTakashi Iwai 			break;
170855a63d4dSTakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
170955a63d4dSTakashi Iwai 		if (path && is_nid_contained(path, spec->mixer_nid))
171055a63d4dSTakashi Iwai 			return false;
171155a63d4dSTakashi Iwai 	}
171255a63d4dSTakashi Iwai 	for (i = 0; i < cfg->speaker_outs; i++) {
171355a63d4dSTakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->speaker_paths[i]);
171455a63d4dSTakashi Iwai 		if (path && is_nid_contained(path, spec->mixer_nid))
171555a63d4dSTakashi Iwai 			return false;
171655a63d4dSTakashi Iwai 	}
171755a63d4dSTakashi Iwai 
171855a63d4dSTakashi Iwai 	return true;
171955a63d4dSTakashi Iwai }
172055a63d4dSTakashi Iwai 
1721a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the
1722a07a949bSTakashi Iwai  * shared dac pointed by the paths
1723a07a949bSTakashi Iwai  */
refill_shared_dacs(struct hda_codec * codec,int num_outs,hda_nid_t * dacs,int * path_idx)1724a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs,
1725a07a949bSTakashi Iwai 			       hda_nid_t *dacs, int *path_idx)
1726a07a949bSTakashi Iwai {
1727a07a949bSTakashi Iwai 	struct nid_path *path;
1728a07a949bSTakashi Iwai 	int i;
1729a07a949bSTakashi Iwai 
1730a07a949bSTakashi Iwai 	for (i = 0; i < num_outs; i++) {
1731a07a949bSTakashi Iwai 		if (dacs[i])
1732a07a949bSTakashi Iwai 			continue;
1733a07a949bSTakashi Iwai 		path = snd_hda_get_path_from_idx(codec, path_idx[i]);
1734a07a949bSTakashi Iwai 		if (!path)
1735a07a949bSTakashi Iwai 			continue;
1736a07a949bSTakashi Iwai 		dacs[i] = path->path[0];
1737a07a949bSTakashi Iwai 	}
1738a07a949bSTakashi Iwai }
1739a07a949bSTakashi Iwai 
1740352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */
fill_and_eval_dacs(struct hda_codec * codec,bool fill_hardwired,bool fill_mio_first)1741352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec,
1742352f7f91STakashi Iwai 			      bool fill_hardwired,
1743352f7f91STakashi Iwai 			      bool fill_mio_first)
1744352f7f91STakashi Iwai {
1745352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1746352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1747352f7f91STakashi Iwai 	int i, err, badness;
1748352f7f91STakashi Iwai 
1749352f7f91STakashi Iwai 	/* set num_dacs once to full for look_for_dac() */
1750352f7f91STakashi Iwai 	spec->multiout.num_dacs = cfg->line_outs;
1751352f7f91STakashi Iwai 	spec->multiout.dac_nids = spec->private_dac_nids;
1752352f7f91STakashi Iwai 	memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
1753352f7f91STakashi Iwai 	memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
1754352f7f91STakashi Iwai 	memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
1755352f7f91STakashi Iwai 	spec->multi_ios = 0;
1756352f7f91STakashi Iwai 	snd_array_free(&spec->paths);
1757cd5be3f9STakashi Iwai 
1758cd5be3f9STakashi Iwai 	/* clear path indices */
1759cd5be3f9STakashi Iwai 	memset(spec->out_paths, 0, sizeof(spec->out_paths));
1760cd5be3f9STakashi Iwai 	memset(spec->hp_paths, 0, sizeof(spec->hp_paths));
1761cd5be3f9STakashi Iwai 	memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths));
1762cd5be3f9STakashi Iwai 	memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths));
1763cd5be3f9STakashi Iwai 	memset(spec->digout_paths, 0, sizeof(spec->digout_paths));
1764c697b716STakashi Iwai 	memset(spec->input_paths, 0, sizeof(spec->input_paths));
1765cd5be3f9STakashi Iwai 	memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths));
1766cd5be3f9STakashi Iwai 	memset(&spec->digin_path, 0, sizeof(spec->digin_path));
1767cd5be3f9STakashi Iwai 
1768352f7f91STakashi Iwai 	badness = 0;
1769352f7f91STakashi Iwai 
1770352f7f91STakashi Iwai 	/* fill hard-wired DACs first */
1771352f7f91STakashi Iwai 	if (fill_hardwired) {
1772352f7f91STakashi Iwai 		bool mapped;
1773352f7f91STakashi Iwai 		do {
1774352f7f91STakashi Iwai 			mapped = map_singles(codec, cfg->line_outs,
1775352f7f91STakashi Iwai 					     cfg->line_out_pins,
1776196c1766STakashi Iwai 					     spec->private_dac_nids,
1777196c1766STakashi Iwai 					     spec->out_paths);
1778352f7f91STakashi Iwai 			mapped |= map_singles(codec, cfg->hp_outs,
1779352f7f91STakashi Iwai 					      cfg->hp_pins,
1780196c1766STakashi Iwai 					      spec->multiout.hp_out_nid,
1781196c1766STakashi Iwai 					      spec->hp_paths);
1782352f7f91STakashi Iwai 			mapped |= map_singles(codec, cfg->speaker_outs,
1783352f7f91STakashi Iwai 					      cfg->speaker_pins,
1784196c1766STakashi Iwai 					      spec->multiout.extra_out_nid,
1785196c1766STakashi Iwai 					      spec->speaker_paths);
1786da96fb5bSTakashi Iwai 			if (!spec->no_multi_io &&
1787da96fb5bSTakashi Iwai 			    fill_mio_first && cfg->line_outs == 1 &&
1788352f7f91STakashi Iwai 			    cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1789e22aab7dSTakashi Iwai 				err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
1790352f7f91STakashi Iwai 				if (!err)
1791352f7f91STakashi Iwai 					mapped = true;
1792352f7f91STakashi Iwai 			}
1793352f7f91STakashi Iwai 		} while (mapped);
1794352f7f91STakashi Iwai 	}
1795352f7f91STakashi Iwai 
1796352f7f91STakashi Iwai 	badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
1797196c1766STakashi Iwai 				   spec->private_dac_nids, spec->out_paths,
179898bd1115STakashi Iwai 				   spec->main_out_badness);
1799352f7f91STakashi Iwai 
1800da96fb5bSTakashi Iwai 	if (!spec->no_multi_io && fill_mio_first &&
1801352f7f91STakashi Iwai 	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1802352f7f91STakashi Iwai 		/* try to fill multi-io first */
1803e22aab7dSTakashi Iwai 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1804352f7f91STakashi Iwai 		if (err < 0)
1805352f7f91STakashi Iwai 			return err;
1806352f7f91STakashi Iwai 		/* we don't count badness at this stage yet */
1807352f7f91STakashi Iwai 	}
1808352f7f91STakashi Iwai 
1809352f7f91STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
1810352f7f91STakashi Iwai 		err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
1811352f7f91STakashi Iwai 				      spec->multiout.hp_out_nid,
1812196c1766STakashi Iwai 				      spec->hp_paths,
181398bd1115STakashi Iwai 				      spec->extra_out_badness);
1814352f7f91STakashi Iwai 		if (err < 0)
1815352f7f91STakashi Iwai 			return err;
1816352f7f91STakashi Iwai 		badness += err;
1817352f7f91STakashi Iwai 	}
1818352f7f91STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1819352f7f91STakashi Iwai 		err = try_assign_dacs(codec, cfg->speaker_outs,
1820352f7f91STakashi Iwai 				      cfg->speaker_pins,
1821352f7f91STakashi Iwai 				      spec->multiout.extra_out_nid,
1822196c1766STakashi Iwai 				      spec->speaker_paths,
182398bd1115STakashi Iwai 				      spec->extra_out_badness);
1824352f7f91STakashi Iwai 		if (err < 0)
1825352f7f91STakashi Iwai 			return err;
1826352f7f91STakashi Iwai 		badness += err;
1827352f7f91STakashi Iwai 	}
1828da96fb5bSTakashi Iwai 	if (!spec->no_multi_io &&
1829da96fb5bSTakashi Iwai 	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1830e22aab7dSTakashi Iwai 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1831352f7f91STakashi Iwai 		if (err < 0)
1832352f7f91STakashi Iwai 			return err;
1833352f7f91STakashi Iwai 		badness += err;
1834352f7f91STakashi Iwai 	}
1835e22aab7dSTakashi Iwai 
1836c30aa7b2STakashi Iwai 	if (spec->mixer_nid) {
1837c30aa7b2STakashi Iwai 		spec->aamix_out_paths[0] =
1838c30aa7b2STakashi Iwai 			check_aamix_out_path(codec, spec->out_paths[0]);
1839c30aa7b2STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1840c30aa7b2STakashi Iwai 			spec->aamix_out_paths[1] =
1841c30aa7b2STakashi Iwai 				check_aamix_out_path(codec, spec->hp_paths[0]);
1842c30aa7b2STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1843c30aa7b2STakashi Iwai 			spec->aamix_out_paths[2] =
1844c30aa7b2STakashi Iwai 				check_aamix_out_path(codec, spec->speaker_paths[0]);
1845c30aa7b2STakashi Iwai 	}
1846c30aa7b2STakashi Iwai 
1847da96fb5bSTakashi Iwai 	if (!spec->no_multi_io &&
1848da96fb5bSTakashi Iwai 	    cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
1849e22aab7dSTakashi Iwai 		if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
1850e22aab7dSTakashi Iwai 			spec->multi_ios = 1; /* give badness */
1851352f7f91STakashi Iwai 
1852a07a949bSTakashi Iwai 	/* re-count num_dacs and squash invalid entries */
1853a07a949bSTakashi Iwai 	spec->multiout.num_dacs = 0;
1854a07a949bSTakashi Iwai 	for (i = 0; i < cfg->line_outs; i++) {
1855a07a949bSTakashi Iwai 		if (spec->private_dac_nids[i])
1856a07a949bSTakashi Iwai 			spec->multiout.num_dacs++;
1857a07a949bSTakashi Iwai 		else {
1858a07a949bSTakashi Iwai 			memmove(spec->private_dac_nids + i,
1859a07a949bSTakashi Iwai 				spec->private_dac_nids + i + 1,
1860a07a949bSTakashi Iwai 				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
1861a07a949bSTakashi Iwai 			spec->private_dac_nids[cfg->line_outs - 1] = 0;
1862a07a949bSTakashi Iwai 		}
1863a07a949bSTakashi Iwai 	}
1864a07a949bSTakashi Iwai 
1865a07a949bSTakashi Iwai 	spec->ext_channel_count = spec->min_channel_count =
1866c0f3b216SDavid Henningsson 		spec->multiout.num_dacs * 2;
1867a07a949bSTakashi Iwai 
1868352f7f91STakashi Iwai 	if (spec->multi_ios == 2) {
1869352f7f91STakashi Iwai 		for (i = 0; i < 2; i++)
1870352f7f91STakashi Iwai 			spec->private_dac_nids[spec->multiout.num_dacs++] =
1871352f7f91STakashi Iwai 				spec->multi_io[i].dac;
1872352f7f91STakashi Iwai 	} else if (spec->multi_ios) {
1873352f7f91STakashi Iwai 		spec->multi_ios = 0;
1874352f7f91STakashi Iwai 		badness += BAD_MULTI_IO;
1875352f7f91STakashi Iwai 	}
1876352f7f91STakashi Iwai 
187755a63d4dSTakashi Iwai 	if (spec->indep_hp && !indep_hp_possible(codec))
187855a63d4dSTakashi Iwai 		badness += BAD_NO_INDEP_HP;
187955a63d4dSTakashi Iwai 
1880a07a949bSTakashi Iwai 	/* re-fill the shared DAC for speaker / headphone */
1881a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1882a07a949bSTakashi Iwai 		refill_shared_dacs(codec, cfg->hp_outs,
1883a07a949bSTakashi Iwai 				   spec->multiout.hp_out_nid,
1884a07a949bSTakashi Iwai 				   spec->hp_paths);
1885a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1886a07a949bSTakashi Iwai 		refill_shared_dacs(codec, cfg->speaker_outs,
1887a07a949bSTakashi Iwai 				   spec->multiout.extra_out_nid,
1888a07a949bSTakashi Iwai 				   spec->speaker_paths);
1889a07a949bSTakashi Iwai 
1890352f7f91STakashi Iwai 	return badness;
1891352f7f91STakashi Iwai }
1892352f7f91STakashi Iwai 
1893352f7f91STakashi Iwai #define DEBUG_BADNESS
1894352f7f91STakashi Iwai 
1895352f7f91STakashi Iwai #ifdef DEBUG_BADNESS
1896d82353e5SJoe Perches #define debug_badness(fmt, ...)						\
1897d82353e5SJoe Perches 	codec_dbg(codec, fmt, ##__VA_ARGS__)
1898352f7f91STakashi Iwai #else
1899d82353e5SJoe Perches #define debug_badness(fmt, ...)						\
1900d82353e5SJoe Perches 	do { if (0) codec_dbg(codec, fmt, ##__VA_ARGS__); } while (0)
1901352f7f91STakashi Iwai #endif
1902352f7f91STakashi Iwai 
1903a769409cSTakashi Iwai #ifdef DEBUG_BADNESS
print_nid_path_idx(struct hda_codec * codec,const char * pfx,int idx)1904a769409cSTakashi Iwai static inline void print_nid_path_idx(struct hda_codec *codec,
1905a769409cSTakashi Iwai 				      const char *pfx, int idx)
1906352f7f91STakashi Iwai {
1907a769409cSTakashi Iwai 	struct nid_path *path;
1908a769409cSTakashi Iwai 
1909a769409cSTakashi Iwai 	path = snd_hda_get_path_from_idx(codec, idx);
1910a769409cSTakashi Iwai 	if (path)
19114e76a883STakashi Iwai 		print_nid_path(codec, pfx, path);
1912a769409cSTakashi Iwai }
1913a769409cSTakashi Iwai 
debug_show_configs(struct hda_codec * codec,struct auto_pin_cfg * cfg)1914a769409cSTakashi Iwai static void debug_show_configs(struct hda_codec *codec,
1915a769409cSTakashi Iwai 			       struct auto_pin_cfg *cfg)
1916a769409cSTakashi Iwai {
1917a769409cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1918a769409cSTakashi Iwai 	static const char * const lo_type[3] = { "LO", "SP", "HP" };
1919a769409cSTakashi Iwai 	int i;
1920a769409cSTakashi Iwai 
1921a769409cSTakashi Iwai 	debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n",
1922352f7f91STakashi Iwai 		      cfg->line_out_pins[0], cfg->line_out_pins[1],
1923708122e8STakashi Iwai 		      cfg->line_out_pins[2], cfg->line_out_pins[3],
1924352f7f91STakashi Iwai 		      spec->multiout.dac_nids[0],
1925352f7f91STakashi Iwai 		      spec->multiout.dac_nids[1],
1926352f7f91STakashi Iwai 		      spec->multiout.dac_nids[2],
1927a769409cSTakashi Iwai 		      spec->multiout.dac_nids[3],
1928a769409cSTakashi Iwai 		      lo_type[cfg->line_out_type]);
1929a769409cSTakashi Iwai 	for (i = 0; i < cfg->line_outs; i++)
1930a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  out", spec->out_paths[i]);
1931352f7f91STakashi Iwai 	if (spec->multi_ios > 0)
1932352f7f91STakashi Iwai 		debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
1933352f7f91STakashi Iwai 			      spec->multi_ios,
1934352f7f91STakashi Iwai 			      spec->multi_io[0].pin, spec->multi_io[1].pin,
1935352f7f91STakashi Iwai 			      spec->multi_io[0].dac, spec->multi_io[1].dac);
1936a769409cSTakashi Iwai 	for (i = 0; i < spec->multi_ios; i++)
1937a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  mio",
1938a769409cSTakashi Iwai 				   spec->out_paths[cfg->line_outs + i]);
1939a769409cSTakashi Iwai 	if (cfg->hp_outs)
1940352f7f91STakashi Iwai 		debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1941352f7f91STakashi Iwai 		      cfg->hp_pins[0], cfg->hp_pins[1],
1942708122e8STakashi Iwai 		      cfg->hp_pins[2], cfg->hp_pins[3],
1943352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[0],
1944352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[1],
1945352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[2],
1946352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[3]);
1947a769409cSTakashi Iwai 	for (i = 0; i < cfg->hp_outs; i++)
1948a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  hp ", spec->hp_paths[i]);
1949a769409cSTakashi Iwai 	if (cfg->speaker_outs)
1950352f7f91STakashi Iwai 		debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1951352f7f91STakashi Iwai 		      cfg->speaker_pins[0], cfg->speaker_pins[1],
1952352f7f91STakashi Iwai 		      cfg->speaker_pins[2], cfg->speaker_pins[3],
1953352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[0],
1954352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[1],
1955352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[2],
1956352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[3]);
1957a769409cSTakashi Iwai 	for (i = 0; i < cfg->speaker_outs; i++)
1958a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  spk", spec->speaker_paths[i]);
1959a769409cSTakashi Iwai 	for (i = 0; i < 3; i++)
1960a769409cSTakashi Iwai 		print_nid_path_idx(codec, "  mix", spec->aamix_out_paths[i]);
1961352f7f91STakashi Iwai }
1962a769409cSTakashi Iwai #else
1963a769409cSTakashi Iwai #define debug_show_configs(codec, cfg) /* NOP */
1964a769409cSTakashi Iwai #endif
1965352f7f91STakashi Iwai 
1966352f7f91STakashi Iwai /* find all available DACs of the codec */
fill_all_dac_nids(struct hda_codec * codec)1967352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec)
1968352f7f91STakashi Iwai {
1969352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
19707639a06cSTakashi Iwai 	hda_nid_t nid;
1971352f7f91STakashi Iwai 
1972352f7f91STakashi Iwai 	spec->num_all_dacs = 0;
1973352f7f91STakashi Iwai 	memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
19747639a06cSTakashi Iwai 	for_each_hda_codec_node(nid, codec) {
1975352f7f91STakashi Iwai 		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
1976352f7f91STakashi Iwai 			continue;
1977352f7f91STakashi Iwai 		if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
19784e76a883STakashi Iwai 			codec_err(codec, "Too many DACs!\n");
1979352f7f91STakashi Iwai 			break;
1980352f7f91STakashi Iwai 		}
1981352f7f91STakashi Iwai 		spec->all_dacs[spec->num_all_dacs++] = nid;
1982352f7f91STakashi Iwai 	}
1983352f7f91STakashi Iwai }
1984352f7f91STakashi Iwai 
parse_output_paths(struct hda_codec * codec)1985352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec)
1986352f7f91STakashi Iwai {
1987352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1988352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1989352f7f91STakashi Iwai 	struct auto_pin_cfg *best_cfg;
19909314a581STakashi Iwai 	unsigned int val;
1991352f7f91STakashi Iwai 	int best_badness = INT_MAX;
1992352f7f91STakashi Iwai 	int badness;
1993352f7f91STakashi Iwai 	bool fill_hardwired = true, fill_mio_first = true;
1994352f7f91STakashi Iwai 	bool best_wired = true, best_mio = true;
1995352f7f91STakashi Iwai 	bool hp_spk_swapped = false;
1996352f7f91STakashi Iwai 
1997352f7f91STakashi Iwai 	best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
1998352f7f91STakashi Iwai 	if (!best_cfg)
1999352f7f91STakashi Iwai 		return -ENOMEM;
2000352f7f91STakashi Iwai 	*best_cfg = *cfg;
2001352f7f91STakashi Iwai 
2002352f7f91STakashi Iwai 	for (;;) {
2003352f7f91STakashi Iwai 		badness = fill_and_eval_dacs(codec, fill_hardwired,
2004352f7f91STakashi Iwai 					     fill_mio_first);
2005352f7f91STakashi Iwai 		if (badness < 0) {
2006352f7f91STakashi Iwai 			kfree(best_cfg);
2007352f7f91STakashi Iwai 			return badness;
2008352f7f91STakashi Iwai 		}
2009352f7f91STakashi Iwai 		debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
2010352f7f91STakashi Iwai 			      cfg->line_out_type, fill_hardwired, fill_mio_first,
2011352f7f91STakashi Iwai 			      badness);
2012a769409cSTakashi Iwai 		debug_show_configs(codec, cfg);
2013352f7f91STakashi Iwai 		if (badness < best_badness) {
2014352f7f91STakashi Iwai 			best_badness = badness;
2015352f7f91STakashi Iwai 			*best_cfg = *cfg;
2016352f7f91STakashi Iwai 			best_wired = fill_hardwired;
2017352f7f91STakashi Iwai 			best_mio = fill_mio_first;
2018352f7f91STakashi Iwai 		}
2019352f7f91STakashi Iwai 		if (!badness)
2020352f7f91STakashi Iwai 			break;
2021352f7f91STakashi Iwai 		fill_mio_first = !fill_mio_first;
2022352f7f91STakashi Iwai 		if (!fill_mio_first)
2023352f7f91STakashi Iwai 			continue;
2024352f7f91STakashi Iwai 		fill_hardwired = !fill_hardwired;
2025352f7f91STakashi Iwai 		if (!fill_hardwired)
2026352f7f91STakashi Iwai 			continue;
2027352f7f91STakashi Iwai 		if (hp_spk_swapped)
2028352f7f91STakashi Iwai 			break;
2029352f7f91STakashi Iwai 		hp_spk_swapped = true;
2030352f7f91STakashi Iwai 		if (cfg->speaker_outs > 0 &&
2031352f7f91STakashi Iwai 		    cfg->line_out_type == AUTO_PIN_HP_OUT) {
2032352f7f91STakashi Iwai 			cfg->hp_outs = cfg->line_outs;
2033352f7f91STakashi Iwai 			memcpy(cfg->hp_pins, cfg->line_out_pins,
2034352f7f91STakashi Iwai 			       sizeof(cfg->hp_pins));
2035352f7f91STakashi Iwai 			cfg->line_outs = cfg->speaker_outs;
2036352f7f91STakashi Iwai 			memcpy(cfg->line_out_pins, cfg->speaker_pins,
2037352f7f91STakashi Iwai 			       sizeof(cfg->speaker_pins));
2038352f7f91STakashi Iwai 			cfg->speaker_outs = 0;
2039352f7f91STakashi Iwai 			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
2040352f7f91STakashi Iwai 			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
2041352f7f91STakashi Iwai 			fill_hardwired = true;
2042352f7f91STakashi Iwai 			continue;
2043352f7f91STakashi Iwai 		}
2044352f7f91STakashi Iwai 		if (cfg->hp_outs > 0 &&
2045352f7f91STakashi Iwai 		    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
2046352f7f91STakashi Iwai 			cfg->speaker_outs = cfg->line_outs;
2047352f7f91STakashi Iwai 			memcpy(cfg->speaker_pins, cfg->line_out_pins,
2048352f7f91STakashi Iwai 			       sizeof(cfg->speaker_pins));
2049352f7f91STakashi Iwai 			cfg->line_outs = cfg->hp_outs;
2050352f7f91STakashi Iwai 			memcpy(cfg->line_out_pins, cfg->hp_pins,
2051352f7f91STakashi Iwai 			       sizeof(cfg->hp_pins));
2052352f7f91STakashi Iwai 			cfg->hp_outs = 0;
2053352f7f91STakashi Iwai 			memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
2054352f7f91STakashi Iwai 			cfg->line_out_type = AUTO_PIN_HP_OUT;
2055352f7f91STakashi Iwai 			fill_hardwired = true;
2056352f7f91STakashi Iwai 			continue;
2057352f7f91STakashi Iwai 		}
2058352f7f91STakashi Iwai 		break;
2059352f7f91STakashi Iwai 	}
2060352f7f91STakashi Iwai 
2061352f7f91STakashi Iwai 	if (badness) {
20620c8c0f56STakashi Iwai 		debug_badness("==> restoring best_cfg\n");
2063352f7f91STakashi Iwai 		*cfg = *best_cfg;
2064352f7f91STakashi Iwai 		fill_and_eval_dacs(codec, best_wired, best_mio);
2065352f7f91STakashi Iwai 	}
2066352f7f91STakashi Iwai 	debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
2067352f7f91STakashi Iwai 		      cfg->line_out_type, best_wired, best_mio);
2068a769409cSTakashi Iwai 	debug_show_configs(codec, cfg);
2069352f7f91STakashi Iwai 
2070352f7f91STakashi Iwai 	if (cfg->line_out_pins[0]) {
2071352f7f91STakashi Iwai 		struct nid_path *path;
2072196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
2073352f7f91STakashi Iwai 		if (path)
2074352f7f91STakashi Iwai 			spec->vmaster_nid = look_for_out_vol_nid(codec, path);
2075d89c6c0cSTakashi Iwai 		if (spec->vmaster_nid) {
20767a71bbf3STakashi Iwai 			snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
20777a71bbf3STakashi Iwai 						HDA_OUTPUT, spec->vmaster_tlv);
2078d89c6c0cSTakashi Iwai 			if (spec->dac_min_mute)
207951cdc8b6STakashi Sakamoto 				spec->vmaster_tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] |= TLV_DB_SCALE_MUTE;
2080d89c6c0cSTakashi Iwai 		}
2081352f7f91STakashi Iwai 	}
2082352f7f91STakashi Iwai 
20839314a581STakashi Iwai 	/* set initial pinctl targets */
20849314a581STakashi Iwai 	if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT)
20859314a581STakashi Iwai 		val = PIN_HP;
20869314a581STakashi Iwai 	else
20879314a581STakashi Iwai 		val = PIN_OUT;
20889314a581STakashi Iwai 	set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val);
20899314a581STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
20909314a581STakashi Iwai 		set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
20919314a581STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
20929314a581STakashi Iwai 		val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT;
20939314a581STakashi Iwai 		set_pin_targets(codec, cfg->speaker_outs,
20949314a581STakashi Iwai 				cfg->speaker_pins, val);
20959314a581STakashi Iwai 	}
20969314a581STakashi Iwai 
209755a63d4dSTakashi Iwai 	/* clear indep_hp flag if not available */
209855a63d4dSTakashi Iwai 	if (spec->indep_hp && !indep_hp_possible(codec))
209955a63d4dSTakashi Iwai 		spec->indep_hp = 0;
210055a63d4dSTakashi Iwai 
2101352f7f91STakashi Iwai 	kfree(best_cfg);
2102352f7f91STakashi Iwai 	return 0;
2103352f7f91STakashi Iwai }
2104352f7f91STakashi Iwai 
2105352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */
create_multi_out_ctls(struct hda_codec * codec,const struct auto_pin_cfg * cfg)2106352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec,
2107352f7f91STakashi Iwai 				 const struct auto_pin_cfg *cfg)
2108352f7f91STakashi Iwai {
2109352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2110352f7f91STakashi Iwai 	int i, err, noutputs;
2111352f7f91STakashi Iwai 
2112352f7f91STakashi Iwai 	noutputs = cfg->line_outs;
2113352f7f91STakashi Iwai 	if (spec->multi_ios > 0 && cfg->line_outs < 3)
2114352f7f91STakashi Iwai 		noutputs += spec->multi_ios;
2115352f7f91STakashi Iwai 
2116352f7f91STakashi Iwai 	for (i = 0; i < noutputs; i++) {
2117352f7f91STakashi Iwai 		const char *name;
2118352f7f91STakashi Iwai 		int index;
2119352f7f91STakashi Iwai 		struct nid_path *path;
2120352f7f91STakashi Iwai 
2121196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
2122352f7f91STakashi Iwai 		if (!path)
2123352f7f91STakashi Iwai 			continue;
2124247d85eeSTakashi Iwai 
2125247d85eeSTakashi Iwai 		name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL);
2126352f7f91STakashi Iwai 		if (!name || !strcmp(name, "CLFE")) {
2127352f7f91STakashi Iwai 			/* Center/LFE */
2128352f7f91STakashi Iwai 			err = add_vol_ctl(codec, "Center", 0, 1, path);
2129352f7f91STakashi Iwai 			if (err < 0)
2130352f7f91STakashi Iwai 				return err;
2131352f7f91STakashi Iwai 			err = add_vol_ctl(codec, "LFE", 0, 2, path);
2132352f7f91STakashi Iwai 			if (err < 0)
2133352f7f91STakashi Iwai 				return err;
2134247d85eeSTakashi Iwai 		} else {
2135247d85eeSTakashi Iwai 			err = add_stereo_vol(codec, name, index, path);
2136247d85eeSTakashi Iwai 			if (err < 0)
2137247d85eeSTakashi Iwai 				return err;
2138247d85eeSTakashi Iwai 		}
2139247d85eeSTakashi Iwai 
2140247d85eeSTakashi Iwai 		name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL);
2141247d85eeSTakashi Iwai 		if (!name || !strcmp(name, "CLFE")) {
2142352f7f91STakashi Iwai 			err = add_sw_ctl(codec, "Center", 0, 1, path);
2143352f7f91STakashi Iwai 			if (err < 0)
2144352f7f91STakashi Iwai 				return err;
2145352f7f91STakashi Iwai 			err = add_sw_ctl(codec, "LFE", 0, 2, path);
2146352f7f91STakashi Iwai 			if (err < 0)
2147352f7f91STakashi Iwai 				return err;
2148352f7f91STakashi Iwai 		} else {
2149352f7f91STakashi Iwai 			err = add_stereo_sw(codec, name, index, path);
2150352f7f91STakashi Iwai 			if (err < 0)
2151352f7f91STakashi Iwai 				return err;
2152352f7f91STakashi Iwai 		}
2153352f7f91STakashi Iwai 	}
2154352f7f91STakashi Iwai 	return 0;
2155352f7f91STakashi Iwai }
2156352f7f91STakashi Iwai 
create_extra_out(struct hda_codec * codec,int path_idx,const char * pfx,int cidx)2157c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx,
2158196c1766STakashi Iwai 			    const char *pfx, int cidx)
2159352f7f91STakashi Iwai {
2160352f7f91STakashi Iwai 	struct nid_path *path;
2161352f7f91STakashi Iwai 	int err;
2162352f7f91STakashi Iwai 
2163196c1766STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
2164352f7f91STakashi Iwai 	if (!path)
2165352f7f91STakashi Iwai 		return 0;
2166352f7f91STakashi Iwai 	err = add_stereo_vol(codec, pfx, cidx, path);
2167352f7f91STakashi Iwai 	if (err < 0)
2168352f7f91STakashi Iwai 		return err;
2169352f7f91STakashi Iwai 	err = add_stereo_sw(codec, pfx, cidx, path);
2170352f7f91STakashi Iwai 	if (err < 0)
2171352f7f91STakashi Iwai 		return err;
2172352f7f91STakashi Iwai 	return 0;
2173352f7f91STakashi Iwai }
2174352f7f91STakashi Iwai 
2175352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */
create_extra_outs(struct hda_codec * codec,int num_pins,const int * paths,const char * pfx)2176352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins,
2177196c1766STakashi Iwai 			     const int *paths, const char *pfx)
2178352f7f91STakashi Iwai {
2179c2c80383STakashi Iwai 	int i;
2180352f7f91STakashi Iwai 
2181352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
2182c2c80383STakashi Iwai 		const char *name;
2183975cc02aSTakashi Iwai 		char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
2184c2c80383STakashi Iwai 		int err, idx = 0;
2185c2c80383STakashi Iwai 
2186c2c80383STakashi Iwai 		if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
2187c2c80383STakashi Iwai 			name = "Bass Speaker";
2188c2c80383STakashi Iwai 		else if (num_pins >= 3) {
2189c2c80383STakashi Iwai 			snprintf(tmp, sizeof(tmp), "%s %s",
2190352f7f91STakashi Iwai 				 pfx, channel_name[i]);
2191c2c80383STakashi Iwai 			name = tmp;
2192352f7f91STakashi Iwai 		} else {
2193c2c80383STakashi Iwai 			name = pfx;
2194c2c80383STakashi Iwai 			idx = i;
2195352f7f91STakashi Iwai 		}
2196c2c80383STakashi Iwai 		err = create_extra_out(codec, paths[i], name, idx);
2197352f7f91STakashi Iwai 		if (err < 0)
2198352f7f91STakashi Iwai 			return err;
2199352f7f91STakashi Iwai 	}
2200352f7f91STakashi Iwai 	return 0;
2201352f7f91STakashi Iwai }
2202352f7f91STakashi Iwai 
create_hp_out_ctls(struct hda_codec * codec)2203352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec)
2204352f7f91STakashi Iwai {
2205352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2206352f7f91STakashi Iwai 	return create_extra_outs(codec, spec->autocfg.hp_outs,
2207196c1766STakashi Iwai 				 spec->hp_paths,
2208352f7f91STakashi Iwai 				 "Headphone");
2209352f7f91STakashi Iwai }
2210352f7f91STakashi Iwai 
create_speaker_out_ctls(struct hda_codec * codec)2211352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec)
2212352f7f91STakashi Iwai {
2213352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2214352f7f91STakashi Iwai 	return create_extra_outs(codec, spec->autocfg.speaker_outs,
2215196c1766STakashi Iwai 				 spec->speaker_paths,
2216352f7f91STakashi Iwai 				 "Speaker");
2217352f7f91STakashi Iwai }
2218352f7f91STakashi Iwai 
2219352f7f91STakashi Iwai /*
222038cf6f1aSTakashi Iwai  * independent HP controls
222138cf6f1aSTakashi Iwai  */
222238cf6f1aSTakashi Iwai 
22231a4f69d5STakashi Iwai static void call_hp_automute(struct hda_codec *codec,
22241a4f69d5STakashi Iwai 			     struct hda_jack_callback *jack);
indep_hp_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)222538cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol,
222638cf6f1aSTakashi Iwai 			 struct snd_ctl_elem_info *uinfo)
222738cf6f1aSTakashi Iwai {
222838cf6f1aSTakashi Iwai 	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
222938cf6f1aSTakashi Iwai }
223038cf6f1aSTakashi Iwai 
indep_hp_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)223138cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol,
223238cf6f1aSTakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
223338cf6f1aSTakashi Iwai {
223438cf6f1aSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
223538cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
223638cf6f1aSTakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled;
223738cf6f1aSTakashi Iwai 	return 0;
223838cf6f1aSTakashi Iwai }
223938cf6f1aSTakashi Iwai 
2240a1e908edSTakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
2241a1e908edSTakashi Iwai 			       int nomix_path_idx, int mix_path_idx,
2242a1e908edSTakashi Iwai 			       int out_type);
2243a1e908edSTakashi Iwai 
indep_hp_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)224438cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol,
224538cf6f1aSTakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
224638cf6f1aSTakashi Iwai {
224738cf6f1aSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
224838cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
224938cf6f1aSTakashi Iwai 	unsigned int select = ucontrol->value.enumerated.item[0];
225038cf6f1aSTakashi Iwai 	int ret = 0;
225138cf6f1aSTakashi Iwai 
225238cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
225338cf6f1aSTakashi Iwai 	if (spec->active_streams) {
225438cf6f1aSTakashi Iwai 		ret = -EBUSY;
225538cf6f1aSTakashi Iwai 		goto unlock;
225638cf6f1aSTakashi Iwai 	}
225738cf6f1aSTakashi Iwai 
225838cf6f1aSTakashi Iwai 	if (spec->indep_hp_enabled != select) {
2259a1e908edSTakashi Iwai 		hda_nid_t *dacp;
2260a1e908edSTakashi Iwai 		if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
2261a1e908edSTakashi Iwai 			dacp = &spec->private_dac_nids[0];
2262a1e908edSTakashi Iwai 		else
2263a1e908edSTakashi Iwai 			dacp = &spec->multiout.hp_out_nid[0];
2264a1e908edSTakashi Iwai 
2265a1e908edSTakashi Iwai 		/* update HP aamix paths in case it conflicts with indep HP */
2266a1e908edSTakashi Iwai 		if (spec->have_aamix_ctl) {
2267a1e908edSTakashi Iwai 			if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
2268a1e908edSTakashi Iwai 				update_aamix_paths(codec, spec->aamix_mode,
2269a1e908edSTakashi Iwai 						   spec->out_paths[0],
2270a1e908edSTakashi Iwai 						   spec->aamix_out_paths[0],
2271a1e908edSTakashi Iwai 						   spec->autocfg.line_out_type);
2272a1e908edSTakashi Iwai 			else
2273a1e908edSTakashi Iwai 				update_aamix_paths(codec, spec->aamix_mode,
2274a1e908edSTakashi Iwai 						   spec->hp_paths[0],
2275a1e908edSTakashi Iwai 						   spec->aamix_out_paths[1],
2276a1e908edSTakashi Iwai 						   AUTO_PIN_HP_OUT);
2277a1e908edSTakashi Iwai 		}
2278a1e908edSTakashi Iwai 
227938cf6f1aSTakashi Iwai 		spec->indep_hp_enabled = select;
228038cf6f1aSTakashi Iwai 		if (spec->indep_hp_enabled)
2281a1e908edSTakashi Iwai 			*dacp = 0;
228238cf6f1aSTakashi Iwai 		else
2283a1e908edSTakashi Iwai 			*dacp = spec->alt_dac_nid;
228492603c59STakashi Iwai 
2285963afde9STakashi Iwai 		call_hp_automute(codec, NULL);
228638cf6f1aSTakashi Iwai 		ret = 1;
228738cf6f1aSTakashi Iwai 	}
228838cf6f1aSTakashi Iwai  unlock:
228938cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
229038cf6f1aSTakashi Iwai 	return ret;
229138cf6f1aSTakashi Iwai }
229238cf6f1aSTakashi Iwai 
229338cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = {
229438cf6f1aSTakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
229538cf6f1aSTakashi Iwai 	.name = "Independent HP",
229638cf6f1aSTakashi Iwai 	.info = indep_hp_info,
229738cf6f1aSTakashi Iwai 	.get = indep_hp_get,
229838cf6f1aSTakashi Iwai 	.put = indep_hp_put,
229938cf6f1aSTakashi Iwai };
230038cf6f1aSTakashi Iwai 
230138cf6f1aSTakashi Iwai 
create_indep_hp_ctls(struct hda_codec * codec)230238cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec)
230338cf6f1aSTakashi Iwai {
230438cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2305a1e908edSTakashi Iwai 	hda_nid_t dac;
230638cf6f1aSTakashi Iwai 
230738cf6f1aSTakashi Iwai 	if (!spec->indep_hp)
230838cf6f1aSTakashi Iwai 		return 0;
2309a1e908edSTakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
2310a1e908edSTakashi Iwai 		dac = spec->multiout.dac_nids[0];
2311a1e908edSTakashi Iwai 	else
2312a1e908edSTakashi Iwai 		dac = spec->multiout.hp_out_nid[0];
2313a1e908edSTakashi Iwai 	if (!dac) {
231438cf6f1aSTakashi Iwai 		spec->indep_hp = 0;
231538cf6f1aSTakashi Iwai 		return 0;
231638cf6f1aSTakashi Iwai 	}
231738cf6f1aSTakashi Iwai 
231838cf6f1aSTakashi Iwai 	spec->indep_hp_enabled = false;
2319a1e908edSTakashi Iwai 	spec->alt_dac_nid = dac;
232038cf6f1aSTakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl))
232138cf6f1aSTakashi Iwai 		return -ENOMEM;
232238cf6f1aSTakashi Iwai 	return 0;
232338cf6f1aSTakashi Iwai }
232438cf6f1aSTakashi Iwai 
232538cf6f1aSTakashi Iwai /*
2326352f7f91STakashi Iwai  * channel mode enum control
2327352f7f91STakashi Iwai  */
2328352f7f91STakashi Iwai 
ch_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2329352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol,
2330352f7f91STakashi Iwai 			struct snd_ctl_elem_info *uinfo)
2331352f7f91STakashi Iwai {
2332352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2333352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2334a07a949bSTakashi Iwai 	int chs;
2335352f7f91STakashi Iwai 
2336352f7f91STakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2337352f7f91STakashi Iwai 	uinfo->count = 1;
2338352f7f91STakashi Iwai 	uinfo->value.enumerated.items = spec->multi_ios + 1;
2339352f7f91STakashi Iwai 	if (uinfo->value.enumerated.item > spec->multi_ios)
2340352f7f91STakashi Iwai 		uinfo->value.enumerated.item = spec->multi_ios;
2341a07a949bSTakashi Iwai 	chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count;
2342a07a949bSTakashi Iwai 	sprintf(uinfo->value.enumerated.name, "%dch", chs);
2343352f7f91STakashi Iwai 	return 0;
2344352f7f91STakashi Iwai }
2345352f7f91STakashi Iwai 
ch_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2346352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol,
2347352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
2348352f7f91STakashi Iwai {
2349352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2350352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2351a07a949bSTakashi Iwai 	ucontrol->value.enumerated.item[0] =
2352a07a949bSTakashi Iwai 		(spec->ext_channel_count - spec->min_channel_count) / 2;
2353352f7f91STakashi Iwai 	return 0;
2354352f7f91STakashi Iwai }
2355352f7f91STakashi Iwai 
2356196c1766STakashi Iwai static inline struct nid_path *
get_multiio_path(struct hda_codec * codec,int idx)2357196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx)
2358196c1766STakashi Iwai {
2359196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2360196c1766STakashi Iwai 	return snd_hda_get_path_from_idx(codec,
2361196c1766STakashi Iwai 		spec->out_paths[spec->autocfg.line_outs + idx]);
2362196c1766STakashi Iwai }
2363196c1766STakashi Iwai 
2364a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec);
2365a5cc2509STakashi Iwai 
236665033cc8STakashi Iwai /* Default value to be passed as aamix argument for snd_hda_activate_path();
236765033cc8STakashi Iwai  * used for output paths
236865033cc8STakashi Iwai  */
aamix_default(struct hda_gen_spec * spec)236965033cc8STakashi Iwai static bool aamix_default(struct hda_gen_spec *spec)
237065033cc8STakashi Iwai {
237165033cc8STakashi Iwai 	return !spec->have_aamix_ctl || spec->aamix_mode;
237265033cc8STakashi Iwai }
237365033cc8STakashi Iwai 
set_multi_io(struct hda_codec * codec,int idx,bool output)2374352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output)
2375352f7f91STakashi Iwai {
2376352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2377352f7f91STakashi Iwai 	hda_nid_t nid = spec->multi_io[idx].pin;
2378352f7f91STakashi Iwai 	struct nid_path *path;
2379352f7f91STakashi Iwai 
2380196c1766STakashi Iwai 	path = get_multiio_path(codec, idx);
2381352f7f91STakashi Iwai 	if (!path)
2382352f7f91STakashi Iwai 		return -EINVAL;
2383352f7f91STakashi Iwai 
2384352f7f91STakashi Iwai 	if (path->active == output)
2385352f7f91STakashi Iwai 		return 0;
2386352f7f91STakashi Iwai 
2387352f7f91STakashi Iwai 	if (output) {
23882c12c30dSTakashi Iwai 		set_pin_target(codec, nid, PIN_OUT, true);
238965033cc8STakashi Iwai 		snd_hda_activate_path(codec, path, true, aamix_default(spec));
2390d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, true);
2391352f7f91STakashi Iwai 	} else {
2392d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, false);
239365033cc8STakashi Iwai 		snd_hda_activate_path(codec, path, false, aamix_default(spec));
23942c12c30dSTakashi Iwai 		set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
239555196fffSTakashi Iwai 		path_power_down_sync(codec, path);
2396352f7f91STakashi Iwai 	}
2397a365fed9STakashi Iwai 
2398a365fed9STakashi Iwai 	/* update jack retasking in case it modifies any of them */
2399a5cc2509STakashi Iwai 	update_automute_all(codec);
2400a365fed9STakashi Iwai 
2401352f7f91STakashi Iwai 	return 0;
2402352f7f91STakashi Iwai }
2403352f7f91STakashi Iwai 
ch_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2404352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol,
2405352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
2406352f7f91STakashi Iwai {
2407352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2408352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2409352f7f91STakashi Iwai 	int i, ch;
2410352f7f91STakashi Iwai 
2411352f7f91STakashi Iwai 	ch = ucontrol->value.enumerated.item[0];
2412352f7f91STakashi Iwai 	if (ch < 0 || ch > spec->multi_ios)
2413352f7f91STakashi Iwai 		return -EINVAL;
2414a07a949bSTakashi Iwai 	if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2)
2415352f7f91STakashi Iwai 		return 0;
2416a07a949bSTakashi Iwai 	spec->ext_channel_count = ch * 2 + spec->min_channel_count;
2417352f7f91STakashi Iwai 	for (i = 0; i < spec->multi_ios; i++)
2418352f7f91STakashi Iwai 		set_multi_io(codec, i, i < ch);
2419352f7f91STakashi Iwai 	spec->multiout.max_channels = max(spec->ext_channel_count,
2420352f7f91STakashi Iwai 					  spec->const_channel_count);
2421352f7f91STakashi Iwai 	if (spec->need_dac_fix)
2422352f7f91STakashi Iwai 		spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2423352f7f91STakashi Iwai 	return 1;
2424352f7f91STakashi Iwai }
2425352f7f91STakashi Iwai 
2426352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = {
2427352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2428352f7f91STakashi Iwai 	.name = "Channel Mode",
2429352f7f91STakashi Iwai 	.info = ch_mode_info,
2430352f7f91STakashi Iwai 	.get = ch_mode_get,
2431352f7f91STakashi Iwai 	.put = ch_mode_put,
2432352f7f91STakashi Iwai };
2433352f7f91STakashi Iwai 
create_multi_channel_mode(struct hda_codec * codec)2434352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec)
2435352f7f91STakashi Iwai {
2436352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2437352f7f91STakashi Iwai 
2438352f7f91STakashi Iwai 	if (spec->multi_ios > 0) {
243912c93df6STakashi Iwai 		if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum))
2440352f7f91STakashi Iwai 			return -ENOMEM;
2441352f7f91STakashi Iwai 	}
2442352f7f91STakashi Iwai 	return 0;
2443352f7f91STakashi Iwai }
2444352f7f91STakashi Iwai 
2445352f7f91STakashi Iwai /*
2446c30aa7b2STakashi Iwai  * aamix loopback enable/disable switch
2447c30aa7b2STakashi Iwai  */
2448c30aa7b2STakashi Iwai 
2449c30aa7b2STakashi Iwai #define loopback_mixing_info	indep_hp_info
2450c30aa7b2STakashi Iwai 
loopback_mixing_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2451c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
2452c30aa7b2STakashi Iwai 			       struct snd_ctl_elem_value *ucontrol)
2453c30aa7b2STakashi Iwai {
2454c30aa7b2STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2455c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2456c30aa7b2STakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->aamix_mode;
2457c30aa7b2STakashi Iwai 	return 0;
2458c30aa7b2STakashi Iwai }
2459c30aa7b2STakashi Iwai 
update_aamix_paths(struct hda_codec * codec,bool do_mix,int nomix_path_idx,int mix_path_idx,int out_type)2460c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
2461a1e908edSTakashi Iwai 			       int nomix_path_idx, int mix_path_idx,
2462a1e908edSTakashi Iwai 			       int out_type)
2463c30aa7b2STakashi Iwai {
2464a1e908edSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2465c30aa7b2STakashi Iwai 	struct nid_path *nomix_path, *mix_path;
2466c30aa7b2STakashi Iwai 
2467c30aa7b2STakashi Iwai 	nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
2468c30aa7b2STakashi Iwai 	mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
2469c30aa7b2STakashi Iwai 	if (!nomix_path || !mix_path)
2470c30aa7b2STakashi Iwai 		return;
2471a1e908edSTakashi Iwai 
2472a1e908edSTakashi Iwai 	/* if HP aamix path is driven from a different DAC and the
2473a1e908edSTakashi Iwai 	 * independent HP mode is ON, can't turn on aamix path
2474a1e908edSTakashi Iwai 	 */
2475a1e908edSTakashi Iwai 	if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled &&
2476a1e908edSTakashi Iwai 	    mix_path->path[0] != spec->alt_dac_nid)
2477a1e908edSTakashi Iwai 		do_mix = false;
2478a1e908edSTakashi Iwai 
2479c30aa7b2STakashi Iwai 	if (do_mix) {
2480c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, nomix_path, false, true);
2481c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, mix_path, true, true);
248255196fffSTakashi Iwai 		path_power_down_sync(codec, nomix_path);
2483c30aa7b2STakashi Iwai 	} else {
248465033cc8STakashi Iwai 		snd_hda_activate_path(codec, mix_path, false, false);
248565033cc8STakashi Iwai 		snd_hda_activate_path(codec, nomix_path, true, false);
248655196fffSTakashi Iwai 		path_power_down_sync(codec, mix_path);
2487c30aa7b2STakashi Iwai 	}
2488c30aa7b2STakashi Iwai }
2489c30aa7b2STakashi Iwai 
2490e7fdd527STakashi Iwai /* re-initialize the output paths; only called from loopback_mixing_put() */
update_output_paths(struct hda_codec * codec,int num_outs,const int * paths)2491e7fdd527STakashi Iwai static void update_output_paths(struct hda_codec *codec, int num_outs,
2492e7fdd527STakashi Iwai 				const int *paths)
2493e7fdd527STakashi Iwai {
2494e7fdd527STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2495e7fdd527STakashi Iwai 	struct nid_path *path;
2496e7fdd527STakashi Iwai 	int i;
2497e7fdd527STakashi Iwai 
2498e7fdd527STakashi Iwai 	for (i = 0; i < num_outs; i++) {
2499e7fdd527STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, paths[i]);
2500e7fdd527STakashi Iwai 		if (path)
2501e7fdd527STakashi Iwai 			snd_hda_activate_path(codec, path, path->active,
2502e7fdd527STakashi Iwai 					      spec->aamix_mode);
2503e7fdd527STakashi Iwai 	}
2504e7fdd527STakashi Iwai }
2505e7fdd527STakashi Iwai 
loopback_mixing_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2506c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
2507c30aa7b2STakashi Iwai 			       struct snd_ctl_elem_value *ucontrol)
2508c30aa7b2STakashi Iwai {
2509c30aa7b2STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2510c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2511e7fdd527STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
2512c30aa7b2STakashi Iwai 	unsigned int val = ucontrol->value.enumerated.item[0];
2513c30aa7b2STakashi Iwai 
2514c30aa7b2STakashi Iwai 	if (val == spec->aamix_mode)
2515c30aa7b2STakashi Iwai 		return 0;
2516c30aa7b2STakashi Iwai 	spec->aamix_mode = val;
2517e7fdd527STakashi Iwai 	if (has_aamix_out_paths(spec)) {
2518c30aa7b2STakashi Iwai 		update_aamix_paths(codec, val, spec->out_paths[0],
2519a1e908edSTakashi Iwai 				   spec->aamix_out_paths[0],
2520e7fdd527STakashi Iwai 				   cfg->line_out_type);
2521c30aa7b2STakashi Iwai 		update_aamix_paths(codec, val, spec->hp_paths[0],
2522a1e908edSTakashi Iwai 				   spec->aamix_out_paths[1],
2523a1e908edSTakashi Iwai 				   AUTO_PIN_HP_OUT);
2524c30aa7b2STakashi Iwai 		update_aamix_paths(codec, val, spec->speaker_paths[0],
2525a1e908edSTakashi Iwai 				   spec->aamix_out_paths[2],
2526a1e908edSTakashi Iwai 				   AUTO_PIN_SPEAKER_OUT);
2527e7fdd527STakashi Iwai 	} else {
2528e7fdd527STakashi Iwai 		update_output_paths(codec, cfg->line_outs, spec->out_paths);
2529e7fdd527STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_HP_OUT)
2530e7fdd527STakashi Iwai 			update_output_paths(codec, cfg->hp_outs, spec->hp_paths);
2531e7fdd527STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
2532e7fdd527STakashi Iwai 			update_output_paths(codec, cfg->speaker_outs,
2533e7fdd527STakashi Iwai 					    spec->speaker_paths);
2534e7fdd527STakashi Iwai 	}
2535c30aa7b2STakashi Iwai 	return 1;
2536c30aa7b2STakashi Iwai }
2537c30aa7b2STakashi Iwai 
2538c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = {
2539c30aa7b2STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2540c30aa7b2STakashi Iwai 	.name = "Loopback Mixing",
2541c30aa7b2STakashi Iwai 	.info = loopback_mixing_info,
2542c30aa7b2STakashi Iwai 	.get = loopback_mixing_get,
2543c30aa7b2STakashi Iwai 	.put = loopback_mixing_put,
2544c30aa7b2STakashi Iwai };
2545c30aa7b2STakashi Iwai 
create_loopback_mixing_ctl(struct hda_codec * codec)2546c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec)
2547c30aa7b2STakashi Iwai {
2548c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2549c30aa7b2STakashi Iwai 
2550c30aa7b2STakashi Iwai 	if (!spec->mixer_nid)
2551c30aa7b2STakashi Iwai 		return 0;
2552c30aa7b2STakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
2553c30aa7b2STakashi Iwai 		return -ENOMEM;
2554a1e908edSTakashi Iwai 	spec->have_aamix_ctl = 1;
2555c30aa7b2STakashi Iwai 	return 0;
2556c30aa7b2STakashi Iwai }
2557c30aa7b2STakashi Iwai 
2558c30aa7b2STakashi Iwai /*
2559352f7f91STakashi Iwai  * shared headphone/mic handling
2560352f7f91STakashi Iwai  */
2561352f7f91STakashi Iwai 
2562352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec);
2563352f7f91STakashi Iwai 
2564352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */
update_hp_mic(struct hda_codec * codec,int adc_mux,bool force)2565967303daSTakashi Iwai static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force)
2566352f7f91STakashi Iwai {
2567352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2568967303daSTakashi Iwai 	bool as_mic;
2569352f7f91STakashi Iwai 	unsigned int val;
2570967303daSTakashi Iwai 	hda_nid_t pin;
2571967303daSTakashi Iwai 
2572967303daSTakashi Iwai 	pin = spec->hp_mic_pin;
2573967303daSTakashi Iwai 	as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx;
2574967303daSTakashi Iwai 
2575967303daSTakashi Iwai 	if (!force) {
2576967303daSTakashi Iwai 		val = snd_hda_codec_get_pin_target(codec, pin);
2577967303daSTakashi Iwai 		if (as_mic) {
2578967303daSTakashi Iwai 			if (val & PIN_IN)
2579967303daSTakashi Iwai 				return;
2580967303daSTakashi Iwai 		} else {
2581967303daSTakashi Iwai 			if (val & PIN_OUT)
2582967303daSTakashi Iwai 				return;
2583967303daSTakashi Iwai 		}
2584967303daSTakashi Iwai 	}
2585352f7f91STakashi Iwai 
2586352f7f91STakashi Iwai 	val = snd_hda_get_default_vref(codec, pin);
2587967303daSTakashi Iwai 	/* if the HP pin doesn't support VREF and the codec driver gives an
2588967303daSTakashi Iwai 	 * alternative pin, set up the VREF on that pin instead
2589967303daSTakashi Iwai 	 */
2590352f7f91STakashi Iwai 	if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
2591352f7f91STakashi Iwai 		const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
2592352f7f91STakashi Iwai 		unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
2593352f7f91STakashi Iwai 		if (vref_val != AC_PINCTL_VREF_HIZ)
25947594aa33STakashi Iwai 			snd_hda_set_pin_ctl_cache(codec, vref_pin,
2595967303daSTakashi Iwai 						  PIN_IN | (as_mic ? vref_val : 0));
2596352f7f91STakashi Iwai 	}
2597352f7f91STakashi Iwai 
25988ba955ceSTakashi Iwai 	if (!spec->hp_mic_jack_modes) {
2599967303daSTakashi Iwai 		if (as_mic)
2600967303daSTakashi Iwai 			val |= PIN_IN;
2601967303daSTakashi Iwai 		else
2602967303daSTakashi Iwai 			val = PIN_HP;
26032c12c30dSTakashi Iwai 		set_pin_target(codec, pin, val, true);
2604963afde9STakashi Iwai 		call_hp_automute(codec, NULL);
26058ba955ceSTakashi Iwai 	}
2606352f7f91STakashi Iwai }
2607352f7f91STakashi Iwai 
2608352f7f91STakashi Iwai /* create a shared input with the headphone out */
create_hp_mic(struct hda_codec * codec)2609967303daSTakashi Iwai static int create_hp_mic(struct hda_codec *codec)
2610352f7f91STakashi Iwai {
2611352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2612352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
2613352f7f91STakashi Iwai 	unsigned int defcfg;
2614352f7f91STakashi Iwai 	hda_nid_t nid;
2615352f7f91STakashi Iwai 
2616967303daSTakashi Iwai 	if (!spec->hp_mic) {
2617967303daSTakashi Iwai 		if (spec->suppress_hp_mic_detect)
2618352f7f91STakashi Iwai 			return 0;
2619967303daSTakashi Iwai 		/* automatic detection: only if no input or a single internal
2620967303daSTakashi Iwai 		 * input pin is found, try to detect the shared hp/mic
2621967303daSTakashi Iwai 		 */
2622967303daSTakashi Iwai 		if (cfg->num_inputs > 1)
2623967303daSTakashi Iwai 			return 0;
2624967303daSTakashi Iwai 		else if (cfg->num_inputs == 1) {
2625352f7f91STakashi Iwai 			defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
2626352f7f91STakashi Iwai 			if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
2627352f7f91STakashi Iwai 				return 0;
2628967303daSTakashi Iwai 		}
2629967303daSTakashi Iwai 	}
2630352f7f91STakashi Iwai 
2631967303daSTakashi Iwai 	spec->hp_mic = 0; /* clear once */
2632967303daSTakashi Iwai 	if (cfg->num_inputs >= AUTO_CFG_MAX_INS)
2633967303daSTakashi Iwai 		return 0;
2634967303daSTakashi Iwai 
2635967303daSTakashi Iwai 	nid = 0;
2636967303daSTakashi Iwai 	if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0)
2637967303daSTakashi Iwai 		nid = cfg->line_out_pins[0];
2638967303daSTakashi Iwai 	else if (cfg->hp_outs > 0)
2639967303daSTakashi Iwai 		nid = cfg->hp_pins[0];
2640967303daSTakashi Iwai 	if (!nid)
2641967303daSTakashi Iwai 		return 0;
2642352f7f91STakashi Iwai 
2643352f7f91STakashi Iwai 	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
2644352f7f91STakashi Iwai 		return 0; /* no input */
2645352f7f91STakashi Iwai 
2646967303daSTakashi Iwai 	cfg->inputs[cfg->num_inputs].pin = nid;
2647967303daSTakashi Iwai 	cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC;
2648cb420b11SDavid Henningsson 	cfg->inputs[cfg->num_inputs].is_headphone_mic = 1;
2649967303daSTakashi Iwai 	cfg->num_inputs++;
2650967303daSTakashi Iwai 	spec->hp_mic = 1;
2651967303daSTakashi Iwai 	spec->hp_mic_pin = nid;
2652967303daSTakashi Iwai 	/* we can't handle auto-mic together with HP-mic */
2653967303daSTakashi Iwai 	spec->suppress_auto_mic = 1;
26544e76a883STakashi Iwai 	codec_dbg(codec, "Enable shared I/O jack on NID 0x%x\n", nid);
2655352f7f91STakashi Iwai 	return 0;
2656352f7f91STakashi Iwai }
2657352f7f91STakashi Iwai 
2658978e77e7STakashi Iwai /*
2659978e77e7STakashi Iwai  * output jack mode
2660978e77e7STakashi Iwai  */
26615f171baaSTakashi Iwai 
26625f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin);
26635f171baaSTakashi Iwai 
26645f171baaSTakashi Iwai static const char * const out_jack_texts[] = {
26655f171baaSTakashi Iwai 	"Line Out", "Headphone Out",
26665f171baaSTakashi Iwai };
26675f171baaSTakashi Iwai 
out_jack_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2668978e77e7STakashi Iwai static int out_jack_mode_info(struct snd_kcontrol *kcontrol,
2669978e77e7STakashi Iwai 			      struct snd_ctl_elem_info *uinfo)
2670978e77e7STakashi Iwai {
26715f171baaSTakashi Iwai 	return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts);
2672978e77e7STakashi Iwai }
2673978e77e7STakashi Iwai 
out_jack_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2674978e77e7STakashi Iwai static int out_jack_mode_get(struct snd_kcontrol *kcontrol,
2675978e77e7STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
2676978e77e7STakashi Iwai {
2677978e77e7STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2678978e77e7STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
2679978e77e7STakashi Iwai 	if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP)
2680978e77e7STakashi Iwai 		ucontrol->value.enumerated.item[0] = 1;
2681978e77e7STakashi Iwai 	else
2682978e77e7STakashi Iwai 		ucontrol->value.enumerated.item[0] = 0;
2683978e77e7STakashi Iwai 	return 0;
2684978e77e7STakashi Iwai }
2685978e77e7STakashi Iwai 
out_jack_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2686978e77e7STakashi Iwai static int out_jack_mode_put(struct snd_kcontrol *kcontrol,
2687978e77e7STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
2688978e77e7STakashi Iwai {
2689978e77e7STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2690978e77e7STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
2691978e77e7STakashi Iwai 	unsigned int val;
2692978e77e7STakashi Iwai 
2693978e77e7STakashi Iwai 	val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT;
2694978e77e7STakashi Iwai 	if (snd_hda_codec_get_pin_target(codec, nid) == val)
2695978e77e7STakashi Iwai 		return 0;
2696978e77e7STakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, nid, val);
2697978e77e7STakashi Iwai 	return 1;
2698978e77e7STakashi Iwai }
2699978e77e7STakashi Iwai 
2700978e77e7STakashi Iwai static const struct snd_kcontrol_new out_jack_mode_enum = {
2701978e77e7STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2702978e77e7STakashi Iwai 	.info = out_jack_mode_info,
2703978e77e7STakashi Iwai 	.get = out_jack_mode_get,
2704978e77e7STakashi Iwai 	.put = out_jack_mode_put,
2705978e77e7STakashi Iwai };
2706978e77e7STakashi Iwai 
find_kctl_name(struct hda_codec * codec,const char * name,int idx)2707978e77e7STakashi Iwai static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx)
2708978e77e7STakashi Iwai {
2709978e77e7STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2710a9c2dfc8STakashi Iwai 	const struct snd_kcontrol_new *kctl;
2711978e77e7STakashi Iwai 	int i;
2712978e77e7STakashi Iwai 
2713a9c2dfc8STakashi Iwai 	snd_array_for_each(&spec->kctls, i, kctl) {
2714978e77e7STakashi Iwai 		if (!strcmp(kctl->name, name) && kctl->index == idx)
2715978e77e7STakashi Iwai 			return true;
2716978e77e7STakashi Iwai 	}
2717978e77e7STakashi Iwai 	return false;
2718978e77e7STakashi Iwai }
2719978e77e7STakashi Iwai 
get_jack_mode_name(struct hda_codec * codec,hda_nid_t pin,char * name,size_t name_len)2720978e77e7STakashi Iwai static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
2721978e77e7STakashi Iwai 			       char *name, size_t name_len)
2722978e77e7STakashi Iwai {
2723978e77e7STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2724978e77e7STakashi Iwai 	int idx = 0;
2725978e77e7STakashi Iwai 
2726978e77e7STakashi Iwai 	snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx);
2727978e77e7STakashi Iwai 	strlcat(name, " Jack Mode", name_len);
2728978e77e7STakashi Iwai 
2729978e77e7STakashi Iwai 	for (; find_kctl_name(codec, name, idx); idx++)
2730978e77e7STakashi Iwai 		;
2731978e77e7STakashi Iwai }
2732978e77e7STakashi Iwai 
get_out_jack_num_items(struct hda_codec * codec,hda_nid_t pin)27335f171baaSTakashi Iwai static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
27345f171baaSTakashi Iwai {
27355f171baaSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2736f811c3cfSTakashi Iwai 	if (spec->add_jack_modes) {
27375f171baaSTakashi Iwai 		unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
27385f171baaSTakashi Iwai 		if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV))
27395f171baaSTakashi Iwai 			return 2;
27405f171baaSTakashi Iwai 	}
27415f171baaSTakashi Iwai 	return 1;
27425f171baaSTakashi Iwai }
27435f171baaSTakashi Iwai 
create_out_jack_modes(struct hda_codec * codec,int num_pins,hda_nid_t * pins)2744978e77e7STakashi Iwai static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
2745978e77e7STakashi Iwai 				 hda_nid_t *pins)
2746978e77e7STakashi Iwai {
2747978e77e7STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2748978e77e7STakashi Iwai 	int i;
2749978e77e7STakashi Iwai 
2750978e77e7STakashi Iwai 	for (i = 0; i < num_pins; i++) {
2751978e77e7STakashi Iwai 		hda_nid_t pin = pins[i];
2752ced4cefcSTakashi Iwai 		if (pin == spec->hp_mic_pin)
27535f171baaSTakashi Iwai 			continue;
27545f171baaSTakashi Iwai 		if (get_out_jack_num_items(codec, pin) > 1) {
2755978e77e7STakashi Iwai 			struct snd_kcontrol_new *knew;
2756975cc02aSTakashi Iwai 			char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
2757978e77e7STakashi Iwai 			get_jack_mode_name(codec, pin, name, sizeof(name));
2758978e77e7STakashi Iwai 			knew = snd_hda_gen_add_kctl(spec, name,
2759978e77e7STakashi Iwai 						    &out_jack_mode_enum);
2760978e77e7STakashi Iwai 			if (!knew)
2761978e77e7STakashi Iwai 				return -ENOMEM;
2762978e77e7STakashi Iwai 			knew->private_value = pin;
2763978e77e7STakashi Iwai 		}
2764978e77e7STakashi Iwai 	}
2765978e77e7STakashi Iwai 
2766978e77e7STakashi Iwai 	return 0;
2767978e77e7STakashi Iwai }
2768978e77e7STakashi Iwai 
276929476558STakashi Iwai /*
277029476558STakashi Iwai  * input jack mode
277129476558STakashi Iwai  */
277229476558STakashi Iwai 
277329476558STakashi Iwai /* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */
277429476558STakashi Iwai #define NUM_VREFS	6
277529476558STakashi Iwai 
277629476558STakashi Iwai static const char * const vref_texts[NUM_VREFS] = {
277729476558STakashi Iwai 	"Line In", "Mic 50pc Bias", "Mic 0V Bias",
277829476558STakashi Iwai 	"", "Mic 80pc Bias", "Mic 100pc Bias"
277929476558STakashi Iwai };
278029476558STakashi Iwai 
get_vref_caps(struct hda_codec * codec,hda_nid_t pin)278129476558STakashi Iwai static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin)
278229476558STakashi Iwai {
278329476558STakashi Iwai 	unsigned int pincap;
278429476558STakashi Iwai 
278529476558STakashi Iwai 	pincap = snd_hda_query_pin_caps(codec, pin);
278629476558STakashi Iwai 	pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
278729476558STakashi Iwai 	/* filter out unusual vrefs */
278829476558STakashi Iwai 	pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100);
278929476558STakashi Iwai 	return pincap;
279029476558STakashi Iwai }
279129476558STakashi Iwai 
279229476558STakashi Iwai /* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */
get_vref_idx(unsigned int vref_caps,unsigned int item_idx)279329476558STakashi Iwai static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx)
279429476558STakashi Iwai {
279529476558STakashi Iwai 	unsigned int i, n = 0;
279629476558STakashi Iwai 
279729476558STakashi Iwai 	for (i = 0; i < NUM_VREFS; i++) {
279829476558STakashi Iwai 		if (vref_caps & (1 << i)) {
279929476558STakashi Iwai 			if (n == item_idx)
280029476558STakashi Iwai 				return i;
280129476558STakashi Iwai 			n++;
280229476558STakashi Iwai 		}
280329476558STakashi Iwai 	}
280429476558STakashi Iwai 	return 0;
280529476558STakashi Iwai }
280629476558STakashi Iwai 
280729476558STakashi Iwai /* convert back from the vref ctl index to the enum item index */
cvt_from_vref_idx(unsigned int vref_caps,unsigned int idx)280829476558STakashi Iwai static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx)
280929476558STakashi Iwai {
281029476558STakashi Iwai 	unsigned int i, n = 0;
281129476558STakashi Iwai 
281229476558STakashi Iwai 	for (i = 0; i < NUM_VREFS; i++) {
281329476558STakashi Iwai 		if (i == idx)
281429476558STakashi Iwai 			return n;
281529476558STakashi Iwai 		if (vref_caps & (1 << i))
281629476558STakashi Iwai 			n++;
281729476558STakashi Iwai 	}
281829476558STakashi Iwai 	return 0;
281929476558STakashi Iwai }
282029476558STakashi Iwai 
in_jack_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)282129476558STakashi Iwai static int in_jack_mode_info(struct snd_kcontrol *kcontrol,
282229476558STakashi Iwai 			     struct snd_ctl_elem_info *uinfo)
282329476558STakashi Iwai {
282429476558STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
282529476558STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
282629476558STakashi Iwai 	unsigned int vref_caps = get_vref_caps(codec, nid);
282729476558STakashi Iwai 
282829476558STakashi Iwai 	snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps),
282929476558STakashi Iwai 				 vref_texts);
283029476558STakashi Iwai 	/* set the right text */
283129476558STakashi Iwai 	strcpy(uinfo->value.enumerated.name,
283229476558STakashi Iwai 	       vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]);
283329476558STakashi Iwai 	return 0;
283429476558STakashi Iwai }
283529476558STakashi Iwai 
in_jack_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)283629476558STakashi Iwai static int in_jack_mode_get(struct snd_kcontrol *kcontrol,
283729476558STakashi Iwai 			    struct snd_ctl_elem_value *ucontrol)
283829476558STakashi Iwai {
283929476558STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
284029476558STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
284129476558STakashi Iwai 	unsigned int vref_caps = get_vref_caps(codec, nid);
284229476558STakashi Iwai 	unsigned int idx;
284329476558STakashi Iwai 
284429476558STakashi Iwai 	idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN;
284529476558STakashi Iwai 	ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx);
284629476558STakashi Iwai 	return 0;
284729476558STakashi Iwai }
284829476558STakashi Iwai 
in_jack_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)284929476558STakashi Iwai static int in_jack_mode_put(struct snd_kcontrol *kcontrol,
285029476558STakashi Iwai 			    struct snd_ctl_elem_value *ucontrol)
285129476558STakashi Iwai {
285229476558STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
285329476558STakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
285429476558STakashi Iwai 	unsigned int vref_caps = get_vref_caps(codec, nid);
285529476558STakashi Iwai 	unsigned int val, idx;
285629476558STakashi Iwai 
285729476558STakashi Iwai 	val = snd_hda_codec_get_pin_target(codec, nid);
285829476558STakashi Iwai 	idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN);
285929476558STakashi Iwai 	if (idx == ucontrol->value.enumerated.item[0])
286029476558STakashi Iwai 		return 0;
286129476558STakashi Iwai 
286229476558STakashi Iwai 	val &= ~AC_PINCTL_VREFEN;
286329476558STakashi Iwai 	val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]);
286429476558STakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, nid, val);
286529476558STakashi Iwai 	return 1;
286629476558STakashi Iwai }
286729476558STakashi Iwai 
286829476558STakashi Iwai static const struct snd_kcontrol_new in_jack_mode_enum = {
286929476558STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
287029476558STakashi Iwai 	.info = in_jack_mode_info,
287129476558STakashi Iwai 	.get = in_jack_mode_get,
287229476558STakashi Iwai 	.put = in_jack_mode_put,
287329476558STakashi Iwai };
287429476558STakashi Iwai 
get_in_jack_num_items(struct hda_codec * codec,hda_nid_t pin)28755f171baaSTakashi Iwai static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
28765f171baaSTakashi Iwai {
28775f171baaSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
28785f171baaSTakashi Iwai 	int nitems = 0;
2879f811c3cfSTakashi Iwai 	if (spec->add_jack_modes)
28805f171baaSTakashi Iwai 		nitems = hweight32(get_vref_caps(codec, pin));
28815f171baaSTakashi Iwai 	return nitems ? nitems : 1;
28825f171baaSTakashi Iwai }
28835f171baaSTakashi Iwai 
create_in_jack_mode(struct hda_codec * codec,hda_nid_t pin)288429476558STakashi Iwai static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
288529476558STakashi Iwai {
288629476558STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
288729476558STakashi Iwai 	struct snd_kcontrol_new *knew;
2888975cc02aSTakashi Iwai 	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
28895f171baaSTakashi Iwai 	unsigned int defcfg;
28905f171baaSTakashi Iwai 
2891f811c3cfSTakashi Iwai 	if (pin == spec->hp_mic_pin)
2892f811c3cfSTakashi Iwai 		return 0; /* already done in create_out_jack_mode() */
289329476558STakashi Iwai 
289429476558STakashi Iwai 	/* no jack mode for fixed pins */
289529476558STakashi Iwai 	defcfg = snd_hda_codec_get_pincfg(codec, pin);
289629476558STakashi Iwai 	if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
289729476558STakashi Iwai 		return 0;
289829476558STakashi Iwai 
289929476558STakashi Iwai 	/* no multiple vref caps? */
29005f171baaSTakashi Iwai 	if (get_in_jack_num_items(codec, pin) <= 1)
290129476558STakashi Iwai 		return 0;
290229476558STakashi Iwai 
290329476558STakashi Iwai 	get_jack_mode_name(codec, pin, name, sizeof(name));
290429476558STakashi Iwai 	knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum);
290529476558STakashi Iwai 	if (!knew)
290629476558STakashi Iwai 		return -ENOMEM;
290729476558STakashi Iwai 	knew->private_value = pin;
290829476558STakashi Iwai 	return 0;
290929476558STakashi Iwai }
291029476558STakashi Iwai 
29115f171baaSTakashi Iwai /*
29125f171baaSTakashi Iwai  * HP/mic shared jack mode
29135f171baaSTakashi Iwai  */
hp_mic_jack_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)29145f171baaSTakashi Iwai static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol,
29155f171baaSTakashi Iwai 				 struct snd_ctl_elem_info *uinfo)
29165f171baaSTakashi Iwai {
29175f171baaSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
29185f171baaSTakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
29195f171baaSTakashi Iwai 	int out_jacks = get_out_jack_num_items(codec, nid);
29205f171baaSTakashi Iwai 	int in_jacks = get_in_jack_num_items(codec, nid);
29215f171baaSTakashi Iwai 	const char *text = NULL;
29225f171baaSTakashi Iwai 	int idx;
29235f171baaSTakashi Iwai 
29245f171baaSTakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
29255f171baaSTakashi Iwai 	uinfo->count = 1;
29265f171baaSTakashi Iwai 	uinfo->value.enumerated.items = out_jacks + in_jacks;
29275f171baaSTakashi Iwai 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
29285f171baaSTakashi Iwai 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
29295f171baaSTakashi Iwai 	idx = uinfo->value.enumerated.item;
29305f171baaSTakashi Iwai 	if (idx < out_jacks) {
29315f171baaSTakashi Iwai 		if (out_jacks > 1)
29325f171baaSTakashi Iwai 			text = out_jack_texts[idx];
29335f171baaSTakashi Iwai 		else
29345f171baaSTakashi Iwai 			text = "Headphone Out";
29355f171baaSTakashi Iwai 	} else {
29365f171baaSTakashi Iwai 		idx -= out_jacks;
29375f171baaSTakashi Iwai 		if (in_jacks > 1) {
29385f171baaSTakashi Iwai 			unsigned int vref_caps = get_vref_caps(codec, nid);
29395f171baaSTakashi Iwai 			text = vref_texts[get_vref_idx(vref_caps, idx)];
29405f171baaSTakashi Iwai 		} else
29415f171baaSTakashi Iwai 			text = "Mic In";
29425f171baaSTakashi Iwai 	}
29435f171baaSTakashi Iwai 
29445f171baaSTakashi Iwai 	strcpy(uinfo->value.enumerated.name, text);
29455f171baaSTakashi Iwai 	return 0;
29465f171baaSTakashi Iwai }
29475f171baaSTakashi Iwai 
get_cur_hp_mic_jack_mode(struct hda_codec * codec,hda_nid_t nid)29485f171baaSTakashi Iwai static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid)
29495f171baaSTakashi Iwai {
29505f171baaSTakashi Iwai 	int out_jacks = get_out_jack_num_items(codec, nid);
29515f171baaSTakashi Iwai 	int in_jacks = get_in_jack_num_items(codec, nid);
29525f171baaSTakashi Iwai 	unsigned int val = snd_hda_codec_get_pin_target(codec, nid);
29535f171baaSTakashi Iwai 	int idx = 0;
29545f171baaSTakashi Iwai 
29555f171baaSTakashi Iwai 	if (val & PIN_OUT) {
29565f171baaSTakashi Iwai 		if (out_jacks > 1 && val == PIN_HP)
29575f171baaSTakashi Iwai 			idx = 1;
29585f171baaSTakashi Iwai 	} else if (val & PIN_IN) {
29595f171baaSTakashi Iwai 		idx = out_jacks;
29605f171baaSTakashi Iwai 		if (in_jacks > 1) {
29615f171baaSTakashi Iwai 			unsigned int vref_caps = get_vref_caps(codec, nid);
29625f171baaSTakashi Iwai 			val &= AC_PINCTL_VREFEN;
29635f171baaSTakashi Iwai 			idx += cvt_from_vref_idx(vref_caps, val);
29645f171baaSTakashi Iwai 		}
29655f171baaSTakashi Iwai 	}
29665f171baaSTakashi Iwai 	return idx;
29675f171baaSTakashi Iwai }
29685f171baaSTakashi Iwai 
hp_mic_jack_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)29695f171baaSTakashi Iwai static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol,
29705f171baaSTakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
29715f171baaSTakashi Iwai {
29725f171baaSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
29735f171baaSTakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
29745f171baaSTakashi Iwai 	ucontrol->value.enumerated.item[0] =
29755f171baaSTakashi Iwai 		get_cur_hp_mic_jack_mode(codec, nid);
29765f171baaSTakashi Iwai 	return 0;
29775f171baaSTakashi Iwai }
29785f171baaSTakashi Iwai 
hp_mic_jack_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)29795f171baaSTakashi Iwai static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
29805f171baaSTakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
29815f171baaSTakashi Iwai {
29825f171baaSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
29835f171baaSTakashi Iwai 	hda_nid_t nid = kcontrol->private_value;
29845f171baaSTakashi Iwai 	int out_jacks = get_out_jack_num_items(codec, nid);
29855f171baaSTakashi Iwai 	int in_jacks = get_in_jack_num_items(codec, nid);
29865f171baaSTakashi Iwai 	unsigned int val, oldval, idx;
29875f171baaSTakashi Iwai 
29885f171baaSTakashi Iwai 	oldval = get_cur_hp_mic_jack_mode(codec, nid);
29895f171baaSTakashi Iwai 	idx = ucontrol->value.enumerated.item[0];
29905f171baaSTakashi Iwai 	if (oldval == idx)
29915f171baaSTakashi Iwai 		return 0;
29925f171baaSTakashi Iwai 
29935f171baaSTakashi Iwai 	if (idx < out_jacks) {
29945f171baaSTakashi Iwai 		if (out_jacks > 1)
29955f171baaSTakashi Iwai 			val = idx ? PIN_HP : PIN_OUT;
29965f171baaSTakashi Iwai 		else
29975f171baaSTakashi Iwai 			val = PIN_HP;
29985f171baaSTakashi Iwai 	} else {
29995f171baaSTakashi Iwai 		idx -= out_jacks;
30005f171baaSTakashi Iwai 		if (in_jacks > 1) {
30015f171baaSTakashi Iwai 			unsigned int vref_caps = get_vref_caps(codec, nid);
30025f171baaSTakashi Iwai 			val = snd_hda_codec_get_pin_target(codec, nid);
30033f550e32STakashi Iwai 			val &= ~(AC_PINCTL_VREFEN | PIN_HP);
30043f550e32STakashi Iwai 			val |= get_vref_idx(vref_caps, idx) | PIN_IN;
30055f171baaSTakashi Iwai 		} else
300616c0cefeSTakashi Iwai 			val = snd_hda_get_default_vref(codec, nid) | PIN_IN;
30075f171baaSTakashi Iwai 	}
30085f171baaSTakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, nid, val);
3009963afde9STakashi Iwai 	call_hp_automute(codec, NULL);
30108ba955ceSTakashi Iwai 
30115f171baaSTakashi Iwai 	return 1;
30125f171baaSTakashi Iwai }
30135f171baaSTakashi Iwai 
30145f171baaSTakashi Iwai static const struct snd_kcontrol_new hp_mic_jack_mode_enum = {
30155f171baaSTakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
30165f171baaSTakashi Iwai 	.info = hp_mic_jack_mode_info,
30175f171baaSTakashi Iwai 	.get = hp_mic_jack_mode_get,
30185f171baaSTakashi Iwai 	.put = hp_mic_jack_mode_put,
30195f171baaSTakashi Iwai };
30205f171baaSTakashi Iwai 
create_hp_mic_jack_mode(struct hda_codec * codec,hda_nid_t pin)30215f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
30225f171baaSTakashi Iwai {
30235f171baaSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
30245f171baaSTakashi Iwai 	struct snd_kcontrol_new *knew;
30255f171baaSTakashi Iwai 
30265f171baaSTakashi Iwai 	knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
30275f171baaSTakashi Iwai 				    &hp_mic_jack_mode_enum);
30285f171baaSTakashi Iwai 	if (!knew)
30295f171baaSTakashi Iwai 		return -ENOMEM;
30305f171baaSTakashi Iwai 	knew->private_value = pin;
30318ba955ceSTakashi Iwai 	spec->hp_mic_jack_modes = 1;
30325f171baaSTakashi Iwai 	return 0;
30335f171baaSTakashi Iwai }
3034352f7f91STakashi Iwai 
3035352f7f91STakashi Iwai /*
3036352f7f91STakashi Iwai  * Parse input paths
3037352f7f91STakashi Iwai  */
3038352f7f91STakashi Iwai 
3039352f7f91STakashi Iwai /* add the powersave loopback-list entry */
add_loopback_list(struct hda_gen_spec * spec,hda_nid_t mix,int idx)30400186f4f4STakashi Iwai static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
3041352f7f91STakashi Iwai {
3042352f7f91STakashi Iwai 	struct hda_amp_list *list;
3043352f7f91STakashi Iwai 
30440186f4f4STakashi Iwai 	list = snd_array_new(&spec->loopback_list);
30450186f4f4STakashi Iwai 	if (!list)
30460186f4f4STakashi Iwai 		return -ENOMEM;
3047352f7f91STakashi Iwai 	list->nid = mix;
3048352f7f91STakashi Iwai 	list->dir = HDA_INPUT;
3049352f7f91STakashi Iwai 	list->idx = idx;
30500186f4f4STakashi Iwai 	spec->loopback.amplist = spec->loopback_list.list;
30510186f4f4STakashi Iwai 	return 0;
3052cb53c626STakashi Iwai }
3053cb53c626STakashi Iwai 
30542ded3e5bSTakashi Iwai /* return true if either a volume or a mute amp is found for the given
30552ded3e5bSTakashi Iwai  * aamix path; the amp has to be either in the mixer node or its direct leaf
30562ded3e5bSTakashi Iwai  */
look_for_mix_leaf_ctls(struct hda_codec * codec,hda_nid_t mix_nid,hda_nid_t pin,unsigned int * mix_val,unsigned int * mute_val)30572ded3e5bSTakashi Iwai static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid,
30582ded3e5bSTakashi Iwai 				   hda_nid_t pin, unsigned int *mix_val,
30592ded3e5bSTakashi Iwai 				   unsigned int *mute_val)
30602ded3e5bSTakashi Iwai {
30612ded3e5bSTakashi Iwai 	int idx, num_conns;
30622ded3e5bSTakashi Iwai 	const hda_nid_t *list;
30632ded3e5bSTakashi Iwai 	hda_nid_t nid;
30642ded3e5bSTakashi Iwai 
30652ded3e5bSTakashi Iwai 	idx = snd_hda_get_conn_index(codec, mix_nid, pin, true);
30662ded3e5bSTakashi Iwai 	if (idx < 0)
30672ded3e5bSTakashi Iwai 		return false;
30682ded3e5bSTakashi Iwai 
30692ded3e5bSTakashi Iwai 	*mix_val = *mute_val = 0;
30702ded3e5bSTakashi Iwai 	if (nid_has_volume(codec, mix_nid, HDA_INPUT))
30712ded3e5bSTakashi Iwai 		*mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
30722ded3e5bSTakashi Iwai 	if (nid_has_mute(codec, mix_nid, HDA_INPUT))
30732ded3e5bSTakashi Iwai 		*mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
30742ded3e5bSTakashi Iwai 	if (*mix_val && *mute_val)
30752ded3e5bSTakashi Iwai 		return true;
30762ded3e5bSTakashi Iwai 
30772ded3e5bSTakashi Iwai 	/* check leaf node */
30782ded3e5bSTakashi Iwai 	num_conns = snd_hda_get_conn_list(codec, mix_nid, &list);
30792ded3e5bSTakashi Iwai 	if (num_conns < idx)
30802ded3e5bSTakashi Iwai 		return false;
30812ded3e5bSTakashi Iwai 	nid = list[idx];
308243a8e50aSTakashi Iwai 	if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) &&
308343a8e50aSTakashi Iwai 	    !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL))
30842ded3e5bSTakashi Iwai 		*mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
308543a8e50aSTakashi Iwai 	if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) &&
308643a8e50aSTakashi Iwai 	    !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL))
30872ded3e5bSTakashi Iwai 		*mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
30882ded3e5bSTakashi Iwai 
30892ded3e5bSTakashi Iwai 	return *mix_val || *mute_val;
30902ded3e5bSTakashi Iwai }
30912ded3e5bSTakashi Iwai 
3092352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */
new_analog_input(struct hda_codec * codec,int input_idx,hda_nid_t pin,const char * ctlname,int ctlidx,hda_nid_t mix_nid)3093196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx,
3094196c1766STakashi Iwai 			    hda_nid_t pin, const char *ctlname, int ctlidx,
3095352f7f91STakashi Iwai 			    hda_nid_t mix_nid)
30961da177e4SLinus Torvalds {
3097352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3098352f7f91STakashi Iwai 	struct nid_path *path;
30992ded3e5bSTakashi Iwai 	unsigned int mix_val, mute_val;
3100352f7f91STakashi Iwai 	int err, idx;
31011da177e4SLinus Torvalds 
31022ded3e5bSTakashi Iwai 	if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val))
31032ded3e5bSTakashi Iwai 		return 0;
3104352f7f91STakashi Iwai 
31053ca529d3STakashi Iwai 	path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
3106352f7f91STakashi Iwai 	if (!path)
3107352f7f91STakashi Iwai 		return -EINVAL;
31084e76a883STakashi Iwai 	print_nid_path(codec, "loopback", path);
3109196c1766STakashi Iwai 	spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
3110352f7f91STakashi Iwai 
3111352f7f91STakashi Iwai 	idx = path->idx[path->depth - 1];
31122ded3e5bSTakashi Iwai 	if (mix_val) {
31132ded3e5bSTakashi Iwai 		err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val);
3114d13bd412STakashi Iwai 		if (err < 0)
31151da177e4SLinus Torvalds 			return err;
31162ded3e5bSTakashi Iwai 		path->ctls[NID_PATH_VOL_CTL] = mix_val;
31171da177e4SLinus Torvalds 	}
31181da177e4SLinus Torvalds 
31192ded3e5bSTakashi Iwai 	if (mute_val) {
31202ded3e5bSTakashi Iwai 		err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val);
3121d13bd412STakashi Iwai 		if (err < 0)
31221da177e4SLinus Torvalds 			return err;
31232ded3e5bSTakashi Iwai 		path->ctls[NID_PATH_MUTE_CTL] = mute_val;
31241da177e4SLinus Torvalds 	}
31251da177e4SLinus Torvalds 
3126352f7f91STakashi Iwai 	path->active = true;
3127e6feb5d0STakashi Iwai 	path->stream_enabled = true; /* no DAC/ADC involved */
31280186f4f4STakashi Iwai 	err = add_loopback_list(spec, mix_nid, idx);
31290186f4f4STakashi Iwai 	if (err < 0)
31300186f4f4STakashi Iwai 		return err;
3131e4a395e7STakashi Iwai 
3132e4a395e7STakashi Iwai 	if (spec->mixer_nid != spec->mixer_merge_nid &&
3133e4a395e7STakashi Iwai 	    !spec->loopback_merge_path) {
3134e4a395e7STakashi Iwai 		path = snd_hda_add_new_path(codec, spec->mixer_nid,
3135e4a395e7STakashi Iwai 					    spec->mixer_merge_nid, 0);
3136e4a395e7STakashi Iwai 		if (path) {
31374e76a883STakashi Iwai 			print_nid_path(codec, "loopback-merge", path);
3138e4a395e7STakashi Iwai 			path->active = true;
31396b275b14STakashi Iwai 			path->pin_fixed = true; /* static route */
3140e6feb5d0STakashi Iwai 			path->stream_enabled = true; /* no DAC/ADC involved */
3141e4a395e7STakashi Iwai 			spec->loopback_merge_path =
3142e4a395e7STakashi Iwai 				snd_hda_get_path_idx(codec, path);
3143e4a395e7STakashi Iwai 		}
3144e4a395e7STakashi Iwai 	}
3145e4a395e7STakashi Iwai 
3146352f7f91STakashi Iwai 	return 0;
31471da177e4SLinus Torvalds }
31481da177e4SLinus Torvalds 
is_input_pin(struct hda_codec * codec,hda_nid_t nid)3149352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid)
31501da177e4SLinus Torvalds {
3151352f7f91STakashi Iwai 	unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
3152352f7f91STakashi Iwai 	return (pincap & AC_PINCAP_IN) != 0;
3153352f7f91STakashi Iwai }
3154352f7f91STakashi Iwai 
3155352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */
fill_adc_nids(struct hda_codec * codec)3156352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec)
3157352f7f91STakashi Iwai {
3158352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3159352f7f91STakashi Iwai 	hda_nid_t nid;
3160352f7f91STakashi Iwai 	hda_nid_t *adc_nids = spec->adc_nids;
3161352f7f91STakashi Iwai 	int max_nums = ARRAY_SIZE(spec->adc_nids);
31627639a06cSTakashi Iwai 	int nums = 0;
3163352f7f91STakashi Iwai 
31647639a06cSTakashi Iwai 	for_each_hda_codec_node(nid, codec) {
3165352f7f91STakashi Iwai 		unsigned int caps = get_wcaps(codec, nid);
3166352f7f91STakashi Iwai 		int type = get_wcaps_type(caps);
3167352f7f91STakashi Iwai 
3168352f7f91STakashi Iwai 		if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
3169352f7f91STakashi Iwai 			continue;
3170352f7f91STakashi Iwai 		adc_nids[nums] = nid;
3171352f7f91STakashi Iwai 		if (++nums >= max_nums)
3172352f7f91STakashi Iwai 			break;
3173352f7f91STakashi Iwai 	}
3174352f7f91STakashi Iwai 	spec->num_adc_nids = nums;
31750ffd534eSTakashi Iwai 
31760ffd534eSTakashi Iwai 	/* copy the detected ADCs to all_adcs[] */
31770ffd534eSTakashi Iwai 	spec->num_all_adcs = nums;
31780ffd534eSTakashi Iwai 	memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t));
31790ffd534eSTakashi Iwai 
3180352f7f91STakashi Iwai 	return nums;
3181352f7f91STakashi Iwai }
3182352f7f91STakashi Iwai 
3183352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins;
3184352f7f91STakashi Iwai  * if needed, check whether dynamic ADC-switching is available
3185352f7f91STakashi Iwai  */
check_dyn_adc_switch(struct hda_codec * codec)3186352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec)
3187352f7f91STakashi Iwai {
3188352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3189352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
31903a65bcdcSTakashi Iwai 	unsigned int ok_bits;
3191352f7f91STakashi Iwai 	int i, n, nums;
3192352f7f91STakashi Iwai 
3193352f7f91STakashi Iwai 	nums = 0;
31943a65bcdcSTakashi Iwai 	ok_bits = 0;
3195352f7f91STakashi Iwai 	for (n = 0; n < spec->num_adc_nids; n++) {
3196352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
31973a65bcdcSTakashi Iwai 			if (!spec->input_paths[i][n])
3198352f7f91STakashi Iwai 				break;
3199352f7f91STakashi Iwai 		}
32003a65bcdcSTakashi Iwai 		if (i >= imux->num_items) {
32013a65bcdcSTakashi Iwai 			ok_bits |= (1 << n);
32023a65bcdcSTakashi Iwai 			nums++;
32033a65bcdcSTakashi Iwai 		}
3204352f7f91STakashi Iwai 	}
3205352f7f91STakashi Iwai 
32063a65bcdcSTakashi Iwai 	if (!ok_bits) {
3207352f7f91STakashi Iwai 		/* check whether ADC-switch is possible */
3208352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
3209352f7f91STakashi Iwai 			for (n = 0; n < spec->num_adc_nids; n++) {
32103a65bcdcSTakashi Iwai 				if (spec->input_paths[i][n]) {
3211352f7f91STakashi Iwai 					spec->dyn_adc_idx[i] = n;
3212352f7f91STakashi Iwai 					break;
3213352f7f91STakashi Iwai 				}
3214352f7f91STakashi Iwai 			}
3215352f7f91STakashi Iwai 		}
3216352f7f91STakashi Iwai 
32174e76a883STakashi Iwai 		codec_dbg(codec, "enabling ADC switching\n");
3218352f7f91STakashi Iwai 		spec->dyn_adc_switch = 1;
3219352f7f91STakashi Iwai 	} else if (nums != spec->num_adc_nids) {
32203a65bcdcSTakashi Iwai 		/* shrink the invalid adcs and input paths */
32213a65bcdcSTakashi Iwai 		nums = 0;
32223a65bcdcSTakashi Iwai 		for (n = 0; n < spec->num_adc_nids; n++) {
32233a65bcdcSTakashi Iwai 			if (!(ok_bits & (1 << n)))
32243a65bcdcSTakashi Iwai 				continue;
32253a65bcdcSTakashi Iwai 			if (n != nums) {
32263a65bcdcSTakashi Iwai 				spec->adc_nids[nums] = spec->adc_nids[n];
3227980428ceSTakashi Iwai 				for (i = 0; i < imux->num_items; i++) {
3228980428ceSTakashi Iwai 					invalidate_nid_path(codec,
3229980428ceSTakashi Iwai 						spec->input_paths[i][nums]);
32303a65bcdcSTakashi Iwai 					spec->input_paths[i][nums] =
32313a65bcdcSTakashi Iwai 						spec->input_paths[i][n];
3232a8f20fd2SHui Wang 					spec->input_paths[i][n] = 0;
32333a65bcdcSTakashi Iwai 				}
3234980428ceSTakashi Iwai 			}
32353a65bcdcSTakashi Iwai 			nums++;
32363a65bcdcSTakashi Iwai 		}
3237352f7f91STakashi Iwai 		spec->num_adc_nids = nums;
3238352f7f91STakashi Iwai 	}
3239352f7f91STakashi Iwai 
3240967303daSTakashi Iwai 	if (imux->num_items == 1 ||
3241967303daSTakashi Iwai 	    (imux->num_items == 2 && spec->hp_mic)) {
32424e76a883STakashi Iwai 		codec_dbg(codec, "reducing to a single ADC\n");
3243352f7f91STakashi Iwai 		spec->num_adc_nids = 1; /* reduce to a single ADC */
3244352f7f91STakashi Iwai 	}
3245352f7f91STakashi Iwai 
3246352f7f91STakashi Iwai 	/* single index for individual volumes ctls */
3247352f7f91STakashi Iwai 	if (!spec->dyn_adc_switch && spec->multi_cap_vol)
3248352f7f91STakashi Iwai 		spec->num_adc_nids = 1;
3249352f7f91STakashi Iwai 
32501da177e4SLinus Torvalds 	return 0;
32511da177e4SLinus Torvalds }
32521da177e4SLinus Torvalds 
3253f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */
parse_capture_source(struct hda_codec * codec,hda_nid_t pin,int cfg_idx,int num_adcs,const char * label,int anchor)3254f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
32559dba205bSTakashi Iwai 				int cfg_idx, int num_adcs,
32569dba205bSTakashi Iwai 				const char *label, int anchor)
3257f3fc0b0bSTakashi Iwai {
3258f3fc0b0bSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3259f3fc0b0bSTakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3260f3fc0b0bSTakashi Iwai 	int imux_idx = imux->num_items;
3261f3fc0b0bSTakashi Iwai 	bool imux_added = false;
3262f3fc0b0bSTakashi Iwai 	int c;
3263f3fc0b0bSTakashi Iwai 
3264f3fc0b0bSTakashi Iwai 	for (c = 0; c < num_adcs; c++) {
3265f3fc0b0bSTakashi Iwai 		struct nid_path *path;
3266f3fc0b0bSTakashi Iwai 		hda_nid_t adc = spec->adc_nids[c];
3267f3fc0b0bSTakashi Iwai 
3268f3fc0b0bSTakashi Iwai 		if (!is_reachable_path(codec, pin, adc))
3269f3fc0b0bSTakashi Iwai 			continue;
3270f3fc0b0bSTakashi Iwai 		path = snd_hda_add_new_path(codec, pin, adc, anchor);
3271f3fc0b0bSTakashi Iwai 		if (!path)
3272f3fc0b0bSTakashi Iwai 			continue;
32734e76a883STakashi Iwai 		print_nid_path(codec, "input", path);
3274f3fc0b0bSTakashi Iwai 		spec->input_paths[imux_idx][c] =
3275f3fc0b0bSTakashi Iwai 			snd_hda_get_path_idx(codec, path);
3276f3fc0b0bSTakashi Iwai 
3277f3fc0b0bSTakashi Iwai 		if (!imux_added) {
3278967303daSTakashi Iwai 			if (spec->hp_mic_pin == pin)
3279967303daSTakashi Iwai 				spec->hp_mic_mux_idx = imux->num_items;
3280f3fc0b0bSTakashi Iwai 			spec->imux_pins[imux->num_items] = pin;
32816194b99dSTakashi Iwai 			snd_hda_add_imux_item(codec, imux, label, cfg_idx, NULL);
3282f3fc0b0bSTakashi Iwai 			imux_added = true;
3283f1e762ddSTakashi Iwai 			if (spec->dyn_adc_switch)
3284f1e762ddSTakashi Iwai 				spec->dyn_adc_idx[imux_idx] = c;
3285f3fc0b0bSTakashi Iwai 		}
3286f3fc0b0bSTakashi Iwai 	}
3287f3fc0b0bSTakashi Iwai 
3288f3fc0b0bSTakashi Iwai 	return 0;
3289f3fc0b0bSTakashi Iwai }
3290f3fc0b0bSTakashi Iwai 
32911da177e4SLinus Torvalds /*
3292352f7f91STakashi Iwai  * create playback/capture controls for input pins
32931da177e4SLinus Torvalds  */
32949dba205bSTakashi Iwai 
3295c970042cSTakashi Iwai /* fill the label for each input at first */
fill_input_pin_labels(struct hda_codec * codec)3296c970042cSTakashi Iwai static int fill_input_pin_labels(struct hda_codec *codec)
3297c970042cSTakashi Iwai {
3298c970042cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3299c970042cSTakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
3300c970042cSTakashi Iwai 	int i;
3301c970042cSTakashi Iwai 
3302c970042cSTakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
3303c970042cSTakashi Iwai 		hda_nid_t pin = cfg->inputs[i].pin;
3304c970042cSTakashi Iwai 		const char *label;
3305c970042cSTakashi Iwai 		int j, idx;
3306c970042cSTakashi Iwai 
3307c970042cSTakashi Iwai 		if (!is_input_pin(codec, pin))
3308c970042cSTakashi Iwai 			continue;
3309c970042cSTakashi Iwai 
3310c970042cSTakashi Iwai 		label = hda_get_autocfg_input_label(codec, cfg, i);
3311c970042cSTakashi Iwai 		idx = 0;
33128e8db7f1SDavid Henningsson 		for (j = i - 1; j >= 0; j--) {
3313c970042cSTakashi Iwai 			if (spec->input_labels[j] &&
3314c970042cSTakashi Iwai 			    !strcmp(spec->input_labels[j], label)) {
3315c970042cSTakashi Iwai 				idx = spec->input_label_idxs[j] + 1;
3316c970042cSTakashi Iwai 				break;
3317c970042cSTakashi Iwai 			}
3318c970042cSTakashi Iwai 		}
3319c970042cSTakashi Iwai 
3320c970042cSTakashi Iwai 		spec->input_labels[i] = label;
3321c970042cSTakashi Iwai 		spec->input_label_idxs[i] = idx;
3322c970042cSTakashi Iwai 	}
3323c970042cSTakashi Iwai 
3324c970042cSTakashi Iwai 	return 0;
3325c970042cSTakashi Iwai }
3326c970042cSTakashi Iwai 
33279dba205bSTakashi Iwai #define CFG_IDX_MIX	99	/* a dummy cfg->input idx for stereo mix */
33289dba205bSTakashi Iwai 
create_input_ctls(struct hda_codec * codec)3329352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec)
3330a7da6ce5STakashi Iwai {
3331352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3332352f7f91STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
3333352f7f91STakashi Iwai 	hda_nid_t mixer = spec->mixer_nid;
3334352f7f91STakashi Iwai 	int num_adcs;
3335c970042cSTakashi Iwai 	int i, err;
33362c12c30dSTakashi Iwai 	unsigned int val;
3337a7da6ce5STakashi Iwai 
3338352f7f91STakashi Iwai 	num_adcs = fill_adc_nids(codec);
3339352f7f91STakashi Iwai 	if (num_adcs < 0)
3340352f7f91STakashi Iwai 		return 0;
3341352f7f91STakashi Iwai 
3342c970042cSTakashi Iwai 	err = fill_input_pin_labels(codec);
3343c970042cSTakashi Iwai 	if (err < 0)
3344c970042cSTakashi Iwai 		return err;
3345c970042cSTakashi Iwai 
3346352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
3347352f7f91STakashi Iwai 		hda_nid_t pin;
3348352f7f91STakashi Iwai 
3349352f7f91STakashi Iwai 		pin = cfg->inputs[i].pin;
3350352f7f91STakashi Iwai 		if (!is_input_pin(codec, pin))
3351352f7f91STakashi Iwai 			continue;
3352352f7f91STakashi Iwai 
33532c12c30dSTakashi Iwai 		val = PIN_IN;
33542c12c30dSTakashi Iwai 		if (cfg->inputs[i].type == AUTO_PIN_MIC)
33552c12c30dSTakashi Iwai 			val |= snd_hda_get_default_vref(codec, pin);
33563e1b0c4aSTakashi Iwai 		if (pin != spec->hp_mic_pin &&
33573e1b0c4aSTakashi Iwai 		    !snd_hda_codec_get_pin_target(codec, pin))
33582c12c30dSTakashi Iwai 			set_pin_target(codec, pin, val, false);
33592c12c30dSTakashi Iwai 
3360352f7f91STakashi Iwai 		if (mixer) {
3361352f7f91STakashi Iwai 			if (is_reachable_path(codec, pin, mixer)) {
3362196c1766STakashi Iwai 				err = new_analog_input(codec, i, pin,
3363c970042cSTakashi Iwai 						       spec->input_labels[i],
3364c970042cSTakashi Iwai 						       spec->input_label_idxs[i],
3365c970042cSTakashi Iwai 						       mixer);
3366a7da6ce5STakashi Iwai 				if (err < 0)
3367a7da6ce5STakashi Iwai 					return err;
3368a7da6ce5STakashi Iwai 			}
3369352f7f91STakashi Iwai 		}
3370352f7f91STakashi Iwai 
3371c970042cSTakashi Iwai 		err = parse_capture_source(codec, pin, i, num_adcs,
3372c970042cSTakashi Iwai 					   spec->input_labels[i], -mixer);
3373f3fc0b0bSTakashi Iwai 		if (err < 0)
3374f3fc0b0bSTakashi Iwai 			return err;
337529476558STakashi Iwai 
3376f811c3cfSTakashi Iwai 		if (spec->add_jack_modes) {
337729476558STakashi Iwai 			err = create_in_jack_mode(codec, pin);
337829476558STakashi Iwai 			if (err < 0)
337929476558STakashi Iwai 				return err;
338029476558STakashi Iwai 		}
3381352f7f91STakashi Iwai 	}
3382f3fc0b0bSTakashi Iwai 
3383f1e762ddSTakashi Iwai 	/* add stereo mix when explicitly enabled via hint */
338474f14b36STakashi Iwai 	if (mixer && spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_ENABLE) {
33859dba205bSTakashi Iwai 		err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
3386f3fc0b0bSTakashi Iwai 					   "Stereo Mix", 0);
3387f3fc0b0bSTakashi Iwai 		if (err < 0)
3388f3fc0b0bSTakashi Iwai 			return err;
338982d04e10STakashi Iwai 		else
339082d04e10STakashi Iwai 			spec->suppress_auto_mic = 1;
3391352f7f91STakashi Iwai 	}
3392352f7f91STakashi Iwai 
3393a7da6ce5STakashi Iwai 	return 0;
3394a7da6ce5STakashi Iwai }
3395a7da6ce5STakashi Iwai 
33961da177e4SLinus Torvalds 
3397352f7f91STakashi Iwai /*
3398352f7f91STakashi Iwai  * input source mux
3399352f7f91STakashi Iwai  */
3400352f7f91STakashi Iwai 
3401c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */
get_input_path(struct hda_codec * codec,int adc_idx,int imux_idx)3402c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx)
3403352f7f91STakashi Iwai {
3404352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3405b56fa1edSDavid Henningsson 	if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) {
3406b56fa1edSDavid Henningsson 		snd_BUG();
3407b56fa1edSDavid Henningsson 		return NULL;
3408b56fa1edSDavid Henningsson 	}
3409352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
3410352f7f91STakashi Iwai 		adc_idx = spec->dyn_adc_idx[imux_idx];
3411d3d982f7SDavid Henningsson 	if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) {
3412b56fa1edSDavid Henningsson 		snd_BUG();
3413b56fa1edSDavid Henningsson 		return NULL;
3414b56fa1edSDavid Henningsson 	}
3415c697b716STakashi Iwai 	return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]);
341697ec558aSTakashi Iwai }
3417352f7f91STakashi Iwai 
3418352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
3419352f7f91STakashi Iwai 		      unsigned int idx);
3420352f7f91STakashi Iwai 
mux_enum_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3421352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol,
3422352f7f91STakashi Iwai 			 struct snd_ctl_elem_info *uinfo)
3423352f7f91STakashi Iwai {
3424352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3425352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3426352f7f91STakashi Iwai 	return snd_hda_input_mux_info(&spec->input_mux, uinfo);
3427352f7f91STakashi Iwai }
3428352f7f91STakashi Iwai 
mux_enum_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3429352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol,
3430352f7f91STakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
3431352f7f91STakashi Iwai {
3432352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3433352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
34342a8d5391STakashi Iwai 	/* the ctls are created at once with multiple counts */
34352a8d5391STakashi Iwai 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3436352f7f91STakashi Iwai 
3437352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
34381da177e4SLinus Torvalds 	return 0;
34391da177e4SLinus Torvalds }
34401da177e4SLinus Torvalds 
mux_enum_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3441352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol,
3442352f7f91STakashi Iwai 			    struct snd_ctl_elem_value *ucontrol)
34431da177e4SLinus Torvalds {
3444352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
34452a8d5391STakashi Iwai 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3446352f7f91STakashi Iwai 	return mux_select(codec, adc_idx,
3447352f7f91STakashi Iwai 			  ucontrol->value.enumerated.item[0]);
3448352f7f91STakashi Iwai }
3449352f7f91STakashi Iwai 
3450352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = {
34511da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3452352f7f91STakashi Iwai 	.name = "Input Source",
3453352f7f91STakashi Iwai 	.info = mux_enum_info,
3454352f7f91STakashi Iwai 	.get = mux_enum_get,
3455352f7f91STakashi Iwai 	.put = mux_enum_put,
34561da177e4SLinus Torvalds };
3457071c73adSTakashi Iwai 
345847d46abbSTakashi Iwai /*
345947d46abbSTakashi Iwai  * capture volume and capture switch ctls
346047d46abbSTakashi Iwai  */
346147d46abbSTakashi Iwai 
3462352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol,
3463352f7f91STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol);
3464071c73adSTakashi Iwai 
346547d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */
cap_put_caller(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol,put_call_t func,int type)3466352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol,
3467352f7f91STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol,
3468352f7f91STakashi Iwai 			  put_call_t func, int type)
3469352f7f91STakashi Iwai {
3470352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3471352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3472352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
3473352f7f91STakashi Iwai 	struct nid_path *path;
3474a2befe93SJaroslav Kysela 	int i, adc_idx, ret, err = 0;
3475071c73adSTakashi Iwai 
3476352f7f91STakashi Iwai 	imux = &spec->input_mux;
3477a053d1e3SDavid Henningsson 	adc_idx = kcontrol->id.index;
3478352f7f91STakashi Iwai 	mutex_lock(&codec->control_mutex);
3479352f7f91STakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
3480c697b716STakashi Iwai 		path = get_input_path(codec, adc_idx, i);
3481c697b716STakashi Iwai 		if (!path || !path->ctls[type])
3482352f7f91STakashi Iwai 			continue;
3483352f7f91STakashi Iwai 		kcontrol->private_value = path->ctls[type];
3484a2befe93SJaroslav Kysela 		ret = func(kcontrol, ucontrol);
3485a2befe93SJaroslav Kysela 		if (ret < 0) {
3486a2befe93SJaroslav Kysela 			err = ret;
3487a551d914STakashi Iwai 			break;
3488352f7f91STakashi Iwai 		}
3489a2befe93SJaroslav Kysela 		if (ret > 0)
3490a2befe93SJaroslav Kysela 			err = 1;
3491a2befe93SJaroslav Kysela 	}
3492352f7f91STakashi Iwai 	mutex_unlock(&codec->control_mutex);
3493352f7f91STakashi Iwai 	if (err >= 0 && spec->cap_sync_hook)
34947fe30711STakashi Iwai 		spec->cap_sync_hook(codec, kcontrol, ucontrol);
3495352f7f91STakashi Iwai 	return err;
3496352f7f91STakashi Iwai }
3497352f7f91STakashi Iwai 
3498352f7f91STakashi Iwai /* capture volume ctl callbacks */
3499352f7f91STakashi Iwai #define cap_vol_info		snd_hda_mixer_amp_volume_info
3500352f7f91STakashi Iwai #define cap_vol_get		snd_hda_mixer_amp_volume_get
3501352f7f91STakashi Iwai #define cap_vol_tlv		snd_hda_mixer_amp_tlv
3502352f7f91STakashi Iwai 
cap_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3503352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol,
3504352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
3505352f7f91STakashi Iwai {
3506352f7f91STakashi Iwai 	return cap_put_caller(kcontrol, ucontrol,
3507352f7f91STakashi Iwai 			      snd_hda_mixer_amp_volume_put,
3508352f7f91STakashi Iwai 			      NID_PATH_VOL_CTL);
3509352f7f91STakashi Iwai }
3510352f7f91STakashi Iwai 
3511352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = {
3512352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3513352f7f91STakashi Iwai 	.name = "Capture Volume",
3514352f7f91STakashi Iwai 	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
3515352f7f91STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_READ |
3516352f7f91STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
3517352f7f91STakashi Iwai 	.info = cap_vol_info,
3518352f7f91STakashi Iwai 	.get = cap_vol_get,
3519352f7f91STakashi Iwai 	.put = cap_vol_put,
3520352f7f91STakashi Iwai 	.tlv = { .c = cap_vol_tlv },
3521352f7f91STakashi Iwai };
3522352f7f91STakashi Iwai 
3523352f7f91STakashi Iwai /* capture switch ctl callbacks */
3524352f7f91STakashi Iwai #define cap_sw_info		snd_ctl_boolean_stereo_info
3525352f7f91STakashi Iwai #define cap_sw_get		snd_hda_mixer_amp_switch_get
3526352f7f91STakashi Iwai 
cap_sw_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3527352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol,
3528352f7f91STakashi Iwai 		      struct snd_ctl_elem_value *ucontrol)
3529352f7f91STakashi Iwai {
3530a90229e0STakashi Iwai 	return cap_put_caller(kcontrol, ucontrol,
3531352f7f91STakashi Iwai 			      snd_hda_mixer_amp_switch_put,
3532352f7f91STakashi Iwai 			      NID_PATH_MUTE_CTL);
3533352f7f91STakashi Iwai }
3534352f7f91STakashi Iwai 
3535352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = {
3536352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3537352f7f91STakashi Iwai 	.name = "Capture Switch",
353808a4b904STakashi Iwai 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
3539352f7f91STakashi Iwai 	.info = cap_sw_info,
3540352f7f91STakashi Iwai 	.get = cap_sw_get,
3541352f7f91STakashi Iwai 	.put = cap_sw_put,
3542352f7f91STakashi Iwai };
3543352f7f91STakashi Iwai 
parse_capvol_in_path(struct hda_codec * codec,struct nid_path * path)3544352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path)
3545352f7f91STakashi Iwai {
3546352f7f91STakashi Iwai 	hda_nid_t nid;
3547352f7f91STakashi Iwai 	int i, depth;
3548352f7f91STakashi Iwai 
3549352f7f91STakashi Iwai 	path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0;
3550352f7f91STakashi Iwai 	for (depth = 0; depth < 3; depth++) {
3551352f7f91STakashi Iwai 		if (depth >= path->depth)
3552352f7f91STakashi Iwai 			return -EINVAL;
3553352f7f91STakashi Iwai 		i = path->depth - depth - 1;
3554352f7f91STakashi Iwai 		nid = path->path[i];
3555352f7f91STakashi Iwai 		if (!path->ctls[NID_PATH_VOL_CTL]) {
3556352f7f91STakashi Iwai 			if (nid_has_volume(codec, nid, HDA_OUTPUT))
3557352f7f91STakashi Iwai 				path->ctls[NID_PATH_VOL_CTL] =
3558352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
3559352f7f91STakashi Iwai 			else if (nid_has_volume(codec, nid, HDA_INPUT)) {
3560352f7f91STakashi Iwai 				int idx = path->idx[i];
3561352f7f91STakashi Iwai 				if (!depth && codec->single_adc_amp)
3562352f7f91STakashi Iwai 					idx = 0;
3563352f7f91STakashi Iwai 				path->ctls[NID_PATH_VOL_CTL] =
3564352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
3565352f7f91STakashi Iwai 			}
3566352f7f91STakashi Iwai 		}
3567352f7f91STakashi Iwai 		if (!path->ctls[NID_PATH_MUTE_CTL]) {
3568352f7f91STakashi Iwai 			if (nid_has_mute(codec, nid, HDA_OUTPUT))
3569352f7f91STakashi Iwai 				path->ctls[NID_PATH_MUTE_CTL] =
3570352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
3571352f7f91STakashi Iwai 			else if (nid_has_mute(codec, nid, HDA_INPUT)) {
3572352f7f91STakashi Iwai 				int idx = path->idx[i];
3573352f7f91STakashi Iwai 				if (!depth && codec->single_adc_amp)
3574352f7f91STakashi Iwai 					idx = 0;
3575352f7f91STakashi Iwai 				path->ctls[NID_PATH_MUTE_CTL] =
3576352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
3577352f7f91STakashi Iwai 			}
3578352f7f91STakashi Iwai 		}
3579352f7f91STakashi Iwai 	}
3580352f7f91STakashi Iwai 	return 0;
3581352f7f91STakashi Iwai }
3582352f7f91STakashi Iwai 
is_inv_dmic_pin(struct hda_codec * codec,hda_nid_t nid)3583352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid)
3584352f7f91STakashi Iwai {
3585352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3586352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
3587352f7f91STakashi Iwai 	unsigned int val;
3588352f7f91STakashi Iwai 	int i;
3589352f7f91STakashi Iwai 
3590352f7f91STakashi Iwai 	if (!spec->inv_dmic_split)
3591352f7f91STakashi Iwai 		return false;
3592352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
3593352f7f91STakashi Iwai 		if (cfg->inputs[i].pin != nid)
3594352f7f91STakashi Iwai 			continue;
3595352f7f91STakashi Iwai 		if (cfg->inputs[i].type != AUTO_PIN_MIC)
3596352f7f91STakashi Iwai 			return false;
3597352f7f91STakashi Iwai 		val = snd_hda_codec_get_pincfg(codec, nid);
3598352f7f91STakashi Iwai 		return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT;
3599352f7f91STakashi Iwai 	}
3600352f7f91STakashi Iwai 	return false;
3601352f7f91STakashi Iwai }
3602352f7f91STakashi Iwai 
3603a90229e0STakashi Iwai /* capture switch put callback for a single control with hook call */
cap_single_sw_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3604a35bd1e3STakashi Iwai static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
3605a35bd1e3STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
3606a35bd1e3STakashi Iwai {
3607a35bd1e3STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3608a35bd1e3STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3609a35bd1e3STakashi Iwai 	int ret;
3610a35bd1e3STakashi Iwai 
3611a35bd1e3STakashi Iwai 	ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3612a35bd1e3STakashi Iwai 	if (ret < 0)
3613a35bd1e3STakashi Iwai 		return ret;
3614a35bd1e3STakashi Iwai 
3615a90229e0STakashi Iwai 	if (spec->cap_sync_hook)
36167fe30711STakashi Iwai 		spec->cap_sync_hook(codec, kcontrol, ucontrol);
3617a35bd1e3STakashi Iwai 
3618a35bd1e3STakashi Iwai 	return ret;
3619a35bd1e3STakashi Iwai }
3620a35bd1e3STakashi Iwai 
add_single_cap_ctl(struct hda_codec * codec,const char * label,int idx,bool is_switch,unsigned int ctl,bool inv_dmic)3621352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
3622352f7f91STakashi Iwai 			      int idx, bool is_switch, unsigned int ctl,
3623352f7f91STakashi Iwai 			      bool inv_dmic)
3624352f7f91STakashi Iwai {
3625352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3626975cc02aSTakashi Iwai 	char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
3627352f7f91STakashi Iwai 	int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
3628352f7f91STakashi Iwai 	const char *sfx = is_switch ? "Switch" : "Volume";
3629352f7f91STakashi Iwai 	unsigned int chs = inv_dmic ? 1 : 3;
3630a35bd1e3STakashi Iwai 	struct snd_kcontrol_new *knew;
3631352f7f91STakashi Iwai 
3632352f7f91STakashi Iwai 	if (!ctl)
3633352f7f91STakashi Iwai 		return 0;
3634352f7f91STakashi Iwai 
3635352f7f91STakashi Iwai 	if (label)
3636352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
3637352f7f91STakashi Iwai 			 "%s Capture %s", label, sfx);
3638352f7f91STakashi Iwai 	else
3639352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
3640352f7f91STakashi Iwai 			 "Capture %s", sfx);
3641a35bd1e3STakashi Iwai 	knew = add_control(spec, type, tmpname, idx,
3642352f7f91STakashi Iwai 			   amp_val_replace_channels(ctl, chs));
3643a35bd1e3STakashi Iwai 	if (!knew)
3644a35bd1e3STakashi Iwai 		return -ENOMEM;
3645e65bf997SJaroslav Kysela 	if (is_switch) {
3646a35bd1e3STakashi Iwai 		knew->put = cap_single_sw_put;
3647e65bf997SJaroslav Kysela 		if (spec->mic_mute_led)
3648e65bf997SJaroslav Kysela 			knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
3649e65bf997SJaroslav Kysela 	}
3650a35bd1e3STakashi Iwai 	if (!inv_dmic)
3651a35bd1e3STakashi Iwai 		return 0;
3652352f7f91STakashi Iwai 
3653352f7f91STakashi Iwai 	/* Make independent right kcontrol */
3654352f7f91STakashi Iwai 	if (label)
3655352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
3656352f7f91STakashi Iwai 			 "Inverted %s Capture %s", label, sfx);
3657352f7f91STakashi Iwai 	else
3658352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
3659352f7f91STakashi Iwai 			 "Inverted Capture %s", sfx);
3660a35bd1e3STakashi Iwai 	knew = add_control(spec, type, tmpname, idx,
3661352f7f91STakashi Iwai 			   amp_val_replace_channels(ctl, 2));
3662a35bd1e3STakashi Iwai 	if (!knew)
3663a35bd1e3STakashi Iwai 		return -ENOMEM;
3664e65bf997SJaroslav Kysela 	if (is_switch) {
3665a35bd1e3STakashi Iwai 		knew->put = cap_single_sw_put;
3666e65bf997SJaroslav Kysela 		if (spec->mic_mute_led)
3667e65bf997SJaroslav Kysela 			knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
3668e65bf997SJaroslav Kysela 	}
3669a35bd1e3STakashi Iwai 	return 0;
3670352f7f91STakashi Iwai }
3671352f7f91STakashi Iwai 
3672352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */
create_single_cap_vol_ctl(struct hda_codec * codec,int idx,unsigned int vol_ctl,unsigned int sw_ctl,bool inv_dmic)3673352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx,
3674352f7f91STakashi Iwai 				     unsigned int vol_ctl, unsigned int sw_ctl,
3675352f7f91STakashi Iwai 				     bool inv_dmic)
3676352f7f91STakashi Iwai {
3677352f7f91STakashi Iwai 	int err;
3678352f7f91STakashi Iwai 	err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic);
3679352f7f91STakashi Iwai 	if (err < 0)
3680352f7f91STakashi Iwai 		return err;
3681352f7f91STakashi Iwai 	err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic);
3682071c73adSTakashi Iwai 	if (err < 0)
3683071c73adSTakashi Iwai 		return err;
3684071c73adSTakashi Iwai 	return 0;
36851da177e4SLinus Torvalds }
3686071c73adSTakashi Iwai 
3687352f7f91STakashi Iwai /* create bound capture volume and switch controls */
create_bind_cap_vol_ctl(struct hda_codec * codec,int idx,unsigned int vol_ctl,unsigned int sw_ctl)3688352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
3689352f7f91STakashi Iwai 				   unsigned int vol_ctl, unsigned int sw_ctl)
3690352f7f91STakashi Iwai {
3691352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3692352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew;
3693352f7f91STakashi Iwai 
3694352f7f91STakashi Iwai 	if (vol_ctl) {
369512c93df6STakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp);
3696352f7f91STakashi Iwai 		if (!knew)
3697352f7f91STakashi Iwai 			return -ENOMEM;
3698352f7f91STakashi Iwai 		knew->index = idx;
3699352f7f91STakashi Iwai 		knew->private_value = vol_ctl;
3700352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
3701352f7f91STakashi Iwai 	}
3702352f7f91STakashi Iwai 	if (sw_ctl) {
370312c93df6STakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp);
3704352f7f91STakashi Iwai 		if (!knew)
3705352f7f91STakashi Iwai 			return -ENOMEM;
3706352f7f91STakashi Iwai 		knew->index = idx;
3707352f7f91STakashi Iwai 		knew->private_value = sw_ctl;
3708352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
3709e65bf997SJaroslav Kysela 		if (spec->mic_mute_led)
3710e65bf997SJaroslav Kysela 			knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
3711352f7f91STakashi Iwai 	}
3712352f7f91STakashi Iwai 	return 0;
3713352f7f91STakashi Iwai }
3714352f7f91STakashi Iwai 
3715352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */
get_first_cap_ctl(struct hda_codec * codec,int idx,int type)3716352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type)
3717352f7f91STakashi Iwai {
3718352f7f91STakashi Iwai 	struct nid_path *path;
3719352f7f91STakashi Iwai 	unsigned int ctl;
3720352f7f91STakashi Iwai 	int i;
3721352f7f91STakashi Iwai 
3722c697b716STakashi Iwai 	path = get_input_path(codec, 0, idx);
3723352f7f91STakashi Iwai 	if (!path)
3724352f7f91STakashi Iwai 		return 0;
3725352f7f91STakashi Iwai 	ctl = path->ctls[type];
3726352f7f91STakashi Iwai 	if (!ctl)
3727352f7f91STakashi Iwai 		return 0;
3728352f7f91STakashi Iwai 	for (i = 0; i < idx - 1; i++) {
3729c697b716STakashi Iwai 		path = get_input_path(codec, 0, i);
3730352f7f91STakashi Iwai 		if (path && path->ctls[type] == ctl)
3731352f7f91STakashi Iwai 			return 0;
3732352f7f91STakashi Iwai 	}
3733352f7f91STakashi Iwai 	return ctl;
3734352f7f91STakashi Iwai }
3735352f7f91STakashi Iwai 
3736352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */
create_multi_cap_vol_ctl(struct hda_codec * codec)3737352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec)
3738352f7f91STakashi Iwai {
3739352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3740352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3741c970042cSTakashi Iwai 	int i, err, type;
3742352f7f91STakashi Iwai 
3743352f7f91STakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
3744352f7f91STakashi Iwai 		bool inv_dmic;
3745c970042cSTakashi Iwai 		int idx;
37469dba205bSTakashi Iwai 
3747c970042cSTakashi Iwai 		idx = imux->items[i].index;
3748c970042cSTakashi Iwai 		if (idx >= spec->autocfg.num_inputs)
37499dba205bSTakashi Iwai 			continue;
3750352f7f91STakashi Iwai 		inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]);
3751352f7f91STakashi Iwai 
3752352f7f91STakashi Iwai 		for (type = 0; type < 2; type++) {
3753c970042cSTakashi Iwai 			err = add_single_cap_ctl(codec,
3754c970042cSTakashi Iwai 						 spec->input_labels[idx],
3755c970042cSTakashi Iwai 						 spec->input_label_idxs[idx],
3756c970042cSTakashi Iwai 						 type,
3757352f7f91STakashi Iwai 						 get_first_cap_ctl(codec, i, type),
3758352f7f91STakashi Iwai 						 inv_dmic);
3759d13bd412STakashi Iwai 			if (err < 0)
3760071c73adSTakashi Iwai 				return err;
3761352f7f91STakashi Iwai 		}
3762352f7f91STakashi Iwai 	}
3763071c73adSTakashi Iwai 	return 0;
3764352f7f91STakashi Iwai }
3765071c73adSTakashi Iwai 
create_capture_mixers(struct hda_codec * codec)3766352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec)
3767352f7f91STakashi Iwai {
3768352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3769352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3770352f7f91STakashi Iwai 	int i, n, nums, err;
3771352f7f91STakashi Iwai 
3772352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
3773352f7f91STakashi Iwai 		nums = 1;
3774352f7f91STakashi Iwai 	else
3775352f7f91STakashi Iwai 		nums = spec->num_adc_nids;
3776352f7f91STakashi Iwai 
3777352f7f91STakashi Iwai 	if (!spec->auto_mic && imux->num_items > 1) {
3778352f7f91STakashi Iwai 		struct snd_kcontrol_new *knew;
3779624d914dSTakashi Iwai 		const char *name;
3780624d914dSTakashi Iwai 		name = nums > 1 ? "Input Source" : "Capture Source";
3781624d914dSTakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp);
3782352f7f91STakashi Iwai 		if (!knew)
3783352f7f91STakashi Iwai 			return -ENOMEM;
3784352f7f91STakashi Iwai 		knew->count = nums;
3785352f7f91STakashi Iwai 	}
3786352f7f91STakashi Iwai 
3787352f7f91STakashi Iwai 	for (n = 0; n < nums; n++) {
3788352f7f91STakashi Iwai 		bool multi = false;
378999a5592dSDavid Henningsson 		bool multi_cap_vol = spec->multi_cap_vol;
3790352f7f91STakashi Iwai 		bool inv_dmic = false;
3791352f7f91STakashi Iwai 		int vol, sw;
3792352f7f91STakashi Iwai 
3793352f7f91STakashi Iwai 		vol = sw = 0;
3794352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
3795352f7f91STakashi Iwai 			struct nid_path *path;
3796c697b716STakashi Iwai 			path = get_input_path(codec, n, i);
3797352f7f91STakashi Iwai 			if (!path)
3798352f7f91STakashi Iwai 				continue;
3799352f7f91STakashi Iwai 			parse_capvol_in_path(codec, path);
3800352f7f91STakashi Iwai 			if (!vol)
3801352f7f91STakashi Iwai 				vol = path->ctls[NID_PATH_VOL_CTL];
380299a5592dSDavid Henningsson 			else if (vol != path->ctls[NID_PATH_VOL_CTL]) {
3803352f7f91STakashi Iwai 				multi = true;
380499a5592dSDavid Henningsson 				if (!same_amp_caps(codec, vol,
380599a5592dSDavid Henningsson 				    path->ctls[NID_PATH_VOL_CTL], HDA_INPUT))
380699a5592dSDavid Henningsson 					multi_cap_vol = true;
380799a5592dSDavid Henningsson 			}
3808352f7f91STakashi Iwai 			if (!sw)
3809352f7f91STakashi Iwai 				sw = path->ctls[NID_PATH_MUTE_CTL];
381099a5592dSDavid Henningsson 			else if (sw != path->ctls[NID_PATH_MUTE_CTL]) {
3811352f7f91STakashi Iwai 				multi = true;
381299a5592dSDavid Henningsson 				if (!same_amp_caps(codec, sw,
381399a5592dSDavid Henningsson 				    path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT))
381499a5592dSDavid Henningsson 					multi_cap_vol = true;
381599a5592dSDavid Henningsson 			}
3816352f7f91STakashi Iwai 			if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
3817352f7f91STakashi Iwai 				inv_dmic = true;
3818352f7f91STakashi Iwai 		}
3819352f7f91STakashi Iwai 
3820352f7f91STakashi Iwai 		if (!multi)
3821352f7f91STakashi Iwai 			err = create_single_cap_vol_ctl(codec, n, vol, sw,
3822352f7f91STakashi Iwai 							inv_dmic);
3823ccb04157SDavid Henningsson 		else if (!multi_cap_vol && !inv_dmic)
3824352f7f91STakashi Iwai 			err = create_bind_cap_vol_ctl(codec, n, vol, sw);
3825352f7f91STakashi Iwai 		else
3826352f7f91STakashi Iwai 			err = create_multi_cap_vol_ctl(codec);
3827d13bd412STakashi Iwai 		if (err < 0)
3828071c73adSTakashi Iwai 			return err;
3829071c73adSTakashi Iwai 	}
3830071c73adSTakashi Iwai 
38311da177e4SLinus Torvalds 	return 0;
38321da177e4SLinus Torvalds }
38331da177e4SLinus Torvalds 
3834352f7f91STakashi Iwai /*
3835352f7f91STakashi Iwai  * add mic boosts if needed
3836352f7f91STakashi Iwai  */
38376f7c83afSTakashi Iwai 
38386f7c83afSTakashi Iwai /* check whether the given amp is feasible as a boost volume */
check_boost_vol(struct hda_codec * codec,hda_nid_t nid,int dir,int idx)38396f7c83afSTakashi Iwai static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid,
38406f7c83afSTakashi Iwai 			    int dir, int idx)
38416f7c83afSTakashi Iwai {
38426f7c83afSTakashi Iwai 	unsigned int step;
38436f7c83afSTakashi Iwai 
38446f7c83afSTakashi Iwai 	if (!nid_has_volume(codec, nid, dir) ||
38456f7c83afSTakashi Iwai 	    is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
38466f7c83afSTakashi Iwai 	    is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
38476f7c83afSTakashi Iwai 		return false;
38486f7c83afSTakashi Iwai 
38496f7c83afSTakashi Iwai 	step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE)
38506f7c83afSTakashi Iwai 		>> AC_AMPCAP_STEP_SIZE_SHIFT;
38516f7c83afSTakashi Iwai 	if (step < 0x20)
38526f7c83afSTakashi Iwai 		return false;
38536f7c83afSTakashi Iwai 	return true;
38546f7c83afSTakashi Iwai }
38556f7c83afSTakashi Iwai 
38566f7c83afSTakashi Iwai /* look for a boost amp in a widget close to the pin */
look_for_boost_amp(struct hda_codec * codec,struct nid_path * path)38576f7c83afSTakashi Iwai static unsigned int look_for_boost_amp(struct hda_codec *codec,
38586f7c83afSTakashi Iwai 				       struct nid_path *path)
38596f7c83afSTakashi Iwai {
38606f7c83afSTakashi Iwai 	unsigned int val = 0;
38616f7c83afSTakashi Iwai 	hda_nid_t nid;
38626f7c83afSTakashi Iwai 	int depth;
38636f7c83afSTakashi Iwai 
38646f7c83afSTakashi Iwai 	for (depth = 0; depth < 3; depth++) {
38656f7c83afSTakashi Iwai 		if (depth >= path->depth - 1)
38666f7c83afSTakashi Iwai 			break;
38676f7c83afSTakashi Iwai 		nid = path->path[depth];
38686f7c83afSTakashi Iwai 		if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) {
38696f7c83afSTakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
38706f7c83afSTakashi Iwai 			break;
38716f7c83afSTakashi Iwai 		} else if (check_boost_vol(codec, nid, HDA_INPUT,
38726f7c83afSTakashi Iwai 					   path->idx[depth])) {
38736f7c83afSTakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth],
38746f7c83afSTakashi Iwai 						  HDA_INPUT);
38756f7c83afSTakashi Iwai 			break;
38766f7c83afSTakashi Iwai 		}
38776f7c83afSTakashi Iwai 	}
38786f7c83afSTakashi Iwai 
38796f7c83afSTakashi Iwai 	return val;
38806f7c83afSTakashi Iwai }
38816f7c83afSTakashi Iwai 
parse_mic_boost(struct hda_codec * codec)3882352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec)
3883352f7f91STakashi Iwai {
3884352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3885352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
38866f7c83afSTakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3887a35bd1e3STakashi Iwai 	int i;
3888352f7f91STakashi Iwai 
38896f7c83afSTakashi Iwai 	if (!spec->num_adc_nids)
38906f7c83afSTakashi Iwai 		return 0;
38916f7c83afSTakashi Iwai 
38926f7c83afSTakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
3893352f7f91STakashi Iwai 		struct nid_path *path;
3894352f7f91STakashi Iwai 		unsigned int val;
38956f7c83afSTakashi Iwai 		int idx;
3896975cc02aSTakashi Iwai 		char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
3897352f7f91STakashi Iwai 
38986f7c83afSTakashi Iwai 		idx = imux->items[i].index;
38996f7c83afSTakashi Iwai 		if (idx >= imux->num_items)
390002aba550SDavid Henningsson 			continue;
390102aba550SDavid Henningsson 
39026f7c83afSTakashi Iwai 		/* check only line-in and mic pins */
39031799cdd5STakashi Iwai 		if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
39046f7c83afSTakashi Iwai 			continue;
39056f7c83afSTakashi Iwai 
39066f7c83afSTakashi Iwai 		path = get_input_path(codec, 0, i);
39076f7c83afSTakashi Iwai 		if (!path)
39086f7c83afSTakashi Iwai 			continue;
39096f7c83afSTakashi Iwai 
39106f7c83afSTakashi Iwai 		val = look_for_boost_amp(codec, path);
39116f7c83afSTakashi Iwai 		if (!val)
39126f7c83afSTakashi Iwai 			continue;
39136f7c83afSTakashi Iwai 
39146f7c83afSTakashi Iwai 		/* create a boost control */
3915352f7f91STakashi Iwai 		snprintf(boost_label, sizeof(boost_label),
39166f7c83afSTakashi Iwai 			 "%s Boost Volume", spec->input_labels[idx]);
3917a35bd1e3STakashi Iwai 		if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label,
3918a35bd1e3STakashi Iwai 				 spec->input_label_idxs[idx], val))
3919a35bd1e3STakashi Iwai 			return -ENOMEM;
3920352f7f91STakashi Iwai 
3921352f7f91STakashi Iwai 		path->ctls[NID_PATH_BOOST_CTL] = val;
3922352f7f91STakashi Iwai 	}
3923352f7f91STakashi Iwai 	return 0;
3924352f7f91STakashi Iwai }
3925352f7f91STakashi Iwai 
39267cdf8c49STakashi Iwai #ifdef CONFIG_SND_HDA_GENERIC_LEDS
3927352f7f91STakashi Iwai /*
392815509b63STakashi Iwai  * vmaster mute LED hook helpers
392915509b63STakashi Iwai  */
393015509b63STakashi Iwai 
create_mute_led_cdev(struct hda_codec * codec,int (* callback)(struct led_classdev *,enum led_brightness),bool micmute)393115509b63STakashi Iwai static int create_mute_led_cdev(struct hda_codec *codec,
393215509b63STakashi Iwai 				int (*callback)(struct led_classdev *,
393315509b63STakashi Iwai 						enum led_brightness),
393415509b63STakashi Iwai 				bool micmute)
393515509b63STakashi Iwai {
3936549f8ffcSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
393715509b63STakashi Iwai 	struct led_classdev *cdev;
3938549f8ffcSTakashi Iwai 	int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
3939549f8ffcSTakashi Iwai 	int err;
394015509b63STakashi Iwai 
394115509b63STakashi Iwai 	cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
394215509b63STakashi Iwai 	if (!cdev)
394315509b63STakashi Iwai 		return -ENOMEM;
394415509b63STakashi Iwai 
394515509b63STakashi Iwai 	cdev->name = micmute ? "hda::micmute" : "hda::mute";
394615509b63STakashi Iwai 	cdev->max_brightness = 1;
394715509b63STakashi Iwai 	cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
394815509b63STakashi Iwai 	cdev->brightness_set_blocking = callback;
3949549f8ffcSTakashi Iwai 	cdev->brightness = ledtrig_audio_get(idx);
3950c9e272f9STakashi Iwai 	cdev->flags = LED_CORE_SUSPENDRESUME;
395115509b63STakashi Iwai 
3952549f8ffcSTakashi Iwai 	err = led_classdev_register(&codec->core.dev, cdev);
3953549f8ffcSTakashi Iwai 	if (err < 0)
3954549f8ffcSTakashi Iwai 		return err;
3955549f8ffcSTakashi Iwai 	spec->led_cdevs[idx] = cdev;
3956549f8ffcSTakashi Iwai 	return 0;
395715509b63STakashi Iwai }
395815509b63STakashi Iwai 
395915509b63STakashi Iwai /**
39603531ba21SPierre-Louis Bossart  * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
396115509b63STakashi Iwai  * @codec: the HDA codec
396215509b63STakashi Iwai  * @callback: the callback for LED classdev brightness_set_blocking
396315509b63STakashi Iwai  */
snd_hda_gen_add_mute_led_cdev(struct hda_codec * codec,int (* callback)(struct led_classdev *,enum led_brightness))396415509b63STakashi Iwai int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
396515509b63STakashi Iwai 				  int (*callback)(struct led_classdev *,
396615509b63STakashi Iwai 						  enum led_brightness))
396715509b63STakashi Iwai {
396815509b63STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
396915509b63STakashi Iwai 	int err;
397015509b63STakashi Iwai 
397115509b63STakashi Iwai 	if (callback) {
397215509b63STakashi Iwai 		err = create_mute_led_cdev(codec, callback, false);
397315509b63STakashi Iwai 		if (err) {
397415509b63STakashi Iwai 			codec_warn(codec, "failed to create a mute LED cdev\n");
397515509b63STakashi Iwai 			return err;
397615509b63STakashi Iwai 		}
397715509b63STakashi Iwai 	}
397815509b63STakashi Iwai 
397915509b63STakashi Iwai 	if (spec->vmaster_mute.hook)
398015509b63STakashi Iwai 		codec_err(codec, "vmaster hook already present before cdev!\n");
398115509b63STakashi Iwai 
3982e65bf997SJaroslav Kysela 	spec->vmaster_mute_led = 1;
398315509b63STakashi Iwai 	return 0;
398415509b63STakashi Iwai }
398515509b63STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);
398615509b63STakashi Iwai 
3987b3802783STakashi Iwai /**
39883531ba21SPierre-Louis Bossart  * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
39897cdf8c49STakashi Iwai  * @codec: the HDA codec
39907cdf8c49STakashi Iwai  * @callback: the callback for LED classdev brightness_set_blocking
39917cdf8c49STakashi Iwai  *
39927cdf8c49STakashi Iwai  * Called from the codec drivers for offering the mic mute LED controls.
39937cdf8c49STakashi Iwai  * This creates a LED classdev and sets up the cap_sync_hook that is called at
39947cdf8c49STakashi Iwai  * each time when the capture mixer switch changes.
39957cdf8c49STakashi Iwai  *
39967cdf8c49STakashi Iwai  * When NULL is passed to @callback, no classdev is created but only the
39977cdf8c49STakashi Iwai  * LED-trigger is set up.
39987cdf8c49STakashi Iwai  *
39997cdf8c49STakashi Iwai  * Returns 0 or a negative error.
40007cdf8c49STakashi Iwai  */
snd_hda_gen_add_micmute_led_cdev(struct hda_codec * codec,int (* callback)(struct led_classdev *,enum led_brightness))40017cdf8c49STakashi Iwai int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
40027cdf8c49STakashi Iwai 				     int (*callback)(struct led_classdev *,
40037cdf8c49STakashi Iwai 						     enum led_brightness))
40047cdf8c49STakashi Iwai {
4005e65bf997SJaroslav Kysela 	struct hda_gen_spec *spec = codec->spec;
40067cdf8c49STakashi Iwai 	int err;
40077cdf8c49STakashi Iwai 
40087cdf8c49STakashi Iwai 	if (callback) {
400915509b63STakashi Iwai 		err = create_mute_led_cdev(codec, callback, true);
40107cdf8c49STakashi Iwai 		if (err) {
40117cdf8c49STakashi Iwai 			codec_warn(codec, "failed to create a mic-mute LED cdev\n");
40127cdf8c49STakashi Iwai 			return err;
40137cdf8c49STakashi Iwai 		}
40147cdf8c49STakashi Iwai 	}
40157cdf8c49STakashi Iwai 
4016e65bf997SJaroslav Kysela 	spec->mic_mute_led = 1;
4017e65bf997SJaroslav Kysela 	return 0;
40187cdf8c49STakashi Iwai }
40197cdf8c49STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
40207cdf8c49STakashi Iwai #endif /* CONFIG_SND_HDA_GENERIC_LEDS */
40217cdf8c49STakashi Iwai 
4022f567b788STakashi Iwai /*
4023352f7f91STakashi Iwai  * parse digital I/Os and set up NIDs in BIOS auto-parse mode
4024352f7f91STakashi Iwai  */
parse_digital(struct hda_codec * codec)4025352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec)
4026352f7f91STakashi Iwai {
4027352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
40280c8c0f56STakashi Iwai 	struct nid_path *path;
4029352f7f91STakashi Iwai 	int i, nums;
40302c12c30dSTakashi Iwai 	hda_nid_t dig_nid, pin;
4031352f7f91STakashi Iwai 
40329ab0cb30STakashi Iwai 	/* support multiple SPDIFs; the secondary is set up as a follower */
4033352f7f91STakashi Iwai 	nums = 0;
4034352f7f91STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++) {
40352c12c30dSTakashi Iwai 		pin = spec->autocfg.dig_out_pins[i];
4036352f7f91STakashi Iwai 		dig_nid = look_for_dac(codec, pin, true);
4037352f7f91STakashi Iwai 		if (!dig_nid)
4038352f7f91STakashi Iwai 			continue;
40393ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
40400c8c0f56STakashi Iwai 		if (!path)
4041352f7f91STakashi Iwai 			continue;
40424e76a883STakashi Iwai 		print_nid_path(codec, "digout", path);
4043e1284af7STakashi Iwai 		path->active = true;
40446b275b14STakashi Iwai 		path->pin_fixed = true; /* no jack detection */
4045196c1766STakashi Iwai 		spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
40462c12c30dSTakashi Iwai 		set_pin_target(codec, pin, PIN_OUT, false);
4047352f7f91STakashi Iwai 		if (!nums) {
4048352f7f91STakashi Iwai 			spec->multiout.dig_out_nid = dig_nid;
4049352f7f91STakashi Iwai 			spec->dig_out_type = spec->autocfg.dig_out_type[0];
4050352f7f91STakashi Iwai 		} else {
40519ab0cb30STakashi Iwai 			spec->multiout.follower_dig_outs = spec->follower_dig_outs;
40529ab0cb30STakashi Iwai 			if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1)
4053352f7f91STakashi Iwai 				break;
40549ab0cb30STakashi Iwai 			spec->follower_dig_outs[nums - 1] = dig_nid;
4055352f7f91STakashi Iwai 		}
4056352f7f91STakashi Iwai 		nums++;
4057352f7f91STakashi Iwai 	}
4058352f7f91STakashi Iwai 
4059352f7f91STakashi Iwai 	if (spec->autocfg.dig_in_pin) {
40602c12c30dSTakashi Iwai 		pin = spec->autocfg.dig_in_pin;
40617639a06cSTakashi Iwai 		for_each_hda_codec_node(dig_nid, codec) {
4062352f7f91STakashi Iwai 			unsigned int wcaps = get_wcaps(codec, dig_nid);
4063352f7f91STakashi Iwai 			if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
4064352f7f91STakashi Iwai 				continue;
4065352f7f91STakashi Iwai 			if (!(wcaps & AC_WCAP_DIGITAL))
4066352f7f91STakashi Iwai 				continue;
40672c12c30dSTakashi Iwai 			path = snd_hda_add_new_path(codec, pin, dig_nid, 0);
4068352f7f91STakashi Iwai 			if (path) {
40694e76a883STakashi Iwai 				print_nid_path(codec, "digin", path);
4070352f7f91STakashi Iwai 				path->active = true;
40716b275b14STakashi Iwai 				path->pin_fixed = true; /* no jack */
4072352f7f91STakashi Iwai 				spec->dig_in_nid = dig_nid;
40732430d7b7STakashi Iwai 				spec->digin_path = snd_hda_get_path_idx(codec, path);
40742c12c30dSTakashi Iwai 				set_pin_target(codec, pin, PIN_IN, false);
4075352f7f91STakashi Iwai 				break;
4076352f7f91STakashi Iwai 			}
4077352f7f91STakashi Iwai 		}
4078352f7f91STakashi Iwai 	}
4079352f7f91STakashi Iwai }
4080352f7f91STakashi Iwai 
40811da177e4SLinus Torvalds 
40821da177e4SLinus Torvalds /*
4083352f7f91STakashi Iwai  * input MUX handling
40841da177e4SLinus Torvalds  */
40851da177e4SLinus Torvalds 
4086352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur);
4087352f7f91STakashi Iwai 
4088352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */
mux_select(struct hda_codec * codec,unsigned int adc_idx,unsigned int idx)4089352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
4090352f7f91STakashi Iwai 		      unsigned int idx)
4091352f7f91STakashi Iwai {
4092352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4093352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
409455196fffSTakashi Iwai 	struct nid_path *old_path, *path;
4095352f7f91STakashi Iwai 
4096352f7f91STakashi Iwai 	imux = &spec->input_mux;
4097352f7f91STakashi Iwai 	if (!imux->num_items)
40981da177e4SLinus Torvalds 		return 0;
40991da177e4SLinus Torvalds 
4100352f7f91STakashi Iwai 	if (idx >= imux->num_items)
4101352f7f91STakashi Iwai 		idx = imux->num_items - 1;
4102352f7f91STakashi Iwai 	if (spec->cur_mux[adc_idx] == idx)
4103352f7f91STakashi Iwai 		return 0;
4104352f7f91STakashi Iwai 
410555196fffSTakashi Iwai 	old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]);
410655196fffSTakashi Iwai 	if (!old_path)
4107352f7f91STakashi Iwai 		return 0;
410855196fffSTakashi Iwai 	if (old_path->active)
410955196fffSTakashi Iwai 		snd_hda_activate_path(codec, old_path, false, false);
4110352f7f91STakashi Iwai 
4111352f7f91STakashi Iwai 	spec->cur_mux[adc_idx] = idx;
4112352f7f91STakashi Iwai 
4113967303daSTakashi Iwai 	if (spec->hp_mic)
4114967303daSTakashi Iwai 		update_hp_mic(codec, adc_idx, false);
4115352f7f91STakashi Iwai 
4116352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
4117352f7f91STakashi Iwai 		dyn_adc_pcm_resetup(codec, idx);
4118352f7f91STakashi Iwai 
4119c697b716STakashi Iwai 	path = get_input_path(codec, adc_idx, idx);
4120352f7f91STakashi Iwai 	if (!path)
4121352f7f91STakashi Iwai 		return 0;
4122352f7f91STakashi Iwai 	if (path->active)
4123352f7f91STakashi Iwai 		return 0;
4124352f7f91STakashi Iwai 	snd_hda_activate_path(codec, path, true, false);
4125352f7f91STakashi Iwai 	if (spec->cap_sync_hook)
41267fe30711STakashi Iwai 		spec->cap_sync_hook(codec, NULL, NULL);
412755196fffSTakashi Iwai 	path_power_down_sync(codec, old_path);
41281da177e4SLinus Torvalds 	return 1;
41291da177e4SLinus Torvalds }
41301da177e4SLinus Torvalds 
4131e6feb5d0STakashi Iwai /* power up/down widgets in the all paths that match with the given NID
4132e6feb5d0STakashi Iwai  * as terminals (either start- or endpoint)
4133e6feb5d0STakashi Iwai  *
4134e6feb5d0STakashi Iwai  * returns the last changed NID, or zero if unchanged.
4135e6feb5d0STakashi Iwai  */
set_path_power(struct hda_codec * codec,hda_nid_t nid,int pin_state,int stream_state)4136e6feb5d0STakashi Iwai static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid,
4137e6feb5d0STakashi Iwai 				int pin_state, int stream_state)
4138e6feb5d0STakashi Iwai {
4139e6feb5d0STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4140e6feb5d0STakashi Iwai 	hda_nid_t last, changed = 0;
4141e6feb5d0STakashi Iwai 	struct nid_path *path;
4142e6feb5d0STakashi Iwai 	int n;
4143e6feb5d0STakashi Iwai 
4144a9c2dfc8STakashi Iwai 	snd_array_for_each(&spec->paths, n, path) {
414581e43960SBob Copeland 		if (!path->depth)
414681e43960SBob Copeland 			continue;
4147e6feb5d0STakashi Iwai 		if (path->path[0] == nid ||
4148e6feb5d0STakashi Iwai 		    path->path[path->depth - 1] == nid) {
4149e6feb5d0STakashi Iwai 			bool pin_old = path->pin_enabled;
4150e6feb5d0STakashi Iwai 			bool stream_old = path->stream_enabled;
4151e6feb5d0STakashi Iwai 
4152e6feb5d0STakashi Iwai 			if (pin_state >= 0)
4153e6feb5d0STakashi Iwai 				path->pin_enabled = pin_state;
4154e6feb5d0STakashi Iwai 			if (stream_state >= 0)
4155e6feb5d0STakashi Iwai 				path->stream_enabled = stream_state;
41566b275b14STakashi Iwai 			if ((!path->pin_fixed && path->pin_enabled != pin_old)
41576b275b14STakashi Iwai 			    || path->stream_enabled != stream_old) {
4158e6feb5d0STakashi Iwai 				last = path_power_update(codec, path, true);
4159e6feb5d0STakashi Iwai 				if (last)
4160e6feb5d0STakashi Iwai 					changed = last;
4161e6feb5d0STakashi Iwai 			}
4162e6feb5d0STakashi Iwai 		}
4163e6feb5d0STakashi Iwai 	}
4164e6feb5d0STakashi Iwai 	return changed;
4165e6feb5d0STakashi Iwai }
4166e6feb5d0STakashi Iwai 
4167d5ac0100STakashi Iwai /* check the jack status for power control */
detect_pin_state(struct hda_codec * codec,hda_nid_t pin)4168d5ac0100STakashi Iwai static bool detect_pin_state(struct hda_codec *codec, hda_nid_t pin)
4169d5ac0100STakashi Iwai {
4170d5ac0100STakashi Iwai 	if (!is_jack_detectable(codec, pin))
4171d5ac0100STakashi Iwai 		return true;
4172d5ac0100STakashi Iwai 	return snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT;
4173d5ac0100STakashi Iwai }
4174d5ac0100STakashi Iwai 
4175e6feb5d0STakashi Iwai /* power up/down the paths of the given pin according to the jack state;
4176e6feb5d0STakashi Iwai  * power = 0/1 : only power up/down if it matches with the jack state,
4177e6feb5d0STakashi Iwai  *       < 0   : force power up/down to follow the jack sate
4178e6feb5d0STakashi Iwai  *
4179e6feb5d0STakashi Iwai  * returns the last changed NID, or zero if unchanged.
4180e6feb5d0STakashi Iwai  */
set_pin_power_jack(struct hda_codec * codec,hda_nid_t pin,int power)4181e6feb5d0STakashi Iwai static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin,
4182e6feb5d0STakashi Iwai 				    int power)
4183e6feb5d0STakashi Iwai {
4184e6feb5d0STakashi Iwai 	bool on;
4185e6feb5d0STakashi Iwai 
4186967b1307STakashi Iwai 	if (!codec->power_save_node)
4187e6feb5d0STakashi Iwai 		return 0;
4188e6feb5d0STakashi Iwai 
4189d5ac0100STakashi Iwai 	on = detect_pin_state(codec, pin);
4190d5ac0100STakashi Iwai 
4191e6feb5d0STakashi Iwai 	if (power >= 0 && on != power)
4192e6feb5d0STakashi Iwai 		return 0;
4193e6feb5d0STakashi Iwai 	return set_path_power(codec, pin, on, -1);
4194e6feb5d0STakashi Iwai }
4195e6feb5d0STakashi Iwai 
pin_power_callback(struct hda_codec * codec,struct hda_jack_callback * jack,bool on)4196e6feb5d0STakashi Iwai static void pin_power_callback(struct hda_codec *codec,
4197e6feb5d0STakashi Iwai 			       struct hda_jack_callback *jack,
4198e6feb5d0STakashi Iwai 			       bool on)
4199e6feb5d0STakashi Iwai {
42002ebab40eSTakashi Iwai 	if (jack && jack->nid)
4201e6feb5d0STakashi Iwai 		sync_power_state_change(codec,
42022ebab40eSTakashi Iwai 					set_pin_power_jack(codec, jack->nid, on));
4203e6feb5d0STakashi Iwai }
4204e6feb5d0STakashi Iwai 
4205e6feb5d0STakashi Iwai /* callback only doing power up -- called at first */
pin_power_up_callback(struct hda_codec * codec,struct hda_jack_callback * jack)4206e6feb5d0STakashi Iwai static void pin_power_up_callback(struct hda_codec *codec,
4207e6feb5d0STakashi Iwai 				  struct hda_jack_callback *jack)
4208e6feb5d0STakashi Iwai {
4209e6feb5d0STakashi Iwai 	pin_power_callback(codec, jack, true);
4210e6feb5d0STakashi Iwai }
4211e6feb5d0STakashi Iwai 
4212e6feb5d0STakashi Iwai /* callback only doing power down -- called at last */
pin_power_down_callback(struct hda_codec * codec,struct hda_jack_callback * jack)4213e6feb5d0STakashi Iwai static void pin_power_down_callback(struct hda_codec *codec,
4214e6feb5d0STakashi Iwai 				    struct hda_jack_callback *jack)
4215e6feb5d0STakashi Iwai {
4216e6feb5d0STakashi Iwai 	pin_power_callback(codec, jack, false);
4217e6feb5d0STakashi Iwai }
4218e6feb5d0STakashi Iwai 
4219e6feb5d0STakashi Iwai /* set up the power up/down callbacks */
add_pin_power_ctls(struct hda_codec * codec,int num_pins,const hda_nid_t * pins,bool on)4220e6feb5d0STakashi Iwai static void add_pin_power_ctls(struct hda_codec *codec, int num_pins,
4221e6feb5d0STakashi Iwai 			       const hda_nid_t *pins, bool on)
4222e6feb5d0STakashi Iwai {
4223e6feb5d0STakashi Iwai 	int i;
4224e6feb5d0STakashi Iwai 	hda_jack_callback_fn cb =
4225e6feb5d0STakashi Iwai 		on ? pin_power_up_callback : pin_power_down_callback;
4226e6feb5d0STakashi Iwai 
4227e6feb5d0STakashi Iwai 	for (i = 0; i < num_pins && pins[i]; i++) {
4228e6feb5d0STakashi Iwai 		if (is_jack_detectable(codec, pins[i]))
4229e6feb5d0STakashi Iwai 			snd_hda_jack_detect_enable_callback(codec, pins[i], cb);
4230e6feb5d0STakashi Iwai 		else
4231e6feb5d0STakashi Iwai 			set_path_power(codec, pins[i], true, -1);
4232e6feb5d0STakashi Iwai 	}
4233e6feb5d0STakashi Iwai }
4234e6feb5d0STakashi Iwai 
4235e6feb5d0STakashi Iwai /* enabled power callback to each available I/O pin with jack detections;
4236e6feb5d0STakashi Iwai  * the digital I/O pins are excluded because of the unreliable detectsion
4237e6feb5d0STakashi Iwai  */
add_all_pin_power_ctls(struct hda_codec * codec,bool on)4238e6feb5d0STakashi Iwai static void add_all_pin_power_ctls(struct hda_codec *codec, bool on)
4239e6feb5d0STakashi Iwai {
4240e6feb5d0STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4241e6feb5d0STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
4242e6feb5d0STakashi Iwai 	int i;
4243e6feb5d0STakashi Iwai 
4244967b1307STakashi Iwai 	if (!codec->power_save_node)
4245e6feb5d0STakashi Iwai 		return;
4246e6feb5d0STakashi Iwai 	add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on);
4247e6feb5d0STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
4248e6feb5d0STakashi Iwai 		add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on);
4249e6feb5d0STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
4250e6feb5d0STakashi Iwai 		add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on);
4251e6feb5d0STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++)
4252e6feb5d0STakashi Iwai 		add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on);
4253e6feb5d0STakashi Iwai }
4254e6feb5d0STakashi Iwai 
4255e6feb5d0STakashi Iwai /* sync path power up/down with the jack states of given pins */
sync_pin_power_ctls(struct hda_codec * codec,int num_pins,const hda_nid_t * pins)4256e6feb5d0STakashi Iwai static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins,
4257e6feb5d0STakashi Iwai 				const hda_nid_t *pins)
4258e6feb5d0STakashi Iwai {
4259e6feb5d0STakashi Iwai 	int i;
4260e6feb5d0STakashi Iwai 
4261e6feb5d0STakashi Iwai 	for (i = 0; i < num_pins && pins[i]; i++)
4262e6feb5d0STakashi Iwai 		if (is_jack_detectable(codec, pins[i]))
4263e6feb5d0STakashi Iwai 			set_pin_power_jack(codec, pins[i], -1);
4264e6feb5d0STakashi Iwai }
4265e6feb5d0STakashi Iwai 
4266e6feb5d0STakashi Iwai /* sync path power up/down with pins; called at init and resume */
sync_all_pin_power_ctls(struct hda_codec * codec)4267e6feb5d0STakashi Iwai static void sync_all_pin_power_ctls(struct hda_codec *codec)
4268e6feb5d0STakashi Iwai {
4269e6feb5d0STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4270e6feb5d0STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
4271e6feb5d0STakashi Iwai 	int i;
4272e6feb5d0STakashi Iwai 
4273967b1307STakashi Iwai 	if (!codec->power_save_node)
4274e6feb5d0STakashi Iwai 		return;
4275e6feb5d0STakashi Iwai 	sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins);
4276e6feb5d0STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
4277e6feb5d0STakashi Iwai 		sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins);
4278e6feb5d0STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
4279e6feb5d0STakashi Iwai 		sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins);
4280e6feb5d0STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++)
4281e6feb5d0STakashi Iwai 		sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin);
4282e6feb5d0STakashi Iwai }
42831da177e4SLinus Torvalds 
42845ccf835cSTakashi Iwai /* add fake paths if not present yet */
add_fake_paths(struct hda_codec * codec,hda_nid_t nid,int num_pins,const hda_nid_t * pins)42855ccf835cSTakashi Iwai static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid,
42865ccf835cSTakashi Iwai 			   int num_pins, const hda_nid_t *pins)
42875ccf835cSTakashi Iwai {
42885ccf835cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
42895ccf835cSTakashi Iwai 	struct nid_path *path;
42905ccf835cSTakashi Iwai 	int i;
42915ccf835cSTakashi Iwai 
42925ccf835cSTakashi Iwai 	for (i = 0; i < num_pins; i++) {
42935ccf835cSTakashi Iwai 		if (!pins[i])
42945ccf835cSTakashi Iwai 			break;
42955ccf835cSTakashi Iwai 		if (get_nid_path(codec, nid, pins[i], 0))
42965ccf835cSTakashi Iwai 			continue;
42975ccf835cSTakashi Iwai 		path = snd_array_new(&spec->paths);
42985ccf835cSTakashi Iwai 		if (!path)
42995ccf835cSTakashi Iwai 			return -ENOMEM;
43005ccf835cSTakashi Iwai 		memset(path, 0, sizeof(*path));
43015ccf835cSTakashi Iwai 		path->depth = 2;
43025ccf835cSTakashi Iwai 		path->path[0] = nid;
43035ccf835cSTakashi Iwai 		path->path[1] = pins[i];
43045ccf835cSTakashi Iwai 		path->active = true;
43055ccf835cSTakashi Iwai 	}
43065ccf835cSTakashi Iwai 	return 0;
43075ccf835cSTakashi Iwai }
43085ccf835cSTakashi Iwai 
43095ccf835cSTakashi Iwai /* create fake paths to all outputs from beep */
add_fake_beep_paths(struct hda_codec * codec)43105ccf835cSTakashi Iwai static int add_fake_beep_paths(struct hda_codec *codec)
43115ccf835cSTakashi Iwai {
43125ccf835cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
43135ccf835cSTakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
43145ccf835cSTakashi Iwai 	hda_nid_t nid = spec->beep_nid;
43155ccf835cSTakashi Iwai 	int err;
43165ccf835cSTakashi Iwai 
4317967b1307STakashi Iwai 	if (!codec->power_save_node || !nid)
43185ccf835cSTakashi Iwai 		return 0;
43195ccf835cSTakashi Iwai 	err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins);
43205ccf835cSTakashi Iwai 	if (err < 0)
43215ccf835cSTakashi Iwai 		return err;
43225ccf835cSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
43235ccf835cSTakashi Iwai 		err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins);
43245ccf835cSTakashi Iwai 		if (err < 0)
43255ccf835cSTakashi Iwai 			return err;
43265ccf835cSTakashi Iwai 	}
43275ccf835cSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
43285ccf835cSTakashi Iwai 		err = add_fake_paths(codec, nid, cfg->speaker_outs,
43295ccf835cSTakashi Iwai 				     cfg->speaker_pins);
43305ccf835cSTakashi Iwai 		if (err < 0)
43315ccf835cSTakashi Iwai 			return err;
43325ccf835cSTakashi Iwai 	}
43335ccf835cSTakashi Iwai 	return 0;
43345ccf835cSTakashi Iwai }
43355ccf835cSTakashi Iwai 
43365ccf835cSTakashi Iwai /* power up/down beep widget and its output paths */
beep_power_hook(struct hda_beep * beep,bool on)43375ccf835cSTakashi Iwai static void beep_power_hook(struct hda_beep *beep, bool on)
43385ccf835cSTakashi Iwai {
43395ccf835cSTakashi Iwai 	set_path_power(beep->codec, beep->nid, -1, on);
43405ccf835cSTakashi Iwai }
43415ccf835cSTakashi Iwai 
43426b275b14STakashi Iwai /**
43436b275b14STakashi Iwai  * snd_hda_gen_fix_pin_power - Fix the power of the given pin widget to D0
43446b275b14STakashi Iwai  * @codec: the HDA codec
43456b275b14STakashi Iwai  * @pin: NID of pin to fix
43466b275b14STakashi Iwai  */
snd_hda_gen_fix_pin_power(struct hda_codec * codec,hda_nid_t pin)43476b275b14STakashi Iwai int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin)
43486b275b14STakashi Iwai {
43496b275b14STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
43506b275b14STakashi Iwai 	struct nid_path *path;
43516b275b14STakashi Iwai 
43526b275b14STakashi Iwai 	path = snd_array_new(&spec->paths);
43536b275b14STakashi Iwai 	if (!path)
43546b275b14STakashi Iwai 		return -ENOMEM;
43556b275b14STakashi Iwai 	memset(path, 0, sizeof(*path));
43566b275b14STakashi Iwai 	path->depth = 1;
43576b275b14STakashi Iwai 	path->path[0] = pin;
43586b275b14STakashi Iwai 	path->active = true;
43596b275b14STakashi Iwai 	path->pin_fixed = true;
43606b275b14STakashi Iwai 	path->stream_enabled = true;
43616b275b14STakashi Iwai 	return 0;
43626b275b14STakashi Iwai }
43636b275b14STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_fix_pin_power);
43646b275b14STakashi Iwai 
43651da177e4SLinus Torvalds /*
4366352f7f91STakashi Iwai  * Jack detections for HP auto-mute and mic-switch
43671da177e4SLinus Torvalds  */
4368352f7f91STakashi Iwai 
4369352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */
detect_jacks(struct hda_codec * codec,int num_pins,const hda_nid_t * pins)4370caf3c043SMichał Mirosław static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins)
43711da177e4SLinus Torvalds {
437260ea8ca2STakashi Iwai 	int i;
437360ea8ca2STakashi Iwai 	bool present = false;
43741da177e4SLinus Torvalds 
4375352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
4376352f7f91STakashi Iwai 		hda_nid_t nid = pins[i];
4377352f7f91STakashi Iwai 		if (!nid)
4378352f7f91STakashi Iwai 			break;
43790b4df931STakashi Iwai 		/* don't detect pins retasked as inputs */
43800b4df931STakashi Iwai 		if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
43810b4df931STakashi Iwai 			continue;
438260ea8ca2STakashi Iwai 		if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT)
438360ea8ca2STakashi Iwai 			present = true;
43841da177e4SLinus Torvalds 	}
4385352f7f91STakashi Iwai 	return present;
43861da177e4SLinus Torvalds }
43871da177e4SLinus Torvalds 
4388352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */
do_automute(struct hda_codec * codec,int num_pins,const hda_nid_t * pins,int * paths,bool mute)4389caf3c043SMichał Mirosław static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins,
4390e80c60f3STakashi Iwai 			int *paths, bool mute)
43911da177e4SLinus Torvalds {
4392352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4393352f7f91STakashi Iwai 	int i;
43941da177e4SLinus Torvalds 
4395352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
4396352f7f91STakashi Iwai 		hda_nid_t nid = pins[i];
4397967303daSTakashi Iwai 		unsigned int val, oldval;
4398352f7f91STakashi Iwai 		if (!nid)
4399352f7f91STakashi Iwai 			break;
44007eebffd3STakashi Iwai 
4401e6feb5d0STakashi Iwai 		oldval = snd_hda_codec_get_pin_target(codec, nid);
4402e6feb5d0STakashi Iwai 		if (oldval & PIN_IN)
4403e6feb5d0STakashi Iwai 			continue; /* no mute for inputs */
4404e6feb5d0STakashi Iwai 
44057eebffd3STakashi Iwai 		if (spec->auto_mute_via_amp) {
4406e80c60f3STakashi Iwai 			struct nid_path *path;
4407e80c60f3STakashi Iwai 			hda_nid_t mute_nid;
4408e80c60f3STakashi Iwai 
4409e80c60f3STakashi Iwai 			path = snd_hda_get_path_from_idx(codec, paths[i]);
4410e80c60f3STakashi Iwai 			if (!path)
4411e80c60f3STakashi Iwai 				continue;
4412e80c60f3STakashi Iwai 			mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]);
4413e80c60f3STakashi Iwai 			if (!mute_nid)
4414e80c60f3STakashi Iwai 				continue;
44157eebffd3STakashi Iwai 			if (mute)
4416e80c60f3STakashi Iwai 				spec->mute_bits |= (1ULL << mute_nid);
44177eebffd3STakashi Iwai 			else
4418e80c60f3STakashi Iwai 				spec->mute_bits &= ~(1ULL << mute_nid);
44197eebffd3STakashi Iwai 			continue;
4420e6feb5d0STakashi Iwai 		} else {
4421352f7f91STakashi Iwai 			/* don't reset VREF value in case it's controlling
4422352f7f91STakashi Iwai 			 * the amp (see alc861_fixup_asus_amp_vref_0f())
4423352f7f91STakashi Iwai 			 */
44242c12c30dSTakashi Iwai 			if (spec->keep_vref_in_automute)
4425967303daSTakashi Iwai 				val = oldval & ~PIN_HP;
44262c12c30dSTakashi Iwai 			else
4427352f7f91STakashi Iwai 				val = 0;
44282c12c30dSTakashi Iwai 			if (!mute)
4429967303daSTakashi Iwai 				val |= oldval;
4430e6feb5d0STakashi Iwai 			/* here we call update_pin_ctl() so that the pinctl is
4431e6feb5d0STakashi Iwai 			 * changed without changing the pinctl target value;
4432e6feb5d0STakashi Iwai 			 * the original target value will be still referred at
4433e6feb5d0STakashi Iwai 			 * the init / resume again
44342c12c30dSTakashi Iwai 			 */
44352c12c30dSTakashi Iwai 			update_pin_ctl(codec, nid, val);
4436e6feb5d0STakashi Iwai 		}
4437e6feb5d0STakashi Iwai 
4438d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, !mute);
4439967b1307STakashi Iwai 		if (codec->power_save_node) {
4440e6feb5d0STakashi Iwai 			bool on = !mute;
4441e6feb5d0STakashi Iwai 			if (on)
4442d5ac0100STakashi Iwai 				on = detect_pin_state(codec, nid);
4443e6feb5d0STakashi Iwai 			set_path_power(codec, nid, on, -1);
4444e6feb5d0STakashi Iwai 		}
4445352f7f91STakashi Iwai 	}
4446352f7f91STakashi Iwai }
44471da177e4SLinus Torvalds 
4448dda42bd0STakashi Iwai /**
4449dda42bd0STakashi Iwai  * snd_hda_gen_update_outputs - Toggle outputs muting
4450dda42bd0STakashi Iwai  * @codec: the HDA codec
4451dda42bd0STakashi Iwai  *
4452dda42bd0STakashi Iwai  * Update the mute status of all outputs based on the current jack states.
4453dda42bd0STakashi Iwai  */
snd_hda_gen_update_outputs(struct hda_codec * codec)44545d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec)
4455352f7f91STakashi Iwai {
4456352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4457e80c60f3STakashi Iwai 	int *paths;
4458352f7f91STakashi Iwai 	int on;
4459352f7f91STakashi Iwai 
4460352f7f91STakashi Iwai 	/* Control HP pins/amps depending on master_mute state;
4461352f7f91STakashi Iwai 	 * in general, HP pins/amps control should be enabled in all cases,
4462352f7f91STakashi Iwai 	 * but currently set only for master_mute, just to be safe
4463352f7f91STakashi Iwai 	 */
4464e80c60f3STakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
4465e80c60f3STakashi Iwai 		paths = spec->out_paths;
4466e80c60f3STakashi Iwai 	else
4467e80c60f3STakashi Iwai 		paths = spec->hp_paths;
4468352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
4469e80c60f3STakashi Iwai 		    spec->autocfg.hp_pins, paths, spec->master_mute);
4470352f7f91STakashi Iwai 
4471352f7f91STakashi Iwai 	if (!spec->automute_speaker)
4472352f7f91STakashi Iwai 		on = 0;
4473352f7f91STakashi Iwai 	else
4474352f7f91STakashi Iwai 		on = spec->hp_jack_present | spec->line_jack_present;
4475352f7f91STakashi Iwai 	on |= spec->master_mute;
447647b9ddb8STakashi Iwai 	spec->speaker_muted = on;
4477e80c60f3STakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
4478e80c60f3STakashi Iwai 		paths = spec->out_paths;
4479e80c60f3STakashi Iwai 	else
4480e80c60f3STakashi Iwai 		paths = spec->speaker_paths;
4481352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
4482e80c60f3STakashi Iwai 		    spec->autocfg.speaker_pins, paths, on);
4483352f7f91STakashi Iwai 
4484352f7f91STakashi Iwai 	/* toggle line-out mutes if needed, too */
4485352f7f91STakashi Iwai 	/* if LO is a copy of either HP or Speaker, don't need to handle it */
4486352f7f91STakashi Iwai 	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
4487352f7f91STakashi Iwai 	    spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
4488352f7f91STakashi Iwai 		return;
4489352f7f91STakashi Iwai 	if (!spec->automute_lo)
4490352f7f91STakashi Iwai 		on = 0;
4491352f7f91STakashi Iwai 	else
4492352f7f91STakashi Iwai 		on = spec->hp_jack_present;
4493352f7f91STakashi Iwai 	on |= spec->master_mute;
449447b9ddb8STakashi Iwai 	spec->line_out_muted = on;
4495e80c60f3STakashi Iwai 	paths = spec->out_paths;
4496352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
4497e80c60f3STakashi Iwai 		    spec->autocfg.line_out_pins, paths, on);
4498352f7f91STakashi Iwai }
44992698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs);
4500352f7f91STakashi Iwai 
call_update_outputs(struct hda_codec * codec)4501352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec)
4502352f7f91STakashi Iwai {
4503352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4504352f7f91STakashi Iwai 	if (spec->automute_hook)
4505352f7f91STakashi Iwai 		spec->automute_hook(codec);
4506352f7f91STakashi Iwai 	else
45075d550e15STakashi Iwai 		snd_hda_gen_update_outputs(codec);
45087eebffd3STakashi Iwai 
45099ab0cb30STakashi Iwai 	/* sync the whole vmaster followers to reflect the new auto-mute status */
45107eebffd3STakashi Iwai 	if (spec->auto_mute_via_amp && !codec->bus->shutdown)
45117eebffd3STakashi Iwai 		snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
4512352f7f91STakashi Iwai }
4513352f7f91STakashi Iwai 
4514dda42bd0STakashi Iwai /**
4515dda42bd0STakashi Iwai  * snd_hda_gen_hp_automute - standard HP-automute helper
4516dda42bd0STakashi Iwai  * @codec: the HDA codec
4517dda42bd0STakashi Iwai  * @jack: jack object, NULL for the whole
4518dda42bd0STakashi Iwai  */
snd_hda_gen_hp_automute(struct hda_codec * codec,struct hda_jack_callback * jack)45191a4f69d5STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec,
45201a4f69d5STakashi Iwai 			     struct hda_jack_callback *jack)
4521352f7f91STakashi Iwai {
4522352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
452392603c59STakashi Iwai 	hda_nid_t *pins = spec->autocfg.hp_pins;
452492603c59STakashi Iwai 	int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins);
4525352f7f91STakashi Iwai 
452692603c59STakashi Iwai 	/* No detection for the first HP jack during indep-HP mode */
452792603c59STakashi Iwai 	if (spec->indep_hp_enabled) {
452892603c59STakashi Iwai 		pins++;
452992603c59STakashi Iwai 		num_pins--;
453092603c59STakashi Iwai 	}
453192603c59STakashi Iwai 
453292603c59STakashi Iwai 	spec->hp_jack_present = detect_jacks(codec, num_pins, pins);
4533352f7f91STakashi Iwai 	if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
4534352f7f91STakashi Iwai 		return;
4535352f7f91STakashi Iwai 	call_update_outputs(codec);
4536352f7f91STakashi Iwai }
45372698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
4538352f7f91STakashi Iwai 
4539dda42bd0STakashi Iwai /**
4540dda42bd0STakashi Iwai  * snd_hda_gen_line_automute - standard line-out-automute helper
4541dda42bd0STakashi Iwai  * @codec: the HDA codec
4542dda42bd0STakashi Iwai  * @jack: jack object, NULL for the whole
4543dda42bd0STakashi Iwai  */
snd_hda_gen_line_automute(struct hda_codec * codec,struct hda_jack_callback * jack)45441a4f69d5STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec,
45451a4f69d5STakashi Iwai 			       struct hda_jack_callback *jack)
4546352f7f91STakashi Iwai {
4547352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4548352f7f91STakashi Iwai 
4549352f7f91STakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
4550352f7f91STakashi Iwai 		return;
4551352f7f91STakashi Iwai 	/* check LO jack only when it's different from HP */
4552352f7f91STakashi Iwai 	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
4553352f7f91STakashi Iwai 		return;
4554352f7f91STakashi Iwai 
4555352f7f91STakashi Iwai 	spec->line_jack_present =
4556352f7f91STakashi Iwai 		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
4557352f7f91STakashi Iwai 			     spec->autocfg.line_out_pins);
4558352f7f91STakashi Iwai 	if (!spec->automute_speaker || !spec->detect_lo)
4559352f7f91STakashi Iwai 		return;
4560352f7f91STakashi Iwai 	call_update_outputs(codec);
4561352f7f91STakashi Iwai }
45622698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
4563352f7f91STakashi Iwai 
4564dda42bd0STakashi Iwai /**
4565dda42bd0STakashi Iwai  * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper
4566dda42bd0STakashi Iwai  * @codec: the HDA codec
4567dda42bd0STakashi Iwai  * @jack: jack object, NULL for the whole
4568dda42bd0STakashi Iwai  */
snd_hda_gen_mic_autoswitch(struct hda_codec * codec,struct hda_jack_callback * jack)45691a4f69d5STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
45701a4f69d5STakashi Iwai 				struct hda_jack_callback *jack)
4571352f7f91STakashi Iwai {
4572352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4573352f7f91STakashi Iwai 	int i;
4574352f7f91STakashi Iwai 
4575352f7f91STakashi Iwai 	if (!spec->auto_mic)
4576352f7f91STakashi Iwai 		return;
4577352f7f91STakashi Iwai 
4578352f7f91STakashi Iwai 	for (i = spec->am_num_entries - 1; i > 0; i--) {
45790b4df931STakashi Iwai 		hda_nid_t pin = spec->am_entry[i].pin;
45800b4df931STakashi Iwai 		/* don't detect pins retasked as outputs */
45810b4df931STakashi Iwai 		if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
45820b4df931STakashi Iwai 			continue;
458360ea8ca2STakashi Iwai 		if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
4584352f7f91STakashi Iwai 			mux_select(codec, 0, spec->am_entry[i].idx);
4585352f7f91STakashi Iwai 			return;
4586352f7f91STakashi Iwai 		}
4587352f7f91STakashi Iwai 	}
4588352f7f91STakashi Iwai 	mux_select(codec, 0, spec->am_entry[0].idx);
45891da177e4SLinus Torvalds }
45902698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);
45911da177e4SLinus Torvalds 
459277afe0e9STakashi Iwai /* call appropriate hooks */
call_hp_automute(struct hda_codec * codec,struct hda_jack_callback * jack)45931a4f69d5STakashi Iwai static void call_hp_automute(struct hda_codec *codec,
45941a4f69d5STakashi Iwai 			     struct hda_jack_callback *jack)
459577afe0e9STakashi Iwai {
459677afe0e9STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
459777afe0e9STakashi Iwai 	if (spec->hp_automute_hook)
459877afe0e9STakashi Iwai 		spec->hp_automute_hook(codec, jack);
459977afe0e9STakashi Iwai 	else
460077afe0e9STakashi Iwai 		snd_hda_gen_hp_automute(codec, jack);
460177afe0e9STakashi Iwai }
460277afe0e9STakashi Iwai 
call_line_automute(struct hda_codec * codec,struct hda_jack_callback * jack)460377afe0e9STakashi Iwai static void call_line_automute(struct hda_codec *codec,
46041a4f69d5STakashi Iwai 			       struct hda_jack_callback *jack)
460577afe0e9STakashi Iwai {
460677afe0e9STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
460777afe0e9STakashi Iwai 	if (spec->line_automute_hook)
460877afe0e9STakashi Iwai 		spec->line_automute_hook(codec, jack);
460977afe0e9STakashi Iwai 	else
461077afe0e9STakashi Iwai 		snd_hda_gen_line_automute(codec, jack);
461177afe0e9STakashi Iwai }
461277afe0e9STakashi Iwai 
call_mic_autoswitch(struct hda_codec * codec,struct hda_jack_callback * jack)461377afe0e9STakashi Iwai static void call_mic_autoswitch(struct hda_codec *codec,
46141a4f69d5STakashi Iwai 				struct hda_jack_callback *jack)
461577afe0e9STakashi Iwai {
461677afe0e9STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
461777afe0e9STakashi Iwai 	if (spec->mic_autoswitch_hook)
461877afe0e9STakashi Iwai 		spec->mic_autoswitch_hook(codec, jack);
461977afe0e9STakashi Iwai 	else
462077afe0e9STakashi Iwai 		snd_hda_gen_mic_autoswitch(codec, jack);
462177afe0e9STakashi Iwai }
462277afe0e9STakashi Iwai 
4623963afde9STakashi Iwai /* update jack retasking */
update_automute_all(struct hda_codec * codec)4624963afde9STakashi Iwai static void update_automute_all(struct hda_codec *codec)
4625963afde9STakashi Iwai {
4626963afde9STakashi Iwai 	call_hp_automute(codec, NULL);
4627963afde9STakashi Iwai 	call_line_automute(codec, NULL);
4628963afde9STakashi Iwai 	call_mic_autoswitch(codec, NULL);
4629963afde9STakashi Iwai }
4630963afde9STakashi Iwai 
46311da177e4SLinus Torvalds /*
4632352f7f91STakashi Iwai  * Auto-Mute mode mixer enum support
46331da177e4SLinus Torvalds  */
automute_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4634352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol,
4635352f7f91STakashi Iwai 			      struct snd_ctl_elem_info *uinfo)
4636352f7f91STakashi Iwai {
4637352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4638352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4639352f7f91STakashi Iwai 	static const char * const texts3[] = {
4640352f7f91STakashi Iwai 		"Disabled", "Speaker Only", "Line Out+Speaker"
46411da177e4SLinus Torvalds 	};
46421da177e4SLinus Torvalds 
4643352f7f91STakashi Iwai 	if (spec->automute_speaker_possible && spec->automute_lo_possible)
4644352f7f91STakashi Iwai 		return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
4645352f7f91STakashi Iwai 	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
4646352f7f91STakashi Iwai }
4647352f7f91STakashi Iwai 
automute_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4648352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol,
4649352f7f91STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
4650352f7f91STakashi Iwai {
4651352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4652352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4653352f7f91STakashi Iwai 	unsigned int val = 0;
4654352f7f91STakashi Iwai 	if (spec->automute_speaker)
4655352f7f91STakashi Iwai 		val++;
4656352f7f91STakashi Iwai 	if (spec->automute_lo)
4657352f7f91STakashi Iwai 		val++;
4658352f7f91STakashi Iwai 
4659352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = val;
4660352f7f91STakashi Iwai 	return 0;
4661352f7f91STakashi Iwai }
4662352f7f91STakashi Iwai 
automute_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4663352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol,
4664352f7f91STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
4665352f7f91STakashi Iwai {
4666352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4667352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4668352f7f91STakashi Iwai 
4669352f7f91STakashi Iwai 	switch (ucontrol->value.enumerated.item[0]) {
4670352f7f91STakashi Iwai 	case 0:
4671352f7f91STakashi Iwai 		if (!spec->automute_speaker && !spec->automute_lo)
4672352f7f91STakashi Iwai 			return 0;
4673352f7f91STakashi Iwai 		spec->automute_speaker = 0;
4674352f7f91STakashi Iwai 		spec->automute_lo = 0;
4675352f7f91STakashi Iwai 		break;
4676352f7f91STakashi Iwai 	case 1:
4677352f7f91STakashi Iwai 		if (spec->automute_speaker_possible) {
4678352f7f91STakashi Iwai 			if (!spec->automute_lo && spec->automute_speaker)
4679352f7f91STakashi Iwai 				return 0;
4680352f7f91STakashi Iwai 			spec->automute_speaker = 1;
4681352f7f91STakashi Iwai 			spec->automute_lo = 0;
4682352f7f91STakashi Iwai 		} else if (spec->automute_lo_possible) {
4683352f7f91STakashi Iwai 			if (spec->automute_lo)
4684352f7f91STakashi Iwai 				return 0;
4685352f7f91STakashi Iwai 			spec->automute_lo = 1;
4686352f7f91STakashi Iwai 		} else
4687352f7f91STakashi Iwai 			return -EINVAL;
4688352f7f91STakashi Iwai 		break;
4689352f7f91STakashi Iwai 	case 2:
4690352f7f91STakashi Iwai 		if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
4691352f7f91STakashi Iwai 			return -EINVAL;
4692352f7f91STakashi Iwai 		if (spec->automute_speaker && spec->automute_lo)
4693352f7f91STakashi Iwai 			return 0;
4694352f7f91STakashi Iwai 		spec->automute_speaker = 1;
4695352f7f91STakashi Iwai 		spec->automute_lo = 1;
4696352f7f91STakashi Iwai 		break;
4697352f7f91STakashi Iwai 	default:
4698352f7f91STakashi Iwai 		return -EINVAL;
4699352f7f91STakashi Iwai 	}
4700352f7f91STakashi Iwai 	call_update_outputs(codec);
4701352f7f91STakashi Iwai 	return 1;
4702352f7f91STakashi Iwai }
4703352f7f91STakashi Iwai 
4704352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = {
4705352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4706352f7f91STakashi Iwai 	.name = "Auto-Mute Mode",
4707352f7f91STakashi Iwai 	.info = automute_mode_info,
4708352f7f91STakashi Iwai 	.get = automute_mode_get,
4709352f7f91STakashi Iwai 	.put = automute_mode_put,
4710352f7f91STakashi Iwai };
4711352f7f91STakashi Iwai 
add_automute_mode_enum(struct hda_codec * codec)4712352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec)
4713352f7f91STakashi Iwai {
4714352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4715352f7f91STakashi Iwai 
471612c93df6STakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum))
4717352f7f91STakashi Iwai 		return -ENOMEM;
4718352f7f91STakashi Iwai 	return 0;
4719352f7f91STakashi Iwai }
4720352f7f91STakashi Iwai 
4721352f7f91STakashi Iwai /*
4722352f7f91STakashi Iwai  * Check the availability of HP/line-out auto-mute;
4723352f7f91STakashi Iwai  * Set up appropriately if really supported
4724352f7f91STakashi Iwai  */
check_auto_mute_availability(struct hda_codec * codec)4725352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec)
4726352f7f91STakashi Iwai {
4727352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4728352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
4729352f7f91STakashi Iwai 	int present = 0;
4730352f7f91STakashi Iwai 	int i, err;
4731352f7f91STakashi Iwai 
4732f72706beSTakashi Iwai 	if (spec->suppress_auto_mute)
4733f72706beSTakashi Iwai 		return 0;
4734f72706beSTakashi Iwai 
4735352f7f91STakashi Iwai 	if (cfg->hp_pins[0])
4736352f7f91STakashi Iwai 		present++;
4737352f7f91STakashi Iwai 	if (cfg->line_out_pins[0])
4738352f7f91STakashi Iwai 		present++;
4739352f7f91STakashi Iwai 	if (cfg->speaker_pins[0])
4740352f7f91STakashi Iwai 		present++;
4741352f7f91STakashi Iwai 	if (present < 2) /* need two different output types */
4742352f7f91STakashi Iwai 		return 0;
4743352f7f91STakashi Iwai 
4744352f7f91STakashi Iwai 	if (!cfg->speaker_pins[0] &&
4745352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
4746352f7f91STakashi Iwai 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
4747352f7f91STakashi Iwai 		       sizeof(cfg->speaker_pins));
4748352f7f91STakashi Iwai 		cfg->speaker_outs = cfg->line_outs;
4749352f7f91STakashi Iwai 	}
4750352f7f91STakashi Iwai 
4751352f7f91STakashi Iwai 	if (!cfg->hp_pins[0] &&
4752352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_HP_OUT) {
4753352f7f91STakashi Iwai 		memcpy(cfg->hp_pins, cfg->line_out_pins,
4754352f7f91STakashi Iwai 		       sizeof(cfg->hp_pins));
4755352f7f91STakashi Iwai 		cfg->hp_outs = cfg->line_outs;
4756352f7f91STakashi Iwai 	}
4757352f7f91STakashi Iwai 
4758352f7f91STakashi Iwai 	for (i = 0; i < cfg->hp_outs; i++) {
4759352f7f91STakashi Iwai 		hda_nid_t nid = cfg->hp_pins[i];
4760352f7f91STakashi Iwai 		if (!is_jack_detectable(codec, nid))
4761352f7f91STakashi Iwai 			continue;
47624e76a883STakashi Iwai 		codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid);
476362f949bfSTakashi Iwai 		snd_hda_jack_detect_enable_callback(codec, nid,
476477afe0e9STakashi Iwai 						    call_hp_automute);
4765352f7f91STakashi Iwai 		spec->detect_hp = 1;
4766352f7f91STakashi Iwai 	}
4767352f7f91STakashi Iwai 
4768352f7f91STakashi Iwai 	if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
4769352f7f91STakashi Iwai 		if (cfg->speaker_outs)
4770352f7f91STakashi Iwai 			for (i = 0; i < cfg->line_outs; i++) {
4771352f7f91STakashi Iwai 				hda_nid_t nid = cfg->line_out_pins[i];
4772352f7f91STakashi Iwai 				if (!is_jack_detectable(codec, nid))
4773352f7f91STakashi Iwai 					continue;
47744e76a883STakashi Iwai 				codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid);
4775352f7f91STakashi Iwai 				snd_hda_jack_detect_enable_callback(codec, nid,
477677afe0e9STakashi Iwai 								    call_line_automute);
4777352f7f91STakashi Iwai 				spec->detect_lo = 1;
4778352f7f91STakashi Iwai 			}
4779352f7f91STakashi Iwai 		spec->automute_lo_possible = spec->detect_hp;
4780352f7f91STakashi Iwai 	}
4781352f7f91STakashi Iwai 
4782352f7f91STakashi Iwai 	spec->automute_speaker_possible = cfg->speaker_outs &&
4783352f7f91STakashi Iwai 		(spec->detect_hp || spec->detect_lo);
4784352f7f91STakashi Iwai 
4785352f7f91STakashi Iwai 	spec->automute_lo = spec->automute_lo_possible;
4786352f7f91STakashi Iwai 	spec->automute_speaker = spec->automute_speaker_possible;
4787352f7f91STakashi Iwai 
4788352f7f91STakashi Iwai 	if (spec->automute_speaker_possible || spec->automute_lo_possible) {
4789352f7f91STakashi Iwai 		/* create a control for automute mode */
4790352f7f91STakashi Iwai 		err = add_automute_mode_enum(codec);
4791352f7f91STakashi Iwai 		if (err < 0)
4792352f7f91STakashi Iwai 			return err;
4793352f7f91STakashi Iwai 	}
4794352f7f91STakashi Iwai 	return 0;
4795352f7f91STakashi Iwai }
4796352f7f91STakashi Iwai 
4797352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */
auto_mic_check_imux(struct hda_codec * codec)4798352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec)
4799352f7f91STakashi Iwai {
4800352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4801352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
4802352f7f91STakashi Iwai 	int i;
4803352f7f91STakashi Iwai 
4804352f7f91STakashi Iwai 	imux = &spec->input_mux;
4805352f7f91STakashi Iwai 	for (i = 0; i < spec->am_num_entries; i++) {
4806352f7f91STakashi Iwai 		spec->am_entry[i].idx =
4807352f7f91STakashi Iwai 			find_idx_in_nid_list(spec->am_entry[i].pin,
4808352f7f91STakashi Iwai 					     spec->imux_pins, imux->num_items);
4809352f7f91STakashi Iwai 		if (spec->am_entry[i].idx < 0)
4810352f7f91STakashi Iwai 			return false; /* no corresponding imux */
4811352f7f91STakashi Iwai 	}
4812352f7f91STakashi Iwai 
4813352f7f91STakashi Iwai 	/* we don't need the jack detection for the first pin */
4814352f7f91STakashi Iwai 	for (i = 1; i < spec->am_num_entries; i++)
4815352f7f91STakashi Iwai 		snd_hda_jack_detect_enable_callback(codec,
4816352f7f91STakashi Iwai 						    spec->am_entry[i].pin,
481777afe0e9STakashi Iwai 						    call_mic_autoswitch);
4818352f7f91STakashi Iwai 	return true;
4819352f7f91STakashi Iwai }
4820352f7f91STakashi Iwai 
compare_attr(const void * ap,const void * bp)4821352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp)
4822352f7f91STakashi Iwai {
4823352f7f91STakashi Iwai 	const struct automic_entry *a = ap;
4824352f7f91STakashi Iwai 	const struct automic_entry *b = bp;
4825352f7f91STakashi Iwai 	return (int)(a->attr - b->attr);
4826352f7f91STakashi Iwai }
4827352f7f91STakashi Iwai 
4828352f7f91STakashi Iwai /*
4829352f7f91STakashi Iwai  * Check the availability of auto-mic switch;
4830352f7f91STakashi Iwai  * Set up if really supported
4831352f7f91STakashi Iwai  */
check_auto_mic_availability(struct hda_codec * codec)4832352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec)
4833352f7f91STakashi Iwai {
4834352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4835352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
4836352f7f91STakashi Iwai 	unsigned int types;
4837352f7f91STakashi Iwai 	int i, num_pins;
4838352f7f91STakashi Iwai 
4839d12daf6fSTakashi Iwai 	if (spec->suppress_auto_mic)
4840d12daf6fSTakashi Iwai 		return 0;
4841d12daf6fSTakashi Iwai 
4842352f7f91STakashi Iwai 	types = 0;
4843352f7f91STakashi Iwai 	num_pins = 0;
4844352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
4845352f7f91STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
4846352f7f91STakashi Iwai 		unsigned int attr;
4847352f7f91STakashi Iwai 		attr = snd_hda_codec_get_pincfg(codec, nid);
4848352f7f91STakashi Iwai 		attr = snd_hda_get_input_pin_attr(attr);
4849352f7f91STakashi Iwai 		if (types & (1 << attr))
4850352f7f91STakashi Iwai 			return 0; /* already occupied */
4851352f7f91STakashi Iwai 		switch (attr) {
4852352f7f91STakashi Iwai 		case INPUT_PIN_ATTR_INT:
4853352f7f91STakashi Iwai 			if (cfg->inputs[i].type != AUTO_PIN_MIC)
4854352f7f91STakashi Iwai 				return 0; /* invalid type */
4855352f7f91STakashi Iwai 			break;
4856352f7f91STakashi Iwai 		case INPUT_PIN_ATTR_UNUSED:
4857352f7f91STakashi Iwai 			return 0; /* invalid entry */
4858352f7f91STakashi Iwai 		default:
4859352f7f91STakashi Iwai 			if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
4860352f7f91STakashi Iwai 				return 0; /* invalid type */
4861352f7f91STakashi Iwai 			if (!spec->line_in_auto_switch &&
4862352f7f91STakashi Iwai 			    cfg->inputs[i].type != AUTO_PIN_MIC)
4863352f7f91STakashi Iwai 				return 0; /* only mic is allowed */
4864352f7f91STakashi Iwai 			if (!is_jack_detectable(codec, nid))
4865352f7f91STakashi Iwai 				return 0; /* no unsol support */
4866352f7f91STakashi Iwai 			break;
4867352f7f91STakashi Iwai 		}
4868352f7f91STakashi Iwai 		if (num_pins >= MAX_AUTO_MIC_PINS)
4869352f7f91STakashi Iwai 			return 0;
4870352f7f91STakashi Iwai 		types |= (1 << attr);
4871352f7f91STakashi Iwai 		spec->am_entry[num_pins].pin = nid;
4872352f7f91STakashi Iwai 		spec->am_entry[num_pins].attr = attr;
4873352f7f91STakashi Iwai 		num_pins++;
4874352f7f91STakashi Iwai 	}
4875352f7f91STakashi Iwai 
4876352f7f91STakashi Iwai 	if (num_pins < 2)
4877352f7f91STakashi Iwai 		return 0;
4878352f7f91STakashi Iwai 
4879352f7f91STakashi Iwai 	spec->am_num_entries = num_pins;
4880352f7f91STakashi Iwai 	/* sort the am_entry in the order of attr so that the pin with a
4881352f7f91STakashi Iwai 	 * higher attr will be selected when the jack is plugged.
4882352f7f91STakashi Iwai 	 */
4883352f7f91STakashi Iwai 	sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]),
4884352f7f91STakashi Iwai 	     compare_attr, NULL);
4885352f7f91STakashi Iwai 
4886352f7f91STakashi Iwai 	if (!auto_mic_check_imux(codec))
4887352f7f91STakashi Iwai 		return 0;
4888352f7f91STakashi Iwai 
4889352f7f91STakashi Iwai 	spec->auto_mic = 1;
4890352f7f91STakashi Iwai 	spec->num_adc_nids = 1;
4891352f7f91STakashi Iwai 	spec->cur_mux[0] = spec->am_entry[0].idx;
48924e76a883STakashi Iwai 	codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
4893352f7f91STakashi Iwai 		    spec->am_entry[0].pin,
4894352f7f91STakashi Iwai 		    spec->am_entry[1].pin,
4895352f7f91STakashi Iwai 		    spec->am_entry[2].pin);
4896352f7f91STakashi Iwai 
4897352f7f91STakashi Iwai 	return 0;
4898352f7f91STakashi Iwai }
4899352f7f91STakashi Iwai 
4900dda42bd0STakashi Iwai /**
4901dda42bd0STakashi Iwai  * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets
4902dda42bd0STakashi Iwai  * into power down
4903dda42bd0STakashi Iwai  * @codec: the HDA codec
4904dda42bd0STakashi Iwai  * @nid: NID to evalute
4905dda42bd0STakashi Iwai  * @power_state: target power state
4906dda42bd0STakashi Iwai  */
snd_hda_gen_path_power_filter(struct hda_codec * codec,hda_nid_t nid,unsigned int power_state)4907dfc6e469STakashi Iwai unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
490855196fffSTakashi Iwai 						  hda_nid_t nid,
490955196fffSTakashi Iwai 						  unsigned int power_state)
491055196fffSTakashi Iwai {
4911b6c09b3cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4912b6c09b3cSTakashi Iwai 
4913b6c09b3cSTakashi Iwai 	if (!spec->power_down_unused && !codec->power_save_node)
4914b6c09b3cSTakashi Iwai 		return power_state;
49157639a06cSTakashi Iwai 	if (power_state != AC_PWRST_D0 || nid == codec->core.afg)
491655196fffSTakashi Iwai 		return power_state;
491755196fffSTakashi Iwai 	if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
491855196fffSTakashi Iwai 		return power_state;
4919b1b9fbd0STakashi Iwai 	if (is_active_nid_for_any(codec, nid))
492055196fffSTakashi Iwai 		return power_state;
492155196fffSTakashi Iwai 	return AC_PWRST_D3;
492255196fffSTakashi Iwai }
4923dfc6e469STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter);
492455196fffSTakashi Iwai 
4925ebb93c05STakashi Iwai /* mute all aamix inputs initially; parse up to the first leaves */
mute_all_mixer_nid(struct hda_codec * codec,hda_nid_t mix)4926ebb93c05STakashi Iwai static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
4927ebb93c05STakashi Iwai {
4928ebb93c05STakashi Iwai 	int i, nums;
4929ebb93c05STakashi Iwai 	const hda_nid_t *conn;
4930ebb93c05STakashi Iwai 	bool has_amp;
4931ebb93c05STakashi Iwai 
4932ebb93c05STakashi Iwai 	nums = snd_hda_get_conn_list(codec, mix, &conn);
4933ebb93c05STakashi Iwai 	has_amp = nid_has_mute(codec, mix, HDA_INPUT);
4934ebb93c05STakashi Iwai 	for (i = 0; i < nums; i++) {
4935ebb93c05STakashi Iwai 		if (has_amp)
4936ef403edbSTakashi Iwai 			update_amp(codec, mix, HDA_INPUT, i,
4937ebb93c05STakashi Iwai 				   0xff, HDA_AMP_MUTE);
4938ebb93c05STakashi Iwai 		else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
4939ef403edbSTakashi Iwai 			update_amp(codec, conn[i], HDA_OUTPUT, 0,
4940ebb93c05STakashi Iwai 				   0xff, HDA_AMP_MUTE);
4941ebb93c05STakashi Iwai 	}
4942ebb93c05STakashi Iwai }
4943352f7f91STakashi Iwai 
4944dda42bd0STakashi Iwai /**
4945e6feb5d0STakashi Iwai  * snd_hda_gen_stream_pm - Stream power management callback
4946e6feb5d0STakashi Iwai  * @codec: the HDA codec
4947e6feb5d0STakashi Iwai  * @nid: audio widget
4948e6feb5d0STakashi Iwai  * @on: power on/off flag
4949e6feb5d0STakashi Iwai  *
4950967b1307STakashi Iwai  * Set this in patch_ops.stream_pm.  Only valid with power_save_node flag.
4951e6feb5d0STakashi Iwai  */
snd_hda_gen_stream_pm(struct hda_codec * codec,hda_nid_t nid,bool on)4952e6feb5d0STakashi Iwai void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
4953e6feb5d0STakashi Iwai {
4954967b1307STakashi Iwai 	if (codec->power_save_node)
4955e6feb5d0STakashi Iwai 		set_path_power(codec, nid, -1, on);
4956e6feb5d0STakashi Iwai }
4957e6feb5d0STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
4958e6feb5d0STakashi Iwai 
4959e6feb5d0STakashi Iwai /**
4960dda42bd0STakashi Iwai  * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
4961dda42bd0STakashi Iwai  * set up the hda_gen_spec
4962dda42bd0STakashi Iwai  * @codec: the HDA codec
4963dda42bd0STakashi Iwai  * @cfg: Parsed pin configuration
49649eb413e5STakashi Iwai  *
49659eb413e5STakashi Iwai  * return 1 if successful, 0 if the proper config is not found,
4966352f7f91STakashi Iwai  * or a negative error code
4967352f7f91STakashi Iwai  */
snd_hda_gen_parse_auto_config(struct hda_codec * codec,struct auto_pin_cfg * cfg)4968352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
49699eb413e5STakashi Iwai 				  struct auto_pin_cfg *cfg)
4970352f7f91STakashi Iwai {
4971352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4972352f7f91STakashi Iwai 	int err;
4973352f7f91STakashi Iwai 
49741c70a583STakashi Iwai 	parse_user_hints(codec);
49751c70a583STakashi Iwai 
4976e65bf997SJaroslav Kysela 	if (spec->vmaster_mute_led || spec->mic_mute_led)
4977e65bf997SJaroslav Kysela 		snd_ctl_led_request();
4978e65bf997SJaroslav Kysela 
4979e4a395e7STakashi Iwai 	if (spec->mixer_nid && !spec->mixer_merge_nid)
4980e4a395e7STakashi Iwai 		spec->mixer_merge_nid = spec->mixer_nid;
4981e4a395e7STakashi Iwai 
49829eb413e5STakashi Iwai 	if (cfg != &spec->autocfg) {
49839eb413e5STakashi Iwai 		spec->autocfg = *cfg;
49849eb413e5STakashi Iwai 		cfg = &spec->autocfg;
49859eb413e5STakashi Iwai 	}
49869eb413e5STakashi Iwai 
498798bd1115STakashi Iwai 	if (!spec->main_out_badness)
498898bd1115STakashi Iwai 		spec->main_out_badness = &hda_main_out_badness;
498998bd1115STakashi Iwai 	if (!spec->extra_out_badness)
499098bd1115STakashi Iwai 		spec->extra_out_badness = &hda_extra_out_badness;
499198bd1115STakashi Iwai 
49926fc4cb97SDavid Henningsson 	fill_all_dac_nids(codec);
49936fc4cb97SDavid Henningsson 
4994352f7f91STakashi Iwai 	if (!cfg->line_outs) {
4995352f7f91STakashi Iwai 		if (cfg->dig_outs || cfg->dig_in_pin) {
4996352f7f91STakashi Iwai 			spec->multiout.max_channels = 2;
4997352f7f91STakashi Iwai 			spec->no_analog = 1;
4998352f7f91STakashi Iwai 			goto dig_only;
4999352f7f91STakashi Iwai 		}
5000c9e4bdb7STakashi Iwai 		if (!cfg->num_inputs && !cfg->dig_in_pin)
5001352f7f91STakashi Iwai 			return 0; /* can't find valid BIOS pin config */
5002352f7f91STakashi Iwai 	}
5003352f7f91STakashi Iwai 
5004352f7f91STakashi Iwai 	if (!spec->no_primary_hp &&
5005352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
5006352f7f91STakashi Iwai 	    cfg->line_outs <= cfg->hp_outs) {
5007352f7f91STakashi Iwai 		/* use HP as primary out */
5008352f7f91STakashi Iwai 		cfg->speaker_outs = cfg->line_outs;
5009352f7f91STakashi Iwai 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
5010352f7f91STakashi Iwai 		       sizeof(cfg->speaker_pins));
5011352f7f91STakashi Iwai 		cfg->line_outs = cfg->hp_outs;
5012352f7f91STakashi Iwai 		memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
5013352f7f91STakashi Iwai 		cfg->hp_outs = 0;
5014352f7f91STakashi Iwai 		memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
5015352f7f91STakashi Iwai 		cfg->line_out_type = AUTO_PIN_HP_OUT;
5016352f7f91STakashi Iwai 	}
5017352f7f91STakashi Iwai 
5018352f7f91STakashi Iwai 	err = parse_output_paths(codec);
5019352f7f91STakashi Iwai 	if (err < 0)
5020352f7f91STakashi Iwai 		return err;
5021352f7f91STakashi Iwai 	err = create_multi_channel_mode(codec);
5022352f7f91STakashi Iwai 	if (err < 0)
5023352f7f91STakashi Iwai 		return err;
5024352f7f91STakashi Iwai 	err = create_multi_out_ctls(codec, cfg);
5025352f7f91STakashi Iwai 	if (err < 0)
5026352f7f91STakashi Iwai 		return err;
5027352f7f91STakashi Iwai 	err = create_hp_out_ctls(codec);
5028352f7f91STakashi Iwai 	if (err < 0)
5029352f7f91STakashi Iwai 		return err;
5030352f7f91STakashi Iwai 	err = create_speaker_out_ctls(codec);
5031352f7f91STakashi Iwai 	if (err < 0)
5032352f7f91STakashi Iwai 		return err;
503338cf6f1aSTakashi Iwai 	err = create_indep_hp_ctls(codec);
503438cf6f1aSTakashi Iwai 	if (err < 0)
503538cf6f1aSTakashi Iwai 		return err;
5036c30aa7b2STakashi Iwai 	err = create_loopback_mixing_ctl(codec);
5037c30aa7b2STakashi Iwai 	if (err < 0)
5038c30aa7b2STakashi Iwai 		return err;
5039967303daSTakashi Iwai 	err = create_hp_mic(codec);
5040352f7f91STakashi Iwai 	if (err < 0)
5041352f7f91STakashi Iwai 		return err;
5042352f7f91STakashi Iwai 	err = create_input_ctls(codec);
5043352f7f91STakashi Iwai 	if (err < 0)
5044352f7f91STakashi Iwai 		return err;
5045352f7f91STakashi Iwai 
5046e6feb5d0STakashi Iwai 	/* add power-down pin callbacks at first */
5047e6feb5d0STakashi Iwai 	add_all_pin_power_ctls(codec, false);
5048e6feb5d0STakashi Iwai 
5049a07a949bSTakashi Iwai 	spec->const_channel_count = spec->ext_channel_count;
5050a07a949bSTakashi Iwai 	/* check the multiple speaker and headphone pins */
5051a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
5052a07a949bSTakashi Iwai 		spec->const_channel_count = max(spec->const_channel_count,
5053a07a949bSTakashi Iwai 						cfg->speaker_outs * 2);
5054a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
5055a07a949bSTakashi Iwai 		spec->const_channel_count = max(spec->const_channel_count,
5056a07a949bSTakashi Iwai 						cfg->hp_outs * 2);
5057352f7f91STakashi Iwai 	spec->multiout.max_channels = max(spec->ext_channel_count,
5058352f7f91STakashi Iwai 					  spec->const_channel_count);
5059352f7f91STakashi Iwai 
5060352f7f91STakashi Iwai 	err = check_auto_mute_availability(codec);
5061352f7f91STakashi Iwai 	if (err < 0)
5062352f7f91STakashi Iwai 		return err;
5063352f7f91STakashi Iwai 
5064352f7f91STakashi Iwai 	err = check_dyn_adc_switch(codec);
5065352f7f91STakashi Iwai 	if (err < 0)
5066352f7f91STakashi Iwai 		return err;
5067352f7f91STakashi Iwai 
5068352f7f91STakashi Iwai 	err = check_auto_mic_availability(codec);
5069352f7f91STakashi Iwai 	if (err < 0)
5070352f7f91STakashi Iwai 		return err;
5071352f7f91STakashi Iwai 
5072f1e762ddSTakashi Iwai 	/* add stereo mix if available and not enabled yet */
5073f1e762ddSTakashi Iwai 	if (!spec->auto_mic && spec->mixer_nid &&
507474f14b36STakashi Iwai 	    spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_AUTO &&
507574f14b36STakashi Iwai 	    spec->input_mux.num_items > 1) {
5076f1e762ddSTakashi Iwai 		err = parse_capture_source(codec, spec->mixer_nid,
5077f1e762ddSTakashi Iwai 					   CFG_IDX_MIX, spec->num_all_adcs,
5078f1e762ddSTakashi Iwai 					   "Stereo Mix", 0);
5079f1e762ddSTakashi Iwai 		if (err < 0)
5080f1e762ddSTakashi Iwai 			return err;
5081f1e762ddSTakashi Iwai 	}
5082f1e762ddSTakashi Iwai 
5083f1e762ddSTakashi Iwai 
5084352f7f91STakashi Iwai 	err = create_capture_mixers(codec);
5085352f7f91STakashi Iwai 	if (err < 0)
5086352f7f91STakashi Iwai 		return err;
5087352f7f91STakashi Iwai 
5088352f7f91STakashi Iwai 	err = parse_mic_boost(codec);
5089352f7f91STakashi Iwai 	if (err < 0)
5090352f7f91STakashi Iwai 		return err;
5091352f7f91STakashi Iwai 
5092ced4cefcSTakashi Iwai 	/* create "Headphone Mic Jack Mode" if no input selection is
5093ced4cefcSTakashi Iwai 	 * available (or user specifies add_jack_modes hint)
5094ced4cefcSTakashi Iwai 	 */
5095ced4cefcSTakashi Iwai 	if (spec->hp_mic_pin &&
5096ced4cefcSTakashi Iwai 	    (spec->auto_mic || spec->input_mux.num_items == 1 ||
5097ced4cefcSTakashi Iwai 	     spec->add_jack_modes)) {
5098ced4cefcSTakashi Iwai 		err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin);
5099ced4cefcSTakashi Iwai 		if (err < 0)
5100ced4cefcSTakashi Iwai 			return err;
5101ced4cefcSTakashi Iwai 	}
5102ced4cefcSTakashi Iwai 
5103f811c3cfSTakashi Iwai 	if (spec->add_jack_modes) {
5104978e77e7STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
5105978e77e7STakashi Iwai 			err = create_out_jack_modes(codec, cfg->line_outs,
5106978e77e7STakashi Iwai 						    cfg->line_out_pins);
5107978e77e7STakashi Iwai 			if (err < 0)
5108978e77e7STakashi Iwai 				return err;
5109978e77e7STakashi Iwai 		}
5110978e77e7STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
5111978e77e7STakashi Iwai 			err = create_out_jack_modes(codec, cfg->hp_outs,
5112978e77e7STakashi Iwai 						    cfg->hp_pins);
5113978e77e7STakashi Iwai 			if (err < 0)
5114978e77e7STakashi Iwai 				return err;
5115978e77e7STakashi Iwai 		}
5116978e77e7STakashi Iwai 	}
5117978e77e7STakashi Iwai 
5118e6feb5d0STakashi Iwai 	/* add power-up pin callbacks at last */
5119e6feb5d0STakashi Iwai 	add_all_pin_power_ctls(codec, true);
5120e6feb5d0STakashi Iwai 
5121ebb93c05STakashi Iwai 	/* mute all aamix input initially */
5122ebb93c05STakashi Iwai 	if (spec->mixer_nid)
5123ebb93c05STakashi Iwai 		mute_all_mixer_nid(codec, spec->mixer_nid);
5124ebb93c05STakashi Iwai 
5125352f7f91STakashi Iwai  dig_only:
5126352f7f91STakashi Iwai 	parse_digital(codec);
5127352f7f91STakashi Iwai 
512849fb1897STakashi Iwai 	if (spec->power_down_unused || codec->power_save_node) {
512924fef902STakashi Iwai 		if (!codec->power_filter)
513055196fffSTakashi Iwai 			codec->power_filter = snd_hda_gen_path_power_filter;
513149fb1897STakashi Iwai 		if (!codec->patch_ops.stream_pm)
513249fb1897STakashi Iwai 			codec->patch_ops.stream_pm = snd_hda_gen_stream_pm;
513349fb1897STakashi Iwai 	}
513455196fffSTakashi Iwai 
51357504b6cdSTakashi Iwai 	if (!spec->no_analog && spec->beep_nid) {
51367504b6cdSTakashi Iwai 		err = snd_hda_attach_beep_device(codec, spec->beep_nid);
51377504b6cdSTakashi Iwai 		if (err < 0)
51387504b6cdSTakashi Iwai 			return err;
5139967b1307STakashi Iwai 		if (codec->beep && codec->power_save_node) {
51405ccf835cSTakashi Iwai 			err = add_fake_beep_paths(codec);
51415ccf835cSTakashi Iwai 			if (err < 0)
51425ccf835cSTakashi Iwai 				return err;
51435ccf835cSTakashi Iwai 			codec->beep->power_hook = beep_power_hook;
51445ccf835cSTakashi Iwai 		}
51457504b6cdSTakashi Iwai 	}
51467504b6cdSTakashi Iwai 
5147352f7f91STakashi Iwai 	return 1;
5148352f7f91STakashi Iwai }
51492698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config);
5150352f7f91STakashi Iwai 
5151352f7f91STakashi Iwai 
5152352f7f91STakashi Iwai /*
5153352f7f91STakashi Iwai  * Build control elements
5154352f7f91STakashi Iwai  */
5155352f7f91STakashi Iwai 
51569ab0cb30STakashi Iwai /* follower controls for virtual master */
51579ab0cb30STakashi Iwai static const char * const follower_pfxs[] = {
5158352f7f91STakashi Iwai 	"Front", "Surround", "Center", "LFE", "Side",
5159352f7f91STakashi Iwai 	"Headphone", "Speaker", "Mono", "Line Out",
5160352f7f91STakashi Iwai 	"CLFE", "Bass Speaker", "PCM",
5161ee79c69aSTakashi Iwai 	"Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
5162ee79c69aSTakashi Iwai 	"Headphone Front", "Headphone Surround", "Headphone CLFE",
516303ad6a8cSDavid Henningsson 	"Headphone Side", "Headphone+LO", "Speaker+LO",
5164352f7f91STakashi Iwai 	NULL,
5165352f7f91STakashi Iwai };
5166352f7f91STakashi Iwai 
5167dda42bd0STakashi Iwai /**
5168dda42bd0STakashi Iwai  * snd_hda_gen_build_controls - Build controls from the parsed results
5169dda42bd0STakashi Iwai  * @codec: the HDA codec
5170dda42bd0STakashi Iwai  *
5171dda42bd0STakashi Iwai  * Pass this to build_controls patch_ops.
5172dda42bd0STakashi Iwai  */
snd_hda_gen_build_controls(struct hda_codec * codec)5173352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec)
5174352f7f91STakashi Iwai {
5175352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5176352f7f91STakashi Iwai 	int err;
5177352f7f91STakashi Iwai 
517836502d02STakashi Iwai 	if (spec->kctls.used) {
5179352f7f91STakashi Iwai 		err = snd_hda_add_new_ctls(codec, spec->kctls.list);
5180352f7f91STakashi Iwai 		if (err < 0)
5181352f7f91STakashi Iwai 			return err;
518236502d02STakashi Iwai 	}
5183352f7f91STakashi Iwai 
5184352f7f91STakashi Iwai 	if (spec->multiout.dig_out_nid) {
5185352f7f91STakashi Iwai 		err = snd_hda_create_dig_out_ctls(codec,
5186352f7f91STakashi Iwai 						  spec->multiout.dig_out_nid,
5187352f7f91STakashi Iwai 						  spec->multiout.dig_out_nid,
5188bbbc7e85STakashi Iwai 						  spec->pcm_rec[1]->pcm_type);
5189352f7f91STakashi Iwai 		if (err < 0)
5190352f7f91STakashi Iwai 			return err;
5191352f7f91STakashi Iwai 		if (!spec->no_analog) {
5192352f7f91STakashi Iwai 			err = snd_hda_create_spdif_share_sw(codec,
5193352f7f91STakashi Iwai 							    &spec->multiout);
5194352f7f91STakashi Iwai 			if (err < 0)
5195352f7f91STakashi Iwai 				return err;
5196352f7f91STakashi Iwai 			spec->multiout.share_spdif = 1;
5197352f7f91STakashi Iwai 		}
5198352f7f91STakashi Iwai 	}
5199352f7f91STakashi Iwai 	if (spec->dig_in_nid) {
5200352f7f91STakashi Iwai 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
5201352f7f91STakashi Iwai 		if (err < 0)
5202352f7f91STakashi Iwai 			return err;
5203352f7f91STakashi Iwai 	}
5204352f7f91STakashi Iwai 
5205352f7f91STakashi Iwai 	/* if we have no master control, let's create it */
52067480316cSTakashi Iwai 	if (!spec->no_analog && !spec->suppress_vmaster &&
5207352f7f91STakashi Iwai 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
5208352f7f91STakashi Iwai 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
52099ab0cb30STakashi Iwai 					  spec->vmaster_tlv, follower_pfxs,
5210e65bf997SJaroslav Kysela 					  "Playback Volume", 0);
5211352f7f91STakashi Iwai 		if (err < 0)
5212352f7f91STakashi Iwai 			return err;
5213352f7f91STakashi Iwai 	}
52147480316cSTakashi Iwai 	if (!spec->no_analog && !spec->suppress_vmaster &&
5215352f7f91STakashi Iwai 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
5216352f7f91STakashi Iwai 		err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
52179ab0cb30STakashi Iwai 					    NULL, follower_pfxs,
5218e65bf997SJaroslav Kysela 					    "Playback Switch", true,
5219e65bf997SJaroslav Kysela 					    spec->vmaster_mute_led ?
5220e65bf997SJaroslav Kysela 						SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0,
5221e65bf997SJaroslav Kysela 					    &spec->vmaster_mute.sw_kctl);
5222352f7f91STakashi Iwai 		if (err < 0)
5223352f7f91STakashi Iwai 			return err;
5224b63eae0aSTakashi Iwai 		if (spec->vmaster_mute.hook) {
5225e65bf997SJaroslav Kysela 			snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
5226b63eae0aSTakashi Iwai 			snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
5227b63eae0aSTakashi Iwai 		}
5228352f7f91STakashi Iwai 	}
5229352f7f91STakashi Iwai 
5230352f7f91STakashi Iwai 	free_kctls(spec); /* no longer needed */
5231352f7f91STakashi Iwai 
5232352f7f91STakashi Iwai 	err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
5233352f7f91STakashi Iwai 	if (err < 0)
5234352f7f91STakashi Iwai 		return err;
5235352f7f91STakashi Iwai 
5236352f7f91STakashi Iwai 	return 0;
5237352f7f91STakashi Iwai }
52382698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls);
5239352f7f91STakashi Iwai 
5240352f7f91STakashi Iwai 
5241352f7f91STakashi Iwai /*
5242352f7f91STakashi Iwai  * PCM definitions
5243352f7f91STakashi Iwai  */
5244352f7f91STakashi Iwai 
call_pcm_playback_hook(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream,int action)5245e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo,
5246e6b85f3cSTakashi Iwai 				   struct hda_codec *codec,
5247e6b85f3cSTakashi Iwai 				   struct snd_pcm_substream *substream,
5248e6b85f3cSTakashi Iwai 				   int action)
5249e6b85f3cSTakashi Iwai {
5250e6b85f3cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5251e6b85f3cSTakashi Iwai 	if (spec->pcm_playback_hook)
5252e6b85f3cSTakashi Iwai 		spec->pcm_playback_hook(hinfo, codec, substream, action);
5253e6b85f3cSTakashi Iwai }
5254e6b85f3cSTakashi Iwai 
call_pcm_capture_hook(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream,int action)5255ac2e8736STakashi Iwai static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo,
5256ac2e8736STakashi Iwai 				  struct hda_codec *codec,
5257ac2e8736STakashi Iwai 				  struct snd_pcm_substream *substream,
5258ac2e8736STakashi Iwai 				  int action)
5259ac2e8736STakashi Iwai {
5260ac2e8736STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5261ac2e8736STakashi Iwai 	if (spec->pcm_capture_hook)
5262ac2e8736STakashi Iwai 		spec->pcm_capture_hook(hinfo, codec, substream, action);
5263ac2e8736STakashi Iwai }
5264ac2e8736STakashi Iwai 
5265352f7f91STakashi Iwai /*
5266352f7f91STakashi Iwai  * Analog playback callbacks
5267352f7f91STakashi Iwai  */
playback_pcm_open(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5268352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo,
5269352f7f91STakashi Iwai 			     struct hda_codec *codec,
5270352f7f91STakashi Iwai 			     struct snd_pcm_substream *substream)
5271352f7f91STakashi Iwai {
5272352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
527338cf6f1aSTakashi Iwai 	int err;
527438cf6f1aSTakashi Iwai 
527538cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
527638cf6f1aSTakashi Iwai 	err = snd_hda_multi_out_analog_open(codec,
527738cf6f1aSTakashi Iwai 					    &spec->multiout, substream,
5278352f7f91STakashi Iwai 					     hinfo);
5279e6b85f3cSTakashi Iwai 	if (!err) {
528038cf6f1aSTakashi Iwai 		spec->active_streams |= 1 << STREAM_MULTI_OUT;
5281e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
5282e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_OPEN);
5283e6b85f3cSTakashi Iwai 	}
528438cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
528538cf6f1aSTakashi Iwai 	return err;
5286352f7f91STakashi Iwai }
5287352f7f91STakashi Iwai 
playback_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5288352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
528997ec558aSTakashi Iwai 				struct hda_codec *codec,
529097ec558aSTakashi Iwai 				unsigned int stream_tag,
529197ec558aSTakashi Iwai 				unsigned int format,
529297ec558aSTakashi Iwai 				struct snd_pcm_substream *substream)
529397ec558aSTakashi Iwai {
5294352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5295e6b85f3cSTakashi Iwai 	int err;
5296e6b85f3cSTakashi Iwai 
5297e6b85f3cSTakashi Iwai 	err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
5298352f7f91STakashi Iwai 					       stream_tag, format, substream);
5299e6b85f3cSTakashi Iwai 	if (!err)
5300e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
5301e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_PREPARE);
5302e6b85f3cSTakashi Iwai 	return err;
5303352f7f91STakashi Iwai }
530497ec558aSTakashi Iwai 
playback_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5305352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
5306352f7f91STakashi Iwai 				struct hda_codec *codec,
5307352f7f91STakashi Iwai 				struct snd_pcm_substream *substream)
5308352f7f91STakashi Iwai {
5309352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5310e6b85f3cSTakashi Iwai 	int err;
5311e6b85f3cSTakashi Iwai 
5312e6b85f3cSTakashi Iwai 	err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
5313e6b85f3cSTakashi Iwai 	if (!err)
5314e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
5315e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_CLEANUP);
5316e6b85f3cSTakashi Iwai 	return err;
5317352f7f91STakashi Iwai }
5318352f7f91STakashi Iwai 
playback_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)531938cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo,
532038cf6f1aSTakashi Iwai 			      struct hda_codec *codec,
532138cf6f1aSTakashi Iwai 			      struct snd_pcm_substream *substream)
532238cf6f1aSTakashi Iwai {
532338cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
532438cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
532538cf6f1aSTakashi Iwai 	spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
5326e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
5327e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLOSE);
532838cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
532938cf6f1aSTakashi Iwai 	return 0;
533038cf6f1aSTakashi Iwai }
533138cf6f1aSTakashi Iwai 
capture_pcm_open(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5332ac2e8736STakashi Iwai static int capture_pcm_open(struct hda_pcm_stream *hinfo,
5333ac2e8736STakashi Iwai 			    struct hda_codec *codec,
5334ac2e8736STakashi Iwai 			    struct snd_pcm_substream *substream)
5335ac2e8736STakashi Iwai {
5336ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN);
5337ac2e8736STakashi Iwai 	return 0;
5338ac2e8736STakashi Iwai }
5339ac2e8736STakashi Iwai 
capture_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5340ac2e8736STakashi Iwai static int capture_pcm_prepare(struct hda_pcm_stream *hinfo,
5341ac2e8736STakashi Iwai 			       struct hda_codec *codec,
5342ac2e8736STakashi Iwai 			       unsigned int stream_tag,
5343ac2e8736STakashi Iwai 			       unsigned int format,
5344ac2e8736STakashi Iwai 			       struct snd_pcm_substream *substream)
5345ac2e8736STakashi Iwai {
5346ac2e8736STakashi Iwai 	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
5347ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream,
5348ac2e8736STakashi Iwai 			      HDA_GEN_PCM_ACT_PREPARE);
5349ac2e8736STakashi Iwai 	return 0;
5350ac2e8736STakashi Iwai }
5351ac2e8736STakashi Iwai 
capture_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5352ac2e8736STakashi Iwai static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
5353ac2e8736STakashi Iwai 			       struct hda_codec *codec,
5354ac2e8736STakashi Iwai 			       struct snd_pcm_substream *substream)
5355ac2e8736STakashi Iwai {
5356ac2e8736STakashi Iwai 	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
5357ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream,
5358ac2e8736STakashi Iwai 			      HDA_GEN_PCM_ACT_CLEANUP);
5359ac2e8736STakashi Iwai 	return 0;
5360ac2e8736STakashi Iwai }
5361ac2e8736STakashi Iwai 
capture_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5362ac2e8736STakashi Iwai static int capture_pcm_close(struct hda_pcm_stream *hinfo,
5363ac2e8736STakashi Iwai 			     struct hda_codec *codec,
5364ac2e8736STakashi Iwai 			     struct snd_pcm_substream *substream)
5365ac2e8736STakashi Iwai {
5366ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE);
5367ac2e8736STakashi Iwai 	return 0;
5368ac2e8736STakashi Iwai }
5369ac2e8736STakashi Iwai 
alt_playback_pcm_open(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)537038cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
537138cf6f1aSTakashi Iwai 				 struct hda_codec *codec,
537238cf6f1aSTakashi Iwai 				 struct snd_pcm_substream *substream)
537338cf6f1aSTakashi Iwai {
537438cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
537538cf6f1aSTakashi Iwai 	int err = 0;
537638cf6f1aSTakashi Iwai 
537738cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
5378d1f15e06STakashi Iwai 	if (spec->indep_hp && !spec->indep_hp_enabled)
537938cf6f1aSTakashi Iwai 		err = -EBUSY;
538038cf6f1aSTakashi Iwai 	else
538138cf6f1aSTakashi Iwai 		spec->active_streams |= 1 << STREAM_INDEP_HP;
5382e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
5383e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_OPEN);
538438cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
538538cf6f1aSTakashi Iwai 	return err;
538638cf6f1aSTakashi Iwai }
538738cf6f1aSTakashi Iwai 
alt_playback_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)538838cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
538938cf6f1aSTakashi Iwai 				  struct hda_codec *codec,
539038cf6f1aSTakashi Iwai 				  struct snd_pcm_substream *substream)
539138cf6f1aSTakashi Iwai {
539238cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
539338cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
539438cf6f1aSTakashi Iwai 	spec->active_streams &= ~(1 << STREAM_INDEP_HP);
5395e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
5396e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLOSE);
539738cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
539838cf6f1aSTakashi Iwai 	return 0;
539938cf6f1aSTakashi Iwai }
540038cf6f1aSTakashi Iwai 
alt_playback_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5401e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
5402e6b85f3cSTakashi Iwai 				    struct hda_codec *codec,
5403e6b85f3cSTakashi Iwai 				    unsigned int stream_tag,
5404e6b85f3cSTakashi Iwai 				    unsigned int format,
5405e6b85f3cSTakashi Iwai 				    struct snd_pcm_substream *substream)
5406e6b85f3cSTakashi Iwai {
5407e6b85f3cSTakashi Iwai 	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
5408e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
5409e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_PREPARE);
5410e6b85f3cSTakashi Iwai 	return 0;
5411e6b85f3cSTakashi Iwai }
5412e6b85f3cSTakashi Iwai 
alt_playback_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5413e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
5414e6b85f3cSTakashi Iwai 				    struct hda_codec *codec,
5415e6b85f3cSTakashi Iwai 				    struct snd_pcm_substream *substream)
5416e6b85f3cSTakashi Iwai {
5417e6b85f3cSTakashi Iwai 	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
5418e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
5419e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLEANUP);
5420e6b85f3cSTakashi Iwai 	return 0;
5421e6b85f3cSTakashi Iwai }
5422e6b85f3cSTakashi Iwai 
5423352f7f91STakashi Iwai /*
5424352f7f91STakashi Iwai  * Digital out
5425352f7f91STakashi Iwai  */
dig_playback_pcm_open(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5426352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
5427352f7f91STakashi Iwai 				 struct hda_codec *codec,
5428352f7f91STakashi Iwai 				 struct snd_pcm_substream *substream)
5429352f7f91STakashi Iwai {
5430352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5431352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
5432352f7f91STakashi Iwai }
5433352f7f91STakashi Iwai 
dig_playback_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5434352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
5435352f7f91STakashi Iwai 				    struct hda_codec *codec,
5436352f7f91STakashi Iwai 				    unsigned int stream_tag,
5437352f7f91STakashi Iwai 				    unsigned int format,
5438352f7f91STakashi Iwai 				    struct snd_pcm_substream *substream)
5439352f7f91STakashi Iwai {
5440352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5441352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
5442352f7f91STakashi Iwai 					     stream_tag, format, substream);
5443352f7f91STakashi Iwai }
5444352f7f91STakashi Iwai 
dig_playback_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5445352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
5446352f7f91STakashi Iwai 				    struct hda_codec *codec,
5447352f7f91STakashi Iwai 				    struct snd_pcm_substream *substream)
5448352f7f91STakashi Iwai {
5449352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5450352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
5451352f7f91STakashi Iwai }
5452352f7f91STakashi Iwai 
dig_playback_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5453352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
5454352f7f91STakashi Iwai 				  struct hda_codec *codec,
5455352f7f91STakashi Iwai 				  struct snd_pcm_substream *substream)
5456352f7f91STakashi Iwai {
5457352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5458352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
5459352f7f91STakashi Iwai }
5460352f7f91STakashi Iwai 
5461352f7f91STakashi Iwai /*
5462352f7f91STakashi Iwai  * Analog capture
5463352f7f91STakashi Iwai  */
5464ac2e8736STakashi Iwai #define alt_capture_pcm_open	capture_pcm_open
5465ac2e8736STakashi Iwai #define alt_capture_pcm_close	capture_pcm_close
5466ac2e8736STakashi Iwai 
alt_capture_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5467352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
5468352f7f91STakashi Iwai 				   struct hda_codec *codec,
5469352f7f91STakashi Iwai 				   unsigned int stream_tag,
5470352f7f91STakashi Iwai 				   unsigned int format,
5471352f7f91STakashi Iwai 				   struct snd_pcm_substream *substream)
5472352f7f91STakashi Iwai {
5473352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5474352f7f91STakashi Iwai 
5475352f7f91STakashi Iwai 	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
547697ec558aSTakashi Iwai 				   stream_tag, 0, format);
5477ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream,
5478ac2e8736STakashi Iwai 			      HDA_GEN_PCM_ACT_PREPARE);
547997ec558aSTakashi Iwai 	return 0;
548097ec558aSTakashi Iwai }
548197ec558aSTakashi Iwai 
alt_capture_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5482352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
548397ec558aSTakashi Iwai 				   struct hda_codec *codec,
548497ec558aSTakashi Iwai 				   struct snd_pcm_substream *substream)
548597ec558aSTakashi Iwai {
5486352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
548797ec558aSTakashi Iwai 
5488352f7f91STakashi Iwai 	snd_hda_codec_cleanup_stream(codec,
5489352f7f91STakashi Iwai 				     spec->adc_nids[substream->number + 1]);
5490ac2e8736STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream,
5491ac2e8736STakashi Iwai 			      HDA_GEN_PCM_ACT_CLEANUP);
549297ec558aSTakashi Iwai 	return 0;
549397ec558aSTakashi Iwai }
549497ec558aSTakashi Iwai 
5495352f7f91STakashi Iwai /*
5496352f7f91STakashi Iwai  */
5497352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = {
5498352f7f91STakashi Iwai 	.substreams = 1,
5499352f7f91STakashi Iwai 	.channels_min = 2,
5500352f7f91STakashi Iwai 	.channels_max = 8,
5501352f7f91STakashi Iwai 	/* NID is set in build_pcms */
5502352f7f91STakashi Iwai 	.ops = {
5503352f7f91STakashi Iwai 		.open = playback_pcm_open,
550438cf6f1aSTakashi Iwai 		.close = playback_pcm_close,
5505352f7f91STakashi Iwai 		.prepare = playback_pcm_prepare,
5506352f7f91STakashi Iwai 		.cleanup = playback_pcm_cleanup
5507352f7f91STakashi Iwai 	},
5508352f7f91STakashi Iwai };
5509352f7f91STakashi Iwai 
5510352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = {
5511352f7f91STakashi Iwai 	.substreams = 1,
5512352f7f91STakashi Iwai 	.channels_min = 2,
5513352f7f91STakashi Iwai 	.channels_max = 2,
5514352f7f91STakashi Iwai 	/* NID is set in build_pcms */
5515ac2e8736STakashi Iwai 	.ops = {
5516ac2e8736STakashi Iwai 		.open = capture_pcm_open,
5517ac2e8736STakashi Iwai 		.close = capture_pcm_close,
5518ac2e8736STakashi Iwai 		.prepare = capture_pcm_prepare,
5519ac2e8736STakashi Iwai 		.cleanup = capture_pcm_cleanup
5520ac2e8736STakashi Iwai 	},
5521352f7f91STakashi Iwai };
5522352f7f91STakashi Iwai 
5523352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = {
5524352f7f91STakashi Iwai 	.substreams = 1,
5525352f7f91STakashi Iwai 	.channels_min = 2,
5526352f7f91STakashi Iwai 	.channels_max = 2,
5527352f7f91STakashi Iwai 	/* NID is set in build_pcms */
552838cf6f1aSTakashi Iwai 	.ops = {
552938cf6f1aSTakashi Iwai 		.open = alt_playback_pcm_open,
5530e6b85f3cSTakashi Iwai 		.close = alt_playback_pcm_close,
5531e6b85f3cSTakashi Iwai 		.prepare = alt_playback_pcm_prepare,
5532e6b85f3cSTakashi Iwai 		.cleanup = alt_playback_pcm_cleanup
553338cf6f1aSTakashi Iwai 	},
5534352f7f91STakashi Iwai };
5535352f7f91STakashi Iwai 
5536352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = {
5537352f7f91STakashi Iwai 	.substreams = 2, /* can be overridden */
5538352f7f91STakashi Iwai 	.channels_min = 2,
5539352f7f91STakashi Iwai 	.channels_max = 2,
5540352f7f91STakashi Iwai 	/* NID is set in build_pcms */
5541352f7f91STakashi Iwai 	.ops = {
5542ac2e8736STakashi Iwai 		.open = alt_capture_pcm_open,
5543ac2e8736STakashi Iwai 		.close = alt_capture_pcm_close,
5544352f7f91STakashi Iwai 		.prepare = alt_capture_pcm_prepare,
5545352f7f91STakashi Iwai 		.cleanup = alt_capture_pcm_cleanup
5546352f7f91STakashi Iwai 	},
5547352f7f91STakashi Iwai };
5548352f7f91STakashi Iwai 
5549352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = {
5550352f7f91STakashi Iwai 	.substreams = 1,
5551352f7f91STakashi Iwai 	.channels_min = 2,
5552352f7f91STakashi Iwai 	.channels_max = 2,
5553352f7f91STakashi Iwai 	/* NID is set in build_pcms */
5554352f7f91STakashi Iwai 	.ops = {
5555352f7f91STakashi Iwai 		.open = dig_playback_pcm_open,
5556352f7f91STakashi Iwai 		.close = dig_playback_pcm_close,
5557352f7f91STakashi Iwai 		.prepare = dig_playback_pcm_prepare,
5558352f7f91STakashi Iwai 		.cleanup = dig_playback_pcm_cleanup
5559352f7f91STakashi Iwai 	},
5560352f7f91STakashi Iwai };
5561352f7f91STakashi Iwai 
5562352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = {
5563352f7f91STakashi Iwai 	.substreams = 1,
5564352f7f91STakashi Iwai 	.channels_min = 2,
5565352f7f91STakashi Iwai 	.channels_max = 2,
5566352f7f91STakashi Iwai 	/* NID is set in build_pcms */
5567352f7f91STakashi Iwai };
5568352f7f91STakashi Iwai 
5569352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */
5570352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = {
5571352f7f91STakashi Iwai 	.substreams = 0,
5572352f7f91STakashi Iwai 	.channels_min = 0,
5573352f7f91STakashi Iwai 	.channels_max = 0,
5574352f7f91STakashi Iwai };
5575352f7f91STakashi Iwai 
5576352f7f91STakashi Iwai /*
5577352f7f91STakashi Iwai  * dynamic changing ADC PCM streams
5578352f7f91STakashi Iwai  */
dyn_adc_pcm_resetup(struct hda_codec * codec,int cur)5579352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
55801da177e4SLinus Torvalds {
5581352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5582352f7f91STakashi Iwai 	hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
55831da177e4SLinus Torvalds 
5584352f7f91STakashi Iwai 	if (spec->cur_adc && spec->cur_adc != new_adc) {
5585352f7f91STakashi Iwai 		/* stream is running, let's swap the current ADC */
5586352f7f91STakashi Iwai 		__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
5587352f7f91STakashi Iwai 		spec->cur_adc = new_adc;
5588352f7f91STakashi Iwai 		snd_hda_codec_setup_stream(codec, new_adc,
5589352f7f91STakashi Iwai 					   spec->cur_adc_stream_tag, 0,
5590352f7f91STakashi Iwai 					   spec->cur_adc_format);
5591352f7f91STakashi Iwai 		return true;
5592352f7f91STakashi Iwai 	}
5593352f7f91STakashi Iwai 	return false;
5594352f7f91STakashi Iwai }
5595352f7f91STakashi Iwai 
5596352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */
dyn_adc_capture_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5597352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
5598352f7f91STakashi Iwai 				       struct hda_codec *codec,
5599352f7f91STakashi Iwai 				       unsigned int stream_tag,
5600352f7f91STakashi Iwai 				       unsigned int format,
5601352f7f91STakashi Iwai 				       struct snd_pcm_substream *substream)
5602352f7f91STakashi Iwai {
5603352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5604352f7f91STakashi Iwai 	spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
5605352f7f91STakashi Iwai 	spec->cur_adc_stream_tag = stream_tag;
5606352f7f91STakashi Iwai 	spec->cur_adc_format = format;
5607352f7f91STakashi Iwai 	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
56084f29efc0STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_PREPARE);
56091da177e4SLinus Torvalds 	return 0;
56101da177e4SLinus Torvalds }
56111da177e4SLinus Torvalds 
dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5612352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
5613352f7f91STakashi Iwai 				       struct hda_codec *codec,
5614352f7f91STakashi Iwai 				       struct snd_pcm_substream *substream)
5615352f7f91STakashi Iwai {
5616352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5617352f7f91STakashi Iwai 	snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
5618352f7f91STakashi Iwai 	spec->cur_adc = 0;
56194f29efc0STakashi Iwai 	call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLEANUP);
5620352f7f91STakashi Iwai 	return 0;
5621352f7f91STakashi Iwai }
5622352f7f91STakashi Iwai 
5623352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
5624352f7f91STakashi Iwai 	.substreams = 1,
5625352f7f91STakashi Iwai 	.channels_min = 2,
5626352f7f91STakashi Iwai 	.channels_max = 2,
5627352f7f91STakashi Iwai 	.nid = 0, /* fill later */
5628352f7f91STakashi Iwai 	.ops = {
5629352f7f91STakashi Iwai 		.prepare = dyn_adc_capture_pcm_prepare,
5630352f7f91STakashi Iwai 		.cleanup = dyn_adc_capture_pcm_cleanup
5631352f7f91STakashi Iwai 	},
5632352f7f91STakashi Iwai };
5633352f7f91STakashi Iwai 
fill_pcm_stream_name(char * str,size_t len,const char * sfx,const char * chip_name)5634f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
5635f873e536STakashi Iwai 				 const char *chip_name)
5636f873e536STakashi Iwai {
5637f873e536STakashi Iwai 	char *p;
5638f873e536STakashi Iwai 
5639f873e536STakashi Iwai 	if (*str)
5640f873e536STakashi Iwai 		return;
564175b1a8f9SJoe Perches 	strscpy(str, chip_name, len);
5642f873e536STakashi Iwai 
5643f873e536STakashi Iwai 	/* drop non-alnum chars after a space */
5644f873e536STakashi Iwai 	for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) {
5645f873e536STakashi Iwai 		if (!isalnum(p[1])) {
5646f873e536STakashi Iwai 			*p = 0;
5647f873e536STakashi Iwai 			break;
5648f873e536STakashi Iwai 		}
5649f873e536STakashi Iwai 	}
5650f873e536STakashi Iwai 	strlcat(str, sfx, len);
5651f873e536STakashi Iwai }
5652f873e536STakashi Iwai 
5653fb83b635STakashi Iwai /* copy PCM stream info from @default_str, and override non-NULL entries
5654fb83b635STakashi Iwai  * from @spec_str and @nid
5655fb83b635STakashi Iwai  */
setup_pcm_stream(struct hda_pcm_stream * str,const struct hda_pcm_stream * default_str,const struct hda_pcm_stream * spec_str,hda_nid_t nid)5656fb83b635STakashi Iwai static void setup_pcm_stream(struct hda_pcm_stream *str,
5657fb83b635STakashi Iwai 			     const struct hda_pcm_stream *default_str,
5658fb83b635STakashi Iwai 			     const struct hda_pcm_stream *spec_str,
5659fb83b635STakashi Iwai 			     hda_nid_t nid)
5660fb83b635STakashi Iwai {
5661fb83b635STakashi Iwai 	*str = *default_str;
5662fb83b635STakashi Iwai 	if (nid)
5663fb83b635STakashi Iwai 		str->nid = nid;
5664fb83b635STakashi Iwai 	if (spec_str) {
5665fb83b635STakashi Iwai 		if (spec_str->substreams)
5666fb83b635STakashi Iwai 			str->substreams = spec_str->substreams;
5667fb83b635STakashi Iwai 		if (spec_str->channels_min)
5668fb83b635STakashi Iwai 			str->channels_min = spec_str->channels_min;
5669fb83b635STakashi Iwai 		if (spec_str->channels_max)
5670fb83b635STakashi Iwai 			str->channels_max = spec_str->channels_max;
5671fb83b635STakashi Iwai 		if (spec_str->rates)
5672fb83b635STakashi Iwai 			str->rates = spec_str->rates;
5673fb83b635STakashi Iwai 		if (spec_str->formats)
5674fb83b635STakashi Iwai 			str->formats = spec_str->formats;
5675fb83b635STakashi Iwai 		if (spec_str->maxbps)
5676fb83b635STakashi Iwai 			str->maxbps = spec_str->maxbps;
5677fb83b635STakashi Iwai 	}
5678fb83b635STakashi Iwai }
5679fb83b635STakashi Iwai 
5680dda42bd0STakashi Iwai /**
5681dda42bd0STakashi Iwai  * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
5682dda42bd0STakashi Iwai  * @codec: the HDA codec
5683dda42bd0STakashi Iwai  *
5684dda42bd0STakashi Iwai  * Pass this to build_pcms patch_ops.
5685dda42bd0STakashi Iwai  */
snd_hda_gen_build_pcms(struct hda_codec * codec)5686352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec)
5687352f7f91STakashi Iwai {
5688352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5689bbbc7e85STakashi Iwai 	struct hda_pcm *info;
5690352f7f91STakashi Iwai 	bool have_multi_adcs;
5691352f7f91STakashi Iwai 
5692352f7f91STakashi Iwai 	if (spec->no_analog)
5693352f7f91STakashi Iwai 		goto skip_analog;
5694352f7f91STakashi Iwai 
5695f873e536STakashi Iwai 	fill_pcm_stream_name(spec->stream_name_analog,
5696f873e536STakashi Iwai 			     sizeof(spec->stream_name_analog),
56977639a06cSTakashi Iwai 			     " Analog", codec->core.chip_name);
5698bbbc7e85STakashi Iwai 	info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
5699bbbc7e85STakashi Iwai 	if (!info)
5700bbbc7e85STakashi Iwai 		return -ENOMEM;
5701bbbc7e85STakashi Iwai 	spec->pcm_rec[0] = info;
5702352f7f91STakashi Iwai 
5703352f7f91STakashi Iwai 	if (spec->multiout.num_dacs > 0) {
5704fb83b635STakashi Iwai 		setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
5705fb83b635STakashi Iwai 				 &pcm_analog_playback,
5706fb83b635STakashi Iwai 				 spec->stream_analog_playback,
5707fb83b635STakashi Iwai 				 spec->multiout.dac_nids[0]);
5708352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
5709352f7f91STakashi Iwai 			spec->multiout.max_channels;
5710352f7f91STakashi Iwai 		if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
5711352f7f91STakashi Iwai 		    spec->autocfg.line_outs == 2)
5712352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
5713352f7f91STakashi Iwai 				snd_pcm_2_1_chmaps;
5714352f7f91STakashi Iwai 	}
5715352f7f91STakashi Iwai 	if (spec->num_adc_nids) {
5716fb83b635STakashi Iwai 		setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
5717fb83b635STakashi Iwai 				 (spec->dyn_adc_switch ?
5718fb83b635STakashi Iwai 				  &dyn_adc_pcm_analog_capture : &pcm_analog_capture),
5719fb83b635STakashi Iwai 				 spec->stream_analog_capture,
5720fb83b635STakashi Iwai 				 spec->adc_nids[0]);
5721352f7f91STakashi Iwai 	}
5722352f7f91STakashi Iwai 
5723352f7f91STakashi Iwai  skip_analog:
5724352f7f91STakashi Iwai 	/* SPDIF for stream index #1 */
5725352f7f91STakashi Iwai 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
5726f873e536STakashi Iwai 		fill_pcm_stream_name(spec->stream_name_digital,
5727352f7f91STakashi Iwai 				     sizeof(spec->stream_name_digital),
57287639a06cSTakashi Iwai 				     " Digital", codec->core.chip_name);
5729bbbc7e85STakashi Iwai 		info = snd_hda_codec_pcm_new(codec, "%s",
5730bbbc7e85STakashi Iwai 					     spec->stream_name_digital);
5731bbbc7e85STakashi Iwai 		if (!info)
5732bbbc7e85STakashi Iwai 			return -ENOMEM;
57339ab0cb30STakashi Iwai 		codec->follower_dig_outs = spec->multiout.follower_dig_outs;
5734bbbc7e85STakashi Iwai 		spec->pcm_rec[1] = info;
5735352f7f91STakashi Iwai 		if (spec->dig_out_type)
5736352f7f91STakashi Iwai 			info->pcm_type = spec->dig_out_type;
5737352f7f91STakashi Iwai 		else
5738352f7f91STakashi Iwai 			info->pcm_type = HDA_PCM_TYPE_SPDIF;
5739fb83b635STakashi Iwai 		if (spec->multiout.dig_out_nid)
5740fb83b635STakashi Iwai 			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
5741fb83b635STakashi Iwai 					 &pcm_digital_playback,
5742fb83b635STakashi Iwai 					 spec->stream_digital_playback,
5743fb83b635STakashi Iwai 					 spec->multiout.dig_out_nid);
5744fb83b635STakashi Iwai 		if (spec->dig_in_nid)
5745fb83b635STakashi Iwai 			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
5746fb83b635STakashi Iwai 					 &pcm_digital_capture,
5747fb83b635STakashi Iwai 					 spec->stream_digital_capture,
5748fb83b635STakashi Iwai 					 spec->dig_in_nid);
5749352f7f91STakashi Iwai 	}
5750352f7f91STakashi Iwai 
5751352f7f91STakashi Iwai 	if (spec->no_analog)
5752352f7f91STakashi Iwai 		return 0;
5753352f7f91STakashi Iwai 
5754352f7f91STakashi Iwai 	/* If the use of more than one ADC is requested for the current
5755352f7f91STakashi Iwai 	 * model, configure a second analog capture-only PCM.
5756352f7f91STakashi Iwai 	 */
5757352f7f91STakashi Iwai 	have_multi_adcs = (spec->num_adc_nids > 1) &&
5758352f7f91STakashi Iwai 		!spec->dyn_adc_switch && !spec->auto_mic;
5759352f7f91STakashi Iwai 	/* Additional Analaog capture for index #2 */
5760352f7f91STakashi Iwai 	if (spec->alt_dac_nid || have_multi_adcs) {
5761a607148fSTakashi Iwai 		fill_pcm_stream_name(spec->stream_name_alt_analog,
5762a607148fSTakashi Iwai 				     sizeof(spec->stream_name_alt_analog),
57637639a06cSTakashi Iwai 			     " Alt Analog", codec->core.chip_name);
5764bbbc7e85STakashi Iwai 		info = snd_hda_codec_pcm_new(codec, "%s",
5765bbbc7e85STakashi Iwai 					     spec->stream_name_alt_analog);
5766bbbc7e85STakashi Iwai 		if (!info)
5767bbbc7e85STakashi Iwai 			return -ENOMEM;
5768bbbc7e85STakashi Iwai 		spec->pcm_rec[2] = info;
5769fb83b635STakashi Iwai 		if (spec->alt_dac_nid)
5770fb83b635STakashi Iwai 			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
5771fb83b635STakashi Iwai 					 &pcm_analog_alt_playback,
5772fb83b635STakashi Iwai 					 spec->stream_analog_alt_playback,
5773fb83b635STakashi Iwai 					 spec->alt_dac_nid);
5774fb83b635STakashi Iwai 		else
5775fb83b635STakashi Iwai 			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
5776fb83b635STakashi Iwai 					 &pcm_null_stream, NULL, 0);
5777352f7f91STakashi Iwai 		if (have_multi_adcs) {
5778fb83b635STakashi Iwai 			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
5779fb83b635STakashi Iwai 					 &pcm_analog_alt_capture,
5780fb83b635STakashi Iwai 					 spec->stream_analog_alt_capture,
5781fb83b635STakashi Iwai 					 spec->adc_nids[1]);
5782352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
5783352f7f91STakashi Iwai 				spec->num_adc_nids - 1;
5784352f7f91STakashi Iwai 		} else {
5785fb83b635STakashi Iwai 			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
5786fb83b635STakashi Iwai 					 &pcm_null_stream, NULL, 0);
5787352f7f91STakashi Iwai 		}
57881da177e4SLinus Torvalds 	}
57891da177e4SLinus Torvalds 
57901da177e4SLinus Torvalds 	return 0;
57911da177e4SLinus Torvalds }
57922698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms);
5793352f7f91STakashi Iwai 
5794352f7f91STakashi Iwai 
5795352f7f91STakashi Iwai /*
5796352f7f91STakashi Iwai  * Standard auto-parser initializations
5797352f7f91STakashi Iwai  */
5798352f7f91STakashi Iwai 
5799d4156930STakashi Iwai /* configure the given path as a proper output */
set_output_and_unmute(struct hda_codec * codec,int path_idx)58002c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx)
5801352f7f91STakashi Iwai {
5802352f7f91STakashi Iwai 	struct nid_path *path;
5803d4156930STakashi Iwai 	hda_nid_t pin;
5804352f7f91STakashi Iwai 
5805196c1766STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
5806d4156930STakashi Iwai 	if (!path || !path->depth)
5807352f7f91STakashi Iwai 		return;
5808d4156930STakashi Iwai 	pin = path->path[path->depth - 1];
58092c12c30dSTakashi Iwai 	restore_pin_ctl(codec, pin);
581065033cc8STakashi Iwai 	snd_hda_activate_path(codec, path, path->active,
581165033cc8STakashi Iwai 			      aamix_default(codec->spec));
5812e1284af7STakashi Iwai 	set_pin_eapd(codec, pin, path->active);
5813352f7f91STakashi Iwai }
5814352f7f91STakashi Iwai 
5815352f7f91STakashi Iwai /* initialize primary output paths */
init_multi_out(struct hda_codec * codec)5816352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec)
5817352f7f91STakashi Iwai {
5818352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5819352f7f91STakashi Iwai 	int i;
5820352f7f91STakashi Iwai 
5821d4156930STakashi Iwai 	for (i = 0; i < spec->autocfg.line_outs; i++)
58222c12c30dSTakashi Iwai 		set_output_and_unmute(codec, spec->out_paths[i]);
5823352f7f91STakashi Iwai }
5824352f7f91STakashi Iwai 
5825db23fd19STakashi Iwai 
__init_extra_out(struct hda_codec * codec,int num_outs,int * paths)58262c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths)
5827352f7f91STakashi Iwai {
5828352f7f91STakashi Iwai 	int i;
5829352f7f91STakashi Iwai 
5830d4156930STakashi Iwai 	for (i = 0; i < num_outs; i++)
58312c12c30dSTakashi Iwai 		set_output_and_unmute(codec, paths[i]);
5832352f7f91STakashi Iwai }
5833db23fd19STakashi Iwai 
5834db23fd19STakashi Iwai /* initialize hp and speaker paths */
init_extra_out(struct hda_codec * codec)5835db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec)
5836db23fd19STakashi Iwai {
5837db23fd19STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5838db23fd19STakashi Iwai 
5839db23fd19STakashi Iwai 	if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT)
58402c12c30dSTakashi Iwai 		__init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths);
5841db23fd19STakashi Iwai 	if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT)
5842db23fd19STakashi Iwai 		__init_extra_out(codec, spec->autocfg.speaker_outs,
58432c12c30dSTakashi Iwai 				 spec->speaker_paths);
5844352f7f91STakashi Iwai }
5845352f7f91STakashi Iwai 
5846352f7f91STakashi Iwai /* initialize multi-io paths */
init_multi_io(struct hda_codec * codec)5847352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec)
5848352f7f91STakashi Iwai {
5849352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5850352f7f91STakashi Iwai 	int i;
5851352f7f91STakashi Iwai 
5852352f7f91STakashi Iwai 	for (i = 0; i < spec->multi_ios; i++) {
5853352f7f91STakashi Iwai 		hda_nid_t pin = spec->multi_io[i].pin;
5854352f7f91STakashi Iwai 		struct nid_path *path;
5855196c1766STakashi Iwai 		path = get_multiio_path(codec, i);
5856352f7f91STakashi Iwai 		if (!path)
5857352f7f91STakashi Iwai 			continue;
5858352f7f91STakashi Iwai 		if (!spec->multi_io[i].ctl_in)
5859352f7f91STakashi Iwai 			spec->multi_io[i].ctl_in =
58602c12c30dSTakashi Iwai 				snd_hda_codec_get_pin_target(codec, pin);
586165033cc8STakashi Iwai 		snd_hda_activate_path(codec, path, path->active,
586265033cc8STakashi Iwai 				      aamix_default(spec));
5863352f7f91STakashi Iwai 	}
5864352f7f91STakashi Iwai }
5865352f7f91STakashi Iwai 
init_aamix_paths(struct hda_codec * codec)58664f7f67fbSTakashi Iwai static void init_aamix_paths(struct hda_codec *codec)
58674f7f67fbSTakashi Iwai {
58684f7f67fbSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
58694f7f67fbSTakashi Iwai 
58704f7f67fbSTakashi Iwai 	if (!spec->have_aamix_ctl)
58714f7f67fbSTakashi Iwai 		return;
5872e7fdd527STakashi Iwai 	if (!has_aamix_out_paths(spec))
5873e7fdd527STakashi Iwai 		return;
58744f7f67fbSTakashi Iwai 	update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0],
58754f7f67fbSTakashi Iwai 			   spec->aamix_out_paths[0],
58764f7f67fbSTakashi Iwai 			   spec->autocfg.line_out_type);
58774f7f67fbSTakashi Iwai 	update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0],
58784f7f67fbSTakashi Iwai 			   spec->aamix_out_paths[1],
58794f7f67fbSTakashi Iwai 			   AUTO_PIN_HP_OUT);
58804f7f67fbSTakashi Iwai 	update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0],
58814f7f67fbSTakashi Iwai 			   spec->aamix_out_paths[2],
58824f7f67fbSTakashi Iwai 			   AUTO_PIN_SPEAKER_OUT);
58834f7f67fbSTakashi Iwai }
58844f7f67fbSTakashi Iwai 
5885352f7f91STakashi Iwai /* set up input pins and loopback paths */
init_analog_input(struct hda_codec * codec)5886352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec)
5887352f7f91STakashi Iwai {
5888352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5889352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
5890352f7f91STakashi Iwai 	int i;
5891352f7f91STakashi Iwai 
5892352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
5893352f7f91STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
5894352f7f91STakashi Iwai 		if (is_input_pin(codec, nid))
58952c12c30dSTakashi Iwai 			restore_pin_ctl(codec, nid);
5896352f7f91STakashi Iwai 
5897352f7f91STakashi Iwai 		/* init loopback inputs */
5898352f7f91STakashi Iwai 		if (spec->mixer_nid) {
58993e367f15STakashi Iwai 			resume_path_from_idx(codec, spec->loopback_paths[i]);
59003e367f15STakashi Iwai 			resume_path_from_idx(codec, spec->loopback_merge_path);
5901352f7f91STakashi Iwai 		}
5902352f7f91STakashi Iwai 	}
5903352f7f91STakashi Iwai }
5904352f7f91STakashi Iwai 
5905352f7f91STakashi Iwai /* initialize ADC paths */
init_input_src(struct hda_codec * codec)5906352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec)
5907352f7f91STakashi Iwai {
5908352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5909352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
5910352f7f91STakashi Iwai 	struct nid_path *path;
5911352f7f91STakashi Iwai 	int i, c, nums;
5912352f7f91STakashi Iwai 
5913352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
5914352f7f91STakashi Iwai 		nums = 1;
5915352f7f91STakashi Iwai 	else
5916352f7f91STakashi Iwai 		nums = spec->num_adc_nids;
5917352f7f91STakashi Iwai 
5918352f7f91STakashi Iwai 	for (c = 0; c < nums; c++) {
5919352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
5920c697b716STakashi Iwai 			path = get_input_path(codec, c, i);
5921352f7f91STakashi Iwai 			if (path) {
5922352f7f91STakashi Iwai 				bool active = path->active;
5923352f7f91STakashi Iwai 				if (i == spec->cur_mux[c])
5924352f7f91STakashi Iwai 					active = true;
5925352f7f91STakashi Iwai 				snd_hda_activate_path(codec, path, active, false);
5926352f7f91STakashi Iwai 			}
5927352f7f91STakashi Iwai 		}
5928967303daSTakashi Iwai 		if (spec->hp_mic)
5929967303daSTakashi Iwai 			update_hp_mic(codec, c, true);
5930352f7f91STakashi Iwai 	}
5931352f7f91STakashi Iwai 
5932352f7f91STakashi Iwai 	if (spec->cap_sync_hook)
59337fe30711STakashi Iwai 		spec->cap_sync_hook(codec, NULL, NULL);
5934352f7f91STakashi Iwai }
5935352f7f91STakashi Iwai 
5936352f7f91STakashi Iwai /* set right pin controls for digital I/O */
init_digital(struct hda_codec * codec)5937352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec)
5938352f7f91STakashi Iwai {
5939352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5940352f7f91STakashi Iwai 	int i;
5941352f7f91STakashi Iwai 	hda_nid_t pin;
5942352f7f91STakashi Iwai 
5943d4156930STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++)
59442c12c30dSTakashi Iwai 		set_output_and_unmute(codec, spec->digout_paths[i]);
5945352f7f91STakashi Iwai 	pin = spec->autocfg.dig_in_pin;
59462430d7b7STakashi Iwai 	if (pin) {
59472c12c30dSTakashi Iwai 		restore_pin_ctl(codec, pin);
59483e367f15STakashi Iwai 		resume_path_from_idx(codec, spec->digin_path);
59492430d7b7STakashi Iwai 	}
5950352f7f91STakashi Iwai }
5951352f7f91STakashi Iwai 
5952973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave
5953973e4972STakashi Iwai  * invalid unsol tags by some reason
5954973e4972STakashi Iwai  */
clear_unsol_on_unused_pins(struct hda_codec * codec)5955973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec)
5956973e4972STakashi Iwai {
5957a9c2dfc8STakashi Iwai 	const struct hda_pincfg *pin;
5958973e4972STakashi Iwai 	int i;
5959973e4972STakashi Iwai 
5960a9c2dfc8STakashi Iwai 	snd_array_for_each(&codec->init_pins, i, pin) {
5961973e4972STakashi Iwai 		hda_nid_t nid = pin->nid;
5962973e4972STakashi Iwai 		if (is_jack_detectable(codec, nid) &&
5963973e4972STakashi Iwai 		    !snd_hda_jack_tbl_get(codec, nid))
5964401caff7STakashi Iwai 			snd_hda_codec_write_cache(codec, nid, 0,
5965973e4972STakashi Iwai 					AC_VERB_SET_UNSOLICITED_ENABLE, 0);
5966973e4972STakashi Iwai 	}
5967973e4972STakashi Iwai }
5968973e4972STakashi Iwai 
5969dda42bd0STakashi Iwai /**
5970dda42bd0STakashi Iwai  * snd_hda_gen_init - initialize the generic spec
5971dda42bd0STakashi Iwai  * @codec: the HDA codec
5972dda42bd0STakashi Iwai  *
5973dda42bd0STakashi Iwai  * This can be put as patch_ops init function.
59745187ac16STakashi Iwai  */
snd_hda_gen_init(struct hda_codec * codec)5975352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec)
5976352f7f91STakashi Iwai {
5977352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
5978352f7f91STakashi Iwai 
5979352f7f91STakashi Iwai 	if (spec->init_hook)
5980352f7f91STakashi Iwai 		spec->init_hook(codec);
5981352f7f91STakashi Iwai 
598289781d08STakashi Iwai 	if (!spec->skip_verbs)
5983352f7f91STakashi Iwai 		snd_hda_apply_verbs(codec);
5984352f7f91STakashi Iwai 
5985352f7f91STakashi Iwai 	init_multi_out(codec);
5986352f7f91STakashi Iwai 	init_extra_out(codec);
5987352f7f91STakashi Iwai 	init_multi_io(codec);
59884f7f67fbSTakashi Iwai 	init_aamix_paths(codec);
5989352f7f91STakashi Iwai 	init_analog_input(codec);
5990352f7f91STakashi Iwai 	init_input_src(codec);
5991352f7f91STakashi Iwai 	init_digital(codec);
5992352f7f91STakashi Iwai 
5993973e4972STakashi Iwai 	clear_unsol_on_unused_pins(codec);
5994973e4972STakashi Iwai 
5995e6feb5d0STakashi Iwai 	sync_all_pin_power_ctls(codec);
5996e6feb5d0STakashi Iwai 
5997352f7f91STakashi Iwai 	/* call init functions of standard auto-mute helpers */
5998a5cc2509STakashi Iwai 	update_automute_all(codec);
5999352f7f91STakashi Iwai 
60001a462be5STakashi Iwai 	snd_hda_regmap_sync(codec);
60013bbcd274STakashi Iwai 
6002352f7f91STakashi Iwai 	if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
6003352f7f91STakashi Iwai 		snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
6004352f7f91STakashi Iwai 
6005352f7f91STakashi Iwai 	hda_call_check_power_status(codec, 0x01);
6006352f7f91STakashi Iwai 	return 0;
6007352f7f91STakashi Iwai }
60082698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_init);
6009fce52a3bSTakashi Iwai 
6010dda42bd0STakashi Iwai /**
6011dda42bd0STakashi Iwai  * snd_hda_gen_free - free the generic spec
6012dda42bd0STakashi Iwai  * @codec: the HDA codec
6013dda42bd0STakashi Iwai  *
6014dda42bd0STakashi Iwai  * This can be put as patch_ops free function.
60155187ac16STakashi Iwai  */
snd_hda_gen_free(struct hda_codec * codec)6016fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec)
6017fce52a3bSTakashi Iwai {
60188a02c0ccSTakashi Iwai 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
6019fce52a3bSTakashi Iwai 	snd_hda_gen_spec_free(codec->spec);
6020fce52a3bSTakashi Iwai 	kfree(codec->spec);
6021fce52a3bSTakashi Iwai 	codec->spec = NULL;
6022fce52a3bSTakashi Iwai }
60232698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_free);
6024fce52a3bSTakashi Iwai 
6025fce52a3bSTakashi Iwai #ifdef CONFIG_PM
6026dda42bd0STakashi Iwai /**
6027dda42bd0STakashi Iwai  * snd_hda_gen_check_power_status - check the loopback power save state
6028dda42bd0STakashi Iwai  * @codec: the HDA codec
6029dda42bd0STakashi Iwai  * @nid: NID to inspect
6030dda42bd0STakashi Iwai  *
6031dda42bd0STakashi Iwai  * This can be put as patch_ops check_power_status function.
60325187ac16STakashi Iwai  */
snd_hda_gen_check_power_status(struct hda_codec * codec,hda_nid_t nid)6033fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
6034fce52a3bSTakashi Iwai {
6035fce52a3bSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
6036fce52a3bSTakashi Iwai 	return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
6037fce52a3bSTakashi Iwai }
60382698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status);
6039fce52a3bSTakashi Iwai #endif
6040352f7f91STakashi Iwai 
6041352f7f91STakashi Iwai 
6042352f7f91STakashi Iwai /*
6043352f7f91STakashi Iwai  * the generic codec support
6044352f7f91STakashi Iwai  */
60451da177e4SLinus Torvalds 
6046352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = {
6047352f7f91STakashi Iwai 	.build_controls = snd_hda_gen_build_controls,
6048352f7f91STakashi Iwai 	.build_pcms = snd_hda_gen_build_pcms,
6049352f7f91STakashi Iwai 	.init = snd_hda_gen_init,
6050fce52a3bSTakashi Iwai 	.free = snd_hda_gen_free,
6051352f7f91STakashi Iwai 	.unsol_event = snd_hda_jack_unsol_event,
605283012a7cSTakashi Iwai #ifdef CONFIG_PM
6053fce52a3bSTakashi Iwai 	.check_power_status = snd_hda_gen_check_power_status,
6054cb53c626STakashi Iwai #endif
60551da177e4SLinus Torvalds };
60561da177e4SLinus Torvalds 
6057d8a766a1STakashi Iwai /*
6058dda42bd0STakashi Iwai  * snd_hda_parse_generic_codec - Generic codec parser
6059dda42bd0STakashi Iwai  * @codec: the HDA codec
6060dda42bd0STakashi Iwai  */
snd_hda_parse_generic_codec(struct hda_codec * codec)6061d8a766a1STakashi Iwai static int snd_hda_parse_generic_codec(struct hda_codec *codec)
60621da177e4SLinus Torvalds {
6063352f7f91STakashi Iwai 	struct hda_gen_spec *spec;
60641da177e4SLinus Torvalds 	int err;
60651da177e4SLinus Torvalds 
6066e560d8d8STakashi Iwai 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
6067352f7f91STakashi Iwai 	if (!spec)
60681da177e4SLinus Torvalds 		return -ENOMEM;
6069352f7f91STakashi Iwai 	snd_hda_gen_spec_init(spec);
60701da177e4SLinus Torvalds 	codec->spec = spec;
60711da177e4SLinus Torvalds 
60729eb413e5STakashi Iwai 	err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
60739eb413e5STakashi Iwai 	if (err < 0)
6074cfef67f0SWenwen Wang 		goto error;
60759eb413e5STakashi Iwai 
60769eb413e5STakashi Iwai 	err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
6077352f7f91STakashi Iwai 	if (err < 0)
60781da177e4SLinus Torvalds 		goto error;
60791da177e4SLinus Torvalds 
60801da177e4SLinus Torvalds 	codec->patch_ops = generic_patch_ops;
60811da177e4SLinus Torvalds 	return 0;
60821da177e4SLinus Torvalds 
60831da177e4SLinus Torvalds error:
6084fce52a3bSTakashi Iwai 	snd_hda_gen_free(codec);
60851da177e4SLinus Torvalds 	return err;
60861da177e4SLinus Torvalds }
6087d8a766a1STakashi Iwai 
6088b9a94a9cSTakashi Iwai static const struct hda_device_id snd_hda_id_generic[] = {
6089b9a94a9cSTakashi Iwai 	HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec),
6090d8a766a1STakashi Iwai 	{} /* terminator */
6091d8a766a1STakashi Iwai };
6092b9a94a9cSTakashi Iwai MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic);
6093d8a766a1STakashi Iwai 
6094d8a766a1STakashi Iwai static struct hda_codec_driver generic_driver = {
6095b9a94a9cSTakashi Iwai 	.id = snd_hda_id_generic,
6096d8a766a1STakashi Iwai };
6097d8a766a1STakashi Iwai 
6098d8a766a1STakashi Iwai module_hda_codec_driver(generic_driver);
6099b21bdd0dSTakashi Iwai 
6100b21bdd0dSTakashi Iwai MODULE_LICENSE("GPL");
6101b21bdd0dSTakashi Iwai MODULE_DESCRIPTION("Generic HD-audio codec parser");
6102