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