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> 27f873e536STakashi Iwai #include <linux/ctype.h> 28f873e536STakashi Iwai #include <linux/string.h> 291da177e4SLinus Torvalds #include <sound/core.h> 30352f7f91STakashi Iwai #include <sound/jack.h> 311da177e4SLinus Torvalds #include "hda_codec.h" 321da177e4SLinus Torvalds #include "hda_local.h" 33352f7f91STakashi Iwai #include "hda_auto_parser.h" 34352f7f91STakashi Iwai #include "hda_jack.h" 35352f7f91STakashi Iwai #include "hda_generic.h" 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds 38352f7f91STakashi Iwai /* initialize hda_gen_spec struct */ 39352f7f91STakashi Iwai int snd_hda_gen_spec_init(struct hda_gen_spec *spec) 401da177e4SLinus Torvalds { 41352f7f91STakashi Iwai snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); 42352f7f91STakashi Iwai snd_array_init(&spec->paths, sizeof(struct nid_path), 8); 4338cf6f1aSTakashi Iwai mutex_init(&spec->pcm_mutex); 44352f7f91STakashi Iwai return 0; 45352f7f91STakashi Iwai } 46352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init); 471da177e4SLinus Torvalds 4812c93df6STakashi Iwai struct snd_kcontrol_new * 4912c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, 50352f7f91STakashi Iwai const struct snd_kcontrol_new *temp) 51352f7f91STakashi Iwai { 52352f7f91STakashi Iwai struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); 53352f7f91STakashi Iwai if (!knew) 54352f7f91STakashi Iwai return NULL; 55352f7f91STakashi Iwai *knew = *temp; 56352f7f91STakashi Iwai if (name) 57352f7f91STakashi Iwai knew->name = kstrdup(name, GFP_KERNEL); 58352f7f91STakashi Iwai else if (knew->name) 59352f7f91STakashi Iwai knew->name = kstrdup(knew->name, GFP_KERNEL); 60352f7f91STakashi Iwai if (!knew->name) 61352f7f91STakashi Iwai return NULL; 62352f7f91STakashi Iwai return knew; 63352f7f91STakashi Iwai } 6412c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl); 65352f7f91STakashi Iwai 66352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec) 67352f7f91STakashi Iwai { 68352f7f91STakashi Iwai if (spec->kctls.list) { 69352f7f91STakashi Iwai struct snd_kcontrol_new *kctl = spec->kctls.list; 70352f7f91STakashi Iwai int i; 71352f7f91STakashi Iwai for (i = 0; i < spec->kctls.used; i++) 72352f7f91STakashi Iwai kfree(kctl[i].name); 73352f7f91STakashi Iwai } 74352f7f91STakashi Iwai snd_array_free(&spec->kctls); 75352f7f91STakashi Iwai } 76352f7f91STakashi Iwai 77352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec) 78352f7f91STakashi Iwai { 791da177e4SLinus Torvalds if (!spec) 801da177e4SLinus Torvalds return; 81352f7f91STakashi Iwai free_kctls(spec); 82352f7f91STakashi Iwai snd_array_free(&spec->paths); 831da177e4SLinus Torvalds } 84352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free); 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* 872c12c30dSTakashi Iwai * pin control value accesses 882c12c30dSTakashi Iwai */ 892c12c30dSTakashi Iwai 902c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \ 912c12c30dSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, \ 922c12c30dSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, val) 932c12c30dSTakashi Iwai 942c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */ 952c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin) 962c12c30dSTakashi Iwai { 972c12c30dSTakashi Iwai update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin)); 982c12c30dSTakashi Iwai } 992c12c30dSTakashi Iwai 1002c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */ 1012c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin, 1022c12c30dSTakashi Iwai unsigned int val, bool do_write) 1032c12c30dSTakashi Iwai { 1042c12c30dSTakashi Iwai if (!pin) 1052c12c30dSTakashi Iwai return; 1062c12c30dSTakashi Iwai val = snd_hda_correct_pin_ctl(codec, pin, val); 1072c12c30dSTakashi Iwai snd_hda_codec_set_pin_target(codec, pin, val); 1082c12c30dSTakashi Iwai if (do_write) 1092c12c30dSTakashi Iwai update_pin_ctl(codec, pin, val); 1102c12c30dSTakashi Iwai } 1112c12c30dSTakashi Iwai 1122c12c30dSTakashi Iwai /* set pinctl target values for all given pins */ 1132c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins, 1142c12c30dSTakashi Iwai hda_nid_t *pins, unsigned int val) 1152c12c30dSTakashi Iwai { 1162c12c30dSTakashi Iwai int i; 1172c12c30dSTakashi Iwai for (i = 0; i < num_pins; i++) 1182c12c30dSTakashi Iwai set_pin_target(codec, pins[i], val, false); 1192c12c30dSTakashi Iwai } 1202c12c30dSTakashi Iwai 1212c12c30dSTakashi Iwai /* 122352f7f91STakashi Iwai * parsing paths 1231da177e4SLinus Torvalds */ 1241da177e4SLinus Torvalds 1253ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */ 1263ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 1273ca529d3STakashi Iwai { 1283ca529d3STakashi Iwai int i; 1293ca529d3STakashi Iwai for (i = 0; i < nums; i++) 1303ca529d3STakashi Iwai if (list[i] == nid) 1313ca529d3STakashi Iwai return i; 1323ca529d3STakashi Iwai return -1; 1333ca529d3STakashi Iwai } 1343ca529d3STakashi Iwai 1353ca529d3STakashi Iwai /* return true if the given NID is contained in the path */ 1363ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid) 1373ca529d3STakashi Iwai { 1383ca529d3STakashi Iwai return find_idx_in_nid_list(nid, path->path, path->depth) >= 0; 1393ca529d3STakashi Iwai } 1403ca529d3STakashi Iwai 141f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec, 142f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 1433ca529d3STakashi Iwai int anchor_nid) 1441da177e4SLinus Torvalds { 145352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 146352f7f91STakashi Iwai int i; 1471da177e4SLinus Torvalds 148352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 149352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 150352f7f91STakashi Iwai if (path->depth <= 0) 151352f7f91STakashi Iwai continue; 152352f7f91STakashi Iwai if ((!from_nid || path->path[0] == from_nid) && 153f5172a7eSTakashi Iwai (!to_nid || path->path[path->depth - 1] == to_nid)) { 1543ca529d3STakashi Iwai if (!anchor_nid || 1553ca529d3STakashi Iwai (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) || 1563ca529d3STakashi Iwai (anchor_nid < 0 && !is_nid_contained(path, anchor_nid))) 157352f7f91STakashi Iwai return path; 1581da177e4SLinus Torvalds } 159f5172a7eSTakashi Iwai } 1601da177e4SLinus Torvalds return NULL; 1611da177e4SLinus Torvalds } 162f5172a7eSTakashi Iwai 163f5172a7eSTakashi Iwai /* get the path between the given NIDs; 164f5172a7eSTakashi Iwai * passing 0 to either @pin or @dac behaves as a wildcard 165f5172a7eSTakashi Iwai */ 166f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, 167f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 168f5172a7eSTakashi Iwai { 1693ca529d3STakashi Iwai return get_nid_path(codec, from_nid, to_nid, 0); 170f5172a7eSTakashi Iwai } 171352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path); 1721da177e4SLinus Torvalds 173196c1766STakashi Iwai /* get the index number corresponding to the path instance; 174196c1766STakashi Iwai * the index starts from 1, for easier checking the invalid value 175196c1766STakashi Iwai */ 176196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) 177196c1766STakashi Iwai { 178196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 179196c1766STakashi Iwai struct nid_path *array = spec->paths.list; 180196c1766STakashi Iwai ssize_t idx; 181196c1766STakashi Iwai 182196c1766STakashi Iwai if (!spec->paths.used) 183196c1766STakashi Iwai return 0; 184196c1766STakashi Iwai idx = path - array; 185196c1766STakashi Iwai if (idx < 0 || idx >= spec->paths.used) 186196c1766STakashi Iwai return 0; 187196c1766STakashi Iwai return idx + 1; 188196c1766STakashi Iwai } 189196c1766STakashi Iwai 190196c1766STakashi Iwai /* get the path instance corresponding to the given index number */ 191196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) 192196c1766STakashi Iwai { 193196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 194196c1766STakashi Iwai 195196c1766STakashi Iwai if (idx <= 0 || idx > spec->paths.used) 196196c1766STakashi Iwai return NULL; 197196c1766STakashi Iwai return snd_array_elem(&spec->paths, idx - 1); 198196c1766STakashi Iwai } 199196c1766STakashi Iwai 200352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */ 201352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) 2021da177e4SLinus Torvalds { 203352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 204352f7f91STakashi Iwai int i; 205352f7f91STakashi Iwai 206352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 207352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 208352f7f91STakashi Iwai if (path->path[0] == nid) 209352f7f91STakashi Iwai return true; 210352f7f91STakashi Iwai } 211352f7f91STakashi Iwai return false; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 214352f7f91STakashi Iwai /* check whether the given two widgets can be connected */ 215352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec, 216352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 2171da177e4SLinus Torvalds { 218352f7f91STakashi Iwai if (!from_nid || !to_nid) 219352f7f91STakashi Iwai return false; 220352f7f91STakashi Iwai return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 223352f7f91STakashi Iwai /* nid, dir and idx */ 224352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) 225352f7f91STakashi Iwai 226352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */ 227352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) 2281da177e4SLinus Torvalds { 229352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 230352f7f91STakashi Iwai int i; 231352f7f91STakashi Iwai 232352f7f91STakashi Iwai val &= AMP_VAL_COMPARE_MASK; 233352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 234352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 235352f7f91STakashi Iwai if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) 236352f7f91STakashi Iwai return true; 237352f7f91STakashi Iwai } 238352f7f91STakashi Iwai return false; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 241352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */ 242352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, 243cb53c626STakashi Iwai int dir, int idx) 244cb53c626STakashi Iwai { 245352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); 246352f7f91STakashi Iwai return is_ctl_used(codec, val, NID_PATH_VOL_CTL) || 247352f7f91STakashi Iwai is_ctl_used(codec, val, NID_PATH_MUTE_CTL); 248cb53c626STakashi Iwai } 249352f7f91STakashi Iwai 2500c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path) 2510c8c0f56STakashi Iwai { 2520c8c0f56STakashi Iwai char buf[40]; 2530c8c0f56STakashi Iwai int i; 2540c8c0f56STakashi Iwai 2550c8c0f56STakashi Iwai 2560c8c0f56STakashi Iwai buf[0] = 0; 2570c8c0f56STakashi Iwai for (i = 0; i < path->depth; i++) { 2580c8c0f56STakashi Iwai char tmp[4]; 2590c8c0f56STakashi Iwai sprintf(tmp, ":%02x", path->path[i]); 2600c8c0f56STakashi Iwai strlcat(buf, tmp, sizeof(buf)); 2610c8c0f56STakashi Iwai } 2620c8c0f56STakashi Iwai snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf); 2630c8c0f56STakashi Iwai } 2640c8c0f56STakashi Iwai 265352f7f91STakashi Iwai /* called recursively */ 266352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec, 267352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 2683ca529d3STakashi Iwai int anchor_nid, struct nid_path *path, 2693ca529d3STakashi Iwai int depth) 270352f7f91STakashi Iwai { 271ee8e765bSTakashi Iwai const hda_nid_t *conn; 272352f7f91STakashi Iwai int i, nums; 273352f7f91STakashi Iwai 2743ca529d3STakashi Iwai if (to_nid == anchor_nid) 2753ca529d3STakashi Iwai anchor_nid = 0; /* anchor passed */ 2763ca529d3STakashi Iwai else if (to_nid == (hda_nid_t)(-anchor_nid)) 2773ca529d3STakashi Iwai return false; /* hit the exclusive nid */ 278352f7f91STakashi Iwai 279ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn); 280352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 281352f7f91STakashi Iwai if (conn[i] != from_nid) { 282352f7f91STakashi Iwai /* special case: when from_nid is 0, 283352f7f91STakashi Iwai * try to find an empty DAC 284352f7f91STakashi Iwai */ 285352f7f91STakashi Iwai if (from_nid || 286352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || 287352f7f91STakashi Iwai is_dac_already_used(codec, conn[i])) 288352f7f91STakashi Iwai continue; 289352f7f91STakashi Iwai } 2903ca529d3STakashi Iwai /* anchor is not requested or already passed? */ 2913ca529d3STakashi Iwai if (anchor_nid <= 0) 292352f7f91STakashi Iwai goto found; 293352f7f91STakashi Iwai } 294352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH) 295352f7f91STakashi Iwai return false; 296352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 297352f7f91STakashi Iwai unsigned int type; 298352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i])); 299352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || 300352f7f91STakashi Iwai type == AC_WID_PIN) 301352f7f91STakashi Iwai continue; 302352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i], 3033ca529d3STakashi Iwai anchor_nid, path, depth + 1)) 304352f7f91STakashi Iwai goto found; 305352f7f91STakashi Iwai } 306352f7f91STakashi Iwai return false; 307352f7f91STakashi Iwai 308352f7f91STakashi Iwai found: 309352f7f91STakashi Iwai path->path[path->depth] = conn[i]; 310352f7f91STakashi Iwai path->idx[path->depth + 1] = i; 311352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) 312352f7f91STakashi Iwai path->multi[path->depth + 1] = 1; 313352f7f91STakashi Iwai path->depth++; 314352f7f91STakashi Iwai return true; 315352f7f91STakashi Iwai } 316352f7f91STakashi Iwai 317352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid; 318352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC; 3193ca529d3STakashi Iwai * when @anchor_nid is set to a positive value, only paths through the widget 3203ca529d3STakashi Iwai * with the given value are evaluated. 3213ca529d3STakashi Iwai * when @anchor_nid is set to a negative value, paths through the widget 3223ca529d3STakashi Iwai * with the negative of given value are excluded, only other paths are chosen. 3233ca529d3STakashi Iwai * when @anchor_nid is zero, no special handling about path selection. 324352f7f91STakashi Iwai */ 325352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, 3263ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid, 327352f7f91STakashi Iwai struct nid_path *path) 328352f7f91STakashi Iwai { 3293ca529d3STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) { 330352f7f91STakashi Iwai path->path[path->depth] = to_nid; 331352f7f91STakashi Iwai path->depth++; 332352f7f91STakashi Iwai return true; 333352f7f91STakashi Iwai } 334352f7f91STakashi Iwai return false; 335352f7f91STakashi Iwai } 336352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path); 337352f7f91STakashi Iwai 338352f7f91STakashi Iwai /* 339352f7f91STakashi Iwai * parse the path between the given NIDs and add to the path list. 340352f7f91STakashi Iwai * if no valid path is found, return NULL 341352f7f91STakashi Iwai */ 342352f7f91STakashi Iwai struct nid_path * 343352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, 3443ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid) 345352f7f91STakashi Iwai { 346352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 347352f7f91STakashi Iwai struct nid_path *path; 348352f7f91STakashi Iwai 349352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) 350352f7f91STakashi Iwai return NULL; 351352f7f91STakashi Iwai 352f5172a7eSTakashi Iwai /* check whether the path has been already added */ 3533ca529d3STakashi Iwai path = get_nid_path(codec, from_nid, to_nid, anchor_nid); 354f5172a7eSTakashi Iwai if (path) 355f5172a7eSTakashi Iwai return path; 356f5172a7eSTakashi Iwai 357352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 358352f7f91STakashi Iwai if (!path) 359352f7f91STakashi Iwai return NULL; 360352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 3613ca529d3STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path)) 362352f7f91STakashi Iwai return path; 363352f7f91STakashi Iwai /* push back */ 364352f7f91STakashi Iwai spec->paths.used--; 365352f7f91STakashi Iwai return NULL; 366352f7f91STakashi Iwai } 367352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path); 368352f7f91STakashi Iwai 369980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */ 370980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx) 371980428ceSTakashi Iwai { 372980428ceSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, idx); 373980428ceSTakashi Iwai if (!path) 374980428ceSTakashi Iwai return; 375980428ceSTakashi Iwai memset(path, 0, sizeof(*path)); 376980428ceSTakashi Iwai } 377980428ceSTakashi Iwai 378352f7f91STakashi Iwai /* look for an empty DAC slot */ 379352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, 380352f7f91STakashi Iwai bool is_digital) 381352f7f91STakashi Iwai { 382352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 383352f7f91STakashi Iwai bool cap_digital; 384352f7f91STakashi Iwai int i; 385352f7f91STakashi Iwai 386352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 387352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 388352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 389352f7f91STakashi Iwai continue; 390352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); 391352f7f91STakashi Iwai if (is_digital != cap_digital) 392352f7f91STakashi Iwai continue; 393352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) 394352f7f91STakashi Iwai return nid; 395352f7f91STakashi Iwai } 396352f7f91STakashi Iwai return 0; 397352f7f91STakashi Iwai } 398352f7f91STakashi Iwai 399352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */ 400352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) 401352f7f91STakashi Iwai { 402352f7f91STakashi Iwai val &= ~(0x3U << 16); 403352f7f91STakashi Iwai val |= chs << 16; 404352f7f91STakashi Iwai return val; 405352f7f91STakashi Iwai } 406352f7f91STakashi Iwai 407352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */ 408352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, 409352f7f91STakashi Iwai int dir, unsigned int bits) 410352f7f91STakashi Iwai { 411352f7f91STakashi Iwai if (!nid) 412352f7f91STakashi Iwai return false; 413352f7f91STakashi Iwai if (get_wcaps(codec, nid) & (1 << (dir + 1))) 414352f7f91STakashi Iwai if (query_amp_caps(codec, nid, dir) & bits) 415352f7f91STakashi Iwai return true; 416352f7f91STakashi Iwai return false; 417352f7f91STakashi Iwai } 418352f7f91STakashi Iwai 419352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \ 420352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) 421352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \ 422352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) 423352f7f91STakashi Iwai 424352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */ 425352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, 426352f7f91STakashi Iwai struct nid_path *path) 427352f7f91STakashi Iwai { 428352f7f91STakashi Iwai int i; 429352f7f91STakashi Iwai 430352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 431352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) 432352f7f91STakashi Iwai return path->path[i]; 433352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 && 434352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT)) 435352f7f91STakashi Iwai return path->path[i]; 436352f7f91STakashi Iwai } 437352f7f91STakashi Iwai return 0; 438352f7f91STakashi Iwai } 439352f7f91STakashi Iwai 440352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */ 441352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, 442352f7f91STakashi Iwai struct nid_path *path) 443352f7f91STakashi Iwai { 444352f7f91STakashi Iwai int i; 445352f7f91STakashi Iwai 446352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 447352f7f91STakashi Iwai if (nid_has_volume(codec, path->path[i], HDA_OUTPUT)) 448352f7f91STakashi Iwai return path->path[i]; 449352f7f91STakashi Iwai } 450352f7f91STakashi Iwai return 0; 451352f7f91STakashi Iwai } 452352f7f91STakashi Iwai 453352f7f91STakashi Iwai /* 454352f7f91STakashi Iwai * path activation / deactivation 455352f7f91STakashi Iwai */ 456352f7f91STakashi Iwai 457352f7f91STakashi Iwai /* can have the amp-in capability? */ 458352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) 459352f7f91STakashi Iwai { 460352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 461352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 462352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 463352f7f91STakashi Iwai 464352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP)) 465352f7f91STakashi Iwai return false; 466352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */ 467352f7f91STakashi Iwai return false; 468352f7f91STakashi Iwai return true; 469352f7f91STakashi Iwai } 470352f7f91STakashi Iwai 471352f7f91STakashi Iwai /* can have the amp-out capability? */ 472352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) 473352f7f91STakashi Iwai { 474352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 475352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 476352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 477352f7f91STakashi Iwai 478352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP)) 479352f7f91STakashi Iwai return false; 480352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */ 481352f7f91STakashi Iwai return false; 482352f7f91STakashi Iwai return true; 483352f7f91STakashi Iwai } 484352f7f91STakashi Iwai 485352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */ 486352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, 487352f7f91STakashi Iwai unsigned int idx, unsigned int dir) 488352f7f91STakashi Iwai { 489352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 490352f7f91STakashi Iwai int i, n; 491352f7f91STakashi Iwai 492352f7f91STakashi Iwai for (n = 0; n < spec->paths.used; n++) { 493352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, n); 494352f7f91STakashi Iwai if (!path->active) 495352f7f91STakashi Iwai continue; 496352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) { 497352f7f91STakashi Iwai if (path->path[i] == nid) { 498352f7f91STakashi Iwai if (dir == HDA_OUTPUT || path->idx[i] == idx) 499352f7f91STakashi Iwai return true; 500352f7f91STakashi Iwai break; 501352f7f91STakashi Iwai } 502352f7f91STakashi Iwai } 503352f7f91STakashi Iwai } 504352f7f91STakashi Iwai return false; 505352f7f91STakashi Iwai } 506352f7f91STakashi Iwai 507352f7f91STakashi Iwai /* get the default amp value for the target state */ 508352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, 509352f7f91STakashi Iwai int dir, bool enable) 510352f7f91STakashi Iwai { 511352f7f91STakashi Iwai unsigned int caps; 512352f7f91STakashi Iwai unsigned int val = 0; 513352f7f91STakashi Iwai 514352f7f91STakashi Iwai caps = query_amp_caps(codec, nid, dir); 515352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 516352f7f91STakashi Iwai /* set to 0dB */ 517352f7f91STakashi Iwai if (enable) 518352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 519352f7f91STakashi Iwai } 520352f7f91STakashi Iwai if (caps & AC_AMPCAP_MUTE) { 521352f7f91STakashi Iwai if (!enable) 522352f7f91STakashi Iwai val |= HDA_AMP_MUTE; 523352f7f91STakashi Iwai } 524352f7f91STakashi Iwai return val; 525352f7f91STakashi Iwai } 526352f7f91STakashi Iwai 527352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */ 528352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 529352f7f91STakashi Iwai { 530352f7f91STakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, false); 531352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 532352f7f91STakashi Iwai } 533352f7f91STakashi Iwai 534352f7f91STakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, 535352f7f91STakashi Iwai int idx, bool enable) 536352f7f91STakashi Iwai { 537352f7f91STakashi Iwai int val; 538352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, dir, idx) || 539985803caSTakashi Iwai (!enable && is_active_nid(codec, nid, dir, idx))) 540352f7f91STakashi Iwai return; 541352f7f91STakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, enable); 542352f7f91STakashi Iwai snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val); 543352f7f91STakashi Iwai } 544352f7f91STakashi Iwai 545352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, 546352f7f91STakashi Iwai int i, bool enable) 547352f7f91STakashi Iwai { 548352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 549352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0); 550352f7f91STakashi Iwai activate_amp(codec, nid, HDA_OUTPUT, 0, enable); 551352f7f91STakashi Iwai } 552352f7f91STakashi Iwai 553352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, 554352f7f91STakashi Iwai int i, bool enable, bool add_aamix) 555352f7f91STakashi Iwai { 556352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 557ee8e765bSTakashi Iwai const hda_nid_t *conn; 558352f7f91STakashi Iwai int n, nums, idx; 559352f7f91STakashi Iwai int type; 560352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 561352f7f91STakashi Iwai 562ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn); 563352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 564352f7f91STakashi Iwai if (type == AC_WID_PIN || 565352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) { 566352f7f91STakashi Iwai nums = 1; 567352f7f91STakashi Iwai idx = 0; 568352f7f91STakashi Iwai } else 569352f7f91STakashi Iwai idx = path->idx[i]; 570352f7f91STakashi Iwai 571352f7f91STakashi Iwai for (n = 0; n < nums; n++) 572352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n); 573352f7f91STakashi Iwai 574352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, HDA_INPUT, idx)) 575352f7f91STakashi Iwai return; 576352f7f91STakashi Iwai 577352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out(); 578352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well 579352f7f91STakashi Iwai */ 580352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 581352f7f91STakashi Iwai if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid)) 582352f7f91STakashi Iwai continue; 583352f7f91STakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, enable); 584352f7f91STakashi Iwai } 585352f7f91STakashi Iwai } 586352f7f91STakashi Iwai 587352f7f91STakashi Iwai /* activate or deactivate the given path 588352f7f91STakashi Iwai * if @add_aamix is set, enable the input from aa-mix NID as well (if any) 589352f7f91STakashi Iwai */ 590352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, 591352f7f91STakashi Iwai bool enable, bool add_aamix) 592352f7f91STakashi Iwai { 593352f7f91STakashi Iwai int i; 594352f7f91STakashi Iwai 595352f7f91STakashi Iwai if (!enable) 596352f7f91STakashi Iwai path->active = false; 597352f7f91STakashi Iwai 598352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 599352f7f91STakashi Iwai if (enable && path->multi[i]) 600352f7f91STakashi Iwai snd_hda_codec_write_cache(codec, path->path[i], 0, 601352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL, 602352f7f91STakashi Iwai path->idx[i]); 603352f7f91STakashi Iwai if (has_amp_in(codec, path, i)) 604352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix); 605352f7f91STakashi Iwai if (has_amp_out(codec, path, i)) 606352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable); 607352f7f91STakashi Iwai } 608352f7f91STakashi Iwai 609352f7f91STakashi Iwai if (enable) 610352f7f91STakashi Iwai path->active = true; 611352f7f91STakashi Iwai } 612352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path); 613352f7f91STakashi Iwai 614d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */ 615d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) 616d5a9f1bbSTakashi Iwai { 617d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 618d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl || 619d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) 620d5a9f1bbSTakashi Iwai return; 621ecac3ed1STakashi Iwai if (codec->inv_eapd) 622ecac3ed1STakashi Iwai enable = !enable; 623d5a9f1bbSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 624d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE, 625d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00); 626d5a9f1bbSTakashi Iwai } 627d5a9f1bbSTakashi Iwai 628352f7f91STakashi Iwai 629352f7f91STakashi Iwai /* 630352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements 631352f7f91STakashi Iwai */ 632352f7f91STakashi Iwai 633352f7f91STakashi Iwai enum { 634352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL, 635352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE, 636352f7f91STakashi Iwai HDA_CTL_BIND_MUTE, 637352f7f91STakashi Iwai }; 638352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = { 639352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0), 640352f7f91STakashi Iwai HDA_CODEC_MUTE(NULL, 0, 0, 0), 641352f7f91STakashi Iwai HDA_BIND_MUTE(NULL, 0, 0, 0), 642352f7f91STakashi Iwai }; 643352f7f91STakashi Iwai 644352f7f91STakashi Iwai /* add dynamic controls from template */ 645352f7f91STakashi Iwai static int add_control(struct hda_gen_spec *spec, int type, const char *name, 646352f7f91STakashi Iwai int cidx, unsigned long val) 647352f7f91STakashi Iwai { 648352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 649352f7f91STakashi Iwai 65012c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); 651352f7f91STakashi Iwai if (!knew) 652352f7f91STakashi Iwai return -ENOMEM; 653352f7f91STakashi Iwai knew->index = cidx; 654352f7f91STakashi Iwai if (get_amp_nid_(val)) 655352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 656352f7f91STakashi Iwai knew->private_value = val; 657352f7f91STakashi Iwai return 0; 658352f7f91STakashi Iwai } 659352f7f91STakashi Iwai 660352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type, 661352f7f91STakashi Iwai const char *pfx, const char *dir, 662352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val) 663352f7f91STakashi Iwai { 664352f7f91STakashi Iwai char name[32]; 665352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 666352f7f91STakashi Iwai return add_control(spec, type, name, cidx, val); 667352f7f91STakashi Iwai } 668352f7f91STakashi Iwai 669352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \ 670352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) 671352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \ 672352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) 673352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ 674352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) 675352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 676352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 677352f7f91STakashi Iwai 678352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, 679352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 680352f7f91STakashi Iwai { 681352f7f91STakashi Iwai unsigned int val; 682352f7f91STakashi Iwai if (!path) 683352f7f91STakashi Iwai return 0; 684352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL]; 685352f7f91STakashi Iwai if (!val) 686352f7f91STakashi Iwai return 0; 687352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 688352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); 689352f7f91STakashi Iwai } 690352f7f91STakashi Iwai 691352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */ 692352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, 693352f7f91STakashi Iwai int type) 694352f7f91STakashi Iwai { 695352f7f91STakashi Iwai int chs = 1; /* mono (left only) */ 696352f7f91STakashi Iwai if (path) { 697352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]); 698352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) 699352f7f91STakashi Iwai chs = 3; /* stereo */ 700352f7f91STakashi Iwai } 701352f7f91STakashi Iwai return chs; 702352f7f91STakashi Iwai } 703352f7f91STakashi Iwai 704352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, 705352f7f91STakashi Iwai struct nid_path *path) 706352f7f91STakashi Iwai { 707352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); 708352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path); 709352f7f91STakashi Iwai } 710352f7f91STakashi Iwai 711352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget; 712352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute 713352f7f91STakashi Iwai */ 714352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, 715352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 716352f7f91STakashi Iwai { 717352f7f91STakashi Iwai unsigned int val; 718352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE; 719352f7f91STakashi Iwai 720352f7f91STakashi Iwai if (!path) 721352f7f91STakashi Iwai return 0; 722352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL]; 723352f7f91STakashi Iwai if (!val) 724352f7f91STakashi Iwai return 0; 725352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 726352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) { 727352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val); 728352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid); 729352f7f91STakashi Iwai if (nums > 1) { 730352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE; 731352f7f91STakashi Iwai val |= nums << 19; 732352f7f91STakashi Iwai } 733352f7f91STakashi Iwai } 734352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 735352f7f91STakashi Iwai } 736352f7f91STakashi Iwai 737352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx, 738352f7f91STakashi Iwai int cidx, struct nid_path *path) 739352f7f91STakashi Iwai { 740352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); 741352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path); 742352f7f91STakashi Iwai } 743352f7f91STakashi Iwai 744352f7f91STakashi Iwai static const char * const channel_name[4] = { 745352f7f91STakashi Iwai "Front", "Surround", "CLFE", "Side" 746352f7f91STakashi Iwai }; 747352f7f91STakashi Iwai 748352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */ 749352f7f91STakashi Iwai static const char *get_line_out_pfx(struct hda_gen_spec *spec, int ch, 750352f7f91STakashi Iwai bool can_be_master, int *index) 751352f7f91STakashi Iwai { 752352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 753352f7f91STakashi Iwai 754352f7f91STakashi Iwai *index = 0; 755352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios && 756352f7f91STakashi Iwai !cfg->hp_outs && !cfg->speaker_outs && can_be_master) 757352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 758352f7f91STakashi Iwai 759352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths, 760352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present) 761352f7f91STakashi Iwai */ 762352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && 763352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) 764352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 765352f7f91STakashi Iwai 766352f7f91STakashi Iwai switch (cfg->line_out_type) { 767352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT: 768352f7f91STakashi Iwai if (cfg->line_outs == 1) 769352f7f91STakashi Iwai return "Speaker"; 770352f7f91STakashi Iwai if (cfg->line_outs == 2) 771352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker"; 772352f7f91STakashi Iwai break; 773352f7f91STakashi Iwai case AUTO_PIN_HP_OUT: 774352f7f91STakashi Iwai /* for multi-io case, only the primary out */ 775352f7f91STakashi Iwai if (ch && spec->multi_ios) 776352f7f91STakashi Iwai break; 777352f7f91STakashi Iwai *index = ch; 778352f7f91STakashi Iwai return "Headphone"; 779352f7f91STakashi Iwai default: 780352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios) 781352f7f91STakashi Iwai return "PCM"; 782352f7f91STakashi Iwai break; 783352f7f91STakashi Iwai } 784352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) { 785352f7f91STakashi Iwai snd_BUG(); 786352f7f91STakashi Iwai return "PCM"; 787352f7f91STakashi Iwai } 788352f7f91STakashi Iwai 789352f7f91STakashi Iwai return channel_name[ch]; 790352f7f91STakashi Iwai } 791352f7f91STakashi Iwai 792352f7f91STakashi Iwai /* 793352f7f91STakashi Iwai * Parse output paths 794352f7f91STakashi Iwai */ 795352f7f91STakashi Iwai 796352f7f91STakashi Iwai /* badness definition */ 797352f7f91STakashi Iwai enum { 798352f7f91STakashi Iwai /* No primary DAC is found for the main output */ 799352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000, 800352f7f91STakashi Iwai /* No DAC is found for the extra output */ 801352f7f91STakashi Iwai BAD_NO_DAC = 0x4000, 802352f7f91STakashi Iwai /* No possible multi-ios */ 803352f7f91STakashi Iwai BAD_MULTI_IO = 0x103, 804352f7f91STakashi Iwai /* No individual DAC for extra output */ 805352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102, 806352f7f91STakashi Iwai /* No individual DAC for extra surrounds */ 807352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101, 808352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */ 809352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100, 810352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */ 811352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10, 812352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */ 813352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10, 814352f7f91STakashi Iwai /* Volume widget is shared */ 815352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10, 816352f7f91STakashi Iwai }; 817352f7f91STakashi Iwai 8180e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for 819352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[]. 820352f7f91STakashi Iwai * 821352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value 822352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the 823352f7f91STakashi Iwai * total badness for both volume and mute controls. 824352f7f91STakashi Iwai */ 8250e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) 826352f7f91STakashi Iwai { 827352f7f91STakashi Iwai hda_nid_t nid; 828352f7f91STakashi Iwai unsigned int val; 829352f7f91STakashi Iwai int badness = 0; 830352f7f91STakashi Iwai 831352f7f91STakashi Iwai if (!path) 832352f7f91STakashi Iwai return BAD_SHARED_VOL * 2; 8330e614dd0STakashi Iwai 8340e614dd0STakashi Iwai if (path->ctls[NID_PATH_VOL_CTL] || 8350e614dd0STakashi Iwai path->ctls[NID_PATH_MUTE_CTL]) 8360e614dd0STakashi Iwai return 0; /* already evaluated */ 8370e614dd0STakashi Iwai 838352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path); 839352f7f91STakashi Iwai if (nid) { 840352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 841352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) 842352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 843352f7f91STakashi Iwai else 844352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 845352f7f91STakashi Iwai } else 846352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 847352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path); 848352f7f91STakashi Iwai if (nid) { 849352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); 850352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || 851352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT)) 852352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 853352f7f91STakashi Iwai else 854352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 855352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) 856352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 857352f7f91STakashi Iwai else 858352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 859352f7f91STakashi Iwai } else 860352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 861352f7f91STakashi Iwai return badness; 862352f7f91STakashi Iwai } 863352f7f91STakashi Iwai 864352f7f91STakashi Iwai struct badness_table { 865352f7f91STakashi Iwai int no_primary_dac; /* no primary DAC */ 866352f7f91STakashi Iwai int no_dac; /* no secondary DACs */ 867352f7f91STakashi Iwai int shared_primary; /* primary DAC is shared with main output */ 868352f7f91STakashi Iwai int shared_surr; /* secondary DAC shared with main or primary */ 869352f7f91STakashi Iwai int shared_clfe; /* third DAC shared with main or primary */ 870352f7f91STakashi Iwai int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ 871352f7f91STakashi Iwai }; 872352f7f91STakashi Iwai 873352f7f91STakashi Iwai static struct badness_table main_out_badness = { 874352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC, 875352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 876352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC, 877352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND, 878352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE, 879352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND, 880352f7f91STakashi Iwai }; 881352f7f91STakashi Iwai 882352f7f91STakashi Iwai static struct badness_table extra_out_badness = { 883352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC, 884352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 885352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC, 886352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND, 887352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND, 888352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, 889352f7f91STakashi Iwai }; 890352f7f91STakashi Iwai 8917385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */ 8927385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) 8937385df61STakashi Iwai { 8947385df61STakashi Iwai struct hda_gen_spec *spec = codec->spec; 8957385df61STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 8967385df61STakashi Iwai 8977385df61STakashi Iwai if (cfg->line_outs > idx) 8987385df61STakashi Iwai return spec->private_dac_nids[idx]; 8997385df61STakashi Iwai idx -= cfg->line_outs; 9007385df61STakashi Iwai if (spec->multi_ios > idx) 9017385df61STakashi Iwai return spec->multi_io[idx].dac; 9027385df61STakashi Iwai return 0; 9037385df61STakashi Iwai } 9047385df61STakashi Iwai 9057385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */ 9067385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec, 9077385df61STakashi Iwai hda_nid_t dac, hda_nid_t pin) 9087385df61STakashi Iwai { 9097385df61STakashi Iwai return is_reachable_path(codec, dac, pin) ? dac : 0; 9107385df61STakashi Iwai } 9117385df61STakashi Iwai 912352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */ 913352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs, 914352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, 915196c1766STakashi Iwai int *path_idx, 916352f7f91STakashi Iwai const struct badness_table *bad) 917352f7f91STakashi Iwai { 918352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 919352f7f91STakashi Iwai int i, j; 920352f7f91STakashi Iwai int badness = 0; 921352f7f91STakashi Iwai hda_nid_t dac; 922352f7f91STakashi Iwai 923352f7f91STakashi Iwai if (!num_outs) 924352f7f91STakashi Iwai return 0; 925352f7f91STakashi Iwai 926352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) { 9270c8c0f56STakashi Iwai struct nid_path *path; 928352f7f91STakashi Iwai hda_nid_t pin = pins[i]; 9291e0b5286STakashi Iwai 9300e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 9310e614dd0STakashi Iwai if (path) { 9320e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 9331e0b5286STakashi Iwai continue; 9341e0b5286STakashi Iwai } 9351e0b5286STakashi Iwai 936352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false); 937352f7f91STakashi Iwai if (!dacs[i] && !i) { 938980428ceSTakashi Iwai /* try to steal the DAC of surrounds for the front */ 939352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) { 940352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) { 941352f7f91STakashi Iwai dacs[0] = dacs[j]; 942352f7f91STakashi Iwai dacs[j] = 0; 943980428ceSTakashi Iwai invalidate_nid_path(codec, path_idx[j]); 944196c1766STakashi Iwai path_idx[j] = 0; 945352f7f91STakashi Iwai break; 946352f7f91STakashi Iwai } 947352f7f91STakashi Iwai } 948352f7f91STakashi Iwai } 949352f7f91STakashi Iwai dac = dacs[i]; 950352f7f91STakashi Iwai if (!dac) { 9517385df61STakashi Iwai if (num_outs > 2) 9527385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 9537385df61STakashi Iwai if (!dac) 9547385df61STakashi Iwai dac = try_dac(codec, dacs[0], pin); 9557385df61STakashi Iwai if (!dac) 9567385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 957352f7f91STakashi Iwai if (dac) { 958352f7f91STakashi Iwai if (!i) 959352f7f91STakashi Iwai badness += bad->shared_primary; 960352f7f91STakashi Iwai else if (i == 1) 961352f7f91STakashi Iwai badness += bad->shared_surr; 962352f7f91STakashi Iwai else 963352f7f91STakashi Iwai badness += bad->shared_clfe; 964352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { 965352f7f91STakashi Iwai dac = spec->private_dac_nids[0]; 966352f7f91STakashi Iwai badness += bad->shared_surr_main; 967352f7f91STakashi Iwai } else if (!i) 968352f7f91STakashi Iwai badness += bad->no_primary_dac; 969352f7f91STakashi Iwai else 970352f7f91STakashi Iwai badness += bad->no_dac; 971352f7f91STakashi Iwai } 9723ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid); 973117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) { 974b3a8c745STakashi Iwai /* try with aamix */ 9753ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 0); 976b3a8c745STakashi Iwai } 9770c8c0f56STakashi Iwai if (!path) 978352f7f91STakashi Iwai dac = dacs[i] = 0; 979e1284af7STakashi Iwai else { 9800c8c0f56STakashi Iwai print_nid_path("output", path); 981e1284af7STakashi Iwai path->active = true; 982196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 9830e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 984e1284af7STakashi Iwai } 985352f7f91STakashi Iwai } 986352f7f91STakashi Iwai 987352f7f91STakashi Iwai return badness; 988352f7f91STakashi Iwai } 989352f7f91STakashi Iwai 990352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */ 991352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 992352f7f91STakashi Iwai { 993352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 994352f7f91STakashi Iwai int i; 995352f7f91STakashi Iwai hda_nid_t nid_found = 0; 996352f7f91STakashi Iwai 997352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 998352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 999352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 1000352f7f91STakashi Iwai continue; 1001352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) { 1002352f7f91STakashi Iwai if (nid_found) 1003352f7f91STakashi Iwai return 0; 1004352f7f91STakashi Iwai nid_found = nid; 1005352f7f91STakashi Iwai } 1006352f7f91STakashi Iwai } 1007352f7f91STakashi Iwai return nid_found; 1008352f7f91STakashi Iwai } 1009352f7f91STakashi Iwai 1010352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */ 1011352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec, 1012352f7f91STakashi Iwai unsigned int location, hda_nid_t nid) 1013352f7f91STakashi Iwai { 1014352f7f91STakashi Iwai unsigned int defcfg, caps; 1015352f7f91STakashi Iwai 1016352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid); 1017352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) 1018352f7f91STakashi Iwai return false; 1019352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location) 1020352f7f91STakashi Iwai return false; 1021352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid); 1022352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT)) 1023352f7f91STakashi Iwai return false; 1024352f7f91STakashi Iwai return true; 1025352f7f91STakashi Iwai } 1026352f7f91STakashi Iwai 1027e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */ 1028e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) 1029e22aab7dSTakashi Iwai { 1030e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1031e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1032e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1033e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1034e22aab7dSTakashi Iwai int type, i; 1035e22aab7dSTakashi Iwai int num_pins = 0; 1036e22aab7dSTakashi Iwai 1037e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1038e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1039e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type) 1040e22aab7dSTakashi Iwai continue; 1041e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location, 1042e22aab7dSTakashi Iwai cfg->inputs[i].pin)) 1043e22aab7dSTakashi Iwai num_pins++; 1044e22aab7dSTakashi Iwai } 1045e22aab7dSTakashi Iwai } 1046e22aab7dSTakashi Iwai return num_pins; 1047e22aab7dSTakashi Iwai } 1048e22aab7dSTakashi Iwai 1049352f7f91STakashi Iwai /* 1050352f7f91STakashi Iwai * multi-io helper 1051352f7f91STakashi Iwai * 1052352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns 1053352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found. 1054352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns 1055352f7f91STakashi Iwai * the badness value. 1056352f7f91STakashi Iwai */ 1057352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec, 1058352f7f91STakashi Iwai hda_nid_t reference_pin, 1059e22aab7dSTakashi Iwai bool hardwired) 1060352f7f91STakashi Iwai { 1061352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1062352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1063e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins; 1064352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1065352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1066352f7f91STakashi Iwai int badness = 0; 10670e614dd0STakashi Iwai struct nid_path *path; 1068352f7f91STakashi Iwai 1069352f7f91STakashi Iwai old_pins = spec->multi_ios; 1070352f7f91STakashi Iwai if (old_pins >= 2) 1071352f7f91STakashi Iwai goto end_fill; 1072352f7f91STakashi Iwai 1073e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin); 1074352f7f91STakashi Iwai if (num_pins < 2) 1075352f7f91STakashi Iwai goto end_fill; 1076352f7f91STakashi Iwai 1077352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1078352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1079352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 1080352f7f91STakashi Iwai hda_nid_t dac = 0; 1081352f7f91STakashi Iwai 1082352f7f91STakashi Iwai if (cfg->inputs[i].type != type) 1083352f7f91STakashi Iwai continue; 1084352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid)) 1085352f7f91STakashi Iwai continue; 1086352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) { 1087352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin) 1088352f7f91STakashi Iwai break; 1089352f7f91STakashi Iwai } 1090352f7f91STakashi Iwai if (j < spec->multi_ios) 1091352f7f91STakashi Iwai continue; 1092352f7f91STakashi Iwai 1093352f7f91STakashi Iwai if (hardwired) 1094352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid); 1095352f7f91STakashi Iwai else if (!dac) 1096352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false); 1097352f7f91STakashi Iwai if (!dac) { 1098352f7f91STakashi Iwai badness++; 1099352f7f91STakashi Iwai continue; 1100352f7f91STakashi Iwai } 11013ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, nid, 11023ca529d3STakashi Iwai -spec->mixer_nid); 11030c8c0f56STakashi Iwai if (!path) { 1104352f7f91STakashi Iwai badness++; 1105352f7f91STakashi Iwai continue; 1106352f7f91STakashi Iwai } 11070c8c0f56STakashi Iwai print_nid_path("multiio", path); 1108352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid; 1109352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac; 1110196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] = 1111196c1766STakashi Iwai snd_hda_get_path_idx(codec, path); 1112352f7f91STakashi Iwai spec->multi_ios++; 1113352f7f91STakashi Iwai if (spec->multi_ios >= 2) 1114352f7f91STakashi Iwai break; 1115352f7f91STakashi Iwai } 1116352f7f91STakashi Iwai } 1117352f7f91STakashi Iwai end_fill: 1118352f7f91STakashi Iwai if (badness) 1119352f7f91STakashi Iwai badness = BAD_MULTI_IO; 1120352f7f91STakashi Iwai if (old_pins == spec->multi_ios) { 1121352f7f91STakashi Iwai if (hardwired) 1122352f7f91STakashi Iwai return 1; /* nothing found */ 1123352f7f91STakashi Iwai else 1124352f7f91STakashi Iwai return badness; /* no badness if nothing found */ 1125352f7f91STakashi Iwai } 1126352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) { 1127352f7f91STakashi Iwai /* cancel newly assigned paths */ 1128352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins; 1129352f7f91STakashi Iwai spec->multi_ios = old_pins; 1130352f7f91STakashi Iwai return badness; 1131352f7f91STakashi Iwai } 1132352f7f91STakashi Iwai 1133352f7f91STakashi Iwai /* assign volume and mute controls */ 11340e614dd0STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) { 11350e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]); 11360e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 11370e614dd0STakashi Iwai } 1138352f7f91STakashi Iwai 1139352f7f91STakashi Iwai return badness; 1140352f7f91STakashi Iwai } 1141352f7f91STakashi Iwai 1142352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */ 1143352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs, 1144196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) 1145352f7f91STakashi Iwai { 1146b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1147352f7f91STakashi Iwai int i; 1148352f7f91STakashi Iwai bool found = false; 1149352f7f91STakashi Iwai for (i = 0; i < outs; i++) { 11500c8c0f56STakashi Iwai struct nid_path *path; 1151352f7f91STakashi Iwai hda_nid_t dac; 1152352f7f91STakashi Iwai if (dacs[i]) 1153352f7f91STakashi Iwai continue; 1154352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]); 1155352f7f91STakashi Iwai if (!dac) 1156352f7f91STakashi Iwai continue; 11573ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 11583ca529d3STakashi Iwai -spec->mixer_nid); 1159117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) 11603ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 0); 11610c8c0f56STakashi Iwai if (path) { 1162352f7f91STakashi Iwai dacs[i] = dac; 1163352f7f91STakashi Iwai found = true; 11640c8c0f56STakashi Iwai print_nid_path("output", path); 1165e1284af7STakashi Iwai path->active = true; 1166196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 1167352f7f91STakashi Iwai } 1168352f7f91STakashi Iwai } 1169352f7f91STakashi Iwai return found; 1170352f7f91STakashi Iwai } 1171352f7f91STakashi Iwai 1172c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */ 1173c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx) 1174c30aa7b2STakashi Iwai { 11753ca529d3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1176c30aa7b2STakashi Iwai struct nid_path *path; 1177c30aa7b2STakashi Iwai 1178c30aa7b2STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 11793ca529d3STakashi Iwai if (!path || !path->depth || 11803ca529d3STakashi Iwai is_nid_contained(path, spec->mixer_nid)) 1181c30aa7b2STakashi Iwai return 0; 1182c30aa7b2STakashi Iwai path = snd_hda_add_new_path(codec, path->path[0], 1183c30aa7b2STakashi Iwai path->path[path->depth - 1], 11843ca529d3STakashi Iwai spec->mixer_nid); 1185c30aa7b2STakashi Iwai if (!path) 1186c30aa7b2STakashi Iwai return 0; 1187c30aa7b2STakashi Iwai print_nid_path("output-aamix", path); 1188c30aa7b2STakashi Iwai path->active = false; /* unused as default */ 1189c30aa7b2STakashi Iwai return snd_hda_get_path_idx(codec, path); 1190c30aa7b2STakashi Iwai } 1191c30aa7b2STakashi Iwai 1192a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the 1193a07a949bSTakashi Iwai * shared dac pointed by the paths 1194a07a949bSTakashi Iwai */ 1195a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs, 1196a07a949bSTakashi Iwai hda_nid_t *dacs, int *path_idx) 1197a07a949bSTakashi Iwai { 1198a07a949bSTakashi Iwai struct nid_path *path; 1199a07a949bSTakashi Iwai int i; 1200a07a949bSTakashi Iwai 1201a07a949bSTakashi Iwai for (i = 0; i < num_outs; i++) { 1202a07a949bSTakashi Iwai if (dacs[i]) 1203a07a949bSTakashi Iwai continue; 1204a07a949bSTakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 1205a07a949bSTakashi Iwai if (!path) 1206a07a949bSTakashi Iwai continue; 1207a07a949bSTakashi Iwai dacs[i] = path->path[0]; 1208a07a949bSTakashi Iwai } 1209a07a949bSTakashi Iwai } 1210a07a949bSTakashi Iwai 1211352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */ 1212352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec, 1213352f7f91STakashi Iwai bool fill_hardwired, 1214352f7f91STakashi Iwai bool fill_mio_first) 1215352f7f91STakashi Iwai { 1216352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1217352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1218352f7f91STakashi Iwai int i, err, badness; 1219352f7f91STakashi Iwai 1220352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */ 1221352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs; 1222352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids; 1223352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); 1224352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 1225352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 1226352f7f91STakashi Iwai spec->multi_ios = 0; 1227352f7f91STakashi Iwai snd_array_free(&spec->paths); 1228cd5be3f9STakashi Iwai 1229cd5be3f9STakashi Iwai /* clear path indices */ 1230cd5be3f9STakashi Iwai memset(spec->out_paths, 0, sizeof(spec->out_paths)); 1231cd5be3f9STakashi Iwai memset(spec->hp_paths, 0, sizeof(spec->hp_paths)); 1232cd5be3f9STakashi Iwai memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths)); 1233cd5be3f9STakashi Iwai memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths)); 1234cd5be3f9STakashi Iwai memset(spec->digout_paths, 0, sizeof(spec->digout_paths)); 1235c697b716STakashi Iwai memset(spec->input_paths, 0, sizeof(spec->input_paths)); 1236cd5be3f9STakashi Iwai memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths)); 1237cd5be3f9STakashi Iwai memset(&spec->digin_path, 0, sizeof(spec->digin_path)); 1238cd5be3f9STakashi Iwai 1239352f7f91STakashi Iwai badness = 0; 1240352f7f91STakashi Iwai 1241352f7f91STakashi Iwai /* fill hard-wired DACs first */ 1242352f7f91STakashi Iwai if (fill_hardwired) { 1243352f7f91STakashi Iwai bool mapped; 1244352f7f91STakashi Iwai do { 1245352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs, 1246352f7f91STakashi Iwai cfg->line_out_pins, 1247196c1766STakashi Iwai spec->private_dac_nids, 1248196c1766STakashi Iwai spec->out_paths); 1249352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs, 1250352f7f91STakashi Iwai cfg->hp_pins, 1251196c1766STakashi Iwai spec->multiout.hp_out_nid, 1252196c1766STakashi Iwai spec->hp_paths); 1253352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs, 1254352f7f91STakashi Iwai cfg->speaker_pins, 1255196c1766STakashi Iwai spec->multiout.extra_out_nid, 1256196c1766STakashi Iwai spec->speaker_paths); 1257352f7f91STakashi Iwai if (fill_mio_first && cfg->line_outs == 1 && 1258352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1259e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true); 1260352f7f91STakashi Iwai if (!err) 1261352f7f91STakashi Iwai mapped = true; 1262352f7f91STakashi Iwai } 1263352f7f91STakashi Iwai } while (mapped); 1264352f7f91STakashi Iwai } 1265352f7f91STakashi Iwai 1266352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, 1267196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths, 1268352f7f91STakashi Iwai &main_out_badness); 1269352f7f91STakashi Iwai 1270352f7f91STakashi Iwai if (fill_mio_first && 1271352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1272352f7f91STakashi Iwai /* try to fill multi-io first */ 1273e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1274352f7f91STakashi Iwai if (err < 0) 1275352f7f91STakashi Iwai return err; 1276352f7f91STakashi Iwai /* we don't count badness at this stage yet */ 1277352f7f91STakashi Iwai } 1278352f7f91STakashi Iwai 1279352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 1280352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, 1281352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1282196c1766STakashi Iwai spec->hp_paths, 1283352f7f91STakashi Iwai &extra_out_badness); 1284352f7f91STakashi Iwai if (err < 0) 1285352f7f91STakashi Iwai return err; 1286352f7f91STakashi Iwai badness += err; 1287352f7f91STakashi Iwai } 1288352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1289352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs, 1290352f7f91STakashi Iwai cfg->speaker_pins, 1291352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1292196c1766STakashi Iwai spec->speaker_paths, 1293352f7f91STakashi Iwai &extra_out_badness); 1294352f7f91STakashi Iwai if (err < 0) 1295352f7f91STakashi Iwai return err; 1296352f7f91STakashi Iwai badness += err; 1297352f7f91STakashi Iwai } 1298352f7f91STakashi Iwai if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1299e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1300352f7f91STakashi Iwai if (err < 0) 1301352f7f91STakashi Iwai return err; 1302352f7f91STakashi Iwai badness += err; 1303352f7f91STakashi Iwai } 1304e22aab7dSTakashi Iwai 1305c30aa7b2STakashi Iwai if (spec->mixer_nid) { 1306c30aa7b2STakashi Iwai spec->aamix_out_paths[0] = 1307c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->out_paths[0]); 1308c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1309c30aa7b2STakashi Iwai spec->aamix_out_paths[1] = 1310c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->hp_paths[0]); 1311c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1312c30aa7b2STakashi Iwai spec->aamix_out_paths[2] = 1313c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->speaker_paths[0]); 1314c30aa7b2STakashi Iwai } 1315c30aa7b2STakashi Iwai 1316e22aab7dSTakashi Iwai if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1317e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1318e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */ 1319352f7f91STakashi Iwai 1320a07a949bSTakashi Iwai /* re-count num_dacs and squash invalid entries */ 1321a07a949bSTakashi Iwai spec->multiout.num_dacs = 0; 1322a07a949bSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 1323a07a949bSTakashi Iwai if (spec->private_dac_nids[i]) 1324a07a949bSTakashi Iwai spec->multiout.num_dacs++; 1325a07a949bSTakashi Iwai else { 1326a07a949bSTakashi Iwai memmove(spec->private_dac_nids + i, 1327a07a949bSTakashi Iwai spec->private_dac_nids + i + 1, 1328a07a949bSTakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); 1329a07a949bSTakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0; 1330a07a949bSTakashi Iwai } 1331a07a949bSTakashi Iwai } 1332a07a949bSTakashi Iwai 1333a07a949bSTakashi Iwai spec->ext_channel_count = spec->min_channel_count = 1334a07a949bSTakashi Iwai spec->multiout.num_dacs; 1335a07a949bSTakashi Iwai 1336352f7f91STakashi Iwai if (spec->multi_ios == 2) { 1337352f7f91STakashi Iwai for (i = 0; i < 2; i++) 1338352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] = 1339352f7f91STakashi Iwai spec->multi_io[i].dac; 1340352f7f91STakashi Iwai } else if (spec->multi_ios) { 1341352f7f91STakashi Iwai spec->multi_ios = 0; 1342352f7f91STakashi Iwai badness += BAD_MULTI_IO; 1343352f7f91STakashi Iwai } 1344352f7f91STakashi Iwai 1345a07a949bSTakashi Iwai /* re-fill the shared DAC for speaker / headphone */ 1346a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1347a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->hp_outs, 1348a07a949bSTakashi Iwai spec->multiout.hp_out_nid, 1349a07a949bSTakashi Iwai spec->hp_paths); 1350a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1351a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->speaker_outs, 1352a07a949bSTakashi Iwai spec->multiout.extra_out_nid, 1353a07a949bSTakashi Iwai spec->speaker_paths); 1354a07a949bSTakashi Iwai 13552c12c30dSTakashi Iwai /* set initial pinctl targets */ 13562c12c30dSTakashi Iwai set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, 13572c12c30dSTakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT ? PIN_HP : PIN_OUT); 13582c12c30dSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 13592c12c30dSTakashi Iwai set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP); 13602c12c30dSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 13612c12c30dSTakashi Iwai set_pin_targets(codec, cfg->speaker_outs, 13622c12c30dSTakashi Iwai cfg->speaker_pins, PIN_OUT); 13632c12c30dSTakashi Iwai 1364352f7f91STakashi Iwai return badness; 1365352f7f91STakashi Iwai } 1366352f7f91STakashi Iwai 1367352f7f91STakashi Iwai #define DEBUG_BADNESS 1368352f7f91STakashi Iwai 1369352f7f91STakashi Iwai #ifdef DEBUG_BADNESS 1370352f7f91STakashi Iwai #define debug_badness snd_printdd 1371352f7f91STakashi Iwai #else 1372352f7f91STakashi Iwai #define debug_badness(...) 1373352f7f91STakashi Iwai #endif 1374352f7f91STakashi Iwai 1375352f7f91STakashi Iwai static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg) 1376352f7f91STakashi Iwai { 1377352f7f91STakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1378352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1], 1379708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 1380352f7f91STakashi Iwai spec->multiout.dac_nids[0], 1381352f7f91STakashi Iwai spec->multiout.dac_nids[1], 1382352f7f91STakashi Iwai spec->multiout.dac_nids[2], 1383352f7f91STakashi Iwai spec->multiout.dac_nids[3]); 1384352f7f91STakashi Iwai if (spec->multi_ios > 0) 1385352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", 1386352f7f91STakashi Iwai spec->multi_ios, 1387352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin, 1388352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac); 1389352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1390352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1], 1391708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3], 1392352f7f91STakashi Iwai spec->multiout.hp_out_nid[0], 1393352f7f91STakashi Iwai spec->multiout.hp_out_nid[1], 1394352f7f91STakashi Iwai spec->multiout.hp_out_nid[2], 1395352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]); 1396352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1397352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1], 1398352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3], 1399352f7f91STakashi Iwai spec->multiout.extra_out_nid[0], 1400352f7f91STakashi Iwai spec->multiout.extra_out_nid[1], 1401352f7f91STakashi Iwai spec->multiout.extra_out_nid[2], 1402352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]); 1403352f7f91STakashi Iwai } 1404352f7f91STakashi Iwai 1405352f7f91STakashi Iwai /* find all available DACs of the codec */ 1406352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec) 1407352f7f91STakashi Iwai { 1408352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1409352f7f91STakashi Iwai int i; 1410352f7f91STakashi Iwai hda_nid_t nid = codec->start_nid; 1411352f7f91STakashi Iwai 1412352f7f91STakashi Iwai spec->num_all_dacs = 0; 1413352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); 1414352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 1415352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) 1416352f7f91STakashi Iwai continue; 1417352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { 1418352f7f91STakashi Iwai snd_printk(KERN_ERR "hda: Too many DACs!\n"); 1419352f7f91STakashi Iwai break; 1420352f7f91STakashi Iwai } 1421352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid; 1422352f7f91STakashi Iwai } 1423352f7f91STakashi Iwai } 1424352f7f91STakashi Iwai 1425352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec) 1426352f7f91STakashi Iwai { 1427352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1428352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1429352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg; 1430352f7f91STakashi Iwai int best_badness = INT_MAX; 1431352f7f91STakashi Iwai int badness; 1432352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true; 1433352f7f91STakashi Iwai bool best_wired = true, best_mio = true; 1434352f7f91STakashi Iwai bool hp_spk_swapped = false; 1435352f7f91STakashi Iwai 1436352f7f91STakashi Iwai fill_all_dac_nids(codec); 1437352f7f91STakashi Iwai 1438352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); 1439352f7f91STakashi Iwai if (!best_cfg) 1440352f7f91STakashi Iwai return -ENOMEM; 1441352f7f91STakashi Iwai *best_cfg = *cfg; 1442352f7f91STakashi Iwai 1443352f7f91STakashi Iwai for (;;) { 1444352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired, 1445352f7f91STakashi Iwai fill_mio_first); 1446352f7f91STakashi Iwai if (badness < 0) { 1447352f7f91STakashi Iwai kfree(best_cfg); 1448352f7f91STakashi Iwai return badness; 1449352f7f91STakashi Iwai } 1450352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", 1451352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first, 1452352f7f91STakashi Iwai badness); 1453352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1454352f7f91STakashi Iwai if (badness < best_badness) { 1455352f7f91STakashi Iwai best_badness = badness; 1456352f7f91STakashi Iwai *best_cfg = *cfg; 1457352f7f91STakashi Iwai best_wired = fill_hardwired; 1458352f7f91STakashi Iwai best_mio = fill_mio_first; 1459352f7f91STakashi Iwai } 1460352f7f91STakashi Iwai if (!badness) 1461352f7f91STakashi Iwai break; 1462352f7f91STakashi Iwai fill_mio_first = !fill_mio_first; 1463352f7f91STakashi Iwai if (!fill_mio_first) 1464352f7f91STakashi Iwai continue; 1465352f7f91STakashi Iwai fill_hardwired = !fill_hardwired; 1466352f7f91STakashi Iwai if (!fill_hardwired) 1467352f7f91STakashi Iwai continue; 1468352f7f91STakashi Iwai if (hp_spk_swapped) 1469352f7f91STakashi Iwai break; 1470352f7f91STakashi Iwai hp_spk_swapped = true; 1471352f7f91STakashi Iwai if (cfg->speaker_outs > 0 && 1472352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 1473352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 1474352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 1475352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1476352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs; 1477352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins, 1478352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1479352f7f91STakashi Iwai cfg->speaker_outs = 0; 1480352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 1481352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 1482352f7f91STakashi Iwai fill_hardwired = true; 1483352f7f91STakashi Iwai continue; 1484352f7f91STakashi Iwai } 1485352f7f91STakashi Iwai if (cfg->hp_outs > 0 && 1486352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 1487352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 1488352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 1489352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1490352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 1491352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, 1492352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1493352f7f91STakashi Iwai cfg->hp_outs = 0; 1494352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 1495352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 1496352f7f91STakashi Iwai fill_hardwired = true; 1497352f7f91STakashi Iwai continue; 1498352f7f91STakashi Iwai } 1499352f7f91STakashi Iwai break; 1500352f7f91STakashi Iwai } 1501352f7f91STakashi Iwai 1502352f7f91STakashi Iwai if (badness) { 15030c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n"); 1504352f7f91STakashi Iwai *cfg = *best_cfg; 1505352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio); 1506352f7f91STakashi Iwai } 1507352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", 1508352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio); 1509352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1510352f7f91STakashi Iwai 1511352f7f91STakashi Iwai if (cfg->line_out_pins[0]) { 1512352f7f91STakashi Iwai struct nid_path *path; 1513196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); 1514352f7f91STakashi Iwai if (path) 1515352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path); 1516352f7f91STakashi Iwai } 1517352f7f91STakashi Iwai 1518352f7f91STakashi Iwai kfree(best_cfg); 1519352f7f91STakashi Iwai return 0; 1520352f7f91STakashi Iwai } 1521352f7f91STakashi Iwai 1522352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */ 1523352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec, 1524352f7f91STakashi Iwai const struct auto_pin_cfg *cfg) 1525352f7f91STakashi Iwai { 1526352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1527352f7f91STakashi Iwai int i, err, noutputs; 1528352f7f91STakashi Iwai 1529352f7f91STakashi Iwai noutputs = cfg->line_outs; 1530352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3) 1531352f7f91STakashi Iwai noutputs += spec->multi_ios; 1532352f7f91STakashi Iwai 1533352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) { 1534352f7f91STakashi Iwai const char *name; 1535352f7f91STakashi Iwai int index; 1536352f7f91STakashi Iwai struct nid_path *path; 1537352f7f91STakashi Iwai 1538352f7f91STakashi Iwai if (i >= cfg->line_outs) { 1539352f7f91STakashi Iwai index = 0; 1540352f7f91STakashi Iwai name = channel_name[i]; 1541352f7f91STakashi Iwai } else { 1542352f7f91STakashi Iwai name = get_line_out_pfx(spec, i, true, &index); 1543352f7f91STakashi Iwai } 1544352f7f91STakashi Iwai 1545196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 1546352f7f91STakashi Iwai if (!path) 1547352f7f91STakashi Iwai continue; 1548352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1549352f7f91STakashi Iwai /* Center/LFE */ 1550352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path); 1551352f7f91STakashi Iwai if (err < 0) 1552352f7f91STakashi Iwai return err; 1553352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path); 1554352f7f91STakashi Iwai if (err < 0) 1555352f7f91STakashi Iwai return err; 1556352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path); 1557352f7f91STakashi Iwai if (err < 0) 1558352f7f91STakashi Iwai return err; 1559352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path); 1560352f7f91STakashi Iwai if (err < 0) 1561352f7f91STakashi Iwai return err; 1562352f7f91STakashi Iwai } else { 1563352f7f91STakashi Iwai err = add_stereo_vol(codec, name, index, path); 1564352f7f91STakashi Iwai if (err < 0) 1565352f7f91STakashi Iwai return err; 1566352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path); 1567352f7f91STakashi Iwai if (err < 0) 1568352f7f91STakashi Iwai return err; 1569352f7f91STakashi Iwai } 1570352f7f91STakashi Iwai } 1571352f7f91STakashi Iwai return 0; 1572352f7f91STakashi Iwai } 1573352f7f91STakashi Iwai 1574c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx, 1575196c1766STakashi Iwai const char *pfx, int cidx) 1576352f7f91STakashi Iwai { 1577352f7f91STakashi Iwai struct nid_path *path; 1578352f7f91STakashi Iwai int err; 1579352f7f91STakashi Iwai 1580196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 1581352f7f91STakashi Iwai if (!path) 1582352f7f91STakashi Iwai return 0; 1583352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path); 1584352f7f91STakashi Iwai if (err < 0) 1585352f7f91STakashi Iwai return err; 1586352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path); 1587352f7f91STakashi Iwai if (err < 0) 1588352f7f91STakashi Iwai return err; 1589352f7f91STakashi Iwai return 0; 1590352f7f91STakashi Iwai } 1591352f7f91STakashi Iwai 1592352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */ 1593352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins, 1594196c1766STakashi Iwai const int *paths, const char *pfx) 1595352f7f91STakashi Iwai { 1596c2c80383STakashi Iwai int i; 1597352f7f91STakashi Iwai 1598352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1599c2c80383STakashi Iwai const char *name; 1600c2c80383STakashi Iwai char tmp[44]; 1601c2c80383STakashi Iwai int err, idx = 0; 1602c2c80383STakashi Iwai 1603c2c80383STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) 1604c2c80383STakashi Iwai name = "Bass Speaker"; 1605c2c80383STakashi Iwai else if (num_pins >= 3) { 1606c2c80383STakashi Iwai snprintf(tmp, sizeof(tmp), "%s %s", 1607352f7f91STakashi Iwai pfx, channel_name[i]); 1608c2c80383STakashi Iwai name = tmp; 1609352f7f91STakashi Iwai } else { 1610c2c80383STakashi Iwai name = pfx; 1611c2c80383STakashi Iwai idx = i; 1612352f7f91STakashi Iwai } 1613c2c80383STakashi Iwai err = create_extra_out(codec, paths[i], name, idx); 1614352f7f91STakashi Iwai if (err < 0) 1615352f7f91STakashi Iwai return err; 1616352f7f91STakashi Iwai } 1617352f7f91STakashi Iwai return 0; 1618352f7f91STakashi Iwai } 1619352f7f91STakashi Iwai 1620352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec) 1621352f7f91STakashi Iwai { 1622352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1623352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs, 1624196c1766STakashi Iwai spec->hp_paths, 1625352f7f91STakashi Iwai "Headphone"); 1626352f7f91STakashi Iwai } 1627352f7f91STakashi Iwai 1628352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec) 1629352f7f91STakashi Iwai { 1630352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1631352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs, 1632196c1766STakashi Iwai spec->speaker_paths, 1633352f7f91STakashi Iwai "Speaker"); 1634352f7f91STakashi Iwai } 1635352f7f91STakashi Iwai 1636352f7f91STakashi Iwai /* 163738cf6f1aSTakashi Iwai * independent HP controls 163838cf6f1aSTakashi Iwai */ 163938cf6f1aSTakashi Iwai 164038cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol, 164138cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo) 164238cf6f1aSTakashi Iwai { 164338cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 164438cf6f1aSTakashi Iwai } 164538cf6f1aSTakashi Iwai 164638cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol, 164738cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 164838cf6f1aSTakashi Iwai { 164938cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 165038cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 165138cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; 165238cf6f1aSTakashi Iwai return 0; 165338cf6f1aSTakashi Iwai } 165438cf6f1aSTakashi Iwai 165538cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol, 165638cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 165738cf6f1aSTakashi Iwai { 165838cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 165938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 166038cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0]; 166138cf6f1aSTakashi Iwai int ret = 0; 166238cf6f1aSTakashi Iwai 166338cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 166438cf6f1aSTakashi Iwai if (spec->active_streams) { 166538cf6f1aSTakashi Iwai ret = -EBUSY; 166638cf6f1aSTakashi Iwai goto unlock; 166738cf6f1aSTakashi Iwai } 166838cf6f1aSTakashi Iwai 166938cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) { 167038cf6f1aSTakashi Iwai spec->indep_hp_enabled = select; 167138cf6f1aSTakashi Iwai if (spec->indep_hp_enabled) 167238cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = 0; 167338cf6f1aSTakashi Iwai else 167438cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = spec->alt_dac_nid; 167538cf6f1aSTakashi Iwai ret = 1; 167638cf6f1aSTakashi Iwai } 167738cf6f1aSTakashi Iwai unlock: 167838cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 167938cf6f1aSTakashi Iwai return ret; 168038cf6f1aSTakashi Iwai } 168138cf6f1aSTakashi Iwai 168238cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = { 168338cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 168438cf6f1aSTakashi Iwai .name = "Independent HP", 168538cf6f1aSTakashi Iwai .info = indep_hp_info, 168638cf6f1aSTakashi Iwai .get = indep_hp_get, 168738cf6f1aSTakashi Iwai .put = indep_hp_put, 168838cf6f1aSTakashi Iwai }; 168938cf6f1aSTakashi Iwai 169038cf6f1aSTakashi Iwai 169138cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec) 169238cf6f1aSTakashi Iwai { 169338cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 169438cf6f1aSTakashi Iwai 169538cf6f1aSTakashi Iwai if (!spec->indep_hp) 169638cf6f1aSTakashi Iwai return 0; 169738cf6f1aSTakashi Iwai if (!spec->multiout.hp_out_nid[0]) { 169838cf6f1aSTakashi Iwai spec->indep_hp = 0; 169938cf6f1aSTakashi Iwai return 0; 170038cf6f1aSTakashi Iwai } 170138cf6f1aSTakashi Iwai 170238cf6f1aSTakashi Iwai spec->indep_hp_enabled = false; 170338cf6f1aSTakashi Iwai spec->alt_dac_nid = spec->multiout.hp_out_nid[0]; 170438cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) 170538cf6f1aSTakashi Iwai return -ENOMEM; 170638cf6f1aSTakashi Iwai return 0; 170738cf6f1aSTakashi Iwai } 170838cf6f1aSTakashi Iwai 170938cf6f1aSTakashi Iwai /* 1710352f7f91STakashi Iwai * channel mode enum control 1711352f7f91STakashi Iwai */ 1712352f7f91STakashi Iwai 1713352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol, 1714352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 1715352f7f91STakashi Iwai { 1716352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1717352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1718a07a949bSTakashi Iwai int chs; 1719352f7f91STakashi Iwai 1720352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1721352f7f91STakashi Iwai uinfo->count = 1; 1722352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1; 1723352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios) 1724352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios; 1725a07a949bSTakashi Iwai chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count; 1726a07a949bSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", chs); 1727352f7f91STakashi Iwai return 0; 1728352f7f91STakashi Iwai } 1729352f7f91STakashi Iwai 1730352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol, 1731352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1732352f7f91STakashi Iwai { 1733352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1734352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1735a07a949bSTakashi Iwai ucontrol->value.enumerated.item[0] = 1736a07a949bSTakashi Iwai (spec->ext_channel_count - spec->min_channel_count) / 2; 1737352f7f91STakashi Iwai return 0; 1738352f7f91STakashi Iwai } 1739352f7f91STakashi Iwai 1740196c1766STakashi Iwai static inline struct nid_path * 1741196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx) 1742196c1766STakashi Iwai { 1743196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1744196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec, 1745196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]); 1746196c1766STakashi Iwai } 1747196c1766STakashi Iwai 1748352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output) 1749352f7f91STakashi Iwai { 1750352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1751352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin; 1752352f7f91STakashi Iwai struct nid_path *path; 1753352f7f91STakashi Iwai 1754196c1766STakashi Iwai path = get_multiio_path(codec, idx); 1755352f7f91STakashi Iwai if (!path) 1756352f7f91STakashi Iwai return -EINVAL; 1757352f7f91STakashi Iwai 1758352f7f91STakashi Iwai if (path->active == output) 1759352f7f91STakashi Iwai return 0; 1760352f7f91STakashi Iwai 1761352f7f91STakashi Iwai if (output) { 17622c12c30dSTakashi Iwai set_pin_target(codec, nid, PIN_OUT, true); 1763352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, true); 1764d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true); 1765352f7f91STakashi Iwai } else { 1766d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false); 1767352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, true); 17682c12c30dSTakashi Iwai set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); 1769352f7f91STakashi Iwai } 1770a365fed9STakashi Iwai 1771a365fed9STakashi Iwai /* update jack retasking in case it modifies any of them */ 1772a365fed9STakashi Iwai snd_hda_gen_hp_automute(codec, NULL); 1773a365fed9STakashi Iwai snd_hda_gen_line_automute(codec, NULL); 1774a365fed9STakashi Iwai snd_hda_gen_mic_autoswitch(codec, NULL); 1775a365fed9STakashi Iwai 1776352f7f91STakashi Iwai return 0; 1777352f7f91STakashi Iwai } 1778352f7f91STakashi Iwai 1779352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol, 1780352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1781352f7f91STakashi Iwai { 1782352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1783352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1784352f7f91STakashi Iwai int i, ch; 1785352f7f91STakashi Iwai 1786352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0]; 1787352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios) 1788352f7f91STakashi Iwai return -EINVAL; 1789a07a949bSTakashi Iwai if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2) 1790352f7f91STakashi Iwai return 0; 1791a07a949bSTakashi Iwai spec->ext_channel_count = ch * 2 + spec->min_channel_count; 1792352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) 1793352f7f91STakashi Iwai set_multi_io(codec, i, i < ch); 1794352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 1795352f7f91STakashi Iwai spec->const_channel_count); 1796352f7f91STakashi Iwai if (spec->need_dac_fix) 1797352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2; 1798352f7f91STakashi Iwai return 1; 1799352f7f91STakashi Iwai } 1800352f7f91STakashi Iwai 1801352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = { 1802352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1803352f7f91STakashi Iwai .name = "Channel Mode", 1804352f7f91STakashi Iwai .info = ch_mode_info, 1805352f7f91STakashi Iwai .get = ch_mode_get, 1806352f7f91STakashi Iwai .put = ch_mode_put, 1807352f7f91STakashi Iwai }; 1808352f7f91STakashi Iwai 1809352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec) 1810352f7f91STakashi Iwai { 1811352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1812352f7f91STakashi Iwai 1813352f7f91STakashi Iwai if (spec->multi_ios > 0) { 181412c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) 1815352f7f91STakashi Iwai return -ENOMEM; 1816352f7f91STakashi Iwai } 1817352f7f91STakashi Iwai return 0; 1818352f7f91STakashi Iwai } 1819352f7f91STakashi Iwai 1820352f7f91STakashi Iwai /* 1821c30aa7b2STakashi Iwai * aamix loopback enable/disable switch 1822c30aa7b2STakashi Iwai */ 1823c30aa7b2STakashi Iwai 1824c30aa7b2STakashi Iwai #define loopback_mixing_info indep_hp_info 1825c30aa7b2STakashi Iwai 1826c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol, 1827c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1828c30aa7b2STakashi Iwai { 1829c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1830c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1831c30aa7b2STakashi Iwai ucontrol->value.enumerated.item[0] = spec->aamix_mode; 1832c30aa7b2STakashi Iwai return 0; 1833c30aa7b2STakashi Iwai } 1834c30aa7b2STakashi Iwai 1835c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 1836c30aa7b2STakashi Iwai int nomix_path_idx, int mix_path_idx) 1837c30aa7b2STakashi Iwai { 1838c30aa7b2STakashi Iwai struct nid_path *nomix_path, *mix_path; 1839c30aa7b2STakashi Iwai 1840c30aa7b2STakashi Iwai nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); 1841c30aa7b2STakashi Iwai mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); 1842c30aa7b2STakashi Iwai if (!nomix_path || !mix_path) 1843c30aa7b2STakashi Iwai return; 1844c30aa7b2STakashi Iwai if (do_mix) { 1845c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, false, true); 1846c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, true, true); 1847c30aa7b2STakashi Iwai } else { 1848c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, false, true); 1849c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, true, true); 1850c30aa7b2STakashi Iwai } 1851c30aa7b2STakashi Iwai } 1852c30aa7b2STakashi Iwai 1853c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol, 1854c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1855c30aa7b2STakashi Iwai { 1856c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1857c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1858c30aa7b2STakashi Iwai unsigned int val = ucontrol->value.enumerated.item[0]; 1859c30aa7b2STakashi Iwai 1860c30aa7b2STakashi Iwai if (val == spec->aamix_mode) 1861c30aa7b2STakashi Iwai return 0; 1862c30aa7b2STakashi Iwai spec->aamix_mode = val; 1863c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->out_paths[0], 1864c30aa7b2STakashi Iwai spec->aamix_out_paths[0]); 1865c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->hp_paths[0], 1866c30aa7b2STakashi Iwai spec->aamix_out_paths[1]); 1867c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->speaker_paths[0], 1868c30aa7b2STakashi Iwai spec->aamix_out_paths[2]); 1869c30aa7b2STakashi Iwai return 1; 1870c30aa7b2STakashi Iwai } 1871c30aa7b2STakashi Iwai 1872c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = { 1873c30aa7b2STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1874c30aa7b2STakashi Iwai .name = "Loopback Mixing", 1875c30aa7b2STakashi Iwai .info = loopback_mixing_info, 1876c30aa7b2STakashi Iwai .get = loopback_mixing_get, 1877c30aa7b2STakashi Iwai .put = loopback_mixing_put, 1878c30aa7b2STakashi Iwai }; 1879c30aa7b2STakashi Iwai 1880c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec) 1881c30aa7b2STakashi Iwai { 1882c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1883c30aa7b2STakashi Iwai 1884c30aa7b2STakashi Iwai if (!spec->mixer_nid) 1885c30aa7b2STakashi Iwai return 0; 1886c30aa7b2STakashi Iwai if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || 1887c30aa7b2STakashi Iwai spec->aamix_out_paths[2])) 1888c30aa7b2STakashi Iwai return 0; 1889c30aa7b2STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) 1890c30aa7b2STakashi Iwai return -ENOMEM; 1891c30aa7b2STakashi Iwai return 0; 1892c30aa7b2STakashi Iwai } 1893c30aa7b2STakashi Iwai 1894c30aa7b2STakashi Iwai /* 1895352f7f91STakashi Iwai * shared headphone/mic handling 1896352f7f91STakashi Iwai */ 1897352f7f91STakashi Iwai 1898352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec); 1899352f7f91STakashi Iwai 1900352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */ 1901352f7f91STakashi Iwai static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) 1902352f7f91STakashi Iwai { 1903352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1904352f7f91STakashi Iwai unsigned int val; 1905352f7f91STakashi Iwai hda_nid_t pin = spec->autocfg.inputs[1].pin; 1906352f7f91STakashi Iwai /* NOTE: this assumes that there are only two inputs, the 1907352f7f91STakashi Iwai * first is the real internal mic and the second is HP/mic jack. 1908352f7f91STakashi Iwai */ 1909352f7f91STakashi Iwai 1910352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin); 1911352f7f91STakashi Iwai 1912352f7f91STakashi Iwai /* This pin does not have vref caps - let's enable vref on pin 0x18 1913352f7f91STakashi Iwai instead, as suggested by Realtek */ 1914352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { 1915352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin; 1916352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); 1917352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ) 19187594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin, 19197594aa33STakashi Iwai PIN_IN | (set_as_mic ? vref_val : 0)); 1920352f7f91STakashi Iwai } 1921352f7f91STakashi Iwai 1922352f7f91STakashi Iwai val = set_as_mic ? val | PIN_IN : PIN_HP; 19232c12c30dSTakashi Iwai set_pin_target(codec, pin, val, true); 1924352f7f91STakashi Iwai 1925352f7f91STakashi Iwai spec->automute_speaker = !set_as_mic; 1926352f7f91STakashi Iwai call_update_outputs(codec); 1927352f7f91STakashi Iwai } 1928352f7f91STakashi Iwai 1929352f7f91STakashi Iwai /* create a shared input with the headphone out */ 1930352f7f91STakashi Iwai static int create_shared_input(struct hda_codec *codec) 1931352f7f91STakashi Iwai { 1932352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1933352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1934352f7f91STakashi Iwai unsigned int defcfg; 1935352f7f91STakashi Iwai hda_nid_t nid; 1936352f7f91STakashi Iwai 1937352f7f91STakashi Iwai /* only one internal input pin? */ 1938352f7f91STakashi Iwai if (cfg->num_inputs != 1) 1939352f7f91STakashi Iwai return 0; 1940352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); 1941352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) 1942352f7f91STakashi Iwai return 0; 1943352f7f91STakashi Iwai 1944352f7f91STakashi Iwai if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1945352f7f91STakashi Iwai nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ 1946352f7f91STakashi Iwai else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) 1947352f7f91STakashi Iwai nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ 1948352f7f91STakashi Iwai else 1949352f7f91STakashi Iwai return 0; /* both not available */ 1950352f7f91STakashi Iwai 1951352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) 1952352f7f91STakashi Iwai return 0; /* no input */ 1953352f7f91STakashi Iwai 1954352f7f91STakashi Iwai cfg->inputs[1].pin = nid; 1955352f7f91STakashi Iwai cfg->inputs[1].type = AUTO_PIN_MIC; 1956352f7f91STakashi Iwai cfg->num_inputs = 2; 1957352f7f91STakashi Iwai spec->shared_mic_hp = 1; 1958352f7f91STakashi Iwai snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); 1959352f7f91STakashi Iwai return 0; 1960352f7f91STakashi Iwai } 1961352f7f91STakashi Iwai 1962352f7f91STakashi Iwai 1963352f7f91STakashi Iwai /* 1964352f7f91STakashi Iwai * Parse input paths 1965352f7f91STakashi Iwai */ 1966352f7f91STakashi Iwai 1967352f7f91STakashi Iwai #ifdef CONFIG_PM 1968352f7f91STakashi Iwai /* add the powersave loopback-list entry */ 1969352f7f91STakashi Iwai static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) 1970352f7f91STakashi Iwai { 1971352f7f91STakashi Iwai struct hda_amp_list *list; 1972352f7f91STakashi Iwai 1973352f7f91STakashi Iwai if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) 1974352f7f91STakashi Iwai return; 1975352f7f91STakashi Iwai list = spec->loopback_list + spec->num_loopbacks; 1976352f7f91STakashi Iwai list->nid = mix; 1977352f7f91STakashi Iwai list->dir = HDA_INPUT; 1978352f7f91STakashi Iwai list->idx = idx; 1979352f7f91STakashi Iwai spec->num_loopbacks++; 1980cb53c626STakashi Iwai spec->loopback.amplist = spec->loopback_list; 1981cb53c626STakashi Iwai } 1982cb53c626STakashi Iwai #else 1983352f7f91STakashi Iwai #define add_loopback_list(spec, mix, idx) /* NOP */ 1984cb53c626STakashi Iwai #endif 1985cb53c626STakashi Iwai 1986352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */ 1987196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx, 1988196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx, 1989352f7f91STakashi Iwai hda_nid_t mix_nid) 19901da177e4SLinus Torvalds { 1991352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1992352f7f91STakashi Iwai struct nid_path *path; 1993352f7f91STakashi Iwai unsigned int val; 1994352f7f91STakashi Iwai int err, idx; 19951da177e4SLinus Torvalds 1996352f7f91STakashi Iwai if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && 1997352f7f91STakashi Iwai !nid_has_mute(codec, mix_nid, HDA_INPUT)) 1998352f7f91STakashi Iwai return 0; /* no need for analog loopback */ 1999352f7f91STakashi Iwai 20003ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, 0); 2001352f7f91STakashi Iwai if (!path) 2002352f7f91STakashi Iwai return -EINVAL; 20030c8c0f56STakashi Iwai print_nid_path("loopback", path); 2004196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 2005352f7f91STakashi Iwai 2006352f7f91STakashi Iwai idx = path->idx[path->depth - 1]; 2007352f7f91STakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { 2008352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2009352f7f91STakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val); 2010d13bd412STakashi Iwai if (err < 0) 20111da177e4SLinus Torvalds return err; 2012352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 20131da177e4SLinus Torvalds } 20141da177e4SLinus Torvalds 2015352f7f91STakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { 2016352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2017352f7f91STakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val); 2018d13bd412STakashi Iwai if (err < 0) 20191da177e4SLinus Torvalds return err; 2020352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 20211da177e4SLinus Torvalds } 20221da177e4SLinus Torvalds 2023352f7f91STakashi Iwai path->active = true; 2024352f7f91STakashi Iwai add_loopback_list(spec, mix_nid, idx); 2025352f7f91STakashi Iwai return 0; 20261da177e4SLinus Torvalds } 20271da177e4SLinus Torvalds 2028352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) 20291da177e4SLinus Torvalds { 2030352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 2031352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0; 2032352f7f91STakashi Iwai } 2033352f7f91STakashi Iwai 2034352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */ 2035352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec) 2036352f7f91STakashi Iwai { 2037352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2038352f7f91STakashi Iwai hda_nid_t nid; 2039352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids; 2040352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids); 2041352f7f91STakashi Iwai int i, nums = 0; 2042352f7f91STakashi Iwai 2043352f7f91STakashi Iwai nid = codec->start_nid; 2044352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 2045352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 2046352f7f91STakashi Iwai int type = get_wcaps_type(caps); 2047352f7f91STakashi Iwai 2048352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) 2049352f7f91STakashi Iwai continue; 2050352f7f91STakashi Iwai adc_nids[nums] = nid; 2051352f7f91STakashi Iwai if (++nums >= max_nums) 2052352f7f91STakashi Iwai break; 2053352f7f91STakashi Iwai } 2054352f7f91STakashi Iwai spec->num_adc_nids = nums; 2055352f7f91STakashi Iwai return nums; 2056352f7f91STakashi Iwai } 2057352f7f91STakashi Iwai 2058352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins; 2059352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available 2060352f7f91STakashi Iwai */ 2061352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec) 2062352f7f91STakashi Iwai { 2063352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2064352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 20653a65bcdcSTakashi Iwai unsigned int ok_bits; 2066352f7f91STakashi Iwai int i, n, nums; 2067352f7f91STakashi Iwai 2068352f7f91STakashi Iwai again: 2069352f7f91STakashi Iwai nums = 0; 20703a65bcdcSTakashi Iwai ok_bits = 0; 2071352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 2072352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 20733a65bcdcSTakashi Iwai if (!spec->input_paths[i][n]) 2074352f7f91STakashi Iwai break; 2075352f7f91STakashi Iwai } 20763a65bcdcSTakashi Iwai if (i >= imux->num_items) { 20773a65bcdcSTakashi Iwai ok_bits |= (1 << n); 20783a65bcdcSTakashi Iwai nums++; 20793a65bcdcSTakashi Iwai } 2080352f7f91STakashi Iwai } 2081352f7f91STakashi Iwai 20823a65bcdcSTakashi Iwai if (!ok_bits) { 2083352f7f91STakashi Iwai if (spec->shared_mic_hp) { 2084352f7f91STakashi Iwai spec->shared_mic_hp = 0; 2085352f7f91STakashi Iwai imux->num_items = 1; 2086352f7f91STakashi Iwai goto again; 2087352f7f91STakashi Iwai } 2088352f7f91STakashi Iwai 2089352f7f91STakashi Iwai /* check whether ADC-switch is possible */ 2090352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2091352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 20923a65bcdcSTakashi Iwai if (spec->input_paths[i][n]) { 2093352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n; 2094352f7f91STakashi Iwai break; 2095352f7f91STakashi Iwai } 2096352f7f91STakashi Iwai } 2097352f7f91STakashi Iwai } 2098352f7f91STakashi Iwai 2099352f7f91STakashi Iwai snd_printdd("hda-codec: enabling ADC switching\n"); 2100352f7f91STakashi Iwai spec->dyn_adc_switch = 1; 2101352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) { 21023a65bcdcSTakashi Iwai /* shrink the invalid adcs and input paths */ 21033a65bcdcSTakashi Iwai nums = 0; 21043a65bcdcSTakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 21053a65bcdcSTakashi Iwai if (!(ok_bits & (1 << n))) 21063a65bcdcSTakashi Iwai continue; 21073a65bcdcSTakashi Iwai if (n != nums) { 21083a65bcdcSTakashi Iwai spec->adc_nids[nums] = spec->adc_nids[n]; 2109980428ceSTakashi Iwai for (i = 0; i < imux->num_items; i++) { 2110980428ceSTakashi Iwai invalidate_nid_path(codec, 2111980428ceSTakashi Iwai spec->input_paths[i][nums]); 21123a65bcdcSTakashi Iwai spec->input_paths[i][nums] = 21133a65bcdcSTakashi Iwai spec->input_paths[i][n]; 21143a65bcdcSTakashi Iwai } 2115980428ceSTakashi Iwai } 21163a65bcdcSTakashi Iwai nums++; 21173a65bcdcSTakashi Iwai } 2118352f7f91STakashi Iwai spec->num_adc_nids = nums; 2119352f7f91STakashi Iwai } 2120352f7f91STakashi Iwai 2121352f7f91STakashi Iwai if (imux->num_items == 1 || spec->shared_mic_hp) { 2122352f7f91STakashi Iwai snd_printdd("hda-codec: reducing to a single ADC\n"); 2123352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */ 2124352f7f91STakashi Iwai } 2125352f7f91STakashi Iwai 2126352f7f91STakashi Iwai /* single index for individual volumes ctls */ 2127352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol) 2128352f7f91STakashi Iwai spec->num_adc_nids = 1; 2129352f7f91STakashi Iwai 21301da177e4SLinus Torvalds return 0; 21311da177e4SLinus Torvalds } 21321da177e4SLinus Torvalds 2133f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */ 2134f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, 2135f3fc0b0bSTakashi Iwai int num_adcs, const char *label, int anchor) 2136f3fc0b0bSTakashi Iwai { 2137f3fc0b0bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2138f3fc0b0bSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2139f3fc0b0bSTakashi Iwai int imux_idx = imux->num_items; 2140f3fc0b0bSTakashi Iwai bool imux_added = false; 2141f3fc0b0bSTakashi Iwai int c; 2142f3fc0b0bSTakashi Iwai 2143f3fc0b0bSTakashi Iwai for (c = 0; c < num_adcs; c++) { 2144f3fc0b0bSTakashi Iwai struct nid_path *path; 2145f3fc0b0bSTakashi Iwai hda_nid_t adc = spec->adc_nids[c]; 2146f3fc0b0bSTakashi Iwai 2147f3fc0b0bSTakashi Iwai if (!is_reachable_path(codec, pin, adc)) 2148f3fc0b0bSTakashi Iwai continue; 2149f3fc0b0bSTakashi Iwai path = snd_hda_add_new_path(codec, pin, adc, anchor); 2150f3fc0b0bSTakashi Iwai if (!path) 2151f3fc0b0bSTakashi Iwai continue; 2152f3fc0b0bSTakashi Iwai print_nid_path("input", path); 2153f3fc0b0bSTakashi Iwai spec->input_paths[imux_idx][c] = 2154f3fc0b0bSTakashi Iwai snd_hda_get_path_idx(codec, path); 2155f3fc0b0bSTakashi Iwai 2156f3fc0b0bSTakashi Iwai if (!imux_added) { 2157f3fc0b0bSTakashi Iwai spec->imux_pins[imux->num_items] = pin; 2158f3fc0b0bSTakashi Iwai snd_hda_add_imux_item(imux, label, 2159f3fc0b0bSTakashi Iwai imux->num_items, NULL); 2160f3fc0b0bSTakashi Iwai imux_added = true; 2161f3fc0b0bSTakashi Iwai } 2162f3fc0b0bSTakashi Iwai } 2163f3fc0b0bSTakashi Iwai 2164f3fc0b0bSTakashi Iwai return 0; 2165f3fc0b0bSTakashi Iwai } 2166f3fc0b0bSTakashi Iwai 21671da177e4SLinus Torvalds /* 2168352f7f91STakashi Iwai * create playback/capture controls for input pins 21691da177e4SLinus Torvalds */ 2170352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec) 2171a7da6ce5STakashi Iwai { 2172352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2173352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 2174352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid; 2175352f7f91STakashi Iwai int num_adcs; 2176f3fc0b0bSTakashi Iwai int i, err, type_idx = 0; 2177352f7f91STakashi Iwai const char *prev_label = NULL; 21782c12c30dSTakashi Iwai unsigned int val; 2179a7da6ce5STakashi Iwai 2180352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec); 2181352f7f91STakashi Iwai if (num_adcs < 0) 2182352f7f91STakashi Iwai return 0; 2183352f7f91STakashi Iwai 2184352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2185352f7f91STakashi Iwai hda_nid_t pin; 2186352f7f91STakashi Iwai const char *label; 2187352f7f91STakashi Iwai 2188352f7f91STakashi Iwai pin = cfg->inputs[i].pin; 2189352f7f91STakashi Iwai if (!is_input_pin(codec, pin)) 2190352f7f91STakashi Iwai continue; 2191352f7f91STakashi Iwai 2192352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2193352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2194352f7f91STakashi Iwai type_idx++; 2195352f7f91STakashi Iwai else 2196352f7f91STakashi Iwai type_idx = 0; 2197352f7f91STakashi Iwai prev_label = label; 2198352f7f91STakashi Iwai 21992c12c30dSTakashi Iwai val = PIN_IN; 22002c12c30dSTakashi Iwai if (cfg->inputs[i].type == AUTO_PIN_MIC) 22012c12c30dSTakashi Iwai val |= snd_hda_get_default_vref(codec, pin); 22022c12c30dSTakashi Iwai set_pin_target(codec, pin, val, false); 22032c12c30dSTakashi Iwai 2204352f7f91STakashi Iwai if (mixer) { 2205352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) { 2206196c1766STakashi Iwai err = new_analog_input(codec, i, pin, 2207352f7f91STakashi Iwai label, type_idx, mixer); 2208a7da6ce5STakashi Iwai if (err < 0) 2209a7da6ce5STakashi Iwai return err; 2210a7da6ce5STakashi Iwai } 2211352f7f91STakashi Iwai } 2212352f7f91STakashi Iwai 2213f3fc0b0bSTakashi Iwai err = parse_capture_source(codec, pin, num_adcs, label, -mixer); 2214f3fc0b0bSTakashi Iwai if (err < 0) 2215f3fc0b0bSTakashi Iwai return err; 2216352f7f91STakashi Iwai } 2217f3fc0b0bSTakashi Iwai 2218f3fc0b0bSTakashi Iwai if (mixer && spec->add_stereo_mix_input) { 2219f3fc0b0bSTakashi Iwai err = parse_capture_source(codec, mixer, num_adcs, 2220f3fc0b0bSTakashi Iwai "Stereo Mix", 0); 2221f3fc0b0bSTakashi Iwai if (err < 0) 2222f3fc0b0bSTakashi Iwai return err; 2223352f7f91STakashi Iwai } 2224352f7f91STakashi Iwai 2225a7da6ce5STakashi Iwai return 0; 2226a7da6ce5STakashi Iwai } 2227a7da6ce5STakashi Iwai 22281da177e4SLinus Torvalds 2229352f7f91STakashi Iwai /* 2230352f7f91STakashi Iwai * input source mux 2231352f7f91STakashi Iwai */ 2232352f7f91STakashi Iwai 2233c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */ 2234c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx) 2235352f7f91STakashi Iwai { 2236352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2237352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2238352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx]; 2239c697b716STakashi Iwai return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]); 224097ec558aSTakashi Iwai } 2241352f7f91STakashi Iwai 2242352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2243352f7f91STakashi Iwai unsigned int idx); 2244352f7f91STakashi Iwai 2245352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol, 2246352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2247352f7f91STakashi Iwai { 2248352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2249352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2250352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo); 2251352f7f91STakashi Iwai } 2252352f7f91STakashi Iwai 2253352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol, 2254352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2255352f7f91STakashi Iwai { 2256352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2257352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2258352f7f91STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2259352f7f91STakashi Iwai 2260352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 22611da177e4SLinus Torvalds return 0; 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds 2264352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol, 2265352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 22661da177e4SLinus Torvalds { 2267352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2268352f7f91STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2269352f7f91STakashi Iwai return mux_select(codec, adc_idx, 2270352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]); 2271352f7f91STakashi Iwai } 2272352f7f91STakashi Iwai 2273352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = { 22741da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2275352f7f91STakashi Iwai .name = "Input Source", 2276352f7f91STakashi Iwai .info = mux_enum_info, 2277352f7f91STakashi Iwai .get = mux_enum_get, 2278352f7f91STakashi Iwai .put = mux_enum_put, 22791da177e4SLinus Torvalds }; 2280071c73adSTakashi Iwai 228147d46abbSTakashi Iwai /* 228247d46abbSTakashi Iwai * capture volume and capture switch ctls 228347d46abbSTakashi Iwai */ 228447d46abbSTakashi Iwai 2285352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, 2286352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol); 2287071c73adSTakashi Iwai 228847d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */ 2289352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol, 2290352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol, 2291352f7f91STakashi Iwai put_call_t func, int type) 2292352f7f91STakashi Iwai { 2293352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2294352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2295352f7f91STakashi Iwai const struct hda_input_mux *imux; 2296352f7f91STakashi Iwai struct nid_path *path; 2297352f7f91STakashi Iwai int i, adc_idx, err = 0; 2298071c73adSTakashi Iwai 2299352f7f91STakashi Iwai imux = &spec->input_mux; 2300352f7f91STakashi Iwai adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2301352f7f91STakashi Iwai mutex_lock(&codec->control_mutex); 230247d46abbSTakashi Iwai /* we use the cache-only update at first since multiple input paths 230347d46abbSTakashi Iwai * may shared the same amp; by updating only caches, the redundant 230447d46abbSTakashi Iwai * writes to hardware can be reduced. 230547d46abbSTakashi Iwai */ 2306352f7f91STakashi Iwai codec->cached_write = 1; 2307352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2308c697b716STakashi Iwai path = get_input_path(codec, adc_idx, i); 2309c697b716STakashi Iwai if (!path || !path->ctls[type]) 2310352f7f91STakashi Iwai continue; 2311352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type]; 2312352f7f91STakashi Iwai err = func(kcontrol, ucontrol); 2313352f7f91STakashi Iwai if (err < 0) 2314352f7f91STakashi Iwai goto error; 2315352f7f91STakashi Iwai } 2316352f7f91STakashi Iwai error: 2317352f7f91STakashi Iwai codec->cached_write = 0; 2318352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex); 231947d46abbSTakashi Iwai snd_hda_codec_flush_amp_cache(codec); /* flush the updates */ 2320352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook) 2321352f7f91STakashi Iwai spec->cap_sync_hook(codec); 2322352f7f91STakashi Iwai return err; 2323352f7f91STakashi Iwai } 2324352f7f91STakashi Iwai 2325352f7f91STakashi Iwai /* capture volume ctl callbacks */ 2326352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info 2327352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get 2328352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv 2329352f7f91STakashi Iwai 2330352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol, 2331352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2332352f7f91STakashi Iwai { 2333352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2334352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put, 2335352f7f91STakashi Iwai NID_PATH_VOL_CTL); 2336352f7f91STakashi Iwai } 2337352f7f91STakashi Iwai 2338352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = { 2339352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2340352f7f91STakashi Iwai .name = "Capture Volume", 2341352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 2342352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ | 2343352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), 2344352f7f91STakashi Iwai .info = cap_vol_info, 2345352f7f91STakashi Iwai .get = cap_vol_get, 2346352f7f91STakashi Iwai .put = cap_vol_put, 2347352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv }, 2348352f7f91STakashi Iwai }; 2349352f7f91STakashi Iwai 2350352f7f91STakashi Iwai /* capture switch ctl callbacks */ 2351352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info 2352352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get 2353352f7f91STakashi Iwai 2354352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol, 2355352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2356352f7f91STakashi Iwai { 2357352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2358352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put, 2359352f7f91STakashi Iwai NID_PATH_MUTE_CTL); 2360352f7f91STakashi Iwai } 2361352f7f91STakashi Iwai 2362352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = { 2363352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2364352f7f91STakashi Iwai .name = "Capture Switch", 2365352f7f91STakashi Iwai .info = cap_sw_info, 2366352f7f91STakashi Iwai .get = cap_sw_get, 2367352f7f91STakashi Iwai .put = cap_sw_put, 2368352f7f91STakashi Iwai }; 2369352f7f91STakashi Iwai 2370352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) 2371352f7f91STakashi Iwai { 2372352f7f91STakashi Iwai hda_nid_t nid; 2373352f7f91STakashi Iwai int i, depth; 2374352f7f91STakashi Iwai 2375352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; 2376352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) { 2377352f7f91STakashi Iwai if (depth >= path->depth) 2378352f7f91STakashi Iwai return -EINVAL; 2379352f7f91STakashi Iwai i = path->depth - depth - 1; 2380352f7f91STakashi Iwai nid = path->path[i]; 2381352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) { 2382352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 2383352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2384352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2385352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) { 2386352f7f91STakashi Iwai int idx = path->idx[i]; 2387352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2388352f7f91STakashi Iwai idx = 0; 2389352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2390352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2391352f7f91STakashi Iwai } 2392352f7f91STakashi Iwai } 2393352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) { 2394352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT)) 2395352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2396352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2397352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) { 2398352f7f91STakashi Iwai int idx = path->idx[i]; 2399352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2400352f7f91STakashi Iwai idx = 0; 2401352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2402352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2403352f7f91STakashi Iwai } 2404352f7f91STakashi Iwai } 2405352f7f91STakashi Iwai } 2406352f7f91STakashi Iwai return 0; 2407352f7f91STakashi Iwai } 2408352f7f91STakashi Iwai 2409352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) 2410352f7f91STakashi Iwai { 2411352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2412352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2413352f7f91STakashi Iwai unsigned int val; 2414352f7f91STakashi Iwai int i; 2415352f7f91STakashi Iwai 2416352f7f91STakashi Iwai if (!spec->inv_dmic_split) 2417352f7f91STakashi Iwai return false; 2418352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2419352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid) 2420352f7f91STakashi Iwai continue; 2421352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 2422352f7f91STakashi Iwai return false; 2423352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid); 2424352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; 2425352f7f91STakashi Iwai } 2426352f7f91STakashi Iwai return false; 2427352f7f91STakashi Iwai } 2428352f7f91STakashi Iwai 2429352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label, 2430352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl, 2431352f7f91STakashi Iwai bool inv_dmic) 2432352f7f91STakashi Iwai { 2433352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2434352f7f91STakashi Iwai char tmpname[44]; 2435352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; 2436352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume"; 2437352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3; 2438352f7f91STakashi Iwai int err; 2439352f7f91STakashi Iwai 2440352f7f91STakashi Iwai if (!ctl) 2441352f7f91STakashi Iwai return 0; 2442352f7f91STakashi Iwai 2443352f7f91STakashi Iwai if (label) 2444352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2445352f7f91STakashi Iwai "%s Capture %s", label, sfx); 2446352f7f91STakashi Iwai else 2447352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2448352f7f91STakashi Iwai "Capture %s", sfx); 2449352f7f91STakashi Iwai err = add_control(spec, type, tmpname, idx, 2450352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs)); 2451352f7f91STakashi Iwai if (err < 0 || !inv_dmic) 2452352f7f91STakashi Iwai return err; 2453352f7f91STakashi Iwai 2454352f7f91STakashi Iwai /* Make independent right kcontrol */ 2455352f7f91STakashi Iwai if (label) 2456352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2457352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx); 2458352f7f91STakashi Iwai else 2459352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2460352f7f91STakashi Iwai "Inverted Capture %s", sfx); 2461352f7f91STakashi Iwai return add_control(spec, type, tmpname, idx, 2462352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2)); 2463352f7f91STakashi Iwai } 2464352f7f91STakashi Iwai 2465352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */ 2466352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, 2467352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl, 2468352f7f91STakashi Iwai bool inv_dmic) 2469352f7f91STakashi Iwai { 2470352f7f91STakashi Iwai int err; 2471352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); 2472352f7f91STakashi Iwai if (err < 0) 2473352f7f91STakashi Iwai return err; 2474352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); 2475071c73adSTakashi Iwai if (err < 0) 2476071c73adSTakashi Iwai return err; 2477071c73adSTakashi Iwai return 0; 24781da177e4SLinus Torvalds } 2479071c73adSTakashi Iwai 2480352f7f91STakashi Iwai /* create bound capture volume and switch controls */ 2481352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, 2482352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl) 2483352f7f91STakashi Iwai { 2484352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2485352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2486352f7f91STakashi Iwai 2487352f7f91STakashi Iwai if (vol_ctl) { 248812c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); 2489352f7f91STakashi Iwai if (!knew) 2490352f7f91STakashi Iwai return -ENOMEM; 2491352f7f91STakashi Iwai knew->index = idx; 2492352f7f91STakashi Iwai knew->private_value = vol_ctl; 2493352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2494352f7f91STakashi Iwai } 2495352f7f91STakashi Iwai if (sw_ctl) { 249612c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); 2497352f7f91STakashi Iwai if (!knew) 2498352f7f91STakashi Iwai return -ENOMEM; 2499352f7f91STakashi Iwai knew->index = idx; 2500352f7f91STakashi Iwai knew->private_value = sw_ctl; 2501352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2502352f7f91STakashi Iwai } 2503352f7f91STakashi Iwai return 0; 2504352f7f91STakashi Iwai } 2505352f7f91STakashi Iwai 2506352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */ 2507352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) 2508352f7f91STakashi Iwai { 2509352f7f91STakashi Iwai struct nid_path *path; 2510352f7f91STakashi Iwai unsigned int ctl; 2511352f7f91STakashi Iwai int i; 2512352f7f91STakashi Iwai 2513c697b716STakashi Iwai path = get_input_path(codec, 0, idx); 2514352f7f91STakashi Iwai if (!path) 2515352f7f91STakashi Iwai return 0; 2516352f7f91STakashi Iwai ctl = path->ctls[type]; 2517352f7f91STakashi Iwai if (!ctl) 2518352f7f91STakashi Iwai return 0; 2519352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) { 2520c697b716STakashi Iwai path = get_input_path(codec, 0, i); 2521352f7f91STakashi Iwai if (path && path->ctls[type] == ctl) 2522352f7f91STakashi Iwai return 0; 2523352f7f91STakashi Iwai } 2524352f7f91STakashi Iwai return ctl; 2525352f7f91STakashi Iwai } 2526352f7f91STakashi Iwai 2527352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */ 2528352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec) 2529352f7f91STakashi Iwai { 2530352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2531352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2532352f7f91STakashi Iwai int i, err, type, type_idx = 0; 2533352f7f91STakashi Iwai const char *prev_label = NULL; 2534352f7f91STakashi Iwai 2535352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2536352f7f91STakashi Iwai const char *label; 2537352f7f91STakashi Iwai bool inv_dmic; 2538352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, &spec->autocfg, i); 2539352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2540352f7f91STakashi Iwai type_idx++; 2541352f7f91STakashi Iwai else 2542352f7f91STakashi Iwai type_idx = 0; 2543352f7f91STakashi Iwai prev_label = label; 2544352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); 2545352f7f91STakashi Iwai 2546352f7f91STakashi Iwai for (type = 0; type < 2; type++) { 2547352f7f91STakashi Iwai err = add_single_cap_ctl(codec, label, type_idx, type, 2548352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type), 2549352f7f91STakashi Iwai inv_dmic); 2550d13bd412STakashi Iwai if (err < 0) 2551071c73adSTakashi Iwai return err; 2552352f7f91STakashi Iwai } 2553352f7f91STakashi Iwai } 2554071c73adSTakashi Iwai return 0; 2555352f7f91STakashi Iwai } 2556071c73adSTakashi Iwai 2557352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec) 2558352f7f91STakashi Iwai { 2559352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2560352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2561352f7f91STakashi Iwai int i, n, nums, err; 2562352f7f91STakashi Iwai 2563352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2564352f7f91STakashi Iwai nums = 1; 2565352f7f91STakashi Iwai else 2566352f7f91STakashi Iwai nums = spec->num_adc_nids; 2567352f7f91STakashi Iwai 2568352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) { 2569352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2570624d914dSTakashi Iwai const char *name; 2571624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source"; 2572624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); 2573352f7f91STakashi Iwai if (!knew) 2574352f7f91STakashi Iwai return -ENOMEM; 2575352f7f91STakashi Iwai knew->count = nums; 2576352f7f91STakashi Iwai } 2577352f7f91STakashi Iwai 2578352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 2579352f7f91STakashi Iwai bool multi = false; 2580352f7f91STakashi Iwai bool inv_dmic = false; 2581352f7f91STakashi Iwai int vol, sw; 2582352f7f91STakashi Iwai 2583352f7f91STakashi Iwai vol = sw = 0; 2584352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2585352f7f91STakashi Iwai struct nid_path *path; 2586c697b716STakashi Iwai path = get_input_path(codec, n, i); 2587352f7f91STakashi Iwai if (!path) 2588352f7f91STakashi Iwai continue; 2589352f7f91STakashi Iwai parse_capvol_in_path(codec, path); 2590352f7f91STakashi Iwai if (!vol) 2591352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL]; 2592352f7f91STakashi Iwai else if (vol != path->ctls[NID_PATH_VOL_CTL]) 2593352f7f91STakashi Iwai multi = true; 2594352f7f91STakashi Iwai if (!sw) 2595352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL]; 2596352f7f91STakashi Iwai else if (sw != path->ctls[NID_PATH_MUTE_CTL]) 2597352f7f91STakashi Iwai multi = true; 2598352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i])) 2599352f7f91STakashi Iwai inv_dmic = true; 2600352f7f91STakashi Iwai } 2601352f7f91STakashi Iwai 2602352f7f91STakashi Iwai if (!multi) 2603352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw, 2604352f7f91STakashi Iwai inv_dmic); 2605352f7f91STakashi Iwai else if (!spec->multi_cap_vol) 2606352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw); 2607352f7f91STakashi Iwai else 2608352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec); 2609d13bd412STakashi Iwai if (err < 0) 2610071c73adSTakashi Iwai return err; 2611071c73adSTakashi Iwai } 2612071c73adSTakashi Iwai 26131da177e4SLinus Torvalds return 0; 26141da177e4SLinus Torvalds } 26151da177e4SLinus Torvalds 2616352f7f91STakashi Iwai /* 2617352f7f91STakashi Iwai * add mic boosts if needed 2618352f7f91STakashi Iwai */ 2619352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec) 2620352f7f91STakashi Iwai { 2621352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2622352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2623352f7f91STakashi Iwai int i, err; 2624352f7f91STakashi Iwai int type_idx = 0; 2625352f7f91STakashi Iwai hda_nid_t nid; 2626352f7f91STakashi Iwai const char *prev_label = NULL; 2627352f7f91STakashi Iwai 2628352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2629352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_MIC) 2630352f7f91STakashi Iwai break; 2631352f7f91STakashi Iwai nid = cfg->inputs[i].pin; 2632352f7f91STakashi Iwai if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { 2633352f7f91STakashi Iwai const char *label; 26345abd4888STakashi Iwai char boost_label[44]; 2635352f7f91STakashi Iwai struct nid_path *path; 2636352f7f91STakashi Iwai unsigned int val; 2637352f7f91STakashi Iwai 2638352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2639352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2640352f7f91STakashi Iwai type_idx++; 2641352f7f91STakashi Iwai else 2642352f7f91STakashi Iwai type_idx = 0; 2643352f7f91STakashi Iwai prev_label = label; 2644352f7f91STakashi Iwai 2645352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label), 2646352f7f91STakashi Iwai "%s Boost Volume", label); 2647352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 2648352f7f91STakashi Iwai err = add_control(spec, HDA_CTL_WIDGET_VOL, 2649352f7f91STakashi Iwai boost_label, type_idx, val); 2650352f7f91STakashi Iwai if (err < 0) 2651352f7f91STakashi Iwai return err; 2652352f7f91STakashi Iwai 2653352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, nid, 0); 2654352f7f91STakashi Iwai if (path) 2655352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val; 2656352f7f91STakashi Iwai } 2657352f7f91STakashi Iwai } 2658352f7f91STakashi Iwai return 0; 2659352f7f91STakashi Iwai } 2660352f7f91STakashi Iwai 2661352f7f91STakashi Iwai /* 2662352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 2663352f7f91STakashi Iwai */ 2664352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 2665352f7f91STakashi Iwai { 2666352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 26670c8c0f56STakashi Iwai struct nid_path *path; 2668352f7f91STakashi Iwai int i, nums; 26692c12c30dSTakashi Iwai hda_nid_t dig_nid, pin; 2670352f7f91STakashi Iwai 2671352f7f91STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a slave */ 2672352f7f91STakashi Iwai nums = 0; 2673352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 26742c12c30dSTakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 2675352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 2676352f7f91STakashi Iwai if (!dig_nid) 2677352f7f91STakashi Iwai continue; 26783ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, 0); 26790c8c0f56STakashi Iwai if (!path) 2680352f7f91STakashi Iwai continue; 26810c8c0f56STakashi Iwai print_nid_path("digout", path); 2682e1284af7STakashi Iwai path->active = true; 2683196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 26842c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_OUT, false); 2685352f7f91STakashi Iwai if (!nums) { 2686352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 2687352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 2688352f7f91STakashi Iwai } else { 2689352f7f91STakashi Iwai spec->multiout.slave_dig_outs = spec->slave_dig_outs; 2690352f7f91STakashi Iwai if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) 2691352f7f91STakashi Iwai break; 2692352f7f91STakashi Iwai spec->slave_dig_outs[nums - 1] = dig_nid; 2693352f7f91STakashi Iwai } 2694352f7f91STakashi Iwai nums++; 2695352f7f91STakashi Iwai } 2696352f7f91STakashi Iwai 2697352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 26982c12c30dSTakashi Iwai pin = spec->autocfg.dig_in_pin; 2699352f7f91STakashi Iwai dig_nid = codec->start_nid; 2700352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, dig_nid++) { 2701352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 2702352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 2703352f7f91STakashi Iwai continue; 2704352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 2705352f7f91STakashi Iwai continue; 27062c12c30dSTakashi Iwai path = snd_hda_add_new_path(codec, pin, dig_nid, 0); 2707352f7f91STakashi Iwai if (path) { 27080c8c0f56STakashi Iwai print_nid_path("digin", path); 2709352f7f91STakashi Iwai path->active = true; 2710352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 27112430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 27122c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_IN, false); 2713352f7f91STakashi Iwai break; 2714352f7f91STakashi Iwai } 2715352f7f91STakashi Iwai } 2716352f7f91STakashi Iwai } 2717352f7f91STakashi Iwai } 2718352f7f91STakashi Iwai 27191da177e4SLinus Torvalds 27201da177e4SLinus Torvalds /* 2721352f7f91STakashi Iwai * input MUX handling 27221da177e4SLinus Torvalds */ 27231da177e4SLinus Torvalds 2724352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 2725352f7f91STakashi Iwai 2726352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 2727352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2728352f7f91STakashi Iwai unsigned int idx) 2729352f7f91STakashi Iwai { 2730352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2731352f7f91STakashi Iwai const struct hda_input_mux *imux; 2732352f7f91STakashi Iwai struct nid_path *path; 2733352f7f91STakashi Iwai 2734352f7f91STakashi Iwai imux = &spec->input_mux; 2735352f7f91STakashi Iwai if (!imux->num_items) 27361da177e4SLinus Torvalds return 0; 27371da177e4SLinus Torvalds 2738352f7f91STakashi Iwai if (idx >= imux->num_items) 2739352f7f91STakashi Iwai idx = imux->num_items - 1; 2740352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 2741352f7f91STakashi Iwai return 0; 2742352f7f91STakashi Iwai 2743c697b716STakashi Iwai path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); 2744352f7f91STakashi Iwai if (!path) 2745352f7f91STakashi Iwai return 0; 2746352f7f91STakashi Iwai if (path->active) 2747352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, false); 2748352f7f91STakashi Iwai 2749352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 2750352f7f91STakashi Iwai 2751352f7f91STakashi Iwai if (spec->shared_mic_hp) 2752352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); 2753352f7f91STakashi Iwai 2754352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2755352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 2756352f7f91STakashi Iwai 2757c697b716STakashi Iwai path = get_input_path(codec, adc_idx, idx); 2758352f7f91STakashi Iwai if (!path) 2759352f7f91STakashi Iwai return 0; 2760352f7f91STakashi Iwai if (path->active) 2761352f7f91STakashi Iwai return 0; 2762352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 2763352f7f91STakashi Iwai if (spec->cap_sync_hook) 2764352f7f91STakashi Iwai spec->cap_sync_hook(codec); 27651da177e4SLinus Torvalds return 1; 27661da177e4SLinus Torvalds } 27671da177e4SLinus Torvalds 27681da177e4SLinus Torvalds 27691da177e4SLinus Torvalds /* 2770352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 27711da177e4SLinus Torvalds */ 2772352f7f91STakashi Iwai 2773352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 2774352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) 27751da177e4SLinus Torvalds { 2776352f7f91STakashi Iwai int i, present = 0; 27771da177e4SLinus Torvalds 2778352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2779352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 2780352f7f91STakashi Iwai if (!nid) 2781352f7f91STakashi Iwai break; 27820b4df931STakashi Iwai /* don't detect pins retasked as inputs */ 27830b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) 27840b4df931STakashi Iwai continue; 2785352f7f91STakashi Iwai present |= snd_hda_jack_detect(codec, nid); 27861da177e4SLinus Torvalds } 2787352f7f91STakashi Iwai return present; 27881da177e4SLinus Torvalds } 27891da177e4SLinus Torvalds 2790352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 2791352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, 27922c12c30dSTakashi Iwai bool mute) 27931da177e4SLinus Torvalds { 2794352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2795352f7f91STakashi Iwai int i; 27961da177e4SLinus Torvalds 2797352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2798352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 2799352f7f91STakashi Iwai unsigned int val; 2800352f7f91STakashi Iwai if (!nid) 2801352f7f91STakashi Iwai break; 2802352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 2803352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 2804352f7f91STakashi Iwai */ 28052c12c30dSTakashi Iwai if (spec->keep_vref_in_automute) 28062c12c30dSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP; 28072c12c30dSTakashi Iwai else 2808352f7f91STakashi Iwai val = 0; 28092c12c30dSTakashi Iwai if (!mute) 28102c12c30dSTakashi Iwai val |= snd_hda_codec_get_pin_target(codec, nid); 28112c12c30dSTakashi Iwai /* here we call update_pin_ctl() so that the pinctl is changed 28122c12c30dSTakashi Iwai * without changing the pinctl target value; 28132c12c30dSTakashi Iwai * the original target value will be still referred at the 28142c12c30dSTakashi Iwai * init / resume again 28152c12c30dSTakashi Iwai */ 28162c12c30dSTakashi Iwai update_pin_ctl(codec, nid, val); 2817d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 2818352f7f91STakashi Iwai } 2819352f7f91STakashi Iwai } 28201da177e4SLinus Torvalds 2821352f7f91STakashi Iwai /* Toggle outputs muting */ 28225d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 2823352f7f91STakashi Iwai { 2824352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2825352f7f91STakashi Iwai int on; 2826352f7f91STakashi Iwai 2827352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 2828352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 2829352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 2830352f7f91STakashi Iwai */ 2831352f7f91STakashi Iwai if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ 2832352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 28332c12c30dSTakashi Iwai spec->autocfg.hp_pins, spec->master_mute); 2834352f7f91STakashi Iwai 2835352f7f91STakashi Iwai if (!spec->automute_speaker) 2836352f7f91STakashi Iwai on = 0; 2837352f7f91STakashi Iwai else 2838352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 2839352f7f91STakashi Iwai on |= spec->master_mute; 2840352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 28412c12c30dSTakashi Iwai spec->autocfg.speaker_pins, on); 2842352f7f91STakashi Iwai 2843352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 2844352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 2845352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 2846352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 2847352f7f91STakashi Iwai return; 2848352f7f91STakashi Iwai if (!spec->automute_lo) 2849352f7f91STakashi Iwai on = 0; 2850352f7f91STakashi Iwai else 2851352f7f91STakashi Iwai on = spec->hp_jack_present; 2852352f7f91STakashi Iwai on |= spec->master_mute; 2853352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 28542c12c30dSTakashi Iwai spec->autocfg.line_out_pins, on); 2855352f7f91STakashi Iwai } 28565d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); 2857352f7f91STakashi Iwai 2858352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 2859352f7f91STakashi Iwai { 2860352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2861352f7f91STakashi Iwai if (spec->automute_hook) 2862352f7f91STakashi Iwai spec->automute_hook(codec); 2863352f7f91STakashi Iwai else 28645d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 2865352f7f91STakashi Iwai } 2866352f7f91STakashi Iwai 2867352f7f91STakashi Iwai /* standard HP-automute helper */ 28685d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 2869352f7f91STakashi Iwai { 2870352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2871352f7f91STakashi Iwai 2872352f7f91STakashi Iwai spec->hp_jack_present = 2873352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 2874352f7f91STakashi Iwai spec->autocfg.hp_pins); 2875352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 2876352f7f91STakashi Iwai return; 2877352f7f91STakashi Iwai call_update_outputs(codec); 2878352f7f91STakashi Iwai } 28795d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute); 2880352f7f91STakashi Iwai 2881352f7f91STakashi Iwai /* standard line-out-automute helper */ 28825d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 2883352f7f91STakashi Iwai { 2884352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2885352f7f91STakashi Iwai 2886352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 2887352f7f91STakashi Iwai return; 2888352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 2889352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 2890352f7f91STakashi Iwai return; 2891352f7f91STakashi Iwai 2892352f7f91STakashi Iwai spec->line_jack_present = 2893352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 2894352f7f91STakashi Iwai spec->autocfg.line_out_pins); 2895352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 2896352f7f91STakashi Iwai return; 2897352f7f91STakashi Iwai call_update_outputs(codec); 2898352f7f91STakashi Iwai } 28995d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute); 2900352f7f91STakashi Iwai 2901352f7f91STakashi Iwai /* standard mic auto-switch helper */ 29025d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) 2903352f7f91STakashi Iwai { 2904352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2905352f7f91STakashi Iwai int i; 2906352f7f91STakashi Iwai 2907352f7f91STakashi Iwai if (!spec->auto_mic) 2908352f7f91STakashi Iwai return; 2909352f7f91STakashi Iwai 2910352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 29110b4df931STakashi Iwai hda_nid_t pin = spec->am_entry[i].pin; 29120b4df931STakashi Iwai /* don't detect pins retasked as outputs */ 29130b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) 29140b4df931STakashi Iwai continue; 29150b4df931STakashi Iwai if (snd_hda_jack_detect(codec, pin)) { 2916352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 2917352f7f91STakashi Iwai return; 2918352f7f91STakashi Iwai } 2919352f7f91STakashi Iwai } 2920352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 29211da177e4SLinus Torvalds } 29225d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch); 29231da177e4SLinus Torvalds 29241da177e4SLinus Torvalds /* 2925352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 29261da177e4SLinus Torvalds */ 2927352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 2928352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2929352f7f91STakashi Iwai { 2930352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2931352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2932352f7f91STakashi Iwai static const char * const texts3[] = { 2933352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 29341da177e4SLinus Torvalds }; 29351da177e4SLinus Torvalds 2936352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 2937352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 2938352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 2939352f7f91STakashi Iwai } 2940352f7f91STakashi Iwai 2941352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 2942352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2943352f7f91STakashi Iwai { 2944352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2945352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2946352f7f91STakashi Iwai unsigned int val = 0; 2947352f7f91STakashi Iwai if (spec->automute_speaker) 2948352f7f91STakashi Iwai val++; 2949352f7f91STakashi Iwai if (spec->automute_lo) 2950352f7f91STakashi Iwai val++; 2951352f7f91STakashi Iwai 2952352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 2953352f7f91STakashi Iwai return 0; 2954352f7f91STakashi Iwai } 2955352f7f91STakashi Iwai 2956352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 2957352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2958352f7f91STakashi Iwai { 2959352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2960352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2961352f7f91STakashi Iwai 2962352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 2963352f7f91STakashi Iwai case 0: 2964352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 2965352f7f91STakashi Iwai return 0; 2966352f7f91STakashi Iwai spec->automute_speaker = 0; 2967352f7f91STakashi Iwai spec->automute_lo = 0; 2968352f7f91STakashi Iwai break; 2969352f7f91STakashi Iwai case 1: 2970352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 2971352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 2972352f7f91STakashi Iwai return 0; 2973352f7f91STakashi Iwai spec->automute_speaker = 1; 2974352f7f91STakashi Iwai spec->automute_lo = 0; 2975352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 2976352f7f91STakashi Iwai if (spec->automute_lo) 2977352f7f91STakashi Iwai return 0; 2978352f7f91STakashi Iwai spec->automute_lo = 1; 2979352f7f91STakashi Iwai } else 2980352f7f91STakashi Iwai return -EINVAL; 2981352f7f91STakashi Iwai break; 2982352f7f91STakashi Iwai case 2: 2983352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 2984352f7f91STakashi Iwai return -EINVAL; 2985352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 2986352f7f91STakashi Iwai return 0; 2987352f7f91STakashi Iwai spec->automute_speaker = 1; 2988352f7f91STakashi Iwai spec->automute_lo = 1; 2989352f7f91STakashi Iwai break; 2990352f7f91STakashi Iwai default: 2991352f7f91STakashi Iwai return -EINVAL; 2992352f7f91STakashi Iwai } 2993352f7f91STakashi Iwai call_update_outputs(codec); 2994352f7f91STakashi Iwai return 1; 2995352f7f91STakashi Iwai } 2996352f7f91STakashi Iwai 2997352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 2998352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2999352f7f91STakashi Iwai .name = "Auto-Mute Mode", 3000352f7f91STakashi Iwai .info = automute_mode_info, 3001352f7f91STakashi Iwai .get = automute_mode_get, 3002352f7f91STakashi Iwai .put = automute_mode_put, 3003352f7f91STakashi Iwai }; 3004352f7f91STakashi Iwai 3005352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 3006352f7f91STakashi Iwai { 3007352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3008352f7f91STakashi Iwai 300912c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 3010352f7f91STakashi Iwai return -ENOMEM; 3011352f7f91STakashi Iwai return 0; 3012352f7f91STakashi Iwai } 3013352f7f91STakashi Iwai 3014352f7f91STakashi Iwai /* 3015352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 3016352f7f91STakashi Iwai * Set up appropriately if really supported 3017352f7f91STakashi Iwai */ 3018352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 3019352f7f91STakashi Iwai { 3020352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3021352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3022352f7f91STakashi Iwai int present = 0; 3023352f7f91STakashi Iwai int i, err; 3024352f7f91STakashi Iwai 3025352f7f91STakashi Iwai if (cfg->hp_pins[0]) 3026352f7f91STakashi Iwai present++; 3027352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 3028352f7f91STakashi Iwai present++; 3029352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 3030352f7f91STakashi Iwai present++; 3031352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 3032352f7f91STakashi Iwai return 0; 3033352f7f91STakashi Iwai 3034352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 3035352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 3036352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3037352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3038352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3039352f7f91STakashi Iwai } 3040352f7f91STakashi Iwai 3041352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 3042352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 3043352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 3044352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 3045352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 3046352f7f91STakashi Iwai } 3047352f7f91STakashi Iwai 3048352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 3049352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 3050352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3051352f7f91STakashi Iwai continue; 3052352f7f91STakashi Iwai snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n", 3053352f7f91STakashi Iwai nid); 3054352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, 30552e03e952STakashi Iwai spec->hp_automute_hook ? 30562e03e952STakashi Iwai spec->hp_automute_hook : 30575d550e15STakashi Iwai snd_hda_gen_hp_automute); 3058352f7f91STakashi Iwai spec->detect_hp = 1; 3059352f7f91STakashi Iwai } 3060352f7f91STakashi Iwai 3061352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 3062352f7f91STakashi Iwai if (cfg->speaker_outs) 3063352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 3064352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 3065352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3066352f7f91STakashi Iwai continue; 3067352f7f91STakashi Iwai snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid); 3068352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 3069352f7f91STakashi Iwai HDA_GEN_FRONT_EVENT, 30702e03e952STakashi Iwai spec->line_automute_hook ? 30712e03e952STakashi Iwai spec->line_automute_hook : 30725d550e15STakashi Iwai snd_hda_gen_line_automute); 3073352f7f91STakashi Iwai spec->detect_lo = 1; 3074352f7f91STakashi Iwai } 3075352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 3076352f7f91STakashi Iwai } 3077352f7f91STakashi Iwai 3078352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 3079352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 3080352f7f91STakashi Iwai 3081352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 3082352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 3083352f7f91STakashi Iwai 3084352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 3085352f7f91STakashi Iwai /* create a control for automute mode */ 3086352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 3087352f7f91STakashi Iwai if (err < 0) 3088352f7f91STakashi Iwai return err; 3089352f7f91STakashi Iwai } 3090352f7f91STakashi Iwai return 0; 3091352f7f91STakashi Iwai } 3092352f7f91STakashi Iwai 3093352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 3094352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 3095352f7f91STakashi Iwai { 3096352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3097352f7f91STakashi Iwai const struct hda_input_mux *imux; 3098352f7f91STakashi Iwai int i; 3099352f7f91STakashi Iwai 3100352f7f91STakashi Iwai imux = &spec->input_mux; 3101352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 3102352f7f91STakashi Iwai spec->am_entry[i].idx = 3103352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 3104352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 3105352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 3106352f7f91STakashi Iwai return false; /* no corresponding imux */ 3107352f7f91STakashi Iwai } 3108352f7f91STakashi Iwai 3109352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 3110352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 3111352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 3112352f7f91STakashi Iwai spec->am_entry[i].pin, 3113352f7f91STakashi Iwai HDA_GEN_MIC_EVENT, 31142e03e952STakashi Iwai spec->mic_autoswitch_hook ? 31152e03e952STakashi Iwai spec->mic_autoswitch_hook : 31165d550e15STakashi Iwai snd_hda_gen_mic_autoswitch); 3117352f7f91STakashi Iwai return true; 3118352f7f91STakashi Iwai } 3119352f7f91STakashi Iwai 3120352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 3121352f7f91STakashi Iwai { 3122352f7f91STakashi Iwai const struct automic_entry *a = ap; 3123352f7f91STakashi Iwai const struct automic_entry *b = bp; 3124352f7f91STakashi Iwai return (int)(a->attr - b->attr); 3125352f7f91STakashi Iwai } 3126352f7f91STakashi Iwai 3127352f7f91STakashi Iwai /* 3128352f7f91STakashi Iwai * Check the availability of auto-mic switch; 3129352f7f91STakashi Iwai * Set up if really supported 3130352f7f91STakashi Iwai */ 3131352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 3132352f7f91STakashi Iwai { 3133352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3134352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3135352f7f91STakashi Iwai unsigned int types; 3136352f7f91STakashi Iwai int i, num_pins; 3137352f7f91STakashi Iwai 3138d12daf6fSTakashi Iwai if (spec->suppress_auto_mic) 3139d12daf6fSTakashi Iwai return 0; 3140d12daf6fSTakashi Iwai 3141352f7f91STakashi Iwai types = 0; 3142352f7f91STakashi Iwai num_pins = 0; 3143352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3144352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 3145352f7f91STakashi Iwai unsigned int attr; 3146352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 3147352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 3148352f7f91STakashi Iwai if (types & (1 << attr)) 3149352f7f91STakashi Iwai return 0; /* already occupied */ 3150352f7f91STakashi Iwai switch (attr) { 3151352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 3152352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 3153352f7f91STakashi Iwai return 0; /* invalid type */ 3154352f7f91STakashi Iwai break; 3155352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 3156352f7f91STakashi Iwai return 0; /* invalid entry */ 3157352f7f91STakashi Iwai default: 3158352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 3159352f7f91STakashi Iwai return 0; /* invalid type */ 3160352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 3161352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 3162352f7f91STakashi Iwai return 0; /* only mic is allowed */ 3163352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3164352f7f91STakashi Iwai return 0; /* no unsol support */ 3165352f7f91STakashi Iwai break; 3166352f7f91STakashi Iwai } 3167352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 3168352f7f91STakashi Iwai return 0; 3169352f7f91STakashi Iwai types |= (1 << attr); 3170352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 3171352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 3172352f7f91STakashi Iwai num_pins++; 3173352f7f91STakashi Iwai } 3174352f7f91STakashi Iwai 3175352f7f91STakashi Iwai if (num_pins < 2) 3176352f7f91STakashi Iwai return 0; 3177352f7f91STakashi Iwai 3178352f7f91STakashi Iwai spec->am_num_entries = num_pins; 3179352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 3180352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 3181352f7f91STakashi Iwai */ 3182352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 3183352f7f91STakashi Iwai compare_attr, NULL); 3184352f7f91STakashi Iwai 3185352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 3186352f7f91STakashi Iwai return 0; 3187352f7f91STakashi Iwai 3188352f7f91STakashi Iwai spec->auto_mic = 1; 3189352f7f91STakashi Iwai spec->num_adc_nids = 1; 3190352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 3191352f7f91STakashi Iwai snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 3192352f7f91STakashi Iwai spec->am_entry[0].pin, 3193352f7f91STakashi Iwai spec->am_entry[1].pin, 3194352f7f91STakashi Iwai spec->am_entry[2].pin); 3195352f7f91STakashi Iwai 3196352f7f91STakashi Iwai return 0; 3197352f7f91STakashi Iwai } 3198352f7f91STakashi Iwai 3199352f7f91STakashi Iwai 32009eb413e5STakashi Iwai /* 32019eb413e5STakashi Iwai * Parse the given BIOS configuration and set up the hda_gen_spec 32029eb413e5STakashi Iwai * 32039eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 3204352f7f91STakashi Iwai * or a negative error code 3205352f7f91STakashi Iwai */ 3206352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 32079eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 3208352f7f91STakashi Iwai { 3209352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3210352f7f91STakashi Iwai int err; 3211352f7f91STakashi Iwai 32129eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 32139eb413e5STakashi Iwai spec->autocfg = *cfg; 32149eb413e5STakashi Iwai cfg = &spec->autocfg; 32159eb413e5STakashi Iwai } 32169eb413e5STakashi Iwai 3217352f7f91STakashi Iwai if (!cfg->line_outs) { 3218352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 3219352f7f91STakashi Iwai spec->multiout.max_channels = 2; 3220352f7f91STakashi Iwai spec->no_analog = 1; 3221352f7f91STakashi Iwai goto dig_only; 3222352f7f91STakashi Iwai } 3223352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 3224352f7f91STakashi Iwai } 3225352f7f91STakashi Iwai 3226352f7f91STakashi Iwai if (!spec->no_primary_hp && 3227352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 3228352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 3229352f7f91STakashi Iwai /* use HP as primary out */ 3230352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3231352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3232352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3233352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 3234352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 3235352f7f91STakashi Iwai cfg->hp_outs = 0; 3236352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 3237352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 3238352f7f91STakashi Iwai } 3239352f7f91STakashi Iwai 3240352f7f91STakashi Iwai err = parse_output_paths(codec); 3241352f7f91STakashi Iwai if (err < 0) 3242352f7f91STakashi Iwai return err; 3243352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 3244352f7f91STakashi Iwai if (err < 0) 3245352f7f91STakashi Iwai return err; 3246352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 3247352f7f91STakashi Iwai if (err < 0) 3248352f7f91STakashi Iwai return err; 3249352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 3250352f7f91STakashi Iwai if (err < 0) 3251352f7f91STakashi Iwai return err; 3252352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 3253352f7f91STakashi Iwai if (err < 0) 3254352f7f91STakashi Iwai return err; 325538cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 325638cf6f1aSTakashi Iwai if (err < 0) 325738cf6f1aSTakashi Iwai return err; 3258c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec); 3259c30aa7b2STakashi Iwai if (err < 0) 3260c30aa7b2STakashi Iwai return err; 3261352f7f91STakashi Iwai err = create_shared_input(codec); 3262352f7f91STakashi Iwai if (err < 0) 3263352f7f91STakashi Iwai return err; 3264352f7f91STakashi Iwai err = create_input_ctls(codec); 3265352f7f91STakashi Iwai if (err < 0) 3266352f7f91STakashi Iwai return err; 3267352f7f91STakashi Iwai 3268a07a949bSTakashi Iwai spec->const_channel_count = spec->ext_channel_count; 3269a07a949bSTakashi Iwai /* check the multiple speaker and headphone pins */ 3270a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 3271a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 3272a07a949bSTakashi Iwai cfg->speaker_outs * 2); 3273a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 3274a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 3275a07a949bSTakashi Iwai cfg->hp_outs * 2); 3276352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 3277352f7f91STakashi Iwai spec->const_channel_count); 3278352f7f91STakashi Iwai 3279352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 3280352f7f91STakashi Iwai if (err < 0) 3281352f7f91STakashi Iwai return err; 3282352f7f91STakashi Iwai 3283352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 3284352f7f91STakashi Iwai if (err < 0) 3285352f7f91STakashi Iwai return err; 3286352f7f91STakashi Iwai 3287352f7f91STakashi Iwai if (!spec->shared_mic_hp) { 3288352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 3289352f7f91STakashi Iwai if (err < 0) 3290352f7f91STakashi Iwai return err; 3291352f7f91STakashi Iwai } 3292352f7f91STakashi Iwai 3293352f7f91STakashi Iwai err = create_capture_mixers(codec); 3294352f7f91STakashi Iwai if (err < 0) 3295352f7f91STakashi Iwai return err; 3296352f7f91STakashi Iwai 3297352f7f91STakashi Iwai err = parse_mic_boost(codec); 3298352f7f91STakashi Iwai if (err < 0) 3299352f7f91STakashi Iwai return err; 3300352f7f91STakashi Iwai 3301352f7f91STakashi Iwai dig_only: 3302352f7f91STakashi Iwai parse_digital(codec); 3303352f7f91STakashi Iwai 3304352f7f91STakashi Iwai return 1; 3305352f7f91STakashi Iwai } 3306352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); 3307352f7f91STakashi Iwai 3308352f7f91STakashi Iwai 3309352f7f91STakashi Iwai /* 3310352f7f91STakashi Iwai * Build control elements 3311352f7f91STakashi Iwai */ 3312352f7f91STakashi Iwai 3313352f7f91STakashi Iwai /* slave controls for virtual master */ 3314352f7f91STakashi Iwai static const char * const slave_pfxs[] = { 3315352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 3316352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 3317352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 3318ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", 3319ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE", 3320ee79c69aSTakashi Iwai "Headphone Side", 3321352f7f91STakashi Iwai NULL, 3322352f7f91STakashi Iwai }; 3323352f7f91STakashi Iwai 3324352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 3325352f7f91STakashi Iwai { 3326352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3327352f7f91STakashi Iwai int err; 3328352f7f91STakashi Iwai 332936502d02STakashi Iwai if (spec->kctls.used) { 3330352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 3331352f7f91STakashi Iwai if (err < 0) 3332352f7f91STakashi Iwai return err; 333336502d02STakashi Iwai } 3334352f7f91STakashi Iwai 3335352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3336352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 3337352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3338352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3339352f7f91STakashi Iwai spec->pcm_rec[1].pcm_type); 3340352f7f91STakashi Iwai if (err < 0) 3341352f7f91STakashi Iwai return err; 3342352f7f91STakashi Iwai if (!spec->no_analog) { 3343352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 3344352f7f91STakashi Iwai &spec->multiout); 3345352f7f91STakashi Iwai if (err < 0) 3346352f7f91STakashi Iwai return err; 3347352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 3348352f7f91STakashi Iwai } 3349352f7f91STakashi Iwai } 3350352f7f91STakashi Iwai if (spec->dig_in_nid) { 3351352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 3352352f7f91STakashi Iwai if (err < 0) 3353352f7f91STakashi Iwai return err; 3354352f7f91STakashi Iwai } 3355352f7f91STakashi Iwai 3356352f7f91STakashi Iwai /* if we have no master control, let's create it */ 3357352f7f91STakashi Iwai if (!spec->no_analog && 3358352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 3359352f7f91STakashi Iwai unsigned int vmaster_tlv[4]; 3360352f7f91STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 3361352f7f91STakashi Iwai HDA_OUTPUT, vmaster_tlv); 3362352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 3363352f7f91STakashi Iwai vmaster_tlv, slave_pfxs, 3364352f7f91STakashi Iwai "Playback Volume"); 3365352f7f91STakashi Iwai if (err < 0) 3366352f7f91STakashi Iwai return err; 3367352f7f91STakashi Iwai } 3368352f7f91STakashi Iwai if (!spec->no_analog && 3369352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 3370352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 3371352f7f91STakashi Iwai NULL, slave_pfxs, 3372352f7f91STakashi Iwai "Playback Switch", 3373352f7f91STakashi Iwai true, &spec->vmaster_mute.sw_kctl); 3374352f7f91STakashi Iwai if (err < 0) 3375352f7f91STakashi Iwai return err; 3376352f7f91STakashi Iwai if (spec->vmaster_mute.hook) 3377fd25a97aSTakashi Iwai snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, 3378fd25a97aSTakashi Iwai spec->vmaster_mute_enum); 3379352f7f91STakashi Iwai } 3380352f7f91STakashi Iwai 3381352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 3382352f7f91STakashi Iwai 3383352f7f91STakashi Iwai if (spec->shared_mic_hp) { 3384352f7f91STakashi Iwai int err; 3385352f7f91STakashi Iwai int nid = spec->autocfg.inputs[1].pin; 3386352f7f91STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); 3387352f7f91STakashi Iwai if (err < 0) 3388352f7f91STakashi Iwai return err; 3389352f7f91STakashi Iwai err = snd_hda_jack_detect_enable(codec, nid, 0); 3390352f7f91STakashi Iwai if (err < 0) 3391352f7f91STakashi Iwai return err; 3392352f7f91STakashi Iwai } 3393352f7f91STakashi Iwai 3394352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 3395352f7f91STakashi Iwai if (err < 0) 3396352f7f91STakashi Iwai return err; 3397352f7f91STakashi Iwai 3398352f7f91STakashi Iwai return 0; 3399352f7f91STakashi Iwai } 3400352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls); 3401352f7f91STakashi Iwai 3402352f7f91STakashi Iwai 3403352f7f91STakashi Iwai /* 3404352f7f91STakashi Iwai * PCM definitions 3405352f7f91STakashi Iwai */ 3406352f7f91STakashi Iwai 3407e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, 3408e6b85f3cSTakashi Iwai struct hda_codec *codec, 3409e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream, 3410e6b85f3cSTakashi Iwai int action) 3411e6b85f3cSTakashi Iwai { 3412e6b85f3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 3413e6b85f3cSTakashi Iwai if (spec->pcm_playback_hook) 3414e6b85f3cSTakashi Iwai spec->pcm_playback_hook(hinfo, codec, substream, action); 3415e6b85f3cSTakashi Iwai } 3416e6b85f3cSTakashi Iwai 3417352f7f91STakashi Iwai /* 3418352f7f91STakashi Iwai * Analog playback callbacks 3419352f7f91STakashi Iwai */ 3420352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 3421352f7f91STakashi Iwai struct hda_codec *codec, 3422352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3423352f7f91STakashi Iwai { 3424352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 342538cf6f1aSTakashi Iwai int err; 342638cf6f1aSTakashi Iwai 342738cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 342838cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 342938cf6f1aSTakashi Iwai &spec->multiout, substream, 3430352f7f91STakashi Iwai hinfo); 3431e6b85f3cSTakashi Iwai if (!err) { 343238cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 3433e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3434e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 3435e6b85f3cSTakashi Iwai } 343638cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 343738cf6f1aSTakashi Iwai return err; 3438352f7f91STakashi Iwai } 3439352f7f91STakashi Iwai 3440352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 344197ec558aSTakashi Iwai struct hda_codec *codec, 344297ec558aSTakashi Iwai unsigned int stream_tag, 344397ec558aSTakashi Iwai unsigned int format, 344497ec558aSTakashi Iwai struct snd_pcm_substream *substream) 344597ec558aSTakashi Iwai { 3446352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3447e6b85f3cSTakashi Iwai int err; 3448e6b85f3cSTakashi Iwai 3449e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 3450352f7f91STakashi Iwai stream_tag, format, substream); 3451e6b85f3cSTakashi Iwai if (!err) 3452e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3453e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 3454e6b85f3cSTakashi Iwai return err; 3455352f7f91STakashi Iwai } 345697ec558aSTakashi Iwai 3457352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3458352f7f91STakashi Iwai struct hda_codec *codec, 3459352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3460352f7f91STakashi Iwai { 3461352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3462e6b85f3cSTakashi Iwai int err; 3463e6b85f3cSTakashi Iwai 3464e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 3465e6b85f3cSTakashi Iwai if (!err) 3466e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3467e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 3468e6b85f3cSTakashi Iwai return err; 3469352f7f91STakashi Iwai } 3470352f7f91STakashi Iwai 347138cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 347238cf6f1aSTakashi Iwai struct hda_codec *codec, 347338cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 347438cf6f1aSTakashi Iwai { 347538cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 347638cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 347738cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 3478e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3479e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 348038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 348138cf6f1aSTakashi Iwai return 0; 348238cf6f1aSTakashi Iwai } 348338cf6f1aSTakashi Iwai 348438cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 348538cf6f1aSTakashi Iwai struct hda_codec *codec, 348638cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 348738cf6f1aSTakashi Iwai { 348838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 348938cf6f1aSTakashi Iwai int err = 0; 349038cf6f1aSTakashi Iwai 349138cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 349238cf6f1aSTakashi Iwai if (!spec->indep_hp_enabled) 349338cf6f1aSTakashi Iwai err = -EBUSY; 349438cf6f1aSTakashi Iwai else 349538cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 3496e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3497e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 349838cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 349938cf6f1aSTakashi Iwai return err; 350038cf6f1aSTakashi Iwai } 350138cf6f1aSTakashi Iwai 350238cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 350338cf6f1aSTakashi Iwai struct hda_codec *codec, 350438cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 350538cf6f1aSTakashi Iwai { 350638cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 350738cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 350838cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 3509e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3510e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 351138cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 351238cf6f1aSTakashi Iwai return 0; 351338cf6f1aSTakashi Iwai } 351438cf6f1aSTakashi Iwai 3515e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 3516e6b85f3cSTakashi Iwai struct hda_codec *codec, 3517e6b85f3cSTakashi Iwai unsigned int stream_tag, 3518e6b85f3cSTakashi Iwai unsigned int format, 3519e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 3520e6b85f3cSTakashi Iwai { 3521e6b85f3cSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 3522e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3523e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 3524e6b85f3cSTakashi Iwai return 0; 3525e6b85f3cSTakashi Iwai } 3526e6b85f3cSTakashi Iwai 3527e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3528e6b85f3cSTakashi Iwai struct hda_codec *codec, 3529e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 3530e6b85f3cSTakashi Iwai { 3531e6b85f3cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 3532e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3533e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 3534e6b85f3cSTakashi Iwai return 0; 3535e6b85f3cSTakashi Iwai } 3536e6b85f3cSTakashi Iwai 3537352f7f91STakashi Iwai /* 3538352f7f91STakashi Iwai * Digital out 3539352f7f91STakashi Iwai */ 3540352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 3541352f7f91STakashi Iwai struct hda_codec *codec, 3542352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3543352f7f91STakashi Iwai { 3544352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3545352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 3546352f7f91STakashi Iwai } 3547352f7f91STakashi Iwai 3548352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 3549352f7f91STakashi Iwai struct hda_codec *codec, 3550352f7f91STakashi Iwai unsigned int stream_tag, 3551352f7f91STakashi Iwai unsigned int format, 3552352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3553352f7f91STakashi Iwai { 3554352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3555352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 3556352f7f91STakashi Iwai stream_tag, format, substream); 3557352f7f91STakashi Iwai } 3558352f7f91STakashi Iwai 3559352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3560352f7f91STakashi Iwai struct hda_codec *codec, 3561352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3562352f7f91STakashi Iwai { 3563352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3564352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 3565352f7f91STakashi Iwai } 3566352f7f91STakashi Iwai 3567352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 3568352f7f91STakashi Iwai struct hda_codec *codec, 3569352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3570352f7f91STakashi Iwai { 3571352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3572352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 3573352f7f91STakashi Iwai } 3574352f7f91STakashi Iwai 3575352f7f91STakashi Iwai /* 3576352f7f91STakashi Iwai * Analog capture 3577352f7f91STakashi Iwai */ 3578352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3579352f7f91STakashi Iwai struct hda_codec *codec, 3580352f7f91STakashi Iwai unsigned int stream_tag, 3581352f7f91STakashi Iwai unsigned int format, 3582352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3583352f7f91STakashi Iwai { 3584352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3585352f7f91STakashi Iwai 3586352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 358797ec558aSTakashi Iwai stream_tag, 0, format); 358897ec558aSTakashi Iwai return 0; 358997ec558aSTakashi Iwai } 359097ec558aSTakashi Iwai 3591352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 359297ec558aSTakashi Iwai struct hda_codec *codec, 359397ec558aSTakashi Iwai struct snd_pcm_substream *substream) 359497ec558aSTakashi Iwai { 3595352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 359697ec558aSTakashi Iwai 3597352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 3598352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 359997ec558aSTakashi Iwai return 0; 360097ec558aSTakashi Iwai } 360197ec558aSTakashi Iwai 3602352f7f91STakashi Iwai /* 3603352f7f91STakashi Iwai */ 3604352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 3605352f7f91STakashi Iwai .substreams = 1, 3606352f7f91STakashi Iwai .channels_min = 2, 3607352f7f91STakashi Iwai .channels_max = 8, 3608352f7f91STakashi Iwai /* NID is set in build_pcms */ 3609352f7f91STakashi Iwai .ops = { 3610352f7f91STakashi Iwai .open = playback_pcm_open, 361138cf6f1aSTakashi Iwai .close = playback_pcm_close, 3612352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 3613352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 3614352f7f91STakashi Iwai }, 3615352f7f91STakashi Iwai }; 3616352f7f91STakashi Iwai 3617352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 3618352f7f91STakashi Iwai .substreams = 1, 3619352f7f91STakashi Iwai .channels_min = 2, 3620352f7f91STakashi Iwai .channels_max = 2, 3621352f7f91STakashi Iwai /* NID is set in build_pcms */ 3622352f7f91STakashi Iwai }; 3623352f7f91STakashi Iwai 3624352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 3625352f7f91STakashi Iwai .substreams = 1, 3626352f7f91STakashi Iwai .channels_min = 2, 3627352f7f91STakashi Iwai .channels_max = 2, 3628352f7f91STakashi Iwai /* NID is set in build_pcms */ 362938cf6f1aSTakashi Iwai .ops = { 363038cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 3631e6b85f3cSTakashi Iwai .close = alt_playback_pcm_close, 3632e6b85f3cSTakashi Iwai .prepare = alt_playback_pcm_prepare, 3633e6b85f3cSTakashi Iwai .cleanup = alt_playback_pcm_cleanup 363438cf6f1aSTakashi Iwai }, 3635352f7f91STakashi Iwai }; 3636352f7f91STakashi Iwai 3637352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 3638352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 3639352f7f91STakashi Iwai .channels_min = 2, 3640352f7f91STakashi Iwai .channels_max = 2, 3641352f7f91STakashi Iwai /* NID is set in build_pcms */ 3642352f7f91STakashi Iwai .ops = { 3643352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 3644352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 3645352f7f91STakashi Iwai }, 3646352f7f91STakashi Iwai }; 3647352f7f91STakashi Iwai 3648352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 3649352f7f91STakashi Iwai .substreams = 1, 3650352f7f91STakashi Iwai .channels_min = 2, 3651352f7f91STakashi Iwai .channels_max = 2, 3652352f7f91STakashi Iwai /* NID is set in build_pcms */ 3653352f7f91STakashi Iwai .ops = { 3654352f7f91STakashi Iwai .open = dig_playback_pcm_open, 3655352f7f91STakashi Iwai .close = dig_playback_pcm_close, 3656352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 3657352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 3658352f7f91STakashi Iwai }, 3659352f7f91STakashi Iwai }; 3660352f7f91STakashi Iwai 3661352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 3662352f7f91STakashi Iwai .substreams = 1, 3663352f7f91STakashi Iwai .channels_min = 2, 3664352f7f91STakashi Iwai .channels_max = 2, 3665352f7f91STakashi Iwai /* NID is set in build_pcms */ 3666352f7f91STakashi Iwai }; 3667352f7f91STakashi Iwai 3668352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 3669352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 3670352f7f91STakashi Iwai .substreams = 0, 3671352f7f91STakashi Iwai .channels_min = 0, 3672352f7f91STakashi Iwai .channels_max = 0, 3673352f7f91STakashi Iwai }; 3674352f7f91STakashi Iwai 3675352f7f91STakashi Iwai /* 3676352f7f91STakashi Iwai * dynamic changing ADC PCM streams 3677352f7f91STakashi Iwai */ 3678352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 36791da177e4SLinus Torvalds { 3680352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3681352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 36821da177e4SLinus Torvalds 3683352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 3684352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 3685352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 3686352f7f91STakashi Iwai spec->cur_adc = new_adc; 3687352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 3688352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 3689352f7f91STakashi Iwai spec->cur_adc_format); 3690352f7f91STakashi Iwai return true; 3691352f7f91STakashi Iwai } 3692352f7f91STakashi Iwai return false; 3693352f7f91STakashi Iwai } 3694352f7f91STakashi Iwai 3695352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 3696352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3697352f7f91STakashi Iwai struct hda_codec *codec, 3698352f7f91STakashi Iwai unsigned int stream_tag, 3699352f7f91STakashi Iwai unsigned int format, 3700352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3701352f7f91STakashi Iwai { 3702352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3703352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 3704352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 3705352f7f91STakashi Iwai spec->cur_adc_format = format; 3706352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 37071da177e4SLinus Torvalds return 0; 37081da177e4SLinus Torvalds } 37091da177e4SLinus Torvalds 3710352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 3711352f7f91STakashi Iwai struct hda_codec *codec, 3712352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3713352f7f91STakashi Iwai { 3714352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3715352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 3716352f7f91STakashi Iwai spec->cur_adc = 0; 3717352f7f91STakashi Iwai return 0; 3718352f7f91STakashi Iwai } 3719352f7f91STakashi Iwai 3720352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 3721352f7f91STakashi Iwai .substreams = 1, 3722352f7f91STakashi Iwai .channels_min = 2, 3723352f7f91STakashi Iwai .channels_max = 2, 3724352f7f91STakashi Iwai .nid = 0, /* fill later */ 3725352f7f91STakashi Iwai .ops = { 3726352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 3727352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 3728352f7f91STakashi Iwai }, 3729352f7f91STakashi Iwai }; 3730352f7f91STakashi Iwai 3731f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 3732f873e536STakashi Iwai const char *chip_name) 3733f873e536STakashi Iwai { 3734f873e536STakashi Iwai char *p; 3735f873e536STakashi Iwai 3736f873e536STakashi Iwai if (*str) 3737f873e536STakashi Iwai return; 3738f873e536STakashi Iwai strlcpy(str, chip_name, len); 3739f873e536STakashi Iwai 3740f873e536STakashi Iwai /* drop non-alnum chars after a space */ 3741f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 3742f873e536STakashi Iwai if (!isalnum(p[1])) { 3743f873e536STakashi Iwai *p = 0; 3744f873e536STakashi Iwai break; 3745f873e536STakashi Iwai } 3746f873e536STakashi Iwai } 3747f873e536STakashi Iwai strlcat(str, sfx, len); 3748f873e536STakashi Iwai } 3749f873e536STakashi Iwai 3750352f7f91STakashi Iwai /* build PCM streams based on the parsed results */ 3751352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 3752352f7f91STakashi Iwai { 3753352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3754352f7f91STakashi Iwai struct hda_pcm *info = spec->pcm_rec; 3755352f7f91STakashi Iwai const struct hda_pcm_stream *p; 3756352f7f91STakashi Iwai bool have_multi_adcs; 3757352f7f91STakashi Iwai 37581da177e4SLinus Torvalds codec->num_pcms = 1; 37591da177e4SLinus Torvalds codec->pcm_info = info; 37601da177e4SLinus Torvalds 3761352f7f91STakashi Iwai if (spec->no_analog) 3762352f7f91STakashi Iwai goto skip_analog; 3763352f7f91STakashi Iwai 3764f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 3765f873e536STakashi Iwai sizeof(spec->stream_name_analog), 3766f873e536STakashi Iwai " Analog", codec->chip_name); 3767352f7f91STakashi Iwai info->name = spec->stream_name_analog; 3768352f7f91STakashi Iwai 3769352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 3770352f7f91STakashi Iwai p = spec->stream_analog_playback; 3771352f7f91STakashi Iwai if (!p) 3772352f7f91STakashi Iwai p = &pcm_analog_playback; 3773352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3774352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 3775352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 3776352f7f91STakashi Iwai spec->multiout.max_channels; 3777352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 3778352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 3779352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 3780352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 3781352f7f91STakashi Iwai } 3782352f7f91STakashi Iwai if (spec->num_adc_nids) { 3783352f7f91STakashi Iwai p = spec->stream_analog_capture; 3784352f7f91STakashi Iwai if (!p) { 3785352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3786352f7f91STakashi Iwai p = &dyn_adc_pcm_analog_capture; 3787352f7f91STakashi Iwai else 3788352f7f91STakashi Iwai p = &pcm_analog_capture; 3789352f7f91STakashi Iwai } 3790352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3791352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 3792352f7f91STakashi Iwai } 3793352f7f91STakashi Iwai 3794352f7f91STakashi Iwai skip_analog: 3795352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 3796352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 3797f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 3798352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 3799f873e536STakashi Iwai " Digital", codec->chip_name); 3800352f7f91STakashi Iwai codec->num_pcms = 2; 3801352f7f91STakashi Iwai codec->slave_dig_outs = spec->multiout.slave_dig_outs; 3802352f7f91STakashi Iwai info = spec->pcm_rec + 1; 3803352f7f91STakashi Iwai info->name = spec->stream_name_digital; 3804352f7f91STakashi Iwai if (spec->dig_out_type) 3805352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 3806352f7f91STakashi Iwai else 3807352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 3808352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3809352f7f91STakashi Iwai p = spec->stream_digital_playback; 3810352f7f91STakashi Iwai if (!p) 3811352f7f91STakashi Iwai p = &pcm_digital_playback; 3812352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3813352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 3814352f7f91STakashi Iwai } 3815352f7f91STakashi Iwai if (spec->dig_in_nid) { 3816352f7f91STakashi Iwai p = spec->stream_digital_capture; 3817352f7f91STakashi Iwai if (!p) 3818352f7f91STakashi Iwai p = &pcm_digital_capture; 3819352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3820352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 3821352f7f91STakashi Iwai } 3822352f7f91STakashi Iwai } 3823352f7f91STakashi Iwai 3824352f7f91STakashi Iwai if (spec->no_analog) 3825352f7f91STakashi Iwai return 0; 3826352f7f91STakashi Iwai 3827352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 3828352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 3829352f7f91STakashi Iwai */ 3830352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 3831352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 3832352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 3833352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 3834352f7f91STakashi Iwai codec->num_pcms = 3; 3835352f7f91STakashi Iwai info = spec->pcm_rec + 2; 3836352f7f91STakashi Iwai info->name = spec->stream_name_analog; 3837352f7f91STakashi Iwai if (spec->alt_dac_nid) { 3838352f7f91STakashi Iwai p = spec->stream_analog_alt_playback; 3839352f7f91STakashi Iwai if (!p) 3840352f7f91STakashi Iwai p = &pcm_analog_alt_playback; 3841352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3842352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 3843352f7f91STakashi Iwai spec->alt_dac_nid; 3844352f7f91STakashi Iwai } else { 3845352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 3846352f7f91STakashi Iwai pcm_null_stream; 3847352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; 3848352f7f91STakashi Iwai } 3849352f7f91STakashi Iwai if (have_multi_adcs) { 3850352f7f91STakashi Iwai p = spec->stream_analog_alt_capture; 3851352f7f91STakashi Iwai if (!p) 3852352f7f91STakashi Iwai p = &pcm_analog_alt_capture; 3853352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3854352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 3855352f7f91STakashi Iwai spec->adc_nids[1]; 3856352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 3857352f7f91STakashi Iwai spec->num_adc_nids - 1; 3858352f7f91STakashi Iwai } else { 3859352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = 3860352f7f91STakashi Iwai pcm_null_stream; 3861352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; 3862352f7f91STakashi Iwai } 38631da177e4SLinus Torvalds } 38641da177e4SLinus Torvalds 38651da177e4SLinus Torvalds return 0; 38661da177e4SLinus Torvalds } 3867352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); 3868352f7f91STakashi Iwai 3869352f7f91STakashi Iwai 3870352f7f91STakashi Iwai /* 3871352f7f91STakashi Iwai * Standard auto-parser initializations 3872352f7f91STakashi Iwai */ 3873352f7f91STakashi Iwai 3874d4156930STakashi Iwai /* configure the given path as a proper output */ 38752c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx) 3876352f7f91STakashi Iwai { 3877352f7f91STakashi Iwai struct nid_path *path; 3878d4156930STakashi Iwai hda_nid_t pin; 3879352f7f91STakashi Iwai 3880196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 3881d4156930STakashi Iwai if (!path || !path->depth) 3882352f7f91STakashi Iwai return; 3883d4156930STakashi Iwai pin = path->path[path->depth - 1]; 38842c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 3885e1284af7STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 3886e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 3887352f7f91STakashi Iwai } 3888352f7f91STakashi Iwai 3889352f7f91STakashi Iwai /* initialize primary output paths */ 3890352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 3891352f7f91STakashi Iwai { 3892352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3893352f7f91STakashi Iwai int i; 3894352f7f91STakashi Iwai 3895d4156930STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) 38962c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->out_paths[i]); 3897352f7f91STakashi Iwai } 3898352f7f91STakashi Iwai 3899db23fd19STakashi Iwai 39002c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) 3901352f7f91STakashi Iwai { 3902352f7f91STakashi Iwai int i; 3903352f7f91STakashi Iwai 3904d4156930STakashi Iwai for (i = 0; i < num_outs; i++) 39052c12c30dSTakashi Iwai set_output_and_unmute(codec, paths[i]); 3906352f7f91STakashi Iwai } 3907db23fd19STakashi Iwai 3908db23fd19STakashi Iwai /* initialize hp and speaker paths */ 3909db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 3910db23fd19STakashi Iwai { 3911db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3912db23fd19STakashi Iwai 3913db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 39142c12c30dSTakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); 3915db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 3916db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 39172c12c30dSTakashi Iwai spec->speaker_paths); 3918352f7f91STakashi Iwai } 3919352f7f91STakashi Iwai 3920352f7f91STakashi Iwai /* initialize multi-io paths */ 3921352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 3922352f7f91STakashi Iwai { 3923352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3924352f7f91STakashi Iwai int i; 3925352f7f91STakashi Iwai 3926352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 3927352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 3928352f7f91STakashi Iwai struct nid_path *path; 3929196c1766STakashi Iwai path = get_multiio_path(codec, i); 3930352f7f91STakashi Iwai if (!path) 3931352f7f91STakashi Iwai continue; 3932352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 3933352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 39342c12c30dSTakashi Iwai snd_hda_codec_get_pin_target(codec, pin); 3935352f7f91STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 3936352f7f91STakashi Iwai } 3937352f7f91STakashi Iwai } 3938352f7f91STakashi Iwai 3939352f7f91STakashi Iwai /* set up input pins and loopback paths */ 3940352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 3941352f7f91STakashi Iwai { 3942352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3943352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3944352f7f91STakashi Iwai int i; 3945352f7f91STakashi Iwai 3946352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3947352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 3948352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 39492c12c30dSTakashi Iwai restore_pin_ctl(codec, nid); 3950352f7f91STakashi Iwai 3951352f7f91STakashi Iwai /* init loopback inputs */ 3952352f7f91STakashi Iwai if (spec->mixer_nid) { 3953352f7f91STakashi Iwai struct nid_path *path; 3954196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]); 3955352f7f91STakashi Iwai if (path) 3956352f7f91STakashi Iwai snd_hda_activate_path(codec, path, 3957352f7f91STakashi Iwai path->active, false); 3958352f7f91STakashi Iwai } 3959352f7f91STakashi Iwai } 3960352f7f91STakashi Iwai } 3961352f7f91STakashi Iwai 3962352f7f91STakashi Iwai /* initialize ADC paths */ 3963352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 3964352f7f91STakashi Iwai { 3965352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3966352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3967352f7f91STakashi Iwai struct nid_path *path; 3968352f7f91STakashi Iwai int i, c, nums; 3969352f7f91STakashi Iwai 3970352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3971352f7f91STakashi Iwai nums = 1; 3972352f7f91STakashi Iwai else 3973352f7f91STakashi Iwai nums = spec->num_adc_nids; 3974352f7f91STakashi Iwai 3975352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 3976352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3977c697b716STakashi Iwai path = get_input_path(codec, c, i); 3978352f7f91STakashi Iwai if (path) { 3979352f7f91STakashi Iwai bool active = path->active; 3980352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 3981352f7f91STakashi Iwai active = true; 3982352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 3983352f7f91STakashi Iwai } 3984352f7f91STakashi Iwai } 3985352f7f91STakashi Iwai } 3986352f7f91STakashi Iwai 3987352f7f91STakashi Iwai if (spec->shared_mic_hp) 3988352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[0]); 3989352f7f91STakashi Iwai 3990352f7f91STakashi Iwai if (spec->cap_sync_hook) 3991352f7f91STakashi Iwai spec->cap_sync_hook(codec); 3992352f7f91STakashi Iwai } 3993352f7f91STakashi Iwai 3994352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 3995352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 3996352f7f91STakashi Iwai { 3997352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3998352f7f91STakashi Iwai int i; 3999352f7f91STakashi Iwai hda_nid_t pin; 4000352f7f91STakashi Iwai 4001d4156930STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) 40022c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->digout_paths[i]); 4003352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 40042430d7b7STakashi Iwai if (pin) { 40052430d7b7STakashi Iwai struct nid_path *path; 40062c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 40072430d7b7STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->digin_path); 40082430d7b7STakashi Iwai if (path) 40092430d7b7STakashi Iwai snd_hda_activate_path(codec, path, path->active, false); 40102430d7b7STakashi Iwai } 4011352f7f91STakashi Iwai } 4012352f7f91STakashi Iwai 4013973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 4014973e4972STakashi Iwai * invalid unsol tags by some reason 4015973e4972STakashi Iwai */ 4016973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 4017973e4972STakashi Iwai { 4018973e4972STakashi Iwai int i; 4019973e4972STakashi Iwai 4020973e4972STakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 4021973e4972STakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 4022973e4972STakashi Iwai hda_nid_t nid = pin->nid; 4023973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 4024973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 4025973e4972STakashi Iwai snd_hda_codec_update_cache(codec, nid, 0, 4026973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 4027973e4972STakashi Iwai } 4028973e4972STakashi Iwai } 4029973e4972STakashi Iwai 40305187ac16STakashi Iwai /* 40315187ac16STakashi Iwai * initialize the generic spec; 40325187ac16STakashi Iwai * this can be put as patch_ops.init function 40335187ac16STakashi Iwai */ 4034352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 4035352f7f91STakashi Iwai { 4036352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4037352f7f91STakashi Iwai 4038352f7f91STakashi Iwai if (spec->init_hook) 4039352f7f91STakashi Iwai spec->init_hook(codec); 4040352f7f91STakashi Iwai 4041352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 4042352f7f91STakashi Iwai 40433bbcd274STakashi Iwai codec->cached_write = 1; 40443bbcd274STakashi Iwai 4045352f7f91STakashi Iwai init_multi_out(codec); 4046352f7f91STakashi Iwai init_extra_out(codec); 4047352f7f91STakashi Iwai init_multi_io(codec); 4048352f7f91STakashi Iwai init_analog_input(codec); 4049352f7f91STakashi Iwai init_input_src(codec); 4050352f7f91STakashi Iwai init_digital(codec); 4051352f7f91STakashi Iwai 4052973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 4053973e4972STakashi Iwai 4054352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 40555d550e15STakashi Iwai snd_hda_gen_hp_automute(codec, NULL); 40565d550e15STakashi Iwai snd_hda_gen_line_automute(codec, NULL); 40575d550e15STakashi Iwai snd_hda_gen_mic_autoswitch(codec, NULL); 4058352f7f91STakashi Iwai 40593bbcd274STakashi Iwai snd_hda_codec_flush_amp_cache(codec); 40603bbcd274STakashi Iwai snd_hda_codec_flush_cmd_cache(codec); 40613bbcd274STakashi Iwai 4062352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 4063352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 4064352f7f91STakashi Iwai 4065352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 4066352f7f91STakashi Iwai return 0; 4067352f7f91STakashi Iwai } 4068fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_init); 4069fce52a3bSTakashi Iwai 40705187ac16STakashi Iwai /* 40715187ac16STakashi Iwai * free the generic spec; 40725187ac16STakashi Iwai * this can be put as patch_ops.free function 40735187ac16STakashi Iwai */ 4074fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec) 4075fce52a3bSTakashi Iwai { 4076fce52a3bSTakashi Iwai snd_hda_gen_spec_free(codec->spec); 4077fce52a3bSTakashi Iwai kfree(codec->spec); 4078fce52a3bSTakashi Iwai codec->spec = NULL; 4079fce52a3bSTakashi Iwai } 4080fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_free); 4081fce52a3bSTakashi Iwai 4082fce52a3bSTakashi Iwai #ifdef CONFIG_PM 40835187ac16STakashi Iwai /* 40845187ac16STakashi Iwai * check the loopback power save state; 40855187ac16STakashi Iwai * this can be put as patch_ops.check_power_status function 40865187ac16STakashi Iwai */ 4087fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) 4088fce52a3bSTakashi Iwai { 4089fce52a3bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 4090fce52a3bSTakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 4091fce52a3bSTakashi Iwai } 4092fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status); 4093fce52a3bSTakashi Iwai #endif 4094352f7f91STakashi Iwai 4095352f7f91STakashi Iwai 4096352f7f91STakashi Iwai /* 4097352f7f91STakashi Iwai * the generic codec support 4098352f7f91STakashi Iwai */ 40991da177e4SLinus Torvalds 4100352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 4101352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 4102352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 4103352f7f91STakashi Iwai .init = snd_hda_gen_init, 4104fce52a3bSTakashi Iwai .free = snd_hda_gen_free, 4105352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 410683012a7cSTakashi Iwai #ifdef CONFIG_PM 4107fce52a3bSTakashi Iwai .check_power_status = snd_hda_gen_check_power_status, 4108cb53c626STakashi Iwai #endif 41091da177e4SLinus Torvalds }; 41101da177e4SLinus Torvalds 41111da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec) 41121da177e4SLinus Torvalds { 4113352f7f91STakashi Iwai struct hda_gen_spec *spec; 41141da177e4SLinus Torvalds int err; 41151da177e4SLinus Torvalds 4116e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 4117352f7f91STakashi Iwai if (!spec) 41181da177e4SLinus Torvalds return -ENOMEM; 4119352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 41201da177e4SLinus Torvalds codec->spec = spec; 41211da177e4SLinus Torvalds 41229eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 41239eb413e5STakashi Iwai if (err < 0) 41249eb413e5STakashi Iwai return err; 41259eb413e5STakashi Iwai 41269eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 4127352f7f91STakashi Iwai if (err < 0) 41281da177e4SLinus Torvalds goto error; 41291da177e4SLinus Torvalds 41301da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 41311da177e4SLinus Torvalds return 0; 41321da177e4SLinus Torvalds 41331da177e4SLinus Torvalds error: 4134fce52a3bSTakashi Iwai snd_hda_gen_free(codec); 41351da177e4SLinus Torvalds return err; 41361da177e4SLinus Torvalds } 4137fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec); 4138