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 */ 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 * 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 * 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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? */ 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? */ 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 */ 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 */ 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? */ 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) */ 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 */ 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 */ 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 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 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 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 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 */ 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 */ 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 */ 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) */ 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 */ 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 */ 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 * 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 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]; 10015f6af005STakashi Iwai int len; 10025f6af005STakashi Iwai 10035f6af005STakashi Iwai len = snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 10045f6af005STakashi Iwai if (snd_BUG_ON(len >= sizeof(name))) 10055f6af005STakashi 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 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[] */ 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 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 */ 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 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 */ 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 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 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 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? */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 1386*1c801e7fSTakashi Iwai if (!spec->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; 1398*1c801e7fSTakashi Iwai } else if (spec->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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 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 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 */ 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 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 */ 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 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 */ 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 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 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); 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 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 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 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 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 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 * 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 */ 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 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 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 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 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 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() */ 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 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%...) */ 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 */ 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 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 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 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 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 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 */ 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 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 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 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 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 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 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 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 */ 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 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 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 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 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 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 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; 3949c9e272f9STakashi Iwai cdev->flags = LED_CORE_SUSPENDRESUME; 395015509b63STakashi Iwai 3951549f8ffcSTakashi Iwai err = led_classdev_register(&codec->core.dev, cdev); 3952549f8ffcSTakashi Iwai if (err < 0) 3953549f8ffcSTakashi Iwai return err; 3954549f8ffcSTakashi Iwai spec->led_cdevs[idx] = cdev; 3955549f8ffcSTakashi Iwai return 0; 395615509b63STakashi Iwai } 395715509b63STakashi Iwai 395815509b63STakashi Iwai /** 39593531ba21SPierre-Louis Bossart * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED 396015509b63STakashi Iwai * @codec: the HDA codec 396115509b63STakashi Iwai * @callback: the callback for LED classdev brightness_set_blocking 396215509b63STakashi Iwai */ 396315509b63STakashi Iwai int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec, 396415509b63STakashi Iwai int (*callback)(struct led_classdev *, 396515509b63STakashi Iwai enum led_brightness)) 396615509b63STakashi Iwai { 396715509b63STakashi Iwai struct hda_gen_spec *spec = codec->spec; 396815509b63STakashi Iwai int err; 396915509b63STakashi Iwai 397015509b63STakashi Iwai if (callback) { 397115509b63STakashi Iwai err = create_mute_led_cdev(codec, callback, false); 397215509b63STakashi Iwai if (err) { 397315509b63STakashi Iwai codec_warn(codec, "failed to create a mute LED cdev\n"); 397415509b63STakashi Iwai return err; 397515509b63STakashi Iwai } 397615509b63STakashi Iwai } 397715509b63STakashi Iwai 397815509b63STakashi Iwai if (spec->vmaster_mute.hook) 397915509b63STakashi Iwai codec_err(codec, "vmaster hook already present before cdev!\n"); 398015509b63STakashi Iwai 3981e65bf997SJaroslav Kysela spec->vmaster_mute_led = 1; 398215509b63STakashi Iwai return 0; 398315509b63STakashi Iwai } 398415509b63STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev); 398515509b63STakashi Iwai 3986b3802783STakashi Iwai /** 39873531ba21SPierre-Louis Bossart * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED 39887cdf8c49STakashi Iwai * @codec: the HDA codec 39897cdf8c49STakashi Iwai * @callback: the callback for LED classdev brightness_set_blocking 39907cdf8c49STakashi Iwai * 39917cdf8c49STakashi Iwai * Called from the codec drivers for offering the mic mute LED controls. 39927cdf8c49STakashi Iwai * This creates a LED classdev and sets up the cap_sync_hook that is called at 39937cdf8c49STakashi Iwai * each time when the capture mixer switch changes. 39947cdf8c49STakashi Iwai * 39957cdf8c49STakashi Iwai * When NULL is passed to @callback, no classdev is created but only the 39967cdf8c49STakashi Iwai * LED-trigger is set up. 39977cdf8c49STakashi Iwai * 39987cdf8c49STakashi Iwai * Returns 0 or a negative error. 39997cdf8c49STakashi Iwai */ 40007cdf8c49STakashi Iwai int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, 40017cdf8c49STakashi Iwai int (*callback)(struct led_classdev *, 40027cdf8c49STakashi Iwai enum led_brightness)) 40037cdf8c49STakashi Iwai { 4004e65bf997SJaroslav Kysela struct hda_gen_spec *spec = codec->spec; 40057cdf8c49STakashi Iwai int err; 40067cdf8c49STakashi Iwai 40077cdf8c49STakashi Iwai if (callback) { 400815509b63STakashi Iwai err = create_mute_led_cdev(codec, callback, true); 40097cdf8c49STakashi Iwai if (err) { 40107cdf8c49STakashi Iwai codec_warn(codec, "failed to create a mic-mute LED cdev\n"); 40117cdf8c49STakashi Iwai return err; 40127cdf8c49STakashi Iwai } 40137cdf8c49STakashi Iwai } 40147cdf8c49STakashi Iwai 4015e65bf997SJaroslav Kysela spec->mic_mute_led = 1; 4016e65bf997SJaroslav Kysela return 0; 40177cdf8c49STakashi Iwai } 40187cdf8c49STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev); 40197cdf8c49STakashi Iwai #endif /* CONFIG_SND_HDA_GENERIC_LEDS */ 40207cdf8c49STakashi Iwai 4021f567b788STakashi Iwai /* 4022352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 4023352f7f91STakashi Iwai */ 4024352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 4025352f7f91STakashi Iwai { 4026352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 40270c8c0f56STakashi Iwai struct nid_path *path; 4028352f7f91STakashi Iwai int i, nums; 40292c12c30dSTakashi Iwai hda_nid_t dig_nid, pin; 4030352f7f91STakashi Iwai 40319ab0cb30STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a follower */ 4032352f7f91STakashi Iwai nums = 0; 4033352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 40342c12c30dSTakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 4035352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 4036352f7f91STakashi Iwai if (!dig_nid) 4037352f7f91STakashi Iwai continue; 40383ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, 0); 40390c8c0f56STakashi Iwai if (!path) 4040352f7f91STakashi Iwai continue; 40414e76a883STakashi Iwai print_nid_path(codec, "digout", path); 4042e1284af7STakashi Iwai path->active = true; 40436b275b14STakashi Iwai path->pin_fixed = true; /* no jack detection */ 4044196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 40452c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_OUT, false); 4046352f7f91STakashi Iwai if (!nums) { 4047352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 4048352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 4049352f7f91STakashi Iwai } else { 40509ab0cb30STakashi Iwai spec->multiout.follower_dig_outs = spec->follower_dig_outs; 40519ab0cb30STakashi Iwai if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1) 4052352f7f91STakashi Iwai break; 40539ab0cb30STakashi Iwai spec->follower_dig_outs[nums - 1] = dig_nid; 4054352f7f91STakashi Iwai } 4055352f7f91STakashi Iwai nums++; 4056352f7f91STakashi Iwai } 4057352f7f91STakashi Iwai 4058352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 40592c12c30dSTakashi Iwai pin = spec->autocfg.dig_in_pin; 40607639a06cSTakashi Iwai for_each_hda_codec_node(dig_nid, codec) { 4061352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 4062352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 4063352f7f91STakashi Iwai continue; 4064352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 4065352f7f91STakashi Iwai continue; 40662c12c30dSTakashi Iwai path = snd_hda_add_new_path(codec, pin, dig_nid, 0); 4067352f7f91STakashi Iwai if (path) { 40684e76a883STakashi Iwai print_nid_path(codec, "digin", path); 4069352f7f91STakashi Iwai path->active = true; 40706b275b14STakashi Iwai path->pin_fixed = true; /* no jack */ 4071352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 40722430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 40732c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_IN, false); 4074352f7f91STakashi Iwai break; 4075352f7f91STakashi Iwai } 4076352f7f91STakashi Iwai } 4077352f7f91STakashi Iwai } 4078352f7f91STakashi Iwai } 4079352f7f91STakashi Iwai 40801da177e4SLinus Torvalds 40811da177e4SLinus Torvalds /* 4082352f7f91STakashi Iwai * input MUX handling 40831da177e4SLinus Torvalds */ 40841da177e4SLinus Torvalds 4085352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 4086352f7f91STakashi Iwai 4087352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 4088352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 4089352f7f91STakashi Iwai unsigned int idx) 4090352f7f91STakashi Iwai { 4091352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4092352f7f91STakashi Iwai const struct hda_input_mux *imux; 409355196fffSTakashi Iwai struct nid_path *old_path, *path; 4094352f7f91STakashi Iwai 4095352f7f91STakashi Iwai imux = &spec->input_mux; 4096352f7f91STakashi Iwai if (!imux->num_items) 40971da177e4SLinus Torvalds return 0; 40981da177e4SLinus Torvalds 4099352f7f91STakashi Iwai if (idx >= imux->num_items) 4100352f7f91STakashi Iwai idx = imux->num_items - 1; 4101352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 4102352f7f91STakashi Iwai return 0; 4103352f7f91STakashi Iwai 410455196fffSTakashi Iwai old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); 410555196fffSTakashi Iwai if (!old_path) 4106352f7f91STakashi Iwai return 0; 410755196fffSTakashi Iwai if (old_path->active) 410855196fffSTakashi Iwai snd_hda_activate_path(codec, old_path, false, false); 4109352f7f91STakashi Iwai 4110352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 4111352f7f91STakashi Iwai 4112967303daSTakashi Iwai if (spec->hp_mic) 4113967303daSTakashi Iwai update_hp_mic(codec, adc_idx, false); 4114352f7f91STakashi Iwai 4115352f7f91STakashi Iwai if (spec->dyn_adc_switch) 4116352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 4117352f7f91STakashi Iwai 4118c697b716STakashi Iwai path = get_input_path(codec, adc_idx, idx); 4119352f7f91STakashi Iwai if (!path) 4120352f7f91STakashi Iwai return 0; 4121352f7f91STakashi Iwai if (path->active) 4122352f7f91STakashi Iwai return 0; 4123352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 4124352f7f91STakashi Iwai if (spec->cap_sync_hook) 41257fe30711STakashi Iwai spec->cap_sync_hook(codec, NULL, NULL); 412655196fffSTakashi Iwai path_power_down_sync(codec, old_path); 41271da177e4SLinus Torvalds return 1; 41281da177e4SLinus Torvalds } 41291da177e4SLinus Torvalds 4130e6feb5d0STakashi Iwai /* power up/down widgets in the all paths that match with the given NID 4131e6feb5d0STakashi Iwai * as terminals (either start- or endpoint) 4132e6feb5d0STakashi Iwai * 4133e6feb5d0STakashi Iwai * returns the last changed NID, or zero if unchanged. 4134e6feb5d0STakashi Iwai */ 4135e6feb5d0STakashi Iwai static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid, 4136e6feb5d0STakashi Iwai int pin_state, int stream_state) 4137e6feb5d0STakashi Iwai { 4138e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4139e6feb5d0STakashi Iwai hda_nid_t last, changed = 0; 4140e6feb5d0STakashi Iwai struct nid_path *path; 4141e6feb5d0STakashi Iwai int n; 4142e6feb5d0STakashi Iwai 4143a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, n, path) { 414481e43960SBob Copeland if (!path->depth) 414581e43960SBob Copeland continue; 4146e6feb5d0STakashi Iwai if (path->path[0] == nid || 4147e6feb5d0STakashi Iwai path->path[path->depth - 1] == nid) { 4148e6feb5d0STakashi Iwai bool pin_old = path->pin_enabled; 4149e6feb5d0STakashi Iwai bool stream_old = path->stream_enabled; 4150e6feb5d0STakashi Iwai 4151e6feb5d0STakashi Iwai if (pin_state >= 0) 4152e6feb5d0STakashi Iwai path->pin_enabled = pin_state; 4153e6feb5d0STakashi Iwai if (stream_state >= 0) 4154e6feb5d0STakashi Iwai path->stream_enabled = stream_state; 41556b275b14STakashi Iwai if ((!path->pin_fixed && path->pin_enabled != pin_old) 41566b275b14STakashi Iwai || path->stream_enabled != stream_old) { 4157e6feb5d0STakashi Iwai last = path_power_update(codec, path, true); 4158e6feb5d0STakashi Iwai if (last) 4159e6feb5d0STakashi Iwai changed = last; 4160e6feb5d0STakashi Iwai } 4161e6feb5d0STakashi Iwai } 4162e6feb5d0STakashi Iwai } 4163e6feb5d0STakashi Iwai return changed; 4164e6feb5d0STakashi Iwai } 4165e6feb5d0STakashi Iwai 4166d5ac0100STakashi Iwai /* check the jack status for power control */ 4167d5ac0100STakashi Iwai static bool detect_pin_state(struct hda_codec *codec, hda_nid_t pin) 4168d5ac0100STakashi Iwai { 4169d5ac0100STakashi Iwai if (!is_jack_detectable(codec, pin)) 4170d5ac0100STakashi Iwai return true; 4171d5ac0100STakashi Iwai return snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT; 4172d5ac0100STakashi Iwai } 4173d5ac0100STakashi Iwai 4174e6feb5d0STakashi Iwai /* power up/down the paths of the given pin according to the jack state; 4175e6feb5d0STakashi Iwai * power = 0/1 : only power up/down if it matches with the jack state, 4176e6feb5d0STakashi Iwai * < 0 : force power up/down to follow the jack sate 4177e6feb5d0STakashi Iwai * 4178e6feb5d0STakashi Iwai * returns the last changed NID, or zero if unchanged. 4179e6feb5d0STakashi Iwai */ 4180e6feb5d0STakashi Iwai static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin, 4181e6feb5d0STakashi Iwai int power) 4182e6feb5d0STakashi Iwai { 4183e6feb5d0STakashi Iwai bool on; 4184e6feb5d0STakashi Iwai 4185967b1307STakashi Iwai if (!codec->power_save_node) 4186e6feb5d0STakashi Iwai return 0; 4187e6feb5d0STakashi Iwai 4188d5ac0100STakashi Iwai on = detect_pin_state(codec, pin); 4189d5ac0100STakashi Iwai 4190e6feb5d0STakashi Iwai if (power >= 0 && on != power) 4191e6feb5d0STakashi Iwai return 0; 4192e6feb5d0STakashi Iwai return set_path_power(codec, pin, on, -1); 4193e6feb5d0STakashi Iwai } 4194e6feb5d0STakashi Iwai 4195e6feb5d0STakashi Iwai static void pin_power_callback(struct hda_codec *codec, 4196e6feb5d0STakashi Iwai struct hda_jack_callback *jack, 4197e6feb5d0STakashi Iwai bool on) 4198e6feb5d0STakashi Iwai { 41992ebab40eSTakashi Iwai if (jack && jack->nid) 4200e6feb5d0STakashi Iwai sync_power_state_change(codec, 42012ebab40eSTakashi Iwai set_pin_power_jack(codec, jack->nid, on)); 4202e6feb5d0STakashi Iwai } 4203e6feb5d0STakashi Iwai 4204e6feb5d0STakashi Iwai /* callback only doing power up -- called at first */ 4205e6feb5d0STakashi Iwai static void pin_power_up_callback(struct hda_codec *codec, 4206e6feb5d0STakashi Iwai struct hda_jack_callback *jack) 4207e6feb5d0STakashi Iwai { 4208e6feb5d0STakashi Iwai pin_power_callback(codec, jack, true); 4209e6feb5d0STakashi Iwai } 4210e6feb5d0STakashi Iwai 4211e6feb5d0STakashi Iwai /* callback only doing power down -- called at last */ 4212e6feb5d0STakashi Iwai static void pin_power_down_callback(struct hda_codec *codec, 4213e6feb5d0STakashi Iwai struct hda_jack_callback *jack) 4214e6feb5d0STakashi Iwai { 4215e6feb5d0STakashi Iwai pin_power_callback(codec, jack, false); 4216e6feb5d0STakashi Iwai } 4217e6feb5d0STakashi Iwai 4218e6feb5d0STakashi Iwai /* set up the power up/down callbacks */ 4219e6feb5d0STakashi Iwai static void add_pin_power_ctls(struct hda_codec *codec, int num_pins, 4220e6feb5d0STakashi Iwai const hda_nid_t *pins, bool on) 4221e6feb5d0STakashi Iwai { 4222e6feb5d0STakashi Iwai int i; 4223e6feb5d0STakashi Iwai hda_jack_callback_fn cb = 4224e6feb5d0STakashi Iwai on ? pin_power_up_callback : pin_power_down_callback; 4225e6feb5d0STakashi Iwai 4226e6feb5d0STakashi Iwai for (i = 0; i < num_pins && pins[i]; i++) { 4227e6feb5d0STakashi Iwai if (is_jack_detectable(codec, pins[i])) 4228e6feb5d0STakashi Iwai snd_hda_jack_detect_enable_callback(codec, pins[i], cb); 4229e6feb5d0STakashi Iwai else 4230e6feb5d0STakashi Iwai set_path_power(codec, pins[i], true, -1); 4231e6feb5d0STakashi Iwai } 4232e6feb5d0STakashi Iwai } 4233e6feb5d0STakashi Iwai 4234e6feb5d0STakashi Iwai /* enabled power callback to each available I/O pin with jack detections; 4235e6feb5d0STakashi Iwai * the digital I/O pins are excluded because of the unreliable detectsion 4236e6feb5d0STakashi Iwai */ 4237e6feb5d0STakashi Iwai static void add_all_pin_power_ctls(struct hda_codec *codec, bool on) 4238e6feb5d0STakashi Iwai { 4239e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4240e6feb5d0STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4241e6feb5d0STakashi Iwai int i; 4242e6feb5d0STakashi Iwai 4243967b1307STakashi Iwai if (!codec->power_save_node) 4244e6feb5d0STakashi Iwai return; 4245e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on); 4246e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 4247e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on); 4248e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 4249e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on); 4250e6feb5d0STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) 4251e6feb5d0STakashi Iwai add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on); 4252e6feb5d0STakashi Iwai } 4253e6feb5d0STakashi Iwai 4254e6feb5d0STakashi Iwai /* sync path power up/down with the jack states of given pins */ 4255e6feb5d0STakashi Iwai static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins, 4256e6feb5d0STakashi Iwai const hda_nid_t *pins) 4257e6feb5d0STakashi Iwai { 4258e6feb5d0STakashi Iwai int i; 4259e6feb5d0STakashi Iwai 4260e6feb5d0STakashi Iwai for (i = 0; i < num_pins && pins[i]; i++) 4261e6feb5d0STakashi Iwai if (is_jack_detectable(codec, pins[i])) 4262e6feb5d0STakashi Iwai set_pin_power_jack(codec, pins[i], -1); 4263e6feb5d0STakashi Iwai } 4264e6feb5d0STakashi Iwai 4265e6feb5d0STakashi Iwai /* sync path power up/down with pins; called at init and resume */ 4266e6feb5d0STakashi Iwai static void sync_all_pin_power_ctls(struct hda_codec *codec) 4267e6feb5d0STakashi Iwai { 4268e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4269e6feb5d0STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4270e6feb5d0STakashi Iwai int i; 4271e6feb5d0STakashi Iwai 4272967b1307STakashi Iwai if (!codec->power_save_node) 4273e6feb5d0STakashi Iwai return; 4274e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins); 4275e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 4276e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins); 4277e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 4278e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins); 4279e6feb5d0STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) 4280e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin); 4281e6feb5d0STakashi Iwai } 42821da177e4SLinus Torvalds 42835ccf835cSTakashi Iwai /* add fake paths if not present yet */ 42845ccf835cSTakashi Iwai static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid, 42855ccf835cSTakashi Iwai int num_pins, const hda_nid_t *pins) 42865ccf835cSTakashi Iwai { 42875ccf835cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 42885ccf835cSTakashi Iwai struct nid_path *path; 42895ccf835cSTakashi Iwai int i; 42905ccf835cSTakashi Iwai 42915ccf835cSTakashi Iwai for (i = 0; i < num_pins; i++) { 42925ccf835cSTakashi Iwai if (!pins[i]) 42935ccf835cSTakashi Iwai break; 42945ccf835cSTakashi Iwai if (get_nid_path(codec, nid, pins[i], 0)) 42955ccf835cSTakashi Iwai continue; 42965ccf835cSTakashi Iwai path = snd_array_new(&spec->paths); 42975ccf835cSTakashi Iwai if (!path) 42985ccf835cSTakashi Iwai return -ENOMEM; 42995ccf835cSTakashi Iwai memset(path, 0, sizeof(*path)); 43005ccf835cSTakashi Iwai path->depth = 2; 43015ccf835cSTakashi Iwai path->path[0] = nid; 43025ccf835cSTakashi Iwai path->path[1] = pins[i]; 43035ccf835cSTakashi Iwai path->active = true; 43045ccf835cSTakashi Iwai } 43055ccf835cSTakashi Iwai return 0; 43065ccf835cSTakashi Iwai } 43075ccf835cSTakashi Iwai 43085ccf835cSTakashi Iwai /* create fake paths to all outputs from beep */ 43095ccf835cSTakashi Iwai static int add_fake_beep_paths(struct hda_codec *codec) 43105ccf835cSTakashi Iwai { 43115ccf835cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 43125ccf835cSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 43135ccf835cSTakashi Iwai hda_nid_t nid = spec->beep_nid; 43145ccf835cSTakashi Iwai int err; 43155ccf835cSTakashi Iwai 4316967b1307STakashi Iwai if (!codec->power_save_node || !nid) 43175ccf835cSTakashi Iwai return 0; 43185ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins); 43195ccf835cSTakashi Iwai if (err < 0) 43205ccf835cSTakashi Iwai return err; 43215ccf835cSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 43225ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins); 43235ccf835cSTakashi Iwai if (err < 0) 43245ccf835cSTakashi Iwai return err; 43255ccf835cSTakashi Iwai } 43265ccf835cSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 43275ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->speaker_outs, 43285ccf835cSTakashi Iwai cfg->speaker_pins); 43295ccf835cSTakashi Iwai if (err < 0) 43305ccf835cSTakashi Iwai return err; 43315ccf835cSTakashi Iwai } 43325ccf835cSTakashi Iwai return 0; 43335ccf835cSTakashi Iwai } 43345ccf835cSTakashi Iwai 43355ccf835cSTakashi Iwai /* power up/down beep widget and its output paths */ 43365ccf835cSTakashi Iwai static void beep_power_hook(struct hda_beep *beep, bool on) 43375ccf835cSTakashi Iwai { 43385ccf835cSTakashi Iwai set_path_power(beep->codec, beep->nid, -1, on); 43395ccf835cSTakashi Iwai } 43405ccf835cSTakashi Iwai 43416b275b14STakashi Iwai /** 43426b275b14STakashi Iwai * snd_hda_gen_fix_pin_power - Fix the power of the given pin widget to D0 43436b275b14STakashi Iwai * @codec: the HDA codec 43446b275b14STakashi Iwai * @pin: NID of pin to fix 43456b275b14STakashi Iwai */ 43466b275b14STakashi Iwai int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin) 43476b275b14STakashi Iwai { 43486b275b14STakashi Iwai struct hda_gen_spec *spec = codec->spec; 43496b275b14STakashi Iwai struct nid_path *path; 43506b275b14STakashi Iwai 43516b275b14STakashi Iwai path = snd_array_new(&spec->paths); 43526b275b14STakashi Iwai if (!path) 43536b275b14STakashi Iwai return -ENOMEM; 43546b275b14STakashi Iwai memset(path, 0, sizeof(*path)); 43556b275b14STakashi Iwai path->depth = 1; 43566b275b14STakashi Iwai path->path[0] = pin; 43576b275b14STakashi Iwai path->active = true; 43586b275b14STakashi Iwai path->pin_fixed = true; 43596b275b14STakashi Iwai path->stream_enabled = true; 43606b275b14STakashi Iwai return 0; 43616b275b14STakashi Iwai } 43626b275b14STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_fix_pin_power); 43636b275b14STakashi Iwai 43641da177e4SLinus Torvalds /* 4365352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 43661da177e4SLinus Torvalds */ 4367352f7f91STakashi Iwai 4368352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 4369caf3c043SMichał Mirosław static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins) 43701da177e4SLinus Torvalds { 437160ea8ca2STakashi Iwai int i; 437260ea8ca2STakashi Iwai bool present = false; 43731da177e4SLinus Torvalds 4374352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 4375352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 4376352f7f91STakashi Iwai if (!nid) 4377352f7f91STakashi Iwai break; 43780b4df931STakashi Iwai /* don't detect pins retasked as inputs */ 43790b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) 43800b4df931STakashi Iwai continue; 438160ea8ca2STakashi Iwai if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT) 438260ea8ca2STakashi Iwai present = true; 43831da177e4SLinus Torvalds } 4384352f7f91STakashi Iwai return present; 43851da177e4SLinus Torvalds } 43861da177e4SLinus Torvalds 4387352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 4388caf3c043SMichał Mirosław static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins, 4389e80c60f3STakashi Iwai int *paths, bool mute) 43901da177e4SLinus Torvalds { 4391352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4392352f7f91STakashi Iwai int i; 43931da177e4SLinus Torvalds 4394352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 4395352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 4396967303daSTakashi Iwai unsigned int val, oldval; 4397352f7f91STakashi Iwai if (!nid) 4398352f7f91STakashi Iwai break; 43997eebffd3STakashi Iwai 4400e6feb5d0STakashi Iwai oldval = snd_hda_codec_get_pin_target(codec, nid); 4401e6feb5d0STakashi Iwai if (oldval & PIN_IN) 4402e6feb5d0STakashi Iwai continue; /* no mute for inputs */ 4403e6feb5d0STakashi Iwai 44047eebffd3STakashi Iwai if (spec->auto_mute_via_amp) { 4405e80c60f3STakashi Iwai struct nid_path *path; 4406e80c60f3STakashi Iwai hda_nid_t mute_nid; 4407e80c60f3STakashi Iwai 4408e80c60f3STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]); 4409e80c60f3STakashi Iwai if (!path) 4410e80c60f3STakashi Iwai continue; 4411e80c60f3STakashi Iwai mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]); 4412e80c60f3STakashi Iwai if (!mute_nid) 4413e80c60f3STakashi Iwai continue; 44147eebffd3STakashi Iwai if (mute) 4415e80c60f3STakashi Iwai spec->mute_bits |= (1ULL << mute_nid); 44167eebffd3STakashi Iwai else 4417e80c60f3STakashi Iwai spec->mute_bits &= ~(1ULL << mute_nid); 44187eebffd3STakashi Iwai continue; 4419e6feb5d0STakashi Iwai } else { 4420352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 4421352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 4422352f7f91STakashi Iwai */ 44232c12c30dSTakashi Iwai if (spec->keep_vref_in_automute) 4424967303daSTakashi Iwai val = oldval & ~PIN_HP; 44252c12c30dSTakashi Iwai else 4426352f7f91STakashi Iwai val = 0; 44272c12c30dSTakashi Iwai if (!mute) 4428967303daSTakashi Iwai val |= oldval; 4429e6feb5d0STakashi Iwai /* here we call update_pin_ctl() so that the pinctl is 4430e6feb5d0STakashi Iwai * changed without changing the pinctl target value; 4431e6feb5d0STakashi Iwai * the original target value will be still referred at 4432e6feb5d0STakashi Iwai * the init / resume again 44332c12c30dSTakashi Iwai */ 44342c12c30dSTakashi Iwai update_pin_ctl(codec, nid, val); 4435e6feb5d0STakashi Iwai } 4436e6feb5d0STakashi Iwai 4437d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 4438967b1307STakashi Iwai if (codec->power_save_node) { 4439e6feb5d0STakashi Iwai bool on = !mute; 4440e6feb5d0STakashi Iwai if (on) 4441d5ac0100STakashi Iwai on = detect_pin_state(codec, nid); 4442e6feb5d0STakashi Iwai set_path_power(codec, nid, on, -1); 4443e6feb5d0STakashi Iwai } 4444352f7f91STakashi Iwai } 4445352f7f91STakashi Iwai } 44461da177e4SLinus Torvalds 4447dda42bd0STakashi Iwai /** 4448dda42bd0STakashi Iwai * snd_hda_gen_update_outputs - Toggle outputs muting 4449dda42bd0STakashi Iwai * @codec: the HDA codec 4450dda42bd0STakashi Iwai * 4451dda42bd0STakashi Iwai * Update the mute status of all outputs based on the current jack states. 4452dda42bd0STakashi Iwai */ 44535d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 4454352f7f91STakashi Iwai { 4455352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4456e80c60f3STakashi Iwai int *paths; 4457352f7f91STakashi Iwai int on; 4458352f7f91STakashi Iwai 4459352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 4460352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 4461352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 4462352f7f91STakashi Iwai */ 4463e80c60f3STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 4464e80c60f3STakashi Iwai paths = spec->out_paths; 4465e80c60f3STakashi Iwai else 4466e80c60f3STakashi Iwai paths = spec->hp_paths; 4467352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 4468e80c60f3STakashi Iwai spec->autocfg.hp_pins, paths, spec->master_mute); 4469352f7f91STakashi Iwai 4470352f7f91STakashi Iwai if (!spec->automute_speaker) 4471352f7f91STakashi Iwai on = 0; 4472352f7f91STakashi Iwai else 4473352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 4474352f7f91STakashi Iwai on |= spec->master_mute; 447547b9ddb8STakashi Iwai spec->speaker_muted = on; 4476e80c60f3STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 4477e80c60f3STakashi Iwai paths = spec->out_paths; 4478e80c60f3STakashi Iwai else 4479e80c60f3STakashi Iwai paths = spec->speaker_paths; 4480352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 4481e80c60f3STakashi Iwai spec->autocfg.speaker_pins, paths, on); 4482352f7f91STakashi Iwai 4483352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 4484352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 4485352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 4486352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 4487352f7f91STakashi Iwai return; 4488352f7f91STakashi Iwai if (!spec->automute_lo) 4489352f7f91STakashi Iwai on = 0; 4490352f7f91STakashi Iwai else 4491352f7f91STakashi Iwai on = spec->hp_jack_present; 4492352f7f91STakashi Iwai on |= spec->master_mute; 449347b9ddb8STakashi Iwai spec->line_out_muted = on; 4494e80c60f3STakashi Iwai paths = spec->out_paths; 4495352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 4496e80c60f3STakashi Iwai spec->autocfg.line_out_pins, paths, on); 4497352f7f91STakashi Iwai } 44982698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs); 4499352f7f91STakashi Iwai 4500352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 4501352f7f91STakashi Iwai { 4502352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4503352f7f91STakashi Iwai if (spec->automute_hook) 4504352f7f91STakashi Iwai spec->automute_hook(codec); 4505352f7f91STakashi Iwai else 45065d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 45077eebffd3STakashi Iwai 45089ab0cb30STakashi Iwai /* sync the whole vmaster followers to reflect the new auto-mute status */ 45097eebffd3STakashi Iwai if (spec->auto_mute_via_amp && !codec->bus->shutdown) 45107eebffd3STakashi Iwai snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); 4511352f7f91STakashi Iwai } 4512352f7f91STakashi Iwai 4513dda42bd0STakashi Iwai /** 4514dda42bd0STakashi Iwai * snd_hda_gen_hp_automute - standard HP-automute helper 4515dda42bd0STakashi Iwai * @codec: the HDA codec 4516dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole 4517dda42bd0STakashi Iwai */ 45181a4f69d5STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, 45191a4f69d5STakashi Iwai struct hda_jack_callback *jack) 4520352f7f91STakashi Iwai { 4521352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 452292603c59STakashi Iwai hda_nid_t *pins = spec->autocfg.hp_pins; 452392603c59STakashi Iwai int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins); 4524352f7f91STakashi Iwai 452592603c59STakashi Iwai /* No detection for the first HP jack during indep-HP mode */ 452692603c59STakashi Iwai if (spec->indep_hp_enabled) { 452792603c59STakashi Iwai pins++; 452892603c59STakashi Iwai num_pins--; 452992603c59STakashi Iwai } 453092603c59STakashi Iwai 453192603c59STakashi Iwai spec->hp_jack_present = detect_jacks(codec, num_pins, pins); 4532352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 4533352f7f91STakashi Iwai return; 4534352f7f91STakashi Iwai call_update_outputs(codec); 4535352f7f91STakashi Iwai } 45362698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute); 4537352f7f91STakashi Iwai 4538dda42bd0STakashi Iwai /** 4539dda42bd0STakashi Iwai * snd_hda_gen_line_automute - standard line-out-automute helper 4540dda42bd0STakashi Iwai * @codec: the HDA codec 4541dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole 4542dda42bd0STakashi Iwai */ 45431a4f69d5STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, 45441a4f69d5STakashi Iwai struct hda_jack_callback *jack) 4545352f7f91STakashi Iwai { 4546352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4547352f7f91STakashi Iwai 4548352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 4549352f7f91STakashi Iwai return; 4550352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 4551352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 4552352f7f91STakashi Iwai return; 4553352f7f91STakashi Iwai 4554352f7f91STakashi Iwai spec->line_jack_present = 4555352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 4556352f7f91STakashi Iwai spec->autocfg.line_out_pins); 4557352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 4558352f7f91STakashi Iwai return; 4559352f7f91STakashi Iwai call_update_outputs(codec); 4560352f7f91STakashi Iwai } 45612698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute); 4562352f7f91STakashi Iwai 4563dda42bd0STakashi Iwai /** 4564dda42bd0STakashi Iwai * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper 4565dda42bd0STakashi Iwai * @codec: the HDA codec 4566dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole 4567dda42bd0STakashi Iwai */ 45681a4f69d5STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, 45691a4f69d5STakashi Iwai struct hda_jack_callback *jack) 4570352f7f91STakashi Iwai { 4571352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4572352f7f91STakashi Iwai int i; 4573352f7f91STakashi Iwai 4574352f7f91STakashi Iwai if (!spec->auto_mic) 4575352f7f91STakashi Iwai return; 4576352f7f91STakashi Iwai 4577352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 45780b4df931STakashi Iwai hda_nid_t pin = spec->am_entry[i].pin; 45790b4df931STakashi Iwai /* don't detect pins retasked as outputs */ 45800b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) 45810b4df931STakashi Iwai continue; 458260ea8ca2STakashi Iwai if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) { 4583352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 4584352f7f91STakashi Iwai return; 4585352f7f91STakashi Iwai } 4586352f7f91STakashi Iwai } 4587352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 45881da177e4SLinus Torvalds } 45892698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch); 45901da177e4SLinus Torvalds 459177afe0e9STakashi Iwai /* call appropriate hooks */ 45921a4f69d5STakashi Iwai static void call_hp_automute(struct hda_codec *codec, 45931a4f69d5STakashi Iwai struct hda_jack_callback *jack) 459477afe0e9STakashi Iwai { 459577afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 459677afe0e9STakashi Iwai if (spec->hp_automute_hook) 459777afe0e9STakashi Iwai spec->hp_automute_hook(codec, jack); 459877afe0e9STakashi Iwai else 459977afe0e9STakashi Iwai snd_hda_gen_hp_automute(codec, jack); 460077afe0e9STakashi Iwai } 460177afe0e9STakashi Iwai 460277afe0e9STakashi Iwai static void call_line_automute(struct hda_codec *codec, 46031a4f69d5STakashi Iwai struct hda_jack_callback *jack) 460477afe0e9STakashi Iwai { 460577afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 460677afe0e9STakashi Iwai if (spec->line_automute_hook) 460777afe0e9STakashi Iwai spec->line_automute_hook(codec, jack); 460877afe0e9STakashi Iwai else 460977afe0e9STakashi Iwai snd_hda_gen_line_automute(codec, jack); 461077afe0e9STakashi Iwai } 461177afe0e9STakashi Iwai 461277afe0e9STakashi Iwai static void call_mic_autoswitch(struct hda_codec *codec, 46131a4f69d5STakashi Iwai struct hda_jack_callback *jack) 461477afe0e9STakashi Iwai { 461577afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 461677afe0e9STakashi Iwai if (spec->mic_autoswitch_hook) 461777afe0e9STakashi Iwai spec->mic_autoswitch_hook(codec, jack); 461877afe0e9STakashi Iwai else 461977afe0e9STakashi Iwai snd_hda_gen_mic_autoswitch(codec, jack); 462077afe0e9STakashi Iwai } 462177afe0e9STakashi Iwai 4622963afde9STakashi Iwai /* update jack retasking */ 4623963afde9STakashi Iwai static void update_automute_all(struct hda_codec *codec) 4624963afde9STakashi Iwai { 4625963afde9STakashi Iwai call_hp_automute(codec, NULL); 4626963afde9STakashi Iwai call_line_automute(codec, NULL); 4627963afde9STakashi Iwai call_mic_autoswitch(codec, NULL); 4628963afde9STakashi Iwai } 4629963afde9STakashi Iwai 46301da177e4SLinus Torvalds /* 4631352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 46321da177e4SLinus Torvalds */ 4633352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 4634352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 4635352f7f91STakashi Iwai { 4636352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4637352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4638352f7f91STakashi Iwai static const char * const texts3[] = { 4639352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 46401da177e4SLinus Torvalds }; 46411da177e4SLinus Torvalds 4642352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 4643352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 4644352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 4645352f7f91STakashi Iwai } 4646352f7f91STakashi Iwai 4647352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 4648352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4649352f7f91STakashi Iwai { 4650352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4651352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4652352f7f91STakashi Iwai unsigned int val = 0; 4653352f7f91STakashi Iwai if (spec->automute_speaker) 4654352f7f91STakashi Iwai val++; 4655352f7f91STakashi Iwai if (spec->automute_lo) 4656352f7f91STakashi Iwai val++; 4657352f7f91STakashi Iwai 4658352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 4659352f7f91STakashi Iwai return 0; 4660352f7f91STakashi Iwai } 4661352f7f91STakashi Iwai 4662352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 4663352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4664352f7f91STakashi Iwai { 4665352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4666352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4667352f7f91STakashi Iwai 4668352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 4669352f7f91STakashi Iwai case 0: 4670352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 4671352f7f91STakashi Iwai return 0; 4672352f7f91STakashi Iwai spec->automute_speaker = 0; 4673352f7f91STakashi Iwai spec->automute_lo = 0; 4674352f7f91STakashi Iwai break; 4675352f7f91STakashi Iwai case 1: 4676352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 4677352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 4678352f7f91STakashi Iwai return 0; 4679352f7f91STakashi Iwai spec->automute_speaker = 1; 4680352f7f91STakashi Iwai spec->automute_lo = 0; 4681352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 4682352f7f91STakashi Iwai if (spec->automute_lo) 4683352f7f91STakashi Iwai return 0; 4684352f7f91STakashi Iwai spec->automute_lo = 1; 4685352f7f91STakashi Iwai } else 4686352f7f91STakashi Iwai return -EINVAL; 4687352f7f91STakashi Iwai break; 4688352f7f91STakashi Iwai case 2: 4689352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 4690352f7f91STakashi Iwai return -EINVAL; 4691352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 4692352f7f91STakashi Iwai return 0; 4693352f7f91STakashi Iwai spec->automute_speaker = 1; 4694352f7f91STakashi Iwai spec->automute_lo = 1; 4695352f7f91STakashi Iwai break; 4696352f7f91STakashi Iwai default: 4697352f7f91STakashi Iwai return -EINVAL; 4698352f7f91STakashi Iwai } 4699352f7f91STakashi Iwai call_update_outputs(codec); 4700352f7f91STakashi Iwai return 1; 4701352f7f91STakashi Iwai } 4702352f7f91STakashi Iwai 4703352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 4704352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4705352f7f91STakashi Iwai .name = "Auto-Mute Mode", 4706352f7f91STakashi Iwai .info = automute_mode_info, 4707352f7f91STakashi Iwai .get = automute_mode_get, 4708352f7f91STakashi Iwai .put = automute_mode_put, 4709352f7f91STakashi Iwai }; 4710352f7f91STakashi Iwai 4711352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 4712352f7f91STakashi Iwai { 4713352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4714352f7f91STakashi Iwai 471512c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 4716352f7f91STakashi Iwai return -ENOMEM; 4717352f7f91STakashi Iwai return 0; 4718352f7f91STakashi Iwai } 4719352f7f91STakashi Iwai 4720352f7f91STakashi Iwai /* 4721352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 4722352f7f91STakashi Iwai * Set up appropriately if really supported 4723352f7f91STakashi Iwai */ 4724352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 4725352f7f91STakashi Iwai { 4726352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4727352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4728352f7f91STakashi Iwai int present = 0; 4729352f7f91STakashi Iwai int i, err; 4730352f7f91STakashi Iwai 4731f72706beSTakashi Iwai if (spec->suppress_auto_mute) 4732f72706beSTakashi Iwai return 0; 4733f72706beSTakashi Iwai 4734352f7f91STakashi Iwai if (cfg->hp_pins[0]) 4735352f7f91STakashi Iwai present++; 4736352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 4737352f7f91STakashi Iwai present++; 4738352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 4739352f7f91STakashi Iwai present++; 4740352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 4741352f7f91STakashi Iwai return 0; 4742352f7f91STakashi Iwai 4743352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 4744352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 4745352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 4746352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 4747352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 4748352f7f91STakashi Iwai } 4749352f7f91STakashi Iwai 4750352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 4751352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 4752352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 4753352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 4754352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 4755352f7f91STakashi Iwai } 4756352f7f91STakashi Iwai 4757352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 4758352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 4759352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4760352f7f91STakashi Iwai continue; 47614e76a883STakashi Iwai codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid); 476262f949bfSTakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 476377afe0e9STakashi Iwai call_hp_automute); 4764352f7f91STakashi Iwai spec->detect_hp = 1; 4765352f7f91STakashi Iwai } 4766352f7f91STakashi Iwai 4767352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 4768352f7f91STakashi Iwai if (cfg->speaker_outs) 4769352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 4770352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 4771352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4772352f7f91STakashi Iwai continue; 47734e76a883STakashi Iwai codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid); 4774352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 477577afe0e9STakashi Iwai call_line_automute); 4776352f7f91STakashi Iwai spec->detect_lo = 1; 4777352f7f91STakashi Iwai } 4778352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 4779352f7f91STakashi Iwai } 4780352f7f91STakashi Iwai 4781352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 4782352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 4783352f7f91STakashi Iwai 4784352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 4785352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 4786352f7f91STakashi Iwai 4787352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 4788352f7f91STakashi Iwai /* create a control for automute mode */ 4789352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 4790352f7f91STakashi Iwai if (err < 0) 4791352f7f91STakashi Iwai return err; 4792352f7f91STakashi Iwai } 4793352f7f91STakashi Iwai return 0; 4794352f7f91STakashi Iwai } 4795352f7f91STakashi Iwai 4796352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 4797352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 4798352f7f91STakashi Iwai { 4799352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4800352f7f91STakashi Iwai const struct hda_input_mux *imux; 4801352f7f91STakashi Iwai int i; 4802352f7f91STakashi Iwai 4803352f7f91STakashi Iwai imux = &spec->input_mux; 4804352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 4805352f7f91STakashi Iwai spec->am_entry[i].idx = 4806352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 4807352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 4808352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 4809352f7f91STakashi Iwai return false; /* no corresponding imux */ 4810352f7f91STakashi Iwai } 4811352f7f91STakashi Iwai 4812352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 4813352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 4814352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 4815352f7f91STakashi Iwai spec->am_entry[i].pin, 481677afe0e9STakashi Iwai call_mic_autoswitch); 4817352f7f91STakashi Iwai return true; 4818352f7f91STakashi Iwai } 4819352f7f91STakashi Iwai 4820352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 4821352f7f91STakashi Iwai { 4822352f7f91STakashi Iwai const struct automic_entry *a = ap; 4823352f7f91STakashi Iwai const struct automic_entry *b = bp; 4824352f7f91STakashi Iwai return (int)(a->attr - b->attr); 4825352f7f91STakashi Iwai } 4826352f7f91STakashi Iwai 4827352f7f91STakashi Iwai /* 4828352f7f91STakashi Iwai * Check the availability of auto-mic switch; 4829352f7f91STakashi Iwai * Set up if really supported 4830352f7f91STakashi Iwai */ 4831352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 4832352f7f91STakashi Iwai { 4833352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4834352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4835352f7f91STakashi Iwai unsigned int types; 4836352f7f91STakashi Iwai int i, num_pins; 4837352f7f91STakashi Iwai 4838d12daf6fSTakashi Iwai if (spec->suppress_auto_mic) 4839d12daf6fSTakashi Iwai return 0; 4840d12daf6fSTakashi Iwai 4841352f7f91STakashi Iwai types = 0; 4842352f7f91STakashi Iwai num_pins = 0; 4843352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 4844352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 4845352f7f91STakashi Iwai unsigned int attr; 4846352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 4847352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 4848352f7f91STakashi Iwai if (types & (1 << attr)) 4849352f7f91STakashi Iwai return 0; /* already occupied */ 4850352f7f91STakashi Iwai switch (attr) { 4851352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 4852352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 4853352f7f91STakashi Iwai return 0; /* invalid type */ 4854352f7f91STakashi Iwai break; 4855352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 4856352f7f91STakashi Iwai return 0; /* invalid entry */ 4857352f7f91STakashi Iwai default: 4858352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 4859352f7f91STakashi Iwai return 0; /* invalid type */ 4860352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 4861352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 4862352f7f91STakashi Iwai return 0; /* only mic is allowed */ 4863352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4864352f7f91STakashi Iwai return 0; /* no unsol support */ 4865352f7f91STakashi Iwai break; 4866352f7f91STakashi Iwai } 4867352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 4868352f7f91STakashi Iwai return 0; 4869352f7f91STakashi Iwai types |= (1 << attr); 4870352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 4871352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 4872352f7f91STakashi Iwai num_pins++; 4873352f7f91STakashi Iwai } 4874352f7f91STakashi Iwai 4875352f7f91STakashi Iwai if (num_pins < 2) 4876352f7f91STakashi Iwai return 0; 4877352f7f91STakashi Iwai 4878352f7f91STakashi Iwai spec->am_num_entries = num_pins; 4879352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 4880352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 4881352f7f91STakashi Iwai */ 4882352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 4883352f7f91STakashi Iwai compare_attr, NULL); 4884352f7f91STakashi Iwai 4885352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 4886352f7f91STakashi Iwai return 0; 4887352f7f91STakashi Iwai 4888352f7f91STakashi Iwai spec->auto_mic = 1; 4889352f7f91STakashi Iwai spec->num_adc_nids = 1; 4890352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 48914e76a883STakashi Iwai codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 4892352f7f91STakashi Iwai spec->am_entry[0].pin, 4893352f7f91STakashi Iwai spec->am_entry[1].pin, 4894352f7f91STakashi Iwai spec->am_entry[2].pin); 4895352f7f91STakashi Iwai 4896352f7f91STakashi Iwai return 0; 4897352f7f91STakashi Iwai } 4898352f7f91STakashi Iwai 4899dda42bd0STakashi Iwai /** 4900dda42bd0STakashi Iwai * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets 4901dda42bd0STakashi Iwai * into power down 4902dda42bd0STakashi Iwai * @codec: the HDA codec 4903dda42bd0STakashi Iwai * @nid: NID to evalute 4904dda42bd0STakashi Iwai * @power_state: target power state 4905dda42bd0STakashi Iwai */ 4906dfc6e469STakashi Iwai unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, 490755196fffSTakashi Iwai hda_nid_t nid, 490855196fffSTakashi Iwai unsigned int power_state) 490955196fffSTakashi Iwai { 4910b6c09b3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 4911b6c09b3cSTakashi Iwai 4912b6c09b3cSTakashi Iwai if (!spec->power_down_unused && !codec->power_save_node) 4913b6c09b3cSTakashi Iwai return power_state; 49147639a06cSTakashi Iwai if (power_state != AC_PWRST_D0 || nid == codec->core.afg) 491555196fffSTakashi Iwai return power_state; 491655196fffSTakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER) 491755196fffSTakashi Iwai return power_state; 4918b1b9fbd0STakashi Iwai if (is_active_nid_for_any(codec, nid)) 491955196fffSTakashi Iwai return power_state; 492055196fffSTakashi Iwai return AC_PWRST_D3; 492155196fffSTakashi Iwai } 4922dfc6e469STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter); 492355196fffSTakashi Iwai 4924ebb93c05STakashi Iwai /* mute all aamix inputs initially; parse up to the first leaves */ 4925ebb93c05STakashi Iwai static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) 4926ebb93c05STakashi Iwai { 4927ebb93c05STakashi Iwai int i, nums; 4928ebb93c05STakashi Iwai const hda_nid_t *conn; 4929ebb93c05STakashi Iwai bool has_amp; 4930ebb93c05STakashi Iwai 4931ebb93c05STakashi Iwai nums = snd_hda_get_conn_list(codec, mix, &conn); 4932ebb93c05STakashi Iwai has_amp = nid_has_mute(codec, mix, HDA_INPUT); 4933ebb93c05STakashi Iwai for (i = 0; i < nums; i++) { 4934ebb93c05STakashi Iwai if (has_amp) 4935ef403edbSTakashi Iwai update_amp(codec, mix, HDA_INPUT, i, 4936ebb93c05STakashi Iwai 0xff, HDA_AMP_MUTE); 4937ebb93c05STakashi Iwai else if (nid_has_volume(codec, conn[i], HDA_OUTPUT)) 4938ef403edbSTakashi Iwai update_amp(codec, conn[i], HDA_OUTPUT, 0, 4939ebb93c05STakashi Iwai 0xff, HDA_AMP_MUTE); 4940ebb93c05STakashi Iwai } 4941ebb93c05STakashi Iwai } 4942352f7f91STakashi Iwai 4943dda42bd0STakashi Iwai /** 4944e6feb5d0STakashi Iwai * snd_hda_gen_stream_pm - Stream power management callback 4945e6feb5d0STakashi Iwai * @codec: the HDA codec 4946e6feb5d0STakashi Iwai * @nid: audio widget 4947e6feb5d0STakashi Iwai * @on: power on/off flag 4948e6feb5d0STakashi Iwai * 4949967b1307STakashi Iwai * Set this in patch_ops.stream_pm. Only valid with power_save_node flag. 4950e6feb5d0STakashi Iwai */ 4951e6feb5d0STakashi Iwai void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on) 4952e6feb5d0STakashi Iwai { 4953967b1307STakashi Iwai if (codec->power_save_node) 4954e6feb5d0STakashi Iwai set_path_power(codec, nid, -1, on); 4955e6feb5d0STakashi Iwai } 4956e6feb5d0STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm); 4957e6feb5d0STakashi Iwai 49586cd23b26STakashi Iwai /* forcibly mute the speaker output without caching; return true if updated */ 49596cd23b26STakashi Iwai static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid) 49606cd23b26STakashi Iwai { 49616cd23b26STakashi Iwai if (!nid) 49626cd23b26STakashi Iwai return false; 49636cd23b26STakashi Iwai if (!nid_has_mute(codec, nid, HDA_OUTPUT)) 49646cd23b26STakashi Iwai return false; /* no mute, skip */ 49656cd23b26STakashi Iwai if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & 49666cd23b26STakashi Iwai snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) & 49676cd23b26STakashi Iwai HDA_AMP_MUTE) 49686cd23b26STakashi Iwai return false; /* both channels already muted, skip */ 49696cd23b26STakashi Iwai 49706cd23b26STakashi Iwai /* direct amp update without caching */ 49716cd23b26STakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 49726cd23b26STakashi Iwai AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT | 49736cd23b26STakashi Iwai AC_AMP_SET_RIGHT | HDA_AMP_MUTE); 49746cd23b26STakashi Iwai return true; 49756cd23b26STakashi Iwai } 49766cd23b26STakashi Iwai 49776cd23b26STakashi Iwai /** 49786cd23b26STakashi Iwai * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs 49796cd23b26STakashi Iwai * @codec: the HDA codec 49806cd23b26STakashi Iwai * 49816cd23b26STakashi Iwai * Forcibly mute the speaker outputs, to be called at suspend or shutdown. 49826cd23b26STakashi Iwai * 49836cd23b26STakashi Iwai * The mute state done by this function isn't cached, hence the original state 49846cd23b26STakashi Iwai * will be restored at resume. 49856cd23b26STakashi Iwai * 49866cd23b26STakashi Iwai * Return true if the mute state has been changed. 49876cd23b26STakashi Iwai */ 49886cd23b26STakashi Iwai bool snd_hda_gen_shutup_speakers(struct hda_codec *codec) 49896cd23b26STakashi Iwai { 49906cd23b26STakashi Iwai struct hda_gen_spec *spec = codec->spec; 49916cd23b26STakashi Iwai const int *paths; 49926cd23b26STakashi Iwai const struct nid_path *path; 49936cd23b26STakashi Iwai int i, p, num_paths; 49946cd23b26STakashi Iwai bool updated = false; 49956cd23b26STakashi Iwai 49966cd23b26STakashi Iwai /* if already powered off, do nothing */ 49976cd23b26STakashi Iwai if (!snd_hdac_is_power_on(&codec->core)) 49986cd23b26STakashi Iwai return false; 49996cd23b26STakashi Iwai 50006cd23b26STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) { 50016cd23b26STakashi Iwai paths = spec->out_paths; 50026cd23b26STakashi Iwai num_paths = spec->autocfg.line_outs; 50036cd23b26STakashi Iwai } else { 50046cd23b26STakashi Iwai paths = spec->speaker_paths; 50056cd23b26STakashi Iwai num_paths = spec->autocfg.speaker_outs; 50066cd23b26STakashi Iwai } 50076cd23b26STakashi Iwai 50086cd23b26STakashi Iwai for (i = 0; i < num_paths; i++) { 50096cd23b26STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]); 50106cd23b26STakashi Iwai if (!path) 50116cd23b26STakashi Iwai continue; 50126cd23b26STakashi Iwai for (p = 0; p < path->depth; p++) 50136cd23b26STakashi Iwai if (force_mute_output_path(codec, path->path[p])) 50146cd23b26STakashi Iwai updated = true; 50156cd23b26STakashi Iwai } 50166cd23b26STakashi Iwai 50176cd23b26STakashi Iwai return updated; 50186cd23b26STakashi Iwai } 50196cd23b26STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers); 50206cd23b26STakashi Iwai 5021e6feb5d0STakashi Iwai /** 5022dda42bd0STakashi Iwai * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and 5023dda42bd0STakashi Iwai * set up the hda_gen_spec 5024dda42bd0STakashi Iwai * @codec: the HDA codec 5025dda42bd0STakashi Iwai * @cfg: Parsed pin configuration 50269eb413e5STakashi Iwai * 50279eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 5028352f7f91STakashi Iwai * or a negative error code 5029352f7f91STakashi Iwai */ 5030352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 50319eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 5032352f7f91STakashi Iwai { 5033352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5034352f7f91STakashi Iwai int err; 5035352f7f91STakashi Iwai 50361c70a583STakashi Iwai parse_user_hints(codec); 50371c70a583STakashi Iwai 5038e65bf997SJaroslav Kysela if (spec->vmaster_mute_led || spec->mic_mute_led) 5039e65bf997SJaroslav Kysela snd_ctl_led_request(); 5040e65bf997SJaroslav Kysela 5041e4a395e7STakashi Iwai if (spec->mixer_nid && !spec->mixer_merge_nid) 5042e4a395e7STakashi Iwai spec->mixer_merge_nid = spec->mixer_nid; 5043e4a395e7STakashi Iwai 50449eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 50459eb413e5STakashi Iwai spec->autocfg = *cfg; 50469eb413e5STakashi Iwai cfg = &spec->autocfg; 50479eb413e5STakashi Iwai } 50489eb413e5STakashi Iwai 504998bd1115STakashi Iwai if (!spec->main_out_badness) 505098bd1115STakashi Iwai spec->main_out_badness = &hda_main_out_badness; 505198bd1115STakashi Iwai if (!spec->extra_out_badness) 505298bd1115STakashi Iwai spec->extra_out_badness = &hda_extra_out_badness; 505398bd1115STakashi Iwai 50546fc4cb97SDavid Henningsson fill_all_dac_nids(codec); 50556fc4cb97SDavid Henningsson 5056352f7f91STakashi Iwai if (!cfg->line_outs) { 5057352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 5058352f7f91STakashi Iwai spec->multiout.max_channels = 2; 5059352f7f91STakashi Iwai spec->no_analog = 1; 5060352f7f91STakashi Iwai goto dig_only; 5061352f7f91STakashi Iwai } 5062c9e4bdb7STakashi Iwai if (!cfg->num_inputs && !cfg->dig_in_pin) 5063352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 5064352f7f91STakashi Iwai } 5065352f7f91STakashi Iwai 5066352f7f91STakashi Iwai if (!spec->no_primary_hp && 5067352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 5068352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 5069352f7f91STakashi Iwai /* use HP as primary out */ 5070352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 5071352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 5072352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 5073352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 5074352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 5075352f7f91STakashi Iwai cfg->hp_outs = 0; 5076352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 5077352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 5078352f7f91STakashi Iwai } 5079352f7f91STakashi Iwai 5080352f7f91STakashi Iwai err = parse_output_paths(codec); 5081352f7f91STakashi Iwai if (err < 0) 5082352f7f91STakashi Iwai return err; 5083352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 5084352f7f91STakashi Iwai if (err < 0) 5085352f7f91STakashi Iwai return err; 5086352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 5087352f7f91STakashi Iwai if (err < 0) 5088352f7f91STakashi Iwai return err; 5089352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 5090352f7f91STakashi Iwai if (err < 0) 5091352f7f91STakashi Iwai return err; 5092352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 5093352f7f91STakashi Iwai if (err < 0) 5094352f7f91STakashi Iwai return err; 509538cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 509638cf6f1aSTakashi Iwai if (err < 0) 509738cf6f1aSTakashi Iwai return err; 5098c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec); 5099c30aa7b2STakashi Iwai if (err < 0) 5100c30aa7b2STakashi Iwai return err; 5101967303daSTakashi Iwai err = create_hp_mic(codec); 5102352f7f91STakashi Iwai if (err < 0) 5103352f7f91STakashi Iwai return err; 5104352f7f91STakashi Iwai err = create_input_ctls(codec); 5105352f7f91STakashi Iwai if (err < 0) 5106352f7f91STakashi Iwai return err; 5107352f7f91STakashi Iwai 5108e6feb5d0STakashi Iwai /* add power-down pin callbacks at first */ 5109e6feb5d0STakashi Iwai add_all_pin_power_ctls(codec, false); 5110e6feb5d0STakashi Iwai 5111a07a949bSTakashi Iwai spec->const_channel_count = spec->ext_channel_count; 5112a07a949bSTakashi Iwai /* check the multiple speaker and headphone pins */ 5113a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 5114a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 5115a07a949bSTakashi Iwai cfg->speaker_outs * 2); 5116a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 5117a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 5118a07a949bSTakashi Iwai cfg->hp_outs * 2); 5119352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 5120352f7f91STakashi Iwai spec->const_channel_count); 5121352f7f91STakashi Iwai 5122352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 5123352f7f91STakashi Iwai if (err < 0) 5124352f7f91STakashi Iwai return err; 5125352f7f91STakashi Iwai 5126352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 5127352f7f91STakashi Iwai if (err < 0) 5128352f7f91STakashi Iwai return err; 5129352f7f91STakashi Iwai 5130352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 5131352f7f91STakashi Iwai if (err < 0) 5132352f7f91STakashi Iwai return err; 5133352f7f91STakashi Iwai 5134f1e762ddSTakashi Iwai /* add stereo mix if available and not enabled yet */ 5135f1e762ddSTakashi Iwai if (!spec->auto_mic && spec->mixer_nid && 513674f14b36STakashi Iwai spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_AUTO && 513774f14b36STakashi Iwai spec->input_mux.num_items > 1) { 5138f1e762ddSTakashi Iwai err = parse_capture_source(codec, spec->mixer_nid, 5139f1e762ddSTakashi Iwai CFG_IDX_MIX, spec->num_all_adcs, 5140f1e762ddSTakashi Iwai "Stereo Mix", 0); 5141f1e762ddSTakashi Iwai if (err < 0) 5142f1e762ddSTakashi Iwai return err; 5143f1e762ddSTakashi Iwai } 5144f1e762ddSTakashi Iwai 5145f1e762ddSTakashi Iwai 5146352f7f91STakashi Iwai err = create_capture_mixers(codec); 5147352f7f91STakashi Iwai if (err < 0) 5148352f7f91STakashi Iwai return err; 5149352f7f91STakashi Iwai 5150352f7f91STakashi Iwai err = parse_mic_boost(codec); 5151352f7f91STakashi Iwai if (err < 0) 5152352f7f91STakashi Iwai return err; 5153352f7f91STakashi Iwai 5154ced4cefcSTakashi Iwai /* create "Headphone Mic Jack Mode" if no input selection is 5155ced4cefcSTakashi Iwai * available (or user specifies add_jack_modes hint) 5156ced4cefcSTakashi Iwai */ 5157ced4cefcSTakashi Iwai if (spec->hp_mic_pin && 5158ced4cefcSTakashi Iwai (spec->auto_mic || spec->input_mux.num_items == 1 || 5159ced4cefcSTakashi Iwai spec->add_jack_modes)) { 5160ced4cefcSTakashi Iwai err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin); 5161ced4cefcSTakashi Iwai if (err < 0) 5162ced4cefcSTakashi Iwai return err; 5163ced4cefcSTakashi Iwai } 5164ced4cefcSTakashi Iwai 5165f811c3cfSTakashi Iwai if (spec->add_jack_modes) { 5166978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 5167978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->line_outs, 5168978e77e7STakashi Iwai cfg->line_out_pins); 5169978e77e7STakashi Iwai if (err < 0) 5170978e77e7STakashi Iwai return err; 5171978e77e7STakashi Iwai } 5172978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 5173978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->hp_outs, 5174978e77e7STakashi Iwai cfg->hp_pins); 5175978e77e7STakashi Iwai if (err < 0) 5176978e77e7STakashi Iwai return err; 5177978e77e7STakashi Iwai } 5178978e77e7STakashi Iwai } 5179978e77e7STakashi Iwai 5180e6feb5d0STakashi Iwai /* add power-up pin callbacks at last */ 5181e6feb5d0STakashi Iwai add_all_pin_power_ctls(codec, true); 5182e6feb5d0STakashi Iwai 5183ebb93c05STakashi Iwai /* mute all aamix input initially */ 5184ebb93c05STakashi Iwai if (spec->mixer_nid) 5185ebb93c05STakashi Iwai mute_all_mixer_nid(codec, spec->mixer_nid); 5186ebb93c05STakashi Iwai 5187352f7f91STakashi Iwai dig_only: 5188352f7f91STakashi Iwai parse_digital(codec); 5189352f7f91STakashi Iwai 519049fb1897STakashi Iwai if (spec->power_down_unused || codec->power_save_node) { 519124fef902STakashi Iwai if (!codec->power_filter) 519255196fffSTakashi Iwai codec->power_filter = snd_hda_gen_path_power_filter; 519349fb1897STakashi Iwai if (!codec->patch_ops.stream_pm) 519449fb1897STakashi Iwai codec->patch_ops.stream_pm = snd_hda_gen_stream_pm; 519549fb1897STakashi Iwai } 519655196fffSTakashi Iwai 51977504b6cdSTakashi Iwai if (!spec->no_analog && spec->beep_nid) { 51987504b6cdSTakashi Iwai err = snd_hda_attach_beep_device(codec, spec->beep_nid); 51997504b6cdSTakashi Iwai if (err < 0) 52007504b6cdSTakashi Iwai return err; 5201967b1307STakashi Iwai if (codec->beep && codec->power_save_node) { 52025ccf835cSTakashi Iwai err = add_fake_beep_paths(codec); 52035ccf835cSTakashi Iwai if (err < 0) 52045ccf835cSTakashi Iwai return err; 52055ccf835cSTakashi Iwai codec->beep->power_hook = beep_power_hook; 52065ccf835cSTakashi Iwai } 52077504b6cdSTakashi Iwai } 52087504b6cdSTakashi Iwai 5209352f7f91STakashi Iwai return 1; 5210352f7f91STakashi Iwai } 52112698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config); 5212352f7f91STakashi Iwai 5213352f7f91STakashi Iwai 5214352f7f91STakashi Iwai /* 5215352f7f91STakashi Iwai * Build control elements 5216352f7f91STakashi Iwai */ 5217352f7f91STakashi Iwai 52189ab0cb30STakashi Iwai /* follower controls for virtual master */ 52199ab0cb30STakashi Iwai static const char * const follower_pfxs[] = { 5220352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 5221352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 5222352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 5223ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", 5224ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE", 522503ad6a8cSDavid Henningsson "Headphone Side", "Headphone+LO", "Speaker+LO", 5226352f7f91STakashi Iwai NULL, 5227352f7f91STakashi Iwai }; 5228352f7f91STakashi Iwai 5229dda42bd0STakashi Iwai /** 5230dda42bd0STakashi Iwai * snd_hda_gen_build_controls - Build controls from the parsed results 5231dda42bd0STakashi Iwai * @codec: the HDA codec 5232dda42bd0STakashi Iwai * 5233dda42bd0STakashi Iwai * Pass this to build_controls patch_ops. 5234dda42bd0STakashi Iwai */ 5235352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 5236352f7f91STakashi Iwai { 5237352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5238352f7f91STakashi Iwai int err; 5239352f7f91STakashi Iwai 524036502d02STakashi Iwai if (spec->kctls.used) { 5241352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 5242352f7f91STakashi Iwai if (err < 0) 5243352f7f91STakashi Iwai return err; 524436502d02STakashi Iwai } 5245352f7f91STakashi Iwai 5246352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 5247352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 5248352f7f91STakashi Iwai spec->multiout.dig_out_nid, 5249352f7f91STakashi Iwai spec->multiout.dig_out_nid, 5250bbbc7e85STakashi Iwai spec->pcm_rec[1]->pcm_type); 5251352f7f91STakashi Iwai if (err < 0) 5252352f7f91STakashi Iwai return err; 5253352f7f91STakashi Iwai if (!spec->no_analog) { 5254352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 5255352f7f91STakashi Iwai &spec->multiout); 5256352f7f91STakashi Iwai if (err < 0) 5257352f7f91STakashi Iwai return err; 5258352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 5259352f7f91STakashi Iwai } 5260352f7f91STakashi Iwai } 5261352f7f91STakashi Iwai if (spec->dig_in_nid) { 5262352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 5263352f7f91STakashi Iwai if (err < 0) 5264352f7f91STakashi Iwai return err; 5265352f7f91STakashi Iwai } 5266352f7f91STakashi Iwai 5267352f7f91STakashi Iwai /* if we have no master control, let's create it */ 52687480316cSTakashi Iwai if (!spec->no_analog && !spec->suppress_vmaster && 5269352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 5270352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 52719ab0cb30STakashi Iwai spec->vmaster_tlv, follower_pfxs, 5272e65bf997SJaroslav Kysela "Playback Volume", 0); 5273352f7f91STakashi Iwai if (err < 0) 5274352f7f91STakashi Iwai return err; 5275352f7f91STakashi Iwai } 52767480316cSTakashi Iwai if (!spec->no_analog && !spec->suppress_vmaster && 5277352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 5278352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 52799ab0cb30STakashi Iwai NULL, follower_pfxs, 5280e65bf997SJaroslav Kysela "Playback Switch", true, 5281e65bf997SJaroslav Kysela spec->vmaster_mute_led ? 5282e65bf997SJaroslav Kysela SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0, 5283e65bf997SJaroslav Kysela &spec->vmaster_mute.sw_kctl); 5284352f7f91STakashi Iwai if (err < 0) 5285352f7f91STakashi Iwai return err; 5286b63eae0aSTakashi Iwai if (spec->vmaster_mute.hook) { 5287e65bf997SJaroslav Kysela snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute); 5288b63eae0aSTakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 5289b63eae0aSTakashi Iwai } 5290352f7f91STakashi Iwai } 5291352f7f91STakashi Iwai 5292352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 5293352f7f91STakashi Iwai 5294352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 5295352f7f91STakashi Iwai if (err < 0) 5296352f7f91STakashi Iwai return err; 5297352f7f91STakashi Iwai 5298352f7f91STakashi Iwai return 0; 5299352f7f91STakashi Iwai } 53002698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls); 5301352f7f91STakashi Iwai 5302352f7f91STakashi Iwai 5303352f7f91STakashi Iwai /* 5304352f7f91STakashi Iwai * PCM definitions 5305352f7f91STakashi Iwai */ 5306352f7f91STakashi Iwai 5307e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, 5308e6b85f3cSTakashi Iwai struct hda_codec *codec, 5309e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream, 5310e6b85f3cSTakashi Iwai int action) 5311e6b85f3cSTakashi Iwai { 5312e6b85f3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 5313e6b85f3cSTakashi Iwai if (spec->pcm_playback_hook) 5314e6b85f3cSTakashi Iwai spec->pcm_playback_hook(hinfo, codec, substream, action); 5315e6b85f3cSTakashi Iwai } 5316e6b85f3cSTakashi Iwai 5317ac2e8736STakashi Iwai static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo, 5318ac2e8736STakashi Iwai struct hda_codec *codec, 5319ac2e8736STakashi Iwai struct snd_pcm_substream *substream, 5320ac2e8736STakashi Iwai int action) 5321ac2e8736STakashi Iwai { 5322ac2e8736STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5323ac2e8736STakashi Iwai if (spec->pcm_capture_hook) 5324ac2e8736STakashi Iwai spec->pcm_capture_hook(hinfo, codec, substream, action); 5325ac2e8736STakashi Iwai } 5326ac2e8736STakashi Iwai 5327352f7f91STakashi Iwai /* 5328352f7f91STakashi Iwai * Analog playback callbacks 5329352f7f91STakashi Iwai */ 5330352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 5331352f7f91STakashi Iwai struct hda_codec *codec, 5332352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5333352f7f91STakashi Iwai { 5334352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 533538cf6f1aSTakashi Iwai int err; 533638cf6f1aSTakashi Iwai 533738cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 533838cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 533938cf6f1aSTakashi Iwai &spec->multiout, substream, 5340352f7f91STakashi Iwai hinfo); 5341e6b85f3cSTakashi Iwai if (!err) { 534238cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 5343e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5344e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 5345e6b85f3cSTakashi Iwai } 534638cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 534738cf6f1aSTakashi Iwai return err; 5348352f7f91STakashi Iwai } 5349352f7f91STakashi Iwai 5350352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 535197ec558aSTakashi Iwai struct hda_codec *codec, 535297ec558aSTakashi Iwai unsigned int stream_tag, 535397ec558aSTakashi Iwai unsigned int format, 535497ec558aSTakashi Iwai struct snd_pcm_substream *substream) 535597ec558aSTakashi Iwai { 5356352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5357e6b85f3cSTakashi Iwai int err; 5358e6b85f3cSTakashi Iwai 5359e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 5360352f7f91STakashi Iwai stream_tag, format, substream); 5361e6b85f3cSTakashi Iwai if (!err) 5362e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5363e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 5364e6b85f3cSTakashi Iwai return err; 5365352f7f91STakashi Iwai } 536697ec558aSTakashi Iwai 5367352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 5368352f7f91STakashi Iwai struct hda_codec *codec, 5369352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5370352f7f91STakashi Iwai { 5371352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5372e6b85f3cSTakashi Iwai int err; 5373e6b85f3cSTakashi Iwai 5374e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 5375e6b85f3cSTakashi Iwai if (!err) 5376e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5377e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 5378e6b85f3cSTakashi Iwai return err; 5379352f7f91STakashi Iwai } 5380352f7f91STakashi Iwai 538138cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 538238cf6f1aSTakashi Iwai struct hda_codec *codec, 538338cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 538438cf6f1aSTakashi Iwai { 538538cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 538638cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 538738cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 5388e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5389e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 539038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 539138cf6f1aSTakashi Iwai return 0; 539238cf6f1aSTakashi Iwai } 539338cf6f1aSTakashi Iwai 5394ac2e8736STakashi Iwai static int capture_pcm_open(struct hda_pcm_stream *hinfo, 5395ac2e8736STakashi Iwai struct hda_codec *codec, 5396ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 5397ac2e8736STakashi Iwai { 5398ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN); 5399ac2e8736STakashi Iwai return 0; 5400ac2e8736STakashi Iwai } 5401ac2e8736STakashi Iwai 5402ac2e8736STakashi Iwai static int capture_pcm_prepare(struct hda_pcm_stream *hinfo, 5403ac2e8736STakashi Iwai struct hda_codec *codec, 5404ac2e8736STakashi Iwai unsigned int stream_tag, 5405ac2e8736STakashi Iwai unsigned int format, 5406ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 5407ac2e8736STakashi Iwai { 5408ac2e8736STakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 5409ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 5410ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 5411ac2e8736STakashi Iwai return 0; 5412ac2e8736STakashi Iwai } 5413ac2e8736STakashi Iwai 5414ac2e8736STakashi Iwai static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 5415ac2e8736STakashi Iwai struct hda_codec *codec, 5416ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 5417ac2e8736STakashi Iwai { 5418ac2e8736STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 5419ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 5420ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 5421ac2e8736STakashi Iwai return 0; 5422ac2e8736STakashi Iwai } 5423ac2e8736STakashi Iwai 5424ac2e8736STakashi Iwai static int capture_pcm_close(struct hda_pcm_stream *hinfo, 5425ac2e8736STakashi Iwai struct hda_codec *codec, 5426ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 5427ac2e8736STakashi Iwai { 5428ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); 5429ac2e8736STakashi Iwai return 0; 5430ac2e8736STakashi Iwai } 5431ac2e8736STakashi Iwai 543238cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 543338cf6f1aSTakashi Iwai struct hda_codec *codec, 543438cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 543538cf6f1aSTakashi Iwai { 543638cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 543738cf6f1aSTakashi Iwai int err = 0; 543838cf6f1aSTakashi Iwai 543938cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 5440d1f15e06STakashi Iwai if (spec->indep_hp && !spec->indep_hp_enabled) 544138cf6f1aSTakashi Iwai err = -EBUSY; 544238cf6f1aSTakashi Iwai else 544338cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 5444e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5445e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 544638cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 544738cf6f1aSTakashi Iwai return err; 544838cf6f1aSTakashi Iwai } 544938cf6f1aSTakashi Iwai 545038cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 545138cf6f1aSTakashi Iwai struct hda_codec *codec, 545238cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 545338cf6f1aSTakashi Iwai { 545438cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 545538cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 545638cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 5457e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5458e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 545938cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 546038cf6f1aSTakashi Iwai return 0; 546138cf6f1aSTakashi Iwai } 546238cf6f1aSTakashi Iwai 5463e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 5464e6b85f3cSTakashi Iwai struct hda_codec *codec, 5465e6b85f3cSTakashi Iwai unsigned int stream_tag, 5466e6b85f3cSTakashi Iwai unsigned int format, 5467e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 5468e6b85f3cSTakashi Iwai { 5469e6b85f3cSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 5470e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5471e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 5472e6b85f3cSTakashi Iwai return 0; 5473e6b85f3cSTakashi Iwai } 5474e6b85f3cSTakashi Iwai 5475e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 5476e6b85f3cSTakashi Iwai struct hda_codec *codec, 5477e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 5478e6b85f3cSTakashi Iwai { 5479e6b85f3cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 5480e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5481e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 5482e6b85f3cSTakashi Iwai return 0; 5483e6b85f3cSTakashi Iwai } 5484e6b85f3cSTakashi Iwai 5485352f7f91STakashi Iwai /* 5486352f7f91STakashi Iwai * Digital out 5487352f7f91STakashi Iwai */ 5488352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 5489352f7f91STakashi Iwai struct hda_codec *codec, 5490352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5491352f7f91STakashi Iwai { 5492352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5493352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 5494352f7f91STakashi Iwai } 5495352f7f91STakashi Iwai 5496352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 5497352f7f91STakashi Iwai struct hda_codec *codec, 5498352f7f91STakashi Iwai unsigned int stream_tag, 5499352f7f91STakashi Iwai unsigned int format, 5500352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5501352f7f91STakashi Iwai { 5502352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5503352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 5504352f7f91STakashi Iwai stream_tag, format, substream); 5505352f7f91STakashi Iwai } 5506352f7f91STakashi Iwai 5507352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 5508352f7f91STakashi Iwai struct hda_codec *codec, 5509352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5510352f7f91STakashi Iwai { 5511352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5512352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 5513352f7f91STakashi Iwai } 5514352f7f91STakashi Iwai 5515352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 5516352f7f91STakashi Iwai struct hda_codec *codec, 5517352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5518352f7f91STakashi Iwai { 5519352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5520352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 5521352f7f91STakashi Iwai } 5522352f7f91STakashi Iwai 5523352f7f91STakashi Iwai /* 5524352f7f91STakashi Iwai * Analog capture 5525352f7f91STakashi Iwai */ 5526ac2e8736STakashi Iwai #define alt_capture_pcm_open capture_pcm_open 5527ac2e8736STakashi Iwai #define alt_capture_pcm_close capture_pcm_close 5528ac2e8736STakashi Iwai 5529352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 5530352f7f91STakashi Iwai struct hda_codec *codec, 5531352f7f91STakashi Iwai unsigned int stream_tag, 5532352f7f91STakashi Iwai unsigned int format, 5533352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5534352f7f91STakashi Iwai { 5535352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5536352f7f91STakashi Iwai 5537352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 553897ec558aSTakashi Iwai stream_tag, 0, format); 5539ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 5540ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 554197ec558aSTakashi Iwai return 0; 554297ec558aSTakashi Iwai } 554397ec558aSTakashi Iwai 5544352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 554597ec558aSTakashi Iwai struct hda_codec *codec, 554697ec558aSTakashi Iwai struct snd_pcm_substream *substream) 554797ec558aSTakashi Iwai { 5548352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 554997ec558aSTakashi Iwai 5550352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 5551352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 5552ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 5553ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 555497ec558aSTakashi Iwai return 0; 555597ec558aSTakashi Iwai } 555697ec558aSTakashi Iwai 5557352f7f91STakashi Iwai /* 5558352f7f91STakashi Iwai */ 5559352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 5560352f7f91STakashi Iwai .substreams = 1, 5561352f7f91STakashi Iwai .channels_min = 2, 5562352f7f91STakashi Iwai .channels_max = 8, 5563352f7f91STakashi Iwai /* NID is set in build_pcms */ 5564352f7f91STakashi Iwai .ops = { 5565352f7f91STakashi Iwai .open = playback_pcm_open, 556638cf6f1aSTakashi Iwai .close = playback_pcm_close, 5567352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 5568352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 5569352f7f91STakashi Iwai }, 5570352f7f91STakashi Iwai }; 5571352f7f91STakashi Iwai 5572352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 5573352f7f91STakashi Iwai .substreams = 1, 5574352f7f91STakashi Iwai .channels_min = 2, 5575352f7f91STakashi Iwai .channels_max = 2, 5576352f7f91STakashi Iwai /* NID is set in build_pcms */ 5577ac2e8736STakashi Iwai .ops = { 5578ac2e8736STakashi Iwai .open = capture_pcm_open, 5579ac2e8736STakashi Iwai .close = capture_pcm_close, 5580ac2e8736STakashi Iwai .prepare = capture_pcm_prepare, 5581ac2e8736STakashi Iwai .cleanup = capture_pcm_cleanup 5582ac2e8736STakashi Iwai }, 5583352f7f91STakashi Iwai }; 5584352f7f91STakashi Iwai 5585352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 5586352f7f91STakashi Iwai .substreams = 1, 5587352f7f91STakashi Iwai .channels_min = 2, 5588352f7f91STakashi Iwai .channels_max = 2, 5589352f7f91STakashi Iwai /* NID is set in build_pcms */ 559038cf6f1aSTakashi Iwai .ops = { 559138cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 5592e6b85f3cSTakashi Iwai .close = alt_playback_pcm_close, 5593e6b85f3cSTakashi Iwai .prepare = alt_playback_pcm_prepare, 5594e6b85f3cSTakashi Iwai .cleanup = alt_playback_pcm_cleanup 559538cf6f1aSTakashi Iwai }, 5596352f7f91STakashi Iwai }; 5597352f7f91STakashi Iwai 5598352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 5599352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 5600352f7f91STakashi Iwai .channels_min = 2, 5601352f7f91STakashi Iwai .channels_max = 2, 5602352f7f91STakashi Iwai /* NID is set in build_pcms */ 5603352f7f91STakashi Iwai .ops = { 5604ac2e8736STakashi Iwai .open = alt_capture_pcm_open, 5605ac2e8736STakashi Iwai .close = alt_capture_pcm_close, 5606352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 5607352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 5608352f7f91STakashi Iwai }, 5609352f7f91STakashi Iwai }; 5610352f7f91STakashi Iwai 5611352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 5612352f7f91STakashi Iwai .substreams = 1, 5613352f7f91STakashi Iwai .channels_min = 2, 5614352f7f91STakashi Iwai .channels_max = 2, 5615352f7f91STakashi Iwai /* NID is set in build_pcms */ 5616352f7f91STakashi Iwai .ops = { 5617352f7f91STakashi Iwai .open = dig_playback_pcm_open, 5618352f7f91STakashi Iwai .close = dig_playback_pcm_close, 5619352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 5620352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 5621352f7f91STakashi Iwai }, 5622352f7f91STakashi Iwai }; 5623352f7f91STakashi Iwai 5624352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 5625352f7f91STakashi Iwai .substreams = 1, 5626352f7f91STakashi Iwai .channels_min = 2, 5627352f7f91STakashi Iwai .channels_max = 2, 5628352f7f91STakashi Iwai /* NID is set in build_pcms */ 5629352f7f91STakashi Iwai }; 5630352f7f91STakashi Iwai 5631352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 5632352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 5633352f7f91STakashi Iwai .substreams = 0, 5634352f7f91STakashi Iwai .channels_min = 0, 5635352f7f91STakashi Iwai .channels_max = 0, 5636352f7f91STakashi Iwai }; 5637352f7f91STakashi Iwai 5638352f7f91STakashi Iwai /* 5639352f7f91STakashi Iwai * dynamic changing ADC PCM streams 5640352f7f91STakashi Iwai */ 5641352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 56421da177e4SLinus Torvalds { 5643352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5644352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 56451da177e4SLinus Torvalds 5646352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 5647352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 5648352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 5649352f7f91STakashi Iwai spec->cur_adc = new_adc; 5650352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 5651352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 5652352f7f91STakashi Iwai spec->cur_adc_format); 5653352f7f91STakashi Iwai return true; 5654352f7f91STakashi Iwai } 5655352f7f91STakashi Iwai return false; 5656352f7f91STakashi Iwai } 5657352f7f91STakashi Iwai 5658352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 5659352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 5660352f7f91STakashi Iwai struct hda_codec *codec, 5661352f7f91STakashi Iwai unsigned int stream_tag, 5662352f7f91STakashi Iwai unsigned int format, 5663352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5664352f7f91STakashi Iwai { 5665352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5666352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 5667352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 5668352f7f91STakashi Iwai spec->cur_adc_format = format; 5669352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 56704f29efc0STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_PREPARE); 56711da177e4SLinus Torvalds return 0; 56721da177e4SLinus Torvalds } 56731da177e4SLinus Torvalds 5674352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 5675352f7f91STakashi Iwai struct hda_codec *codec, 5676352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5677352f7f91STakashi Iwai { 5678352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5679352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 5680352f7f91STakashi Iwai spec->cur_adc = 0; 56814f29efc0STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLEANUP); 5682352f7f91STakashi Iwai return 0; 5683352f7f91STakashi Iwai } 5684352f7f91STakashi Iwai 5685352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 5686352f7f91STakashi Iwai .substreams = 1, 5687352f7f91STakashi Iwai .channels_min = 2, 5688352f7f91STakashi Iwai .channels_max = 2, 5689352f7f91STakashi Iwai .nid = 0, /* fill later */ 5690352f7f91STakashi Iwai .ops = { 5691352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 5692352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 5693352f7f91STakashi Iwai }, 5694352f7f91STakashi Iwai }; 5695352f7f91STakashi Iwai 5696f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 5697f873e536STakashi Iwai const char *chip_name) 5698f873e536STakashi Iwai { 5699f873e536STakashi Iwai char *p; 5700f873e536STakashi Iwai 5701f873e536STakashi Iwai if (*str) 5702f873e536STakashi Iwai return; 570375b1a8f9SJoe Perches strscpy(str, chip_name, len); 5704f873e536STakashi Iwai 5705f873e536STakashi Iwai /* drop non-alnum chars after a space */ 5706f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 5707f873e536STakashi Iwai if (!isalnum(p[1])) { 5708f873e536STakashi Iwai *p = 0; 5709f873e536STakashi Iwai break; 5710f873e536STakashi Iwai } 5711f873e536STakashi Iwai } 5712f873e536STakashi Iwai strlcat(str, sfx, len); 5713f873e536STakashi Iwai } 5714f873e536STakashi Iwai 5715fb83b635STakashi Iwai /* copy PCM stream info from @default_str, and override non-NULL entries 5716fb83b635STakashi Iwai * from @spec_str and @nid 5717fb83b635STakashi Iwai */ 5718fb83b635STakashi Iwai static void setup_pcm_stream(struct hda_pcm_stream *str, 5719fb83b635STakashi Iwai const struct hda_pcm_stream *default_str, 5720fb83b635STakashi Iwai const struct hda_pcm_stream *spec_str, 5721fb83b635STakashi Iwai hda_nid_t nid) 5722fb83b635STakashi Iwai { 5723fb83b635STakashi Iwai *str = *default_str; 5724fb83b635STakashi Iwai if (nid) 5725fb83b635STakashi Iwai str->nid = nid; 5726fb83b635STakashi Iwai if (spec_str) { 5727fb83b635STakashi Iwai if (spec_str->substreams) 5728fb83b635STakashi Iwai str->substreams = spec_str->substreams; 5729fb83b635STakashi Iwai if (spec_str->channels_min) 5730fb83b635STakashi Iwai str->channels_min = spec_str->channels_min; 5731fb83b635STakashi Iwai if (spec_str->channels_max) 5732fb83b635STakashi Iwai str->channels_max = spec_str->channels_max; 5733fb83b635STakashi Iwai if (spec_str->rates) 5734fb83b635STakashi Iwai str->rates = spec_str->rates; 5735fb83b635STakashi Iwai if (spec_str->formats) 5736fb83b635STakashi Iwai str->formats = spec_str->formats; 5737fb83b635STakashi Iwai if (spec_str->maxbps) 5738fb83b635STakashi Iwai str->maxbps = spec_str->maxbps; 5739fb83b635STakashi Iwai } 5740fb83b635STakashi Iwai } 5741fb83b635STakashi Iwai 5742dda42bd0STakashi Iwai /** 5743dda42bd0STakashi Iwai * snd_hda_gen_build_pcms - build PCM streams based on the parsed results 5744dda42bd0STakashi Iwai * @codec: the HDA codec 5745dda42bd0STakashi Iwai * 5746dda42bd0STakashi Iwai * Pass this to build_pcms patch_ops. 5747dda42bd0STakashi Iwai */ 5748352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 5749352f7f91STakashi Iwai { 5750352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5751bbbc7e85STakashi Iwai struct hda_pcm *info; 5752352f7f91STakashi Iwai bool have_multi_adcs; 5753352f7f91STakashi Iwai 5754352f7f91STakashi Iwai if (spec->no_analog) 5755352f7f91STakashi Iwai goto skip_analog; 5756352f7f91STakashi Iwai 5757f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 5758f873e536STakashi Iwai sizeof(spec->stream_name_analog), 57597639a06cSTakashi Iwai " Analog", codec->core.chip_name); 5760bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog); 5761bbbc7e85STakashi Iwai if (!info) 5762bbbc7e85STakashi Iwai return -ENOMEM; 5763bbbc7e85STakashi Iwai spec->pcm_rec[0] = info; 5764352f7f91STakashi Iwai 5765352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 5766fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK], 5767fb83b635STakashi Iwai &pcm_analog_playback, 5768fb83b635STakashi Iwai spec->stream_analog_playback, 5769fb83b635STakashi Iwai spec->multiout.dac_nids[0]); 5770352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 5771352f7f91STakashi Iwai spec->multiout.max_channels; 5772352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 5773352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 5774352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 5775352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 5776352f7f91STakashi Iwai } 5777352f7f91STakashi Iwai if (spec->num_adc_nids) { 5778fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE], 5779fb83b635STakashi Iwai (spec->dyn_adc_switch ? 5780fb83b635STakashi Iwai &dyn_adc_pcm_analog_capture : &pcm_analog_capture), 5781fb83b635STakashi Iwai spec->stream_analog_capture, 5782fb83b635STakashi Iwai spec->adc_nids[0]); 5783352f7f91STakashi Iwai } 5784352f7f91STakashi Iwai 5785352f7f91STakashi Iwai skip_analog: 5786352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 5787352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 5788f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 5789352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 57907639a06cSTakashi Iwai " Digital", codec->core.chip_name); 5791bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s", 5792bbbc7e85STakashi Iwai spec->stream_name_digital); 5793bbbc7e85STakashi Iwai if (!info) 5794bbbc7e85STakashi Iwai return -ENOMEM; 57959ab0cb30STakashi Iwai codec->follower_dig_outs = spec->multiout.follower_dig_outs; 5796bbbc7e85STakashi Iwai spec->pcm_rec[1] = info; 5797352f7f91STakashi Iwai if (spec->dig_out_type) 5798352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 5799352f7f91STakashi Iwai else 5800352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 5801fb83b635STakashi Iwai if (spec->multiout.dig_out_nid) 5802fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK], 5803fb83b635STakashi Iwai &pcm_digital_playback, 5804fb83b635STakashi Iwai spec->stream_digital_playback, 5805fb83b635STakashi Iwai spec->multiout.dig_out_nid); 5806fb83b635STakashi Iwai if (spec->dig_in_nid) 5807fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE], 5808fb83b635STakashi Iwai &pcm_digital_capture, 5809fb83b635STakashi Iwai spec->stream_digital_capture, 5810fb83b635STakashi Iwai spec->dig_in_nid); 5811352f7f91STakashi Iwai } 5812352f7f91STakashi Iwai 5813352f7f91STakashi Iwai if (spec->no_analog) 5814352f7f91STakashi Iwai return 0; 5815352f7f91STakashi Iwai 5816352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 5817352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 5818352f7f91STakashi Iwai */ 5819352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 5820352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 5821352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 5822352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 5823a607148fSTakashi Iwai fill_pcm_stream_name(spec->stream_name_alt_analog, 5824a607148fSTakashi Iwai sizeof(spec->stream_name_alt_analog), 58257639a06cSTakashi Iwai " Alt Analog", codec->core.chip_name); 5826bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s", 5827bbbc7e85STakashi Iwai spec->stream_name_alt_analog); 5828bbbc7e85STakashi Iwai if (!info) 5829bbbc7e85STakashi Iwai return -ENOMEM; 5830bbbc7e85STakashi Iwai spec->pcm_rec[2] = info; 5831fb83b635STakashi Iwai if (spec->alt_dac_nid) 5832fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK], 5833fb83b635STakashi Iwai &pcm_analog_alt_playback, 5834fb83b635STakashi Iwai spec->stream_analog_alt_playback, 5835fb83b635STakashi Iwai spec->alt_dac_nid); 5836fb83b635STakashi Iwai else 5837fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK], 5838fb83b635STakashi Iwai &pcm_null_stream, NULL, 0); 5839352f7f91STakashi Iwai if (have_multi_adcs) { 5840fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE], 5841fb83b635STakashi Iwai &pcm_analog_alt_capture, 5842fb83b635STakashi Iwai spec->stream_analog_alt_capture, 5843fb83b635STakashi Iwai spec->adc_nids[1]); 5844352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 5845352f7f91STakashi Iwai spec->num_adc_nids - 1; 5846352f7f91STakashi Iwai } else { 5847fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE], 5848fb83b635STakashi Iwai &pcm_null_stream, NULL, 0); 5849352f7f91STakashi Iwai } 58501da177e4SLinus Torvalds } 58511da177e4SLinus Torvalds 58521da177e4SLinus Torvalds return 0; 58531da177e4SLinus Torvalds } 58542698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms); 5855352f7f91STakashi Iwai 5856352f7f91STakashi Iwai 5857352f7f91STakashi Iwai /* 5858352f7f91STakashi Iwai * Standard auto-parser initializations 5859352f7f91STakashi Iwai */ 5860352f7f91STakashi Iwai 5861d4156930STakashi Iwai /* configure the given path as a proper output */ 58622c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx) 5863352f7f91STakashi Iwai { 5864352f7f91STakashi Iwai struct nid_path *path; 5865d4156930STakashi Iwai hda_nid_t pin; 5866352f7f91STakashi Iwai 5867196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 5868d4156930STakashi Iwai if (!path || !path->depth) 5869352f7f91STakashi Iwai return; 5870d4156930STakashi Iwai pin = path->path[path->depth - 1]; 58712c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 587265033cc8STakashi Iwai snd_hda_activate_path(codec, path, path->active, 587365033cc8STakashi Iwai aamix_default(codec->spec)); 5874e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 5875352f7f91STakashi Iwai } 5876352f7f91STakashi Iwai 5877352f7f91STakashi Iwai /* initialize primary output paths */ 5878352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 5879352f7f91STakashi Iwai { 5880352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5881352f7f91STakashi Iwai int i; 5882352f7f91STakashi Iwai 5883d4156930STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) 58842c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->out_paths[i]); 5885352f7f91STakashi Iwai } 5886352f7f91STakashi Iwai 5887db23fd19STakashi Iwai 58882c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) 5889352f7f91STakashi Iwai { 5890352f7f91STakashi Iwai int i; 5891352f7f91STakashi Iwai 5892d4156930STakashi Iwai for (i = 0; i < num_outs; i++) 58932c12c30dSTakashi Iwai set_output_and_unmute(codec, paths[i]); 5894352f7f91STakashi Iwai } 5895db23fd19STakashi Iwai 5896db23fd19STakashi Iwai /* initialize hp and speaker paths */ 5897db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 5898db23fd19STakashi Iwai { 5899db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5900db23fd19STakashi Iwai 5901db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 59022c12c30dSTakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); 5903db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 5904db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 59052c12c30dSTakashi Iwai spec->speaker_paths); 5906352f7f91STakashi Iwai } 5907352f7f91STakashi Iwai 5908352f7f91STakashi Iwai /* initialize multi-io paths */ 5909352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 5910352f7f91STakashi Iwai { 5911352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5912352f7f91STakashi Iwai int i; 5913352f7f91STakashi Iwai 5914352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 5915352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 5916352f7f91STakashi Iwai struct nid_path *path; 5917196c1766STakashi Iwai path = get_multiio_path(codec, i); 5918352f7f91STakashi Iwai if (!path) 5919352f7f91STakashi Iwai continue; 5920352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 5921352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 59222c12c30dSTakashi Iwai snd_hda_codec_get_pin_target(codec, pin); 592365033cc8STakashi Iwai snd_hda_activate_path(codec, path, path->active, 592465033cc8STakashi Iwai aamix_default(spec)); 5925352f7f91STakashi Iwai } 5926352f7f91STakashi Iwai } 5927352f7f91STakashi Iwai 59284f7f67fbSTakashi Iwai static void init_aamix_paths(struct hda_codec *codec) 59294f7f67fbSTakashi Iwai { 59304f7f67fbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 59314f7f67fbSTakashi Iwai 59324f7f67fbSTakashi Iwai if (!spec->have_aamix_ctl) 59334f7f67fbSTakashi Iwai return; 5934e7fdd527STakashi Iwai if (!has_aamix_out_paths(spec)) 5935e7fdd527STakashi Iwai return; 59364f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0], 59374f7f67fbSTakashi Iwai spec->aamix_out_paths[0], 59384f7f67fbSTakashi Iwai spec->autocfg.line_out_type); 59394f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0], 59404f7f67fbSTakashi Iwai spec->aamix_out_paths[1], 59414f7f67fbSTakashi Iwai AUTO_PIN_HP_OUT); 59424f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0], 59434f7f67fbSTakashi Iwai spec->aamix_out_paths[2], 59444f7f67fbSTakashi Iwai AUTO_PIN_SPEAKER_OUT); 59454f7f67fbSTakashi Iwai } 59464f7f67fbSTakashi Iwai 5947352f7f91STakashi Iwai /* set up input pins and loopback paths */ 5948352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 5949352f7f91STakashi Iwai { 5950352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5951352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 5952352f7f91STakashi Iwai int i; 5953352f7f91STakashi Iwai 5954352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 5955352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 5956352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 59572c12c30dSTakashi Iwai restore_pin_ctl(codec, nid); 5958352f7f91STakashi Iwai 5959352f7f91STakashi Iwai /* init loopback inputs */ 5960352f7f91STakashi Iwai if (spec->mixer_nid) { 59613e367f15STakashi Iwai resume_path_from_idx(codec, spec->loopback_paths[i]); 59623e367f15STakashi Iwai resume_path_from_idx(codec, spec->loopback_merge_path); 5963352f7f91STakashi Iwai } 5964352f7f91STakashi Iwai } 5965352f7f91STakashi Iwai } 5966352f7f91STakashi Iwai 5967352f7f91STakashi Iwai /* initialize ADC paths */ 5968352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 5969352f7f91STakashi Iwai { 5970352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5971352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 5972352f7f91STakashi Iwai struct nid_path *path; 5973352f7f91STakashi Iwai int i, c, nums; 5974352f7f91STakashi Iwai 5975352f7f91STakashi Iwai if (spec->dyn_adc_switch) 5976352f7f91STakashi Iwai nums = 1; 5977352f7f91STakashi Iwai else 5978352f7f91STakashi Iwai nums = spec->num_adc_nids; 5979352f7f91STakashi Iwai 5980352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 5981352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 5982c697b716STakashi Iwai path = get_input_path(codec, c, i); 5983352f7f91STakashi Iwai if (path) { 5984352f7f91STakashi Iwai bool active = path->active; 5985352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 5986352f7f91STakashi Iwai active = true; 5987352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 5988352f7f91STakashi Iwai } 5989352f7f91STakashi Iwai } 5990967303daSTakashi Iwai if (spec->hp_mic) 5991967303daSTakashi Iwai update_hp_mic(codec, c, true); 5992352f7f91STakashi Iwai } 5993352f7f91STakashi Iwai 5994352f7f91STakashi Iwai if (spec->cap_sync_hook) 59957fe30711STakashi Iwai spec->cap_sync_hook(codec, NULL, NULL); 5996352f7f91STakashi Iwai } 5997352f7f91STakashi Iwai 5998352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 5999352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 6000352f7f91STakashi Iwai { 6001352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 6002352f7f91STakashi Iwai int i; 6003352f7f91STakashi Iwai hda_nid_t pin; 6004352f7f91STakashi Iwai 6005d4156930STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) 60062c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->digout_paths[i]); 6007352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 60082430d7b7STakashi Iwai if (pin) { 60092c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 60103e367f15STakashi Iwai resume_path_from_idx(codec, spec->digin_path); 60112430d7b7STakashi Iwai } 6012352f7f91STakashi Iwai } 6013352f7f91STakashi Iwai 6014973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 6015973e4972STakashi Iwai * invalid unsol tags by some reason 6016973e4972STakashi Iwai */ 6017973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 6018973e4972STakashi Iwai { 6019a9c2dfc8STakashi Iwai const struct hda_pincfg *pin; 6020973e4972STakashi Iwai int i; 6021973e4972STakashi Iwai 6022a9c2dfc8STakashi Iwai snd_array_for_each(&codec->init_pins, i, pin) { 6023973e4972STakashi Iwai hda_nid_t nid = pin->nid; 6024973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 6025973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 6026401caff7STakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 6027973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 6028973e4972STakashi Iwai } 6029973e4972STakashi Iwai } 6030973e4972STakashi Iwai 6031dda42bd0STakashi Iwai /** 6032dda42bd0STakashi Iwai * snd_hda_gen_init - initialize the generic spec 6033dda42bd0STakashi Iwai * @codec: the HDA codec 6034dda42bd0STakashi Iwai * 6035dda42bd0STakashi Iwai * This can be put as patch_ops init function. 60365187ac16STakashi Iwai */ 6037352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 6038352f7f91STakashi Iwai { 6039352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 6040352f7f91STakashi Iwai 6041352f7f91STakashi Iwai if (spec->init_hook) 6042352f7f91STakashi Iwai spec->init_hook(codec); 6043352f7f91STakashi Iwai 604489781d08STakashi Iwai if (!spec->skip_verbs) 6045352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 6046352f7f91STakashi Iwai 6047352f7f91STakashi Iwai init_multi_out(codec); 6048352f7f91STakashi Iwai init_extra_out(codec); 6049352f7f91STakashi Iwai init_multi_io(codec); 60504f7f67fbSTakashi Iwai init_aamix_paths(codec); 6051352f7f91STakashi Iwai init_analog_input(codec); 6052352f7f91STakashi Iwai init_input_src(codec); 6053352f7f91STakashi Iwai init_digital(codec); 6054352f7f91STakashi Iwai 6055973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 6056973e4972STakashi Iwai 6057e6feb5d0STakashi Iwai sync_all_pin_power_ctls(codec); 6058e6feb5d0STakashi Iwai 6059352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 6060a5cc2509STakashi Iwai update_automute_all(codec); 6061352f7f91STakashi Iwai 60621a462be5STakashi Iwai snd_hda_regmap_sync(codec); 60633bbcd274STakashi Iwai 6064352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 6065352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 6066352f7f91STakashi Iwai 6067352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 6068352f7f91STakashi Iwai return 0; 6069352f7f91STakashi Iwai } 60702698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_init); 6071fce52a3bSTakashi Iwai 6072dda42bd0STakashi Iwai /** 6073dda42bd0STakashi Iwai * snd_hda_gen_free - free the generic spec 6074dda42bd0STakashi Iwai * @codec: the HDA codec 6075dda42bd0STakashi Iwai * 6076dda42bd0STakashi Iwai * This can be put as patch_ops free function. 60775187ac16STakashi Iwai */ 6078fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec) 6079fce52a3bSTakashi Iwai { 60808a02c0ccSTakashi Iwai snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); 6081fce52a3bSTakashi Iwai snd_hda_gen_spec_free(codec->spec); 6082fce52a3bSTakashi Iwai kfree(codec->spec); 6083fce52a3bSTakashi Iwai codec->spec = NULL; 6084fce52a3bSTakashi Iwai } 60852698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_free); 6086fce52a3bSTakashi Iwai 6087dda42bd0STakashi Iwai /** 6088dda42bd0STakashi Iwai * snd_hda_gen_check_power_status - check the loopback power save state 6089dda42bd0STakashi Iwai * @codec: the HDA codec 6090dda42bd0STakashi Iwai * @nid: NID to inspect 6091dda42bd0STakashi Iwai * 6092dda42bd0STakashi Iwai * This can be put as patch_ops check_power_status function. 60935187ac16STakashi Iwai */ 6094fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) 6095fce52a3bSTakashi Iwai { 6096fce52a3bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 6097fce52a3bSTakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 6098fce52a3bSTakashi Iwai } 60992698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status); 6100352f7f91STakashi Iwai 6101352f7f91STakashi Iwai 6102352f7f91STakashi Iwai /* 6103352f7f91STakashi Iwai * the generic codec support 6104352f7f91STakashi Iwai */ 61051da177e4SLinus Torvalds 6106352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 6107352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 6108352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 6109352f7f91STakashi Iwai .init = snd_hda_gen_init, 6110fce52a3bSTakashi Iwai .free = snd_hda_gen_free, 6111352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 6112fce52a3bSTakashi Iwai .check_power_status = snd_hda_gen_check_power_status, 61131da177e4SLinus Torvalds }; 61141da177e4SLinus Torvalds 6115d8a766a1STakashi Iwai /* 6116dda42bd0STakashi Iwai * snd_hda_parse_generic_codec - Generic codec parser 6117dda42bd0STakashi Iwai * @codec: the HDA codec 6118dda42bd0STakashi Iwai */ 6119d8a766a1STakashi Iwai static int snd_hda_parse_generic_codec(struct hda_codec *codec) 61201da177e4SLinus Torvalds { 6121352f7f91STakashi Iwai struct hda_gen_spec *spec; 61221da177e4SLinus Torvalds int err; 61231da177e4SLinus Torvalds 6124e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 6125352f7f91STakashi Iwai if (!spec) 61261da177e4SLinus Torvalds return -ENOMEM; 6127352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 61281da177e4SLinus Torvalds codec->spec = spec; 61291da177e4SLinus Torvalds 61309eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 61319eb413e5STakashi Iwai if (err < 0) 6132cfef67f0SWenwen Wang goto error; 61339eb413e5STakashi Iwai 61349eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 6135352f7f91STakashi Iwai if (err < 0) 61361da177e4SLinus Torvalds goto error; 61371da177e4SLinus Torvalds 61381da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 61391da177e4SLinus Torvalds return 0; 61401da177e4SLinus Torvalds 61411da177e4SLinus Torvalds error: 6142fce52a3bSTakashi Iwai snd_hda_gen_free(codec); 61431da177e4SLinus Torvalds return err; 61441da177e4SLinus Torvalds } 6145d8a766a1STakashi Iwai 6146b9a94a9cSTakashi Iwai static const struct hda_device_id snd_hda_id_generic[] = { 6147b9a94a9cSTakashi Iwai HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec), 6148d8a766a1STakashi Iwai {} /* terminator */ 6149d8a766a1STakashi Iwai }; 6150b9a94a9cSTakashi Iwai MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic); 6151d8a766a1STakashi Iwai 6152d8a766a1STakashi Iwai static struct hda_codec_driver generic_driver = { 6153b9a94a9cSTakashi Iwai .id = snd_hda_id_generic, 6154d8a766a1STakashi Iwai }; 6155d8a766a1STakashi Iwai 6156d8a766a1STakashi Iwai module_hda_codec_driver(generic_driver); 6157b21bdd0dSTakashi Iwai 6158b21bdd0dSTakashi Iwai MODULE_LICENSE("GPL"); 6159b21bdd0dSTakashi Iwai MODULE_DESCRIPTION("Generic HD-audio codec parser"); 6160