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); 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds /* 971c70a583STakashi Iwai * store user hints 981c70a583STakashi Iwai */ 991c70a583STakashi Iwai static void parse_user_hints(struct hda_codec *codec) 1001c70a583STakashi Iwai { 1011c70a583STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1021c70a583STakashi Iwai int val; 1031c70a583STakashi Iwai 1041c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "jack_detect"); 1051c70a583STakashi Iwai if (val >= 0) 1061c70a583STakashi Iwai codec->no_jack_detect = !val; 1071c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_jack_detect"); 1081c70a583STakashi Iwai if (val >= 0) 1091c70a583STakashi Iwai codec->inv_jack_detect = !!val; 1101c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "trigger_sense"); 1111c70a583STakashi Iwai if (val >= 0) 1121c70a583STakashi Iwai codec->no_trigger_sense = !val; 1131c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_eapd"); 1141c70a583STakashi Iwai if (val >= 0) 1151c70a583STakashi Iwai codec->inv_eapd = !!val; 1161c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pcm_format_first"); 1171c70a583STakashi Iwai if (val >= 0) 1181c70a583STakashi Iwai codec->pcm_format_first = !!val; 1191c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "sticky_stream"); 1201c70a583STakashi Iwai if (val >= 0) 1211c70a583STakashi Iwai codec->no_sticky_stream = !val; 1221c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "spdif_status_reset"); 1231c70a583STakashi Iwai if (val >= 0) 1241c70a583STakashi Iwai codec->spdif_status_reset = !!val; 1251c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pin_amp_workaround"); 1261c70a583STakashi Iwai if (val >= 0) 1271c70a583STakashi Iwai codec->pin_amp_workaround = !!val; 1281c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "single_adc_amp"); 1291c70a583STakashi Iwai if (val >= 0) 1301c70a583STakashi Iwai codec->single_adc_amp = !!val; 131967b1307STakashi Iwai val = snd_hda_get_bool_hint(codec, "power_save_node"); 132e6feb5d0STakashi Iwai if (val >= 0) 133967b1307STakashi Iwai codec->power_save_node = !!val; 1341c70a583STakashi Iwai 135f72706beSTakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mute"); 136f72706beSTakashi Iwai if (val >= 0) 137f72706beSTakashi Iwai spec->suppress_auto_mute = !val; 1381c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mic"); 1391c70a583STakashi Iwai if (val >= 0) 1401c70a583STakashi Iwai spec->suppress_auto_mic = !val; 1411c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); 1421c70a583STakashi Iwai if (val >= 0) 1431c70a583STakashi Iwai spec->line_in_auto_switch = !!val; 1447eebffd3STakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp"); 1457eebffd3STakashi Iwai if (val >= 0) 1467eebffd3STakashi Iwai spec->auto_mute_via_amp = !!val; 1471c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "need_dac_fix"); 1481c70a583STakashi Iwai if (val >= 0) 1491c70a583STakashi Iwai spec->need_dac_fix = !!val; 1501c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "primary_hp"); 1511c70a583STakashi Iwai if (val >= 0) 1521c70a583STakashi Iwai spec->no_primary_hp = !val; 153da96fb5bSTakashi Iwai val = snd_hda_get_bool_hint(codec, "multi_io"); 154da96fb5bSTakashi Iwai if (val >= 0) 155da96fb5bSTakashi Iwai spec->no_multi_io = !val; 1561c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); 1571c70a583STakashi Iwai if (val >= 0) 1581c70a583STakashi Iwai spec->multi_cap_vol = !!val; 1591c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_dmic_split"); 1601c70a583STakashi Iwai if (val >= 0) 1611c70a583STakashi Iwai spec->inv_dmic_split = !!val; 1621c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "indep_hp"); 1631c70a583STakashi Iwai if (val >= 0) 1641c70a583STakashi Iwai spec->indep_hp = !!val; 1651c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input"); 1661c70a583STakashi Iwai if (val >= 0) 1671c70a583STakashi Iwai spec->add_stereo_mix_input = !!val; 168f811c3cfSTakashi Iwai /* the following two are just for compatibility */ 1691c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_out_jack_modes"); 1701c70a583STakashi Iwai if (val >= 0) 171f811c3cfSTakashi Iwai spec->add_jack_modes = !!val; 17229476558STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_in_jack_modes"); 17329476558STakashi Iwai if (val >= 0) 174f811c3cfSTakashi Iwai spec->add_jack_modes = !!val; 175f811c3cfSTakashi Iwai val = snd_hda_get_bool_hint(codec, "add_jack_modes"); 176f811c3cfSTakashi Iwai if (val >= 0) 177f811c3cfSTakashi Iwai spec->add_jack_modes = !!val; 17855196fffSTakashi Iwai val = snd_hda_get_bool_hint(codec, "power_down_unused"); 17955196fffSTakashi Iwai if (val >= 0) 18055196fffSTakashi Iwai spec->power_down_unused = !!val; 181967303daSTakashi Iwai val = snd_hda_get_bool_hint(codec, "add_hp_mic"); 182967303daSTakashi Iwai if (val >= 0) 183967303daSTakashi Iwai spec->hp_mic = !!val; 184967303daSTakashi Iwai val = snd_hda_get_bool_hint(codec, "hp_mic_detect"); 185967303daSTakashi Iwai if (val >= 0) 186967303daSTakashi Iwai spec->suppress_hp_mic_detect = !val; 1877480316cSTakashi Iwai val = snd_hda_get_bool_hint(codec, "vmaster"); 1887480316cSTakashi Iwai if (val >= 0) 1897480316cSTakashi Iwai spec->suppress_vmaster = !val; 1901c70a583STakashi Iwai 1911c70a583STakashi Iwai if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) 1921c70a583STakashi Iwai spec->mixer_nid = val; 1931c70a583STakashi Iwai } 1941c70a583STakashi Iwai 1951c70a583STakashi Iwai /* 1962c12c30dSTakashi Iwai * pin control value accesses 1972c12c30dSTakashi Iwai */ 1982c12c30dSTakashi Iwai 1992c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \ 200401caff7STakashi Iwai snd_hda_codec_write_cache(codec, pin, 0, \ 2012c12c30dSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, val) 2022c12c30dSTakashi Iwai 2032c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */ 2042c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin) 2052c12c30dSTakashi Iwai { 2062c12c30dSTakashi Iwai update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin)); 2072c12c30dSTakashi Iwai } 2082c12c30dSTakashi Iwai 2092c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */ 2102c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin, 2112c12c30dSTakashi Iwai unsigned int val, bool do_write) 2122c12c30dSTakashi Iwai { 2132c12c30dSTakashi Iwai if (!pin) 2142c12c30dSTakashi Iwai return; 2152c12c30dSTakashi Iwai val = snd_hda_correct_pin_ctl(codec, pin, val); 2162c12c30dSTakashi Iwai snd_hda_codec_set_pin_target(codec, pin, val); 2172c12c30dSTakashi Iwai if (do_write) 2182c12c30dSTakashi Iwai update_pin_ctl(codec, pin, val); 2192c12c30dSTakashi Iwai } 2202c12c30dSTakashi Iwai 2212c12c30dSTakashi Iwai /* set pinctl target values for all given pins */ 2222c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins, 2232c12c30dSTakashi Iwai hda_nid_t *pins, unsigned int val) 2242c12c30dSTakashi Iwai { 2252c12c30dSTakashi Iwai int i; 2262c12c30dSTakashi Iwai for (i = 0; i < num_pins; i++) 2272c12c30dSTakashi Iwai set_pin_target(codec, pins[i], val, false); 2282c12c30dSTakashi Iwai } 2292c12c30dSTakashi Iwai 2302c12c30dSTakashi Iwai /* 231352f7f91STakashi Iwai * parsing paths 2321da177e4SLinus Torvalds */ 2331da177e4SLinus Torvalds 2343ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */ 2353ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 2363ca529d3STakashi Iwai { 2373ca529d3STakashi Iwai int i; 2383ca529d3STakashi Iwai for (i = 0; i < nums; i++) 2393ca529d3STakashi Iwai if (list[i] == nid) 2403ca529d3STakashi Iwai return i; 2413ca529d3STakashi Iwai return -1; 2423ca529d3STakashi Iwai } 2433ca529d3STakashi Iwai 2443ca529d3STakashi Iwai /* return true if the given NID is contained in the path */ 2453ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid) 2463ca529d3STakashi Iwai { 2473ca529d3STakashi Iwai return find_idx_in_nid_list(nid, path->path, path->depth) >= 0; 2483ca529d3STakashi Iwai } 2493ca529d3STakashi Iwai 250f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec, 251f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 2523ca529d3STakashi Iwai int anchor_nid) 2531da177e4SLinus Torvalds { 254352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 255a9c2dfc8STakashi Iwai struct nid_path *path; 256352f7f91STakashi Iwai int i; 2571da177e4SLinus Torvalds 258a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, i, path) { 259352f7f91STakashi Iwai if (path->depth <= 0) 260352f7f91STakashi Iwai continue; 261352f7f91STakashi Iwai if ((!from_nid || path->path[0] == from_nid) && 262f5172a7eSTakashi Iwai (!to_nid || path->path[path->depth - 1] == to_nid)) { 2633ca529d3STakashi Iwai if (!anchor_nid || 2643ca529d3STakashi Iwai (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) || 2653ca529d3STakashi Iwai (anchor_nid < 0 && !is_nid_contained(path, anchor_nid))) 266352f7f91STakashi Iwai return path; 2671da177e4SLinus Torvalds } 268f5172a7eSTakashi Iwai } 2691da177e4SLinus Torvalds return NULL; 2701da177e4SLinus Torvalds } 271f5172a7eSTakashi Iwai 272dda42bd0STakashi Iwai /** 273dda42bd0STakashi Iwai * snd_hda_get_path_idx - get the index number corresponding to the path 274dda42bd0STakashi Iwai * instance 275dda42bd0STakashi Iwai * @codec: the HDA codec 276dda42bd0STakashi Iwai * @path: nid_path object 277dda42bd0STakashi Iwai * 278dda42bd0STakashi Iwai * The returned index starts from 1, i.e. the actual array index with offset 1, 279dda42bd0STakashi Iwai * and zero is handled as an invalid path 280196c1766STakashi Iwai */ 281196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) 282196c1766STakashi Iwai { 283196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 284196c1766STakashi Iwai struct nid_path *array = spec->paths.list; 285196c1766STakashi Iwai ssize_t idx; 286196c1766STakashi Iwai 287196c1766STakashi Iwai if (!spec->paths.used) 288196c1766STakashi Iwai return 0; 289196c1766STakashi Iwai idx = path - array; 290196c1766STakashi Iwai if (idx < 0 || idx >= spec->paths.used) 291196c1766STakashi Iwai return 0; 292196c1766STakashi Iwai return idx + 1; 293196c1766STakashi Iwai } 2942698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_path_idx); 295196c1766STakashi Iwai 296dda42bd0STakashi Iwai /** 297dda42bd0STakashi Iwai * snd_hda_get_path_from_idx - get the path instance corresponding to the 298dda42bd0STakashi Iwai * given index number 299dda42bd0STakashi Iwai * @codec: the HDA codec 300dda42bd0STakashi Iwai * @idx: the path index 301dda42bd0STakashi Iwai */ 302196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) 303196c1766STakashi Iwai { 304196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 305196c1766STakashi Iwai 306196c1766STakashi Iwai if (idx <= 0 || idx > spec->paths.used) 307196c1766STakashi Iwai return NULL; 308196c1766STakashi Iwai return snd_array_elem(&spec->paths, idx - 1); 309196c1766STakashi Iwai } 3102698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx); 311196c1766STakashi Iwai 312352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */ 313352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) 3141da177e4SLinus Torvalds { 315352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 316a9c2dfc8STakashi Iwai const struct nid_path *path; 317352f7f91STakashi Iwai int i; 318352f7f91STakashi Iwai 319a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, i, path) { 320352f7f91STakashi Iwai if (path->path[0] == nid) 321352f7f91STakashi Iwai return true; 322352f7f91STakashi Iwai } 323352f7f91STakashi Iwai return false; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 326352f7f91STakashi Iwai /* check whether the given two widgets can be connected */ 327352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec, 328352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 3291da177e4SLinus Torvalds { 330352f7f91STakashi Iwai if (!from_nid || !to_nid) 331352f7f91STakashi Iwai return false; 332352f7f91STakashi Iwai return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 335352f7f91STakashi Iwai /* nid, dir and idx */ 336352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) 337352f7f91STakashi Iwai 338352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */ 339352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) 3401da177e4SLinus Torvalds { 341352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 342a9c2dfc8STakashi Iwai const struct nid_path *path; 343352f7f91STakashi Iwai int i; 344352f7f91STakashi Iwai 345352f7f91STakashi Iwai val &= AMP_VAL_COMPARE_MASK; 346a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, i, path) { 347352f7f91STakashi Iwai if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) 348352f7f91STakashi Iwai return true; 349352f7f91STakashi Iwai } 350352f7f91STakashi Iwai return false; 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds 353352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */ 354352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, 3558999bf0aSTakashi Iwai int dir, int idx, int type) 356cb53c626STakashi Iwai { 357352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); 3588999bf0aSTakashi Iwai return is_ctl_used(codec, val, type); 359cb53c626STakashi Iwai } 360352f7f91STakashi Iwai 3614e76a883STakashi Iwai static void print_nid_path(struct hda_codec *codec, 3624e76a883STakashi Iwai const char *pfx, struct nid_path *path) 3630c8c0f56STakashi Iwai { 3640c8c0f56STakashi Iwai char buf[40]; 365d82353e5SJoe Perches char *pos = buf; 3660c8c0f56STakashi Iwai int i; 3670c8c0f56STakashi Iwai 368d82353e5SJoe Perches *pos = 0; 369d82353e5SJoe Perches for (i = 0; i < path->depth; i++) 370d82353e5SJoe Perches pos += scnprintf(pos, sizeof(buf) - (pos - buf), "%s%02x", 371d82353e5SJoe Perches pos != buf ? ":" : "", 372d82353e5SJoe Perches path->path[i]); 3730c8c0f56STakashi Iwai 374d82353e5SJoe Perches codec_dbg(codec, "%s path: depth=%d '%s'\n", pfx, path->depth, buf); 3750c8c0f56STakashi Iwai } 3760c8c0f56STakashi Iwai 377352f7f91STakashi Iwai /* called recursively */ 378352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec, 379352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 3803ca529d3STakashi Iwai int anchor_nid, struct nid_path *path, 3813ca529d3STakashi Iwai int depth) 382352f7f91STakashi Iwai { 383ee8e765bSTakashi Iwai const hda_nid_t *conn; 384352f7f91STakashi Iwai int i, nums; 385352f7f91STakashi Iwai 3863ca529d3STakashi Iwai if (to_nid == anchor_nid) 3873ca529d3STakashi Iwai anchor_nid = 0; /* anchor passed */ 3883ca529d3STakashi Iwai else if (to_nid == (hda_nid_t)(-anchor_nid)) 3893ca529d3STakashi Iwai return false; /* hit the exclusive nid */ 390352f7f91STakashi Iwai 391ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn); 392352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 393352f7f91STakashi Iwai if (conn[i] != from_nid) { 394352f7f91STakashi Iwai /* special case: when from_nid is 0, 395352f7f91STakashi Iwai * try to find an empty DAC 396352f7f91STakashi Iwai */ 397352f7f91STakashi Iwai if (from_nid || 398352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || 399352f7f91STakashi Iwai is_dac_already_used(codec, conn[i])) 400352f7f91STakashi Iwai continue; 401352f7f91STakashi Iwai } 4023ca529d3STakashi Iwai /* anchor is not requested or already passed? */ 4033ca529d3STakashi Iwai if (anchor_nid <= 0) 404352f7f91STakashi Iwai goto found; 405352f7f91STakashi Iwai } 406352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH) 407352f7f91STakashi Iwai return false; 408352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 409352f7f91STakashi Iwai unsigned int type; 410352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i])); 411352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || 412352f7f91STakashi Iwai type == AC_WID_PIN) 413352f7f91STakashi Iwai continue; 414352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i], 4153ca529d3STakashi Iwai anchor_nid, path, depth + 1)) 416352f7f91STakashi Iwai goto found; 417352f7f91STakashi Iwai } 418352f7f91STakashi Iwai return false; 419352f7f91STakashi Iwai 420352f7f91STakashi Iwai found: 421352f7f91STakashi Iwai path->path[path->depth] = conn[i]; 422352f7f91STakashi Iwai path->idx[path->depth + 1] = i; 423352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) 424352f7f91STakashi Iwai path->multi[path->depth + 1] = 1; 425352f7f91STakashi Iwai path->depth++; 426352f7f91STakashi Iwai return true; 427352f7f91STakashi Iwai } 428352f7f91STakashi Iwai 429c4a58c30STakashi Iwai /* 430dda42bd0STakashi Iwai * snd_hda_parse_nid_path - parse the widget path from the given nid to 431dda42bd0STakashi Iwai * the target nid 432dda42bd0STakashi Iwai * @codec: the HDA codec 433dda42bd0STakashi Iwai * @from_nid: the NID where the path start from 434dda42bd0STakashi Iwai * @to_nid: the NID where the path ends at 435dda42bd0STakashi Iwai * @anchor_nid: the anchor indication 436dda42bd0STakashi Iwai * @path: the path object to store the result 437dda42bd0STakashi Iwai * 438dda42bd0STakashi Iwai * Returns true if a matching path is found. 439dda42bd0STakashi Iwai * 440dda42bd0STakashi Iwai * The parsing behavior depends on parameters: 441352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC; 4423ca529d3STakashi Iwai * when @anchor_nid is set to a positive value, only paths through the widget 4433ca529d3STakashi Iwai * with the given value are evaluated. 4443ca529d3STakashi Iwai * when @anchor_nid is set to a negative value, paths through the widget 4453ca529d3STakashi Iwai * with the negative of given value are excluded, only other paths are chosen. 4463ca529d3STakashi Iwai * when @anchor_nid is zero, no special handling about path selection. 447352f7f91STakashi Iwai */ 448c4a58c30STakashi Iwai static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, 4493ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid, 450352f7f91STakashi Iwai struct nid_path *path) 451352f7f91STakashi Iwai { 4523ca529d3STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) { 453352f7f91STakashi Iwai path->path[path->depth] = to_nid; 454352f7f91STakashi Iwai path->depth++; 455352f7f91STakashi Iwai return true; 456352f7f91STakashi Iwai } 457352f7f91STakashi Iwai return false; 458352f7f91STakashi Iwai } 459352f7f91STakashi Iwai 460dda42bd0STakashi Iwai /** 461dda42bd0STakashi Iwai * snd_hda_add_new_path - parse the path between the given NIDs and 462dda42bd0STakashi Iwai * add to the path list 463dda42bd0STakashi Iwai * @codec: the HDA codec 464dda42bd0STakashi Iwai * @from_nid: the NID where the path start from 465dda42bd0STakashi Iwai * @to_nid: the NID where the path ends at 466dda42bd0STakashi Iwai * @anchor_nid: the anchor indication, see snd_hda_parse_nid_path() 467dda42bd0STakashi Iwai * 468dda42bd0STakashi Iwai * If no valid path is found, returns NULL. 469352f7f91STakashi Iwai */ 470352f7f91STakashi Iwai struct nid_path * 471352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, 4723ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid) 473352f7f91STakashi Iwai { 474352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 475352f7f91STakashi Iwai struct nid_path *path; 476352f7f91STakashi Iwai 477352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) 478352f7f91STakashi Iwai return NULL; 479352f7f91STakashi Iwai 480f5172a7eSTakashi Iwai /* check whether the path has been already added */ 4813ca529d3STakashi Iwai path = get_nid_path(codec, from_nid, to_nid, anchor_nid); 482f5172a7eSTakashi Iwai if (path) 483f5172a7eSTakashi Iwai return path; 484f5172a7eSTakashi Iwai 485352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 486352f7f91STakashi Iwai if (!path) 487352f7f91STakashi Iwai return NULL; 488352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 4893ca529d3STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path)) 490352f7f91STakashi Iwai return path; 491352f7f91STakashi Iwai /* push back */ 492352f7f91STakashi Iwai spec->paths.used--; 493352f7f91STakashi Iwai return NULL; 494352f7f91STakashi Iwai } 4952698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_add_new_path); 496352f7f91STakashi Iwai 497980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */ 498980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx) 499980428ceSTakashi Iwai { 500980428ceSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, idx); 501980428ceSTakashi Iwai if (!path) 502980428ceSTakashi Iwai return; 503980428ceSTakashi Iwai memset(path, 0, sizeof(*path)); 504980428ceSTakashi Iwai } 505980428ceSTakashi Iwai 5063690739bSTakashi Iwai /* return a DAC if paired to the given pin by codec driver */ 5073690739bSTakashi Iwai static hda_nid_t get_preferred_dac(struct hda_codec *codec, hda_nid_t pin) 5083690739bSTakashi Iwai { 5093690739bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 5103690739bSTakashi Iwai const hda_nid_t *list = spec->preferred_dacs; 5113690739bSTakashi Iwai 5123690739bSTakashi Iwai if (!list) 5133690739bSTakashi Iwai return 0; 5143690739bSTakashi Iwai for (; *list; list += 2) 5153690739bSTakashi Iwai if (*list == pin) 5163690739bSTakashi Iwai return list[1]; 5173690739bSTakashi Iwai return 0; 5183690739bSTakashi Iwai } 5193690739bSTakashi Iwai 520352f7f91STakashi Iwai /* look for an empty DAC slot */ 521352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, 522352f7f91STakashi Iwai bool is_digital) 523352f7f91STakashi Iwai { 524352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 525352f7f91STakashi Iwai bool cap_digital; 526352f7f91STakashi Iwai int i; 527352f7f91STakashi Iwai 528352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 529352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 530352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 531352f7f91STakashi Iwai continue; 532352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); 533352f7f91STakashi Iwai if (is_digital != cap_digital) 534352f7f91STakashi Iwai continue; 535352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) 536352f7f91STakashi Iwai return nid; 537352f7f91STakashi Iwai } 538352f7f91STakashi Iwai return 0; 539352f7f91STakashi Iwai } 540352f7f91STakashi Iwai 541352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */ 542352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) 543352f7f91STakashi Iwai { 544352f7f91STakashi Iwai val &= ~(0x3U << 16); 545352f7f91STakashi Iwai val |= chs << 16; 546352f7f91STakashi Iwai return val; 547352f7f91STakashi Iwai } 548352f7f91STakashi Iwai 54999a5592dSDavid Henningsson static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1, 55099a5592dSDavid Henningsson hda_nid_t nid2, int dir) 55199a5592dSDavid Henningsson { 55299a5592dSDavid Henningsson if (!(get_wcaps(codec, nid1) & (1 << (dir + 1)))) 55399a5592dSDavid Henningsson return !(get_wcaps(codec, nid2) & (1 << (dir + 1))); 55499a5592dSDavid Henningsson return (query_amp_caps(codec, nid1, dir) == 55599a5592dSDavid Henningsson query_amp_caps(codec, nid2, dir)); 55699a5592dSDavid Henningsson } 55799a5592dSDavid Henningsson 558352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */ 559352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, 560352f7f91STakashi Iwai struct nid_path *path) 561352f7f91STakashi Iwai { 562352f7f91STakashi Iwai int i; 563352f7f91STakashi Iwai 564352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 565352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) 566352f7f91STakashi Iwai return path->path[i]; 567352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 && 568352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT)) 569352f7f91STakashi Iwai return path->path[i]; 570352f7f91STakashi Iwai } 571352f7f91STakashi Iwai return 0; 572352f7f91STakashi Iwai } 573352f7f91STakashi Iwai 574352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */ 575352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, 576352f7f91STakashi Iwai struct nid_path *path) 577352f7f91STakashi Iwai { 578a1114a8cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 579352f7f91STakashi Iwai int i; 580352f7f91STakashi Iwai 581352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 582a1114a8cSTakashi Iwai hda_nid_t nid = path->path[i]; 583a1114a8cSTakashi Iwai if ((spec->out_vol_mask >> nid) & 1) 584a1114a8cSTakashi Iwai continue; 585a1114a8cSTakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 586a1114a8cSTakashi Iwai return nid; 587352f7f91STakashi Iwai } 588352f7f91STakashi Iwai return 0; 589352f7f91STakashi Iwai } 590352f7f91STakashi Iwai 591352f7f91STakashi Iwai /* 592352f7f91STakashi Iwai * path activation / deactivation 593352f7f91STakashi Iwai */ 594352f7f91STakashi Iwai 595352f7f91STakashi Iwai /* can have the amp-in capability? */ 596352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) 597352f7f91STakashi Iwai { 598352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 599352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 600352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 601352f7f91STakashi Iwai 602352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP)) 603352f7f91STakashi Iwai return false; 604352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */ 605352f7f91STakashi Iwai return false; 606352f7f91STakashi Iwai return true; 607352f7f91STakashi Iwai } 608352f7f91STakashi Iwai 609352f7f91STakashi Iwai /* can have the amp-out capability? */ 610352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) 611352f7f91STakashi Iwai { 612352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 613352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 614352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 615352f7f91STakashi Iwai 616352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP)) 617352f7f91STakashi Iwai return false; 618352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */ 619352f7f91STakashi Iwai return false; 620352f7f91STakashi Iwai return true; 621352f7f91STakashi Iwai } 622352f7f91STakashi Iwai 623352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */ 624352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, 6257dddf2aeSTakashi Iwai unsigned int dir, unsigned int idx) 626352f7f91STakashi Iwai { 627352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 628e6feb5d0STakashi Iwai int type = get_wcaps_type(get_wcaps(codec, nid)); 629a9c2dfc8STakashi Iwai const struct nid_path *path; 630352f7f91STakashi Iwai int i, n; 631352f7f91STakashi Iwai 6327639a06cSTakashi Iwai if (nid == codec->core.afg) 6335ccf835cSTakashi Iwai return true; 6345ccf835cSTakashi Iwai 635a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, n, path) { 636352f7f91STakashi Iwai if (!path->active) 637352f7f91STakashi Iwai continue; 638967b1307STakashi Iwai if (codec->power_save_node) { 639e6feb5d0STakashi Iwai if (!path->stream_enabled) 640e6feb5d0STakashi Iwai continue; 641e6feb5d0STakashi Iwai /* ignore unplugged paths except for DAC/ADC */ 6426b275b14STakashi Iwai if (!(path->pin_enabled || path->pin_fixed) && 643e6feb5d0STakashi Iwai type != AC_WID_AUD_OUT && type != AC_WID_AUD_IN) 644e6feb5d0STakashi Iwai continue; 645e6feb5d0STakashi Iwai } 646352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) { 647352f7f91STakashi Iwai if (path->path[i] == nid) { 6489d2b48f7STakashi Iwai if (dir == HDA_OUTPUT || idx == -1 || 6499d2b48f7STakashi Iwai path->idx[i] == idx) 650352f7f91STakashi Iwai return true; 651352f7f91STakashi Iwai break; 652352f7f91STakashi Iwai } 653352f7f91STakashi Iwai } 654352f7f91STakashi Iwai } 655352f7f91STakashi Iwai return false; 656352f7f91STakashi Iwai } 657352f7f91STakashi Iwai 658b1b9fbd0STakashi Iwai /* check whether the NID is referred by any active paths */ 659b1b9fbd0STakashi Iwai #define is_active_nid_for_any(codec, nid) \ 6609d2b48f7STakashi Iwai is_active_nid(codec, nid, HDA_OUTPUT, -1) 661b1b9fbd0STakashi Iwai 662352f7f91STakashi Iwai /* get the default amp value for the target state */ 663352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, 6648999bf0aSTakashi Iwai int dir, unsigned int caps, bool enable) 665352f7f91STakashi Iwai { 666352f7f91STakashi Iwai unsigned int val = 0; 667352f7f91STakashi Iwai 668352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 669352f7f91STakashi Iwai /* set to 0dB */ 670352f7f91STakashi Iwai if (enable) 671352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 672352f7f91STakashi Iwai } 673f69910ddSTakashi Iwai if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) { 674352f7f91STakashi Iwai if (!enable) 675352f7f91STakashi Iwai val |= HDA_AMP_MUTE; 676352f7f91STakashi Iwai } 677352f7f91STakashi Iwai return val; 678352f7f91STakashi Iwai } 679352f7f91STakashi Iwai 680cc261738STakashi Iwai /* is this a stereo widget or a stereo-to-mono mix? */ 681cc261738STakashi Iwai static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir) 682cc261738STakashi Iwai { 683cc261738STakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 684cc261738STakashi Iwai hda_nid_t conn; 685cc261738STakashi Iwai 686cc261738STakashi Iwai if (wcaps & AC_WCAP_STEREO) 687cc261738STakashi Iwai return true; 688cc261738STakashi Iwai if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX) 689cc261738STakashi Iwai return false; 690cc261738STakashi Iwai if (snd_hda_get_num_conns(codec, nid) != 1) 691cc261738STakashi Iwai return false; 692cc261738STakashi Iwai if (snd_hda_get_connections(codec, nid, &conn, 1) < 0) 693cc261738STakashi Iwai return false; 694cc261738STakashi Iwai return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO); 695cc261738STakashi Iwai } 696cc261738STakashi Iwai 697352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */ 698352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 699352f7f91STakashi Iwai { 7008999bf0aSTakashi Iwai unsigned int caps = query_amp_caps(codec, nid, dir); 7018999bf0aSTakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, caps, false); 702ef403edbSTakashi Iwai 703cc261738STakashi Iwai if (is_stereo_amps(codec, nid, dir)) 704352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 705ef403edbSTakashi Iwai else 706ef403edbSTakashi Iwai snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val); 707ef403edbSTakashi Iwai } 708ef403edbSTakashi Iwai 709ef403edbSTakashi Iwai /* update the amp, doing in stereo or mono depending on NID */ 710ef403edbSTakashi Iwai static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, 711ef403edbSTakashi Iwai unsigned int mask, unsigned int val) 712ef403edbSTakashi Iwai { 713cc261738STakashi Iwai if (is_stereo_amps(codec, nid, dir)) 714ef403edbSTakashi Iwai return snd_hda_codec_amp_stereo(codec, nid, dir, idx, 715ef403edbSTakashi Iwai mask, val); 716ef403edbSTakashi Iwai else 717ef403edbSTakashi Iwai return snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 718ef403edbSTakashi Iwai mask, val); 719352f7f91STakashi Iwai } 720352f7f91STakashi Iwai 7218999bf0aSTakashi Iwai /* calculate amp value mask we can modify; 7228999bf0aSTakashi Iwai * if the given amp is controlled by mixers, don't touch it 7238999bf0aSTakashi Iwai */ 7248999bf0aSTakashi Iwai static unsigned int get_amp_mask_to_modify(struct hda_codec *codec, 7258999bf0aSTakashi Iwai hda_nid_t nid, int dir, int idx, 7268999bf0aSTakashi Iwai unsigned int caps) 727352f7f91STakashi Iwai { 7288999bf0aSTakashi Iwai unsigned int mask = 0xff; 7298999bf0aSTakashi Iwai 730f69910ddSTakashi Iwai if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) { 7318999bf0aSTakashi Iwai if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL)) 7328999bf0aSTakashi Iwai mask &= ~0x80; 7338999bf0aSTakashi Iwai } 7348999bf0aSTakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 7358999bf0aSTakashi Iwai if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || 7368999bf0aSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) 7378999bf0aSTakashi Iwai mask &= ~0x7f; 7388999bf0aSTakashi Iwai } 7398999bf0aSTakashi Iwai return mask; 7408999bf0aSTakashi Iwai } 7418999bf0aSTakashi Iwai 7428999bf0aSTakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, 7438999bf0aSTakashi Iwai int idx, int idx_to_check, bool enable) 7448999bf0aSTakashi Iwai { 7458999bf0aSTakashi Iwai unsigned int caps; 7468999bf0aSTakashi Iwai unsigned int mask, val; 7478999bf0aSTakashi Iwai 7488999bf0aSTakashi Iwai caps = query_amp_caps(codec, nid, dir); 7498999bf0aSTakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, caps, enable); 7508999bf0aSTakashi Iwai mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); 7518999bf0aSTakashi Iwai if (!mask) 7528999bf0aSTakashi Iwai return; 7538999bf0aSTakashi Iwai 7548999bf0aSTakashi Iwai val &= mask; 755ef403edbSTakashi Iwai update_amp(codec, nid, dir, idx, mask, val); 756352f7f91STakashi Iwai } 757352f7f91STakashi Iwai 758e7fdd527STakashi Iwai static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid, 759e7fdd527STakashi Iwai int dir, int idx, int idx_to_check, 760e7fdd527STakashi Iwai bool enable) 761e7fdd527STakashi Iwai { 762e7fdd527STakashi Iwai /* check whether the given amp is still used by others */ 763e7fdd527STakashi Iwai if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) 764e7fdd527STakashi Iwai return; 765e7fdd527STakashi Iwai activate_amp(codec, nid, dir, idx, idx_to_check, enable); 766e7fdd527STakashi Iwai } 767e7fdd527STakashi Iwai 768352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, 769352f7f91STakashi Iwai int i, bool enable) 770352f7f91STakashi Iwai { 771352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 772352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0); 773e7fdd527STakashi Iwai check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); 774352f7f91STakashi Iwai } 775352f7f91STakashi Iwai 776352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, 777352f7f91STakashi Iwai int i, bool enable, bool add_aamix) 778352f7f91STakashi Iwai { 779352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 780ee8e765bSTakashi Iwai const hda_nid_t *conn; 781352f7f91STakashi Iwai int n, nums, idx; 782352f7f91STakashi Iwai int type; 783352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 784352f7f91STakashi Iwai 785ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn); 7860de7d835SDan Carpenter if (nums < 0) 7870de7d835SDan Carpenter return; 788352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 789352f7f91STakashi Iwai if (type == AC_WID_PIN || 790352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) { 791352f7f91STakashi Iwai nums = 1; 792352f7f91STakashi Iwai idx = 0; 793352f7f91STakashi Iwai } else 794352f7f91STakashi Iwai idx = path->idx[i]; 795352f7f91STakashi Iwai 796352f7f91STakashi Iwai for (n = 0; n < nums; n++) 797352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n); 798352f7f91STakashi Iwai 799352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out(); 800352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well 801352f7f91STakashi Iwai */ 802352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 803e7fdd527STakashi Iwai if (n != idx) { 804e7fdd527STakashi Iwai if (conn[n] != spec->mixer_merge_nid) 805352f7f91STakashi Iwai continue; 806e7fdd527STakashi Iwai /* when aamix is disabled, force to off */ 807e7fdd527STakashi Iwai if (!add_aamix) { 808e7fdd527STakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, n, false); 809e7fdd527STakashi Iwai continue; 810e7fdd527STakashi Iwai } 811e7fdd527STakashi Iwai } 812e7fdd527STakashi Iwai check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable); 813352f7f91STakashi Iwai } 814352f7f91STakashi Iwai } 815352f7f91STakashi Iwai 816e6feb5d0STakashi Iwai /* sync power of each widget in the the given path */ 817e6feb5d0STakashi Iwai static hda_nid_t path_power_update(struct hda_codec *codec, 818e6feb5d0STakashi Iwai struct nid_path *path, 819e6feb5d0STakashi Iwai bool allow_powerdown) 820e6feb5d0STakashi Iwai { 821e6feb5d0STakashi Iwai hda_nid_t nid, changed = 0; 82250fd4987STakashi Iwai int i, state, power; 823e6feb5d0STakashi Iwai 824e6feb5d0STakashi Iwai for (i = 0; i < path->depth; i++) { 825e6feb5d0STakashi Iwai nid = path->path[i]; 8262206dc94STakashi Iwai if (!(get_wcaps(codec, nid) & AC_WCAP_POWER)) 8272206dc94STakashi Iwai continue; 8287639a06cSTakashi Iwai if (nid == codec->core.afg) 8295ccf835cSTakashi Iwai continue; 830e6feb5d0STakashi Iwai if (!allow_powerdown || is_active_nid_for_any(codec, nid)) 831e6feb5d0STakashi Iwai state = AC_PWRST_D0; 832e6feb5d0STakashi Iwai else 833e6feb5d0STakashi Iwai state = AC_PWRST_D3; 83450fd4987STakashi Iwai power = snd_hda_codec_read(codec, nid, 0, 83550fd4987STakashi Iwai AC_VERB_GET_POWER_STATE, 0); 83650fd4987STakashi Iwai if (power != (state | (state << 4))) { 837e6feb5d0STakashi Iwai snd_hda_codec_write(codec, nid, 0, 838e6feb5d0STakashi Iwai AC_VERB_SET_POWER_STATE, state); 839e6feb5d0STakashi Iwai changed = nid; 84048f4b3a2STakashi Iwai /* all known codecs seem to be capable to handl 84148f4b3a2STakashi Iwai * widgets state even in D3, so far. 84248f4b3a2STakashi Iwai * if any new codecs need to restore the widget 84348f4b3a2STakashi Iwai * states after D0 transition, call the function 84448f4b3a2STakashi Iwai * below. 84548f4b3a2STakashi Iwai */ 84648f4b3a2STakashi Iwai #if 0 /* disabled */ 847d545a57cSTakashi Iwai if (state == AC_PWRST_D0) 848d545a57cSTakashi Iwai snd_hdac_regmap_sync_node(&codec->core, nid); 84948f4b3a2STakashi Iwai #endif 850e6feb5d0STakashi Iwai } 851e6feb5d0STakashi Iwai } 852e6feb5d0STakashi Iwai return changed; 853e6feb5d0STakashi Iwai } 854e6feb5d0STakashi Iwai 855e6feb5d0STakashi Iwai /* do sync with the last power state change */ 856e6feb5d0STakashi Iwai static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid) 857e6feb5d0STakashi Iwai { 858e6feb5d0STakashi Iwai if (nid) { 859e6feb5d0STakashi Iwai msleep(10); 860e6feb5d0STakashi Iwai snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); 861e6feb5d0STakashi Iwai } 862e6feb5d0STakashi Iwai } 863e6feb5d0STakashi Iwai 864dda42bd0STakashi Iwai /** 865dda42bd0STakashi Iwai * snd_hda_activate_path - activate or deactivate the given path 866dda42bd0STakashi Iwai * @codec: the HDA codec 867dda42bd0STakashi Iwai * @path: the path to activate/deactivate 868dda42bd0STakashi Iwai * @enable: flag to activate or not 869dda42bd0STakashi Iwai * @add_aamix: enable the input from aamix NID 870dda42bd0STakashi Iwai * 871dda42bd0STakashi Iwai * If @add_aamix is set, enable the input from aa-mix NID as well (if any). 872352f7f91STakashi Iwai */ 873352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, 874352f7f91STakashi Iwai bool enable, bool add_aamix) 875352f7f91STakashi Iwai { 87655196fffSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 877352f7f91STakashi Iwai int i; 878352f7f91STakashi Iwai 879c7cd0ef6STakashi Iwai path->active = enable; 880352f7f91STakashi Iwai 881e6feb5d0STakashi Iwai /* make sure the widget is powered up */ 882967b1307STakashi Iwai if (enable && (spec->power_down_unused || codec->power_save_node)) 883967b1307STakashi Iwai path_power_update(codec, path, codec->power_save_node); 884e6feb5d0STakashi Iwai 885352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 88655196fffSTakashi Iwai hda_nid_t nid = path->path[i]; 887e6feb5d0STakashi Iwai 888352f7f91STakashi Iwai if (enable && path->multi[i]) 889401caff7STakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 890352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL, 891352f7f91STakashi Iwai path->idx[i]); 892352f7f91STakashi Iwai if (has_amp_in(codec, path, i)) 893352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix); 894352f7f91STakashi Iwai if (has_amp_out(codec, path, i)) 895352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable); 896352f7f91STakashi Iwai } 897352f7f91STakashi Iwai } 8982698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_activate_path); 899352f7f91STakashi Iwai 90055196fffSTakashi Iwai /* if the given path is inactive, put widgets into D3 (only if suitable) */ 90155196fffSTakashi Iwai static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path) 90255196fffSTakashi Iwai { 90355196fffSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 90455196fffSTakashi Iwai 905967b1307STakashi Iwai if (!(spec->power_down_unused || codec->power_save_node) || path->active) 90655196fffSTakashi Iwai return; 907e6feb5d0STakashi Iwai sync_power_state_change(codec, path_power_update(codec, path, true)); 90855196fffSTakashi Iwai } 90955196fffSTakashi Iwai 910d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */ 911d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) 912d5a9f1bbSTakashi Iwai { 913d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 914d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl || 915d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) 916d5a9f1bbSTakashi Iwai return; 91705909d5cSTakashi Iwai if (spec->keep_eapd_on && !enable) 91805909d5cSTakashi Iwai return; 919468ac413STakashi Iwai if (codec->inv_eapd) 920468ac413STakashi Iwai enable = !enable; 921401caff7STakashi Iwai snd_hda_codec_write_cache(codec, pin, 0, 922d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE, 923d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00); 924d5a9f1bbSTakashi Iwai } 925d5a9f1bbSTakashi Iwai 9263e367f15STakashi Iwai /* re-initialize the path specified by the given path index */ 9273e367f15STakashi Iwai static void resume_path_from_idx(struct hda_codec *codec, int path_idx) 9283e367f15STakashi Iwai { 9293e367f15STakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); 9303e367f15STakashi Iwai if (path) 9313e367f15STakashi Iwai snd_hda_activate_path(codec, path, path->active, false); 9323e367f15STakashi Iwai } 9333e367f15STakashi Iwai 934352f7f91STakashi Iwai 935352f7f91STakashi Iwai /* 936352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements 937352f7f91STakashi Iwai */ 938352f7f91STakashi Iwai 9397eebffd3STakashi Iwai static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, 9407eebffd3STakashi Iwai struct snd_ctl_elem_value *ucontrol); 941698f5ee3STakashi Iwai static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol, 942698f5ee3STakashi Iwai struct snd_ctl_elem_value *ucontrol); 943bc2eee29STakashi Iwai static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, 944bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol); 9457eebffd3STakashi Iwai 946352f7f91STakashi Iwai enum { 947352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL, 948352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE, 949352f7f91STakashi Iwai HDA_CTL_BIND_MUTE, 950352f7f91STakashi Iwai }; 951352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = { 952352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0), 9537eebffd3STakashi Iwai /* only the put callback is replaced for handling the special mute */ 9547eebffd3STakashi Iwai { 9557eebffd3STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 9567eebffd3STakashi Iwai .subdevice = HDA_SUBDEV_AMP_FLAG, 9577eebffd3STakashi Iwai .info = snd_hda_mixer_amp_switch_info, 9587eebffd3STakashi Iwai .get = snd_hda_mixer_amp_switch_get, 9597eebffd3STakashi Iwai .put = hda_gen_mixer_mute_put, /* replaced */ 9607eebffd3STakashi Iwai .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), 9617eebffd3STakashi Iwai }, 962bc2eee29STakashi Iwai { 963bc2eee29STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 964bc2eee29STakashi Iwai .info = snd_hda_mixer_amp_switch_info, 965698f5ee3STakashi Iwai .get = hda_gen_bind_mute_get, 966bc2eee29STakashi Iwai .put = hda_gen_bind_mute_put, /* replaced */ 967bc2eee29STakashi Iwai .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), 968bc2eee29STakashi Iwai }, 969352f7f91STakashi Iwai }; 970352f7f91STakashi Iwai 971352f7f91STakashi Iwai /* add dynamic controls from template */ 972a35bd1e3STakashi Iwai static struct snd_kcontrol_new * 973a35bd1e3STakashi Iwai add_control(struct hda_gen_spec *spec, int type, const char *name, 974352f7f91STakashi Iwai int cidx, unsigned long val) 975352f7f91STakashi Iwai { 976352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 977352f7f91STakashi Iwai 97812c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); 979352f7f91STakashi Iwai if (!knew) 980a35bd1e3STakashi Iwai return NULL; 981352f7f91STakashi Iwai knew->index = cidx; 982352f7f91STakashi Iwai if (get_amp_nid_(val)) 983352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 984352f7f91STakashi Iwai knew->private_value = val; 985a35bd1e3STakashi Iwai return knew; 986352f7f91STakashi Iwai } 987352f7f91STakashi Iwai 988352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type, 989352f7f91STakashi Iwai const char *pfx, const char *dir, 990352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val) 991352f7f91STakashi Iwai { 992975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 993352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 994a35bd1e3STakashi Iwai if (!add_control(spec, type, name, cidx, val)) 995a35bd1e3STakashi Iwai return -ENOMEM; 996a35bd1e3STakashi Iwai return 0; 997352f7f91STakashi Iwai } 998352f7f91STakashi Iwai 999352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \ 1000352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) 1001352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \ 1002352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) 1003352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ 1004352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) 1005352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 1006352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 1007352f7f91STakashi Iwai 1008352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, 1009352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 1010352f7f91STakashi Iwai { 1011352f7f91STakashi Iwai unsigned int val; 1012352f7f91STakashi Iwai if (!path) 1013352f7f91STakashi Iwai return 0; 1014352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL]; 1015352f7f91STakashi Iwai if (!val) 1016352f7f91STakashi Iwai return 0; 1017352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 1018352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); 1019352f7f91STakashi Iwai } 1020352f7f91STakashi Iwai 1021352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */ 1022352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, 1023352f7f91STakashi Iwai int type) 1024352f7f91STakashi Iwai { 1025352f7f91STakashi Iwai int chs = 1; /* mono (left only) */ 1026352f7f91STakashi Iwai if (path) { 1027352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]); 1028352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) 1029352f7f91STakashi Iwai chs = 3; /* stereo */ 1030352f7f91STakashi Iwai } 1031352f7f91STakashi Iwai return chs; 1032352f7f91STakashi Iwai } 1033352f7f91STakashi Iwai 1034352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, 1035352f7f91STakashi Iwai struct nid_path *path) 1036352f7f91STakashi Iwai { 1037352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); 1038352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path); 1039352f7f91STakashi Iwai } 1040352f7f91STakashi Iwai 1041352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget; 1042352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute 1043352f7f91STakashi Iwai */ 1044352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, 1045352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 1046352f7f91STakashi Iwai { 1047352f7f91STakashi Iwai unsigned int val; 1048352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE; 1049352f7f91STakashi Iwai 1050352f7f91STakashi Iwai if (!path) 1051352f7f91STakashi Iwai return 0; 1052352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL]; 1053352f7f91STakashi Iwai if (!val) 1054352f7f91STakashi Iwai return 0; 1055352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 1056352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) { 1057352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val); 1058352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid); 1059352f7f91STakashi Iwai if (nums > 1) { 1060352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE; 1061352f7f91STakashi Iwai val |= nums << 19; 1062352f7f91STakashi Iwai } 1063352f7f91STakashi Iwai } 1064352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 1065352f7f91STakashi Iwai } 1066352f7f91STakashi Iwai 1067352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx, 1068352f7f91STakashi Iwai int cidx, struct nid_path *path) 1069352f7f91STakashi Iwai { 1070352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); 1071352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path); 1072352f7f91STakashi Iwai } 1073352f7f91STakashi Iwai 10747eebffd3STakashi Iwai /* playback mute control with the software mute bit check */ 1075bc2eee29STakashi Iwai static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol, 10767eebffd3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10777eebffd3STakashi Iwai { 10787eebffd3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 10797eebffd3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 10807eebffd3STakashi Iwai 10817eebffd3STakashi Iwai if (spec->auto_mute_via_amp) { 10827eebffd3STakashi Iwai hda_nid_t nid = get_amp_nid(kcontrol); 10837eebffd3STakashi Iwai bool enabled = !((spec->mute_bits >> nid) & 1); 10847eebffd3STakashi Iwai ucontrol->value.integer.value[0] &= enabled; 10857eebffd3STakashi Iwai ucontrol->value.integer.value[1] &= enabled; 10867eebffd3STakashi Iwai } 1087bc2eee29STakashi Iwai } 10887eebffd3STakashi Iwai 1089bc2eee29STakashi Iwai static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, 1090bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1091bc2eee29STakashi Iwai { 1092bc2eee29STakashi Iwai sync_auto_mute_bits(kcontrol, ucontrol); 10937eebffd3STakashi Iwai return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 10947eebffd3STakashi Iwai } 10957eebffd3STakashi Iwai 1096698f5ee3STakashi Iwai /* 1097698f5ee3STakashi Iwai * Bound mute controls 1098698f5ee3STakashi Iwai */ 1099698f5ee3STakashi Iwai #define AMP_VAL_IDX_SHIFT 19 1100698f5ee3STakashi Iwai #define AMP_VAL_IDX_MASK (0x0f<<19) 1101698f5ee3STakashi Iwai 1102698f5ee3STakashi Iwai static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol, 1103698f5ee3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1104698f5ee3STakashi Iwai { 1105698f5ee3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1106698f5ee3STakashi Iwai unsigned long pval; 1107698f5ee3STakashi Iwai int err; 1108698f5ee3STakashi Iwai 1109698f5ee3STakashi Iwai mutex_lock(&codec->control_mutex); 1110698f5ee3STakashi Iwai pval = kcontrol->private_value; 1111698f5ee3STakashi Iwai kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ 1112698f5ee3STakashi Iwai err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); 1113698f5ee3STakashi Iwai kcontrol->private_value = pval; 1114698f5ee3STakashi Iwai mutex_unlock(&codec->control_mutex); 1115698f5ee3STakashi Iwai return err; 1116698f5ee3STakashi Iwai } 1117698f5ee3STakashi Iwai 1118bc2eee29STakashi Iwai static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, 1119bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1120bc2eee29STakashi Iwai { 1121698f5ee3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1122698f5ee3STakashi Iwai unsigned long pval; 1123698f5ee3STakashi Iwai int i, indices, err = 0, change = 0; 1124698f5ee3STakashi Iwai 1125bc2eee29STakashi Iwai sync_auto_mute_bits(kcontrol, ucontrol); 1126698f5ee3STakashi Iwai 1127698f5ee3STakashi Iwai mutex_lock(&codec->control_mutex); 1128698f5ee3STakashi Iwai pval = kcontrol->private_value; 1129698f5ee3STakashi Iwai indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; 1130698f5ee3STakashi Iwai for (i = 0; i < indices; i++) { 1131698f5ee3STakashi Iwai kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | 1132698f5ee3STakashi Iwai (i << AMP_VAL_IDX_SHIFT); 1133698f5ee3STakashi Iwai err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 1134698f5ee3STakashi Iwai if (err < 0) 1135698f5ee3STakashi Iwai break; 1136698f5ee3STakashi Iwai change |= err; 1137698f5ee3STakashi Iwai } 1138698f5ee3STakashi Iwai kcontrol->private_value = pval; 1139698f5ee3STakashi Iwai mutex_unlock(&codec->control_mutex); 1140698f5ee3STakashi Iwai return err < 0 ? err : change; 1141bc2eee29STakashi Iwai } 1142bc2eee29STakashi Iwai 1143247d85eeSTakashi Iwai /* any ctl assigned to the path with the given index? */ 1144247d85eeSTakashi Iwai static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) 1145247d85eeSTakashi Iwai { 1146247d85eeSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); 1147247d85eeSTakashi Iwai return path && path->ctls[ctl_type]; 1148247d85eeSTakashi Iwai } 1149247d85eeSTakashi Iwai 1150352f7f91STakashi Iwai static const char * const channel_name[4] = { 1151352f7f91STakashi Iwai "Front", "Surround", "CLFE", "Side" 1152352f7f91STakashi Iwai }; 1153352f7f91STakashi Iwai 1154352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */ 1155247d85eeSTakashi Iwai static const char *get_line_out_pfx(struct hda_codec *codec, int ch, 1156247d85eeSTakashi Iwai int *index, int ctl_type) 1157352f7f91STakashi Iwai { 1158247d85eeSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1159352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1160352f7f91STakashi Iwai 1161352f7f91STakashi Iwai *index = 0; 1162352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios && 11639f3dadb1STakashi Iwai !codec->force_pin_prefix && 1164247d85eeSTakashi Iwai !cfg->hp_outs && !cfg->speaker_outs) 1165352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 1166352f7f91STakashi Iwai 1167352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths, 1168352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present) 1169352f7f91STakashi Iwai */ 1170352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && 11719f3dadb1STakashi Iwai !codec->force_pin_prefix && 1172352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) 1173352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 1174352f7f91STakashi Iwai 1175247d85eeSTakashi Iwai /* multi-io channels */ 1176247d85eeSTakashi Iwai if (ch >= cfg->line_outs) 1177247d85eeSTakashi Iwai return channel_name[ch]; 1178247d85eeSTakashi Iwai 1179352f7f91STakashi Iwai switch (cfg->line_out_type) { 1180352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT: 1181247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with HP volume, 1182247d85eeSTakashi Iwai * don't name it as Speaker 1183247d85eeSTakashi Iwai */ 1184247d85eeSTakashi Iwai if (!ch && cfg->hp_outs && 1185247d85eeSTakashi Iwai !path_has_mixer(codec, spec->hp_paths[0], ctl_type)) 1186247d85eeSTakashi Iwai break; 1187352f7f91STakashi Iwai if (cfg->line_outs == 1) 1188352f7f91STakashi Iwai return "Speaker"; 1189352f7f91STakashi Iwai if (cfg->line_outs == 2) 1190352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker"; 1191352f7f91STakashi Iwai break; 1192352f7f91STakashi Iwai case AUTO_PIN_HP_OUT: 1193247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with spk volume, 1194247d85eeSTakashi Iwai * don't name it as Headphone 1195247d85eeSTakashi Iwai */ 1196247d85eeSTakashi Iwai if (!ch && cfg->speaker_outs && 1197247d85eeSTakashi Iwai !path_has_mixer(codec, spec->speaker_paths[0], ctl_type)) 1198247d85eeSTakashi Iwai break; 1199352f7f91STakashi Iwai /* for multi-io case, only the primary out */ 1200352f7f91STakashi Iwai if (ch && spec->multi_ios) 1201352f7f91STakashi Iwai break; 1202352f7f91STakashi Iwai *index = ch; 1203352f7f91STakashi Iwai return "Headphone"; 120403ad6a8cSDavid Henningsson case AUTO_PIN_LINE_OUT: 120503ad6a8cSDavid Henningsson /* This deals with the case where we have two DACs and 120603ad6a8cSDavid Henningsson * one LO, one HP and one Speaker */ 120703ad6a8cSDavid Henningsson if (!ch && cfg->speaker_outs && cfg->hp_outs) { 120803ad6a8cSDavid Henningsson bool hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type); 120903ad6a8cSDavid Henningsson bool spk_lo_shared = !path_has_mixer(codec, spec->speaker_paths[0], ctl_type); 121003ad6a8cSDavid Henningsson if (hp_lo_shared && spk_lo_shared) 121103ad6a8cSDavid Henningsson return spec->vmaster_mute.hook ? "PCM" : "Master"; 121203ad6a8cSDavid Henningsson if (hp_lo_shared) 121303ad6a8cSDavid Henningsson return "Headphone+LO"; 121403ad6a8cSDavid Henningsson if (spk_lo_shared) 121503ad6a8cSDavid Henningsson return "Speaker+LO"; 121603ad6a8cSDavid Henningsson } 1217247d85eeSTakashi Iwai } 1218247d85eeSTakashi Iwai 1219247d85eeSTakashi Iwai /* for a single channel output, we don't have to name the channel */ 1220352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios) 12213abb4f4dSDavid Henningsson return "Line Out"; 1222247d85eeSTakashi Iwai 1223352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) { 1224352f7f91STakashi Iwai snd_BUG(); 1225352f7f91STakashi Iwai return "PCM"; 1226352f7f91STakashi Iwai } 1227352f7f91STakashi Iwai 1228352f7f91STakashi Iwai return channel_name[ch]; 1229352f7f91STakashi Iwai } 1230352f7f91STakashi Iwai 1231352f7f91STakashi Iwai /* 1232352f7f91STakashi Iwai * Parse output paths 1233352f7f91STakashi Iwai */ 1234352f7f91STakashi Iwai 1235352f7f91STakashi Iwai /* badness definition */ 1236352f7f91STakashi Iwai enum { 1237352f7f91STakashi Iwai /* No primary DAC is found for the main output */ 1238352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000, 1239352f7f91STakashi Iwai /* No DAC is found for the extra output */ 1240352f7f91STakashi Iwai BAD_NO_DAC = 0x4000, 1241352f7f91STakashi Iwai /* No possible multi-ios */ 12421d739066STakashi Iwai BAD_MULTI_IO = 0x120, 1243352f7f91STakashi Iwai /* No individual DAC for extra output */ 1244352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102, 1245352f7f91STakashi Iwai /* No individual DAC for extra surrounds */ 1246352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101, 1247352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */ 1248352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100, 124955a63d4dSTakashi Iwai /* No independent HP possible */ 1250bec8e680STakashi Iwai BAD_NO_INDEP_HP = 0x10, 1251352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */ 1252352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10, 1253352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */ 1254352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10, 1255352f7f91STakashi Iwai /* Volume widget is shared */ 1256352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10, 1257352f7f91STakashi Iwai }; 1258352f7f91STakashi Iwai 12590e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for 1260352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[]. 1261352f7f91STakashi Iwai * 1262352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value 1263352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the 1264352f7f91STakashi Iwai * total badness for both volume and mute controls. 1265352f7f91STakashi Iwai */ 12660e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) 1267352f7f91STakashi Iwai { 1268d89c6c0cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1269352f7f91STakashi Iwai hda_nid_t nid; 1270352f7f91STakashi Iwai unsigned int val; 1271352f7f91STakashi Iwai int badness = 0; 1272352f7f91STakashi Iwai 1273352f7f91STakashi Iwai if (!path) 1274352f7f91STakashi Iwai return BAD_SHARED_VOL * 2; 12750e614dd0STakashi Iwai 12760e614dd0STakashi Iwai if (path->ctls[NID_PATH_VOL_CTL] || 12770e614dd0STakashi Iwai path->ctls[NID_PATH_MUTE_CTL]) 12780e614dd0STakashi Iwai return 0; /* already evaluated */ 12790e614dd0STakashi Iwai 1280352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path); 1281352f7f91STakashi Iwai if (nid) { 1282352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 1283d89c6c0cSTakashi Iwai if (spec->dac_min_mute) 1284d89c6c0cSTakashi Iwai val |= HDA_AMP_VAL_MIN_MUTE; 1285352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) 1286352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 1287352f7f91STakashi Iwai else 1288352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 1289352f7f91STakashi Iwai } else 1290352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 1291352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path); 1292352f7f91STakashi Iwai if (nid) { 1293352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); 1294352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || 1295352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT)) 1296352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 1297352f7f91STakashi Iwai else 1298352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 1299352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) 1300352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 1301352f7f91STakashi Iwai else 1302352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 1303352f7f91STakashi Iwai } else 1304352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 1305352f7f91STakashi Iwai return badness; 1306352f7f91STakashi Iwai } 1307352f7f91STakashi Iwai 130898bd1115STakashi Iwai const struct badness_table hda_main_out_badness = { 1309352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC, 1310352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 1311352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC, 1312352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND, 1313352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE, 1314352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND, 1315352f7f91STakashi Iwai }; 13162698ea98STakashi Iwai EXPORT_SYMBOL_GPL(hda_main_out_badness); 1317352f7f91STakashi Iwai 131898bd1115STakashi Iwai const struct badness_table hda_extra_out_badness = { 1319352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC, 1320352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 1321352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC, 1322352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND, 1323352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND, 1324352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, 1325352f7f91STakashi Iwai }; 13262698ea98STakashi Iwai EXPORT_SYMBOL_GPL(hda_extra_out_badness); 1327352f7f91STakashi Iwai 13287385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */ 13297385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) 13307385df61STakashi Iwai { 13317385df61STakashi Iwai struct hda_gen_spec *spec = codec->spec; 13327385df61STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 13337385df61STakashi Iwai 13347385df61STakashi Iwai if (cfg->line_outs > idx) 13357385df61STakashi Iwai return spec->private_dac_nids[idx]; 13367385df61STakashi Iwai idx -= cfg->line_outs; 13377385df61STakashi Iwai if (spec->multi_ios > idx) 13387385df61STakashi Iwai return spec->multi_io[idx].dac; 13397385df61STakashi Iwai return 0; 13407385df61STakashi Iwai } 13417385df61STakashi Iwai 13427385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */ 13437385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec, 13447385df61STakashi Iwai hda_nid_t dac, hda_nid_t pin) 13457385df61STakashi Iwai { 13467385df61STakashi Iwai return is_reachable_path(codec, dac, pin) ? dac : 0; 13477385df61STakashi Iwai } 13487385df61STakashi Iwai 1349352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */ 1350352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs, 1351352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, 1352196c1766STakashi Iwai int *path_idx, 1353352f7f91STakashi Iwai const struct badness_table *bad) 1354352f7f91STakashi Iwai { 1355352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1356352f7f91STakashi Iwai int i, j; 1357352f7f91STakashi Iwai int badness = 0; 1358352f7f91STakashi Iwai hda_nid_t dac; 1359352f7f91STakashi Iwai 1360352f7f91STakashi Iwai if (!num_outs) 1361352f7f91STakashi Iwai return 0; 1362352f7f91STakashi Iwai 1363352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) { 13640c8c0f56STakashi Iwai struct nid_path *path; 1365352f7f91STakashi Iwai hda_nid_t pin = pins[i]; 13661e0b5286STakashi Iwai 13670e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 13680e614dd0STakashi Iwai if (path) { 13690e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 13701e0b5286STakashi Iwai continue; 13711e0b5286STakashi Iwai } 13721e0b5286STakashi Iwai 13733690739bSTakashi Iwai dacs[i] = get_preferred_dac(codec, pin); 13743690739bSTakashi Iwai if (dacs[i]) { 13753690739bSTakashi Iwai if (is_dac_already_used(codec, dacs[i])) 13763690739bSTakashi Iwai badness += bad->shared_primary; 13773690739bSTakashi Iwai } 13783690739bSTakashi Iwai 13793690739bSTakashi Iwai if (!dacs[i]) 1380352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false); 1381352f7f91STakashi Iwai if (!dacs[i] && !i) { 1382980428ceSTakashi Iwai /* try to steal the DAC of surrounds for the front */ 1383352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) { 1384352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) { 1385352f7f91STakashi Iwai dacs[0] = dacs[j]; 1386352f7f91STakashi Iwai dacs[j] = 0; 1387980428ceSTakashi Iwai invalidate_nid_path(codec, path_idx[j]); 1388196c1766STakashi Iwai path_idx[j] = 0; 1389352f7f91STakashi Iwai break; 1390352f7f91STakashi Iwai } 1391352f7f91STakashi Iwai } 1392352f7f91STakashi Iwai } 1393352f7f91STakashi Iwai dac = dacs[i]; 1394352f7f91STakashi Iwai if (!dac) { 13957385df61STakashi Iwai if (num_outs > 2) 13967385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 13977385df61STakashi Iwai if (!dac) 13987385df61STakashi Iwai dac = try_dac(codec, dacs[0], pin); 13997385df61STakashi Iwai if (!dac) 14007385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 1401352f7f91STakashi Iwai if (dac) { 1402352f7f91STakashi Iwai if (!i) 1403352f7f91STakashi Iwai badness += bad->shared_primary; 1404352f7f91STakashi Iwai else if (i == 1) 1405352f7f91STakashi Iwai badness += bad->shared_surr; 1406352f7f91STakashi Iwai else 1407352f7f91STakashi Iwai badness += bad->shared_clfe; 1408352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { 1409352f7f91STakashi Iwai dac = spec->private_dac_nids[0]; 1410352f7f91STakashi Iwai badness += bad->shared_surr_main; 1411352f7f91STakashi Iwai } else if (!i) 1412352f7f91STakashi Iwai badness += bad->no_primary_dac; 1413352f7f91STakashi Iwai else 1414352f7f91STakashi Iwai badness += bad->no_dac; 1415352f7f91STakashi Iwai } 14161fa335b0STakashi Iwai if (!dac) 14171fa335b0STakashi Iwai continue; 14183ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid); 1419117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) { 1420b3a8c745STakashi Iwai /* try with aamix */ 14213ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 0); 1422b3a8c745STakashi Iwai } 14231fa335b0STakashi Iwai if (!path) { 1424352f7f91STakashi Iwai dac = dacs[i] = 0; 14251fa335b0STakashi Iwai badness += bad->no_dac; 14261fa335b0STakashi Iwai } else { 14274e76a883STakashi Iwai /* print_nid_path(codec, "output", path); */ 1428e1284af7STakashi Iwai path->active = true; 1429196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 14300e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 1431e1284af7STakashi Iwai } 1432352f7f91STakashi Iwai } 1433352f7f91STakashi Iwai 1434352f7f91STakashi Iwai return badness; 1435352f7f91STakashi Iwai } 1436352f7f91STakashi Iwai 1437352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */ 1438352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 1439352f7f91STakashi Iwai { 1440352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1441352f7f91STakashi Iwai int i; 1442352f7f91STakashi Iwai hda_nid_t nid_found = 0; 1443352f7f91STakashi Iwai 1444352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 1445352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 1446352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 1447352f7f91STakashi Iwai continue; 1448352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) { 1449352f7f91STakashi Iwai if (nid_found) 1450352f7f91STakashi Iwai return 0; 1451352f7f91STakashi Iwai nid_found = nid; 1452352f7f91STakashi Iwai } 1453352f7f91STakashi Iwai } 1454352f7f91STakashi Iwai return nid_found; 1455352f7f91STakashi Iwai } 1456352f7f91STakashi Iwai 1457352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */ 1458352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec, 1459352f7f91STakashi Iwai unsigned int location, hda_nid_t nid) 1460352f7f91STakashi Iwai { 1461352f7f91STakashi Iwai unsigned int defcfg, caps; 1462352f7f91STakashi Iwai 1463352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid); 1464352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) 1465352f7f91STakashi Iwai return false; 1466352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location) 1467352f7f91STakashi Iwai return false; 1468352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid); 1469352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT)) 1470352f7f91STakashi Iwai return false; 1471352f7f91STakashi Iwai return true; 1472352f7f91STakashi Iwai } 1473352f7f91STakashi Iwai 1474e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */ 1475e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) 1476e22aab7dSTakashi Iwai { 1477e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1478e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1479e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1480e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1481e22aab7dSTakashi Iwai int type, i; 1482e22aab7dSTakashi Iwai int num_pins = 0; 1483e22aab7dSTakashi Iwai 1484e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1485e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1486e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type) 1487e22aab7dSTakashi Iwai continue; 1488e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location, 1489e22aab7dSTakashi Iwai cfg->inputs[i].pin)) 1490e22aab7dSTakashi Iwai num_pins++; 1491e22aab7dSTakashi Iwai } 1492e22aab7dSTakashi Iwai } 1493e22aab7dSTakashi Iwai return num_pins; 1494e22aab7dSTakashi Iwai } 1495e22aab7dSTakashi Iwai 1496352f7f91STakashi Iwai /* 1497352f7f91STakashi Iwai * multi-io helper 1498352f7f91STakashi Iwai * 1499352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns 1500352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found. 1501352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns 1502352f7f91STakashi Iwai * the badness value. 1503352f7f91STakashi Iwai */ 1504352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec, 1505352f7f91STakashi Iwai hda_nid_t reference_pin, 1506e22aab7dSTakashi Iwai bool hardwired) 1507352f7f91STakashi Iwai { 1508352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1509352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1510e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins; 1511352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1512352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1513352f7f91STakashi Iwai int badness = 0; 15140e614dd0STakashi Iwai struct nid_path *path; 1515352f7f91STakashi Iwai 1516352f7f91STakashi Iwai old_pins = spec->multi_ios; 1517352f7f91STakashi Iwai if (old_pins >= 2) 1518352f7f91STakashi Iwai goto end_fill; 1519352f7f91STakashi Iwai 1520e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin); 1521352f7f91STakashi Iwai if (num_pins < 2) 1522352f7f91STakashi Iwai goto end_fill; 1523352f7f91STakashi Iwai 1524352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1525352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1526352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 1527352f7f91STakashi Iwai hda_nid_t dac = 0; 1528352f7f91STakashi Iwai 1529352f7f91STakashi Iwai if (cfg->inputs[i].type != type) 1530352f7f91STakashi Iwai continue; 1531352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid)) 1532352f7f91STakashi Iwai continue; 1533352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) { 1534352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin) 1535352f7f91STakashi Iwai break; 1536352f7f91STakashi Iwai } 1537352f7f91STakashi Iwai if (j < spec->multi_ios) 1538352f7f91STakashi Iwai continue; 1539352f7f91STakashi Iwai 1540352f7f91STakashi Iwai if (hardwired) 1541352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid); 1542352f7f91STakashi Iwai else if (!dac) 1543352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false); 1544352f7f91STakashi Iwai if (!dac) { 1545352f7f91STakashi Iwai badness++; 1546352f7f91STakashi Iwai continue; 1547352f7f91STakashi Iwai } 15483ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, nid, 15493ca529d3STakashi Iwai -spec->mixer_nid); 15500c8c0f56STakashi Iwai if (!path) { 1551352f7f91STakashi Iwai badness++; 1552352f7f91STakashi Iwai continue; 1553352f7f91STakashi Iwai } 15544e76a883STakashi Iwai /* print_nid_path(codec, "multiio", path); */ 1555352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid; 1556352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac; 1557196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] = 1558196c1766STakashi Iwai snd_hda_get_path_idx(codec, path); 1559352f7f91STakashi Iwai spec->multi_ios++; 1560352f7f91STakashi Iwai if (spec->multi_ios >= 2) 1561352f7f91STakashi Iwai break; 1562352f7f91STakashi Iwai } 1563352f7f91STakashi Iwai } 1564352f7f91STakashi Iwai end_fill: 1565352f7f91STakashi Iwai if (badness) 1566352f7f91STakashi Iwai badness = BAD_MULTI_IO; 1567352f7f91STakashi Iwai if (old_pins == spec->multi_ios) { 1568352f7f91STakashi Iwai if (hardwired) 1569352f7f91STakashi Iwai return 1; /* nothing found */ 1570352f7f91STakashi Iwai else 1571352f7f91STakashi Iwai return badness; /* no badness if nothing found */ 1572352f7f91STakashi Iwai } 1573352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) { 1574352f7f91STakashi Iwai /* cancel newly assigned paths */ 1575352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins; 1576352f7f91STakashi Iwai spec->multi_ios = old_pins; 1577352f7f91STakashi Iwai return badness; 1578352f7f91STakashi Iwai } 1579352f7f91STakashi Iwai 1580352f7f91STakashi Iwai /* assign volume and mute controls */ 15810e614dd0STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) { 15820e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]); 15830e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 15840e614dd0STakashi Iwai } 1585352f7f91STakashi Iwai 1586352f7f91STakashi Iwai return badness; 1587352f7f91STakashi Iwai } 1588352f7f91STakashi Iwai 1589352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */ 1590352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs, 1591196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) 1592352f7f91STakashi Iwai { 1593b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1594352f7f91STakashi Iwai int i; 1595352f7f91STakashi Iwai bool found = false; 1596352f7f91STakashi Iwai for (i = 0; i < outs; i++) { 15970c8c0f56STakashi Iwai struct nid_path *path; 1598352f7f91STakashi Iwai hda_nid_t dac; 1599352f7f91STakashi Iwai if (dacs[i]) 1600352f7f91STakashi Iwai continue; 1601352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]); 1602352f7f91STakashi Iwai if (!dac) 1603352f7f91STakashi Iwai continue; 16043ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 16053ca529d3STakashi Iwai -spec->mixer_nid); 1606117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) 16073ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 0); 16080c8c0f56STakashi Iwai if (path) { 1609352f7f91STakashi Iwai dacs[i] = dac; 1610352f7f91STakashi Iwai found = true; 16114e76a883STakashi Iwai /* print_nid_path(codec, "output", path); */ 1612e1284af7STakashi Iwai path->active = true; 1613196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 1614352f7f91STakashi Iwai } 1615352f7f91STakashi Iwai } 1616352f7f91STakashi Iwai return found; 1617352f7f91STakashi Iwai } 1618352f7f91STakashi Iwai 1619e7fdd527STakashi Iwai static inline bool has_aamix_out_paths(struct hda_gen_spec *spec) 1620e7fdd527STakashi Iwai { 1621e7fdd527STakashi Iwai return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || 1622e7fdd527STakashi Iwai spec->aamix_out_paths[2]; 1623e7fdd527STakashi Iwai } 1624e7fdd527STakashi Iwai 1625c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */ 1626c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx) 1627c30aa7b2STakashi Iwai { 16283ca529d3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1629c30aa7b2STakashi Iwai struct nid_path *path; 16305ead56f2STakashi Iwai hda_nid_t path_dac, dac, pin; 1631c30aa7b2STakashi Iwai 1632c30aa7b2STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 16333ca529d3STakashi Iwai if (!path || !path->depth || 16343ca529d3STakashi Iwai is_nid_contained(path, spec->mixer_nid)) 1635c30aa7b2STakashi Iwai return 0; 16365ead56f2STakashi Iwai path_dac = path->path[0]; 16375ead56f2STakashi Iwai dac = spec->private_dac_nids[0]; 1638f87498b6STakashi Iwai pin = path->path[path->depth - 1]; 1639f87498b6STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid); 1640f87498b6STakashi Iwai if (!path) { 16415ead56f2STakashi Iwai if (dac != path_dac) 16425ead56f2STakashi Iwai dac = path_dac; 1643f87498b6STakashi Iwai else if (spec->multiout.hp_out_nid[0]) 1644f87498b6STakashi Iwai dac = spec->multiout.hp_out_nid[0]; 1645f87498b6STakashi Iwai else if (spec->multiout.extra_out_nid[0]) 1646f87498b6STakashi Iwai dac = spec->multiout.extra_out_nid[0]; 16475ead56f2STakashi Iwai else 16485ead56f2STakashi Iwai dac = 0; 1649f87498b6STakashi Iwai if (dac) 1650f87498b6STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 16513ca529d3STakashi Iwai spec->mixer_nid); 1652f87498b6STakashi Iwai } 1653c30aa7b2STakashi Iwai if (!path) 1654c30aa7b2STakashi Iwai return 0; 16554e76a883STakashi Iwai /* print_nid_path(codec, "output-aamix", path); */ 1656c30aa7b2STakashi Iwai path->active = false; /* unused as default */ 16576b275b14STakashi Iwai path->pin_fixed = true; /* static route */ 1658c30aa7b2STakashi Iwai return snd_hda_get_path_idx(codec, path); 1659c30aa7b2STakashi Iwai } 1660c30aa7b2STakashi Iwai 166155a63d4dSTakashi Iwai /* check whether the independent HP is available with the current config */ 166255a63d4dSTakashi Iwai static bool indep_hp_possible(struct hda_codec *codec) 166355a63d4dSTakashi Iwai { 166455a63d4dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 166555a63d4dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 166655a63d4dSTakashi Iwai struct nid_path *path; 166755a63d4dSTakashi Iwai int i, idx; 166855a63d4dSTakashi Iwai 166955a63d4dSTakashi Iwai if (cfg->line_out_type == AUTO_PIN_HP_OUT) 167055a63d4dSTakashi Iwai idx = spec->out_paths[0]; 167155a63d4dSTakashi Iwai else 167255a63d4dSTakashi Iwai idx = spec->hp_paths[0]; 167355a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, idx); 167455a63d4dSTakashi Iwai if (!path) 167555a63d4dSTakashi Iwai return false; 167655a63d4dSTakashi Iwai 167755a63d4dSTakashi Iwai /* assume no path conflicts unless aamix is involved */ 167855a63d4dSTakashi Iwai if (!spec->mixer_nid || !is_nid_contained(path, spec->mixer_nid)) 167955a63d4dSTakashi Iwai return true; 168055a63d4dSTakashi Iwai 168155a63d4dSTakashi Iwai /* check whether output paths contain aamix */ 168255a63d4dSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 168355a63d4dSTakashi Iwai if (spec->out_paths[i] == idx) 168455a63d4dSTakashi Iwai break; 168555a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 168655a63d4dSTakashi Iwai if (path && is_nid_contained(path, spec->mixer_nid)) 168755a63d4dSTakashi Iwai return false; 168855a63d4dSTakashi Iwai } 168955a63d4dSTakashi Iwai for (i = 0; i < cfg->speaker_outs; i++) { 169055a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->speaker_paths[i]); 169155a63d4dSTakashi Iwai if (path && is_nid_contained(path, spec->mixer_nid)) 169255a63d4dSTakashi Iwai return false; 169355a63d4dSTakashi Iwai } 169455a63d4dSTakashi Iwai 169555a63d4dSTakashi Iwai return true; 169655a63d4dSTakashi Iwai } 169755a63d4dSTakashi Iwai 1698a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the 1699a07a949bSTakashi Iwai * shared dac pointed by the paths 1700a07a949bSTakashi Iwai */ 1701a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs, 1702a07a949bSTakashi Iwai hda_nid_t *dacs, int *path_idx) 1703a07a949bSTakashi Iwai { 1704a07a949bSTakashi Iwai struct nid_path *path; 1705a07a949bSTakashi Iwai int i; 1706a07a949bSTakashi Iwai 1707a07a949bSTakashi Iwai for (i = 0; i < num_outs; i++) { 1708a07a949bSTakashi Iwai if (dacs[i]) 1709a07a949bSTakashi Iwai continue; 1710a07a949bSTakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 1711a07a949bSTakashi Iwai if (!path) 1712a07a949bSTakashi Iwai continue; 1713a07a949bSTakashi Iwai dacs[i] = path->path[0]; 1714a07a949bSTakashi Iwai } 1715a07a949bSTakashi Iwai } 1716a07a949bSTakashi Iwai 1717352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */ 1718352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec, 1719352f7f91STakashi Iwai bool fill_hardwired, 1720352f7f91STakashi Iwai bool fill_mio_first) 1721352f7f91STakashi Iwai { 1722352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1723352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1724352f7f91STakashi Iwai int i, err, badness; 1725352f7f91STakashi Iwai 1726352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */ 1727352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs; 1728352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids; 1729352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); 1730352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 1731352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 1732352f7f91STakashi Iwai spec->multi_ios = 0; 1733352f7f91STakashi Iwai snd_array_free(&spec->paths); 1734cd5be3f9STakashi Iwai 1735cd5be3f9STakashi Iwai /* clear path indices */ 1736cd5be3f9STakashi Iwai memset(spec->out_paths, 0, sizeof(spec->out_paths)); 1737cd5be3f9STakashi Iwai memset(spec->hp_paths, 0, sizeof(spec->hp_paths)); 1738cd5be3f9STakashi Iwai memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths)); 1739cd5be3f9STakashi Iwai memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths)); 1740cd5be3f9STakashi Iwai memset(spec->digout_paths, 0, sizeof(spec->digout_paths)); 1741c697b716STakashi Iwai memset(spec->input_paths, 0, sizeof(spec->input_paths)); 1742cd5be3f9STakashi Iwai memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths)); 1743cd5be3f9STakashi Iwai memset(&spec->digin_path, 0, sizeof(spec->digin_path)); 1744cd5be3f9STakashi Iwai 1745352f7f91STakashi Iwai badness = 0; 1746352f7f91STakashi Iwai 1747352f7f91STakashi Iwai /* fill hard-wired DACs first */ 1748352f7f91STakashi Iwai if (fill_hardwired) { 1749352f7f91STakashi Iwai bool mapped; 1750352f7f91STakashi Iwai do { 1751352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs, 1752352f7f91STakashi Iwai cfg->line_out_pins, 1753196c1766STakashi Iwai spec->private_dac_nids, 1754196c1766STakashi Iwai spec->out_paths); 1755352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs, 1756352f7f91STakashi Iwai cfg->hp_pins, 1757196c1766STakashi Iwai spec->multiout.hp_out_nid, 1758196c1766STakashi Iwai spec->hp_paths); 1759352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs, 1760352f7f91STakashi Iwai cfg->speaker_pins, 1761196c1766STakashi Iwai spec->multiout.extra_out_nid, 1762196c1766STakashi Iwai spec->speaker_paths); 1763da96fb5bSTakashi Iwai if (!spec->no_multi_io && 1764da96fb5bSTakashi Iwai fill_mio_first && cfg->line_outs == 1 && 1765352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1766e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true); 1767352f7f91STakashi Iwai if (!err) 1768352f7f91STakashi Iwai mapped = true; 1769352f7f91STakashi Iwai } 1770352f7f91STakashi Iwai } while (mapped); 1771352f7f91STakashi Iwai } 1772352f7f91STakashi Iwai 1773352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, 1774196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths, 177598bd1115STakashi Iwai spec->main_out_badness); 1776352f7f91STakashi Iwai 1777da96fb5bSTakashi Iwai if (!spec->no_multi_io && fill_mio_first && 1778352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1779352f7f91STakashi Iwai /* try to fill multi-io first */ 1780e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1781352f7f91STakashi Iwai if (err < 0) 1782352f7f91STakashi Iwai return err; 1783352f7f91STakashi Iwai /* we don't count badness at this stage yet */ 1784352f7f91STakashi Iwai } 1785352f7f91STakashi Iwai 1786352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 1787352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, 1788352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1789196c1766STakashi Iwai spec->hp_paths, 179098bd1115STakashi Iwai spec->extra_out_badness); 1791352f7f91STakashi Iwai if (err < 0) 1792352f7f91STakashi Iwai return err; 1793352f7f91STakashi Iwai badness += err; 1794352f7f91STakashi Iwai } 1795352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1796352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs, 1797352f7f91STakashi Iwai cfg->speaker_pins, 1798352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1799196c1766STakashi Iwai spec->speaker_paths, 180098bd1115STakashi Iwai spec->extra_out_badness); 1801352f7f91STakashi Iwai if (err < 0) 1802352f7f91STakashi Iwai return err; 1803352f7f91STakashi Iwai badness += err; 1804352f7f91STakashi Iwai } 1805da96fb5bSTakashi Iwai if (!spec->no_multi_io && 1806da96fb5bSTakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1807e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1808352f7f91STakashi Iwai if (err < 0) 1809352f7f91STakashi Iwai return err; 1810352f7f91STakashi Iwai badness += err; 1811352f7f91STakashi Iwai } 1812e22aab7dSTakashi Iwai 1813c30aa7b2STakashi Iwai if (spec->mixer_nid) { 1814c30aa7b2STakashi Iwai spec->aamix_out_paths[0] = 1815c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->out_paths[0]); 1816c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1817c30aa7b2STakashi Iwai spec->aamix_out_paths[1] = 1818c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->hp_paths[0]); 1819c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1820c30aa7b2STakashi Iwai spec->aamix_out_paths[2] = 1821c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->speaker_paths[0]); 1822c30aa7b2STakashi Iwai } 1823c30aa7b2STakashi Iwai 1824da96fb5bSTakashi Iwai if (!spec->no_multi_io && 1825da96fb5bSTakashi Iwai cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1826e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1827e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */ 1828352f7f91STakashi Iwai 1829a07a949bSTakashi Iwai /* re-count num_dacs and squash invalid entries */ 1830a07a949bSTakashi Iwai spec->multiout.num_dacs = 0; 1831a07a949bSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 1832a07a949bSTakashi Iwai if (spec->private_dac_nids[i]) 1833a07a949bSTakashi Iwai spec->multiout.num_dacs++; 1834a07a949bSTakashi Iwai else { 1835a07a949bSTakashi Iwai memmove(spec->private_dac_nids + i, 1836a07a949bSTakashi Iwai spec->private_dac_nids + i + 1, 1837a07a949bSTakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); 1838a07a949bSTakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0; 1839a07a949bSTakashi Iwai } 1840a07a949bSTakashi Iwai } 1841a07a949bSTakashi Iwai 1842a07a949bSTakashi Iwai spec->ext_channel_count = spec->min_channel_count = 1843c0f3b216SDavid Henningsson spec->multiout.num_dacs * 2; 1844a07a949bSTakashi Iwai 1845352f7f91STakashi Iwai if (spec->multi_ios == 2) { 1846352f7f91STakashi Iwai for (i = 0; i < 2; i++) 1847352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] = 1848352f7f91STakashi Iwai spec->multi_io[i].dac; 1849352f7f91STakashi Iwai } else if (spec->multi_ios) { 1850352f7f91STakashi Iwai spec->multi_ios = 0; 1851352f7f91STakashi Iwai badness += BAD_MULTI_IO; 1852352f7f91STakashi Iwai } 1853352f7f91STakashi Iwai 185455a63d4dSTakashi Iwai if (spec->indep_hp && !indep_hp_possible(codec)) 185555a63d4dSTakashi Iwai badness += BAD_NO_INDEP_HP; 185655a63d4dSTakashi Iwai 1857a07a949bSTakashi Iwai /* re-fill the shared DAC for speaker / headphone */ 1858a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1859a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->hp_outs, 1860a07a949bSTakashi Iwai spec->multiout.hp_out_nid, 1861a07a949bSTakashi Iwai spec->hp_paths); 1862a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1863a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->speaker_outs, 1864a07a949bSTakashi Iwai spec->multiout.extra_out_nid, 1865a07a949bSTakashi Iwai spec->speaker_paths); 1866a07a949bSTakashi Iwai 1867352f7f91STakashi Iwai return badness; 1868352f7f91STakashi Iwai } 1869352f7f91STakashi Iwai 1870352f7f91STakashi Iwai #define DEBUG_BADNESS 1871352f7f91STakashi Iwai 1872352f7f91STakashi Iwai #ifdef DEBUG_BADNESS 1873d82353e5SJoe Perches #define debug_badness(fmt, ...) \ 1874d82353e5SJoe Perches codec_dbg(codec, fmt, ##__VA_ARGS__) 1875352f7f91STakashi Iwai #else 1876d82353e5SJoe Perches #define debug_badness(fmt, ...) \ 1877d82353e5SJoe Perches do { if (0) codec_dbg(codec, fmt, ##__VA_ARGS__); } while (0) 1878352f7f91STakashi Iwai #endif 1879352f7f91STakashi Iwai 1880a769409cSTakashi Iwai #ifdef DEBUG_BADNESS 1881a769409cSTakashi Iwai static inline void print_nid_path_idx(struct hda_codec *codec, 1882a769409cSTakashi Iwai const char *pfx, int idx) 1883352f7f91STakashi Iwai { 1884a769409cSTakashi Iwai struct nid_path *path; 1885a769409cSTakashi Iwai 1886a769409cSTakashi Iwai path = snd_hda_get_path_from_idx(codec, idx); 1887a769409cSTakashi Iwai if (path) 18884e76a883STakashi Iwai print_nid_path(codec, pfx, path); 1889a769409cSTakashi Iwai } 1890a769409cSTakashi Iwai 1891a769409cSTakashi Iwai static void debug_show_configs(struct hda_codec *codec, 1892a769409cSTakashi Iwai struct auto_pin_cfg *cfg) 1893a769409cSTakashi Iwai { 1894a769409cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1895a769409cSTakashi Iwai static const char * const lo_type[3] = { "LO", "SP", "HP" }; 1896a769409cSTakashi Iwai int i; 1897a769409cSTakashi Iwai 1898a769409cSTakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n", 1899352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1], 1900708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 1901352f7f91STakashi Iwai spec->multiout.dac_nids[0], 1902352f7f91STakashi Iwai spec->multiout.dac_nids[1], 1903352f7f91STakashi Iwai spec->multiout.dac_nids[2], 1904a769409cSTakashi Iwai spec->multiout.dac_nids[3], 1905a769409cSTakashi Iwai lo_type[cfg->line_out_type]); 1906a769409cSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) 1907a769409cSTakashi Iwai print_nid_path_idx(codec, " out", spec->out_paths[i]); 1908352f7f91STakashi Iwai if (spec->multi_ios > 0) 1909352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", 1910352f7f91STakashi Iwai spec->multi_ios, 1911352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin, 1912352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac); 1913a769409cSTakashi Iwai for (i = 0; i < spec->multi_ios; i++) 1914a769409cSTakashi Iwai print_nid_path_idx(codec, " mio", 1915a769409cSTakashi Iwai spec->out_paths[cfg->line_outs + i]); 1916a769409cSTakashi Iwai if (cfg->hp_outs) 1917352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1918352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1], 1919708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3], 1920352f7f91STakashi Iwai spec->multiout.hp_out_nid[0], 1921352f7f91STakashi Iwai spec->multiout.hp_out_nid[1], 1922352f7f91STakashi Iwai spec->multiout.hp_out_nid[2], 1923352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]); 1924a769409cSTakashi Iwai for (i = 0; i < cfg->hp_outs; i++) 1925a769409cSTakashi Iwai print_nid_path_idx(codec, " hp ", spec->hp_paths[i]); 1926a769409cSTakashi Iwai if (cfg->speaker_outs) 1927352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1928352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1], 1929352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3], 1930352f7f91STakashi Iwai spec->multiout.extra_out_nid[0], 1931352f7f91STakashi Iwai spec->multiout.extra_out_nid[1], 1932352f7f91STakashi Iwai spec->multiout.extra_out_nid[2], 1933352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]); 1934a769409cSTakashi Iwai for (i = 0; i < cfg->speaker_outs; i++) 1935a769409cSTakashi Iwai print_nid_path_idx(codec, " spk", spec->speaker_paths[i]); 1936a769409cSTakashi Iwai for (i = 0; i < 3; i++) 1937a769409cSTakashi Iwai print_nid_path_idx(codec, " mix", spec->aamix_out_paths[i]); 1938352f7f91STakashi Iwai } 1939a769409cSTakashi Iwai #else 1940a769409cSTakashi Iwai #define debug_show_configs(codec, cfg) /* NOP */ 1941a769409cSTakashi Iwai #endif 1942352f7f91STakashi Iwai 1943352f7f91STakashi Iwai /* find all available DACs of the codec */ 1944352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec) 1945352f7f91STakashi Iwai { 1946352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 19477639a06cSTakashi Iwai hda_nid_t nid; 1948352f7f91STakashi Iwai 1949352f7f91STakashi Iwai spec->num_all_dacs = 0; 1950352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); 19517639a06cSTakashi Iwai for_each_hda_codec_node(nid, codec) { 1952352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) 1953352f7f91STakashi Iwai continue; 1954352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { 19554e76a883STakashi Iwai codec_err(codec, "Too many DACs!\n"); 1956352f7f91STakashi Iwai break; 1957352f7f91STakashi Iwai } 1958352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid; 1959352f7f91STakashi Iwai } 1960352f7f91STakashi Iwai } 1961352f7f91STakashi Iwai 1962352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec) 1963352f7f91STakashi Iwai { 1964352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1965352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1966352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg; 19679314a581STakashi Iwai unsigned int val; 1968352f7f91STakashi Iwai int best_badness = INT_MAX; 1969352f7f91STakashi Iwai int badness; 1970352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true; 1971352f7f91STakashi Iwai bool best_wired = true, best_mio = true; 1972352f7f91STakashi Iwai bool hp_spk_swapped = false; 1973352f7f91STakashi Iwai 1974352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); 1975352f7f91STakashi Iwai if (!best_cfg) 1976352f7f91STakashi Iwai return -ENOMEM; 1977352f7f91STakashi Iwai *best_cfg = *cfg; 1978352f7f91STakashi Iwai 1979352f7f91STakashi Iwai for (;;) { 1980352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired, 1981352f7f91STakashi Iwai fill_mio_first); 1982352f7f91STakashi Iwai if (badness < 0) { 1983352f7f91STakashi Iwai kfree(best_cfg); 1984352f7f91STakashi Iwai return badness; 1985352f7f91STakashi Iwai } 1986352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", 1987352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first, 1988352f7f91STakashi Iwai badness); 1989a769409cSTakashi Iwai debug_show_configs(codec, cfg); 1990352f7f91STakashi Iwai if (badness < best_badness) { 1991352f7f91STakashi Iwai best_badness = badness; 1992352f7f91STakashi Iwai *best_cfg = *cfg; 1993352f7f91STakashi Iwai best_wired = fill_hardwired; 1994352f7f91STakashi Iwai best_mio = fill_mio_first; 1995352f7f91STakashi Iwai } 1996352f7f91STakashi Iwai if (!badness) 1997352f7f91STakashi Iwai break; 1998352f7f91STakashi Iwai fill_mio_first = !fill_mio_first; 1999352f7f91STakashi Iwai if (!fill_mio_first) 2000352f7f91STakashi Iwai continue; 2001352f7f91STakashi Iwai fill_hardwired = !fill_hardwired; 2002352f7f91STakashi Iwai if (!fill_hardwired) 2003352f7f91STakashi Iwai continue; 2004352f7f91STakashi Iwai if (hp_spk_swapped) 2005352f7f91STakashi Iwai break; 2006352f7f91STakashi Iwai hp_spk_swapped = true; 2007352f7f91STakashi Iwai if (cfg->speaker_outs > 0 && 2008352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 2009352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 2010352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 2011352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 2012352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs; 2013352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins, 2014352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 2015352f7f91STakashi Iwai cfg->speaker_outs = 0; 2016352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 2017352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 2018352f7f91STakashi Iwai fill_hardwired = true; 2019352f7f91STakashi Iwai continue; 2020352f7f91STakashi Iwai } 2021352f7f91STakashi Iwai if (cfg->hp_outs > 0 && 2022352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 2023352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 2024352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 2025352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 2026352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 2027352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, 2028352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 2029352f7f91STakashi Iwai cfg->hp_outs = 0; 2030352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 2031352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 2032352f7f91STakashi Iwai fill_hardwired = true; 2033352f7f91STakashi Iwai continue; 2034352f7f91STakashi Iwai } 2035352f7f91STakashi Iwai break; 2036352f7f91STakashi Iwai } 2037352f7f91STakashi Iwai 2038352f7f91STakashi Iwai if (badness) { 20390c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n"); 2040352f7f91STakashi Iwai *cfg = *best_cfg; 2041352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio); 2042352f7f91STakashi Iwai } 2043352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", 2044352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio); 2045a769409cSTakashi Iwai debug_show_configs(codec, cfg); 2046352f7f91STakashi Iwai 2047352f7f91STakashi Iwai if (cfg->line_out_pins[0]) { 2048352f7f91STakashi Iwai struct nid_path *path; 2049196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); 2050352f7f91STakashi Iwai if (path) 2051352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path); 2052d89c6c0cSTakashi Iwai if (spec->vmaster_nid) { 20537a71bbf3STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 20547a71bbf3STakashi Iwai HDA_OUTPUT, spec->vmaster_tlv); 2055d89c6c0cSTakashi Iwai if (spec->dac_min_mute) 205651cdc8b6STakashi Sakamoto spec->vmaster_tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] |= TLV_DB_SCALE_MUTE; 2057d89c6c0cSTakashi Iwai } 2058352f7f91STakashi Iwai } 2059352f7f91STakashi Iwai 20609314a581STakashi Iwai /* set initial pinctl targets */ 20619314a581STakashi Iwai if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT) 20629314a581STakashi Iwai val = PIN_HP; 20639314a581STakashi Iwai else 20649314a581STakashi Iwai val = PIN_OUT; 20659314a581STakashi Iwai set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val); 20669314a581STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 20679314a581STakashi Iwai set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP); 20689314a581STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 20699314a581STakashi Iwai val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT; 20709314a581STakashi Iwai set_pin_targets(codec, cfg->speaker_outs, 20719314a581STakashi Iwai cfg->speaker_pins, val); 20729314a581STakashi Iwai } 20739314a581STakashi Iwai 207455a63d4dSTakashi Iwai /* clear indep_hp flag if not available */ 207555a63d4dSTakashi Iwai if (spec->indep_hp && !indep_hp_possible(codec)) 207655a63d4dSTakashi Iwai spec->indep_hp = 0; 207755a63d4dSTakashi Iwai 2078352f7f91STakashi Iwai kfree(best_cfg); 2079352f7f91STakashi Iwai return 0; 2080352f7f91STakashi Iwai } 2081352f7f91STakashi Iwai 2082352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */ 2083352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec, 2084352f7f91STakashi Iwai const struct auto_pin_cfg *cfg) 2085352f7f91STakashi Iwai { 2086352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2087352f7f91STakashi Iwai int i, err, noutputs; 2088352f7f91STakashi Iwai 2089352f7f91STakashi Iwai noutputs = cfg->line_outs; 2090352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3) 2091352f7f91STakashi Iwai noutputs += spec->multi_ios; 2092352f7f91STakashi Iwai 2093352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) { 2094352f7f91STakashi Iwai const char *name; 2095352f7f91STakashi Iwai int index; 2096352f7f91STakashi Iwai struct nid_path *path; 2097352f7f91STakashi Iwai 2098196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 2099352f7f91STakashi Iwai if (!path) 2100352f7f91STakashi Iwai continue; 2101247d85eeSTakashi Iwai 2102247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL); 2103352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) { 2104352f7f91STakashi Iwai /* Center/LFE */ 2105352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path); 2106352f7f91STakashi Iwai if (err < 0) 2107352f7f91STakashi Iwai return err; 2108352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path); 2109352f7f91STakashi Iwai if (err < 0) 2110352f7f91STakashi Iwai return err; 2111247d85eeSTakashi Iwai } else { 2112247d85eeSTakashi Iwai err = add_stereo_vol(codec, name, index, path); 2113247d85eeSTakashi Iwai if (err < 0) 2114247d85eeSTakashi Iwai return err; 2115247d85eeSTakashi Iwai } 2116247d85eeSTakashi Iwai 2117247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL); 2118247d85eeSTakashi Iwai if (!name || !strcmp(name, "CLFE")) { 2119352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path); 2120352f7f91STakashi Iwai if (err < 0) 2121352f7f91STakashi Iwai return err; 2122352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path); 2123352f7f91STakashi Iwai if (err < 0) 2124352f7f91STakashi Iwai return err; 2125352f7f91STakashi Iwai } else { 2126352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path); 2127352f7f91STakashi Iwai if (err < 0) 2128352f7f91STakashi Iwai return err; 2129352f7f91STakashi Iwai } 2130352f7f91STakashi Iwai } 2131352f7f91STakashi Iwai return 0; 2132352f7f91STakashi Iwai } 2133352f7f91STakashi Iwai 2134c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx, 2135196c1766STakashi Iwai const char *pfx, int cidx) 2136352f7f91STakashi Iwai { 2137352f7f91STakashi Iwai struct nid_path *path; 2138352f7f91STakashi Iwai int err; 2139352f7f91STakashi Iwai 2140196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 2141352f7f91STakashi Iwai if (!path) 2142352f7f91STakashi Iwai return 0; 2143352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path); 2144352f7f91STakashi Iwai if (err < 0) 2145352f7f91STakashi Iwai return err; 2146352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path); 2147352f7f91STakashi Iwai if (err < 0) 2148352f7f91STakashi Iwai return err; 2149352f7f91STakashi Iwai return 0; 2150352f7f91STakashi Iwai } 2151352f7f91STakashi Iwai 2152352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */ 2153352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins, 2154196c1766STakashi Iwai const int *paths, const char *pfx) 2155352f7f91STakashi Iwai { 2156c2c80383STakashi Iwai int i; 2157352f7f91STakashi Iwai 2158352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2159c2c80383STakashi Iwai const char *name; 2160975cc02aSTakashi Iwai char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 2161c2c80383STakashi Iwai int err, idx = 0; 2162c2c80383STakashi Iwai 2163c2c80383STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) 2164c2c80383STakashi Iwai name = "Bass Speaker"; 2165c2c80383STakashi Iwai else if (num_pins >= 3) { 2166c2c80383STakashi Iwai snprintf(tmp, sizeof(tmp), "%s %s", 2167352f7f91STakashi Iwai pfx, channel_name[i]); 2168c2c80383STakashi Iwai name = tmp; 2169352f7f91STakashi Iwai } else { 2170c2c80383STakashi Iwai name = pfx; 2171c2c80383STakashi Iwai idx = i; 2172352f7f91STakashi Iwai } 2173c2c80383STakashi Iwai err = create_extra_out(codec, paths[i], name, idx); 2174352f7f91STakashi Iwai if (err < 0) 2175352f7f91STakashi Iwai return err; 2176352f7f91STakashi Iwai } 2177352f7f91STakashi Iwai return 0; 2178352f7f91STakashi Iwai } 2179352f7f91STakashi Iwai 2180352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec) 2181352f7f91STakashi Iwai { 2182352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2183352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs, 2184196c1766STakashi Iwai spec->hp_paths, 2185352f7f91STakashi Iwai "Headphone"); 2186352f7f91STakashi Iwai } 2187352f7f91STakashi Iwai 2188352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec) 2189352f7f91STakashi Iwai { 2190352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2191352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs, 2192196c1766STakashi Iwai spec->speaker_paths, 2193352f7f91STakashi Iwai "Speaker"); 2194352f7f91STakashi Iwai } 2195352f7f91STakashi Iwai 2196352f7f91STakashi Iwai /* 219738cf6f1aSTakashi Iwai * independent HP controls 219838cf6f1aSTakashi Iwai */ 219938cf6f1aSTakashi Iwai 22001a4f69d5STakashi Iwai static void call_hp_automute(struct hda_codec *codec, 22011a4f69d5STakashi Iwai struct hda_jack_callback *jack); 220238cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol, 220338cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo) 220438cf6f1aSTakashi Iwai { 220538cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 220638cf6f1aSTakashi Iwai } 220738cf6f1aSTakashi Iwai 220838cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol, 220938cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 221038cf6f1aSTakashi Iwai { 221138cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 221238cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 221338cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; 221438cf6f1aSTakashi Iwai return 0; 221538cf6f1aSTakashi Iwai } 221638cf6f1aSTakashi Iwai 2217a1e908edSTakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 2218a1e908edSTakashi Iwai int nomix_path_idx, int mix_path_idx, 2219a1e908edSTakashi Iwai int out_type); 2220a1e908edSTakashi Iwai 222138cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol, 222238cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 222338cf6f1aSTakashi Iwai { 222438cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 222538cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 222638cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0]; 222738cf6f1aSTakashi Iwai int ret = 0; 222838cf6f1aSTakashi Iwai 222938cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 223038cf6f1aSTakashi Iwai if (spec->active_streams) { 223138cf6f1aSTakashi Iwai ret = -EBUSY; 223238cf6f1aSTakashi Iwai goto unlock; 223338cf6f1aSTakashi Iwai } 223438cf6f1aSTakashi Iwai 223538cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) { 2236a1e908edSTakashi Iwai hda_nid_t *dacp; 2237a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 2238a1e908edSTakashi Iwai dacp = &spec->private_dac_nids[0]; 2239a1e908edSTakashi Iwai else 2240a1e908edSTakashi Iwai dacp = &spec->multiout.hp_out_nid[0]; 2241a1e908edSTakashi Iwai 2242a1e908edSTakashi Iwai /* update HP aamix paths in case it conflicts with indep HP */ 2243a1e908edSTakashi Iwai if (spec->have_aamix_ctl) { 2244a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 2245a1e908edSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, 2246a1e908edSTakashi Iwai spec->out_paths[0], 2247a1e908edSTakashi Iwai spec->aamix_out_paths[0], 2248a1e908edSTakashi Iwai spec->autocfg.line_out_type); 2249a1e908edSTakashi Iwai else 2250a1e908edSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, 2251a1e908edSTakashi Iwai spec->hp_paths[0], 2252a1e908edSTakashi Iwai spec->aamix_out_paths[1], 2253a1e908edSTakashi Iwai AUTO_PIN_HP_OUT); 2254a1e908edSTakashi Iwai } 2255a1e908edSTakashi Iwai 225638cf6f1aSTakashi Iwai spec->indep_hp_enabled = select; 225738cf6f1aSTakashi Iwai if (spec->indep_hp_enabled) 2258a1e908edSTakashi Iwai *dacp = 0; 225938cf6f1aSTakashi Iwai else 2260a1e908edSTakashi Iwai *dacp = spec->alt_dac_nid; 226192603c59STakashi Iwai 2262963afde9STakashi Iwai call_hp_automute(codec, NULL); 226338cf6f1aSTakashi Iwai ret = 1; 226438cf6f1aSTakashi Iwai } 226538cf6f1aSTakashi Iwai unlock: 226638cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 226738cf6f1aSTakashi Iwai return ret; 226838cf6f1aSTakashi Iwai } 226938cf6f1aSTakashi Iwai 227038cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = { 227138cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 227238cf6f1aSTakashi Iwai .name = "Independent HP", 227338cf6f1aSTakashi Iwai .info = indep_hp_info, 227438cf6f1aSTakashi Iwai .get = indep_hp_get, 227538cf6f1aSTakashi Iwai .put = indep_hp_put, 227638cf6f1aSTakashi Iwai }; 227738cf6f1aSTakashi Iwai 227838cf6f1aSTakashi Iwai 227938cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec) 228038cf6f1aSTakashi Iwai { 228138cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2282a1e908edSTakashi Iwai hda_nid_t dac; 228338cf6f1aSTakashi Iwai 228438cf6f1aSTakashi Iwai if (!spec->indep_hp) 228538cf6f1aSTakashi Iwai return 0; 2286a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 2287a1e908edSTakashi Iwai dac = spec->multiout.dac_nids[0]; 2288a1e908edSTakashi Iwai else 2289a1e908edSTakashi Iwai dac = spec->multiout.hp_out_nid[0]; 2290a1e908edSTakashi Iwai if (!dac) { 229138cf6f1aSTakashi Iwai spec->indep_hp = 0; 229238cf6f1aSTakashi Iwai return 0; 229338cf6f1aSTakashi Iwai } 229438cf6f1aSTakashi Iwai 229538cf6f1aSTakashi Iwai spec->indep_hp_enabled = false; 2296a1e908edSTakashi Iwai spec->alt_dac_nid = dac; 229738cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) 229838cf6f1aSTakashi Iwai return -ENOMEM; 229938cf6f1aSTakashi Iwai return 0; 230038cf6f1aSTakashi Iwai } 230138cf6f1aSTakashi Iwai 230238cf6f1aSTakashi Iwai /* 2303352f7f91STakashi Iwai * channel mode enum control 2304352f7f91STakashi Iwai */ 2305352f7f91STakashi Iwai 2306352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol, 2307352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2308352f7f91STakashi Iwai { 2309352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2310352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2311a07a949bSTakashi Iwai int chs; 2312352f7f91STakashi Iwai 2313352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2314352f7f91STakashi Iwai uinfo->count = 1; 2315352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1; 2316352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios) 2317352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios; 2318a07a949bSTakashi Iwai chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count; 2319a07a949bSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", chs); 2320352f7f91STakashi Iwai return 0; 2321352f7f91STakashi Iwai } 2322352f7f91STakashi Iwai 2323352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol, 2324352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2325352f7f91STakashi Iwai { 2326352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2327352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2328a07a949bSTakashi Iwai ucontrol->value.enumerated.item[0] = 2329a07a949bSTakashi Iwai (spec->ext_channel_count - spec->min_channel_count) / 2; 2330352f7f91STakashi Iwai return 0; 2331352f7f91STakashi Iwai } 2332352f7f91STakashi Iwai 2333196c1766STakashi Iwai static inline struct nid_path * 2334196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx) 2335196c1766STakashi Iwai { 2336196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2337196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec, 2338196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]); 2339196c1766STakashi Iwai } 2340196c1766STakashi Iwai 2341a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec); 2342a5cc2509STakashi Iwai 234365033cc8STakashi Iwai /* Default value to be passed as aamix argument for snd_hda_activate_path(); 234465033cc8STakashi Iwai * used for output paths 234565033cc8STakashi Iwai */ 234665033cc8STakashi Iwai static bool aamix_default(struct hda_gen_spec *spec) 234765033cc8STakashi Iwai { 234865033cc8STakashi Iwai return !spec->have_aamix_ctl || spec->aamix_mode; 234965033cc8STakashi Iwai } 235065033cc8STakashi Iwai 2351352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output) 2352352f7f91STakashi Iwai { 2353352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2354352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin; 2355352f7f91STakashi Iwai struct nid_path *path; 2356352f7f91STakashi Iwai 2357196c1766STakashi Iwai path = get_multiio_path(codec, idx); 2358352f7f91STakashi Iwai if (!path) 2359352f7f91STakashi Iwai return -EINVAL; 2360352f7f91STakashi Iwai 2361352f7f91STakashi Iwai if (path->active == output) 2362352f7f91STakashi Iwai return 0; 2363352f7f91STakashi Iwai 2364352f7f91STakashi Iwai if (output) { 23652c12c30dSTakashi Iwai set_pin_target(codec, nid, PIN_OUT, true); 236665033cc8STakashi Iwai snd_hda_activate_path(codec, path, true, aamix_default(spec)); 2367d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true); 2368352f7f91STakashi Iwai } else { 2369d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false); 237065033cc8STakashi Iwai snd_hda_activate_path(codec, path, false, aamix_default(spec)); 23712c12c30dSTakashi Iwai set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); 237255196fffSTakashi Iwai path_power_down_sync(codec, path); 2373352f7f91STakashi Iwai } 2374a365fed9STakashi Iwai 2375a365fed9STakashi Iwai /* update jack retasking in case it modifies any of them */ 2376a5cc2509STakashi Iwai update_automute_all(codec); 2377a365fed9STakashi Iwai 2378352f7f91STakashi Iwai return 0; 2379352f7f91STakashi Iwai } 2380352f7f91STakashi Iwai 2381352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol, 2382352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2383352f7f91STakashi Iwai { 2384352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2385352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2386352f7f91STakashi Iwai int i, ch; 2387352f7f91STakashi Iwai 2388352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0]; 2389352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios) 2390352f7f91STakashi Iwai return -EINVAL; 2391a07a949bSTakashi Iwai if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2) 2392352f7f91STakashi Iwai return 0; 2393a07a949bSTakashi Iwai spec->ext_channel_count = ch * 2 + spec->min_channel_count; 2394352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) 2395352f7f91STakashi Iwai set_multi_io(codec, i, i < ch); 2396352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 2397352f7f91STakashi Iwai spec->const_channel_count); 2398352f7f91STakashi Iwai if (spec->need_dac_fix) 2399352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2; 2400352f7f91STakashi Iwai return 1; 2401352f7f91STakashi Iwai } 2402352f7f91STakashi Iwai 2403352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = { 2404352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2405352f7f91STakashi Iwai .name = "Channel Mode", 2406352f7f91STakashi Iwai .info = ch_mode_info, 2407352f7f91STakashi Iwai .get = ch_mode_get, 2408352f7f91STakashi Iwai .put = ch_mode_put, 2409352f7f91STakashi Iwai }; 2410352f7f91STakashi Iwai 2411352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec) 2412352f7f91STakashi Iwai { 2413352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2414352f7f91STakashi Iwai 2415352f7f91STakashi Iwai if (spec->multi_ios > 0) { 241612c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) 2417352f7f91STakashi Iwai return -ENOMEM; 2418352f7f91STakashi Iwai } 2419352f7f91STakashi Iwai return 0; 2420352f7f91STakashi Iwai } 2421352f7f91STakashi Iwai 2422352f7f91STakashi Iwai /* 2423c30aa7b2STakashi Iwai * aamix loopback enable/disable switch 2424c30aa7b2STakashi Iwai */ 2425c30aa7b2STakashi Iwai 2426c30aa7b2STakashi Iwai #define loopback_mixing_info indep_hp_info 2427c30aa7b2STakashi Iwai 2428c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol, 2429c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2430c30aa7b2STakashi Iwai { 2431c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2432c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2433c30aa7b2STakashi Iwai ucontrol->value.enumerated.item[0] = spec->aamix_mode; 2434c30aa7b2STakashi Iwai return 0; 2435c30aa7b2STakashi Iwai } 2436c30aa7b2STakashi Iwai 2437c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 2438a1e908edSTakashi Iwai int nomix_path_idx, int mix_path_idx, 2439a1e908edSTakashi Iwai int out_type) 2440c30aa7b2STakashi Iwai { 2441a1e908edSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2442c30aa7b2STakashi Iwai struct nid_path *nomix_path, *mix_path; 2443c30aa7b2STakashi Iwai 2444c30aa7b2STakashi Iwai nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); 2445c30aa7b2STakashi Iwai mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); 2446c30aa7b2STakashi Iwai if (!nomix_path || !mix_path) 2447c30aa7b2STakashi Iwai return; 2448a1e908edSTakashi Iwai 2449a1e908edSTakashi Iwai /* if HP aamix path is driven from a different DAC and the 2450a1e908edSTakashi Iwai * independent HP mode is ON, can't turn on aamix path 2451a1e908edSTakashi Iwai */ 2452a1e908edSTakashi Iwai if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled && 2453a1e908edSTakashi Iwai mix_path->path[0] != spec->alt_dac_nid) 2454a1e908edSTakashi Iwai do_mix = false; 2455a1e908edSTakashi Iwai 2456c30aa7b2STakashi Iwai if (do_mix) { 2457c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, false, true); 2458c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, true, true); 245955196fffSTakashi Iwai path_power_down_sync(codec, nomix_path); 2460c30aa7b2STakashi Iwai } else { 246165033cc8STakashi Iwai snd_hda_activate_path(codec, mix_path, false, false); 246265033cc8STakashi Iwai snd_hda_activate_path(codec, nomix_path, true, false); 246355196fffSTakashi Iwai path_power_down_sync(codec, mix_path); 2464c30aa7b2STakashi Iwai } 2465c30aa7b2STakashi Iwai } 2466c30aa7b2STakashi Iwai 2467e7fdd527STakashi Iwai /* re-initialize the output paths; only called from loopback_mixing_put() */ 2468e7fdd527STakashi Iwai static void update_output_paths(struct hda_codec *codec, int num_outs, 2469e7fdd527STakashi Iwai const int *paths) 2470e7fdd527STakashi Iwai { 2471e7fdd527STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2472e7fdd527STakashi Iwai struct nid_path *path; 2473e7fdd527STakashi Iwai int i; 2474e7fdd527STakashi Iwai 2475e7fdd527STakashi Iwai for (i = 0; i < num_outs; i++) { 2476e7fdd527STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]); 2477e7fdd527STakashi Iwai if (path) 2478e7fdd527STakashi Iwai snd_hda_activate_path(codec, path, path->active, 2479e7fdd527STakashi Iwai spec->aamix_mode); 2480e7fdd527STakashi Iwai } 2481e7fdd527STakashi Iwai } 2482e7fdd527STakashi Iwai 2483c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol, 2484c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2485c30aa7b2STakashi Iwai { 2486c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2487c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2488e7fdd527STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 2489c30aa7b2STakashi Iwai unsigned int val = ucontrol->value.enumerated.item[0]; 2490c30aa7b2STakashi Iwai 2491c30aa7b2STakashi Iwai if (val == spec->aamix_mode) 2492c30aa7b2STakashi Iwai return 0; 2493c30aa7b2STakashi Iwai spec->aamix_mode = val; 2494e7fdd527STakashi Iwai if (has_aamix_out_paths(spec)) { 2495c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->out_paths[0], 2496a1e908edSTakashi Iwai spec->aamix_out_paths[0], 2497e7fdd527STakashi Iwai cfg->line_out_type); 2498c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->hp_paths[0], 2499a1e908edSTakashi Iwai spec->aamix_out_paths[1], 2500a1e908edSTakashi Iwai AUTO_PIN_HP_OUT); 2501c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->speaker_paths[0], 2502a1e908edSTakashi Iwai spec->aamix_out_paths[2], 2503a1e908edSTakashi Iwai AUTO_PIN_SPEAKER_OUT); 2504e7fdd527STakashi Iwai } else { 2505e7fdd527STakashi Iwai update_output_paths(codec, cfg->line_outs, spec->out_paths); 2506e7fdd527STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 2507e7fdd527STakashi Iwai update_output_paths(codec, cfg->hp_outs, spec->hp_paths); 2508e7fdd527STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 2509e7fdd527STakashi Iwai update_output_paths(codec, cfg->speaker_outs, 2510e7fdd527STakashi Iwai spec->speaker_paths); 2511e7fdd527STakashi Iwai } 2512c30aa7b2STakashi Iwai return 1; 2513c30aa7b2STakashi Iwai } 2514c30aa7b2STakashi Iwai 2515c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = { 2516c30aa7b2STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2517c30aa7b2STakashi Iwai .name = "Loopback Mixing", 2518c30aa7b2STakashi Iwai .info = loopback_mixing_info, 2519c30aa7b2STakashi Iwai .get = loopback_mixing_get, 2520c30aa7b2STakashi Iwai .put = loopback_mixing_put, 2521c30aa7b2STakashi Iwai }; 2522c30aa7b2STakashi Iwai 2523c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec) 2524c30aa7b2STakashi Iwai { 2525c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2526c30aa7b2STakashi Iwai 2527c30aa7b2STakashi Iwai if (!spec->mixer_nid) 2528c30aa7b2STakashi Iwai return 0; 2529c30aa7b2STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) 2530c30aa7b2STakashi Iwai return -ENOMEM; 2531a1e908edSTakashi Iwai spec->have_aamix_ctl = 1; 2532c30aa7b2STakashi Iwai return 0; 2533c30aa7b2STakashi Iwai } 2534c30aa7b2STakashi Iwai 2535c30aa7b2STakashi Iwai /* 2536352f7f91STakashi Iwai * shared headphone/mic handling 2537352f7f91STakashi Iwai */ 2538352f7f91STakashi Iwai 2539352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec); 2540352f7f91STakashi Iwai 2541352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */ 2542967303daSTakashi Iwai static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force) 2543352f7f91STakashi Iwai { 2544352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2545967303daSTakashi Iwai bool as_mic; 2546352f7f91STakashi Iwai unsigned int val; 2547967303daSTakashi Iwai hda_nid_t pin; 2548967303daSTakashi Iwai 2549967303daSTakashi Iwai pin = spec->hp_mic_pin; 2550967303daSTakashi Iwai as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx; 2551967303daSTakashi Iwai 2552967303daSTakashi Iwai if (!force) { 2553967303daSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, pin); 2554967303daSTakashi Iwai if (as_mic) { 2555967303daSTakashi Iwai if (val & PIN_IN) 2556967303daSTakashi Iwai return; 2557967303daSTakashi Iwai } else { 2558967303daSTakashi Iwai if (val & PIN_OUT) 2559967303daSTakashi Iwai return; 2560967303daSTakashi Iwai } 2561967303daSTakashi Iwai } 2562352f7f91STakashi Iwai 2563352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin); 2564967303daSTakashi Iwai /* if the HP pin doesn't support VREF and the codec driver gives an 2565967303daSTakashi Iwai * alternative pin, set up the VREF on that pin instead 2566967303daSTakashi Iwai */ 2567352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { 2568352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin; 2569352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); 2570352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ) 25717594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin, 2572967303daSTakashi Iwai PIN_IN | (as_mic ? vref_val : 0)); 2573352f7f91STakashi Iwai } 2574352f7f91STakashi Iwai 25758ba955ceSTakashi Iwai if (!spec->hp_mic_jack_modes) { 2576967303daSTakashi Iwai if (as_mic) 2577967303daSTakashi Iwai val |= PIN_IN; 2578967303daSTakashi Iwai else 2579967303daSTakashi Iwai val = PIN_HP; 25802c12c30dSTakashi Iwai set_pin_target(codec, pin, val, true); 2581963afde9STakashi Iwai call_hp_automute(codec, NULL); 25828ba955ceSTakashi Iwai } 2583352f7f91STakashi Iwai } 2584352f7f91STakashi Iwai 2585352f7f91STakashi Iwai /* create a shared input with the headphone out */ 2586967303daSTakashi Iwai static int create_hp_mic(struct hda_codec *codec) 2587352f7f91STakashi Iwai { 2588352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2589352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2590352f7f91STakashi Iwai unsigned int defcfg; 2591352f7f91STakashi Iwai hda_nid_t nid; 2592352f7f91STakashi Iwai 2593967303daSTakashi Iwai if (!spec->hp_mic) { 2594967303daSTakashi Iwai if (spec->suppress_hp_mic_detect) 2595352f7f91STakashi Iwai return 0; 2596967303daSTakashi Iwai /* automatic detection: only if no input or a single internal 2597967303daSTakashi Iwai * input pin is found, try to detect the shared hp/mic 2598967303daSTakashi Iwai */ 2599967303daSTakashi Iwai if (cfg->num_inputs > 1) 2600967303daSTakashi Iwai return 0; 2601967303daSTakashi Iwai else if (cfg->num_inputs == 1) { 2602352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); 2603352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) 2604352f7f91STakashi Iwai return 0; 2605967303daSTakashi Iwai } 2606967303daSTakashi Iwai } 2607352f7f91STakashi Iwai 2608967303daSTakashi Iwai spec->hp_mic = 0; /* clear once */ 2609967303daSTakashi Iwai if (cfg->num_inputs >= AUTO_CFG_MAX_INS) 2610967303daSTakashi Iwai return 0; 2611967303daSTakashi Iwai 2612967303daSTakashi Iwai nid = 0; 2613967303daSTakashi Iwai if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0) 2614967303daSTakashi Iwai nid = cfg->line_out_pins[0]; 2615967303daSTakashi Iwai else if (cfg->hp_outs > 0) 2616967303daSTakashi Iwai nid = cfg->hp_pins[0]; 2617967303daSTakashi Iwai if (!nid) 2618967303daSTakashi Iwai return 0; 2619352f7f91STakashi Iwai 2620352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) 2621352f7f91STakashi Iwai return 0; /* no input */ 2622352f7f91STakashi Iwai 2623967303daSTakashi Iwai cfg->inputs[cfg->num_inputs].pin = nid; 2624967303daSTakashi Iwai cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC; 2625cb420b11SDavid Henningsson cfg->inputs[cfg->num_inputs].is_headphone_mic = 1; 2626967303daSTakashi Iwai cfg->num_inputs++; 2627967303daSTakashi Iwai spec->hp_mic = 1; 2628967303daSTakashi Iwai spec->hp_mic_pin = nid; 2629967303daSTakashi Iwai /* we can't handle auto-mic together with HP-mic */ 2630967303daSTakashi Iwai spec->suppress_auto_mic = 1; 26314e76a883STakashi Iwai codec_dbg(codec, "Enable shared I/O jack on NID 0x%x\n", nid); 2632352f7f91STakashi Iwai return 0; 2633352f7f91STakashi Iwai } 2634352f7f91STakashi Iwai 2635978e77e7STakashi Iwai /* 2636978e77e7STakashi Iwai * output jack mode 2637978e77e7STakashi Iwai */ 26385f171baaSTakashi Iwai 26395f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin); 26405f171baaSTakashi Iwai 26415f171baaSTakashi Iwai static const char * const out_jack_texts[] = { 26425f171baaSTakashi Iwai "Line Out", "Headphone Out", 26435f171baaSTakashi Iwai }; 26445f171baaSTakashi Iwai 2645978e77e7STakashi Iwai static int out_jack_mode_info(struct snd_kcontrol *kcontrol, 2646978e77e7STakashi Iwai struct snd_ctl_elem_info *uinfo) 2647978e77e7STakashi Iwai { 26485f171baaSTakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts); 2649978e77e7STakashi Iwai } 2650978e77e7STakashi Iwai 2651978e77e7STakashi Iwai static int out_jack_mode_get(struct snd_kcontrol *kcontrol, 2652978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2653978e77e7STakashi Iwai { 2654978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2655978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2656978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP) 2657978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 1; 2658978e77e7STakashi Iwai else 2659978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 0; 2660978e77e7STakashi Iwai return 0; 2661978e77e7STakashi Iwai } 2662978e77e7STakashi Iwai 2663978e77e7STakashi Iwai static int out_jack_mode_put(struct snd_kcontrol *kcontrol, 2664978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2665978e77e7STakashi Iwai { 2666978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2667978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2668978e77e7STakashi Iwai unsigned int val; 2669978e77e7STakashi Iwai 2670978e77e7STakashi Iwai val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT; 2671978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == val) 2672978e77e7STakashi Iwai return 0; 2673978e77e7STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2674978e77e7STakashi Iwai return 1; 2675978e77e7STakashi Iwai } 2676978e77e7STakashi Iwai 2677978e77e7STakashi Iwai static const struct snd_kcontrol_new out_jack_mode_enum = { 2678978e77e7STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2679978e77e7STakashi Iwai .info = out_jack_mode_info, 2680978e77e7STakashi Iwai .get = out_jack_mode_get, 2681978e77e7STakashi Iwai .put = out_jack_mode_put, 2682978e77e7STakashi Iwai }; 2683978e77e7STakashi Iwai 2684978e77e7STakashi Iwai static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) 2685978e77e7STakashi Iwai { 2686978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2687a9c2dfc8STakashi Iwai const struct snd_kcontrol_new *kctl; 2688978e77e7STakashi Iwai int i; 2689978e77e7STakashi Iwai 2690a9c2dfc8STakashi Iwai snd_array_for_each(&spec->kctls, i, kctl) { 2691978e77e7STakashi Iwai if (!strcmp(kctl->name, name) && kctl->index == idx) 2692978e77e7STakashi Iwai return true; 2693978e77e7STakashi Iwai } 2694978e77e7STakashi Iwai return false; 2695978e77e7STakashi Iwai } 2696978e77e7STakashi Iwai 2697978e77e7STakashi Iwai static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, 2698978e77e7STakashi Iwai char *name, size_t name_len) 2699978e77e7STakashi Iwai { 2700978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2701978e77e7STakashi Iwai int idx = 0; 2702978e77e7STakashi Iwai 2703978e77e7STakashi Iwai snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); 2704978e77e7STakashi Iwai strlcat(name, " Jack Mode", name_len); 2705978e77e7STakashi Iwai 2706978e77e7STakashi Iwai for (; find_kctl_name(codec, name, idx); idx++) 2707978e77e7STakashi Iwai ; 2708978e77e7STakashi Iwai } 2709978e77e7STakashi Iwai 27105f171baaSTakashi Iwai static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin) 27115f171baaSTakashi Iwai { 27125f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2713f811c3cfSTakashi Iwai if (spec->add_jack_modes) { 27145f171baaSTakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, pin); 27155f171baaSTakashi Iwai if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) 27165f171baaSTakashi Iwai return 2; 27175f171baaSTakashi Iwai } 27185f171baaSTakashi Iwai return 1; 27195f171baaSTakashi Iwai } 27205f171baaSTakashi Iwai 2721978e77e7STakashi Iwai static int create_out_jack_modes(struct hda_codec *codec, int num_pins, 2722978e77e7STakashi Iwai hda_nid_t *pins) 2723978e77e7STakashi Iwai { 2724978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2725978e77e7STakashi Iwai int i; 2726978e77e7STakashi Iwai 2727978e77e7STakashi Iwai for (i = 0; i < num_pins; i++) { 2728978e77e7STakashi Iwai hda_nid_t pin = pins[i]; 2729ced4cefcSTakashi Iwai if (pin == spec->hp_mic_pin) 27305f171baaSTakashi Iwai continue; 27315f171baaSTakashi Iwai if (get_out_jack_num_items(codec, pin) > 1) { 2732978e77e7STakashi Iwai struct snd_kcontrol_new *knew; 2733975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 2734978e77e7STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 2735978e77e7STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, 2736978e77e7STakashi Iwai &out_jack_mode_enum); 2737978e77e7STakashi Iwai if (!knew) 2738978e77e7STakashi Iwai return -ENOMEM; 2739978e77e7STakashi Iwai knew->private_value = pin; 2740978e77e7STakashi Iwai } 2741978e77e7STakashi Iwai } 2742978e77e7STakashi Iwai 2743978e77e7STakashi Iwai return 0; 2744978e77e7STakashi Iwai } 2745978e77e7STakashi Iwai 274629476558STakashi Iwai /* 274729476558STakashi Iwai * input jack mode 274829476558STakashi Iwai */ 274929476558STakashi Iwai 275029476558STakashi Iwai /* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */ 275129476558STakashi Iwai #define NUM_VREFS 6 275229476558STakashi Iwai 275329476558STakashi Iwai static const char * const vref_texts[NUM_VREFS] = { 275429476558STakashi Iwai "Line In", "Mic 50pc Bias", "Mic 0V Bias", 275529476558STakashi Iwai "", "Mic 80pc Bias", "Mic 100pc Bias" 275629476558STakashi Iwai }; 275729476558STakashi Iwai 275829476558STakashi Iwai static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin) 275929476558STakashi Iwai { 276029476558STakashi Iwai unsigned int pincap; 276129476558STakashi Iwai 276229476558STakashi Iwai pincap = snd_hda_query_pin_caps(codec, pin); 276329476558STakashi Iwai pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; 276429476558STakashi Iwai /* filter out unusual vrefs */ 276529476558STakashi Iwai pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100); 276629476558STakashi Iwai return pincap; 276729476558STakashi Iwai } 276829476558STakashi Iwai 276929476558STakashi Iwai /* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */ 277029476558STakashi Iwai static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx) 277129476558STakashi Iwai { 277229476558STakashi Iwai unsigned int i, n = 0; 277329476558STakashi Iwai 277429476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) { 277529476558STakashi Iwai if (vref_caps & (1 << i)) { 277629476558STakashi Iwai if (n == item_idx) 277729476558STakashi Iwai return i; 277829476558STakashi Iwai n++; 277929476558STakashi Iwai } 278029476558STakashi Iwai } 278129476558STakashi Iwai return 0; 278229476558STakashi Iwai } 278329476558STakashi Iwai 278429476558STakashi Iwai /* convert back from the vref ctl index to the enum item index */ 278529476558STakashi Iwai static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx) 278629476558STakashi Iwai { 278729476558STakashi Iwai unsigned int i, n = 0; 278829476558STakashi Iwai 278929476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) { 279029476558STakashi Iwai if (i == idx) 279129476558STakashi Iwai return n; 279229476558STakashi Iwai if (vref_caps & (1 << i)) 279329476558STakashi Iwai n++; 279429476558STakashi Iwai } 279529476558STakashi Iwai return 0; 279629476558STakashi Iwai } 279729476558STakashi Iwai 279829476558STakashi Iwai static int in_jack_mode_info(struct snd_kcontrol *kcontrol, 279929476558STakashi Iwai struct snd_ctl_elem_info *uinfo) 280029476558STakashi Iwai { 280129476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 280229476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 280329476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 280429476558STakashi Iwai 280529476558STakashi Iwai snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps), 280629476558STakashi Iwai vref_texts); 280729476558STakashi Iwai /* set the right text */ 280829476558STakashi Iwai strcpy(uinfo->value.enumerated.name, 280929476558STakashi Iwai vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]); 281029476558STakashi Iwai return 0; 281129476558STakashi Iwai } 281229476558STakashi Iwai 281329476558STakashi Iwai static int in_jack_mode_get(struct snd_kcontrol *kcontrol, 281429476558STakashi Iwai struct snd_ctl_elem_value *ucontrol) 281529476558STakashi Iwai { 281629476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 281729476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 281829476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 281929476558STakashi Iwai unsigned int idx; 282029476558STakashi Iwai 282129476558STakashi Iwai idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN; 282229476558STakashi Iwai ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx); 282329476558STakashi Iwai return 0; 282429476558STakashi Iwai } 282529476558STakashi Iwai 282629476558STakashi Iwai static int in_jack_mode_put(struct snd_kcontrol *kcontrol, 282729476558STakashi Iwai struct snd_ctl_elem_value *ucontrol) 282829476558STakashi Iwai { 282929476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 283029476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 283129476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 283229476558STakashi Iwai unsigned int val, idx; 283329476558STakashi Iwai 283429476558STakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid); 283529476558STakashi Iwai idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN); 283629476558STakashi Iwai if (idx == ucontrol->value.enumerated.item[0]) 283729476558STakashi Iwai return 0; 283829476558STakashi Iwai 283929476558STakashi Iwai val &= ~AC_PINCTL_VREFEN; 284029476558STakashi Iwai val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]); 284129476558STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 284229476558STakashi Iwai return 1; 284329476558STakashi Iwai } 284429476558STakashi Iwai 284529476558STakashi Iwai static const struct snd_kcontrol_new in_jack_mode_enum = { 284629476558STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 284729476558STakashi Iwai .info = in_jack_mode_info, 284829476558STakashi Iwai .get = in_jack_mode_get, 284929476558STakashi Iwai .put = in_jack_mode_put, 285029476558STakashi Iwai }; 285129476558STakashi Iwai 28525f171baaSTakashi Iwai static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin) 28535f171baaSTakashi Iwai { 28545f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 28555f171baaSTakashi Iwai int nitems = 0; 2856f811c3cfSTakashi Iwai if (spec->add_jack_modes) 28575f171baaSTakashi Iwai nitems = hweight32(get_vref_caps(codec, pin)); 28585f171baaSTakashi Iwai return nitems ? nitems : 1; 28595f171baaSTakashi Iwai } 28605f171baaSTakashi Iwai 286129476558STakashi Iwai static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) 286229476558STakashi Iwai { 286329476558STakashi Iwai struct hda_gen_spec *spec = codec->spec; 286429476558STakashi Iwai struct snd_kcontrol_new *knew; 2865975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 28665f171baaSTakashi Iwai unsigned int defcfg; 28675f171baaSTakashi Iwai 2868f811c3cfSTakashi Iwai if (pin == spec->hp_mic_pin) 2869f811c3cfSTakashi Iwai return 0; /* already done in create_out_jack_mode() */ 287029476558STakashi Iwai 287129476558STakashi Iwai /* no jack mode for fixed pins */ 287229476558STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, pin); 287329476558STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) 287429476558STakashi Iwai return 0; 287529476558STakashi Iwai 287629476558STakashi Iwai /* no multiple vref caps? */ 28775f171baaSTakashi Iwai if (get_in_jack_num_items(codec, pin) <= 1) 287829476558STakashi Iwai return 0; 287929476558STakashi Iwai 288029476558STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 288129476558STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum); 288229476558STakashi Iwai if (!knew) 288329476558STakashi Iwai return -ENOMEM; 288429476558STakashi Iwai knew->private_value = pin; 288529476558STakashi Iwai return 0; 288629476558STakashi Iwai } 288729476558STakashi Iwai 28885f171baaSTakashi Iwai /* 28895f171baaSTakashi Iwai * HP/mic shared jack mode 28905f171baaSTakashi Iwai */ 28915f171baaSTakashi Iwai static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol, 28925f171baaSTakashi Iwai struct snd_ctl_elem_info *uinfo) 28935f171baaSTakashi Iwai { 28945f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 28955f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value; 28965f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid); 28975f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid); 28985f171baaSTakashi Iwai const char *text = NULL; 28995f171baaSTakashi Iwai int idx; 29005f171baaSTakashi Iwai 29015f171baaSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 29025f171baaSTakashi Iwai uinfo->count = 1; 29035f171baaSTakashi Iwai uinfo->value.enumerated.items = out_jacks + in_jacks; 29045f171baaSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 29055f171baaSTakashi Iwai uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 29065f171baaSTakashi Iwai idx = uinfo->value.enumerated.item; 29075f171baaSTakashi Iwai if (idx < out_jacks) { 29085f171baaSTakashi Iwai if (out_jacks > 1) 29095f171baaSTakashi Iwai text = out_jack_texts[idx]; 29105f171baaSTakashi Iwai else 29115f171baaSTakashi Iwai text = "Headphone Out"; 29125f171baaSTakashi Iwai } else { 29135f171baaSTakashi Iwai idx -= out_jacks; 29145f171baaSTakashi Iwai if (in_jacks > 1) { 29155f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 29165f171baaSTakashi Iwai text = vref_texts[get_vref_idx(vref_caps, idx)]; 29175f171baaSTakashi Iwai } else 29185f171baaSTakashi Iwai text = "Mic In"; 29195f171baaSTakashi Iwai } 29205f171baaSTakashi Iwai 29215f171baaSTakashi Iwai strcpy(uinfo->value.enumerated.name, text); 29225f171baaSTakashi Iwai return 0; 29235f171baaSTakashi Iwai } 29245f171baaSTakashi Iwai 29255f171baaSTakashi Iwai static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid) 29265f171baaSTakashi Iwai { 29275f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid); 29285f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid); 29295f171baaSTakashi Iwai unsigned int val = snd_hda_codec_get_pin_target(codec, nid); 29305f171baaSTakashi Iwai int idx = 0; 29315f171baaSTakashi Iwai 29325f171baaSTakashi Iwai if (val & PIN_OUT) { 29335f171baaSTakashi Iwai if (out_jacks > 1 && val == PIN_HP) 29345f171baaSTakashi Iwai idx = 1; 29355f171baaSTakashi Iwai } else if (val & PIN_IN) { 29365f171baaSTakashi Iwai idx = out_jacks; 29375f171baaSTakashi Iwai if (in_jacks > 1) { 29385f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 29395f171baaSTakashi Iwai val &= AC_PINCTL_VREFEN; 29405f171baaSTakashi Iwai idx += cvt_from_vref_idx(vref_caps, val); 29415f171baaSTakashi Iwai } 29425f171baaSTakashi Iwai } 29435f171baaSTakashi Iwai return idx; 29445f171baaSTakashi Iwai } 29455f171baaSTakashi Iwai 29465f171baaSTakashi Iwai static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol, 29475f171baaSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 29485f171baaSTakashi Iwai { 29495f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 29505f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value; 29515f171baaSTakashi Iwai ucontrol->value.enumerated.item[0] = 29525f171baaSTakashi Iwai get_cur_hp_mic_jack_mode(codec, nid); 29535f171baaSTakashi Iwai return 0; 29545f171baaSTakashi Iwai } 29555f171baaSTakashi Iwai 29565f171baaSTakashi Iwai static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol, 29575f171baaSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 29585f171baaSTakashi Iwai { 29595f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 29605f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value; 29615f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid); 29625f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid); 29635f171baaSTakashi Iwai unsigned int val, oldval, idx; 29645f171baaSTakashi Iwai 29655f171baaSTakashi Iwai oldval = get_cur_hp_mic_jack_mode(codec, nid); 29665f171baaSTakashi Iwai idx = ucontrol->value.enumerated.item[0]; 29675f171baaSTakashi Iwai if (oldval == idx) 29685f171baaSTakashi Iwai return 0; 29695f171baaSTakashi Iwai 29705f171baaSTakashi Iwai if (idx < out_jacks) { 29715f171baaSTakashi Iwai if (out_jacks > 1) 29725f171baaSTakashi Iwai val = idx ? PIN_HP : PIN_OUT; 29735f171baaSTakashi Iwai else 29745f171baaSTakashi Iwai val = PIN_HP; 29755f171baaSTakashi Iwai } else { 29765f171baaSTakashi Iwai idx -= out_jacks; 29775f171baaSTakashi Iwai if (in_jacks > 1) { 29785f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 29795f171baaSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid); 29803f550e32STakashi Iwai val &= ~(AC_PINCTL_VREFEN | PIN_HP); 29813f550e32STakashi Iwai val |= get_vref_idx(vref_caps, idx) | PIN_IN; 29825f171baaSTakashi Iwai } else 298316c0cefeSTakashi Iwai val = snd_hda_get_default_vref(codec, nid) | PIN_IN; 29845f171baaSTakashi Iwai } 29855f171baaSTakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2986963afde9STakashi Iwai call_hp_automute(codec, NULL); 29878ba955ceSTakashi Iwai 29885f171baaSTakashi Iwai return 1; 29895f171baaSTakashi Iwai } 29905f171baaSTakashi Iwai 29915f171baaSTakashi Iwai static const struct snd_kcontrol_new hp_mic_jack_mode_enum = { 29925f171baaSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 29935f171baaSTakashi Iwai .info = hp_mic_jack_mode_info, 29945f171baaSTakashi Iwai .get = hp_mic_jack_mode_get, 29955f171baaSTakashi Iwai .put = hp_mic_jack_mode_put, 29965f171baaSTakashi Iwai }; 29975f171baaSTakashi Iwai 29985f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin) 29995f171baaSTakashi Iwai { 30005f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 30015f171baaSTakashi Iwai struct snd_kcontrol_new *knew; 30025f171baaSTakashi Iwai 30035f171baaSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode", 30045f171baaSTakashi Iwai &hp_mic_jack_mode_enum); 30055f171baaSTakashi Iwai if (!knew) 30065f171baaSTakashi Iwai return -ENOMEM; 30075f171baaSTakashi Iwai knew->private_value = pin; 30088ba955ceSTakashi Iwai spec->hp_mic_jack_modes = 1; 30095f171baaSTakashi Iwai return 0; 30105f171baaSTakashi Iwai } 3011352f7f91STakashi Iwai 3012352f7f91STakashi Iwai /* 3013352f7f91STakashi Iwai * Parse input paths 3014352f7f91STakashi Iwai */ 3015352f7f91STakashi Iwai 3016352f7f91STakashi Iwai /* add the powersave loopback-list entry */ 30170186f4f4STakashi Iwai static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) 3018352f7f91STakashi Iwai { 3019352f7f91STakashi Iwai struct hda_amp_list *list; 3020352f7f91STakashi Iwai 30210186f4f4STakashi Iwai list = snd_array_new(&spec->loopback_list); 30220186f4f4STakashi Iwai if (!list) 30230186f4f4STakashi Iwai return -ENOMEM; 3024352f7f91STakashi Iwai list->nid = mix; 3025352f7f91STakashi Iwai list->dir = HDA_INPUT; 3026352f7f91STakashi Iwai list->idx = idx; 30270186f4f4STakashi Iwai spec->loopback.amplist = spec->loopback_list.list; 30280186f4f4STakashi Iwai return 0; 3029cb53c626STakashi Iwai } 3030cb53c626STakashi Iwai 30312ded3e5bSTakashi Iwai /* return true if either a volume or a mute amp is found for the given 30322ded3e5bSTakashi Iwai * aamix path; the amp has to be either in the mixer node or its direct leaf 30332ded3e5bSTakashi Iwai */ 30342ded3e5bSTakashi Iwai static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid, 30352ded3e5bSTakashi Iwai hda_nid_t pin, unsigned int *mix_val, 30362ded3e5bSTakashi Iwai unsigned int *mute_val) 30372ded3e5bSTakashi Iwai { 30382ded3e5bSTakashi Iwai int idx, num_conns; 30392ded3e5bSTakashi Iwai const hda_nid_t *list; 30402ded3e5bSTakashi Iwai hda_nid_t nid; 30412ded3e5bSTakashi Iwai 30422ded3e5bSTakashi Iwai idx = snd_hda_get_conn_index(codec, mix_nid, pin, true); 30432ded3e5bSTakashi Iwai if (idx < 0) 30442ded3e5bSTakashi Iwai return false; 30452ded3e5bSTakashi Iwai 30462ded3e5bSTakashi Iwai *mix_val = *mute_val = 0; 30472ded3e5bSTakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT)) 30482ded3e5bSTakashi Iwai *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 30492ded3e5bSTakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT)) 30502ded3e5bSTakashi Iwai *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 30512ded3e5bSTakashi Iwai if (*mix_val && *mute_val) 30522ded3e5bSTakashi Iwai return true; 30532ded3e5bSTakashi Iwai 30542ded3e5bSTakashi Iwai /* check leaf node */ 30552ded3e5bSTakashi Iwai num_conns = snd_hda_get_conn_list(codec, mix_nid, &list); 30562ded3e5bSTakashi Iwai if (num_conns < idx) 30572ded3e5bSTakashi Iwai return false; 30582ded3e5bSTakashi Iwai nid = list[idx]; 305943a8e50aSTakashi Iwai if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) && 306043a8e50aSTakashi Iwai !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL)) 30612ded3e5bSTakashi Iwai *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 306243a8e50aSTakashi Iwai if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) && 306343a8e50aSTakashi Iwai !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL)) 30642ded3e5bSTakashi Iwai *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 30652ded3e5bSTakashi Iwai 30662ded3e5bSTakashi Iwai return *mix_val || *mute_val; 30672ded3e5bSTakashi Iwai } 30682ded3e5bSTakashi Iwai 3069352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */ 3070196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx, 3071196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx, 3072352f7f91STakashi Iwai hda_nid_t mix_nid) 30731da177e4SLinus Torvalds { 3074352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3075352f7f91STakashi Iwai struct nid_path *path; 30762ded3e5bSTakashi Iwai unsigned int mix_val, mute_val; 3077352f7f91STakashi Iwai int err, idx; 30781da177e4SLinus Torvalds 30792ded3e5bSTakashi Iwai if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val)) 30802ded3e5bSTakashi Iwai return 0; 3081352f7f91STakashi Iwai 30823ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, 0); 3083352f7f91STakashi Iwai if (!path) 3084352f7f91STakashi Iwai return -EINVAL; 30854e76a883STakashi Iwai print_nid_path(codec, "loopback", path); 3086196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 3087352f7f91STakashi Iwai 3088352f7f91STakashi Iwai idx = path->idx[path->depth - 1]; 30892ded3e5bSTakashi Iwai if (mix_val) { 30902ded3e5bSTakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val); 3091d13bd412STakashi Iwai if (err < 0) 30921da177e4SLinus Torvalds return err; 30932ded3e5bSTakashi Iwai path->ctls[NID_PATH_VOL_CTL] = mix_val; 30941da177e4SLinus Torvalds } 30951da177e4SLinus Torvalds 30962ded3e5bSTakashi Iwai if (mute_val) { 30972ded3e5bSTakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val); 3098d13bd412STakashi Iwai if (err < 0) 30991da177e4SLinus Torvalds return err; 31002ded3e5bSTakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = mute_val; 31011da177e4SLinus Torvalds } 31021da177e4SLinus Torvalds 3103352f7f91STakashi Iwai path->active = true; 3104e6feb5d0STakashi Iwai path->stream_enabled = true; /* no DAC/ADC involved */ 31050186f4f4STakashi Iwai err = add_loopback_list(spec, mix_nid, idx); 31060186f4f4STakashi Iwai if (err < 0) 31070186f4f4STakashi Iwai return err; 3108e4a395e7STakashi Iwai 3109e4a395e7STakashi Iwai if (spec->mixer_nid != spec->mixer_merge_nid && 3110e4a395e7STakashi Iwai !spec->loopback_merge_path) { 3111e4a395e7STakashi Iwai path = snd_hda_add_new_path(codec, spec->mixer_nid, 3112e4a395e7STakashi Iwai spec->mixer_merge_nid, 0); 3113e4a395e7STakashi Iwai if (path) { 31144e76a883STakashi Iwai print_nid_path(codec, "loopback-merge", path); 3115e4a395e7STakashi Iwai path->active = true; 31166b275b14STakashi Iwai path->pin_fixed = true; /* static route */ 3117e6feb5d0STakashi Iwai path->stream_enabled = true; /* no DAC/ADC involved */ 3118e4a395e7STakashi Iwai spec->loopback_merge_path = 3119e4a395e7STakashi Iwai snd_hda_get_path_idx(codec, path); 3120e4a395e7STakashi Iwai } 3121e4a395e7STakashi Iwai } 3122e4a395e7STakashi Iwai 3123352f7f91STakashi Iwai return 0; 31241da177e4SLinus Torvalds } 31251da177e4SLinus Torvalds 3126352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) 31271da177e4SLinus Torvalds { 3128352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 3129352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0; 3130352f7f91STakashi Iwai } 3131352f7f91STakashi Iwai 3132352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */ 3133352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec) 3134352f7f91STakashi Iwai { 3135352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3136352f7f91STakashi Iwai hda_nid_t nid; 3137352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids; 3138352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids); 31397639a06cSTakashi Iwai int nums = 0; 3140352f7f91STakashi Iwai 31417639a06cSTakashi Iwai for_each_hda_codec_node(nid, codec) { 3142352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 3143352f7f91STakashi Iwai int type = get_wcaps_type(caps); 3144352f7f91STakashi Iwai 3145352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) 3146352f7f91STakashi Iwai continue; 3147352f7f91STakashi Iwai adc_nids[nums] = nid; 3148352f7f91STakashi Iwai if (++nums >= max_nums) 3149352f7f91STakashi Iwai break; 3150352f7f91STakashi Iwai } 3151352f7f91STakashi Iwai spec->num_adc_nids = nums; 31520ffd534eSTakashi Iwai 31530ffd534eSTakashi Iwai /* copy the detected ADCs to all_adcs[] */ 31540ffd534eSTakashi Iwai spec->num_all_adcs = nums; 31550ffd534eSTakashi Iwai memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t)); 31560ffd534eSTakashi Iwai 3157352f7f91STakashi Iwai return nums; 3158352f7f91STakashi Iwai } 3159352f7f91STakashi Iwai 3160352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins; 3161352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available 3162352f7f91STakashi Iwai */ 3163352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec) 3164352f7f91STakashi Iwai { 3165352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3166352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 31673a65bcdcSTakashi Iwai unsigned int ok_bits; 3168352f7f91STakashi Iwai int i, n, nums; 3169352f7f91STakashi Iwai 3170352f7f91STakashi Iwai nums = 0; 31713a65bcdcSTakashi Iwai ok_bits = 0; 3172352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 3173352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 31743a65bcdcSTakashi Iwai if (!spec->input_paths[i][n]) 3175352f7f91STakashi Iwai break; 3176352f7f91STakashi Iwai } 31773a65bcdcSTakashi Iwai if (i >= imux->num_items) { 31783a65bcdcSTakashi Iwai ok_bits |= (1 << n); 31793a65bcdcSTakashi Iwai nums++; 31803a65bcdcSTakashi Iwai } 3181352f7f91STakashi Iwai } 3182352f7f91STakashi Iwai 31833a65bcdcSTakashi Iwai if (!ok_bits) { 3184352f7f91STakashi Iwai /* check whether ADC-switch is possible */ 3185352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3186352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 31873a65bcdcSTakashi Iwai if (spec->input_paths[i][n]) { 3188352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n; 3189352f7f91STakashi Iwai break; 3190352f7f91STakashi Iwai } 3191352f7f91STakashi Iwai } 3192352f7f91STakashi Iwai } 3193352f7f91STakashi Iwai 31944e76a883STakashi Iwai codec_dbg(codec, "enabling ADC switching\n"); 3195352f7f91STakashi Iwai spec->dyn_adc_switch = 1; 3196352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) { 31973a65bcdcSTakashi Iwai /* shrink the invalid adcs and input paths */ 31983a65bcdcSTakashi Iwai nums = 0; 31993a65bcdcSTakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 32003a65bcdcSTakashi Iwai if (!(ok_bits & (1 << n))) 32013a65bcdcSTakashi Iwai continue; 32023a65bcdcSTakashi Iwai if (n != nums) { 32033a65bcdcSTakashi Iwai spec->adc_nids[nums] = spec->adc_nids[n]; 3204980428ceSTakashi Iwai for (i = 0; i < imux->num_items; i++) { 3205980428ceSTakashi Iwai invalidate_nid_path(codec, 3206980428ceSTakashi Iwai spec->input_paths[i][nums]); 32073a65bcdcSTakashi Iwai spec->input_paths[i][nums] = 32083a65bcdcSTakashi Iwai spec->input_paths[i][n]; 3209a8f20fd2SHui Wang spec->input_paths[i][n] = 0; 32103a65bcdcSTakashi Iwai } 3211980428ceSTakashi Iwai } 32123a65bcdcSTakashi Iwai nums++; 32133a65bcdcSTakashi Iwai } 3214352f7f91STakashi Iwai spec->num_adc_nids = nums; 3215352f7f91STakashi Iwai } 3216352f7f91STakashi Iwai 3217967303daSTakashi Iwai if (imux->num_items == 1 || 3218967303daSTakashi Iwai (imux->num_items == 2 && spec->hp_mic)) { 32194e76a883STakashi Iwai codec_dbg(codec, "reducing to a single ADC\n"); 3220352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */ 3221352f7f91STakashi Iwai } 3222352f7f91STakashi Iwai 3223352f7f91STakashi Iwai /* single index for individual volumes ctls */ 3224352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol) 3225352f7f91STakashi Iwai spec->num_adc_nids = 1; 3226352f7f91STakashi Iwai 32271da177e4SLinus Torvalds return 0; 32281da177e4SLinus Torvalds } 32291da177e4SLinus Torvalds 3230f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */ 3231f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, 32329dba205bSTakashi Iwai int cfg_idx, int num_adcs, 32339dba205bSTakashi Iwai const char *label, int anchor) 3234f3fc0b0bSTakashi Iwai { 3235f3fc0b0bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 3236f3fc0b0bSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3237f3fc0b0bSTakashi Iwai int imux_idx = imux->num_items; 3238f3fc0b0bSTakashi Iwai bool imux_added = false; 3239f3fc0b0bSTakashi Iwai int c; 3240f3fc0b0bSTakashi Iwai 3241f3fc0b0bSTakashi Iwai for (c = 0; c < num_adcs; c++) { 3242f3fc0b0bSTakashi Iwai struct nid_path *path; 3243f3fc0b0bSTakashi Iwai hda_nid_t adc = spec->adc_nids[c]; 3244f3fc0b0bSTakashi Iwai 3245f3fc0b0bSTakashi Iwai if (!is_reachable_path(codec, pin, adc)) 3246f3fc0b0bSTakashi Iwai continue; 3247f3fc0b0bSTakashi Iwai path = snd_hda_add_new_path(codec, pin, adc, anchor); 3248f3fc0b0bSTakashi Iwai if (!path) 3249f3fc0b0bSTakashi Iwai continue; 32504e76a883STakashi Iwai print_nid_path(codec, "input", path); 3251f3fc0b0bSTakashi Iwai spec->input_paths[imux_idx][c] = 3252f3fc0b0bSTakashi Iwai snd_hda_get_path_idx(codec, path); 3253f3fc0b0bSTakashi Iwai 3254f3fc0b0bSTakashi Iwai if (!imux_added) { 3255967303daSTakashi Iwai if (spec->hp_mic_pin == pin) 3256967303daSTakashi Iwai spec->hp_mic_mux_idx = imux->num_items; 3257f3fc0b0bSTakashi Iwai spec->imux_pins[imux->num_items] = pin; 32586194b99dSTakashi Iwai snd_hda_add_imux_item(codec, imux, label, cfg_idx, NULL); 3259f3fc0b0bSTakashi Iwai imux_added = true; 3260f1e762ddSTakashi Iwai if (spec->dyn_adc_switch) 3261f1e762ddSTakashi Iwai spec->dyn_adc_idx[imux_idx] = c; 3262f3fc0b0bSTakashi Iwai } 3263f3fc0b0bSTakashi Iwai } 3264f3fc0b0bSTakashi Iwai 3265f3fc0b0bSTakashi Iwai return 0; 3266f3fc0b0bSTakashi Iwai } 3267f3fc0b0bSTakashi Iwai 32681da177e4SLinus Torvalds /* 3269352f7f91STakashi Iwai * create playback/capture controls for input pins 32701da177e4SLinus Torvalds */ 32719dba205bSTakashi Iwai 3272c970042cSTakashi Iwai /* fill the label for each input at first */ 3273c970042cSTakashi Iwai static int fill_input_pin_labels(struct hda_codec *codec) 3274c970042cSTakashi Iwai { 3275c970042cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 3276c970042cSTakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 3277c970042cSTakashi Iwai int i; 3278c970042cSTakashi Iwai 3279c970042cSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3280c970042cSTakashi Iwai hda_nid_t pin = cfg->inputs[i].pin; 3281c970042cSTakashi Iwai const char *label; 3282c970042cSTakashi Iwai int j, idx; 3283c970042cSTakashi Iwai 3284c970042cSTakashi Iwai if (!is_input_pin(codec, pin)) 3285c970042cSTakashi Iwai continue; 3286c970042cSTakashi Iwai 3287c970042cSTakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 3288c970042cSTakashi Iwai idx = 0; 32898e8db7f1SDavid Henningsson for (j = i - 1; j >= 0; j--) { 3290c970042cSTakashi Iwai if (spec->input_labels[j] && 3291c970042cSTakashi Iwai !strcmp(spec->input_labels[j], label)) { 3292c970042cSTakashi Iwai idx = spec->input_label_idxs[j] + 1; 3293c970042cSTakashi Iwai break; 3294c970042cSTakashi Iwai } 3295c970042cSTakashi Iwai } 3296c970042cSTakashi Iwai 3297c970042cSTakashi Iwai spec->input_labels[i] = label; 3298c970042cSTakashi Iwai spec->input_label_idxs[i] = idx; 3299c970042cSTakashi Iwai } 3300c970042cSTakashi Iwai 3301c970042cSTakashi Iwai return 0; 3302c970042cSTakashi Iwai } 3303c970042cSTakashi Iwai 33049dba205bSTakashi Iwai #define CFG_IDX_MIX 99 /* a dummy cfg->input idx for stereo mix */ 33059dba205bSTakashi Iwai 3306352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec) 3307a7da6ce5STakashi Iwai { 3308352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3309352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 3310352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid; 3311352f7f91STakashi Iwai int num_adcs; 3312c970042cSTakashi Iwai int i, err; 33132c12c30dSTakashi Iwai unsigned int val; 3314a7da6ce5STakashi Iwai 3315352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec); 3316352f7f91STakashi Iwai if (num_adcs < 0) 3317352f7f91STakashi Iwai return 0; 3318352f7f91STakashi Iwai 3319c970042cSTakashi Iwai err = fill_input_pin_labels(codec); 3320c970042cSTakashi Iwai if (err < 0) 3321c970042cSTakashi Iwai return err; 3322c970042cSTakashi Iwai 3323352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3324352f7f91STakashi Iwai hda_nid_t pin; 3325352f7f91STakashi Iwai 3326352f7f91STakashi Iwai pin = cfg->inputs[i].pin; 3327352f7f91STakashi Iwai if (!is_input_pin(codec, pin)) 3328352f7f91STakashi Iwai continue; 3329352f7f91STakashi Iwai 33302c12c30dSTakashi Iwai val = PIN_IN; 33312c12c30dSTakashi Iwai if (cfg->inputs[i].type == AUTO_PIN_MIC) 33322c12c30dSTakashi Iwai val |= snd_hda_get_default_vref(codec, pin); 33333e1b0c4aSTakashi Iwai if (pin != spec->hp_mic_pin && 33343e1b0c4aSTakashi Iwai !snd_hda_codec_get_pin_target(codec, pin)) 33352c12c30dSTakashi Iwai set_pin_target(codec, pin, val, false); 33362c12c30dSTakashi Iwai 3337352f7f91STakashi Iwai if (mixer) { 3338352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) { 3339196c1766STakashi Iwai err = new_analog_input(codec, i, pin, 3340c970042cSTakashi Iwai spec->input_labels[i], 3341c970042cSTakashi Iwai spec->input_label_idxs[i], 3342c970042cSTakashi Iwai mixer); 3343a7da6ce5STakashi Iwai if (err < 0) 3344a7da6ce5STakashi Iwai return err; 3345a7da6ce5STakashi Iwai } 3346352f7f91STakashi Iwai } 3347352f7f91STakashi Iwai 3348c970042cSTakashi Iwai err = parse_capture_source(codec, pin, i, num_adcs, 3349c970042cSTakashi Iwai spec->input_labels[i], -mixer); 3350f3fc0b0bSTakashi Iwai if (err < 0) 3351f3fc0b0bSTakashi Iwai return err; 335229476558STakashi Iwai 3353f811c3cfSTakashi Iwai if (spec->add_jack_modes) { 335429476558STakashi Iwai err = create_in_jack_mode(codec, pin); 335529476558STakashi Iwai if (err < 0) 335629476558STakashi Iwai return err; 335729476558STakashi Iwai } 3358352f7f91STakashi Iwai } 3359f3fc0b0bSTakashi Iwai 3360f1e762ddSTakashi Iwai /* add stereo mix when explicitly enabled via hint */ 336174f14b36STakashi Iwai if (mixer && spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_ENABLE) { 33629dba205bSTakashi Iwai err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs, 3363f3fc0b0bSTakashi Iwai "Stereo Mix", 0); 3364f3fc0b0bSTakashi Iwai if (err < 0) 3365f3fc0b0bSTakashi Iwai return err; 336682d04e10STakashi Iwai else 336782d04e10STakashi Iwai spec->suppress_auto_mic = 1; 3368352f7f91STakashi Iwai } 3369352f7f91STakashi Iwai 3370a7da6ce5STakashi Iwai return 0; 3371a7da6ce5STakashi Iwai } 3372a7da6ce5STakashi Iwai 33731da177e4SLinus Torvalds 3374352f7f91STakashi Iwai /* 3375352f7f91STakashi Iwai * input source mux 3376352f7f91STakashi Iwai */ 3377352f7f91STakashi Iwai 3378c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */ 3379c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx) 3380352f7f91STakashi Iwai { 3381352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3382b56fa1edSDavid Henningsson if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) { 3383b56fa1edSDavid Henningsson snd_BUG(); 3384b56fa1edSDavid Henningsson return NULL; 3385b56fa1edSDavid Henningsson } 3386352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3387352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx]; 3388d3d982f7SDavid Henningsson if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) { 3389b56fa1edSDavid Henningsson snd_BUG(); 3390b56fa1edSDavid Henningsson return NULL; 3391b56fa1edSDavid Henningsson } 3392c697b716STakashi Iwai return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]); 339397ec558aSTakashi Iwai } 3394352f7f91STakashi Iwai 3395352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 3396352f7f91STakashi Iwai unsigned int idx); 3397352f7f91STakashi Iwai 3398352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol, 3399352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 3400352f7f91STakashi Iwai { 3401352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3402352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3403352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo); 3404352f7f91STakashi Iwai } 3405352f7f91STakashi Iwai 3406352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol, 3407352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3408352f7f91STakashi Iwai { 3409352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3410352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 34112a8d5391STakashi Iwai /* the ctls are created at once with multiple counts */ 34122a8d5391STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3413352f7f91STakashi Iwai 3414352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 34151da177e4SLinus Torvalds return 0; 34161da177e4SLinus Torvalds } 34171da177e4SLinus Torvalds 3418352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol, 3419352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 34201da177e4SLinus Torvalds { 3421352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 34222a8d5391STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3423352f7f91STakashi Iwai return mux_select(codec, adc_idx, 3424352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]); 3425352f7f91STakashi Iwai } 3426352f7f91STakashi Iwai 3427352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = { 34281da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3429352f7f91STakashi Iwai .name = "Input Source", 3430352f7f91STakashi Iwai .info = mux_enum_info, 3431352f7f91STakashi Iwai .get = mux_enum_get, 3432352f7f91STakashi Iwai .put = mux_enum_put, 34331da177e4SLinus Torvalds }; 3434071c73adSTakashi Iwai 343547d46abbSTakashi Iwai /* 343647d46abbSTakashi Iwai * capture volume and capture switch ctls 343747d46abbSTakashi Iwai */ 343847d46abbSTakashi Iwai 3439352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, 3440352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol); 3441071c73adSTakashi Iwai 344247d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */ 3443352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol, 3444352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol, 3445352f7f91STakashi Iwai put_call_t func, int type) 3446352f7f91STakashi Iwai { 3447352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3448352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3449352f7f91STakashi Iwai const struct hda_input_mux *imux; 3450352f7f91STakashi Iwai struct nid_path *path; 3451352f7f91STakashi Iwai int i, adc_idx, err = 0; 3452071c73adSTakashi Iwai 3453352f7f91STakashi Iwai imux = &spec->input_mux; 3454a053d1e3SDavid Henningsson adc_idx = kcontrol->id.index; 3455352f7f91STakashi Iwai mutex_lock(&codec->control_mutex); 3456352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3457c697b716STakashi Iwai path = get_input_path(codec, adc_idx, i); 3458c697b716STakashi Iwai if (!path || !path->ctls[type]) 3459352f7f91STakashi Iwai continue; 3460352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type]; 3461352f7f91STakashi Iwai err = func(kcontrol, ucontrol); 3462352f7f91STakashi Iwai if (err < 0) 3463a551d914STakashi Iwai break; 3464352f7f91STakashi Iwai } 3465352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex); 3466352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook) 34677fe30711STakashi Iwai spec->cap_sync_hook(codec, kcontrol, ucontrol); 3468352f7f91STakashi Iwai return err; 3469352f7f91STakashi Iwai } 3470352f7f91STakashi Iwai 3471352f7f91STakashi Iwai /* capture volume ctl callbacks */ 3472352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info 3473352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get 3474352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv 3475352f7f91STakashi Iwai 3476352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol, 3477352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3478352f7f91STakashi Iwai { 3479352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 3480352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put, 3481352f7f91STakashi Iwai NID_PATH_VOL_CTL); 3482352f7f91STakashi Iwai } 3483352f7f91STakashi Iwai 3484352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = { 3485352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3486352f7f91STakashi Iwai .name = "Capture Volume", 3487352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 3488352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ | 3489352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), 3490352f7f91STakashi Iwai .info = cap_vol_info, 3491352f7f91STakashi Iwai .get = cap_vol_get, 3492352f7f91STakashi Iwai .put = cap_vol_put, 3493352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv }, 3494352f7f91STakashi Iwai }; 3495352f7f91STakashi Iwai 3496352f7f91STakashi Iwai /* capture switch ctl callbacks */ 3497352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info 3498352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get 3499352f7f91STakashi Iwai 3500352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol, 3501352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3502352f7f91STakashi Iwai { 3503a90229e0STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 3504352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put, 3505352f7f91STakashi Iwai NID_PATH_MUTE_CTL); 3506352f7f91STakashi Iwai } 3507352f7f91STakashi Iwai 3508352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = { 3509352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3510352f7f91STakashi Iwai .name = "Capture Switch", 3511352f7f91STakashi Iwai .info = cap_sw_info, 3512352f7f91STakashi Iwai .get = cap_sw_get, 3513352f7f91STakashi Iwai .put = cap_sw_put, 3514352f7f91STakashi Iwai }; 3515352f7f91STakashi Iwai 3516352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) 3517352f7f91STakashi Iwai { 3518352f7f91STakashi Iwai hda_nid_t nid; 3519352f7f91STakashi Iwai int i, depth; 3520352f7f91STakashi Iwai 3521352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; 3522352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) { 3523352f7f91STakashi Iwai if (depth >= path->depth) 3524352f7f91STakashi Iwai return -EINVAL; 3525352f7f91STakashi Iwai i = path->depth - depth - 1; 3526352f7f91STakashi Iwai nid = path->path[i]; 3527352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) { 3528352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 3529352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 3530352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 3531352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) { 3532352f7f91STakashi Iwai int idx = path->idx[i]; 3533352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 3534352f7f91STakashi Iwai idx = 0; 3535352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 3536352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 3537352f7f91STakashi Iwai } 3538352f7f91STakashi Iwai } 3539352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) { 3540352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT)) 3541352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 3542352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 3543352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) { 3544352f7f91STakashi Iwai int idx = path->idx[i]; 3545352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 3546352f7f91STakashi Iwai idx = 0; 3547352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 3548352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 3549352f7f91STakashi Iwai } 3550352f7f91STakashi Iwai } 3551352f7f91STakashi Iwai } 3552352f7f91STakashi Iwai return 0; 3553352f7f91STakashi Iwai } 3554352f7f91STakashi Iwai 3555352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) 3556352f7f91STakashi Iwai { 3557352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3558352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3559352f7f91STakashi Iwai unsigned int val; 3560352f7f91STakashi Iwai int i; 3561352f7f91STakashi Iwai 3562352f7f91STakashi Iwai if (!spec->inv_dmic_split) 3563352f7f91STakashi Iwai return false; 3564352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3565352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid) 3566352f7f91STakashi Iwai continue; 3567352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 3568352f7f91STakashi Iwai return false; 3569352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid); 3570352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; 3571352f7f91STakashi Iwai } 3572352f7f91STakashi Iwai return false; 3573352f7f91STakashi Iwai } 3574352f7f91STakashi Iwai 3575a90229e0STakashi Iwai /* capture switch put callback for a single control with hook call */ 3576a35bd1e3STakashi Iwai static int cap_single_sw_put(struct snd_kcontrol *kcontrol, 3577a35bd1e3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3578a35bd1e3STakashi Iwai { 3579a35bd1e3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3580a35bd1e3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3581a35bd1e3STakashi Iwai int ret; 3582a35bd1e3STakashi Iwai 3583a35bd1e3STakashi Iwai ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 3584a35bd1e3STakashi Iwai if (ret < 0) 3585a35bd1e3STakashi Iwai return ret; 3586a35bd1e3STakashi Iwai 3587a90229e0STakashi Iwai if (spec->cap_sync_hook) 35887fe30711STakashi Iwai spec->cap_sync_hook(codec, kcontrol, ucontrol); 3589a35bd1e3STakashi Iwai 3590a35bd1e3STakashi Iwai return ret; 3591a35bd1e3STakashi Iwai } 3592a35bd1e3STakashi Iwai 3593352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label, 3594352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl, 3595352f7f91STakashi Iwai bool inv_dmic) 3596352f7f91STakashi Iwai { 3597352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3598975cc02aSTakashi Iwai char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 3599352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; 3600352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume"; 3601352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3; 3602a35bd1e3STakashi Iwai struct snd_kcontrol_new *knew; 3603352f7f91STakashi Iwai 3604352f7f91STakashi Iwai if (!ctl) 3605352f7f91STakashi Iwai return 0; 3606352f7f91STakashi Iwai 3607352f7f91STakashi Iwai if (label) 3608352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 3609352f7f91STakashi Iwai "%s Capture %s", label, sfx); 3610352f7f91STakashi Iwai else 3611352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 3612352f7f91STakashi Iwai "Capture %s", sfx); 3613a35bd1e3STakashi Iwai knew = add_control(spec, type, tmpname, idx, 3614352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs)); 3615a35bd1e3STakashi Iwai if (!knew) 3616a35bd1e3STakashi Iwai return -ENOMEM; 3617a90229e0STakashi Iwai if (is_switch) 3618a35bd1e3STakashi Iwai knew->put = cap_single_sw_put; 3619a35bd1e3STakashi Iwai if (!inv_dmic) 3620a35bd1e3STakashi Iwai return 0; 3621352f7f91STakashi Iwai 3622352f7f91STakashi Iwai /* Make independent right kcontrol */ 3623352f7f91STakashi Iwai if (label) 3624352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 3625352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx); 3626352f7f91STakashi Iwai else 3627352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 3628352f7f91STakashi Iwai "Inverted Capture %s", sfx); 3629a35bd1e3STakashi Iwai knew = add_control(spec, type, tmpname, idx, 3630352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2)); 3631a35bd1e3STakashi Iwai if (!knew) 3632a35bd1e3STakashi Iwai return -ENOMEM; 3633a90229e0STakashi Iwai if (is_switch) 3634a35bd1e3STakashi Iwai knew->put = cap_single_sw_put; 3635a35bd1e3STakashi Iwai return 0; 3636352f7f91STakashi Iwai } 3637352f7f91STakashi Iwai 3638352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */ 3639352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, 3640352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl, 3641352f7f91STakashi Iwai bool inv_dmic) 3642352f7f91STakashi Iwai { 3643352f7f91STakashi Iwai int err; 3644352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); 3645352f7f91STakashi Iwai if (err < 0) 3646352f7f91STakashi Iwai return err; 3647352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); 3648071c73adSTakashi Iwai if (err < 0) 3649071c73adSTakashi Iwai return err; 3650071c73adSTakashi Iwai return 0; 36511da177e4SLinus Torvalds } 3652071c73adSTakashi Iwai 3653352f7f91STakashi Iwai /* create bound capture volume and switch controls */ 3654352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, 3655352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl) 3656352f7f91STakashi Iwai { 3657352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3658352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 3659352f7f91STakashi Iwai 3660352f7f91STakashi Iwai if (vol_ctl) { 366112c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); 3662352f7f91STakashi Iwai if (!knew) 3663352f7f91STakashi Iwai return -ENOMEM; 3664352f7f91STakashi Iwai knew->index = idx; 3665352f7f91STakashi Iwai knew->private_value = vol_ctl; 3666352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 3667352f7f91STakashi Iwai } 3668352f7f91STakashi Iwai if (sw_ctl) { 366912c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); 3670352f7f91STakashi Iwai if (!knew) 3671352f7f91STakashi Iwai return -ENOMEM; 3672352f7f91STakashi Iwai knew->index = idx; 3673352f7f91STakashi Iwai knew->private_value = sw_ctl; 3674352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 3675352f7f91STakashi Iwai } 3676352f7f91STakashi Iwai return 0; 3677352f7f91STakashi Iwai } 3678352f7f91STakashi Iwai 3679352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */ 3680352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) 3681352f7f91STakashi Iwai { 3682352f7f91STakashi Iwai struct nid_path *path; 3683352f7f91STakashi Iwai unsigned int ctl; 3684352f7f91STakashi Iwai int i; 3685352f7f91STakashi Iwai 3686c697b716STakashi Iwai path = get_input_path(codec, 0, idx); 3687352f7f91STakashi Iwai if (!path) 3688352f7f91STakashi Iwai return 0; 3689352f7f91STakashi Iwai ctl = path->ctls[type]; 3690352f7f91STakashi Iwai if (!ctl) 3691352f7f91STakashi Iwai return 0; 3692352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) { 3693c697b716STakashi Iwai path = get_input_path(codec, 0, i); 3694352f7f91STakashi Iwai if (path && path->ctls[type] == ctl) 3695352f7f91STakashi Iwai return 0; 3696352f7f91STakashi Iwai } 3697352f7f91STakashi Iwai return ctl; 3698352f7f91STakashi Iwai } 3699352f7f91STakashi Iwai 3700352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */ 3701352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec) 3702352f7f91STakashi Iwai { 3703352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3704352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3705c970042cSTakashi Iwai int i, err, type; 3706352f7f91STakashi Iwai 3707352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3708352f7f91STakashi Iwai bool inv_dmic; 3709c970042cSTakashi Iwai int idx; 37109dba205bSTakashi Iwai 3711c970042cSTakashi Iwai idx = imux->items[i].index; 3712c970042cSTakashi Iwai if (idx >= spec->autocfg.num_inputs) 37139dba205bSTakashi Iwai continue; 3714352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); 3715352f7f91STakashi Iwai 3716352f7f91STakashi Iwai for (type = 0; type < 2; type++) { 3717c970042cSTakashi Iwai err = add_single_cap_ctl(codec, 3718c970042cSTakashi Iwai spec->input_labels[idx], 3719c970042cSTakashi Iwai spec->input_label_idxs[idx], 3720c970042cSTakashi Iwai type, 3721352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type), 3722352f7f91STakashi Iwai inv_dmic); 3723d13bd412STakashi Iwai if (err < 0) 3724071c73adSTakashi Iwai return err; 3725352f7f91STakashi Iwai } 3726352f7f91STakashi Iwai } 3727071c73adSTakashi Iwai return 0; 3728352f7f91STakashi Iwai } 3729071c73adSTakashi Iwai 3730352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec) 3731352f7f91STakashi Iwai { 3732352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3733352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3734352f7f91STakashi Iwai int i, n, nums, err; 3735352f7f91STakashi Iwai 3736352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3737352f7f91STakashi Iwai nums = 1; 3738352f7f91STakashi Iwai else 3739352f7f91STakashi Iwai nums = spec->num_adc_nids; 3740352f7f91STakashi Iwai 3741352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) { 3742352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 3743624d914dSTakashi Iwai const char *name; 3744624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source"; 3745624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); 3746352f7f91STakashi Iwai if (!knew) 3747352f7f91STakashi Iwai return -ENOMEM; 3748352f7f91STakashi Iwai knew->count = nums; 3749352f7f91STakashi Iwai } 3750352f7f91STakashi Iwai 3751352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 3752352f7f91STakashi Iwai bool multi = false; 375399a5592dSDavid Henningsson bool multi_cap_vol = spec->multi_cap_vol; 3754352f7f91STakashi Iwai bool inv_dmic = false; 3755352f7f91STakashi Iwai int vol, sw; 3756352f7f91STakashi Iwai 3757352f7f91STakashi Iwai vol = sw = 0; 3758352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3759352f7f91STakashi Iwai struct nid_path *path; 3760c697b716STakashi Iwai path = get_input_path(codec, n, i); 3761352f7f91STakashi Iwai if (!path) 3762352f7f91STakashi Iwai continue; 3763352f7f91STakashi Iwai parse_capvol_in_path(codec, path); 3764352f7f91STakashi Iwai if (!vol) 3765352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL]; 376699a5592dSDavid Henningsson else if (vol != path->ctls[NID_PATH_VOL_CTL]) { 3767352f7f91STakashi Iwai multi = true; 376899a5592dSDavid Henningsson if (!same_amp_caps(codec, vol, 376999a5592dSDavid Henningsson path->ctls[NID_PATH_VOL_CTL], HDA_INPUT)) 377099a5592dSDavid Henningsson multi_cap_vol = true; 377199a5592dSDavid Henningsson } 3772352f7f91STakashi Iwai if (!sw) 3773352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL]; 377499a5592dSDavid Henningsson else if (sw != path->ctls[NID_PATH_MUTE_CTL]) { 3775352f7f91STakashi Iwai multi = true; 377699a5592dSDavid Henningsson if (!same_amp_caps(codec, sw, 377799a5592dSDavid Henningsson path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT)) 377899a5592dSDavid Henningsson multi_cap_vol = true; 377999a5592dSDavid Henningsson } 3780352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i])) 3781352f7f91STakashi Iwai inv_dmic = true; 3782352f7f91STakashi Iwai } 3783352f7f91STakashi Iwai 3784352f7f91STakashi Iwai if (!multi) 3785352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw, 3786352f7f91STakashi Iwai inv_dmic); 3787ccb04157SDavid Henningsson else if (!multi_cap_vol && !inv_dmic) 3788352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw); 3789352f7f91STakashi Iwai else 3790352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec); 3791d13bd412STakashi Iwai if (err < 0) 3792071c73adSTakashi Iwai return err; 3793071c73adSTakashi Iwai } 3794071c73adSTakashi Iwai 37951da177e4SLinus Torvalds return 0; 37961da177e4SLinus Torvalds } 37971da177e4SLinus Torvalds 3798352f7f91STakashi Iwai /* 3799352f7f91STakashi Iwai * add mic boosts if needed 3800352f7f91STakashi Iwai */ 38016f7c83afSTakashi Iwai 38026f7c83afSTakashi Iwai /* check whether the given amp is feasible as a boost volume */ 38036f7c83afSTakashi Iwai static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid, 38046f7c83afSTakashi Iwai int dir, int idx) 38056f7c83afSTakashi Iwai { 38066f7c83afSTakashi Iwai unsigned int step; 38076f7c83afSTakashi Iwai 38086f7c83afSTakashi Iwai if (!nid_has_volume(codec, nid, dir) || 38096f7c83afSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || 38106f7c83afSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) 38116f7c83afSTakashi Iwai return false; 38126f7c83afSTakashi Iwai 38136f7c83afSTakashi Iwai step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE) 38146f7c83afSTakashi Iwai >> AC_AMPCAP_STEP_SIZE_SHIFT; 38156f7c83afSTakashi Iwai if (step < 0x20) 38166f7c83afSTakashi Iwai return false; 38176f7c83afSTakashi Iwai return true; 38186f7c83afSTakashi Iwai } 38196f7c83afSTakashi Iwai 38206f7c83afSTakashi Iwai /* look for a boost amp in a widget close to the pin */ 38216f7c83afSTakashi Iwai static unsigned int look_for_boost_amp(struct hda_codec *codec, 38226f7c83afSTakashi Iwai struct nid_path *path) 38236f7c83afSTakashi Iwai { 38246f7c83afSTakashi Iwai unsigned int val = 0; 38256f7c83afSTakashi Iwai hda_nid_t nid; 38266f7c83afSTakashi Iwai int depth; 38276f7c83afSTakashi Iwai 38286f7c83afSTakashi Iwai for (depth = 0; depth < 3; depth++) { 38296f7c83afSTakashi Iwai if (depth >= path->depth - 1) 38306f7c83afSTakashi Iwai break; 38316f7c83afSTakashi Iwai nid = path->path[depth]; 38326f7c83afSTakashi Iwai if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) { 38336f7c83afSTakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 38346f7c83afSTakashi Iwai break; 38356f7c83afSTakashi Iwai } else if (check_boost_vol(codec, nid, HDA_INPUT, 38366f7c83afSTakashi Iwai path->idx[depth])) { 38376f7c83afSTakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth], 38386f7c83afSTakashi Iwai HDA_INPUT); 38396f7c83afSTakashi Iwai break; 38406f7c83afSTakashi Iwai } 38416f7c83afSTakashi Iwai } 38426f7c83afSTakashi Iwai 38436f7c83afSTakashi Iwai return val; 38446f7c83afSTakashi Iwai } 38456f7c83afSTakashi Iwai 3846352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec) 3847352f7f91STakashi Iwai { 3848352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3849352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 38506f7c83afSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3851a35bd1e3STakashi Iwai int i; 3852352f7f91STakashi Iwai 38536f7c83afSTakashi Iwai if (!spec->num_adc_nids) 38546f7c83afSTakashi Iwai return 0; 38556f7c83afSTakashi Iwai 38566f7c83afSTakashi Iwai for (i = 0; i < imux->num_items; i++) { 3857352f7f91STakashi Iwai struct nid_path *path; 3858352f7f91STakashi Iwai unsigned int val; 38596f7c83afSTakashi Iwai int idx; 3860975cc02aSTakashi Iwai char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 3861352f7f91STakashi Iwai 38626f7c83afSTakashi Iwai idx = imux->items[i].index; 38636f7c83afSTakashi Iwai if (idx >= imux->num_items) 386402aba550SDavid Henningsson continue; 386502aba550SDavid Henningsson 38666f7c83afSTakashi Iwai /* check only line-in and mic pins */ 38671799cdd5STakashi Iwai if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN) 38686f7c83afSTakashi Iwai continue; 38696f7c83afSTakashi Iwai 38706f7c83afSTakashi Iwai path = get_input_path(codec, 0, i); 38716f7c83afSTakashi Iwai if (!path) 38726f7c83afSTakashi Iwai continue; 38736f7c83afSTakashi Iwai 38746f7c83afSTakashi Iwai val = look_for_boost_amp(codec, path); 38756f7c83afSTakashi Iwai if (!val) 38766f7c83afSTakashi Iwai continue; 38776f7c83afSTakashi Iwai 38786f7c83afSTakashi Iwai /* create a boost control */ 3879352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label), 38806f7c83afSTakashi Iwai "%s Boost Volume", spec->input_labels[idx]); 3881a35bd1e3STakashi Iwai if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label, 3882a35bd1e3STakashi Iwai spec->input_label_idxs[idx], val)) 3883a35bd1e3STakashi Iwai return -ENOMEM; 3884352f7f91STakashi Iwai 3885352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val; 3886352f7f91STakashi Iwai } 3887352f7f91STakashi Iwai return 0; 3888352f7f91STakashi Iwai } 3889352f7f91STakashi Iwai 3890352f7f91STakashi Iwai /* 3891f567b788STakashi Iwai * mic mute LED hook helpers 3892f567b788STakashi Iwai */ 3893f567b788STakashi Iwai enum { 3894f567b788STakashi Iwai MICMUTE_LED_ON, 3895f567b788STakashi Iwai MICMUTE_LED_OFF, 3896f567b788STakashi Iwai MICMUTE_LED_FOLLOW_CAPTURE, 3897f567b788STakashi Iwai MICMUTE_LED_FOLLOW_MUTE, 3898f567b788STakashi Iwai }; 3899f567b788STakashi Iwai 3900f567b788STakashi Iwai static void call_micmute_led_update(struct hda_codec *codec) 3901f567b788STakashi Iwai { 3902f567b788STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3903f567b788STakashi Iwai unsigned int val; 3904f567b788STakashi Iwai 3905f567b788STakashi Iwai switch (spec->micmute_led.led_mode) { 3906f567b788STakashi Iwai case MICMUTE_LED_ON: 3907f567b788STakashi Iwai val = 1; 3908f567b788STakashi Iwai break; 3909f567b788STakashi Iwai case MICMUTE_LED_OFF: 3910f567b788STakashi Iwai val = 0; 3911f567b788STakashi Iwai break; 3912f567b788STakashi Iwai case MICMUTE_LED_FOLLOW_CAPTURE: 3913c647f806STakashi Iwai val = !!spec->micmute_led.capture; 3914f567b788STakashi Iwai break; 3915f567b788STakashi Iwai case MICMUTE_LED_FOLLOW_MUTE: 3916f567b788STakashi Iwai default: 3917f567b788STakashi Iwai val = !spec->micmute_led.capture; 3918f567b788STakashi Iwai break; 3919f567b788STakashi Iwai } 3920f567b788STakashi Iwai 3921f567b788STakashi Iwai if (val == spec->micmute_led.led_value) 3922f567b788STakashi Iwai return; 3923f567b788STakashi Iwai spec->micmute_led.led_value = val; 3924f567b788STakashi Iwai if (spec->micmute_led.update) 3925f567b788STakashi Iwai spec->micmute_led.update(codec); 3926f567b788STakashi Iwai } 3927f567b788STakashi Iwai 3928f567b788STakashi Iwai static void update_micmute_led(struct hda_codec *codec, 3929f567b788STakashi Iwai struct snd_kcontrol *kcontrol, 3930f567b788STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3931f567b788STakashi Iwai { 3932f567b788STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3933c647f806STakashi Iwai unsigned int mask; 3934f567b788STakashi Iwai 3935f567b788STakashi Iwai if (spec->micmute_led.old_hook) 3936f567b788STakashi Iwai spec->micmute_led.old_hook(codec, kcontrol, ucontrol); 3937f567b788STakashi Iwai 3938f567b788STakashi Iwai if (!ucontrol) 3939f567b788STakashi Iwai return; 3940c647f806STakashi Iwai mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3941c647f806STakashi Iwai if (!strcmp("Capture Switch", ucontrol->id.name)) { 3942f567b788STakashi Iwai /* TODO: How do I verify if it's a mono or stereo here? */ 3943c647f806STakashi Iwai if (ucontrol->value.integer.value[0] || 3944c647f806STakashi Iwai ucontrol->value.integer.value[1]) 3945c647f806STakashi Iwai spec->micmute_led.capture |= mask; 3946c647f806STakashi Iwai else 3947c647f806STakashi Iwai spec->micmute_led.capture &= ~mask; 3948f567b788STakashi Iwai call_micmute_led_update(codec); 3949f567b788STakashi Iwai } 3950f567b788STakashi Iwai } 3951f567b788STakashi Iwai 3952f567b788STakashi Iwai static int micmute_led_mode_info(struct snd_kcontrol *kcontrol, 3953f567b788STakashi Iwai struct snd_ctl_elem_info *uinfo) 3954f567b788STakashi Iwai { 3955f567b788STakashi Iwai static const char * const texts[] = { 3956f567b788STakashi Iwai "On", "Off", "Follow Capture", "Follow Mute", 3957f567b788STakashi Iwai }; 3958f567b788STakashi Iwai 3959f567b788STakashi Iwai return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 3960f567b788STakashi Iwai } 3961f567b788STakashi Iwai 3962f567b788STakashi Iwai static int micmute_led_mode_get(struct snd_kcontrol *kcontrol, 3963f567b788STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3964f567b788STakashi Iwai { 3965f567b788STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3966f567b788STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3967f567b788STakashi Iwai 3968f567b788STakashi Iwai ucontrol->value.enumerated.item[0] = spec->micmute_led.led_mode; 3969f567b788STakashi Iwai return 0; 3970f567b788STakashi Iwai } 3971f567b788STakashi Iwai 3972f567b788STakashi Iwai static int micmute_led_mode_put(struct snd_kcontrol *kcontrol, 3973f567b788STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3974f567b788STakashi Iwai { 3975f567b788STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3976f567b788STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3977f567b788STakashi Iwai unsigned int mode; 3978f567b788STakashi Iwai 3979f567b788STakashi Iwai mode = ucontrol->value.enumerated.item[0]; 3980f567b788STakashi Iwai if (mode > MICMUTE_LED_FOLLOW_MUTE) 3981f567b788STakashi Iwai mode = MICMUTE_LED_FOLLOW_MUTE; 3982f567b788STakashi Iwai if (mode == spec->micmute_led.led_mode) 3983f567b788STakashi Iwai return 0; 3984f567b788STakashi Iwai spec->micmute_led.led_mode = mode; 3985f567b788STakashi Iwai call_micmute_led_update(codec); 3986f567b788STakashi Iwai return 1; 3987f567b788STakashi Iwai } 3988f567b788STakashi Iwai 3989f567b788STakashi Iwai static const struct snd_kcontrol_new micmute_led_mode_ctl = { 3990f567b788STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3991f567b788STakashi Iwai .name = "Mic Mute-LED Mode", 3992f567b788STakashi Iwai .info = micmute_led_mode_info, 3993f567b788STakashi Iwai .get = micmute_led_mode_get, 3994f567b788STakashi Iwai .put = micmute_led_mode_put, 3995f567b788STakashi Iwai }; 3996f567b788STakashi Iwai 3997f567b788STakashi Iwai /** 3998f567b788STakashi Iwai * snd_hda_gen_add_micmute_led - helper for setting up mic mute LED hook 3999f567b788STakashi Iwai * @codec: the HDA codec 4000f567b788STakashi Iwai * @hook: the callback for updating LED 4001f567b788STakashi Iwai * 4002f567b788STakashi Iwai * Called from the codec drivers for offering the mic mute LED controls. 4003c647f806STakashi Iwai * When established, it sets up cap_sync_hook and triggers the callback at 4004c647f806STakashi Iwai * each time when the capture mixer switch changes. The callback is supposed 4005c647f806STakashi Iwai * to update the LED accordingly. 4006f567b788STakashi Iwai * 4007c647f806STakashi Iwai * Returns 0 if the hook is established or a negative error code. 4008f567b788STakashi Iwai */ 4009f567b788STakashi Iwai int snd_hda_gen_add_micmute_led(struct hda_codec *codec, 4010f567b788STakashi Iwai void (*hook)(struct hda_codec *)) 4011f567b788STakashi Iwai { 4012f567b788STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4013f567b788STakashi Iwai 4014f567b788STakashi Iwai spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE; 4015f567b788STakashi Iwai spec->micmute_led.capture = 0; 4016f567b788STakashi Iwai spec->micmute_led.led_value = 0; 4017f567b788STakashi Iwai spec->micmute_led.old_hook = spec->cap_sync_hook; 4018f567b788STakashi Iwai spec->micmute_led.update = hook; 4019f567b788STakashi Iwai spec->cap_sync_hook = update_micmute_led; 4020f567b788STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl)) 4021f567b788STakashi Iwai return -ENOMEM; 4022c647f806STakashi Iwai return 0; 4023f567b788STakashi Iwai } 4024f567b788STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led); 4025f567b788STakashi Iwai 4026b3802783STakashi Iwai #if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO) 4027b3802783STakashi Iwai static void call_ledtrig_micmute(struct hda_codec *codec) 4028b3802783STakashi Iwai { 4029b3802783STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4030b3802783STakashi Iwai 4031b3802783STakashi Iwai ledtrig_audio_set(LED_AUDIO_MICMUTE, 4032b3802783STakashi Iwai spec->micmute_led.led_value ? LED_ON : LED_OFF); 4033b3802783STakashi Iwai } 4034b3802783STakashi Iwai #endif 4035b3802783STakashi Iwai 4036b3802783STakashi Iwai /** 4037b3802783STakashi Iwai * snd_hda_gen_fixup_micmute_led - A fixup for mic-mute LED trigger 4038b3802783STakashi Iwai * 4039b3802783STakashi Iwai * Pass this function to the quirk entry if another driver supports the 4040b3802783STakashi Iwai * audio mic-mute LED trigger. Then this will bind the mixer capture switch 4041b3802783STakashi Iwai * change with the LED. 4042b3802783STakashi Iwai * 4043b3802783STakashi Iwai * Note that this fixup has to be called after other fixup that sets 4044b3802783STakashi Iwai * cap_sync_hook. Otherwise the chaining wouldn't work. 4045b3802783STakashi Iwai */ 4046b3802783STakashi Iwai void snd_hda_gen_fixup_micmute_led(struct hda_codec *codec, 4047b3802783STakashi Iwai const struct hda_fixup *fix, int action) 4048b3802783STakashi Iwai { 4049b3802783STakashi Iwai #if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO) 4050b3802783STakashi Iwai if (action == HDA_FIXUP_ACT_PROBE) 4051b3802783STakashi Iwai snd_hda_gen_add_micmute_led(codec, call_ledtrig_micmute); 4052b3802783STakashi Iwai #endif 4053b3802783STakashi Iwai } 4054b3802783STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_fixup_micmute_led); 4055b3802783STakashi Iwai 4056f567b788STakashi Iwai /* 4057352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 4058352f7f91STakashi Iwai */ 4059352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 4060352f7f91STakashi Iwai { 4061352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 40620c8c0f56STakashi Iwai struct nid_path *path; 4063352f7f91STakashi Iwai int i, nums; 40642c12c30dSTakashi Iwai hda_nid_t dig_nid, pin; 4065352f7f91STakashi Iwai 4066352f7f91STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a slave */ 4067352f7f91STakashi Iwai nums = 0; 4068352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 40692c12c30dSTakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 4070352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 4071352f7f91STakashi Iwai if (!dig_nid) 4072352f7f91STakashi Iwai continue; 40733ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, 0); 40740c8c0f56STakashi Iwai if (!path) 4075352f7f91STakashi Iwai continue; 40764e76a883STakashi Iwai print_nid_path(codec, "digout", path); 4077e1284af7STakashi Iwai path->active = true; 40786b275b14STakashi Iwai path->pin_fixed = true; /* no jack detection */ 4079196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 40802c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_OUT, false); 4081352f7f91STakashi Iwai if (!nums) { 4082352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 4083352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 4084352f7f91STakashi Iwai } else { 4085352f7f91STakashi Iwai spec->multiout.slave_dig_outs = spec->slave_dig_outs; 4086352f7f91STakashi Iwai if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) 4087352f7f91STakashi Iwai break; 4088352f7f91STakashi Iwai spec->slave_dig_outs[nums - 1] = dig_nid; 4089352f7f91STakashi Iwai } 4090352f7f91STakashi Iwai nums++; 4091352f7f91STakashi Iwai } 4092352f7f91STakashi Iwai 4093352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 40942c12c30dSTakashi Iwai pin = spec->autocfg.dig_in_pin; 40957639a06cSTakashi Iwai for_each_hda_codec_node(dig_nid, codec) { 4096352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 4097352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 4098352f7f91STakashi Iwai continue; 4099352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 4100352f7f91STakashi Iwai continue; 41012c12c30dSTakashi Iwai path = snd_hda_add_new_path(codec, pin, dig_nid, 0); 4102352f7f91STakashi Iwai if (path) { 41034e76a883STakashi Iwai print_nid_path(codec, "digin", path); 4104352f7f91STakashi Iwai path->active = true; 41056b275b14STakashi Iwai path->pin_fixed = true; /* no jack */ 4106352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 41072430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 41082c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_IN, false); 4109352f7f91STakashi Iwai break; 4110352f7f91STakashi Iwai } 4111352f7f91STakashi Iwai } 4112352f7f91STakashi Iwai } 4113352f7f91STakashi Iwai } 4114352f7f91STakashi Iwai 41151da177e4SLinus Torvalds 41161da177e4SLinus Torvalds /* 4117352f7f91STakashi Iwai * input MUX handling 41181da177e4SLinus Torvalds */ 41191da177e4SLinus Torvalds 4120352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 4121352f7f91STakashi Iwai 4122352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 4123352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 4124352f7f91STakashi Iwai unsigned int idx) 4125352f7f91STakashi Iwai { 4126352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4127352f7f91STakashi Iwai const struct hda_input_mux *imux; 412855196fffSTakashi Iwai struct nid_path *old_path, *path; 4129352f7f91STakashi Iwai 4130352f7f91STakashi Iwai imux = &spec->input_mux; 4131352f7f91STakashi Iwai if (!imux->num_items) 41321da177e4SLinus Torvalds return 0; 41331da177e4SLinus Torvalds 4134352f7f91STakashi Iwai if (idx >= imux->num_items) 4135352f7f91STakashi Iwai idx = imux->num_items - 1; 4136352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 4137352f7f91STakashi Iwai return 0; 4138352f7f91STakashi Iwai 413955196fffSTakashi Iwai old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); 414055196fffSTakashi Iwai if (!old_path) 4141352f7f91STakashi Iwai return 0; 414255196fffSTakashi Iwai if (old_path->active) 414355196fffSTakashi Iwai snd_hda_activate_path(codec, old_path, false, false); 4144352f7f91STakashi Iwai 4145352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 4146352f7f91STakashi Iwai 4147967303daSTakashi Iwai if (spec->hp_mic) 4148967303daSTakashi Iwai update_hp_mic(codec, adc_idx, false); 4149352f7f91STakashi Iwai 4150352f7f91STakashi Iwai if (spec->dyn_adc_switch) 4151352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 4152352f7f91STakashi Iwai 4153c697b716STakashi Iwai path = get_input_path(codec, adc_idx, idx); 4154352f7f91STakashi Iwai if (!path) 4155352f7f91STakashi Iwai return 0; 4156352f7f91STakashi Iwai if (path->active) 4157352f7f91STakashi Iwai return 0; 4158352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 4159352f7f91STakashi Iwai if (spec->cap_sync_hook) 41607fe30711STakashi Iwai spec->cap_sync_hook(codec, NULL, NULL); 416155196fffSTakashi Iwai path_power_down_sync(codec, old_path); 41621da177e4SLinus Torvalds return 1; 41631da177e4SLinus Torvalds } 41641da177e4SLinus Torvalds 4165e6feb5d0STakashi Iwai /* power up/down widgets in the all paths that match with the given NID 4166e6feb5d0STakashi Iwai * as terminals (either start- or endpoint) 4167e6feb5d0STakashi Iwai * 4168e6feb5d0STakashi Iwai * returns the last changed NID, or zero if unchanged. 4169e6feb5d0STakashi Iwai */ 4170e6feb5d0STakashi Iwai static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid, 4171e6feb5d0STakashi Iwai int pin_state, int stream_state) 4172e6feb5d0STakashi Iwai { 4173e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4174e6feb5d0STakashi Iwai hda_nid_t last, changed = 0; 4175e6feb5d0STakashi Iwai struct nid_path *path; 4176e6feb5d0STakashi Iwai int n; 4177e6feb5d0STakashi Iwai 4178a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, n, path) { 417981e43960SBob Copeland if (!path->depth) 418081e43960SBob Copeland continue; 4181e6feb5d0STakashi Iwai if (path->path[0] == nid || 4182e6feb5d0STakashi Iwai path->path[path->depth - 1] == nid) { 4183e6feb5d0STakashi Iwai bool pin_old = path->pin_enabled; 4184e6feb5d0STakashi Iwai bool stream_old = path->stream_enabled; 4185e6feb5d0STakashi Iwai 4186e6feb5d0STakashi Iwai if (pin_state >= 0) 4187e6feb5d0STakashi Iwai path->pin_enabled = pin_state; 4188e6feb5d0STakashi Iwai if (stream_state >= 0) 4189e6feb5d0STakashi Iwai path->stream_enabled = stream_state; 41906b275b14STakashi Iwai if ((!path->pin_fixed && path->pin_enabled != pin_old) 41916b275b14STakashi Iwai || path->stream_enabled != stream_old) { 4192e6feb5d0STakashi Iwai last = path_power_update(codec, path, true); 4193e6feb5d0STakashi Iwai if (last) 4194e6feb5d0STakashi Iwai changed = last; 4195e6feb5d0STakashi Iwai } 4196e6feb5d0STakashi Iwai } 4197e6feb5d0STakashi Iwai } 4198e6feb5d0STakashi Iwai return changed; 4199e6feb5d0STakashi Iwai } 4200e6feb5d0STakashi Iwai 4201d5ac0100STakashi Iwai /* check the jack status for power control */ 4202d5ac0100STakashi Iwai static bool detect_pin_state(struct hda_codec *codec, hda_nid_t pin) 4203d5ac0100STakashi Iwai { 4204d5ac0100STakashi Iwai if (!is_jack_detectable(codec, pin)) 4205d5ac0100STakashi Iwai return true; 4206d5ac0100STakashi Iwai return snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT; 4207d5ac0100STakashi Iwai } 4208d5ac0100STakashi Iwai 4209e6feb5d0STakashi Iwai /* power up/down the paths of the given pin according to the jack state; 4210e6feb5d0STakashi Iwai * power = 0/1 : only power up/down if it matches with the jack state, 4211e6feb5d0STakashi Iwai * < 0 : force power up/down to follow the jack sate 4212e6feb5d0STakashi Iwai * 4213e6feb5d0STakashi Iwai * returns the last changed NID, or zero if unchanged. 4214e6feb5d0STakashi Iwai */ 4215e6feb5d0STakashi Iwai static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin, 4216e6feb5d0STakashi Iwai int power) 4217e6feb5d0STakashi Iwai { 4218e6feb5d0STakashi Iwai bool on; 4219e6feb5d0STakashi Iwai 4220967b1307STakashi Iwai if (!codec->power_save_node) 4221e6feb5d0STakashi Iwai return 0; 4222e6feb5d0STakashi Iwai 4223d5ac0100STakashi Iwai on = detect_pin_state(codec, pin); 4224d5ac0100STakashi Iwai 4225e6feb5d0STakashi Iwai if (power >= 0 && on != power) 4226e6feb5d0STakashi Iwai return 0; 4227e6feb5d0STakashi Iwai return set_path_power(codec, pin, on, -1); 4228e6feb5d0STakashi Iwai } 4229e6feb5d0STakashi Iwai 4230e6feb5d0STakashi Iwai static void pin_power_callback(struct hda_codec *codec, 4231e6feb5d0STakashi Iwai struct hda_jack_callback *jack, 4232e6feb5d0STakashi Iwai bool on) 4233e6feb5d0STakashi Iwai { 42342ebab40eSTakashi Iwai if (jack && jack->nid) 4235e6feb5d0STakashi Iwai sync_power_state_change(codec, 42362ebab40eSTakashi Iwai set_pin_power_jack(codec, jack->nid, on)); 4237e6feb5d0STakashi Iwai } 4238e6feb5d0STakashi Iwai 4239e6feb5d0STakashi Iwai /* callback only doing power up -- called at first */ 4240e6feb5d0STakashi Iwai static void pin_power_up_callback(struct hda_codec *codec, 4241e6feb5d0STakashi Iwai struct hda_jack_callback *jack) 4242e6feb5d0STakashi Iwai { 4243e6feb5d0STakashi Iwai pin_power_callback(codec, jack, true); 4244e6feb5d0STakashi Iwai } 4245e6feb5d0STakashi Iwai 4246e6feb5d0STakashi Iwai /* callback only doing power down -- called at last */ 4247e6feb5d0STakashi Iwai static void pin_power_down_callback(struct hda_codec *codec, 4248e6feb5d0STakashi Iwai struct hda_jack_callback *jack) 4249e6feb5d0STakashi Iwai { 4250e6feb5d0STakashi Iwai pin_power_callback(codec, jack, false); 4251e6feb5d0STakashi Iwai } 4252e6feb5d0STakashi Iwai 4253e6feb5d0STakashi Iwai /* set up the power up/down callbacks */ 4254e6feb5d0STakashi Iwai static void add_pin_power_ctls(struct hda_codec *codec, int num_pins, 4255e6feb5d0STakashi Iwai const hda_nid_t *pins, bool on) 4256e6feb5d0STakashi Iwai { 4257e6feb5d0STakashi Iwai int i; 4258e6feb5d0STakashi Iwai hda_jack_callback_fn cb = 4259e6feb5d0STakashi Iwai on ? pin_power_up_callback : pin_power_down_callback; 4260e6feb5d0STakashi Iwai 4261e6feb5d0STakashi Iwai for (i = 0; i < num_pins && pins[i]; i++) { 4262e6feb5d0STakashi Iwai if (is_jack_detectable(codec, pins[i])) 4263e6feb5d0STakashi Iwai snd_hda_jack_detect_enable_callback(codec, pins[i], cb); 4264e6feb5d0STakashi Iwai else 4265e6feb5d0STakashi Iwai set_path_power(codec, pins[i], true, -1); 4266e6feb5d0STakashi Iwai } 4267e6feb5d0STakashi Iwai } 4268e6feb5d0STakashi Iwai 4269e6feb5d0STakashi Iwai /* enabled power callback to each available I/O pin with jack detections; 4270e6feb5d0STakashi Iwai * the digital I/O pins are excluded because of the unreliable detectsion 4271e6feb5d0STakashi Iwai */ 4272e6feb5d0STakashi Iwai static void add_all_pin_power_ctls(struct hda_codec *codec, bool on) 4273e6feb5d0STakashi Iwai { 4274e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4275e6feb5d0STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4276e6feb5d0STakashi Iwai int i; 4277e6feb5d0STakashi Iwai 4278967b1307STakashi Iwai if (!codec->power_save_node) 4279e6feb5d0STakashi Iwai return; 4280e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on); 4281e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 4282e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on); 4283e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 4284e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on); 4285e6feb5d0STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) 4286e6feb5d0STakashi Iwai add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on); 4287e6feb5d0STakashi Iwai } 4288e6feb5d0STakashi Iwai 4289e6feb5d0STakashi Iwai /* sync path power up/down with the jack states of given pins */ 4290e6feb5d0STakashi Iwai static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins, 4291e6feb5d0STakashi Iwai const hda_nid_t *pins) 4292e6feb5d0STakashi Iwai { 4293e6feb5d0STakashi Iwai int i; 4294e6feb5d0STakashi Iwai 4295e6feb5d0STakashi Iwai for (i = 0; i < num_pins && pins[i]; i++) 4296e6feb5d0STakashi Iwai if (is_jack_detectable(codec, pins[i])) 4297e6feb5d0STakashi Iwai set_pin_power_jack(codec, pins[i], -1); 4298e6feb5d0STakashi Iwai } 4299e6feb5d0STakashi Iwai 4300e6feb5d0STakashi Iwai /* sync path power up/down with pins; called at init and resume */ 4301e6feb5d0STakashi Iwai static void sync_all_pin_power_ctls(struct hda_codec *codec) 4302e6feb5d0STakashi Iwai { 4303e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4304e6feb5d0STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4305e6feb5d0STakashi Iwai int i; 4306e6feb5d0STakashi Iwai 4307967b1307STakashi Iwai if (!codec->power_save_node) 4308e6feb5d0STakashi Iwai return; 4309e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins); 4310e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 4311e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins); 4312e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 4313e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins); 4314e6feb5d0STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) 4315e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin); 4316e6feb5d0STakashi Iwai } 43171da177e4SLinus Torvalds 43185ccf835cSTakashi Iwai /* add fake paths if not present yet */ 43195ccf835cSTakashi Iwai static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid, 43205ccf835cSTakashi Iwai int num_pins, const hda_nid_t *pins) 43215ccf835cSTakashi Iwai { 43225ccf835cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 43235ccf835cSTakashi Iwai struct nid_path *path; 43245ccf835cSTakashi Iwai int i; 43255ccf835cSTakashi Iwai 43265ccf835cSTakashi Iwai for (i = 0; i < num_pins; i++) { 43275ccf835cSTakashi Iwai if (!pins[i]) 43285ccf835cSTakashi Iwai break; 43295ccf835cSTakashi Iwai if (get_nid_path(codec, nid, pins[i], 0)) 43305ccf835cSTakashi Iwai continue; 43315ccf835cSTakashi Iwai path = snd_array_new(&spec->paths); 43325ccf835cSTakashi Iwai if (!path) 43335ccf835cSTakashi Iwai return -ENOMEM; 43345ccf835cSTakashi Iwai memset(path, 0, sizeof(*path)); 43355ccf835cSTakashi Iwai path->depth = 2; 43365ccf835cSTakashi Iwai path->path[0] = nid; 43375ccf835cSTakashi Iwai path->path[1] = pins[i]; 43385ccf835cSTakashi Iwai path->active = true; 43395ccf835cSTakashi Iwai } 43405ccf835cSTakashi Iwai return 0; 43415ccf835cSTakashi Iwai } 43425ccf835cSTakashi Iwai 43435ccf835cSTakashi Iwai /* create fake paths to all outputs from beep */ 43445ccf835cSTakashi Iwai static int add_fake_beep_paths(struct hda_codec *codec) 43455ccf835cSTakashi Iwai { 43465ccf835cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 43475ccf835cSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 43485ccf835cSTakashi Iwai hda_nid_t nid = spec->beep_nid; 43495ccf835cSTakashi Iwai int err; 43505ccf835cSTakashi Iwai 4351967b1307STakashi Iwai if (!codec->power_save_node || !nid) 43525ccf835cSTakashi Iwai return 0; 43535ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins); 43545ccf835cSTakashi Iwai if (err < 0) 43555ccf835cSTakashi Iwai return err; 43565ccf835cSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 43575ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins); 43585ccf835cSTakashi Iwai if (err < 0) 43595ccf835cSTakashi Iwai return err; 43605ccf835cSTakashi Iwai } 43615ccf835cSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 43625ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->speaker_outs, 43635ccf835cSTakashi Iwai cfg->speaker_pins); 43645ccf835cSTakashi Iwai if (err < 0) 43655ccf835cSTakashi Iwai return err; 43665ccf835cSTakashi Iwai } 43675ccf835cSTakashi Iwai return 0; 43685ccf835cSTakashi Iwai } 43695ccf835cSTakashi Iwai 43705ccf835cSTakashi Iwai /* power up/down beep widget and its output paths */ 43715ccf835cSTakashi Iwai static void beep_power_hook(struct hda_beep *beep, bool on) 43725ccf835cSTakashi Iwai { 43735ccf835cSTakashi Iwai set_path_power(beep->codec, beep->nid, -1, on); 43745ccf835cSTakashi Iwai } 43755ccf835cSTakashi Iwai 43766b275b14STakashi Iwai /** 43776b275b14STakashi Iwai * snd_hda_gen_fix_pin_power - Fix the power of the given pin widget to D0 43786b275b14STakashi Iwai * @codec: the HDA codec 43796b275b14STakashi Iwai * @pin: NID of pin to fix 43806b275b14STakashi Iwai */ 43816b275b14STakashi Iwai int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin) 43826b275b14STakashi Iwai { 43836b275b14STakashi Iwai struct hda_gen_spec *spec = codec->spec; 43846b275b14STakashi Iwai struct nid_path *path; 43856b275b14STakashi Iwai 43866b275b14STakashi Iwai path = snd_array_new(&spec->paths); 43876b275b14STakashi Iwai if (!path) 43886b275b14STakashi Iwai return -ENOMEM; 43896b275b14STakashi Iwai memset(path, 0, sizeof(*path)); 43906b275b14STakashi Iwai path->depth = 1; 43916b275b14STakashi Iwai path->path[0] = pin; 43926b275b14STakashi Iwai path->active = true; 43936b275b14STakashi Iwai path->pin_fixed = true; 43946b275b14STakashi Iwai path->stream_enabled = true; 43956b275b14STakashi Iwai return 0; 43966b275b14STakashi Iwai } 43976b275b14STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_fix_pin_power); 43986b275b14STakashi Iwai 43991da177e4SLinus Torvalds /* 4400352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 44011da177e4SLinus Torvalds */ 4402352f7f91STakashi Iwai 4403352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 4404caf3c043SMichał Mirosław static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins) 44051da177e4SLinus Torvalds { 440660ea8ca2STakashi Iwai int i; 440760ea8ca2STakashi Iwai bool present = false; 44081da177e4SLinus Torvalds 4409352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 4410352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 4411352f7f91STakashi Iwai if (!nid) 4412352f7f91STakashi Iwai break; 44130b4df931STakashi Iwai /* don't detect pins retasked as inputs */ 44140b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) 44150b4df931STakashi Iwai continue; 441660ea8ca2STakashi Iwai if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT) 441760ea8ca2STakashi Iwai present = true; 44181da177e4SLinus Torvalds } 4419352f7f91STakashi Iwai return present; 44201da177e4SLinus Torvalds } 44211da177e4SLinus Torvalds 4422352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 4423caf3c043SMichał Mirosław static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins, 4424e80c60f3STakashi Iwai int *paths, bool mute) 44251da177e4SLinus Torvalds { 4426352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4427352f7f91STakashi Iwai int i; 44281da177e4SLinus Torvalds 4429352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 4430352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 4431967303daSTakashi Iwai unsigned int val, oldval; 4432352f7f91STakashi Iwai if (!nid) 4433352f7f91STakashi Iwai break; 44347eebffd3STakashi Iwai 4435e6feb5d0STakashi Iwai oldval = snd_hda_codec_get_pin_target(codec, nid); 4436e6feb5d0STakashi Iwai if (oldval & PIN_IN) 4437e6feb5d0STakashi Iwai continue; /* no mute for inputs */ 4438e6feb5d0STakashi Iwai 44397eebffd3STakashi Iwai if (spec->auto_mute_via_amp) { 4440e80c60f3STakashi Iwai struct nid_path *path; 4441e80c60f3STakashi Iwai hda_nid_t mute_nid; 4442e80c60f3STakashi Iwai 4443e80c60f3STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]); 4444e80c60f3STakashi Iwai if (!path) 4445e80c60f3STakashi Iwai continue; 4446e80c60f3STakashi Iwai mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]); 4447e80c60f3STakashi Iwai if (!mute_nid) 4448e80c60f3STakashi Iwai continue; 44497eebffd3STakashi Iwai if (mute) 4450e80c60f3STakashi Iwai spec->mute_bits |= (1ULL << mute_nid); 44517eebffd3STakashi Iwai else 4452e80c60f3STakashi Iwai spec->mute_bits &= ~(1ULL << mute_nid); 44537eebffd3STakashi Iwai continue; 4454e6feb5d0STakashi Iwai } else { 4455352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 4456352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 4457352f7f91STakashi Iwai */ 44582c12c30dSTakashi Iwai if (spec->keep_vref_in_automute) 4459967303daSTakashi Iwai val = oldval & ~PIN_HP; 44602c12c30dSTakashi Iwai else 4461352f7f91STakashi Iwai val = 0; 44622c12c30dSTakashi Iwai if (!mute) 4463967303daSTakashi Iwai val |= oldval; 4464e6feb5d0STakashi Iwai /* here we call update_pin_ctl() so that the pinctl is 4465e6feb5d0STakashi Iwai * changed without changing the pinctl target value; 4466e6feb5d0STakashi Iwai * the original target value will be still referred at 4467e6feb5d0STakashi Iwai * the init / resume again 44682c12c30dSTakashi Iwai */ 44692c12c30dSTakashi Iwai update_pin_ctl(codec, nid, val); 4470e6feb5d0STakashi Iwai } 4471e6feb5d0STakashi Iwai 4472d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 4473967b1307STakashi Iwai if (codec->power_save_node) { 4474e6feb5d0STakashi Iwai bool on = !mute; 4475e6feb5d0STakashi Iwai if (on) 4476d5ac0100STakashi Iwai on = detect_pin_state(codec, nid); 4477e6feb5d0STakashi Iwai set_path_power(codec, nid, on, -1); 4478e6feb5d0STakashi Iwai } 4479352f7f91STakashi Iwai } 4480352f7f91STakashi Iwai } 44811da177e4SLinus Torvalds 4482dda42bd0STakashi Iwai /** 4483dda42bd0STakashi Iwai * snd_hda_gen_update_outputs - Toggle outputs muting 4484dda42bd0STakashi Iwai * @codec: the HDA codec 4485dda42bd0STakashi Iwai * 4486dda42bd0STakashi Iwai * Update the mute status of all outputs based on the current jack states. 4487dda42bd0STakashi Iwai */ 44885d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 4489352f7f91STakashi Iwai { 4490352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4491e80c60f3STakashi Iwai int *paths; 4492352f7f91STakashi Iwai int on; 4493352f7f91STakashi Iwai 4494352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 4495352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 4496352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 4497352f7f91STakashi Iwai */ 4498e80c60f3STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 4499e80c60f3STakashi Iwai paths = spec->out_paths; 4500e80c60f3STakashi Iwai else 4501e80c60f3STakashi Iwai paths = spec->hp_paths; 4502352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 4503e80c60f3STakashi Iwai spec->autocfg.hp_pins, paths, spec->master_mute); 4504352f7f91STakashi Iwai 4505352f7f91STakashi Iwai if (!spec->automute_speaker) 4506352f7f91STakashi Iwai on = 0; 4507352f7f91STakashi Iwai else 4508352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 4509352f7f91STakashi Iwai on |= spec->master_mute; 451047b9ddb8STakashi Iwai spec->speaker_muted = on; 4511e80c60f3STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 4512e80c60f3STakashi Iwai paths = spec->out_paths; 4513e80c60f3STakashi Iwai else 4514e80c60f3STakashi Iwai paths = spec->speaker_paths; 4515352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 4516e80c60f3STakashi Iwai spec->autocfg.speaker_pins, paths, on); 4517352f7f91STakashi Iwai 4518352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 4519352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 4520352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 4521352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 4522352f7f91STakashi Iwai return; 4523352f7f91STakashi Iwai if (!spec->automute_lo) 4524352f7f91STakashi Iwai on = 0; 4525352f7f91STakashi Iwai else 4526352f7f91STakashi Iwai on = spec->hp_jack_present; 4527352f7f91STakashi Iwai on |= spec->master_mute; 452847b9ddb8STakashi Iwai spec->line_out_muted = on; 4529e80c60f3STakashi Iwai paths = spec->out_paths; 4530352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 4531e80c60f3STakashi Iwai spec->autocfg.line_out_pins, paths, on); 4532352f7f91STakashi Iwai } 45332698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs); 4534352f7f91STakashi Iwai 4535352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 4536352f7f91STakashi Iwai { 4537352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4538352f7f91STakashi Iwai if (spec->automute_hook) 4539352f7f91STakashi Iwai spec->automute_hook(codec); 4540352f7f91STakashi Iwai else 45415d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 45427eebffd3STakashi Iwai 45437eebffd3STakashi Iwai /* sync the whole vmaster slaves to reflect the new auto-mute status */ 45447eebffd3STakashi Iwai if (spec->auto_mute_via_amp && !codec->bus->shutdown) 45457eebffd3STakashi Iwai snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); 4546352f7f91STakashi Iwai } 4547352f7f91STakashi Iwai 4548dda42bd0STakashi Iwai /** 4549dda42bd0STakashi Iwai * snd_hda_gen_hp_automute - standard HP-automute helper 4550dda42bd0STakashi Iwai * @codec: the HDA codec 4551dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole 4552dda42bd0STakashi Iwai */ 45531a4f69d5STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, 45541a4f69d5STakashi Iwai struct hda_jack_callback *jack) 4555352f7f91STakashi Iwai { 4556352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 455792603c59STakashi Iwai hda_nid_t *pins = spec->autocfg.hp_pins; 455892603c59STakashi Iwai int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins); 4559352f7f91STakashi Iwai 456092603c59STakashi Iwai /* No detection for the first HP jack during indep-HP mode */ 456192603c59STakashi Iwai if (spec->indep_hp_enabled) { 456292603c59STakashi Iwai pins++; 456392603c59STakashi Iwai num_pins--; 456492603c59STakashi Iwai } 456592603c59STakashi Iwai 456692603c59STakashi Iwai spec->hp_jack_present = detect_jacks(codec, num_pins, pins); 4567352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 4568352f7f91STakashi Iwai return; 4569352f7f91STakashi Iwai call_update_outputs(codec); 4570352f7f91STakashi Iwai } 45712698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute); 4572352f7f91STakashi Iwai 4573dda42bd0STakashi Iwai /** 4574dda42bd0STakashi Iwai * snd_hda_gen_line_automute - standard line-out-automute helper 4575dda42bd0STakashi Iwai * @codec: the HDA codec 4576dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole 4577dda42bd0STakashi Iwai */ 45781a4f69d5STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, 45791a4f69d5STakashi Iwai struct hda_jack_callback *jack) 4580352f7f91STakashi Iwai { 4581352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4582352f7f91STakashi Iwai 4583352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 4584352f7f91STakashi Iwai return; 4585352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 4586352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 4587352f7f91STakashi Iwai return; 4588352f7f91STakashi Iwai 4589352f7f91STakashi Iwai spec->line_jack_present = 4590352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 4591352f7f91STakashi Iwai spec->autocfg.line_out_pins); 4592352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 4593352f7f91STakashi Iwai return; 4594352f7f91STakashi Iwai call_update_outputs(codec); 4595352f7f91STakashi Iwai } 45962698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute); 4597352f7f91STakashi Iwai 4598dda42bd0STakashi Iwai /** 4599dda42bd0STakashi Iwai * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper 4600dda42bd0STakashi Iwai * @codec: the HDA codec 4601dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole 4602dda42bd0STakashi Iwai */ 46031a4f69d5STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, 46041a4f69d5STakashi Iwai struct hda_jack_callback *jack) 4605352f7f91STakashi Iwai { 4606352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4607352f7f91STakashi Iwai int i; 4608352f7f91STakashi Iwai 4609352f7f91STakashi Iwai if (!spec->auto_mic) 4610352f7f91STakashi Iwai return; 4611352f7f91STakashi Iwai 4612352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 46130b4df931STakashi Iwai hda_nid_t pin = spec->am_entry[i].pin; 46140b4df931STakashi Iwai /* don't detect pins retasked as outputs */ 46150b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) 46160b4df931STakashi Iwai continue; 461760ea8ca2STakashi Iwai if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) { 4618352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 4619352f7f91STakashi Iwai return; 4620352f7f91STakashi Iwai } 4621352f7f91STakashi Iwai } 4622352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 46231da177e4SLinus Torvalds } 46242698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch); 46251da177e4SLinus Torvalds 462677afe0e9STakashi Iwai /* call appropriate hooks */ 46271a4f69d5STakashi Iwai static void call_hp_automute(struct hda_codec *codec, 46281a4f69d5STakashi Iwai struct hda_jack_callback *jack) 462977afe0e9STakashi Iwai { 463077afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 463177afe0e9STakashi Iwai if (spec->hp_automute_hook) 463277afe0e9STakashi Iwai spec->hp_automute_hook(codec, jack); 463377afe0e9STakashi Iwai else 463477afe0e9STakashi Iwai snd_hda_gen_hp_automute(codec, jack); 463577afe0e9STakashi Iwai } 463677afe0e9STakashi Iwai 463777afe0e9STakashi Iwai static void call_line_automute(struct hda_codec *codec, 46381a4f69d5STakashi Iwai struct hda_jack_callback *jack) 463977afe0e9STakashi Iwai { 464077afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 464177afe0e9STakashi Iwai if (spec->line_automute_hook) 464277afe0e9STakashi Iwai spec->line_automute_hook(codec, jack); 464377afe0e9STakashi Iwai else 464477afe0e9STakashi Iwai snd_hda_gen_line_automute(codec, jack); 464577afe0e9STakashi Iwai } 464677afe0e9STakashi Iwai 464777afe0e9STakashi Iwai static void call_mic_autoswitch(struct hda_codec *codec, 46481a4f69d5STakashi Iwai struct hda_jack_callback *jack) 464977afe0e9STakashi Iwai { 465077afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 465177afe0e9STakashi Iwai if (spec->mic_autoswitch_hook) 465277afe0e9STakashi Iwai spec->mic_autoswitch_hook(codec, jack); 465377afe0e9STakashi Iwai else 465477afe0e9STakashi Iwai snd_hda_gen_mic_autoswitch(codec, jack); 465577afe0e9STakashi Iwai } 465677afe0e9STakashi Iwai 4657963afde9STakashi Iwai /* update jack retasking */ 4658963afde9STakashi Iwai static void update_automute_all(struct hda_codec *codec) 4659963afde9STakashi Iwai { 4660963afde9STakashi Iwai call_hp_automute(codec, NULL); 4661963afde9STakashi Iwai call_line_automute(codec, NULL); 4662963afde9STakashi Iwai call_mic_autoswitch(codec, NULL); 4663963afde9STakashi Iwai } 4664963afde9STakashi Iwai 46651da177e4SLinus Torvalds /* 4666352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 46671da177e4SLinus Torvalds */ 4668352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 4669352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 4670352f7f91STakashi Iwai { 4671352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4672352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4673352f7f91STakashi Iwai static const char * const texts3[] = { 4674352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 46751da177e4SLinus Torvalds }; 46761da177e4SLinus Torvalds 4677352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 4678352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 4679352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 4680352f7f91STakashi Iwai } 4681352f7f91STakashi Iwai 4682352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 4683352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4684352f7f91STakashi Iwai { 4685352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4686352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4687352f7f91STakashi Iwai unsigned int val = 0; 4688352f7f91STakashi Iwai if (spec->automute_speaker) 4689352f7f91STakashi Iwai val++; 4690352f7f91STakashi Iwai if (spec->automute_lo) 4691352f7f91STakashi Iwai val++; 4692352f7f91STakashi Iwai 4693352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 4694352f7f91STakashi Iwai return 0; 4695352f7f91STakashi Iwai } 4696352f7f91STakashi Iwai 4697352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 4698352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4699352f7f91STakashi Iwai { 4700352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4701352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4702352f7f91STakashi Iwai 4703352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 4704352f7f91STakashi Iwai case 0: 4705352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 4706352f7f91STakashi Iwai return 0; 4707352f7f91STakashi Iwai spec->automute_speaker = 0; 4708352f7f91STakashi Iwai spec->automute_lo = 0; 4709352f7f91STakashi Iwai break; 4710352f7f91STakashi Iwai case 1: 4711352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 4712352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 4713352f7f91STakashi Iwai return 0; 4714352f7f91STakashi Iwai spec->automute_speaker = 1; 4715352f7f91STakashi Iwai spec->automute_lo = 0; 4716352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 4717352f7f91STakashi Iwai if (spec->automute_lo) 4718352f7f91STakashi Iwai return 0; 4719352f7f91STakashi Iwai spec->automute_lo = 1; 4720352f7f91STakashi Iwai } else 4721352f7f91STakashi Iwai return -EINVAL; 4722352f7f91STakashi Iwai break; 4723352f7f91STakashi Iwai case 2: 4724352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 4725352f7f91STakashi Iwai return -EINVAL; 4726352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 4727352f7f91STakashi Iwai return 0; 4728352f7f91STakashi Iwai spec->automute_speaker = 1; 4729352f7f91STakashi Iwai spec->automute_lo = 1; 4730352f7f91STakashi Iwai break; 4731352f7f91STakashi Iwai default: 4732352f7f91STakashi Iwai return -EINVAL; 4733352f7f91STakashi Iwai } 4734352f7f91STakashi Iwai call_update_outputs(codec); 4735352f7f91STakashi Iwai return 1; 4736352f7f91STakashi Iwai } 4737352f7f91STakashi Iwai 4738352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 4739352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4740352f7f91STakashi Iwai .name = "Auto-Mute Mode", 4741352f7f91STakashi Iwai .info = automute_mode_info, 4742352f7f91STakashi Iwai .get = automute_mode_get, 4743352f7f91STakashi Iwai .put = automute_mode_put, 4744352f7f91STakashi Iwai }; 4745352f7f91STakashi Iwai 4746352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 4747352f7f91STakashi Iwai { 4748352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4749352f7f91STakashi Iwai 475012c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 4751352f7f91STakashi Iwai return -ENOMEM; 4752352f7f91STakashi Iwai return 0; 4753352f7f91STakashi Iwai } 4754352f7f91STakashi Iwai 4755352f7f91STakashi Iwai /* 4756352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 4757352f7f91STakashi Iwai * Set up appropriately if really supported 4758352f7f91STakashi Iwai */ 4759352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 4760352f7f91STakashi Iwai { 4761352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4762352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4763352f7f91STakashi Iwai int present = 0; 4764352f7f91STakashi Iwai int i, err; 4765352f7f91STakashi Iwai 4766f72706beSTakashi Iwai if (spec->suppress_auto_mute) 4767f72706beSTakashi Iwai return 0; 4768f72706beSTakashi Iwai 4769352f7f91STakashi Iwai if (cfg->hp_pins[0]) 4770352f7f91STakashi Iwai present++; 4771352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 4772352f7f91STakashi Iwai present++; 4773352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 4774352f7f91STakashi Iwai present++; 4775352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 4776352f7f91STakashi Iwai return 0; 4777352f7f91STakashi Iwai 4778352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 4779352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 4780352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 4781352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 4782352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 4783352f7f91STakashi Iwai } 4784352f7f91STakashi Iwai 4785352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 4786352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 4787352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 4788352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 4789352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 4790352f7f91STakashi Iwai } 4791352f7f91STakashi Iwai 4792352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 4793352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 4794352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4795352f7f91STakashi Iwai continue; 47964e76a883STakashi Iwai codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid); 479762f949bfSTakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 479877afe0e9STakashi Iwai call_hp_automute); 4799352f7f91STakashi Iwai spec->detect_hp = 1; 4800352f7f91STakashi Iwai } 4801352f7f91STakashi Iwai 4802352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 4803352f7f91STakashi Iwai if (cfg->speaker_outs) 4804352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 4805352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 4806352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4807352f7f91STakashi Iwai continue; 48084e76a883STakashi Iwai codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid); 4809352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 481077afe0e9STakashi Iwai call_line_automute); 4811352f7f91STakashi Iwai spec->detect_lo = 1; 4812352f7f91STakashi Iwai } 4813352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 4814352f7f91STakashi Iwai } 4815352f7f91STakashi Iwai 4816352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 4817352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 4818352f7f91STakashi Iwai 4819352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 4820352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 4821352f7f91STakashi Iwai 4822352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 4823352f7f91STakashi Iwai /* create a control for automute mode */ 4824352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 4825352f7f91STakashi Iwai if (err < 0) 4826352f7f91STakashi Iwai return err; 4827352f7f91STakashi Iwai } 4828352f7f91STakashi Iwai return 0; 4829352f7f91STakashi Iwai } 4830352f7f91STakashi Iwai 4831352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 4832352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 4833352f7f91STakashi Iwai { 4834352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4835352f7f91STakashi Iwai const struct hda_input_mux *imux; 4836352f7f91STakashi Iwai int i; 4837352f7f91STakashi Iwai 4838352f7f91STakashi Iwai imux = &spec->input_mux; 4839352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 4840352f7f91STakashi Iwai spec->am_entry[i].idx = 4841352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 4842352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 4843352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 4844352f7f91STakashi Iwai return false; /* no corresponding imux */ 4845352f7f91STakashi Iwai } 4846352f7f91STakashi Iwai 4847352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 4848352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 4849352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 4850352f7f91STakashi Iwai spec->am_entry[i].pin, 485177afe0e9STakashi Iwai call_mic_autoswitch); 4852352f7f91STakashi Iwai return true; 4853352f7f91STakashi Iwai } 4854352f7f91STakashi Iwai 4855352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 4856352f7f91STakashi Iwai { 4857352f7f91STakashi Iwai const struct automic_entry *a = ap; 4858352f7f91STakashi Iwai const struct automic_entry *b = bp; 4859352f7f91STakashi Iwai return (int)(a->attr - b->attr); 4860352f7f91STakashi Iwai } 4861352f7f91STakashi Iwai 4862352f7f91STakashi Iwai /* 4863352f7f91STakashi Iwai * Check the availability of auto-mic switch; 4864352f7f91STakashi Iwai * Set up if really supported 4865352f7f91STakashi Iwai */ 4866352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 4867352f7f91STakashi Iwai { 4868352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4869352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4870352f7f91STakashi Iwai unsigned int types; 4871352f7f91STakashi Iwai int i, num_pins; 4872352f7f91STakashi Iwai 4873d12daf6fSTakashi Iwai if (spec->suppress_auto_mic) 4874d12daf6fSTakashi Iwai return 0; 4875d12daf6fSTakashi Iwai 4876352f7f91STakashi Iwai types = 0; 4877352f7f91STakashi Iwai num_pins = 0; 4878352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 4879352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 4880352f7f91STakashi Iwai unsigned int attr; 4881352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 4882352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 4883352f7f91STakashi Iwai if (types & (1 << attr)) 4884352f7f91STakashi Iwai return 0; /* already occupied */ 4885352f7f91STakashi Iwai switch (attr) { 4886352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 4887352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 4888352f7f91STakashi Iwai return 0; /* invalid type */ 4889352f7f91STakashi Iwai break; 4890352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 4891352f7f91STakashi Iwai return 0; /* invalid entry */ 4892352f7f91STakashi Iwai default: 4893352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 4894352f7f91STakashi Iwai return 0; /* invalid type */ 4895352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 4896352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 4897352f7f91STakashi Iwai return 0; /* only mic is allowed */ 4898352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4899352f7f91STakashi Iwai return 0; /* no unsol support */ 4900352f7f91STakashi Iwai break; 4901352f7f91STakashi Iwai } 4902352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 4903352f7f91STakashi Iwai return 0; 4904352f7f91STakashi Iwai types |= (1 << attr); 4905352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 4906352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 4907352f7f91STakashi Iwai num_pins++; 4908352f7f91STakashi Iwai } 4909352f7f91STakashi Iwai 4910352f7f91STakashi Iwai if (num_pins < 2) 4911352f7f91STakashi Iwai return 0; 4912352f7f91STakashi Iwai 4913352f7f91STakashi Iwai spec->am_num_entries = num_pins; 4914352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 4915352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 4916352f7f91STakashi Iwai */ 4917352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 4918352f7f91STakashi Iwai compare_attr, NULL); 4919352f7f91STakashi Iwai 4920352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 4921352f7f91STakashi Iwai return 0; 4922352f7f91STakashi Iwai 4923352f7f91STakashi Iwai spec->auto_mic = 1; 4924352f7f91STakashi Iwai spec->num_adc_nids = 1; 4925352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 49264e76a883STakashi Iwai codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 4927352f7f91STakashi Iwai spec->am_entry[0].pin, 4928352f7f91STakashi Iwai spec->am_entry[1].pin, 4929352f7f91STakashi Iwai spec->am_entry[2].pin); 4930352f7f91STakashi Iwai 4931352f7f91STakashi Iwai return 0; 4932352f7f91STakashi Iwai } 4933352f7f91STakashi Iwai 4934dda42bd0STakashi Iwai /** 4935dda42bd0STakashi Iwai * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets 4936dda42bd0STakashi Iwai * into power down 4937dda42bd0STakashi Iwai * @codec: the HDA codec 4938dda42bd0STakashi Iwai * @nid: NID to evalute 4939dda42bd0STakashi Iwai * @power_state: target power state 4940dda42bd0STakashi Iwai */ 4941dfc6e469STakashi Iwai unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, 494255196fffSTakashi Iwai hda_nid_t nid, 494355196fffSTakashi Iwai unsigned int power_state) 494455196fffSTakashi Iwai { 4945b6c09b3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 4946b6c09b3cSTakashi Iwai 4947b6c09b3cSTakashi Iwai if (!spec->power_down_unused && !codec->power_save_node) 4948b6c09b3cSTakashi Iwai return power_state; 49497639a06cSTakashi Iwai if (power_state != AC_PWRST_D0 || nid == codec->core.afg) 495055196fffSTakashi Iwai return power_state; 495155196fffSTakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER) 495255196fffSTakashi Iwai return power_state; 4953b1b9fbd0STakashi Iwai if (is_active_nid_for_any(codec, nid)) 495455196fffSTakashi Iwai return power_state; 495555196fffSTakashi Iwai return AC_PWRST_D3; 495655196fffSTakashi Iwai } 4957dfc6e469STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter); 495855196fffSTakashi Iwai 4959ebb93c05STakashi Iwai /* mute all aamix inputs initially; parse up to the first leaves */ 4960ebb93c05STakashi Iwai static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) 4961ebb93c05STakashi Iwai { 4962ebb93c05STakashi Iwai int i, nums; 4963ebb93c05STakashi Iwai const hda_nid_t *conn; 4964ebb93c05STakashi Iwai bool has_amp; 4965ebb93c05STakashi Iwai 4966ebb93c05STakashi Iwai nums = snd_hda_get_conn_list(codec, mix, &conn); 4967ebb93c05STakashi Iwai has_amp = nid_has_mute(codec, mix, HDA_INPUT); 4968ebb93c05STakashi Iwai for (i = 0; i < nums; i++) { 4969ebb93c05STakashi Iwai if (has_amp) 4970ef403edbSTakashi Iwai update_amp(codec, mix, HDA_INPUT, i, 4971ebb93c05STakashi Iwai 0xff, HDA_AMP_MUTE); 4972ebb93c05STakashi Iwai else if (nid_has_volume(codec, conn[i], HDA_OUTPUT)) 4973ef403edbSTakashi Iwai update_amp(codec, conn[i], HDA_OUTPUT, 0, 4974ebb93c05STakashi Iwai 0xff, HDA_AMP_MUTE); 4975ebb93c05STakashi Iwai } 4976ebb93c05STakashi Iwai } 4977352f7f91STakashi Iwai 4978dda42bd0STakashi Iwai /** 4979e6feb5d0STakashi Iwai * snd_hda_gen_stream_pm - Stream power management callback 4980e6feb5d0STakashi Iwai * @codec: the HDA codec 4981e6feb5d0STakashi Iwai * @nid: audio widget 4982e6feb5d0STakashi Iwai * @on: power on/off flag 4983e6feb5d0STakashi Iwai * 4984967b1307STakashi Iwai * Set this in patch_ops.stream_pm. Only valid with power_save_node flag. 4985e6feb5d0STakashi Iwai */ 4986e6feb5d0STakashi Iwai void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on) 4987e6feb5d0STakashi Iwai { 4988967b1307STakashi Iwai if (codec->power_save_node) 4989e6feb5d0STakashi Iwai set_path_power(codec, nid, -1, on); 4990e6feb5d0STakashi Iwai } 4991e6feb5d0STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm); 4992e6feb5d0STakashi Iwai 4993e6feb5d0STakashi Iwai /** 4994dda42bd0STakashi Iwai * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and 4995dda42bd0STakashi Iwai * set up the hda_gen_spec 4996dda42bd0STakashi Iwai * @codec: the HDA codec 4997dda42bd0STakashi Iwai * @cfg: Parsed pin configuration 49989eb413e5STakashi Iwai * 49999eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 5000352f7f91STakashi Iwai * or a negative error code 5001352f7f91STakashi Iwai */ 5002352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 50039eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 5004352f7f91STakashi Iwai { 5005352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5006352f7f91STakashi Iwai int err; 5007352f7f91STakashi Iwai 50081c70a583STakashi Iwai parse_user_hints(codec); 50091c70a583STakashi Iwai 5010e4a395e7STakashi Iwai if (spec->mixer_nid && !spec->mixer_merge_nid) 5011e4a395e7STakashi Iwai spec->mixer_merge_nid = spec->mixer_nid; 5012e4a395e7STakashi Iwai 50139eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 50149eb413e5STakashi Iwai spec->autocfg = *cfg; 50159eb413e5STakashi Iwai cfg = &spec->autocfg; 50169eb413e5STakashi Iwai } 50179eb413e5STakashi Iwai 501898bd1115STakashi Iwai if (!spec->main_out_badness) 501998bd1115STakashi Iwai spec->main_out_badness = &hda_main_out_badness; 502098bd1115STakashi Iwai if (!spec->extra_out_badness) 502198bd1115STakashi Iwai spec->extra_out_badness = &hda_extra_out_badness; 502298bd1115STakashi Iwai 50236fc4cb97SDavid Henningsson fill_all_dac_nids(codec); 50246fc4cb97SDavid Henningsson 5025352f7f91STakashi Iwai if (!cfg->line_outs) { 5026352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 5027352f7f91STakashi Iwai spec->multiout.max_channels = 2; 5028352f7f91STakashi Iwai spec->no_analog = 1; 5029352f7f91STakashi Iwai goto dig_only; 5030352f7f91STakashi Iwai } 5031c9e4bdb7STakashi Iwai if (!cfg->num_inputs && !cfg->dig_in_pin) 5032352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 5033352f7f91STakashi Iwai } 5034352f7f91STakashi Iwai 5035352f7f91STakashi Iwai if (!spec->no_primary_hp && 5036352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 5037352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 5038352f7f91STakashi Iwai /* use HP as primary out */ 5039352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 5040352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 5041352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 5042352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 5043352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 5044352f7f91STakashi Iwai cfg->hp_outs = 0; 5045352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 5046352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 5047352f7f91STakashi Iwai } 5048352f7f91STakashi Iwai 5049352f7f91STakashi Iwai err = parse_output_paths(codec); 5050352f7f91STakashi Iwai if (err < 0) 5051352f7f91STakashi Iwai return err; 5052352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 5053352f7f91STakashi Iwai if (err < 0) 5054352f7f91STakashi Iwai return err; 5055352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 5056352f7f91STakashi Iwai if (err < 0) 5057352f7f91STakashi Iwai return err; 5058352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 5059352f7f91STakashi Iwai if (err < 0) 5060352f7f91STakashi Iwai return err; 5061352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 5062352f7f91STakashi Iwai if (err < 0) 5063352f7f91STakashi Iwai return err; 506438cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 506538cf6f1aSTakashi Iwai if (err < 0) 506638cf6f1aSTakashi Iwai return err; 5067c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec); 5068c30aa7b2STakashi Iwai if (err < 0) 5069c30aa7b2STakashi Iwai return err; 5070967303daSTakashi Iwai err = create_hp_mic(codec); 5071352f7f91STakashi Iwai if (err < 0) 5072352f7f91STakashi Iwai return err; 5073352f7f91STakashi Iwai err = create_input_ctls(codec); 5074352f7f91STakashi Iwai if (err < 0) 5075352f7f91STakashi Iwai return err; 5076352f7f91STakashi Iwai 5077e6feb5d0STakashi Iwai /* add power-down pin callbacks at first */ 5078e6feb5d0STakashi Iwai add_all_pin_power_ctls(codec, false); 5079e6feb5d0STakashi Iwai 5080a07a949bSTakashi Iwai spec->const_channel_count = spec->ext_channel_count; 5081a07a949bSTakashi Iwai /* check the multiple speaker and headphone pins */ 5082a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 5083a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 5084a07a949bSTakashi Iwai cfg->speaker_outs * 2); 5085a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 5086a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 5087a07a949bSTakashi Iwai cfg->hp_outs * 2); 5088352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 5089352f7f91STakashi Iwai spec->const_channel_count); 5090352f7f91STakashi Iwai 5091352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 5092352f7f91STakashi Iwai if (err < 0) 5093352f7f91STakashi Iwai return err; 5094352f7f91STakashi Iwai 5095352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 5096352f7f91STakashi Iwai if (err < 0) 5097352f7f91STakashi Iwai return err; 5098352f7f91STakashi Iwai 5099352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 5100352f7f91STakashi Iwai if (err < 0) 5101352f7f91STakashi Iwai return err; 5102352f7f91STakashi Iwai 5103f1e762ddSTakashi Iwai /* add stereo mix if available and not enabled yet */ 5104f1e762ddSTakashi Iwai if (!spec->auto_mic && spec->mixer_nid && 510574f14b36STakashi Iwai spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_AUTO && 510674f14b36STakashi Iwai spec->input_mux.num_items > 1) { 5107f1e762ddSTakashi Iwai err = parse_capture_source(codec, spec->mixer_nid, 5108f1e762ddSTakashi Iwai CFG_IDX_MIX, spec->num_all_adcs, 5109f1e762ddSTakashi Iwai "Stereo Mix", 0); 5110f1e762ddSTakashi Iwai if (err < 0) 5111f1e762ddSTakashi Iwai return err; 5112f1e762ddSTakashi Iwai } 5113f1e762ddSTakashi Iwai 5114f1e762ddSTakashi Iwai 5115352f7f91STakashi Iwai err = create_capture_mixers(codec); 5116352f7f91STakashi Iwai if (err < 0) 5117352f7f91STakashi Iwai return err; 5118352f7f91STakashi Iwai 5119352f7f91STakashi Iwai err = parse_mic_boost(codec); 5120352f7f91STakashi Iwai if (err < 0) 5121352f7f91STakashi Iwai return err; 5122352f7f91STakashi Iwai 5123ced4cefcSTakashi Iwai /* create "Headphone Mic Jack Mode" if no input selection is 5124ced4cefcSTakashi Iwai * available (or user specifies add_jack_modes hint) 5125ced4cefcSTakashi Iwai */ 5126ced4cefcSTakashi Iwai if (spec->hp_mic_pin && 5127ced4cefcSTakashi Iwai (spec->auto_mic || spec->input_mux.num_items == 1 || 5128ced4cefcSTakashi Iwai spec->add_jack_modes)) { 5129ced4cefcSTakashi Iwai err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin); 5130ced4cefcSTakashi Iwai if (err < 0) 5131ced4cefcSTakashi Iwai return err; 5132ced4cefcSTakashi Iwai } 5133ced4cefcSTakashi Iwai 5134f811c3cfSTakashi Iwai if (spec->add_jack_modes) { 5135978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 5136978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->line_outs, 5137978e77e7STakashi Iwai cfg->line_out_pins); 5138978e77e7STakashi Iwai if (err < 0) 5139978e77e7STakashi Iwai return err; 5140978e77e7STakashi Iwai } 5141978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 5142978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->hp_outs, 5143978e77e7STakashi Iwai cfg->hp_pins); 5144978e77e7STakashi Iwai if (err < 0) 5145978e77e7STakashi Iwai return err; 5146978e77e7STakashi Iwai } 5147978e77e7STakashi Iwai } 5148978e77e7STakashi Iwai 5149e6feb5d0STakashi Iwai /* add power-up pin callbacks at last */ 5150e6feb5d0STakashi Iwai add_all_pin_power_ctls(codec, true); 5151e6feb5d0STakashi Iwai 5152ebb93c05STakashi Iwai /* mute all aamix input initially */ 5153ebb93c05STakashi Iwai if (spec->mixer_nid) 5154ebb93c05STakashi Iwai mute_all_mixer_nid(codec, spec->mixer_nid); 5155ebb93c05STakashi Iwai 5156352f7f91STakashi Iwai dig_only: 5157352f7f91STakashi Iwai parse_digital(codec); 5158352f7f91STakashi Iwai 515949fb1897STakashi Iwai if (spec->power_down_unused || codec->power_save_node) { 516024fef902STakashi Iwai if (!codec->power_filter) 516155196fffSTakashi Iwai codec->power_filter = snd_hda_gen_path_power_filter; 516249fb1897STakashi Iwai if (!codec->patch_ops.stream_pm) 516349fb1897STakashi Iwai codec->patch_ops.stream_pm = snd_hda_gen_stream_pm; 516449fb1897STakashi Iwai } 516555196fffSTakashi Iwai 51667504b6cdSTakashi Iwai if (!spec->no_analog && spec->beep_nid) { 51677504b6cdSTakashi Iwai err = snd_hda_attach_beep_device(codec, spec->beep_nid); 51687504b6cdSTakashi Iwai if (err < 0) 51697504b6cdSTakashi Iwai return err; 5170967b1307STakashi Iwai if (codec->beep && codec->power_save_node) { 51715ccf835cSTakashi Iwai err = add_fake_beep_paths(codec); 51725ccf835cSTakashi Iwai if (err < 0) 51735ccf835cSTakashi Iwai return err; 51745ccf835cSTakashi Iwai codec->beep->power_hook = beep_power_hook; 51755ccf835cSTakashi Iwai } 51767504b6cdSTakashi Iwai } 51777504b6cdSTakashi Iwai 5178352f7f91STakashi Iwai return 1; 5179352f7f91STakashi Iwai } 51802698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config); 5181352f7f91STakashi Iwai 5182352f7f91STakashi Iwai 5183352f7f91STakashi Iwai /* 5184352f7f91STakashi Iwai * Build control elements 5185352f7f91STakashi Iwai */ 5186352f7f91STakashi Iwai 5187352f7f91STakashi Iwai /* slave controls for virtual master */ 5188352f7f91STakashi Iwai static const char * const slave_pfxs[] = { 5189352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 5190352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 5191352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 5192ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", 5193ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE", 519403ad6a8cSDavid Henningsson "Headphone Side", "Headphone+LO", "Speaker+LO", 5195352f7f91STakashi Iwai NULL, 5196352f7f91STakashi Iwai }; 5197352f7f91STakashi Iwai 5198dda42bd0STakashi Iwai /** 5199dda42bd0STakashi Iwai * snd_hda_gen_build_controls - Build controls from the parsed results 5200dda42bd0STakashi Iwai * @codec: the HDA codec 5201dda42bd0STakashi Iwai * 5202dda42bd0STakashi Iwai * Pass this to build_controls patch_ops. 5203dda42bd0STakashi Iwai */ 5204352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 5205352f7f91STakashi Iwai { 5206352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5207352f7f91STakashi Iwai int err; 5208352f7f91STakashi Iwai 520936502d02STakashi Iwai if (spec->kctls.used) { 5210352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 5211352f7f91STakashi Iwai if (err < 0) 5212352f7f91STakashi Iwai return err; 521336502d02STakashi Iwai } 5214352f7f91STakashi Iwai 5215352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 5216352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 5217352f7f91STakashi Iwai spec->multiout.dig_out_nid, 5218352f7f91STakashi Iwai spec->multiout.dig_out_nid, 5219bbbc7e85STakashi Iwai spec->pcm_rec[1]->pcm_type); 5220352f7f91STakashi Iwai if (err < 0) 5221352f7f91STakashi Iwai return err; 5222352f7f91STakashi Iwai if (!spec->no_analog) { 5223352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 5224352f7f91STakashi Iwai &spec->multiout); 5225352f7f91STakashi Iwai if (err < 0) 5226352f7f91STakashi Iwai return err; 5227352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 5228352f7f91STakashi Iwai } 5229352f7f91STakashi Iwai } 5230352f7f91STakashi Iwai if (spec->dig_in_nid) { 5231352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 5232352f7f91STakashi Iwai if (err < 0) 5233352f7f91STakashi Iwai return err; 5234352f7f91STakashi Iwai } 5235352f7f91STakashi Iwai 5236352f7f91STakashi Iwai /* if we have no master control, let's create it */ 52377480316cSTakashi Iwai if (!spec->no_analog && !spec->suppress_vmaster && 5238352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 5239352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 52407a71bbf3STakashi Iwai spec->vmaster_tlv, slave_pfxs, 5241352f7f91STakashi Iwai "Playback Volume"); 5242352f7f91STakashi Iwai if (err < 0) 5243352f7f91STakashi Iwai return err; 5244352f7f91STakashi Iwai } 52457480316cSTakashi Iwai if (!spec->no_analog && !spec->suppress_vmaster && 5246352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 5247352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 5248352f7f91STakashi Iwai NULL, slave_pfxs, 5249352f7f91STakashi Iwai "Playback Switch", 5250352f7f91STakashi Iwai true, &spec->vmaster_mute.sw_kctl); 5251352f7f91STakashi Iwai if (err < 0) 5252352f7f91STakashi Iwai return err; 5253b63eae0aSTakashi Iwai if (spec->vmaster_mute.hook) { 5254fd25a97aSTakashi Iwai snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, 5255fd25a97aSTakashi Iwai spec->vmaster_mute_enum); 5256b63eae0aSTakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 5257b63eae0aSTakashi Iwai } 5258352f7f91STakashi Iwai } 5259352f7f91STakashi Iwai 5260352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 5261352f7f91STakashi Iwai 5262352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 5263352f7f91STakashi Iwai if (err < 0) 5264352f7f91STakashi Iwai return err; 5265352f7f91STakashi Iwai 5266352f7f91STakashi Iwai return 0; 5267352f7f91STakashi Iwai } 52682698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls); 5269352f7f91STakashi Iwai 5270352f7f91STakashi Iwai 5271352f7f91STakashi Iwai /* 5272352f7f91STakashi Iwai * PCM definitions 5273352f7f91STakashi Iwai */ 5274352f7f91STakashi Iwai 5275e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, 5276e6b85f3cSTakashi Iwai struct hda_codec *codec, 5277e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream, 5278e6b85f3cSTakashi Iwai int action) 5279e6b85f3cSTakashi Iwai { 5280e6b85f3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 5281e6b85f3cSTakashi Iwai if (spec->pcm_playback_hook) 5282e6b85f3cSTakashi Iwai spec->pcm_playback_hook(hinfo, codec, substream, action); 5283e6b85f3cSTakashi Iwai } 5284e6b85f3cSTakashi Iwai 5285ac2e8736STakashi Iwai static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo, 5286ac2e8736STakashi Iwai struct hda_codec *codec, 5287ac2e8736STakashi Iwai struct snd_pcm_substream *substream, 5288ac2e8736STakashi Iwai int action) 5289ac2e8736STakashi Iwai { 5290ac2e8736STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5291ac2e8736STakashi Iwai if (spec->pcm_capture_hook) 5292ac2e8736STakashi Iwai spec->pcm_capture_hook(hinfo, codec, substream, action); 5293ac2e8736STakashi Iwai } 5294ac2e8736STakashi Iwai 5295352f7f91STakashi Iwai /* 5296352f7f91STakashi Iwai * Analog playback callbacks 5297352f7f91STakashi Iwai */ 5298352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 5299352f7f91STakashi Iwai struct hda_codec *codec, 5300352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5301352f7f91STakashi Iwai { 5302352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 530338cf6f1aSTakashi Iwai int err; 530438cf6f1aSTakashi Iwai 530538cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 530638cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 530738cf6f1aSTakashi Iwai &spec->multiout, substream, 5308352f7f91STakashi Iwai hinfo); 5309e6b85f3cSTakashi Iwai if (!err) { 531038cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 5311e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5312e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 5313e6b85f3cSTakashi Iwai } 531438cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 531538cf6f1aSTakashi Iwai return err; 5316352f7f91STakashi Iwai } 5317352f7f91STakashi Iwai 5318352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 531997ec558aSTakashi Iwai struct hda_codec *codec, 532097ec558aSTakashi Iwai unsigned int stream_tag, 532197ec558aSTakashi Iwai unsigned int format, 532297ec558aSTakashi Iwai struct snd_pcm_substream *substream) 532397ec558aSTakashi Iwai { 5324352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5325e6b85f3cSTakashi Iwai int err; 5326e6b85f3cSTakashi Iwai 5327e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 5328352f7f91STakashi Iwai stream_tag, format, substream); 5329e6b85f3cSTakashi Iwai if (!err) 5330e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5331e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 5332e6b85f3cSTakashi Iwai return err; 5333352f7f91STakashi Iwai } 533497ec558aSTakashi Iwai 5335352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 5336352f7f91STakashi Iwai struct hda_codec *codec, 5337352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5338352f7f91STakashi Iwai { 5339352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5340e6b85f3cSTakashi Iwai int err; 5341e6b85f3cSTakashi Iwai 5342e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 5343e6b85f3cSTakashi Iwai if (!err) 5344e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5345e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 5346e6b85f3cSTakashi Iwai return err; 5347352f7f91STakashi Iwai } 5348352f7f91STakashi Iwai 534938cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 535038cf6f1aSTakashi Iwai struct hda_codec *codec, 535138cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 535238cf6f1aSTakashi Iwai { 535338cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 535438cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 535538cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 5356e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5357e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 535838cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 535938cf6f1aSTakashi Iwai return 0; 536038cf6f1aSTakashi Iwai } 536138cf6f1aSTakashi Iwai 5362ac2e8736STakashi Iwai static int capture_pcm_open(struct hda_pcm_stream *hinfo, 5363ac2e8736STakashi Iwai struct hda_codec *codec, 5364ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 5365ac2e8736STakashi Iwai { 5366ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN); 5367ac2e8736STakashi Iwai return 0; 5368ac2e8736STakashi Iwai } 5369ac2e8736STakashi Iwai 5370ac2e8736STakashi Iwai static int capture_pcm_prepare(struct hda_pcm_stream *hinfo, 5371ac2e8736STakashi Iwai struct hda_codec *codec, 5372ac2e8736STakashi Iwai unsigned int stream_tag, 5373ac2e8736STakashi Iwai unsigned int format, 5374ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 5375ac2e8736STakashi Iwai { 5376ac2e8736STakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 5377ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 5378ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 5379ac2e8736STakashi Iwai return 0; 5380ac2e8736STakashi Iwai } 5381ac2e8736STakashi Iwai 5382ac2e8736STakashi Iwai static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 5383ac2e8736STakashi Iwai struct hda_codec *codec, 5384ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 5385ac2e8736STakashi Iwai { 5386ac2e8736STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 5387ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 5388ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 5389ac2e8736STakashi Iwai return 0; 5390ac2e8736STakashi Iwai } 5391ac2e8736STakashi Iwai 5392ac2e8736STakashi Iwai static int capture_pcm_close(struct hda_pcm_stream *hinfo, 5393ac2e8736STakashi Iwai struct hda_codec *codec, 5394ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 5395ac2e8736STakashi Iwai { 5396ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); 5397ac2e8736STakashi Iwai return 0; 5398ac2e8736STakashi Iwai } 5399ac2e8736STakashi Iwai 540038cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 540138cf6f1aSTakashi Iwai struct hda_codec *codec, 540238cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 540338cf6f1aSTakashi Iwai { 540438cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 540538cf6f1aSTakashi Iwai int err = 0; 540638cf6f1aSTakashi Iwai 540738cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 5408d1f15e06STakashi Iwai if (spec->indep_hp && !spec->indep_hp_enabled) 540938cf6f1aSTakashi Iwai err = -EBUSY; 541038cf6f1aSTakashi Iwai else 541138cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 5412e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5413e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 541438cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 541538cf6f1aSTakashi Iwai return err; 541638cf6f1aSTakashi Iwai } 541738cf6f1aSTakashi Iwai 541838cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 541938cf6f1aSTakashi Iwai struct hda_codec *codec, 542038cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 542138cf6f1aSTakashi Iwai { 542238cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 542338cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 542438cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 5425e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5426e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 542738cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 542838cf6f1aSTakashi Iwai return 0; 542938cf6f1aSTakashi Iwai } 543038cf6f1aSTakashi Iwai 5431e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 5432e6b85f3cSTakashi Iwai struct hda_codec *codec, 5433e6b85f3cSTakashi Iwai unsigned int stream_tag, 5434e6b85f3cSTakashi Iwai unsigned int format, 5435e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 5436e6b85f3cSTakashi Iwai { 5437e6b85f3cSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 5438e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5439e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 5440e6b85f3cSTakashi Iwai return 0; 5441e6b85f3cSTakashi Iwai } 5442e6b85f3cSTakashi Iwai 5443e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 5444e6b85f3cSTakashi Iwai struct hda_codec *codec, 5445e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 5446e6b85f3cSTakashi Iwai { 5447e6b85f3cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 5448e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 5449e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 5450e6b85f3cSTakashi Iwai return 0; 5451e6b85f3cSTakashi Iwai } 5452e6b85f3cSTakashi Iwai 5453352f7f91STakashi Iwai /* 5454352f7f91STakashi Iwai * Digital out 5455352f7f91STakashi Iwai */ 5456352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 5457352f7f91STakashi Iwai struct hda_codec *codec, 5458352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5459352f7f91STakashi Iwai { 5460352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5461352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 5462352f7f91STakashi Iwai } 5463352f7f91STakashi Iwai 5464352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 5465352f7f91STakashi Iwai struct hda_codec *codec, 5466352f7f91STakashi Iwai unsigned int stream_tag, 5467352f7f91STakashi Iwai unsigned int format, 5468352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5469352f7f91STakashi Iwai { 5470352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5471352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 5472352f7f91STakashi Iwai stream_tag, format, substream); 5473352f7f91STakashi Iwai } 5474352f7f91STakashi Iwai 5475352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 5476352f7f91STakashi Iwai struct hda_codec *codec, 5477352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5478352f7f91STakashi Iwai { 5479352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5480352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 5481352f7f91STakashi Iwai } 5482352f7f91STakashi Iwai 5483352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 5484352f7f91STakashi Iwai struct hda_codec *codec, 5485352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5486352f7f91STakashi Iwai { 5487352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5488352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 5489352f7f91STakashi Iwai } 5490352f7f91STakashi Iwai 5491352f7f91STakashi Iwai /* 5492352f7f91STakashi Iwai * Analog capture 5493352f7f91STakashi Iwai */ 5494ac2e8736STakashi Iwai #define alt_capture_pcm_open capture_pcm_open 5495ac2e8736STakashi Iwai #define alt_capture_pcm_close capture_pcm_close 5496ac2e8736STakashi Iwai 5497352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 5498352f7f91STakashi Iwai struct hda_codec *codec, 5499352f7f91STakashi Iwai unsigned int stream_tag, 5500352f7f91STakashi Iwai unsigned int format, 5501352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5502352f7f91STakashi Iwai { 5503352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5504352f7f91STakashi Iwai 5505352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 550697ec558aSTakashi Iwai stream_tag, 0, format); 5507ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 5508ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 550997ec558aSTakashi Iwai return 0; 551097ec558aSTakashi Iwai } 551197ec558aSTakashi Iwai 5512352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 551397ec558aSTakashi Iwai struct hda_codec *codec, 551497ec558aSTakashi Iwai struct snd_pcm_substream *substream) 551597ec558aSTakashi Iwai { 5516352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 551797ec558aSTakashi Iwai 5518352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 5519352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 5520ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 5521ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 552297ec558aSTakashi Iwai return 0; 552397ec558aSTakashi Iwai } 552497ec558aSTakashi Iwai 5525352f7f91STakashi Iwai /* 5526352f7f91STakashi Iwai */ 5527352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 5528352f7f91STakashi Iwai .substreams = 1, 5529352f7f91STakashi Iwai .channels_min = 2, 5530352f7f91STakashi Iwai .channels_max = 8, 5531352f7f91STakashi Iwai /* NID is set in build_pcms */ 5532352f7f91STakashi Iwai .ops = { 5533352f7f91STakashi Iwai .open = playback_pcm_open, 553438cf6f1aSTakashi Iwai .close = playback_pcm_close, 5535352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 5536352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 5537352f7f91STakashi Iwai }, 5538352f7f91STakashi Iwai }; 5539352f7f91STakashi Iwai 5540352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 5541352f7f91STakashi Iwai .substreams = 1, 5542352f7f91STakashi Iwai .channels_min = 2, 5543352f7f91STakashi Iwai .channels_max = 2, 5544352f7f91STakashi Iwai /* NID is set in build_pcms */ 5545ac2e8736STakashi Iwai .ops = { 5546ac2e8736STakashi Iwai .open = capture_pcm_open, 5547ac2e8736STakashi Iwai .close = capture_pcm_close, 5548ac2e8736STakashi Iwai .prepare = capture_pcm_prepare, 5549ac2e8736STakashi Iwai .cleanup = capture_pcm_cleanup 5550ac2e8736STakashi Iwai }, 5551352f7f91STakashi Iwai }; 5552352f7f91STakashi Iwai 5553352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 5554352f7f91STakashi Iwai .substreams = 1, 5555352f7f91STakashi Iwai .channels_min = 2, 5556352f7f91STakashi Iwai .channels_max = 2, 5557352f7f91STakashi Iwai /* NID is set in build_pcms */ 555838cf6f1aSTakashi Iwai .ops = { 555938cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 5560e6b85f3cSTakashi Iwai .close = alt_playback_pcm_close, 5561e6b85f3cSTakashi Iwai .prepare = alt_playback_pcm_prepare, 5562e6b85f3cSTakashi Iwai .cleanup = alt_playback_pcm_cleanup 556338cf6f1aSTakashi Iwai }, 5564352f7f91STakashi Iwai }; 5565352f7f91STakashi Iwai 5566352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 5567352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 5568352f7f91STakashi Iwai .channels_min = 2, 5569352f7f91STakashi Iwai .channels_max = 2, 5570352f7f91STakashi Iwai /* NID is set in build_pcms */ 5571352f7f91STakashi Iwai .ops = { 5572ac2e8736STakashi Iwai .open = alt_capture_pcm_open, 5573ac2e8736STakashi Iwai .close = alt_capture_pcm_close, 5574352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 5575352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 5576352f7f91STakashi Iwai }, 5577352f7f91STakashi Iwai }; 5578352f7f91STakashi Iwai 5579352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 5580352f7f91STakashi Iwai .substreams = 1, 5581352f7f91STakashi Iwai .channels_min = 2, 5582352f7f91STakashi Iwai .channels_max = 2, 5583352f7f91STakashi Iwai /* NID is set in build_pcms */ 5584352f7f91STakashi Iwai .ops = { 5585352f7f91STakashi Iwai .open = dig_playback_pcm_open, 5586352f7f91STakashi Iwai .close = dig_playback_pcm_close, 5587352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 5588352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 5589352f7f91STakashi Iwai }, 5590352f7f91STakashi Iwai }; 5591352f7f91STakashi Iwai 5592352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 5593352f7f91STakashi Iwai .substreams = 1, 5594352f7f91STakashi Iwai .channels_min = 2, 5595352f7f91STakashi Iwai .channels_max = 2, 5596352f7f91STakashi Iwai /* NID is set in build_pcms */ 5597352f7f91STakashi Iwai }; 5598352f7f91STakashi Iwai 5599352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 5600352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 5601352f7f91STakashi Iwai .substreams = 0, 5602352f7f91STakashi Iwai .channels_min = 0, 5603352f7f91STakashi Iwai .channels_max = 0, 5604352f7f91STakashi Iwai }; 5605352f7f91STakashi Iwai 5606352f7f91STakashi Iwai /* 5607352f7f91STakashi Iwai * dynamic changing ADC PCM streams 5608352f7f91STakashi Iwai */ 5609352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 56101da177e4SLinus Torvalds { 5611352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5612352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 56131da177e4SLinus Torvalds 5614352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 5615352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 5616352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 5617352f7f91STakashi Iwai spec->cur_adc = new_adc; 5618352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 5619352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 5620352f7f91STakashi Iwai spec->cur_adc_format); 5621352f7f91STakashi Iwai return true; 5622352f7f91STakashi Iwai } 5623352f7f91STakashi Iwai return false; 5624352f7f91STakashi Iwai } 5625352f7f91STakashi Iwai 5626352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 5627352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 5628352f7f91STakashi Iwai struct hda_codec *codec, 5629352f7f91STakashi Iwai unsigned int stream_tag, 5630352f7f91STakashi Iwai unsigned int format, 5631352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5632352f7f91STakashi Iwai { 5633352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5634352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 5635352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 5636352f7f91STakashi Iwai spec->cur_adc_format = format; 5637352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 56384f29efc0STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_PREPARE); 56391da177e4SLinus Torvalds return 0; 56401da177e4SLinus Torvalds } 56411da177e4SLinus Torvalds 5642352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 5643352f7f91STakashi Iwai struct hda_codec *codec, 5644352f7f91STakashi Iwai struct snd_pcm_substream *substream) 5645352f7f91STakashi Iwai { 5646352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5647352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 5648352f7f91STakashi Iwai spec->cur_adc = 0; 56494f29efc0STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLEANUP); 5650352f7f91STakashi Iwai return 0; 5651352f7f91STakashi Iwai } 5652352f7f91STakashi Iwai 5653352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 5654352f7f91STakashi Iwai .substreams = 1, 5655352f7f91STakashi Iwai .channels_min = 2, 5656352f7f91STakashi Iwai .channels_max = 2, 5657352f7f91STakashi Iwai .nid = 0, /* fill later */ 5658352f7f91STakashi Iwai .ops = { 5659352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 5660352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 5661352f7f91STakashi Iwai }, 5662352f7f91STakashi Iwai }; 5663352f7f91STakashi Iwai 5664f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 5665f873e536STakashi Iwai const char *chip_name) 5666f873e536STakashi Iwai { 5667f873e536STakashi Iwai char *p; 5668f873e536STakashi Iwai 5669f873e536STakashi Iwai if (*str) 5670f873e536STakashi Iwai return; 5671f873e536STakashi Iwai strlcpy(str, chip_name, len); 5672f873e536STakashi Iwai 5673f873e536STakashi Iwai /* drop non-alnum chars after a space */ 5674f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 5675f873e536STakashi Iwai if (!isalnum(p[1])) { 5676f873e536STakashi Iwai *p = 0; 5677f873e536STakashi Iwai break; 5678f873e536STakashi Iwai } 5679f873e536STakashi Iwai } 5680f873e536STakashi Iwai strlcat(str, sfx, len); 5681f873e536STakashi Iwai } 5682f873e536STakashi Iwai 5683fb83b635STakashi Iwai /* copy PCM stream info from @default_str, and override non-NULL entries 5684fb83b635STakashi Iwai * from @spec_str and @nid 5685fb83b635STakashi Iwai */ 5686fb83b635STakashi Iwai static void setup_pcm_stream(struct hda_pcm_stream *str, 5687fb83b635STakashi Iwai const struct hda_pcm_stream *default_str, 5688fb83b635STakashi Iwai const struct hda_pcm_stream *spec_str, 5689fb83b635STakashi Iwai hda_nid_t nid) 5690fb83b635STakashi Iwai { 5691fb83b635STakashi Iwai *str = *default_str; 5692fb83b635STakashi Iwai if (nid) 5693fb83b635STakashi Iwai str->nid = nid; 5694fb83b635STakashi Iwai if (spec_str) { 5695fb83b635STakashi Iwai if (spec_str->substreams) 5696fb83b635STakashi Iwai str->substreams = spec_str->substreams; 5697fb83b635STakashi Iwai if (spec_str->channels_min) 5698fb83b635STakashi Iwai str->channels_min = spec_str->channels_min; 5699fb83b635STakashi Iwai if (spec_str->channels_max) 5700fb83b635STakashi Iwai str->channels_max = spec_str->channels_max; 5701fb83b635STakashi Iwai if (spec_str->rates) 5702fb83b635STakashi Iwai str->rates = spec_str->rates; 5703fb83b635STakashi Iwai if (spec_str->formats) 5704fb83b635STakashi Iwai str->formats = spec_str->formats; 5705fb83b635STakashi Iwai if (spec_str->maxbps) 5706fb83b635STakashi Iwai str->maxbps = spec_str->maxbps; 5707fb83b635STakashi Iwai } 5708fb83b635STakashi Iwai } 5709fb83b635STakashi Iwai 5710dda42bd0STakashi Iwai /** 5711dda42bd0STakashi Iwai * snd_hda_gen_build_pcms - build PCM streams based on the parsed results 5712dda42bd0STakashi Iwai * @codec: the HDA codec 5713dda42bd0STakashi Iwai * 5714dda42bd0STakashi Iwai * Pass this to build_pcms patch_ops. 5715dda42bd0STakashi Iwai */ 5716352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 5717352f7f91STakashi Iwai { 5718352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5719bbbc7e85STakashi Iwai struct hda_pcm *info; 5720352f7f91STakashi Iwai bool have_multi_adcs; 5721352f7f91STakashi Iwai 5722352f7f91STakashi Iwai if (spec->no_analog) 5723352f7f91STakashi Iwai goto skip_analog; 5724352f7f91STakashi Iwai 5725f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 5726f873e536STakashi Iwai sizeof(spec->stream_name_analog), 57277639a06cSTakashi Iwai " Analog", codec->core.chip_name); 5728bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog); 5729bbbc7e85STakashi Iwai if (!info) 5730bbbc7e85STakashi Iwai return -ENOMEM; 5731bbbc7e85STakashi Iwai spec->pcm_rec[0] = info; 5732352f7f91STakashi Iwai 5733352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 5734fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK], 5735fb83b635STakashi Iwai &pcm_analog_playback, 5736fb83b635STakashi Iwai spec->stream_analog_playback, 5737fb83b635STakashi Iwai spec->multiout.dac_nids[0]); 5738352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 5739352f7f91STakashi Iwai spec->multiout.max_channels; 5740352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 5741352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 5742352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 5743352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 5744352f7f91STakashi Iwai } 5745352f7f91STakashi Iwai if (spec->num_adc_nids) { 5746fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE], 5747fb83b635STakashi Iwai (spec->dyn_adc_switch ? 5748fb83b635STakashi Iwai &dyn_adc_pcm_analog_capture : &pcm_analog_capture), 5749fb83b635STakashi Iwai spec->stream_analog_capture, 5750fb83b635STakashi Iwai spec->adc_nids[0]); 5751352f7f91STakashi Iwai } 5752352f7f91STakashi Iwai 5753352f7f91STakashi Iwai skip_analog: 5754352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 5755352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 5756f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 5757352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 57587639a06cSTakashi Iwai " Digital", codec->core.chip_name); 5759bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s", 5760bbbc7e85STakashi Iwai spec->stream_name_digital); 5761bbbc7e85STakashi Iwai if (!info) 5762bbbc7e85STakashi Iwai return -ENOMEM; 5763352f7f91STakashi Iwai codec->slave_dig_outs = spec->multiout.slave_dig_outs; 5764bbbc7e85STakashi Iwai spec->pcm_rec[1] = info; 5765352f7f91STakashi Iwai if (spec->dig_out_type) 5766352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 5767352f7f91STakashi Iwai else 5768352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 5769fb83b635STakashi Iwai if (spec->multiout.dig_out_nid) 5770fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK], 5771fb83b635STakashi Iwai &pcm_digital_playback, 5772fb83b635STakashi Iwai spec->stream_digital_playback, 5773fb83b635STakashi Iwai spec->multiout.dig_out_nid); 5774fb83b635STakashi Iwai if (spec->dig_in_nid) 5775fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE], 5776fb83b635STakashi Iwai &pcm_digital_capture, 5777fb83b635STakashi Iwai spec->stream_digital_capture, 5778fb83b635STakashi Iwai spec->dig_in_nid); 5779352f7f91STakashi Iwai } 5780352f7f91STakashi Iwai 5781352f7f91STakashi Iwai if (spec->no_analog) 5782352f7f91STakashi Iwai return 0; 5783352f7f91STakashi Iwai 5784352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 5785352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 5786352f7f91STakashi Iwai */ 5787352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 5788352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 5789352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 5790352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 5791a607148fSTakashi Iwai fill_pcm_stream_name(spec->stream_name_alt_analog, 5792a607148fSTakashi Iwai sizeof(spec->stream_name_alt_analog), 57937639a06cSTakashi Iwai " Alt Analog", codec->core.chip_name); 5794bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s", 5795bbbc7e85STakashi Iwai spec->stream_name_alt_analog); 5796bbbc7e85STakashi Iwai if (!info) 5797bbbc7e85STakashi Iwai return -ENOMEM; 5798bbbc7e85STakashi Iwai spec->pcm_rec[2] = info; 5799fb83b635STakashi Iwai if (spec->alt_dac_nid) 5800fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK], 5801fb83b635STakashi Iwai &pcm_analog_alt_playback, 5802fb83b635STakashi Iwai spec->stream_analog_alt_playback, 5803fb83b635STakashi Iwai spec->alt_dac_nid); 5804fb83b635STakashi Iwai else 5805fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK], 5806fb83b635STakashi Iwai &pcm_null_stream, NULL, 0); 5807352f7f91STakashi Iwai if (have_multi_adcs) { 5808fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE], 5809fb83b635STakashi Iwai &pcm_analog_alt_capture, 5810fb83b635STakashi Iwai spec->stream_analog_alt_capture, 5811fb83b635STakashi Iwai spec->adc_nids[1]); 5812352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 5813352f7f91STakashi Iwai spec->num_adc_nids - 1; 5814352f7f91STakashi Iwai } else { 5815fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE], 5816fb83b635STakashi Iwai &pcm_null_stream, NULL, 0); 5817352f7f91STakashi Iwai } 58181da177e4SLinus Torvalds } 58191da177e4SLinus Torvalds 58201da177e4SLinus Torvalds return 0; 58211da177e4SLinus Torvalds } 58222698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms); 5823352f7f91STakashi Iwai 5824352f7f91STakashi Iwai 5825352f7f91STakashi Iwai /* 5826352f7f91STakashi Iwai * Standard auto-parser initializations 5827352f7f91STakashi Iwai */ 5828352f7f91STakashi Iwai 5829d4156930STakashi Iwai /* configure the given path as a proper output */ 58302c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx) 5831352f7f91STakashi Iwai { 5832352f7f91STakashi Iwai struct nid_path *path; 5833d4156930STakashi Iwai hda_nid_t pin; 5834352f7f91STakashi Iwai 5835196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 5836d4156930STakashi Iwai if (!path || !path->depth) 5837352f7f91STakashi Iwai return; 5838d4156930STakashi Iwai pin = path->path[path->depth - 1]; 58392c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 584065033cc8STakashi Iwai snd_hda_activate_path(codec, path, path->active, 584165033cc8STakashi Iwai aamix_default(codec->spec)); 5842e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 5843352f7f91STakashi Iwai } 5844352f7f91STakashi Iwai 5845352f7f91STakashi Iwai /* initialize primary output paths */ 5846352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 5847352f7f91STakashi Iwai { 5848352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5849352f7f91STakashi Iwai int i; 5850352f7f91STakashi Iwai 5851d4156930STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) 58522c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->out_paths[i]); 5853352f7f91STakashi Iwai } 5854352f7f91STakashi Iwai 5855db23fd19STakashi Iwai 58562c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) 5857352f7f91STakashi Iwai { 5858352f7f91STakashi Iwai int i; 5859352f7f91STakashi Iwai 5860d4156930STakashi Iwai for (i = 0; i < num_outs; i++) 58612c12c30dSTakashi Iwai set_output_and_unmute(codec, paths[i]); 5862352f7f91STakashi Iwai } 5863db23fd19STakashi Iwai 5864db23fd19STakashi Iwai /* initialize hp and speaker paths */ 5865db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 5866db23fd19STakashi Iwai { 5867db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5868db23fd19STakashi Iwai 5869db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 58702c12c30dSTakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); 5871db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 5872db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 58732c12c30dSTakashi Iwai spec->speaker_paths); 5874352f7f91STakashi Iwai } 5875352f7f91STakashi Iwai 5876352f7f91STakashi Iwai /* initialize multi-io paths */ 5877352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 5878352f7f91STakashi Iwai { 5879352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5880352f7f91STakashi Iwai int i; 5881352f7f91STakashi Iwai 5882352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 5883352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 5884352f7f91STakashi Iwai struct nid_path *path; 5885196c1766STakashi Iwai path = get_multiio_path(codec, i); 5886352f7f91STakashi Iwai if (!path) 5887352f7f91STakashi Iwai continue; 5888352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 5889352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 58902c12c30dSTakashi Iwai snd_hda_codec_get_pin_target(codec, pin); 589165033cc8STakashi Iwai snd_hda_activate_path(codec, path, path->active, 589265033cc8STakashi Iwai aamix_default(spec)); 5893352f7f91STakashi Iwai } 5894352f7f91STakashi Iwai } 5895352f7f91STakashi Iwai 58964f7f67fbSTakashi Iwai static void init_aamix_paths(struct hda_codec *codec) 58974f7f67fbSTakashi Iwai { 58984f7f67fbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 58994f7f67fbSTakashi Iwai 59004f7f67fbSTakashi Iwai if (!spec->have_aamix_ctl) 59014f7f67fbSTakashi Iwai return; 5902e7fdd527STakashi Iwai if (!has_aamix_out_paths(spec)) 5903e7fdd527STakashi Iwai return; 59044f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0], 59054f7f67fbSTakashi Iwai spec->aamix_out_paths[0], 59064f7f67fbSTakashi Iwai spec->autocfg.line_out_type); 59074f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0], 59084f7f67fbSTakashi Iwai spec->aamix_out_paths[1], 59094f7f67fbSTakashi Iwai AUTO_PIN_HP_OUT); 59104f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0], 59114f7f67fbSTakashi Iwai spec->aamix_out_paths[2], 59124f7f67fbSTakashi Iwai AUTO_PIN_SPEAKER_OUT); 59134f7f67fbSTakashi Iwai } 59144f7f67fbSTakashi Iwai 5915352f7f91STakashi Iwai /* set up input pins and loopback paths */ 5916352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 5917352f7f91STakashi Iwai { 5918352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5919352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 5920352f7f91STakashi Iwai int i; 5921352f7f91STakashi Iwai 5922352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 5923352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 5924352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 59252c12c30dSTakashi Iwai restore_pin_ctl(codec, nid); 5926352f7f91STakashi Iwai 5927352f7f91STakashi Iwai /* init loopback inputs */ 5928352f7f91STakashi Iwai if (spec->mixer_nid) { 59293e367f15STakashi Iwai resume_path_from_idx(codec, spec->loopback_paths[i]); 59303e367f15STakashi Iwai resume_path_from_idx(codec, spec->loopback_merge_path); 5931352f7f91STakashi Iwai } 5932352f7f91STakashi Iwai } 5933352f7f91STakashi Iwai } 5934352f7f91STakashi Iwai 5935352f7f91STakashi Iwai /* initialize ADC paths */ 5936352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 5937352f7f91STakashi Iwai { 5938352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5939352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 5940352f7f91STakashi Iwai struct nid_path *path; 5941352f7f91STakashi Iwai int i, c, nums; 5942352f7f91STakashi Iwai 5943352f7f91STakashi Iwai if (spec->dyn_adc_switch) 5944352f7f91STakashi Iwai nums = 1; 5945352f7f91STakashi Iwai else 5946352f7f91STakashi Iwai nums = spec->num_adc_nids; 5947352f7f91STakashi Iwai 5948352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 5949352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 5950c697b716STakashi Iwai path = get_input_path(codec, c, i); 5951352f7f91STakashi Iwai if (path) { 5952352f7f91STakashi Iwai bool active = path->active; 5953352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 5954352f7f91STakashi Iwai active = true; 5955352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 5956352f7f91STakashi Iwai } 5957352f7f91STakashi Iwai } 5958967303daSTakashi Iwai if (spec->hp_mic) 5959967303daSTakashi Iwai update_hp_mic(codec, c, true); 5960352f7f91STakashi Iwai } 5961352f7f91STakashi Iwai 5962352f7f91STakashi Iwai if (spec->cap_sync_hook) 59637fe30711STakashi Iwai spec->cap_sync_hook(codec, NULL, NULL); 5964352f7f91STakashi Iwai } 5965352f7f91STakashi Iwai 5966352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 5967352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 5968352f7f91STakashi Iwai { 5969352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5970352f7f91STakashi Iwai int i; 5971352f7f91STakashi Iwai hda_nid_t pin; 5972352f7f91STakashi Iwai 5973d4156930STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) 59742c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->digout_paths[i]); 5975352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 59762430d7b7STakashi Iwai if (pin) { 59772c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 59783e367f15STakashi Iwai resume_path_from_idx(codec, spec->digin_path); 59792430d7b7STakashi Iwai } 5980352f7f91STakashi Iwai } 5981352f7f91STakashi Iwai 5982973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 5983973e4972STakashi Iwai * invalid unsol tags by some reason 5984973e4972STakashi Iwai */ 5985973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 5986973e4972STakashi Iwai { 5987a9c2dfc8STakashi Iwai const struct hda_pincfg *pin; 5988973e4972STakashi Iwai int i; 5989973e4972STakashi Iwai 5990a9c2dfc8STakashi Iwai snd_array_for_each(&codec->init_pins, i, pin) { 5991973e4972STakashi Iwai hda_nid_t nid = pin->nid; 5992973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 5993973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 5994401caff7STakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 5995973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 5996973e4972STakashi Iwai } 5997973e4972STakashi Iwai } 5998973e4972STakashi Iwai 5999dda42bd0STakashi Iwai /** 6000dda42bd0STakashi Iwai * snd_hda_gen_init - initialize the generic spec 6001dda42bd0STakashi Iwai * @codec: the HDA codec 6002dda42bd0STakashi Iwai * 6003dda42bd0STakashi Iwai * This can be put as patch_ops init function. 60045187ac16STakashi Iwai */ 6005352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 6006352f7f91STakashi Iwai { 6007352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 6008352f7f91STakashi Iwai 6009352f7f91STakashi Iwai if (spec->init_hook) 6010352f7f91STakashi Iwai spec->init_hook(codec); 6011352f7f91STakashi Iwai 601289781d08STakashi Iwai if (!spec->skip_verbs) 6013352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 6014352f7f91STakashi Iwai 6015352f7f91STakashi Iwai init_multi_out(codec); 6016352f7f91STakashi Iwai init_extra_out(codec); 6017352f7f91STakashi Iwai init_multi_io(codec); 60184f7f67fbSTakashi Iwai init_aamix_paths(codec); 6019352f7f91STakashi Iwai init_analog_input(codec); 6020352f7f91STakashi Iwai init_input_src(codec); 6021352f7f91STakashi Iwai init_digital(codec); 6022352f7f91STakashi Iwai 6023973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 6024973e4972STakashi Iwai 6025e6feb5d0STakashi Iwai sync_all_pin_power_ctls(codec); 6026e6feb5d0STakashi Iwai 6027352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 6028a5cc2509STakashi Iwai update_automute_all(codec); 6029352f7f91STakashi Iwai 6030a551d914STakashi Iwai regcache_sync(codec->core.regmap); 60313bbcd274STakashi Iwai 6032352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 6033352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 6034352f7f91STakashi Iwai 6035352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 6036352f7f91STakashi Iwai return 0; 6037352f7f91STakashi Iwai } 60382698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_init); 6039fce52a3bSTakashi Iwai 6040dda42bd0STakashi Iwai /** 6041dda42bd0STakashi Iwai * snd_hda_gen_free - free the generic spec 6042dda42bd0STakashi Iwai * @codec: the HDA codec 6043dda42bd0STakashi Iwai * 6044dda42bd0STakashi Iwai * This can be put as patch_ops free function. 60455187ac16STakashi Iwai */ 6046fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec) 6047fce52a3bSTakashi Iwai { 60488a02c0ccSTakashi Iwai snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); 6049fce52a3bSTakashi Iwai snd_hda_gen_spec_free(codec->spec); 6050fce52a3bSTakashi Iwai kfree(codec->spec); 6051fce52a3bSTakashi Iwai codec->spec = NULL; 6052fce52a3bSTakashi Iwai } 60532698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_free); 6054fce52a3bSTakashi Iwai 6055871b9066SHui Wang /** 6056871b9066SHui Wang * snd_hda_gen_reboot_notify - Make codec enter D3 before rebooting 6057871b9066SHui Wang * @codec: the HDA codec 6058871b9066SHui Wang * 6059871b9066SHui Wang * This can be put as patch_ops reboot_notify function. 6060871b9066SHui Wang */ 6061871b9066SHui Wang void snd_hda_gen_reboot_notify(struct hda_codec *codec) 6062871b9066SHui Wang { 6063871b9066SHui Wang /* Make the codec enter D3 to avoid spurious noises from the internal 6064871b9066SHui Wang * speaker during (and after) reboot 6065871b9066SHui Wang */ 6066871b9066SHui Wang snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3); 6067871b9066SHui Wang snd_hda_codec_write(codec, codec->core.afg, 0, 6068871b9066SHui Wang AC_VERB_SET_POWER_STATE, AC_PWRST_D3); 6069871b9066SHui Wang msleep(10); 6070871b9066SHui Wang } 6071871b9066SHui Wang EXPORT_SYMBOL_GPL(snd_hda_gen_reboot_notify); 6072871b9066SHui Wang 6073fce52a3bSTakashi Iwai #ifdef CONFIG_PM 6074dda42bd0STakashi Iwai /** 6075dda42bd0STakashi Iwai * snd_hda_gen_check_power_status - check the loopback power save state 6076dda42bd0STakashi Iwai * @codec: the HDA codec 6077dda42bd0STakashi Iwai * @nid: NID to inspect 6078dda42bd0STakashi Iwai * 6079dda42bd0STakashi Iwai * This can be put as patch_ops check_power_status function. 60805187ac16STakashi Iwai */ 6081fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) 6082fce52a3bSTakashi Iwai { 6083fce52a3bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 6084fce52a3bSTakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 6085fce52a3bSTakashi Iwai } 60862698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status); 6087fce52a3bSTakashi Iwai #endif 6088352f7f91STakashi Iwai 6089352f7f91STakashi Iwai 6090352f7f91STakashi Iwai /* 6091352f7f91STakashi Iwai * the generic codec support 6092352f7f91STakashi Iwai */ 60931da177e4SLinus Torvalds 6094352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 6095352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 6096352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 6097352f7f91STakashi Iwai .init = snd_hda_gen_init, 6098fce52a3bSTakashi Iwai .free = snd_hda_gen_free, 6099352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 6100871b9066SHui Wang .reboot_notify = snd_hda_gen_reboot_notify, 610183012a7cSTakashi Iwai #ifdef CONFIG_PM 6102fce52a3bSTakashi Iwai .check_power_status = snd_hda_gen_check_power_status, 6103cb53c626STakashi Iwai #endif 61041da177e4SLinus Torvalds }; 61051da177e4SLinus Torvalds 6106d8a766a1STakashi Iwai /* 6107dda42bd0STakashi Iwai * snd_hda_parse_generic_codec - Generic codec parser 6108dda42bd0STakashi Iwai * @codec: the HDA codec 6109dda42bd0STakashi Iwai */ 6110d8a766a1STakashi Iwai static int snd_hda_parse_generic_codec(struct hda_codec *codec) 61111da177e4SLinus Torvalds { 6112352f7f91STakashi Iwai struct hda_gen_spec *spec; 61131da177e4SLinus Torvalds int err; 61141da177e4SLinus Torvalds 6115e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 6116352f7f91STakashi Iwai if (!spec) 61171da177e4SLinus Torvalds return -ENOMEM; 6118352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 61191da177e4SLinus Torvalds codec->spec = spec; 61201da177e4SLinus Torvalds 61219eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 61229eb413e5STakashi Iwai if (err < 0) 6123cfef67f0SWenwen Wang goto error; 61249eb413e5STakashi Iwai 61259eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 6126352f7f91STakashi Iwai if (err < 0) 61271da177e4SLinus Torvalds goto error; 61281da177e4SLinus Torvalds 61291da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 61301da177e4SLinus Torvalds return 0; 61311da177e4SLinus Torvalds 61321da177e4SLinus Torvalds error: 6133fce52a3bSTakashi Iwai snd_hda_gen_free(codec); 61341da177e4SLinus Torvalds return err; 61351da177e4SLinus Torvalds } 6136d8a766a1STakashi Iwai 6137b9a94a9cSTakashi Iwai static const struct hda_device_id snd_hda_id_generic[] = { 6138b9a94a9cSTakashi Iwai HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec), 6139d8a766a1STakashi Iwai {} /* terminator */ 6140d8a766a1STakashi Iwai }; 6141b9a94a9cSTakashi Iwai MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic); 6142d8a766a1STakashi Iwai 6143d8a766a1STakashi Iwai static struct hda_codec_driver generic_driver = { 6144b9a94a9cSTakashi Iwai .id = snd_hda_id_generic, 6145d8a766a1STakashi Iwai }; 6146d8a766a1STakashi Iwai 6147d8a766a1STakashi Iwai module_hda_codec_driver(generic_driver); 6148b21bdd0dSTakashi Iwai 6149b21bdd0dSTakashi Iwai MODULE_LICENSE("GPL"); 6150b21bdd0dSTakashi Iwai MODULE_DESCRIPTION("Generic HD-audio codec parser"); 6151