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->bind_ctls, sizeof(struct hda_bind_ctls *), 8); 43352f7f91STakashi Iwai snd_array_init(&spec->paths, sizeof(struct nid_path), 8); 4438cf6f1aSTakashi Iwai mutex_init(&spec->pcm_mutex); 45352f7f91STakashi Iwai return 0; 46352f7f91STakashi Iwai } 47352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init); 481da177e4SLinus Torvalds 4912c93df6STakashi Iwai struct snd_kcontrol_new * 5012c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, 51352f7f91STakashi Iwai const struct snd_kcontrol_new *temp) 52352f7f91STakashi Iwai { 53352f7f91STakashi Iwai struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); 54352f7f91STakashi Iwai if (!knew) 55352f7f91STakashi Iwai return NULL; 56352f7f91STakashi Iwai *knew = *temp; 57352f7f91STakashi Iwai if (name) 58352f7f91STakashi Iwai knew->name = kstrdup(name, GFP_KERNEL); 59352f7f91STakashi Iwai else if (knew->name) 60352f7f91STakashi Iwai knew->name = kstrdup(knew->name, GFP_KERNEL); 61352f7f91STakashi Iwai if (!knew->name) 62352f7f91STakashi Iwai return NULL; 63352f7f91STakashi Iwai return knew; 64352f7f91STakashi Iwai } 6512c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl); 66352f7f91STakashi Iwai 67352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec) 68352f7f91STakashi Iwai { 69352f7f91STakashi Iwai if (spec->kctls.list) { 70352f7f91STakashi Iwai struct snd_kcontrol_new *kctl = spec->kctls.list; 71352f7f91STakashi Iwai int i; 72352f7f91STakashi Iwai for (i = 0; i < spec->kctls.used; i++) 73352f7f91STakashi Iwai kfree(kctl[i].name); 74352f7f91STakashi Iwai } 75352f7f91STakashi Iwai snd_array_free(&spec->kctls); 76352f7f91STakashi Iwai } 77352f7f91STakashi Iwai 78352f7f91STakashi Iwai static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec, 79352f7f91STakashi Iwai unsigned int nums, 80352f7f91STakashi Iwai struct hda_ctl_ops *ops) 81352f7f91STakashi Iwai { 82352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 83352f7f91STakashi Iwai struct hda_bind_ctls **ctlp, *ctl; 84352f7f91STakashi Iwai ctlp = snd_array_new(&spec->bind_ctls); 85352f7f91STakashi Iwai if (!ctlp) 86352f7f91STakashi Iwai return NULL; 87352f7f91STakashi Iwai ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL); 88352f7f91STakashi Iwai *ctlp = ctl; 89352f7f91STakashi Iwai if (ctl) 90352f7f91STakashi Iwai ctl->ops = ops; 91352f7f91STakashi Iwai return ctl; 92352f7f91STakashi Iwai } 93352f7f91STakashi Iwai 94352f7f91STakashi Iwai static void free_bind_ctls(struct hda_gen_spec *spec) 95352f7f91STakashi Iwai { 96352f7f91STakashi Iwai if (spec->bind_ctls.list) { 97352f7f91STakashi Iwai struct hda_bind_ctls **ctl = spec->bind_ctls.list; 98352f7f91STakashi Iwai int i; 99352f7f91STakashi Iwai for (i = 0; i < spec->bind_ctls.used; i++) 100352f7f91STakashi Iwai kfree(ctl[i]); 101352f7f91STakashi Iwai } 102352f7f91STakashi Iwai snd_array_free(&spec->bind_ctls); 103352f7f91STakashi Iwai } 104352f7f91STakashi Iwai 105352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec) 106352f7f91STakashi Iwai { 1071da177e4SLinus Torvalds if (!spec) 1081da177e4SLinus Torvalds return; 109352f7f91STakashi Iwai free_kctls(spec); 110352f7f91STakashi Iwai free_bind_ctls(spec); 111352f7f91STakashi Iwai snd_array_free(&spec->paths); 1121da177e4SLinus Torvalds } 113352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free); 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /* 116352f7f91STakashi Iwai * parsing paths 1171da177e4SLinus Torvalds */ 1181da177e4SLinus Torvalds 119f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec, 120f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 121f5172a7eSTakashi Iwai int with_aa_mix) 1221da177e4SLinus Torvalds { 123352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 124352f7f91STakashi Iwai int i; 1251da177e4SLinus Torvalds 126352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 127352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 128352f7f91STakashi Iwai if (path->depth <= 0) 129352f7f91STakashi Iwai continue; 130352f7f91STakashi Iwai if ((!from_nid || path->path[0] == from_nid) && 131f5172a7eSTakashi Iwai (!to_nid || path->path[path->depth - 1] == to_nid)) { 132f5172a7eSTakashi Iwai if (with_aa_mix == HDA_PARSE_ALL || 133f5172a7eSTakashi Iwai path->with_aa_mix == with_aa_mix) 134352f7f91STakashi Iwai return path; 1351da177e4SLinus Torvalds } 136f5172a7eSTakashi Iwai } 1371da177e4SLinus Torvalds return NULL; 1381da177e4SLinus Torvalds } 139f5172a7eSTakashi Iwai 140f5172a7eSTakashi Iwai /* get the path between the given NIDs; 141f5172a7eSTakashi Iwai * passing 0 to either @pin or @dac behaves as a wildcard 142f5172a7eSTakashi Iwai */ 143f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, 144f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 145f5172a7eSTakashi Iwai { 146f5172a7eSTakashi Iwai return get_nid_path(codec, from_nid, to_nid, HDA_PARSE_ALL); 147f5172a7eSTakashi Iwai } 148352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path); 1491da177e4SLinus Torvalds 150196c1766STakashi Iwai /* get the index number corresponding to the path instance; 151196c1766STakashi Iwai * the index starts from 1, for easier checking the invalid value 152196c1766STakashi Iwai */ 153196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) 154196c1766STakashi Iwai { 155196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 156196c1766STakashi Iwai struct nid_path *array = spec->paths.list; 157196c1766STakashi Iwai ssize_t idx; 158196c1766STakashi Iwai 159196c1766STakashi Iwai if (!spec->paths.used) 160196c1766STakashi Iwai return 0; 161196c1766STakashi Iwai idx = path - array; 162196c1766STakashi Iwai if (idx < 0 || idx >= spec->paths.used) 163196c1766STakashi Iwai return 0; 164196c1766STakashi Iwai return idx + 1; 165196c1766STakashi Iwai } 166196c1766STakashi Iwai 167196c1766STakashi Iwai /* get the path instance corresponding to the given index number */ 168196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) 169196c1766STakashi Iwai { 170196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 171196c1766STakashi Iwai 172196c1766STakashi Iwai if (idx <= 0 || idx > spec->paths.used) 173196c1766STakashi Iwai return NULL; 174196c1766STakashi Iwai return snd_array_elem(&spec->paths, idx - 1); 175196c1766STakashi Iwai } 176196c1766STakashi Iwai 177352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */ 178352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) 1791da177e4SLinus Torvalds { 180352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 181352f7f91STakashi Iwai int i; 182352f7f91STakashi Iwai 183352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 184352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 185352f7f91STakashi Iwai if (path->path[0] == nid) 186352f7f91STakashi Iwai return true; 187352f7f91STakashi Iwai } 188352f7f91STakashi Iwai return false; 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 191352f7f91STakashi Iwai /* check whether the given two widgets can be connected */ 192352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec, 193352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 1941da177e4SLinus Torvalds { 195352f7f91STakashi Iwai if (!from_nid || !to_nid) 196352f7f91STakashi Iwai return false; 197352f7f91STakashi Iwai return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 200352f7f91STakashi Iwai /* nid, dir and idx */ 201352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) 202352f7f91STakashi Iwai 203352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */ 204352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) 2051da177e4SLinus Torvalds { 206352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 207352f7f91STakashi Iwai int i; 208352f7f91STakashi Iwai 209352f7f91STakashi Iwai val &= AMP_VAL_COMPARE_MASK; 210352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 211352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 212352f7f91STakashi Iwai if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) 213352f7f91STakashi Iwai return true; 214352f7f91STakashi Iwai } 215352f7f91STakashi Iwai return false; 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 218352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */ 219352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, 220cb53c626STakashi Iwai int dir, int idx) 221cb53c626STakashi Iwai { 222352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); 223352f7f91STakashi Iwai return is_ctl_used(codec, val, NID_PATH_VOL_CTL) || 224352f7f91STakashi Iwai is_ctl_used(codec, val, NID_PATH_MUTE_CTL); 225cb53c626STakashi Iwai } 226352f7f91STakashi Iwai 2270c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path) 2280c8c0f56STakashi Iwai { 2290c8c0f56STakashi Iwai char buf[40]; 2300c8c0f56STakashi Iwai int i; 2310c8c0f56STakashi Iwai 2320c8c0f56STakashi Iwai 2330c8c0f56STakashi Iwai buf[0] = 0; 2340c8c0f56STakashi Iwai for (i = 0; i < path->depth; i++) { 2350c8c0f56STakashi Iwai char tmp[4]; 2360c8c0f56STakashi Iwai sprintf(tmp, ":%02x", path->path[i]); 2370c8c0f56STakashi Iwai strlcat(buf, tmp, sizeof(buf)); 2380c8c0f56STakashi Iwai } 2390c8c0f56STakashi Iwai snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf); 2400c8c0f56STakashi Iwai } 2410c8c0f56STakashi Iwai 242352f7f91STakashi Iwai /* called recursively */ 243352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec, 244352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 245352f7f91STakashi Iwai int with_aa_mix, struct nid_path *path, int depth) 246352f7f91STakashi Iwai { 247352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 248ee8e765bSTakashi Iwai const hda_nid_t *conn; 249352f7f91STakashi Iwai int i, nums; 250352f7f91STakashi Iwai 251352f7f91STakashi Iwai if (to_nid == spec->mixer_nid) { 2524ac0eefaSTakashi Iwai if (with_aa_mix == HDA_PARSE_NO_AAMIX) 253352f7f91STakashi Iwai return false; 2544ac0eefaSTakashi Iwai with_aa_mix = HDA_PARSE_ALL; /* mark aa-mix is included */ 255352f7f91STakashi Iwai } 256352f7f91STakashi Iwai 257ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn); 258352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 259352f7f91STakashi Iwai if (conn[i] != from_nid) { 260352f7f91STakashi Iwai /* special case: when from_nid is 0, 261352f7f91STakashi Iwai * try to find an empty DAC 262352f7f91STakashi Iwai */ 263352f7f91STakashi Iwai if (from_nid || 264352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || 265352f7f91STakashi Iwai is_dac_already_used(codec, conn[i])) 266352f7f91STakashi Iwai continue; 267352f7f91STakashi Iwai } 268352f7f91STakashi Iwai /* aa-mix is requested but not included? */ 2694ac0eefaSTakashi Iwai if (!(spec->mixer_nid && with_aa_mix == HDA_PARSE_ONLY_AAMIX)) 270352f7f91STakashi Iwai goto found; 271352f7f91STakashi Iwai } 272352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH) 273352f7f91STakashi Iwai return false; 274352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 275352f7f91STakashi Iwai unsigned int type; 276352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i])); 277352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || 278352f7f91STakashi Iwai type == AC_WID_PIN) 279352f7f91STakashi Iwai continue; 280352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i], 281352f7f91STakashi Iwai with_aa_mix, path, depth + 1)) 282352f7f91STakashi Iwai goto found; 283352f7f91STakashi Iwai } 284352f7f91STakashi Iwai return false; 285352f7f91STakashi Iwai 286352f7f91STakashi Iwai found: 287352f7f91STakashi Iwai path->path[path->depth] = conn[i]; 288f5172a7eSTakashi Iwai if (conn[i] == spec->mixer_nid) 289f5172a7eSTakashi Iwai path->with_aa_mix = true; 290352f7f91STakashi Iwai path->idx[path->depth + 1] = i; 291352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) 292352f7f91STakashi Iwai path->multi[path->depth + 1] = 1; 293352f7f91STakashi Iwai path->depth++; 294352f7f91STakashi Iwai return true; 295352f7f91STakashi Iwai } 296352f7f91STakashi Iwai 297352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid; 298352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC; 2994ac0eefaSTakashi Iwai * when @with_aa_mix is HDA_PARSE_NO_AAMIX, paths with spec->mixer_nid are 3004ac0eefaSTakashi Iwai * excluded, only the paths that don't go through the mixer will be chosen. 3014ac0eefaSTakashi Iwai * when @with_aa_mix is HDA_PARSE_ONLY_AAMIX, only the paths going through 3024ac0eefaSTakashi Iwai * spec->mixer_nid will be chosen. 3034ac0eefaSTakashi Iwai * when @with_aa_mix is HDA_PARSE_ALL, no special handling about mixer widget. 304352f7f91STakashi Iwai */ 305352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, 306352f7f91STakashi Iwai hda_nid_t to_nid, int with_aa_mix, 307352f7f91STakashi Iwai struct nid_path *path) 308352f7f91STakashi Iwai { 309352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path, 1)) { 310352f7f91STakashi Iwai path->path[path->depth] = to_nid; 311352f7f91STakashi Iwai path->depth++; 312352f7f91STakashi Iwai return true; 313352f7f91STakashi Iwai } 314352f7f91STakashi Iwai return false; 315352f7f91STakashi Iwai } 316352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path); 317352f7f91STakashi Iwai 318352f7f91STakashi Iwai /* 319352f7f91STakashi Iwai * parse the path between the given NIDs and add to the path list. 320352f7f91STakashi Iwai * if no valid path is found, return NULL 321352f7f91STakashi Iwai */ 322352f7f91STakashi Iwai struct nid_path * 323352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, 324352f7f91STakashi Iwai hda_nid_t to_nid, int with_aa_mix) 325352f7f91STakashi Iwai { 326352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 327352f7f91STakashi Iwai struct nid_path *path; 328352f7f91STakashi Iwai 329352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) 330352f7f91STakashi Iwai return NULL; 331352f7f91STakashi Iwai 332f5172a7eSTakashi Iwai /* check whether the path has been already added */ 333f5172a7eSTakashi Iwai path = get_nid_path(codec, from_nid, to_nid, with_aa_mix); 334f5172a7eSTakashi Iwai if (path) 335f5172a7eSTakashi Iwai return path; 336f5172a7eSTakashi Iwai 337352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 338352f7f91STakashi Iwai if (!path) 339352f7f91STakashi Iwai return NULL; 340352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 341352f7f91STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path)) 342352f7f91STakashi Iwai return path; 343352f7f91STakashi Iwai /* push back */ 344352f7f91STakashi Iwai spec->paths.used--; 345352f7f91STakashi Iwai return NULL; 346352f7f91STakashi Iwai } 347352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path); 348352f7f91STakashi Iwai 349352f7f91STakashi Iwai /* look for an empty DAC slot */ 350352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, 351352f7f91STakashi Iwai bool is_digital) 352352f7f91STakashi Iwai { 353352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 354352f7f91STakashi Iwai bool cap_digital; 355352f7f91STakashi Iwai int i; 356352f7f91STakashi Iwai 357352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 358352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 359352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 360352f7f91STakashi Iwai continue; 361352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); 362352f7f91STakashi Iwai if (is_digital != cap_digital) 363352f7f91STakashi Iwai continue; 364352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) 365352f7f91STakashi Iwai return nid; 366352f7f91STakashi Iwai } 367352f7f91STakashi Iwai return 0; 368352f7f91STakashi Iwai } 369352f7f91STakashi Iwai 370352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */ 371352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) 372352f7f91STakashi Iwai { 373352f7f91STakashi Iwai val &= ~(0x3U << 16); 374352f7f91STakashi Iwai val |= chs << 16; 375352f7f91STakashi Iwai return val; 376352f7f91STakashi Iwai } 377352f7f91STakashi Iwai 378352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */ 379352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, 380352f7f91STakashi Iwai int dir, unsigned int bits) 381352f7f91STakashi Iwai { 382352f7f91STakashi Iwai if (!nid) 383352f7f91STakashi Iwai return false; 384352f7f91STakashi Iwai if (get_wcaps(codec, nid) & (1 << (dir + 1))) 385352f7f91STakashi Iwai if (query_amp_caps(codec, nid, dir) & bits) 386352f7f91STakashi Iwai return true; 387352f7f91STakashi Iwai return false; 388352f7f91STakashi Iwai } 389352f7f91STakashi Iwai 390352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \ 391352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) 392352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \ 393352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) 394352f7f91STakashi Iwai 395352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */ 396352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, 397352f7f91STakashi Iwai struct nid_path *path) 398352f7f91STakashi Iwai { 399352f7f91STakashi Iwai int i; 400352f7f91STakashi Iwai 401352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 402352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) 403352f7f91STakashi Iwai return path->path[i]; 404352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 && 405352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT)) 406352f7f91STakashi Iwai return path->path[i]; 407352f7f91STakashi Iwai } 408352f7f91STakashi Iwai return 0; 409352f7f91STakashi Iwai } 410352f7f91STakashi Iwai 411352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */ 412352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, 413352f7f91STakashi Iwai struct nid_path *path) 414352f7f91STakashi Iwai { 415352f7f91STakashi Iwai int i; 416352f7f91STakashi Iwai 417352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 418352f7f91STakashi Iwai if (nid_has_volume(codec, path->path[i], HDA_OUTPUT)) 419352f7f91STakashi Iwai return path->path[i]; 420352f7f91STakashi Iwai } 421352f7f91STakashi Iwai return 0; 422352f7f91STakashi Iwai } 423352f7f91STakashi Iwai 424352f7f91STakashi Iwai /* 425352f7f91STakashi Iwai * path activation / deactivation 426352f7f91STakashi Iwai */ 427352f7f91STakashi Iwai 428352f7f91STakashi Iwai /* can have the amp-in capability? */ 429352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) 430352f7f91STakashi Iwai { 431352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 432352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 433352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 434352f7f91STakashi Iwai 435352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP)) 436352f7f91STakashi Iwai return false; 437352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */ 438352f7f91STakashi Iwai return false; 439352f7f91STakashi Iwai return true; 440352f7f91STakashi Iwai } 441352f7f91STakashi Iwai 442352f7f91STakashi Iwai /* can have the amp-out capability? */ 443352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) 444352f7f91STakashi Iwai { 445352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 446352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 447352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 448352f7f91STakashi Iwai 449352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP)) 450352f7f91STakashi Iwai return false; 451352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */ 452352f7f91STakashi Iwai return false; 453352f7f91STakashi Iwai return true; 454352f7f91STakashi Iwai } 455352f7f91STakashi Iwai 456352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */ 457352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, 458352f7f91STakashi Iwai unsigned int idx, unsigned int dir) 459352f7f91STakashi Iwai { 460352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 461352f7f91STakashi Iwai int i, n; 462352f7f91STakashi Iwai 463352f7f91STakashi Iwai for (n = 0; n < spec->paths.used; n++) { 464352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, n); 465352f7f91STakashi Iwai if (!path->active) 466352f7f91STakashi Iwai continue; 467352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) { 468352f7f91STakashi Iwai if (path->path[i] == nid) { 469352f7f91STakashi Iwai if (dir == HDA_OUTPUT || path->idx[i] == idx) 470352f7f91STakashi Iwai return true; 471352f7f91STakashi Iwai break; 472352f7f91STakashi Iwai } 473352f7f91STakashi Iwai } 474352f7f91STakashi Iwai } 475352f7f91STakashi Iwai return false; 476352f7f91STakashi Iwai } 477352f7f91STakashi Iwai 478352f7f91STakashi Iwai /* get the default amp value for the target state */ 479352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, 480352f7f91STakashi Iwai int dir, bool enable) 481352f7f91STakashi Iwai { 482352f7f91STakashi Iwai unsigned int caps; 483352f7f91STakashi Iwai unsigned int val = 0; 484352f7f91STakashi Iwai 485352f7f91STakashi Iwai caps = query_amp_caps(codec, nid, dir); 486352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 487352f7f91STakashi Iwai /* set to 0dB */ 488352f7f91STakashi Iwai if (enable) 489352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 490352f7f91STakashi Iwai } 491352f7f91STakashi Iwai if (caps & AC_AMPCAP_MUTE) { 492352f7f91STakashi Iwai if (!enable) 493352f7f91STakashi Iwai val |= HDA_AMP_MUTE; 494352f7f91STakashi Iwai } 495352f7f91STakashi Iwai return val; 496352f7f91STakashi Iwai } 497352f7f91STakashi Iwai 498352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */ 499352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 500352f7f91STakashi Iwai { 501352f7f91STakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, false); 502352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 503352f7f91STakashi Iwai } 504352f7f91STakashi Iwai 505352f7f91STakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, 506352f7f91STakashi Iwai int idx, bool enable) 507352f7f91STakashi Iwai { 508352f7f91STakashi Iwai int val; 509352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, dir, idx) || 510985803caSTakashi Iwai (!enable && is_active_nid(codec, nid, dir, idx))) 511352f7f91STakashi Iwai return; 512352f7f91STakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, enable); 513352f7f91STakashi Iwai snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val); 514352f7f91STakashi Iwai } 515352f7f91STakashi Iwai 516352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, 517352f7f91STakashi Iwai int i, bool enable) 518352f7f91STakashi Iwai { 519352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 520352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0); 521352f7f91STakashi Iwai activate_amp(codec, nid, HDA_OUTPUT, 0, enable); 522352f7f91STakashi Iwai } 523352f7f91STakashi Iwai 524352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, 525352f7f91STakashi Iwai int i, bool enable, bool add_aamix) 526352f7f91STakashi Iwai { 527352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 528ee8e765bSTakashi Iwai const hda_nid_t *conn; 529352f7f91STakashi Iwai int n, nums, idx; 530352f7f91STakashi Iwai int type; 531352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 532352f7f91STakashi Iwai 533ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn); 534352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 535352f7f91STakashi Iwai if (type == AC_WID_PIN || 536352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) { 537352f7f91STakashi Iwai nums = 1; 538352f7f91STakashi Iwai idx = 0; 539352f7f91STakashi Iwai } else 540352f7f91STakashi Iwai idx = path->idx[i]; 541352f7f91STakashi Iwai 542352f7f91STakashi Iwai for (n = 0; n < nums; n++) 543352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n); 544352f7f91STakashi Iwai 545352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, HDA_INPUT, idx)) 546352f7f91STakashi Iwai return; 547352f7f91STakashi Iwai 548352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out(); 549352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well 550352f7f91STakashi Iwai */ 551352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 552352f7f91STakashi Iwai if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid)) 553352f7f91STakashi Iwai continue; 554352f7f91STakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, enable); 555352f7f91STakashi Iwai } 556352f7f91STakashi Iwai } 557352f7f91STakashi Iwai 558352f7f91STakashi Iwai /* activate or deactivate the given path 559352f7f91STakashi Iwai * if @add_aamix is set, enable the input from aa-mix NID as well (if any) 560352f7f91STakashi Iwai */ 561352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, 562352f7f91STakashi Iwai bool enable, bool add_aamix) 563352f7f91STakashi Iwai { 564352f7f91STakashi Iwai int i; 565352f7f91STakashi Iwai 566352f7f91STakashi Iwai if (!enable) 567352f7f91STakashi Iwai path->active = false; 568352f7f91STakashi Iwai 569352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 570352f7f91STakashi Iwai if (enable && path->multi[i]) 571352f7f91STakashi Iwai snd_hda_codec_write_cache(codec, path->path[i], 0, 572352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL, 573352f7f91STakashi Iwai path->idx[i]); 574352f7f91STakashi Iwai if (has_amp_in(codec, path, i)) 575352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix); 576352f7f91STakashi Iwai if (has_amp_out(codec, path, i)) 577352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable); 578352f7f91STakashi Iwai } 579352f7f91STakashi Iwai 580352f7f91STakashi Iwai if (enable) 581352f7f91STakashi Iwai path->active = true; 582352f7f91STakashi Iwai } 583352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path); 584352f7f91STakashi Iwai 585d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */ 586d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) 587d5a9f1bbSTakashi Iwai { 588d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 589d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl || 590d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) 591d5a9f1bbSTakashi Iwai return; 592ecac3ed1STakashi Iwai if (codec->inv_eapd) 593ecac3ed1STakashi Iwai enable = !enable; 594d5a9f1bbSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 595d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE, 596d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00); 597d5a9f1bbSTakashi Iwai } 598d5a9f1bbSTakashi Iwai 599352f7f91STakashi Iwai 600352f7f91STakashi Iwai /* 601352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements 602352f7f91STakashi Iwai */ 603352f7f91STakashi Iwai 604352f7f91STakashi Iwai enum { 605352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL, 606352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE, 607352f7f91STakashi Iwai HDA_CTL_BIND_MUTE, 608352f7f91STakashi Iwai HDA_CTL_BIND_VOL, 609352f7f91STakashi Iwai HDA_CTL_BIND_SW, 610352f7f91STakashi Iwai }; 611352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = { 612352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0), 613352f7f91STakashi Iwai HDA_CODEC_MUTE(NULL, 0, 0, 0), 614352f7f91STakashi Iwai HDA_BIND_MUTE(NULL, 0, 0, 0), 615352f7f91STakashi Iwai HDA_BIND_VOL(NULL, 0), 616352f7f91STakashi Iwai HDA_BIND_SW(NULL, 0), 617352f7f91STakashi Iwai }; 618352f7f91STakashi Iwai 619352f7f91STakashi Iwai /* add dynamic controls from template */ 620352f7f91STakashi Iwai static int add_control(struct hda_gen_spec *spec, int type, const char *name, 621352f7f91STakashi Iwai int cidx, unsigned long val) 622352f7f91STakashi Iwai { 623352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 624352f7f91STakashi Iwai 62512c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); 626352f7f91STakashi Iwai if (!knew) 627352f7f91STakashi Iwai return -ENOMEM; 628352f7f91STakashi Iwai knew->index = cidx; 629352f7f91STakashi Iwai if (get_amp_nid_(val)) 630352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 631352f7f91STakashi Iwai knew->private_value = val; 632352f7f91STakashi Iwai return 0; 633352f7f91STakashi Iwai } 634352f7f91STakashi Iwai 635352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type, 636352f7f91STakashi Iwai const char *pfx, const char *dir, 637352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val) 638352f7f91STakashi Iwai { 639352f7f91STakashi Iwai char name[32]; 640352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 641352f7f91STakashi Iwai return add_control(spec, type, name, cidx, val); 642352f7f91STakashi Iwai } 643352f7f91STakashi Iwai 644352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \ 645352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) 646352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \ 647352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) 648352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ 649352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) 650352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 651352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 652352f7f91STakashi Iwai 653352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, 654352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 655352f7f91STakashi Iwai { 656352f7f91STakashi Iwai unsigned int val; 657352f7f91STakashi Iwai if (!path) 658352f7f91STakashi Iwai return 0; 659352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL]; 660352f7f91STakashi Iwai if (!val) 661352f7f91STakashi Iwai return 0; 662352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 663352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); 664352f7f91STakashi Iwai } 665352f7f91STakashi Iwai 666352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */ 667352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, 668352f7f91STakashi Iwai int type) 669352f7f91STakashi Iwai { 670352f7f91STakashi Iwai int chs = 1; /* mono (left only) */ 671352f7f91STakashi Iwai if (path) { 672352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]); 673352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) 674352f7f91STakashi Iwai chs = 3; /* stereo */ 675352f7f91STakashi Iwai } 676352f7f91STakashi Iwai return chs; 677352f7f91STakashi Iwai } 678352f7f91STakashi Iwai 679352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, 680352f7f91STakashi Iwai struct nid_path *path) 681352f7f91STakashi Iwai { 682352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); 683352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path); 684352f7f91STakashi Iwai } 685352f7f91STakashi Iwai 686352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget; 687352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute 688352f7f91STakashi Iwai */ 689352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, 690352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 691352f7f91STakashi Iwai { 692352f7f91STakashi Iwai unsigned int val; 693352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE; 694352f7f91STakashi Iwai 695352f7f91STakashi Iwai if (!path) 696352f7f91STakashi Iwai return 0; 697352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL]; 698352f7f91STakashi Iwai if (!val) 699352f7f91STakashi Iwai return 0; 700352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 701352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) { 702352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val); 703352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid); 704352f7f91STakashi Iwai if (nums > 1) { 705352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE; 706352f7f91STakashi Iwai val |= nums << 19; 707352f7f91STakashi Iwai } 708352f7f91STakashi Iwai } 709352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 710352f7f91STakashi Iwai } 711352f7f91STakashi Iwai 712352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx, 713352f7f91STakashi Iwai int cidx, struct nid_path *path) 714352f7f91STakashi Iwai { 715352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); 716352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path); 717352f7f91STakashi Iwai } 718352f7f91STakashi Iwai 719352f7f91STakashi Iwai static const char * const channel_name[4] = { 720352f7f91STakashi Iwai "Front", "Surround", "CLFE", "Side" 721352f7f91STakashi Iwai }; 722352f7f91STakashi Iwai 723352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */ 724352f7f91STakashi Iwai static const char *get_line_out_pfx(struct hda_gen_spec *spec, int ch, 725352f7f91STakashi Iwai bool can_be_master, int *index) 726352f7f91STakashi Iwai { 727352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 728352f7f91STakashi Iwai 729352f7f91STakashi Iwai *index = 0; 730352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios && 731352f7f91STakashi Iwai !cfg->hp_outs && !cfg->speaker_outs && can_be_master) 732352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 733352f7f91STakashi Iwai 734352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths, 735352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present) 736352f7f91STakashi Iwai */ 737352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && 738352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) 739352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 740352f7f91STakashi Iwai 741352f7f91STakashi Iwai switch (cfg->line_out_type) { 742352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT: 743352f7f91STakashi Iwai if (cfg->line_outs == 1) 744352f7f91STakashi Iwai return "Speaker"; 745352f7f91STakashi Iwai if (cfg->line_outs == 2) 746352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker"; 747352f7f91STakashi Iwai break; 748352f7f91STakashi Iwai case AUTO_PIN_HP_OUT: 749352f7f91STakashi Iwai /* for multi-io case, only the primary out */ 750352f7f91STakashi Iwai if (ch && spec->multi_ios) 751352f7f91STakashi Iwai break; 752352f7f91STakashi Iwai *index = ch; 753352f7f91STakashi Iwai return "Headphone"; 754352f7f91STakashi Iwai default: 755352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios) 756352f7f91STakashi Iwai return "PCM"; 757352f7f91STakashi Iwai break; 758352f7f91STakashi Iwai } 759352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) { 760352f7f91STakashi Iwai snd_BUG(); 761352f7f91STakashi Iwai return "PCM"; 762352f7f91STakashi Iwai } 763352f7f91STakashi Iwai 764352f7f91STakashi Iwai return channel_name[ch]; 765352f7f91STakashi Iwai } 766352f7f91STakashi Iwai 767352f7f91STakashi Iwai /* 768352f7f91STakashi Iwai * Parse output paths 769352f7f91STakashi Iwai */ 770352f7f91STakashi Iwai 771352f7f91STakashi Iwai /* badness definition */ 772352f7f91STakashi Iwai enum { 773352f7f91STakashi Iwai /* No primary DAC is found for the main output */ 774352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000, 775352f7f91STakashi Iwai /* No DAC is found for the extra output */ 776352f7f91STakashi Iwai BAD_NO_DAC = 0x4000, 777352f7f91STakashi Iwai /* No possible multi-ios */ 778352f7f91STakashi Iwai BAD_MULTI_IO = 0x103, 779352f7f91STakashi Iwai /* No individual DAC for extra output */ 780352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102, 781352f7f91STakashi Iwai /* No individual DAC for extra surrounds */ 782352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101, 783352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */ 784352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100, 785352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */ 786352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10, 787352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */ 788352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10, 789352f7f91STakashi Iwai /* Volume widget is shared */ 790352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10, 791352f7f91STakashi Iwai }; 792352f7f91STakashi Iwai 793352f7f91STakashi Iwai /* look for widgets in the path between the given NIDs appropriate for 794352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[]. 795352f7f91STakashi Iwai * 796352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value 797352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the 798352f7f91STakashi Iwai * total badness for both volume and mute controls. 799352f7f91STakashi Iwai */ 800352f7f91STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, hda_nid_t pin, 801352f7f91STakashi Iwai hda_nid_t dac) 802352f7f91STakashi Iwai { 803352f7f91STakashi Iwai struct nid_path *path = snd_hda_get_nid_path(codec, dac, pin); 804352f7f91STakashi Iwai hda_nid_t nid; 805352f7f91STakashi Iwai unsigned int val; 806352f7f91STakashi Iwai int badness = 0; 807352f7f91STakashi Iwai 808352f7f91STakashi Iwai if (!path) 809352f7f91STakashi Iwai return BAD_SHARED_VOL * 2; 810352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path); 811352f7f91STakashi Iwai if (nid) { 812352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 813352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) 814352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 815352f7f91STakashi Iwai else 816352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 817352f7f91STakashi Iwai } else 818352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 819352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path); 820352f7f91STakashi Iwai if (nid) { 821352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); 822352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || 823352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT)) 824352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 825352f7f91STakashi Iwai else 826352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 827352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) 828352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 829352f7f91STakashi Iwai else 830352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 831352f7f91STakashi Iwai } else 832352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 833352f7f91STakashi Iwai return badness; 834352f7f91STakashi Iwai } 835352f7f91STakashi Iwai 836352f7f91STakashi Iwai struct badness_table { 837352f7f91STakashi Iwai int no_primary_dac; /* no primary DAC */ 838352f7f91STakashi Iwai int no_dac; /* no secondary DACs */ 839352f7f91STakashi Iwai int shared_primary; /* primary DAC is shared with main output */ 840352f7f91STakashi Iwai int shared_surr; /* secondary DAC shared with main or primary */ 841352f7f91STakashi Iwai int shared_clfe; /* third DAC shared with main or primary */ 842352f7f91STakashi Iwai int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ 843352f7f91STakashi Iwai }; 844352f7f91STakashi Iwai 845352f7f91STakashi Iwai static struct badness_table main_out_badness = { 846352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC, 847352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 848352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC, 849352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND, 850352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE, 851352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND, 852352f7f91STakashi Iwai }; 853352f7f91STakashi Iwai 854352f7f91STakashi Iwai static struct badness_table extra_out_badness = { 855352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC, 856352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 857352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC, 858352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND, 859352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND, 860352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, 861352f7f91STakashi Iwai }; 862352f7f91STakashi Iwai 863352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */ 864352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs, 865352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, 866196c1766STakashi Iwai int *path_idx, 867352f7f91STakashi Iwai const struct badness_table *bad) 868352f7f91STakashi Iwai { 869352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 870352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 871352f7f91STakashi Iwai int i, j; 872352f7f91STakashi Iwai int badness = 0; 873352f7f91STakashi Iwai hda_nid_t dac; 874352f7f91STakashi Iwai 875352f7f91STakashi Iwai if (!num_outs) 876352f7f91STakashi Iwai return 0; 877352f7f91STakashi Iwai 878352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) { 8790c8c0f56STakashi Iwai struct nid_path *path; 880352f7f91STakashi Iwai hda_nid_t pin = pins[i]; 8811e0b5286STakashi Iwai 8821e0b5286STakashi Iwai if (dacs[i]) { 8831e0b5286STakashi Iwai badness += assign_out_path_ctls(codec, pin, dacs[i]); 8841e0b5286STakashi Iwai continue; 8851e0b5286STakashi Iwai } 8861e0b5286STakashi Iwai 887352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false); 888352f7f91STakashi Iwai if (!dacs[i] && !i) { 889352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) { 890352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) { 891352f7f91STakashi Iwai dacs[0] = dacs[j]; 892352f7f91STakashi Iwai dacs[j] = 0; 893196c1766STakashi Iwai path_idx[j] = 0; 894352f7f91STakashi Iwai break; 895352f7f91STakashi Iwai } 896352f7f91STakashi Iwai } 897352f7f91STakashi Iwai } 898352f7f91STakashi Iwai dac = dacs[i]; 899352f7f91STakashi Iwai if (!dac) { 900352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[0], pin)) 901352f7f91STakashi Iwai dac = dacs[0]; 902352f7f91STakashi Iwai else if (cfg->line_outs > i && 903352f7f91STakashi Iwai is_reachable_path(codec, spec->private_dac_nids[i], pin)) 904352f7f91STakashi Iwai dac = spec->private_dac_nids[i]; 905352f7f91STakashi Iwai if (dac) { 906352f7f91STakashi Iwai if (!i) 907352f7f91STakashi Iwai badness += bad->shared_primary; 908352f7f91STakashi Iwai else if (i == 1) 909352f7f91STakashi Iwai badness += bad->shared_surr; 910352f7f91STakashi Iwai else 911352f7f91STakashi Iwai badness += bad->shared_clfe; 912352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { 913352f7f91STakashi Iwai dac = spec->private_dac_nids[0]; 914352f7f91STakashi Iwai badness += bad->shared_surr_main; 915352f7f91STakashi Iwai } else if (!i) 916352f7f91STakashi Iwai badness += bad->no_primary_dac; 917352f7f91STakashi Iwai else 918352f7f91STakashi Iwai badness += bad->no_dac; 919352f7f91STakashi Iwai } 9204ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_NO_AAMIX); 921117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) { 922b3a8c745STakashi Iwai /* try with aamix */ 923b3a8c745STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_ALL); 924b3a8c745STakashi Iwai } 9250c8c0f56STakashi Iwai if (!path) 926352f7f91STakashi Iwai dac = dacs[i] = 0; 927e1284af7STakashi Iwai else { 9280c8c0f56STakashi Iwai print_nid_path("output", path); 929e1284af7STakashi Iwai path->active = true; 930196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 931e1284af7STakashi Iwai } 932352f7f91STakashi Iwai if (dac) 933352f7f91STakashi Iwai badness += assign_out_path_ctls(codec, pin, dac); 934352f7f91STakashi Iwai } 935352f7f91STakashi Iwai 936352f7f91STakashi Iwai return badness; 937352f7f91STakashi Iwai } 938352f7f91STakashi Iwai 939352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */ 940352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 941352f7f91STakashi Iwai { 942352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 943352f7f91STakashi Iwai int i; 944352f7f91STakashi Iwai hda_nid_t nid_found = 0; 945352f7f91STakashi Iwai 946352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 947352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 948352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 949352f7f91STakashi Iwai continue; 950352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) { 951352f7f91STakashi Iwai if (nid_found) 952352f7f91STakashi Iwai return 0; 953352f7f91STakashi Iwai nid_found = nid; 954352f7f91STakashi Iwai } 955352f7f91STakashi Iwai } 956352f7f91STakashi Iwai return nid_found; 957352f7f91STakashi Iwai } 958352f7f91STakashi Iwai 959352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */ 960352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec, 961352f7f91STakashi Iwai unsigned int location, hda_nid_t nid) 962352f7f91STakashi Iwai { 963352f7f91STakashi Iwai unsigned int defcfg, caps; 964352f7f91STakashi Iwai 965352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid); 966352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) 967352f7f91STakashi Iwai return false; 968352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location) 969352f7f91STakashi Iwai return false; 970352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid); 971352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT)) 972352f7f91STakashi Iwai return false; 973352f7f91STakashi Iwai return true; 974352f7f91STakashi Iwai } 975352f7f91STakashi Iwai 976e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */ 977e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) 978e22aab7dSTakashi Iwai { 979e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 980e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 981e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 982e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg); 983e22aab7dSTakashi Iwai int type, i; 984e22aab7dSTakashi Iwai int num_pins = 0; 985e22aab7dSTakashi Iwai 986e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 987e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 988e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type) 989e22aab7dSTakashi Iwai continue; 990e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location, 991e22aab7dSTakashi Iwai cfg->inputs[i].pin)) 992e22aab7dSTakashi Iwai num_pins++; 993e22aab7dSTakashi Iwai } 994e22aab7dSTakashi Iwai } 995e22aab7dSTakashi Iwai return num_pins; 996e22aab7dSTakashi Iwai } 997e22aab7dSTakashi Iwai 998352f7f91STakashi Iwai /* 999352f7f91STakashi Iwai * multi-io helper 1000352f7f91STakashi Iwai * 1001352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns 1002352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found. 1003352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns 1004352f7f91STakashi Iwai * the badness value. 1005352f7f91STakashi Iwai */ 1006352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec, 1007352f7f91STakashi Iwai hda_nid_t reference_pin, 1008e22aab7dSTakashi Iwai bool hardwired) 1009352f7f91STakashi Iwai { 1010352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1011352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1012e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins; 1013352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1014352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1015352f7f91STakashi Iwai int badness = 0; 1016352f7f91STakashi Iwai 1017352f7f91STakashi Iwai old_pins = spec->multi_ios; 1018352f7f91STakashi Iwai if (old_pins >= 2) 1019352f7f91STakashi Iwai goto end_fill; 1020352f7f91STakashi Iwai 1021e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin); 1022352f7f91STakashi Iwai if (num_pins < 2) 1023352f7f91STakashi Iwai goto end_fill; 1024352f7f91STakashi Iwai 1025352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1026352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 10270c8c0f56STakashi Iwai struct nid_path *path; 1028352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 1029352f7f91STakashi Iwai hda_nid_t dac = 0; 1030352f7f91STakashi Iwai 1031352f7f91STakashi Iwai if (cfg->inputs[i].type != type) 1032352f7f91STakashi Iwai continue; 1033352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid)) 1034352f7f91STakashi Iwai continue; 1035352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) { 1036352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin) 1037352f7f91STakashi Iwai break; 1038352f7f91STakashi Iwai } 1039352f7f91STakashi Iwai if (j < spec->multi_ios) 1040352f7f91STakashi Iwai continue; 1041352f7f91STakashi Iwai 1042352f7f91STakashi Iwai if (hardwired) 1043352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid); 1044352f7f91STakashi Iwai else if (!dac) 1045352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false); 1046352f7f91STakashi Iwai if (!dac) { 1047352f7f91STakashi Iwai badness++; 1048352f7f91STakashi Iwai continue; 1049352f7f91STakashi Iwai } 10504ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, dac, nid, HDA_PARSE_NO_AAMIX); 10510c8c0f56STakashi Iwai if (!path) { 1052352f7f91STakashi Iwai badness++; 1053352f7f91STakashi Iwai continue; 1054352f7f91STakashi Iwai } 10550c8c0f56STakashi Iwai print_nid_path("multiio", path); 1056352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid; 1057352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac; 1058196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] = 1059196c1766STakashi Iwai snd_hda_get_path_idx(codec, path); 1060352f7f91STakashi Iwai spec->multi_ios++; 1061352f7f91STakashi Iwai if (spec->multi_ios >= 2) 1062352f7f91STakashi Iwai break; 1063352f7f91STakashi Iwai } 1064352f7f91STakashi Iwai } 1065352f7f91STakashi Iwai end_fill: 1066352f7f91STakashi Iwai if (badness) 1067352f7f91STakashi Iwai badness = BAD_MULTI_IO; 1068352f7f91STakashi Iwai if (old_pins == spec->multi_ios) { 1069352f7f91STakashi Iwai if (hardwired) 1070352f7f91STakashi Iwai return 1; /* nothing found */ 1071352f7f91STakashi Iwai else 1072352f7f91STakashi Iwai return badness; /* no badness if nothing found */ 1073352f7f91STakashi Iwai } 1074352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) { 1075352f7f91STakashi Iwai /* cancel newly assigned paths */ 1076352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins; 1077352f7f91STakashi Iwai spec->multi_ios = old_pins; 1078352f7f91STakashi Iwai return badness; 1079352f7f91STakashi Iwai } 1080352f7f91STakashi Iwai 1081352f7f91STakashi Iwai /* assign volume and mute controls */ 1082352f7f91STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) 1083352f7f91STakashi Iwai badness += assign_out_path_ctls(codec, spec->multi_io[i].pin, 1084352f7f91STakashi Iwai spec->multi_io[i].dac); 1085352f7f91STakashi Iwai 1086352f7f91STakashi Iwai return badness; 1087352f7f91STakashi Iwai } 1088352f7f91STakashi Iwai 1089352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */ 1090352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs, 1091196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) 1092352f7f91STakashi Iwai { 1093b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1094352f7f91STakashi Iwai int i; 1095352f7f91STakashi Iwai bool found = false; 1096352f7f91STakashi Iwai for (i = 0; i < outs; i++) { 10970c8c0f56STakashi Iwai struct nid_path *path; 1098352f7f91STakashi Iwai hda_nid_t dac; 1099352f7f91STakashi Iwai if (dacs[i]) 1100352f7f91STakashi Iwai continue; 1101352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]); 1102352f7f91STakashi Iwai if (!dac) 1103352f7f91STakashi Iwai continue; 11044ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_NO_AAMIX); 1105117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) 1106b3a8c745STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_ALL); 11070c8c0f56STakashi Iwai if (path) { 1108352f7f91STakashi Iwai dacs[i] = dac; 1109352f7f91STakashi Iwai found = true; 11100c8c0f56STakashi Iwai print_nid_path("output", path); 1111e1284af7STakashi Iwai path->active = true; 1112196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 1113352f7f91STakashi Iwai } 1114352f7f91STakashi Iwai } 1115352f7f91STakashi Iwai return found; 1116352f7f91STakashi Iwai } 1117352f7f91STakashi Iwai 1118352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */ 1119352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec, 1120352f7f91STakashi Iwai bool fill_hardwired, 1121352f7f91STakashi Iwai bool fill_mio_first) 1122352f7f91STakashi Iwai { 1123352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1124352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1125352f7f91STakashi Iwai int i, err, badness; 1126352f7f91STakashi Iwai 1127352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */ 1128352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs; 1129352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids; 1130352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); 1131352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 1132352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 1133352f7f91STakashi Iwai spec->multi_ios = 0; 1134352f7f91STakashi Iwai snd_array_free(&spec->paths); 1135352f7f91STakashi Iwai badness = 0; 1136352f7f91STakashi Iwai 1137352f7f91STakashi Iwai /* fill hard-wired DACs first */ 1138352f7f91STakashi Iwai if (fill_hardwired) { 1139352f7f91STakashi Iwai bool mapped; 1140352f7f91STakashi Iwai do { 1141352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs, 1142352f7f91STakashi Iwai cfg->line_out_pins, 1143196c1766STakashi Iwai spec->private_dac_nids, 1144196c1766STakashi Iwai spec->out_paths); 1145352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs, 1146352f7f91STakashi Iwai cfg->hp_pins, 1147196c1766STakashi Iwai spec->multiout.hp_out_nid, 1148196c1766STakashi Iwai spec->hp_paths); 1149352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs, 1150352f7f91STakashi Iwai cfg->speaker_pins, 1151196c1766STakashi Iwai spec->multiout.extra_out_nid, 1152196c1766STakashi Iwai spec->speaker_paths); 1153352f7f91STakashi Iwai if (fill_mio_first && cfg->line_outs == 1 && 1154352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1155e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true); 1156352f7f91STakashi Iwai if (!err) 1157352f7f91STakashi Iwai mapped = true; 1158352f7f91STakashi Iwai } 1159352f7f91STakashi Iwai } while (mapped); 1160352f7f91STakashi Iwai } 1161352f7f91STakashi Iwai 1162352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, 1163196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths, 1164352f7f91STakashi Iwai &main_out_badness); 1165352f7f91STakashi Iwai 1166352f7f91STakashi Iwai /* re-count num_dacs and squash invalid entries */ 1167352f7f91STakashi Iwai spec->multiout.num_dacs = 0; 1168352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 1169352f7f91STakashi Iwai if (spec->private_dac_nids[i]) 1170352f7f91STakashi Iwai spec->multiout.num_dacs++; 1171352f7f91STakashi Iwai else { 1172352f7f91STakashi Iwai memmove(spec->private_dac_nids + i, 1173352f7f91STakashi Iwai spec->private_dac_nids + i + 1, 1174352f7f91STakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); 1175352f7f91STakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0; 1176352f7f91STakashi Iwai } 1177352f7f91STakashi Iwai } 1178352f7f91STakashi Iwai 1179352f7f91STakashi Iwai if (fill_mio_first && 1180352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1181352f7f91STakashi Iwai /* try to fill multi-io first */ 1182e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1183352f7f91STakashi Iwai if (err < 0) 1184352f7f91STakashi Iwai return err; 1185352f7f91STakashi Iwai /* we don't count badness at this stage yet */ 1186352f7f91STakashi Iwai } 1187352f7f91STakashi Iwai 1188352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 1189352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, 1190352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1191196c1766STakashi Iwai spec->hp_paths, 1192352f7f91STakashi Iwai &extra_out_badness); 1193352f7f91STakashi Iwai if (err < 0) 1194352f7f91STakashi Iwai return err; 1195352f7f91STakashi Iwai badness += err; 1196352f7f91STakashi Iwai } 1197352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1198352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs, 1199352f7f91STakashi Iwai cfg->speaker_pins, 1200352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1201196c1766STakashi Iwai spec->speaker_paths, 1202352f7f91STakashi Iwai &extra_out_badness); 1203352f7f91STakashi Iwai if (err < 0) 1204352f7f91STakashi Iwai return err; 1205352f7f91STakashi Iwai badness += err; 1206352f7f91STakashi Iwai } 1207352f7f91STakashi Iwai if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1208e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1209352f7f91STakashi Iwai if (err < 0) 1210352f7f91STakashi Iwai return err; 1211352f7f91STakashi Iwai badness += err; 1212352f7f91STakashi Iwai } 1213e22aab7dSTakashi Iwai 1214e22aab7dSTakashi Iwai if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1215e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1216e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */ 1217352f7f91STakashi Iwai 1218352f7f91STakashi Iwai if (spec->multi_ios == 2) { 1219352f7f91STakashi Iwai for (i = 0; i < 2; i++) 1220352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] = 1221352f7f91STakashi Iwai spec->multi_io[i].dac; 1222352f7f91STakashi Iwai spec->ext_channel_count = 2; 1223352f7f91STakashi Iwai } else if (spec->multi_ios) { 1224352f7f91STakashi Iwai spec->multi_ios = 0; 1225352f7f91STakashi Iwai badness += BAD_MULTI_IO; 1226352f7f91STakashi Iwai } 1227352f7f91STakashi Iwai 1228352f7f91STakashi Iwai return badness; 1229352f7f91STakashi Iwai } 1230352f7f91STakashi Iwai 1231352f7f91STakashi Iwai #define DEBUG_BADNESS 1232352f7f91STakashi Iwai 1233352f7f91STakashi Iwai #ifdef DEBUG_BADNESS 1234352f7f91STakashi Iwai #define debug_badness snd_printdd 1235352f7f91STakashi Iwai #else 1236352f7f91STakashi Iwai #define debug_badness(...) 1237352f7f91STakashi Iwai #endif 1238352f7f91STakashi Iwai 1239352f7f91STakashi Iwai static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg) 1240352f7f91STakashi Iwai { 1241352f7f91STakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1242352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1], 1243708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 1244352f7f91STakashi Iwai spec->multiout.dac_nids[0], 1245352f7f91STakashi Iwai spec->multiout.dac_nids[1], 1246352f7f91STakashi Iwai spec->multiout.dac_nids[2], 1247352f7f91STakashi Iwai spec->multiout.dac_nids[3]); 1248352f7f91STakashi Iwai if (spec->multi_ios > 0) 1249352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", 1250352f7f91STakashi Iwai spec->multi_ios, 1251352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin, 1252352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac); 1253352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1254352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1], 1255708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3], 1256352f7f91STakashi Iwai spec->multiout.hp_out_nid[0], 1257352f7f91STakashi Iwai spec->multiout.hp_out_nid[1], 1258352f7f91STakashi Iwai spec->multiout.hp_out_nid[2], 1259352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]); 1260352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1261352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1], 1262352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3], 1263352f7f91STakashi Iwai spec->multiout.extra_out_nid[0], 1264352f7f91STakashi Iwai spec->multiout.extra_out_nid[1], 1265352f7f91STakashi Iwai spec->multiout.extra_out_nid[2], 1266352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]); 1267352f7f91STakashi Iwai } 1268352f7f91STakashi Iwai 1269352f7f91STakashi Iwai /* find all available DACs of the codec */ 1270352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec) 1271352f7f91STakashi Iwai { 1272352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1273352f7f91STakashi Iwai int i; 1274352f7f91STakashi Iwai hda_nid_t nid = codec->start_nid; 1275352f7f91STakashi Iwai 1276352f7f91STakashi Iwai spec->num_all_dacs = 0; 1277352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); 1278352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 1279352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) 1280352f7f91STakashi Iwai continue; 1281352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { 1282352f7f91STakashi Iwai snd_printk(KERN_ERR "hda: Too many DACs!\n"); 1283352f7f91STakashi Iwai break; 1284352f7f91STakashi Iwai } 1285352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid; 1286352f7f91STakashi Iwai } 1287352f7f91STakashi Iwai } 1288352f7f91STakashi Iwai 1289352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec) 1290352f7f91STakashi Iwai { 1291352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1292352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1293352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg; 1294352f7f91STakashi Iwai int best_badness = INT_MAX; 1295352f7f91STakashi Iwai int badness; 1296352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true; 1297352f7f91STakashi Iwai bool best_wired = true, best_mio = true; 1298352f7f91STakashi Iwai bool hp_spk_swapped = false; 1299352f7f91STakashi Iwai 1300352f7f91STakashi Iwai fill_all_dac_nids(codec); 1301352f7f91STakashi Iwai 1302352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); 1303352f7f91STakashi Iwai if (!best_cfg) 1304352f7f91STakashi Iwai return -ENOMEM; 1305352f7f91STakashi Iwai *best_cfg = *cfg; 1306352f7f91STakashi Iwai 1307352f7f91STakashi Iwai for (;;) { 1308352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired, 1309352f7f91STakashi Iwai fill_mio_first); 1310352f7f91STakashi Iwai if (badness < 0) { 1311352f7f91STakashi Iwai kfree(best_cfg); 1312352f7f91STakashi Iwai return badness; 1313352f7f91STakashi Iwai } 1314352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", 1315352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first, 1316352f7f91STakashi Iwai badness); 1317352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1318352f7f91STakashi Iwai if (badness < best_badness) { 1319352f7f91STakashi Iwai best_badness = badness; 1320352f7f91STakashi Iwai *best_cfg = *cfg; 1321352f7f91STakashi Iwai best_wired = fill_hardwired; 1322352f7f91STakashi Iwai best_mio = fill_mio_first; 1323352f7f91STakashi Iwai } 1324352f7f91STakashi Iwai if (!badness) 1325352f7f91STakashi Iwai break; 1326352f7f91STakashi Iwai fill_mio_first = !fill_mio_first; 1327352f7f91STakashi Iwai if (!fill_mio_first) 1328352f7f91STakashi Iwai continue; 1329352f7f91STakashi Iwai fill_hardwired = !fill_hardwired; 1330352f7f91STakashi Iwai if (!fill_hardwired) 1331352f7f91STakashi Iwai continue; 1332352f7f91STakashi Iwai if (hp_spk_swapped) 1333352f7f91STakashi Iwai break; 1334352f7f91STakashi Iwai hp_spk_swapped = true; 1335352f7f91STakashi Iwai if (cfg->speaker_outs > 0 && 1336352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 1337352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 1338352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 1339352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1340352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs; 1341352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins, 1342352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1343352f7f91STakashi Iwai cfg->speaker_outs = 0; 1344352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 1345352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 1346352f7f91STakashi Iwai fill_hardwired = true; 1347352f7f91STakashi Iwai continue; 1348352f7f91STakashi Iwai } 1349352f7f91STakashi Iwai if (cfg->hp_outs > 0 && 1350352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 1351352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 1352352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 1353352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1354352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 1355352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, 1356352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1357352f7f91STakashi Iwai cfg->hp_outs = 0; 1358352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 1359352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 1360352f7f91STakashi Iwai fill_hardwired = true; 1361352f7f91STakashi Iwai continue; 1362352f7f91STakashi Iwai } 1363352f7f91STakashi Iwai break; 1364352f7f91STakashi Iwai } 1365352f7f91STakashi Iwai 1366352f7f91STakashi Iwai if (badness) { 13670c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n"); 1368352f7f91STakashi Iwai *cfg = *best_cfg; 1369352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio); 1370352f7f91STakashi Iwai } 1371352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", 1372352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio); 1373352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1374352f7f91STakashi Iwai 1375352f7f91STakashi Iwai if (cfg->line_out_pins[0]) { 1376352f7f91STakashi Iwai struct nid_path *path; 1377196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); 1378352f7f91STakashi Iwai if (path) 1379352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path); 1380352f7f91STakashi Iwai } 1381352f7f91STakashi Iwai 1382352f7f91STakashi Iwai kfree(best_cfg); 1383352f7f91STakashi Iwai return 0; 1384352f7f91STakashi Iwai } 1385352f7f91STakashi Iwai 1386352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */ 1387352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec, 1388352f7f91STakashi Iwai const struct auto_pin_cfg *cfg) 1389352f7f91STakashi Iwai { 1390352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1391352f7f91STakashi Iwai int i, err, noutputs; 1392352f7f91STakashi Iwai 1393352f7f91STakashi Iwai noutputs = cfg->line_outs; 1394352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3) 1395352f7f91STakashi Iwai noutputs += spec->multi_ios; 1396352f7f91STakashi Iwai 1397352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) { 1398352f7f91STakashi Iwai const char *name; 1399352f7f91STakashi Iwai int index; 1400196c1766STakashi Iwai hda_nid_t dac; 1401352f7f91STakashi Iwai struct nid_path *path; 1402352f7f91STakashi Iwai 1403352f7f91STakashi Iwai dac = spec->multiout.dac_nids[i]; 1404352f7f91STakashi Iwai if (!dac) 1405352f7f91STakashi Iwai continue; 1406352f7f91STakashi Iwai if (i >= cfg->line_outs) { 1407352f7f91STakashi Iwai index = 0; 1408352f7f91STakashi Iwai name = channel_name[i]; 1409352f7f91STakashi Iwai } else { 1410352f7f91STakashi Iwai name = get_line_out_pfx(spec, i, true, &index); 1411352f7f91STakashi Iwai } 1412352f7f91STakashi Iwai 1413196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 1414352f7f91STakashi Iwai if (!path) 1415352f7f91STakashi Iwai continue; 1416352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1417352f7f91STakashi Iwai /* Center/LFE */ 1418352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path); 1419352f7f91STakashi Iwai if (err < 0) 1420352f7f91STakashi Iwai return err; 1421352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path); 1422352f7f91STakashi Iwai if (err < 0) 1423352f7f91STakashi Iwai return err; 1424352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path); 1425352f7f91STakashi Iwai if (err < 0) 1426352f7f91STakashi Iwai return err; 1427352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path); 1428352f7f91STakashi Iwai if (err < 0) 1429352f7f91STakashi Iwai return err; 1430352f7f91STakashi Iwai } else { 1431352f7f91STakashi Iwai err = add_stereo_vol(codec, name, index, path); 1432352f7f91STakashi Iwai if (err < 0) 1433352f7f91STakashi Iwai return err; 1434352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path); 1435352f7f91STakashi Iwai if (err < 0) 1436352f7f91STakashi Iwai return err; 1437352f7f91STakashi Iwai } 1438352f7f91STakashi Iwai } 1439352f7f91STakashi Iwai return 0; 1440352f7f91STakashi Iwai } 1441352f7f91STakashi Iwai 1442352f7f91STakashi Iwai static int create_extra_out(struct hda_codec *codec, hda_nid_t pin, 1443196c1766STakashi Iwai hda_nid_t dac, int path_idx, 1444196c1766STakashi Iwai const char *pfx, int cidx) 1445352f7f91STakashi Iwai { 1446352f7f91STakashi Iwai struct nid_path *path; 1447352f7f91STakashi Iwai int err; 1448352f7f91STakashi Iwai 1449196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 1450352f7f91STakashi Iwai if (!path) 1451352f7f91STakashi Iwai return 0; 1452352f7f91STakashi Iwai /* bind volume control will be created in the case of dac = 0 */ 1453352f7f91STakashi Iwai if (dac) { 1454352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path); 1455352f7f91STakashi Iwai if (err < 0) 1456352f7f91STakashi Iwai return err; 1457352f7f91STakashi Iwai } 1458352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path); 1459352f7f91STakashi Iwai if (err < 0) 1460352f7f91STakashi Iwai return err; 1461352f7f91STakashi Iwai return 0; 1462352f7f91STakashi Iwai } 1463352f7f91STakashi Iwai 1464352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */ 1465352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins, 1466352f7f91STakashi Iwai const hda_nid_t *pins, const hda_nid_t *dacs, 1467196c1766STakashi Iwai const int *paths, const char *pfx) 1468352f7f91STakashi Iwai { 1469352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1470352f7f91STakashi Iwai struct hda_bind_ctls *ctl; 1471352f7f91STakashi Iwai char name[32]; 1472352f7f91STakashi Iwai int i, n, err; 1473352f7f91STakashi Iwai 1474352f7f91STakashi Iwai if (!num_pins || !pins[0]) 1475352f7f91STakashi Iwai return 0; 1476352f7f91STakashi Iwai 1477352f7f91STakashi Iwai if (num_pins == 1) { 1478352f7f91STakashi Iwai hda_nid_t dac = *dacs; 1479352f7f91STakashi Iwai if (!dac) 1480352f7f91STakashi Iwai dac = spec->multiout.dac_nids[0]; 1481196c1766STakashi Iwai return create_extra_out(codec, *pins, dac, paths[0], pfx, 0); 1482352f7f91STakashi Iwai } 1483352f7f91STakashi Iwai 1484352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1485352f7f91STakashi Iwai hda_nid_t dac; 1486352f7f91STakashi Iwai if (dacs[num_pins - 1]) 1487352f7f91STakashi Iwai dac = dacs[i]; /* with individual volumes */ 1488352f7f91STakashi Iwai else 1489352f7f91STakashi Iwai dac = 0; 1490352f7f91STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) { 1491196c1766STakashi Iwai err = create_extra_out(codec, pins[i], dac, paths[i], 1492352f7f91STakashi Iwai "Bass Speaker", 0); 1493352f7f91STakashi Iwai } else if (num_pins >= 3) { 1494352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s", 1495352f7f91STakashi Iwai pfx, channel_name[i]); 1496196c1766STakashi Iwai err = create_extra_out(codec, pins[i], dac, paths[i], 1497196c1766STakashi Iwai name, 0); 1498352f7f91STakashi Iwai } else { 1499196c1766STakashi Iwai err = create_extra_out(codec, pins[i], dac, paths[i], 1500196c1766STakashi Iwai pfx, i); 1501352f7f91STakashi Iwai } 1502352f7f91STakashi Iwai if (err < 0) 1503352f7f91STakashi Iwai return err; 1504352f7f91STakashi Iwai } 1505352f7f91STakashi Iwai if (dacs[num_pins - 1]) 1506352f7f91STakashi Iwai return 0; 1507352f7f91STakashi Iwai 1508352f7f91STakashi Iwai /* Let's create a bind-controls for volumes */ 1509352f7f91STakashi Iwai ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol); 1510352f7f91STakashi Iwai if (!ctl) 1511352f7f91STakashi Iwai return -ENOMEM; 1512352f7f91STakashi Iwai n = 0; 1513352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1514352f7f91STakashi Iwai hda_nid_t vol; 1515352f7f91STakashi Iwai struct nid_path *path; 1516352f7f91STakashi Iwai if (!pins[i] || !dacs[i]) 1517352f7f91STakashi Iwai continue; 1518196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]); 1519352f7f91STakashi Iwai if (!path) 1520352f7f91STakashi Iwai continue; 1521352f7f91STakashi Iwai vol = look_for_out_vol_nid(codec, path); 1522352f7f91STakashi Iwai if (vol) 1523352f7f91STakashi Iwai ctl->values[n++] = 1524352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT); 1525352f7f91STakashi Iwai } 1526352f7f91STakashi Iwai if (n) { 1527352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s Playback Volume", pfx); 1528352f7f91STakashi Iwai err = add_control(spec, HDA_CTL_BIND_VOL, name, 0, (long)ctl); 1529352f7f91STakashi Iwai if (err < 0) 1530352f7f91STakashi Iwai return err; 1531352f7f91STakashi Iwai } 1532352f7f91STakashi Iwai return 0; 1533352f7f91STakashi Iwai } 1534352f7f91STakashi Iwai 1535352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec) 1536352f7f91STakashi Iwai { 1537352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1538352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs, 1539352f7f91STakashi Iwai spec->autocfg.hp_pins, 1540352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1541196c1766STakashi Iwai spec->hp_paths, 1542352f7f91STakashi Iwai "Headphone"); 1543352f7f91STakashi Iwai } 1544352f7f91STakashi Iwai 1545352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec) 1546352f7f91STakashi Iwai { 1547352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1548352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs, 1549352f7f91STakashi Iwai spec->autocfg.speaker_pins, 1550352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1551196c1766STakashi Iwai spec->speaker_paths, 1552352f7f91STakashi Iwai "Speaker"); 1553352f7f91STakashi Iwai } 1554352f7f91STakashi Iwai 1555352f7f91STakashi Iwai /* 155638cf6f1aSTakashi Iwai * independent HP controls 155738cf6f1aSTakashi Iwai */ 155838cf6f1aSTakashi Iwai 155938cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol, 156038cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo) 156138cf6f1aSTakashi Iwai { 156238cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 156338cf6f1aSTakashi Iwai } 156438cf6f1aSTakashi Iwai 156538cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol, 156638cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 156738cf6f1aSTakashi Iwai { 156838cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 156938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 157038cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; 157138cf6f1aSTakashi Iwai return 0; 157238cf6f1aSTakashi Iwai } 157338cf6f1aSTakashi Iwai 157438cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol, 157538cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 157638cf6f1aSTakashi Iwai { 157738cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 157838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 157938cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0]; 158038cf6f1aSTakashi Iwai int ret = 0; 158138cf6f1aSTakashi Iwai 158238cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 158338cf6f1aSTakashi Iwai if (spec->active_streams) { 158438cf6f1aSTakashi Iwai ret = -EBUSY; 158538cf6f1aSTakashi Iwai goto unlock; 158638cf6f1aSTakashi Iwai } 158738cf6f1aSTakashi Iwai 158838cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) { 158938cf6f1aSTakashi Iwai spec->indep_hp_enabled = select; 159038cf6f1aSTakashi Iwai if (spec->indep_hp_enabled) 159138cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = 0; 159238cf6f1aSTakashi Iwai else 159338cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = spec->alt_dac_nid; 159438cf6f1aSTakashi Iwai ret = 1; 159538cf6f1aSTakashi Iwai } 159638cf6f1aSTakashi Iwai unlock: 159738cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 159838cf6f1aSTakashi Iwai return ret; 159938cf6f1aSTakashi Iwai } 160038cf6f1aSTakashi Iwai 160138cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = { 160238cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 160338cf6f1aSTakashi Iwai .name = "Independent HP", 160438cf6f1aSTakashi Iwai .info = indep_hp_info, 160538cf6f1aSTakashi Iwai .get = indep_hp_get, 160638cf6f1aSTakashi Iwai .put = indep_hp_put, 160738cf6f1aSTakashi Iwai }; 160838cf6f1aSTakashi Iwai 160938cf6f1aSTakashi Iwai 161038cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec) 161138cf6f1aSTakashi Iwai { 161238cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 161338cf6f1aSTakashi Iwai 161438cf6f1aSTakashi Iwai if (!spec->indep_hp) 161538cf6f1aSTakashi Iwai return 0; 161638cf6f1aSTakashi Iwai if (!spec->multiout.hp_out_nid[0]) { 161738cf6f1aSTakashi Iwai spec->indep_hp = 0; 161838cf6f1aSTakashi Iwai return 0; 161938cf6f1aSTakashi Iwai } 162038cf6f1aSTakashi Iwai 162138cf6f1aSTakashi Iwai spec->indep_hp_enabled = false; 162238cf6f1aSTakashi Iwai spec->alt_dac_nid = spec->multiout.hp_out_nid[0]; 162338cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) 162438cf6f1aSTakashi Iwai return -ENOMEM; 162538cf6f1aSTakashi Iwai return 0; 162638cf6f1aSTakashi Iwai } 162738cf6f1aSTakashi Iwai 162838cf6f1aSTakashi Iwai /* 1629352f7f91STakashi Iwai * channel mode enum control 1630352f7f91STakashi Iwai */ 1631352f7f91STakashi Iwai 1632352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol, 1633352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 1634352f7f91STakashi Iwai { 1635352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1636352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1637352f7f91STakashi Iwai 1638352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1639352f7f91STakashi Iwai uinfo->count = 1; 1640352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1; 1641352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios) 1642352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios; 1643352f7f91STakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", 1644352f7f91STakashi Iwai (uinfo->value.enumerated.item + 1) * 2); 1645352f7f91STakashi Iwai return 0; 1646352f7f91STakashi Iwai } 1647352f7f91STakashi Iwai 1648352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol, 1649352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1650352f7f91STakashi Iwai { 1651352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1652352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1653352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; 1654352f7f91STakashi Iwai return 0; 1655352f7f91STakashi Iwai } 1656352f7f91STakashi Iwai 1657196c1766STakashi Iwai static inline struct nid_path * 1658196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx) 1659196c1766STakashi Iwai { 1660196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1661196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec, 1662196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]); 1663196c1766STakashi Iwai } 1664196c1766STakashi Iwai 1665352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output) 1666352f7f91STakashi Iwai { 1667352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1668352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin; 1669352f7f91STakashi Iwai struct nid_path *path; 1670352f7f91STakashi Iwai 1671196c1766STakashi Iwai path = get_multiio_path(codec, idx); 1672352f7f91STakashi Iwai if (!path) 1673352f7f91STakashi Iwai return -EINVAL; 1674352f7f91STakashi Iwai 1675352f7f91STakashi Iwai if (path->active == output) 1676352f7f91STakashi Iwai return 0; 1677352f7f91STakashi Iwai 1678352f7f91STakashi Iwai if (output) { 1679352f7f91STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT); 1680352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, true); 1681d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true); 1682352f7f91STakashi Iwai } else { 1683d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false); 1684352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, true); 1685352f7f91STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, 1686352f7f91STakashi Iwai spec->multi_io[idx].ctl_in); 1687352f7f91STakashi Iwai } 1688352f7f91STakashi Iwai return 0; 1689352f7f91STakashi Iwai } 1690352f7f91STakashi Iwai 1691352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol, 1692352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1693352f7f91STakashi Iwai { 1694352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1695352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1696352f7f91STakashi Iwai int i, ch; 1697352f7f91STakashi Iwai 1698352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0]; 1699352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios) 1700352f7f91STakashi Iwai return -EINVAL; 1701352f7f91STakashi Iwai if (ch == (spec->ext_channel_count - 1) / 2) 1702352f7f91STakashi Iwai return 0; 1703352f7f91STakashi Iwai spec->ext_channel_count = (ch + 1) * 2; 1704352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) 1705352f7f91STakashi Iwai set_multi_io(codec, i, i < ch); 1706352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 1707352f7f91STakashi Iwai spec->const_channel_count); 1708352f7f91STakashi Iwai if (spec->need_dac_fix) 1709352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2; 1710352f7f91STakashi Iwai return 1; 1711352f7f91STakashi Iwai } 1712352f7f91STakashi Iwai 1713352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = { 1714352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1715352f7f91STakashi Iwai .name = "Channel Mode", 1716352f7f91STakashi Iwai .info = ch_mode_info, 1717352f7f91STakashi Iwai .get = ch_mode_get, 1718352f7f91STakashi Iwai .put = ch_mode_put, 1719352f7f91STakashi Iwai }; 1720352f7f91STakashi Iwai 1721352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec) 1722352f7f91STakashi Iwai { 1723352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1724352f7f91STakashi Iwai 1725352f7f91STakashi Iwai if (spec->multi_ios > 0) { 172612c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) 1727352f7f91STakashi Iwai return -ENOMEM; 1728352f7f91STakashi Iwai } 1729352f7f91STakashi Iwai return 0; 1730352f7f91STakashi Iwai } 1731352f7f91STakashi Iwai 1732352f7f91STakashi Iwai /* 1733352f7f91STakashi Iwai * shared headphone/mic handling 1734352f7f91STakashi Iwai */ 1735352f7f91STakashi Iwai 1736352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec); 1737352f7f91STakashi Iwai 1738352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */ 1739352f7f91STakashi Iwai static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) 1740352f7f91STakashi Iwai { 1741352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1742352f7f91STakashi Iwai unsigned int val; 1743352f7f91STakashi Iwai hda_nid_t pin = spec->autocfg.inputs[1].pin; 1744352f7f91STakashi Iwai /* NOTE: this assumes that there are only two inputs, the 1745352f7f91STakashi Iwai * first is the real internal mic and the second is HP/mic jack. 1746352f7f91STakashi Iwai */ 1747352f7f91STakashi Iwai 1748352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin); 1749352f7f91STakashi Iwai 1750352f7f91STakashi Iwai /* This pin does not have vref caps - let's enable vref on pin 0x18 1751352f7f91STakashi Iwai instead, as suggested by Realtek */ 1752352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { 1753352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin; 1754352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); 1755352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ) 17567594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin, 17577594aa33STakashi Iwai PIN_IN | (set_as_mic ? vref_val : 0)); 1758352f7f91STakashi Iwai } 1759352f7f91STakashi Iwai 1760352f7f91STakashi Iwai val = set_as_mic ? val | PIN_IN : PIN_HP; 17617594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, pin, val); 1762352f7f91STakashi Iwai 1763352f7f91STakashi Iwai spec->automute_speaker = !set_as_mic; 1764352f7f91STakashi Iwai call_update_outputs(codec); 1765352f7f91STakashi Iwai } 1766352f7f91STakashi Iwai 1767352f7f91STakashi Iwai /* create a shared input with the headphone out */ 1768352f7f91STakashi Iwai static int create_shared_input(struct hda_codec *codec) 1769352f7f91STakashi Iwai { 1770352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1771352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1772352f7f91STakashi Iwai unsigned int defcfg; 1773352f7f91STakashi Iwai hda_nid_t nid; 1774352f7f91STakashi Iwai 1775352f7f91STakashi Iwai /* only one internal input pin? */ 1776352f7f91STakashi Iwai if (cfg->num_inputs != 1) 1777352f7f91STakashi Iwai return 0; 1778352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); 1779352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) 1780352f7f91STakashi Iwai return 0; 1781352f7f91STakashi Iwai 1782352f7f91STakashi Iwai if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1783352f7f91STakashi Iwai nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ 1784352f7f91STakashi Iwai else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) 1785352f7f91STakashi Iwai nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ 1786352f7f91STakashi Iwai else 1787352f7f91STakashi Iwai return 0; /* both not available */ 1788352f7f91STakashi Iwai 1789352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) 1790352f7f91STakashi Iwai return 0; /* no input */ 1791352f7f91STakashi Iwai 1792352f7f91STakashi Iwai cfg->inputs[1].pin = nid; 1793352f7f91STakashi Iwai cfg->inputs[1].type = AUTO_PIN_MIC; 1794352f7f91STakashi Iwai cfg->num_inputs = 2; 1795352f7f91STakashi Iwai spec->shared_mic_hp = 1; 1796352f7f91STakashi Iwai snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); 1797352f7f91STakashi Iwai return 0; 1798352f7f91STakashi Iwai } 1799352f7f91STakashi Iwai 1800352f7f91STakashi Iwai 1801352f7f91STakashi Iwai /* 1802352f7f91STakashi Iwai * Parse input paths 1803352f7f91STakashi Iwai */ 1804352f7f91STakashi Iwai 1805352f7f91STakashi Iwai #ifdef CONFIG_PM 1806352f7f91STakashi Iwai /* add the powersave loopback-list entry */ 1807352f7f91STakashi Iwai static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) 1808352f7f91STakashi Iwai { 1809352f7f91STakashi Iwai struct hda_amp_list *list; 1810352f7f91STakashi Iwai 1811352f7f91STakashi Iwai if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) 1812352f7f91STakashi Iwai return; 1813352f7f91STakashi Iwai list = spec->loopback_list + spec->num_loopbacks; 1814352f7f91STakashi Iwai list->nid = mix; 1815352f7f91STakashi Iwai list->dir = HDA_INPUT; 1816352f7f91STakashi Iwai list->idx = idx; 1817352f7f91STakashi Iwai spec->num_loopbacks++; 1818cb53c626STakashi Iwai spec->loopback.amplist = spec->loopback_list; 1819cb53c626STakashi Iwai } 1820cb53c626STakashi Iwai #else 1821352f7f91STakashi Iwai #define add_loopback_list(spec, mix, idx) /* NOP */ 1822cb53c626STakashi Iwai #endif 1823cb53c626STakashi Iwai 1824352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */ 1825196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx, 1826196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx, 1827352f7f91STakashi Iwai hda_nid_t mix_nid) 18281da177e4SLinus Torvalds { 1829352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1830352f7f91STakashi Iwai struct nid_path *path; 1831352f7f91STakashi Iwai unsigned int val; 1832352f7f91STakashi Iwai int err, idx; 18331da177e4SLinus Torvalds 1834352f7f91STakashi Iwai if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && 1835352f7f91STakashi Iwai !nid_has_mute(codec, mix_nid, HDA_INPUT)) 1836352f7f91STakashi Iwai return 0; /* no need for analog loopback */ 1837352f7f91STakashi Iwai 18384ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, HDA_PARSE_ALL); 1839352f7f91STakashi Iwai if (!path) 1840352f7f91STakashi Iwai return -EINVAL; 18410c8c0f56STakashi Iwai print_nid_path("loopback", path); 1842196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 1843352f7f91STakashi Iwai 1844352f7f91STakashi Iwai idx = path->idx[path->depth - 1]; 1845352f7f91STakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { 1846352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 1847352f7f91STakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val); 1848d13bd412STakashi Iwai if (err < 0) 18491da177e4SLinus Torvalds return err; 1850352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 18511da177e4SLinus Torvalds } 18521da177e4SLinus Torvalds 1853352f7f91STakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { 1854352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 1855352f7f91STakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val); 1856d13bd412STakashi Iwai if (err < 0) 18571da177e4SLinus Torvalds return err; 1858352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 18591da177e4SLinus Torvalds } 18601da177e4SLinus Torvalds 1861352f7f91STakashi Iwai path->active = true; 1862352f7f91STakashi Iwai add_loopback_list(spec, mix_nid, idx); 1863352f7f91STakashi Iwai return 0; 18641da177e4SLinus Torvalds } 18651da177e4SLinus Torvalds 1866352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) 18671da177e4SLinus Torvalds { 1868352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 1869352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0; 1870352f7f91STakashi Iwai } 1871352f7f91STakashi Iwai 1872352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */ 1873352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec) 1874352f7f91STakashi Iwai { 1875352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1876352f7f91STakashi Iwai hda_nid_t nid; 1877352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids; 1878352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids); 1879352f7f91STakashi Iwai int i, nums = 0; 1880352f7f91STakashi Iwai 1881352f7f91STakashi Iwai nid = codec->start_nid; 1882352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 1883352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 1884352f7f91STakashi Iwai int type = get_wcaps_type(caps); 1885352f7f91STakashi Iwai 1886352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) 1887352f7f91STakashi Iwai continue; 1888352f7f91STakashi Iwai adc_nids[nums] = nid; 1889352f7f91STakashi Iwai if (++nums >= max_nums) 1890352f7f91STakashi Iwai break; 1891352f7f91STakashi Iwai } 1892352f7f91STakashi Iwai spec->num_adc_nids = nums; 1893352f7f91STakashi Iwai return nums; 1894352f7f91STakashi Iwai } 1895352f7f91STakashi Iwai 1896352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins; 1897352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available 1898352f7f91STakashi Iwai */ 1899352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec) 1900352f7f91STakashi Iwai { 1901352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1902352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 1903352f7f91STakashi Iwai hda_nid_t adc_nids[ARRAY_SIZE(spec->adc_nids)]; 1904352f7f91STakashi Iwai int i, n, nums; 1905352f7f91STakashi Iwai hda_nid_t pin, adc; 1906352f7f91STakashi Iwai 1907352f7f91STakashi Iwai again: 1908352f7f91STakashi Iwai nums = 0; 1909352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 1910352f7f91STakashi Iwai adc = spec->adc_nids[n]; 1911352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 1912352f7f91STakashi Iwai pin = spec->imux_pins[i]; 1913352f7f91STakashi Iwai if (!is_reachable_path(codec, pin, adc)) 1914352f7f91STakashi Iwai break; 1915352f7f91STakashi Iwai } 1916352f7f91STakashi Iwai if (i >= imux->num_items) 1917352f7f91STakashi Iwai adc_nids[nums++] = adc; 1918352f7f91STakashi Iwai } 1919352f7f91STakashi Iwai 1920352f7f91STakashi Iwai if (!nums) { 1921352f7f91STakashi Iwai if (spec->shared_mic_hp) { 1922352f7f91STakashi Iwai spec->shared_mic_hp = 0; 1923352f7f91STakashi Iwai imux->num_items = 1; 1924352f7f91STakashi Iwai goto again; 1925352f7f91STakashi Iwai } 1926352f7f91STakashi Iwai 1927352f7f91STakashi Iwai /* check whether ADC-switch is possible */ 1928352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 1929352f7f91STakashi Iwai pin = spec->imux_pins[i]; 1930352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 1931352f7f91STakashi Iwai adc = spec->adc_nids[n]; 1932352f7f91STakashi Iwai if (is_reachable_path(codec, pin, adc)) { 1933352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n; 1934352f7f91STakashi Iwai break; 1935352f7f91STakashi Iwai } 1936352f7f91STakashi Iwai } 1937352f7f91STakashi Iwai } 1938352f7f91STakashi Iwai 1939352f7f91STakashi Iwai snd_printdd("hda-codec: enabling ADC switching\n"); 1940352f7f91STakashi Iwai spec->dyn_adc_switch = 1; 1941352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) { 1942352f7f91STakashi Iwai memcpy(spec->adc_nids, adc_nids, nums * sizeof(hda_nid_t)); 1943352f7f91STakashi Iwai spec->num_adc_nids = nums; 1944352f7f91STakashi Iwai } 1945352f7f91STakashi Iwai 1946352f7f91STakashi Iwai if (imux->num_items == 1 || spec->shared_mic_hp) { 1947352f7f91STakashi Iwai snd_printdd("hda-codec: reducing to a single ADC\n"); 1948352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */ 1949352f7f91STakashi Iwai } 1950352f7f91STakashi Iwai 1951352f7f91STakashi Iwai /* single index for individual volumes ctls */ 1952352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol) 1953352f7f91STakashi Iwai spec->num_adc_nids = 1; 1954352f7f91STakashi Iwai 19551da177e4SLinus Torvalds return 0; 19561da177e4SLinus Torvalds } 19571da177e4SLinus Torvalds 19581da177e4SLinus Torvalds /* 1959352f7f91STakashi Iwai * create playback/capture controls for input pins 19601da177e4SLinus Torvalds */ 1961352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec) 1962a7da6ce5STakashi Iwai { 1963352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1964352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 1965352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid; 1966352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 1967352f7f91STakashi Iwai int num_adcs; 1968352f7f91STakashi Iwai int i, c, err, type_idx = 0; 1969352f7f91STakashi Iwai const char *prev_label = NULL; 1970a7da6ce5STakashi Iwai 1971352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec); 1972352f7f91STakashi Iwai if (num_adcs < 0) 1973352f7f91STakashi Iwai return 0; 1974352f7f91STakashi Iwai 1975352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1976352f7f91STakashi Iwai hda_nid_t pin; 1977352f7f91STakashi Iwai const char *label; 1978352f7f91STakashi Iwai bool imux_added; 1979352f7f91STakashi Iwai 1980352f7f91STakashi Iwai pin = cfg->inputs[i].pin; 1981352f7f91STakashi Iwai if (!is_input_pin(codec, pin)) 1982352f7f91STakashi Iwai continue; 1983352f7f91STakashi Iwai 1984352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 1985352f7f91STakashi Iwai if (spec->shared_mic_hp && !strcmp(label, "Misc")) 1986352f7f91STakashi Iwai label = "Headphone Mic"; 1987352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 1988352f7f91STakashi Iwai type_idx++; 1989352f7f91STakashi Iwai else 1990352f7f91STakashi Iwai type_idx = 0; 1991352f7f91STakashi Iwai prev_label = label; 1992352f7f91STakashi Iwai 1993352f7f91STakashi Iwai if (mixer) { 1994352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) { 1995196c1766STakashi Iwai err = new_analog_input(codec, i, pin, 1996352f7f91STakashi Iwai label, type_idx, mixer); 1997a7da6ce5STakashi Iwai if (err < 0) 1998a7da6ce5STakashi Iwai return err; 1999a7da6ce5STakashi Iwai } 2000352f7f91STakashi Iwai } 2001352f7f91STakashi Iwai 2002352f7f91STakashi Iwai imux_added = false; 2003352f7f91STakashi Iwai for (c = 0; c < num_adcs; c++) { 2004352f7f91STakashi Iwai struct nid_path *path; 2005352f7f91STakashi Iwai hda_nid_t adc = spec->adc_nids[c]; 2006352f7f91STakashi Iwai 2007352f7f91STakashi Iwai if (!is_reachable_path(codec, pin, adc)) 2008352f7f91STakashi Iwai continue; 2009352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 2010352f7f91STakashi Iwai if (!path) 2011352f7f91STakashi Iwai return -ENOMEM; 2012352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 20134ac0eefaSTakashi Iwai if (!snd_hda_parse_nid_path(codec, pin, adc, HDA_PARSE_ALL, path)) { 2014352f7f91STakashi Iwai snd_printd(KERN_ERR 2015352f7f91STakashi Iwai "invalid input path 0x%x -> 0x%x\n", 2016352f7f91STakashi Iwai pin, adc); 2017352f7f91STakashi Iwai spec->paths.used--; 2018352f7f91STakashi Iwai continue; 2019352f7f91STakashi Iwai } 20200c8c0f56STakashi Iwai print_nid_path("input", path); 2021352f7f91STakashi Iwai 2022352f7f91STakashi Iwai if (!imux_added) { 2023352f7f91STakashi Iwai spec->imux_pins[imux->num_items] = pin; 2024352f7f91STakashi Iwai snd_hda_add_imux_item(imux, label, 2025352f7f91STakashi Iwai imux->num_items, NULL); 2026352f7f91STakashi Iwai imux_added = true; 2027352f7f91STakashi Iwai } 2028352f7f91STakashi Iwai } 2029352f7f91STakashi Iwai } 2030352f7f91STakashi Iwai 2031a7da6ce5STakashi Iwai return 0; 2032a7da6ce5STakashi Iwai } 2033a7da6ce5STakashi Iwai 20341da177e4SLinus Torvalds 2035352f7f91STakashi Iwai /* 2036352f7f91STakashi Iwai * input source mux 2037352f7f91STakashi Iwai */ 2038352f7f91STakashi Iwai 2039352f7f91STakashi Iwai /* get the ADC NID corresponding to the given index */ 2040352f7f91STakashi Iwai static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx) 2041352f7f91STakashi Iwai { 2042352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2043352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2044352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx]; 2045352f7f91STakashi Iwai return spec->adc_nids[adc_idx]; 204697ec558aSTakashi Iwai } 2047352f7f91STakashi Iwai 2048352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2049352f7f91STakashi Iwai unsigned int idx); 2050352f7f91STakashi Iwai 2051352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol, 2052352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2053352f7f91STakashi Iwai { 2054352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2055352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2056352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo); 2057352f7f91STakashi Iwai } 2058352f7f91STakashi Iwai 2059352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol, 2060352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2061352f7f91STakashi Iwai { 2062352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2063352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2064352f7f91STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2065352f7f91STakashi Iwai 2066352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 20671da177e4SLinus Torvalds return 0; 20681da177e4SLinus Torvalds } 20691da177e4SLinus Torvalds 2070352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol, 2071352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 20721da177e4SLinus Torvalds { 2073352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2074352f7f91STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2075352f7f91STakashi Iwai return mux_select(codec, adc_idx, 2076352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]); 2077352f7f91STakashi Iwai } 2078352f7f91STakashi Iwai 2079352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = { 20801da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2081352f7f91STakashi Iwai .name = "Input Source", 2082352f7f91STakashi Iwai .info = mux_enum_info, 2083352f7f91STakashi Iwai .get = mux_enum_get, 2084352f7f91STakashi Iwai .put = mux_enum_put, 20851da177e4SLinus Torvalds }; 2086071c73adSTakashi Iwai 208747d46abbSTakashi Iwai /* 208847d46abbSTakashi Iwai * capture volume and capture switch ctls 208947d46abbSTakashi Iwai */ 209047d46abbSTakashi Iwai 2091352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, 2092352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol); 2093071c73adSTakashi Iwai 209447d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */ 2095352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol, 2096352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol, 2097352f7f91STakashi Iwai put_call_t func, int type) 2098352f7f91STakashi Iwai { 2099352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2100352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2101352f7f91STakashi Iwai const struct hda_input_mux *imux; 2102352f7f91STakashi Iwai struct nid_path *path; 2103352f7f91STakashi Iwai int i, adc_idx, err = 0; 2104071c73adSTakashi Iwai 2105352f7f91STakashi Iwai imux = &spec->input_mux; 2106352f7f91STakashi Iwai adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2107352f7f91STakashi Iwai mutex_lock(&codec->control_mutex); 210847d46abbSTakashi Iwai /* we use the cache-only update at first since multiple input paths 210947d46abbSTakashi Iwai * may shared the same amp; by updating only caches, the redundant 211047d46abbSTakashi Iwai * writes to hardware can be reduced. 211147d46abbSTakashi Iwai */ 2112352f7f91STakashi Iwai codec->cached_write = 1; 2113352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2114352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[i], 2115352f7f91STakashi Iwai get_adc_nid(codec, adc_idx, i)); 2116352f7f91STakashi Iwai if (!path->ctls[type]) 2117352f7f91STakashi Iwai continue; 2118352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type]; 2119352f7f91STakashi Iwai err = func(kcontrol, ucontrol); 2120352f7f91STakashi Iwai if (err < 0) 2121352f7f91STakashi Iwai goto error; 2122352f7f91STakashi Iwai } 2123352f7f91STakashi Iwai error: 2124352f7f91STakashi Iwai codec->cached_write = 0; 2125352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex); 212647d46abbSTakashi Iwai snd_hda_codec_flush_amp_cache(codec); /* flush the updates */ 2127352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook) 2128352f7f91STakashi Iwai spec->cap_sync_hook(codec); 2129352f7f91STakashi Iwai return err; 2130352f7f91STakashi Iwai } 2131352f7f91STakashi Iwai 2132352f7f91STakashi Iwai /* capture volume ctl callbacks */ 2133352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info 2134352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get 2135352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv 2136352f7f91STakashi Iwai 2137352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol, 2138352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2139352f7f91STakashi Iwai { 2140352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2141352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put, 2142352f7f91STakashi Iwai NID_PATH_VOL_CTL); 2143352f7f91STakashi Iwai } 2144352f7f91STakashi Iwai 2145352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = { 2146352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2147352f7f91STakashi Iwai .name = "Capture Volume", 2148352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 2149352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ | 2150352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), 2151352f7f91STakashi Iwai .info = cap_vol_info, 2152352f7f91STakashi Iwai .get = cap_vol_get, 2153352f7f91STakashi Iwai .put = cap_vol_put, 2154352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv }, 2155352f7f91STakashi Iwai }; 2156352f7f91STakashi Iwai 2157352f7f91STakashi Iwai /* capture switch ctl callbacks */ 2158352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info 2159352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get 2160352f7f91STakashi Iwai 2161352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol, 2162352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2163352f7f91STakashi Iwai { 2164352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2165352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put, 2166352f7f91STakashi Iwai NID_PATH_MUTE_CTL); 2167352f7f91STakashi Iwai } 2168352f7f91STakashi Iwai 2169352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = { 2170352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2171352f7f91STakashi Iwai .name = "Capture Switch", 2172352f7f91STakashi Iwai .info = cap_sw_info, 2173352f7f91STakashi Iwai .get = cap_sw_get, 2174352f7f91STakashi Iwai .put = cap_sw_put, 2175352f7f91STakashi Iwai }; 2176352f7f91STakashi Iwai 2177352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) 2178352f7f91STakashi Iwai { 2179352f7f91STakashi Iwai hda_nid_t nid; 2180352f7f91STakashi Iwai int i, depth; 2181352f7f91STakashi Iwai 2182352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; 2183352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) { 2184352f7f91STakashi Iwai if (depth >= path->depth) 2185352f7f91STakashi Iwai return -EINVAL; 2186352f7f91STakashi Iwai i = path->depth - depth - 1; 2187352f7f91STakashi Iwai nid = path->path[i]; 2188352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) { 2189352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 2190352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2191352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2192352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) { 2193352f7f91STakashi Iwai int idx = path->idx[i]; 2194352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2195352f7f91STakashi Iwai idx = 0; 2196352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2197352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2198352f7f91STakashi Iwai } 2199352f7f91STakashi Iwai } 2200352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) { 2201352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT)) 2202352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2203352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2204352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) { 2205352f7f91STakashi Iwai int idx = path->idx[i]; 2206352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2207352f7f91STakashi Iwai idx = 0; 2208352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2209352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2210352f7f91STakashi Iwai } 2211352f7f91STakashi Iwai } 2212352f7f91STakashi Iwai } 2213352f7f91STakashi Iwai return 0; 2214352f7f91STakashi Iwai } 2215352f7f91STakashi Iwai 2216352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) 2217352f7f91STakashi Iwai { 2218352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2219352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2220352f7f91STakashi Iwai unsigned int val; 2221352f7f91STakashi Iwai int i; 2222352f7f91STakashi Iwai 2223352f7f91STakashi Iwai if (!spec->inv_dmic_split) 2224352f7f91STakashi Iwai return false; 2225352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2226352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid) 2227352f7f91STakashi Iwai continue; 2228352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 2229352f7f91STakashi Iwai return false; 2230352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid); 2231352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; 2232352f7f91STakashi Iwai } 2233352f7f91STakashi Iwai return false; 2234352f7f91STakashi Iwai } 2235352f7f91STakashi Iwai 2236352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label, 2237352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl, 2238352f7f91STakashi Iwai bool inv_dmic) 2239352f7f91STakashi Iwai { 2240352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2241352f7f91STakashi Iwai char tmpname[44]; 2242352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; 2243352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume"; 2244352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3; 2245352f7f91STakashi Iwai int err; 2246352f7f91STakashi Iwai 2247352f7f91STakashi Iwai if (!ctl) 2248352f7f91STakashi Iwai return 0; 2249352f7f91STakashi Iwai 2250352f7f91STakashi Iwai if (label) 2251352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2252352f7f91STakashi Iwai "%s Capture %s", label, sfx); 2253352f7f91STakashi Iwai else 2254352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2255352f7f91STakashi Iwai "Capture %s", sfx); 2256352f7f91STakashi Iwai err = add_control(spec, type, tmpname, idx, 2257352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs)); 2258352f7f91STakashi Iwai if (err < 0 || !inv_dmic) 2259352f7f91STakashi Iwai return err; 2260352f7f91STakashi Iwai 2261352f7f91STakashi Iwai /* Make independent right kcontrol */ 2262352f7f91STakashi Iwai if (label) 2263352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2264352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx); 2265352f7f91STakashi Iwai else 2266352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2267352f7f91STakashi Iwai "Inverted Capture %s", sfx); 2268352f7f91STakashi Iwai return add_control(spec, type, tmpname, idx, 2269352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2)); 2270352f7f91STakashi Iwai } 2271352f7f91STakashi Iwai 2272352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */ 2273352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, 2274352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl, 2275352f7f91STakashi Iwai bool inv_dmic) 2276352f7f91STakashi Iwai { 2277352f7f91STakashi Iwai int err; 2278352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); 2279352f7f91STakashi Iwai if (err < 0) 2280352f7f91STakashi Iwai return err; 2281352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); 2282071c73adSTakashi Iwai if (err < 0) 2283071c73adSTakashi Iwai return err; 2284071c73adSTakashi Iwai return 0; 22851da177e4SLinus Torvalds } 2286071c73adSTakashi Iwai 2287352f7f91STakashi Iwai /* create bound capture volume and switch controls */ 2288352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, 2289352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl) 2290352f7f91STakashi Iwai { 2291352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2292352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2293352f7f91STakashi Iwai 2294352f7f91STakashi Iwai if (vol_ctl) { 229512c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); 2296352f7f91STakashi Iwai if (!knew) 2297352f7f91STakashi Iwai return -ENOMEM; 2298352f7f91STakashi Iwai knew->index = idx; 2299352f7f91STakashi Iwai knew->private_value = vol_ctl; 2300352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2301352f7f91STakashi Iwai } 2302352f7f91STakashi Iwai if (sw_ctl) { 230312c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); 2304352f7f91STakashi Iwai if (!knew) 2305352f7f91STakashi Iwai return -ENOMEM; 2306352f7f91STakashi Iwai knew->index = idx; 2307352f7f91STakashi Iwai knew->private_value = sw_ctl; 2308352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2309352f7f91STakashi Iwai } 2310352f7f91STakashi Iwai return 0; 2311352f7f91STakashi Iwai } 2312352f7f91STakashi Iwai 2313352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */ 2314352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) 2315352f7f91STakashi Iwai { 2316352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2317352f7f91STakashi Iwai struct nid_path *path; 2318352f7f91STakashi Iwai unsigned int ctl; 2319352f7f91STakashi Iwai int i; 2320352f7f91STakashi Iwai 2321352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[idx], 2322352f7f91STakashi Iwai get_adc_nid(codec, 0, idx)); 2323352f7f91STakashi Iwai if (!path) 2324352f7f91STakashi Iwai return 0; 2325352f7f91STakashi Iwai ctl = path->ctls[type]; 2326352f7f91STakashi Iwai if (!ctl) 2327352f7f91STakashi Iwai return 0; 2328352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) { 2329352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[i], 2330352f7f91STakashi Iwai get_adc_nid(codec, 0, i)); 2331352f7f91STakashi Iwai if (path && path->ctls[type] == ctl) 2332352f7f91STakashi Iwai return 0; 2333352f7f91STakashi Iwai } 2334352f7f91STakashi Iwai return ctl; 2335352f7f91STakashi Iwai } 2336352f7f91STakashi Iwai 2337352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */ 2338352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec) 2339352f7f91STakashi Iwai { 2340352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2341352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2342352f7f91STakashi Iwai int i, err, type, type_idx = 0; 2343352f7f91STakashi Iwai const char *prev_label = NULL; 2344352f7f91STakashi Iwai 2345352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2346352f7f91STakashi Iwai const char *label; 2347352f7f91STakashi Iwai bool inv_dmic; 2348352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, &spec->autocfg, i); 2349352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2350352f7f91STakashi Iwai type_idx++; 2351352f7f91STakashi Iwai else 2352352f7f91STakashi Iwai type_idx = 0; 2353352f7f91STakashi Iwai prev_label = label; 2354352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); 2355352f7f91STakashi Iwai 2356352f7f91STakashi Iwai for (type = 0; type < 2; type++) { 2357352f7f91STakashi Iwai err = add_single_cap_ctl(codec, label, type_idx, type, 2358352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type), 2359352f7f91STakashi Iwai inv_dmic); 2360d13bd412STakashi Iwai if (err < 0) 2361071c73adSTakashi Iwai return err; 2362352f7f91STakashi Iwai } 2363352f7f91STakashi Iwai } 2364071c73adSTakashi Iwai return 0; 2365352f7f91STakashi Iwai } 2366071c73adSTakashi Iwai 2367352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec) 2368352f7f91STakashi Iwai { 2369352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2370352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2371352f7f91STakashi Iwai int i, n, nums, err; 2372352f7f91STakashi Iwai 2373352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2374352f7f91STakashi Iwai nums = 1; 2375352f7f91STakashi Iwai else 2376352f7f91STakashi Iwai nums = spec->num_adc_nids; 2377352f7f91STakashi Iwai 2378352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) { 2379352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2380624d914dSTakashi Iwai const char *name; 2381624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source"; 2382624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); 2383352f7f91STakashi Iwai if (!knew) 2384352f7f91STakashi Iwai return -ENOMEM; 2385352f7f91STakashi Iwai knew->count = nums; 2386352f7f91STakashi Iwai } 2387352f7f91STakashi Iwai 2388352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 2389352f7f91STakashi Iwai bool multi = false; 2390352f7f91STakashi Iwai bool inv_dmic = false; 2391352f7f91STakashi Iwai int vol, sw; 2392352f7f91STakashi Iwai 2393352f7f91STakashi Iwai vol = sw = 0; 2394352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2395352f7f91STakashi Iwai struct nid_path *path; 2396352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[i], 2397352f7f91STakashi Iwai get_adc_nid(codec, n, i)); 2398352f7f91STakashi Iwai if (!path) 2399352f7f91STakashi Iwai continue; 2400352f7f91STakashi Iwai parse_capvol_in_path(codec, path); 2401352f7f91STakashi Iwai if (!vol) 2402352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL]; 2403352f7f91STakashi Iwai else if (vol != path->ctls[NID_PATH_VOL_CTL]) 2404352f7f91STakashi Iwai multi = true; 2405352f7f91STakashi Iwai if (!sw) 2406352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL]; 2407352f7f91STakashi Iwai else if (sw != path->ctls[NID_PATH_MUTE_CTL]) 2408352f7f91STakashi Iwai multi = true; 2409352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i])) 2410352f7f91STakashi Iwai inv_dmic = true; 2411352f7f91STakashi Iwai } 2412352f7f91STakashi Iwai 2413352f7f91STakashi Iwai if (!multi) 2414352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw, 2415352f7f91STakashi Iwai inv_dmic); 2416352f7f91STakashi Iwai else if (!spec->multi_cap_vol) 2417352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw); 2418352f7f91STakashi Iwai else 2419352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec); 2420d13bd412STakashi Iwai if (err < 0) 2421071c73adSTakashi Iwai return err; 2422071c73adSTakashi Iwai } 2423071c73adSTakashi Iwai 24241da177e4SLinus Torvalds return 0; 24251da177e4SLinus Torvalds } 24261da177e4SLinus Torvalds 2427352f7f91STakashi Iwai /* 2428352f7f91STakashi Iwai * add mic boosts if needed 2429352f7f91STakashi Iwai */ 2430352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec) 2431352f7f91STakashi Iwai { 2432352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2433352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2434352f7f91STakashi Iwai int i, err; 2435352f7f91STakashi Iwai int type_idx = 0; 2436352f7f91STakashi Iwai hda_nid_t nid; 2437352f7f91STakashi Iwai const char *prev_label = NULL; 2438352f7f91STakashi Iwai 2439352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2440352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_MIC) 2441352f7f91STakashi Iwai break; 2442352f7f91STakashi Iwai nid = cfg->inputs[i].pin; 2443352f7f91STakashi Iwai if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { 2444352f7f91STakashi Iwai const char *label; 2445352f7f91STakashi Iwai char boost_label[32]; 2446352f7f91STakashi Iwai struct nid_path *path; 2447352f7f91STakashi Iwai unsigned int val; 2448352f7f91STakashi Iwai 2449352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2450352f7f91STakashi Iwai if (spec->shared_mic_hp && !strcmp(label, "Misc")) 2451352f7f91STakashi Iwai label = "Headphone Mic"; 2452352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2453352f7f91STakashi Iwai type_idx++; 2454352f7f91STakashi Iwai else 2455352f7f91STakashi Iwai type_idx = 0; 2456352f7f91STakashi Iwai prev_label = label; 2457352f7f91STakashi Iwai 2458352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label), 2459352f7f91STakashi Iwai "%s Boost Volume", label); 2460352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 2461352f7f91STakashi Iwai err = add_control(spec, HDA_CTL_WIDGET_VOL, 2462352f7f91STakashi Iwai boost_label, type_idx, val); 2463352f7f91STakashi Iwai if (err < 0) 2464352f7f91STakashi Iwai return err; 2465352f7f91STakashi Iwai 2466352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, nid, 0); 2467352f7f91STakashi Iwai if (path) 2468352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val; 2469352f7f91STakashi Iwai } 2470352f7f91STakashi Iwai } 2471352f7f91STakashi Iwai return 0; 2472352f7f91STakashi Iwai } 2473352f7f91STakashi Iwai 2474352f7f91STakashi Iwai /* 2475352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 2476352f7f91STakashi Iwai */ 2477352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 2478352f7f91STakashi Iwai { 2479352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 24800c8c0f56STakashi Iwai struct nid_path *path; 2481352f7f91STakashi Iwai int i, nums; 2482352f7f91STakashi Iwai hda_nid_t dig_nid; 2483352f7f91STakashi Iwai 2484352f7f91STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a slave */ 2485352f7f91STakashi Iwai nums = 0; 2486352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 2487352f7f91STakashi Iwai hda_nid_t pin = spec->autocfg.dig_out_pins[i]; 2488352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 2489352f7f91STakashi Iwai if (!dig_nid) 2490352f7f91STakashi Iwai continue; 24914ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, HDA_PARSE_ALL); 24920c8c0f56STakashi Iwai if (!path) 2493352f7f91STakashi Iwai continue; 24940c8c0f56STakashi Iwai print_nid_path("digout", path); 2495e1284af7STakashi Iwai path->active = true; 2496196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 2497352f7f91STakashi Iwai if (!nums) { 2498352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 2499352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 2500352f7f91STakashi Iwai } else { 2501352f7f91STakashi Iwai spec->multiout.slave_dig_outs = spec->slave_dig_outs; 2502352f7f91STakashi Iwai if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) 2503352f7f91STakashi Iwai break; 2504352f7f91STakashi Iwai spec->slave_dig_outs[nums - 1] = dig_nid; 2505352f7f91STakashi Iwai } 2506352f7f91STakashi Iwai nums++; 2507352f7f91STakashi Iwai } 2508352f7f91STakashi Iwai 2509352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 2510352f7f91STakashi Iwai dig_nid = codec->start_nid; 2511352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, dig_nid++) { 2512352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 2513352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 2514352f7f91STakashi Iwai continue; 2515352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 2516352f7f91STakashi Iwai continue; 2517352f7f91STakashi Iwai path = snd_hda_add_new_path(codec, 2518352f7f91STakashi Iwai spec->autocfg.dig_in_pin, 25194ac0eefaSTakashi Iwai dig_nid, HDA_PARSE_ALL); 2520352f7f91STakashi Iwai if (path) { 25210c8c0f56STakashi Iwai print_nid_path("digin", path); 2522352f7f91STakashi Iwai path->active = true; 2523352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 25242430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 2525352f7f91STakashi Iwai break; 2526352f7f91STakashi Iwai } 2527352f7f91STakashi Iwai } 2528352f7f91STakashi Iwai } 2529352f7f91STakashi Iwai } 2530352f7f91STakashi Iwai 25311da177e4SLinus Torvalds 25321da177e4SLinus Torvalds /* 2533352f7f91STakashi Iwai * input MUX handling 25341da177e4SLinus Torvalds */ 25351da177e4SLinus Torvalds 2536352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 2537352f7f91STakashi Iwai 2538352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 2539352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2540352f7f91STakashi Iwai unsigned int idx) 2541352f7f91STakashi Iwai { 2542352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2543352f7f91STakashi Iwai const struct hda_input_mux *imux; 2544352f7f91STakashi Iwai struct nid_path *path; 2545352f7f91STakashi Iwai 2546352f7f91STakashi Iwai imux = &spec->input_mux; 2547352f7f91STakashi Iwai if (!imux->num_items) 25481da177e4SLinus Torvalds return 0; 25491da177e4SLinus Torvalds 2550352f7f91STakashi Iwai if (idx >= imux->num_items) 2551352f7f91STakashi Iwai idx = imux->num_items - 1; 2552352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 2553352f7f91STakashi Iwai return 0; 2554352f7f91STakashi Iwai 2555352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, 2556352f7f91STakashi Iwai spec->imux_pins[spec->cur_mux[adc_idx]], 2557352f7f91STakashi Iwai spec->adc_nids[adc_idx]); 2558352f7f91STakashi Iwai if (!path) 2559352f7f91STakashi Iwai return 0; 2560352f7f91STakashi Iwai if (path->active) 2561352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, false); 2562352f7f91STakashi Iwai 2563352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 2564352f7f91STakashi Iwai 2565352f7f91STakashi Iwai if (spec->shared_mic_hp) 2566352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); 2567352f7f91STakashi Iwai 2568352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2569352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 2570352f7f91STakashi Iwai 2571352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[idx], 2572352f7f91STakashi Iwai get_adc_nid(codec, adc_idx, idx)); 2573352f7f91STakashi Iwai if (!path) 2574352f7f91STakashi Iwai return 0; 2575352f7f91STakashi Iwai if (path->active) 2576352f7f91STakashi Iwai return 0; 2577352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 2578352f7f91STakashi Iwai if (spec->cap_sync_hook) 2579352f7f91STakashi Iwai spec->cap_sync_hook(codec); 25801da177e4SLinus Torvalds return 1; 25811da177e4SLinus Torvalds } 25821da177e4SLinus Torvalds 25831da177e4SLinus Torvalds 25841da177e4SLinus Torvalds /* 2585352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 25861da177e4SLinus Torvalds */ 2587352f7f91STakashi Iwai 2588352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 2589352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) 25901da177e4SLinus Torvalds { 2591352f7f91STakashi Iwai int i, present = 0; 25921da177e4SLinus Torvalds 2593352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2594352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 2595352f7f91STakashi Iwai if (!nid) 2596352f7f91STakashi Iwai break; 2597352f7f91STakashi Iwai present |= snd_hda_jack_detect(codec, nid); 25981da177e4SLinus Torvalds } 2599352f7f91STakashi Iwai return present; 26001da177e4SLinus Torvalds } 26011da177e4SLinus Torvalds 2602352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 2603352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, 2604352f7f91STakashi Iwai bool mute, bool hp_out) 26051da177e4SLinus Torvalds { 2606352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2607352f7f91STakashi Iwai unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT); 2608352f7f91STakashi Iwai int i; 26091da177e4SLinus Torvalds 2610352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2611352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 2612352f7f91STakashi Iwai unsigned int val; 2613352f7f91STakashi Iwai if (!nid) 2614352f7f91STakashi Iwai break; 2615352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 2616352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 2617352f7f91STakashi Iwai */ 2618352f7f91STakashi Iwai if (spec->keep_vref_in_automute) { 2619352f7f91STakashi Iwai val = snd_hda_codec_read(codec, nid, 0, 2620352f7f91STakashi Iwai AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 2621352f7f91STakashi Iwai val &= ~PIN_HP; 2622352f7f91STakashi Iwai } else 2623352f7f91STakashi Iwai val = 0; 2624352f7f91STakashi Iwai val |= pin_bits; 26257594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2626d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 2627352f7f91STakashi Iwai } 2628352f7f91STakashi Iwai } 26291da177e4SLinus Torvalds 2630352f7f91STakashi Iwai /* Toggle outputs muting */ 26315d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 2632352f7f91STakashi Iwai { 2633352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2634352f7f91STakashi Iwai int on; 2635352f7f91STakashi Iwai 2636352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 2637352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 2638352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 2639352f7f91STakashi Iwai */ 2640352f7f91STakashi Iwai if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ 2641352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 2642352f7f91STakashi Iwai spec->autocfg.hp_pins, spec->master_mute, true); 2643352f7f91STakashi Iwai 2644352f7f91STakashi Iwai if (!spec->automute_speaker) 2645352f7f91STakashi Iwai on = 0; 2646352f7f91STakashi Iwai else 2647352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 2648352f7f91STakashi Iwai on |= spec->master_mute; 2649352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 2650352f7f91STakashi Iwai spec->autocfg.speaker_pins, on, false); 2651352f7f91STakashi Iwai 2652352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 2653352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 2654352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 2655352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 2656352f7f91STakashi Iwai return; 2657352f7f91STakashi Iwai if (!spec->automute_lo) 2658352f7f91STakashi Iwai on = 0; 2659352f7f91STakashi Iwai else 2660352f7f91STakashi Iwai on = spec->hp_jack_present; 2661352f7f91STakashi Iwai on |= spec->master_mute; 2662352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 2663352f7f91STakashi Iwai spec->autocfg.line_out_pins, on, false); 2664352f7f91STakashi Iwai } 26655d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); 2666352f7f91STakashi Iwai 2667352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 2668352f7f91STakashi Iwai { 2669352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2670352f7f91STakashi Iwai if (spec->automute_hook) 2671352f7f91STakashi Iwai spec->automute_hook(codec); 2672352f7f91STakashi Iwai else 26735d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 2674352f7f91STakashi Iwai } 2675352f7f91STakashi Iwai 2676352f7f91STakashi Iwai /* standard HP-automute helper */ 26775d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 2678352f7f91STakashi Iwai { 2679352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2680352f7f91STakashi Iwai 2681352f7f91STakashi Iwai spec->hp_jack_present = 2682352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 2683352f7f91STakashi Iwai spec->autocfg.hp_pins); 2684352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 2685352f7f91STakashi Iwai return; 2686352f7f91STakashi Iwai call_update_outputs(codec); 2687352f7f91STakashi Iwai } 26885d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute); 2689352f7f91STakashi Iwai 2690352f7f91STakashi Iwai /* standard line-out-automute helper */ 26915d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 2692352f7f91STakashi Iwai { 2693352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2694352f7f91STakashi Iwai 2695352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 2696352f7f91STakashi Iwai return; 2697352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 2698352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 2699352f7f91STakashi Iwai return; 2700352f7f91STakashi Iwai 2701352f7f91STakashi Iwai spec->line_jack_present = 2702352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 2703352f7f91STakashi Iwai spec->autocfg.line_out_pins); 2704352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 2705352f7f91STakashi Iwai return; 2706352f7f91STakashi Iwai call_update_outputs(codec); 2707352f7f91STakashi Iwai } 27085d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute); 2709352f7f91STakashi Iwai 2710352f7f91STakashi Iwai /* standard mic auto-switch helper */ 27115d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) 2712352f7f91STakashi Iwai { 2713352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2714352f7f91STakashi Iwai int i; 2715352f7f91STakashi Iwai 2716352f7f91STakashi Iwai if (!spec->auto_mic) 2717352f7f91STakashi Iwai return; 2718352f7f91STakashi Iwai 2719352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 2720352f7f91STakashi Iwai if (snd_hda_jack_detect(codec, spec->am_entry[i].pin)) { 2721352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 2722352f7f91STakashi Iwai return; 2723352f7f91STakashi Iwai } 2724352f7f91STakashi Iwai } 2725352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 27261da177e4SLinus Torvalds } 27275d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch); 27281da177e4SLinus Torvalds 27291da177e4SLinus Torvalds /* 2730352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 27311da177e4SLinus Torvalds */ 2732352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 2733352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2734352f7f91STakashi Iwai { 2735352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2736352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2737352f7f91STakashi Iwai static const char * const texts3[] = { 2738352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 27391da177e4SLinus Torvalds }; 27401da177e4SLinus Torvalds 2741352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 2742352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 2743352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 2744352f7f91STakashi Iwai } 2745352f7f91STakashi Iwai 2746352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 2747352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2748352f7f91STakashi Iwai { 2749352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2750352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2751352f7f91STakashi Iwai unsigned int val = 0; 2752352f7f91STakashi Iwai if (spec->automute_speaker) 2753352f7f91STakashi Iwai val++; 2754352f7f91STakashi Iwai if (spec->automute_lo) 2755352f7f91STakashi Iwai val++; 2756352f7f91STakashi Iwai 2757352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 2758352f7f91STakashi Iwai return 0; 2759352f7f91STakashi Iwai } 2760352f7f91STakashi Iwai 2761352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 2762352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2763352f7f91STakashi Iwai { 2764352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2765352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2766352f7f91STakashi Iwai 2767352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 2768352f7f91STakashi Iwai case 0: 2769352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 2770352f7f91STakashi Iwai return 0; 2771352f7f91STakashi Iwai spec->automute_speaker = 0; 2772352f7f91STakashi Iwai spec->automute_lo = 0; 2773352f7f91STakashi Iwai break; 2774352f7f91STakashi Iwai case 1: 2775352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 2776352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 2777352f7f91STakashi Iwai return 0; 2778352f7f91STakashi Iwai spec->automute_speaker = 1; 2779352f7f91STakashi Iwai spec->automute_lo = 0; 2780352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 2781352f7f91STakashi Iwai if (spec->automute_lo) 2782352f7f91STakashi Iwai return 0; 2783352f7f91STakashi Iwai spec->automute_lo = 1; 2784352f7f91STakashi Iwai } else 2785352f7f91STakashi Iwai return -EINVAL; 2786352f7f91STakashi Iwai break; 2787352f7f91STakashi Iwai case 2: 2788352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 2789352f7f91STakashi Iwai return -EINVAL; 2790352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 2791352f7f91STakashi Iwai return 0; 2792352f7f91STakashi Iwai spec->automute_speaker = 1; 2793352f7f91STakashi Iwai spec->automute_lo = 1; 2794352f7f91STakashi Iwai break; 2795352f7f91STakashi Iwai default: 2796352f7f91STakashi Iwai return -EINVAL; 2797352f7f91STakashi Iwai } 2798352f7f91STakashi Iwai call_update_outputs(codec); 2799352f7f91STakashi Iwai return 1; 2800352f7f91STakashi Iwai } 2801352f7f91STakashi Iwai 2802352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 2803352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2804352f7f91STakashi Iwai .name = "Auto-Mute Mode", 2805352f7f91STakashi Iwai .info = automute_mode_info, 2806352f7f91STakashi Iwai .get = automute_mode_get, 2807352f7f91STakashi Iwai .put = automute_mode_put, 2808352f7f91STakashi Iwai }; 2809352f7f91STakashi Iwai 2810352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 2811352f7f91STakashi Iwai { 2812352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2813352f7f91STakashi Iwai 281412c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 2815352f7f91STakashi Iwai return -ENOMEM; 2816352f7f91STakashi Iwai return 0; 2817352f7f91STakashi Iwai } 2818352f7f91STakashi Iwai 2819352f7f91STakashi Iwai /* 2820352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 2821352f7f91STakashi Iwai * Set up appropriately if really supported 2822352f7f91STakashi Iwai */ 2823352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 2824352f7f91STakashi Iwai { 2825352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2826352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2827352f7f91STakashi Iwai int present = 0; 2828352f7f91STakashi Iwai int i, err; 2829352f7f91STakashi Iwai 2830352f7f91STakashi Iwai if (cfg->hp_pins[0]) 2831352f7f91STakashi Iwai present++; 2832352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 2833352f7f91STakashi Iwai present++; 2834352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 2835352f7f91STakashi Iwai present++; 2836352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 2837352f7f91STakashi Iwai return 0; 2838352f7f91STakashi Iwai 2839352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 2840352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 2841352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 2842352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 2843352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 2844352f7f91STakashi Iwai } 2845352f7f91STakashi Iwai 2846352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 2847352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 2848352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 2849352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 2850352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 2851352f7f91STakashi Iwai } 2852352f7f91STakashi Iwai 2853352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 2854352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 2855352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 2856352f7f91STakashi Iwai continue; 2857352f7f91STakashi Iwai snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n", 2858352f7f91STakashi Iwai nid); 2859352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, 28602e03e952STakashi Iwai spec->hp_automute_hook ? 28612e03e952STakashi Iwai spec->hp_automute_hook : 28625d550e15STakashi Iwai snd_hda_gen_hp_automute); 2863352f7f91STakashi Iwai spec->detect_hp = 1; 2864352f7f91STakashi Iwai } 2865352f7f91STakashi Iwai 2866352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 2867352f7f91STakashi Iwai if (cfg->speaker_outs) 2868352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 2869352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 2870352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 2871352f7f91STakashi Iwai continue; 2872352f7f91STakashi Iwai snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid); 2873352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 2874352f7f91STakashi Iwai HDA_GEN_FRONT_EVENT, 28752e03e952STakashi Iwai spec->line_automute_hook ? 28762e03e952STakashi Iwai spec->line_automute_hook : 28775d550e15STakashi Iwai snd_hda_gen_line_automute); 2878352f7f91STakashi Iwai spec->detect_lo = 1; 2879352f7f91STakashi Iwai } 2880352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 2881352f7f91STakashi Iwai } 2882352f7f91STakashi Iwai 2883352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 2884352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 2885352f7f91STakashi Iwai 2886352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 2887352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 2888352f7f91STakashi Iwai 2889352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 2890352f7f91STakashi Iwai /* create a control for automute mode */ 2891352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 2892352f7f91STakashi Iwai if (err < 0) 2893352f7f91STakashi Iwai return err; 2894352f7f91STakashi Iwai } 2895352f7f91STakashi Iwai return 0; 2896352f7f91STakashi Iwai } 2897352f7f91STakashi Iwai 2898352f7f91STakashi Iwai /* return the position of NID in the list, or -1 if not found */ 2899352f7f91STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 2900352f7f91STakashi Iwai { 2901352f7f91STakashi Iwai int i; 2902352f7f91STakashi Iwai for (i = 0; i < nums; i++) 2903352f7f91STakashi Iwai if (list[i] == nid) 2904352f7f91STakashi Iwai return i; 2905352f7f91STakashi Iwai return -1; 2906352f7f91STakashi Iwai } 2907352f7f91STakashi Iwai 2908352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 2909352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 2910352f7f91STakashi Iwai { 2911352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2912352f7f91STakashi Iwai const struct hda_input_mux *imux; 2913352f7f91STakashi Iwai int i; 2914352f7f91STakashi Iwai 2915352f7f91STakashi Iwai imux = &spec->input_mux; 2916352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 2917352f7f91STakashi Iwai spec->am_entry[i].idx = 2918352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 2919352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 2920352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 2921352f7f91STakashi Iwai return false; /* no corresponding imux */ 2922352f7f91STakashi Iwai } 2923352f7f91STakashi Iwai 2924352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 2925352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 2926352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 2927352f7f91STakashi Iwai spec->am_entry[i].pin, 2928352f7f91STakashi Iwai HDA_GEN_MIC_EVENT, 29292e03e952STakashi Iwai spec->mic_autoswitch_hook ? 29302e03e952STakashi Iwai spec->mic_autoswitch_hook : 29315d550e15STakashi Iwai snd_hda_gen_mic_autoswitch); 2932352f7f91STakashi Iwai return true; 2933352f7f91STakashi Iwai } 2934352f7f91STakashi Iwai 2935352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 2936352f7f91STakashi Iwai { 2937352f7f91STakashi Iwai const struct automic_entry *a = ap; 2938352f7f91STakashi Iwai const struct automic_entry *b = bp; 2939352f7f91STakashi Iwai return (int)(a->attr - b->attr); 2940352f7f91STakashi Iwai } 2941352f7f91STakashi Iwai 2942352f7f91STakashi Iwai /* 2943352f7f91STakashi Iwai * Check the availability of auto-mic switch; 2944352f7f91STakashi Iwai * Set up if really supported 2945352f7f91STakashi Iwai */ 2946352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 2947352f7f91STakashi Iwai { 2948352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2949352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2950352f7f91STakashi Iwai unsigned int types; 2951352f7f91STakashi Iwai int i, num_pins; 2952352f7f91STakashi Iwai 2953352f7f91STakashi Iwai types = 0; 2954352f7f91STakashi Iwai num_pins = 0; 2955352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2956352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 2957352f7f91STakashi Iwai unsigned int attr; 2958352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 2959352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 2960352f7f91STakashi Iwai if (types & (1 << attr)) 2961352f7f91STakashi Iwai return 0; /* already occupied */ 2962352f7f91STakashi Iwai switch (attr) { 2963352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 2964352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 2965352f7f91STakashi Iwai return 0; /* invalid type */ 2966352f7f91STakashi Iwai break; 2967352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 2968352f7f91STakashi Iwai return 0; /* invalid entry */ 2969352f7f91STakashi Iwai default: 2970352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 2971352f7f91STakashi Iwai return 0; /* invalid type */ 2972352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 2973352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 2974352f7f91STakashi Iwai return 0; /* only mic is allowed */ 2975352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 2976352f7f91STakashi Iwai return 0; /* no unsol support */ 2977352f7f91STakashi Iwai break; 2978352f7f91STakashi Iwai } 2979352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 2980352f7f91STakashi Iwai return 0; 2981352f7f91STakashi Iwai types |= (1 << attr); 2982352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 2983352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 2984352f7f91STakashi Iwai num_pins++; 2985352f7f91STakashi Iwai } 2986352f7f91STakashi Iwai 2987352f7f91STakashi Iwai if (num_pins < 2) 2988352f7f91STakashi Iwai return 0; 2989352f7f91STakashi Iwai 2990352f7f91STakashi Iwai spec->am_num_entries = num_pins; 2991352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 2992352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 2993352f7f91STakashi Iwai */ 2994352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 2995352f7f91STakashi Iwai compare_attr, NULL); 2996352f7f91STakashi Iwai 2997352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 2998352f7f91STakashi Iwai return 0; 2999352f7f91STakashi Iwai 3000352f7f91STakashi Iwai spec->auto_mic = 1; 3001352f7f91STakashi Iwai spec->num_adc_nids = 1; 3002352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 3003352f7f91STakashi Iwai snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 3004352f7f91STakashi Iwai spec->am_entry[0].pin, 3005352f7f91STakashi Iwai spec->am_entry[1].pin, 3006352f7f91STakashi Iwai spec->am_entry[2].pin); 3007352f7f91STakashi Iwai 3008352f7f91STakashi Iwai return 0; 3009352f7f91STakashi Iwai } 3010352f7f91STakashi Iwai 3011352f7f91STakashi Iwai 30129eb413e5STakashi Iwai /* 30139eb413e5STakashi Iwai * Parse the given BIOS configuration and set up the hda_gen_spec 30149eb413e5STakashi Iwai * 30159eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 3016352f7f91STakashi Iwai * or a negative error code 3017352f7f91STakashi Iwai */ 3018352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 30199eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 3020352f7f91STakashi Iwai { 3021352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3022352f7f91STakashi Iwai int err; 3023352f7f91STakashi Iwai 30249eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 30259eb413e5STakashi Iwai spec->autocfg = *cfg; 30269eb413e5STakashi Iwai cfg = &spec->autocfg; 30279eb413e5STakashi Iwai } 30289eb413e5STakashi Iwai 3029352f7f91STakashi Iwai if (!cfg->line_outs) { 3030352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 3031352f7f91STakashi Iwai spec->multiout.max_channels = 2; 3032352f7f91STakashi Iwai spec->no_analog = 1; 3033352f7f91STakashi Iwai goto dig_only; 3034352f7f91STakashi Iwai } 3035352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 3036352f7f91STakashi Iwai } 3037352f7f91STakashi Iwai 3038352f7f91STakashi Iwai if (!spec->no_primary_hp && 3039352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 3040352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 3041352f7f91STakashi Iwai /* use HP as primary out */ 3042352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3043352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3044352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3045352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 3046352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 3047352f7f91STakashi Iwai cfg->hp_outs = 0; 3048352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 3049352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 3050352f7f91STakashi Iwai } 3051352f7f91STakashi Iwai 3052352f7f91STakashi Iwai err = parse_output_paths(codec); 3053352f7f91STakashi Iwai if (err < 0) 3054352f7f91STakashi Iwai return err; 3055352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 3056352f7f91STakashi Iwai if (err < 0) 3057352f7f91STakashi Iwai return err; 3058352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 3059352f7f91STakashi Iwai if (err < 0) 3060352f7f91STakashi Iwai return err; 3061352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 3062352f7f91STakashi Iwai if (err < 0) 3063352f7f91STakashi Iwai return err; 3064352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 3065352f7f91STakashi Iwai if (err < 0) 3066352f7f91STakashi Iwai return err; 306738cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 306838cf6f1aSTakashi Iwai if (err < 0) 306938cf6f1aSTakashi Iwai return err; 3070352f7f91STakashi Iwai err = create_shared_input(codec); 3071352f7f91STakashi Iwai if (err < 0) 3072352f7f91STakashi Iwai return err; 3073352f7f91STakashi Iwai err = create_input_ctls(codec); 3074352f7f91STakashi Iwai if (err < 0) 3075352f7f91STakashi Iwai return err; 3076352f7f91STakashi Iwai 3077352f7f91STakashi Iwai /* check the multiple speaker pins */ 3078352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 3079352f7f91STakashi Iwai spec->const_channel_count = cfg->line_outs * 2; 3080352f7f91STakashi Iwai else 3081352f7f91STakashi Iwai spec->const_channel_count = cfg->speaker_outs * 2; 3082352f7f91STakashi Iwai 3083352f7f91STakashi Iwai if (spec->multi_ios > 0) 3084352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 3085352f7f91STakashi Iwai spec->const_channel_count); 3086352f7f91STakashi Iwai else 3087352f7f91STakashi Iwai spec->multiout.max_channels = spec->multiout.num_dacs * 2; 3088352f7f91STakashi Iwai 3089352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 3090352f7f91STakashi Iwai if (err < 0) 3091352f7f91STakashi Iwai return err; 3092352f7f91STakashi Iwai 3093352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 3094352f7f91STakashi Iwai if (err < 0) 3095352f7f91STakashi Iwai return err; 3096352f7f91STakashi Iwai 3097352f7f91STakashi Iwai if (!spec->shared_mic_hp) { 3098352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 3099352f7f91STakashi Iwai if (err < 0) 3100352f7f91STakashi Iwai return err; 3101352f7f91STakashi Iwai } 3102352f7f91STakashi Iwai 3103352f7f91STakashi Iwai err = create_capture_mixers(codec); 3104352f7f91STakashi Iwai if (err < 0) 3105352f7f91STakashi Iwai return err; 3106352f7f91STakashi Iwai 3107352f7f91STakashi Iwai err = parse_mic_boost(codec); 3108352f7f91STakashi Iwai if (err < 0) 3109352f7f91STakashi Iwai return err; 3110352f7f91STakashi Iwai 3111352f7f91STakashi Iwai dig_only: 3112352f7f91STakashi Iwai parse_digital(codec); 3113352f7f91STakashi Iwai 3114352f7f91STakashi Iwai return 1; 3115352f7f91STakashi Iwai } 3116352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); 3117352f7f91STakashi Iwai 3118352f7f91STakashi Iwai 3119352f7f91STakashi Iwai /* 3120352f7f91STakashi Iwai * Build control elements 3121352f7f91STakashi Iwai */ 3122352f7f91STakashi Iwai 3123352f7f91STakashi Iwai /* slave controls for virtual master */ 3124352f7f91STakashi Iwai static const char * const slave_pfxs[] = { 3125352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 3126352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 3127352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 3128352f7f91STakashi Iwai NULL, 3129352f7f91STakashi Iwai }; 3130352f7f91STakashi Iwai 3131352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 3132352f7f91STakashi Iwai { 3133352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3134352f7f91STakashi Iwai int err; 3135352f7f91STakashi Iwai 313636502d02STakashi Iwai if (spec->kctls.used) { 3137352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 3138352f7f91STakashi Iwai if (err < 0) 3139352f7f91STakashi Iwai return err; 314036502d02STakashi Iwai } 3141352f7f91STakashi Iwai 3142352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3143352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 3144352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3145352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3146352f7f91STakashi Iwai spec->pcm_rec[1].pcm_type); 3147352f7f91STakashi Iwai if (err < 0) 3148352f7f91STakashi Iwai return err; 3149352f7f91STakashi Iwai if (!spec->no_analog) { 3150352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 3151352f7f91STakashi Iwai &spec->multiout); 3152352f7f91STakashi Iwai if (err < 0) 3153352f7f91STakashi Iwai return err; 3154352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 3155352f7f91STakashi Iwai } 3156352f7f91STakashi Iwai } 3157352f7f91STakashi Iwai if (spec->dig_in_nid) { 3158352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 3159352f7f91STakashi Iwai if (err < 0) 3160352f7f91STakashi Iwai return err; 3161352f7f91STakashi Iwai } 3162352f7f91STakashi Iwai 3163352f7f91STakashi Iwai /* if we have no master control, let's create it */ 3164352f7f91STakashi Iwai if (!spec->no_analog && 3165352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 3166352f7f91STakashi Iwai unsigned int vmaster_tlv[4]; 3167352f7f91STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 3168352f7f91STakashi Iwai HDA_OUTPUT, vmaster_tlv); 3169352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 3170352f7f91STakashi Iwai vmaster_tlv, slave_pfxs, 3171352f7f91STakashi Iwai "Playback Volume"); 3172352f7f91STakashi Iwai if (err < 0) 3173352f7f91STakashi Iwai return err; 3174352f7f91STakashi Iwai } 3175352f7f91STakashi Iwai if (!spec->no_analog && 3176352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 3177352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 3178352f7f91STakashi Iwai NULL, slave_pfxs, 3179352f7f91STakashi Iwai "Playback Switch", 3180352f7f91STakashi Iwai true, &spec->vmaster_mute.sw_kctl); 3181352f7f91STakashi Iwai if (err < 0) 3182352f7f91STakashi Iwai return err; 3183352f7f91STakashi Iwai if (spec->vmaster_mute.hook) 3184fd25a97aSTakashi Iwai snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, 3185fd25a97aSTakashi Iwai spec->vmaster_mute_enum); 3186352f7f91STakashi Iwai } 3187352f7f91STakashi Iwai 3188352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 3189352f7f91STakashi Iwai 3190352f7f91STakashi Iwai if (spec->shared_mic_hp) { 3191352f7f91STakashi Iwai int err; 3192352f7f91STakashi Iwai int nid = spec->autocfg.inputs[1].pin; 3193352f7f91STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); 3194352f7f91STakashi Iwai if (err < 0) 3195352f7f91STakashi Iwai return err; 3196352f7f91STakashi Iwai err = snd_hda_jack_detect_enable(codec, nid, 0); 3197352f7f91STakashi Iwai if (err < 0) 3198352f7f91STakashi Iwai return err; 3199352f7f91STakashi Iwai } 3200352f7f91STakashi Iwai 3201352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 3202352f7f91STakashi Iwai if (err < 0) 3203352f7f91STakashi Iwai return err; 3204352f7f91STakashi Iwai 3205352f7f91STakashi Iwai return 0; 3206352f7f91STakashi Iwai } 3207352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls); 3208352f7f91STakashi Iwai 3209352f7f91STakashi Iwai 3210352f7f91STakashi Iwai /* 3211352f7f91STakashi Iwai * PCM definitions 3212352f7f91STakashi Iwai */ 3213352f7f91STakashi Iwai 3214352f7f91STakashi Iwai /* 3215352f7f91STakashi Iwai * Analog playback callbacks 3216352f7f91STakashi Iwai */ 3217352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 3218352f7f91STakashi Iwai struct hda_codec *codec, 3219352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3220352f7f91STakashi Iwai { 3221352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 322238cf6f1aSTakashi Iwai int err; 322338cf6f1aSTakashi Iwai 322438cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 322538cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 322638cf6f1aSTakashi Iwai &spec->multiout, substream, 3227352f7f91STakashi Iwai hinfo); 322838cf6f1aSTakashi Iwai if (!err) 322938cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 323038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 323138cf6f1aSTakashi Iwai return err; 3232352f7f91STakashi Iwai } 3233352f7f91STakashi Iwai 3234352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 323597ec558aSTakashi Iwai struct hda_codec *codec, 323697ec558aSTakashi Iwai unsigned int stream_tag, 323797ec558aSTakashi Iwai unsigned int format, 323897ec558aSTakashi Iwai struct snd_pcm_substream *substream) 323997ec558aSTakashi Iwai { 3240352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3241352f7f91STakashi Iwai return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 3242352f7f91STakashi Iwai stream_tag, format, substream); 3243352f7f91STakashi Iwai } 324497ec558aSTakashi Iwai 3245352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3246352f7f91STakashi Iwai struct hda_codec *codec, 3247352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3248352f7f91STakashi Iwai { 3249352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3250352f7f91STakashi Iwai return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 3251352f7f91STakashi Iwai } 3252352f7f91STakashi Iwai 325338cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 325438cf6f1aSTakashi Iwai struct hda_codec *codec, 325538cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 325638cf6f1aSTakashi Iwai { 325738cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 325838cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 325938cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 326038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 326138cf6f1aSTakashi Iwai return 0; 326238cf6f1aSTakashi Iwai } 326338cf6f1aSTakashi Iwai 326438cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 326538cf6f1aSTakashi Iwai struct hda_codec *codec, 326638cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 326738cf6f1aSTakashi Iwai { 326838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 326938cf6f1aSTakashi Iwai int err = 0; 327038cf6f1aSTakashi Iwai 327138cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 327238cf6f1aSTakashi Iwai if (!spec->indep_hp_enabled) 327338cf6f1aSTakashi Iwai err = -EBUSY; 327438cf6f1aSTakashi Iwai else 327538cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 327638cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 327738cf6f1aSTakashi Iwai return err; 327838cf6f1aSTakashi Iwai } 327938cf6f1aSTakashi Iwai 328038cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 328138cf6f1aSTakashi Iwai struct hda_codec *codec, 328238cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 328338cf6f1aSTakashi Iwai { 328438cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 328538cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 328638cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 328738cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 328838cf6f1aSTakashi Iwai return 0; 328938cf6f1aSTakashi Iwai } 329038cf6f1aSTakashi Iwai 3291352f7f91STakashi Iwai /* 3292352f7f91STakashi Iwai * Digital out 3293352f7f91STakashi Iwai */ 3294352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 3295352f7f91STakashi Iwai struct hda_codec *codec, 3296352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3297352f7f91STakashi Iwai { 3298352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3299352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 3300352f7f91STakashi Iwai } 3301352f7f91STakashi Iwai 3302352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 3303352f7f91STakashi Iwai struct hda_codec *codec, 3304352f7f91STakashi Iwai unsigned int stream_tag, 3305352f7f91STakashi Iwai unsigned int format, 3306352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3307352f7f91STakashi Iwai { 3308352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3309352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 3310352f7f91STakashi Iwai stream_tag, format, substream); 3311352f7f91STakashi Iwai } 3312352f7f91STakashi Iwai 3313352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3314352f7f91STakashi Iwai struct hda_codec *codec, 3315352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3316352f7f91STakashi Iwai { 3317352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3318352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 3319352f7f91STakashi Iwai } 3320352f7f91STakashi Iwai 3321352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 3322352f7f91STakashi Iwai struct hda_codec *codec, 3323352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3324352f7f91STakashi Iwai { 3325352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3326352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 3327352f7f91STakashi Iwai } 3328352f7f91STakashi Iwai 3329352f7f91STakashi Iwai /* 3330352f7f91STakashi Iwai * Analog capture 3331352f7f91STakashi Iwai */ 3332352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3333352f7f91STakashi Iwai struct hda_codec *codec, 3334352f7f91STakashi Iwai unsigned int stream_tag, 3335352f7f91STakashi Iwai unsigned int format, 3336352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3337352f7f91STakashi Iwai { 3338352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3339352f7f91STakashi Iwai 3340352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 334197ec558aSTakashi Iwai stream_tag, 0, format); 334297ec558aSTakashi Iwai return 0; 334397ec558aSTakashi Iwai } 334497ec558aSTakashi Iwai 3345352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 334697ec558aSTakashi Iwai struct hda_codec *codec, 334797ec558aSTakashi Iwai struct snd_pcm_substream *substream) 334897ec558aSTakashi Iwai { 3349352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 335097ec558aSTakashi Iwai 3351352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 3352352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 335397ec558aSTakashi Iwai return 0; 335497ec558aSTakashi Iwai } 335597ec558aSTakashi Iwai 3356352f7f91STakashi Iwai /* 3357352f7f91STakashi Iwai */ 3358352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 3359352f7f91STakashi Iwai .substreams = 1, 3360352f7f91STakashi Iwai .channels_min = 2, 3361352f7f91STakashi Iwai .channels_max = 8, 3362352f7f91STakashi Iwai /* NID is set in build_pcms */ 3363352f7f91STakashi Iwai .ops = { 3364352f7f91STakashi Iwai .open = playback_pcm_open, 336538cf6f1aSTakashi Iwai .close = playback_pcm_close, 3366352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 3367352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 3368352f7f91STakashi Iwai }, 3369352f7f91STakashi Iwai }; 3370352f7f91STakashi Iwai 3371352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 3372352f7f91STakashi Iwai .substreams = 1, 3373352f7f91STakashi Iwai .channels_min = 2, 3374352f7f91STakashi Iwai .channels_max = 2, 3375352f7f91STakashi Iwai /* NID is set in build_pcms */ 3376352f7f91STakashi Iwai }; 3377352f7f91STakashi Iwai 3378352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 3379352f7f91STakashi Iwai .substreams = 1, 3380352f7f91STakashi Iwai .channels_min = 2, 3381352f7f91STakashi Iwai .channels_max = 2, 3382352f7f91STakashi Iwai /* NID is set in build_pcms */ 338338cf6f1aSTakashi Iwai .ops = { 338438cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 338538cf6f1aSTakashi Iwai .close = alt_playback_pcm_close 338638cf6f1aSTakashi Iwai }, 3387352f7f91STakashi Iwai }; 3388352f7f91STakashi Iwai 3389352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 3390352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 3391352f7f91STakashi Iwai .channels_min = 2, 3392352f7f91STakashi Iwai .channels_max = 2, 3393352f7f91STakashi Iwai /* NID is set in build_pcms */ 3394352f7f91STakashi Iwai .ops = { 3395352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 3396352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 3397352f7f91STakashi Iwai }, 3398352f7f91STakashi Iwai }; 3399352f7f91STakashi Iwai 3400352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 3401352f7f91STakashi Iwai .substreams = 1, 3402352f7f91STakashi Iwai .channels_min = 2, 3403352f7f91STakashi Iwai .channels_max = 2, 3404352f7f91STakashi Iwai /* NID is set in build_pcms */ 3405352f7f91STakashi Iwai .ops = { 3406352f7f91STakashi Iwai .open = dig_playback_pcm_open, 3407352f7f91STakashi Iwai .close = dig_playback_pcm_close, 3408352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 3409352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 3410352f7f91STakashi Iwai }, 3411352f7f91STakashi Iwai }; 3412352f7f91STakashi Iwai 3413352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 3414352f7f91STakashi Iwai .substreams = 1, 3415352f7f91STakashi Iwai .channels_min = 2, 3416352f7f91STakashi Iwai .channels_max = 2, 3417352f7f91STakashi Iwai /* NID is set in build_pcms */ 3418352f7f91STakashi Iwai }; 3419352f7f91STakashi Iwai 3420352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 3421352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 3422352f7f91STakashi Iwai .substreams = 0, 3423352f7f91STakashi Iwai .channels_min = 0, 3424352f7f91STakashi Iwai .channels_max = 0, 3425352f7f91STakashi Iwai }; 3426352f7f91STakashi Iwai 3427352f7f91STakashi Iwai /* 3428352f7f91STakashi Iwai * dynamic changing ADC PCM streams 3429352f7f91STakashi Iwai */ 3430352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 34311da177e4SLinus Torvalds { 3432352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3433352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 34341da177e4SLinus Torvalds 3435352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 3436352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 3437352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 3438352f7f91STakashi Iwai spec->cur_adc = new_adc; 3439352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 3440352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 3441352f7f91STakashi Iwai spec->cur_adc_format); 3442352f7f91STakashi Iwai return true; 3443352f7f91STakashi Iwai } 3444352f7f91STakashi Iwai return false; 3445352f7f91STakashi Iwai } 3446352f7f91STakashi Iwai 3447352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 3448352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3449352f7f91STakashi Iwai struct hda_codec *codec, 3450352f7f91STakashi Iwai unsigned int stream_tag, 3451352f7f91STakashi Iwai unsigned int format, 3452352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3453352f7f91STakashi Iwai { 3454352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3455352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 3456352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 3457352f7f91STakashi Iwai spec->cur_adc_format = format; 3458352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 34591da177e4SLinus Torvalds return 0; 34601da177e4SLinus Torvalds } 34611da177e4SLinus Torvalds 3462352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 3463352f7f91STakashi Iwai struct hda_codec *codec, 3464352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3465352f7f91STakashi Iwai { 3466352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3467352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 3468352f7f91STakashi Iwai spec->cur_adc = 0; 3469352f7f91STakashi Iwai return 0; 3470352f7f91STakashi Iwai } 3471352f7f91STakashi Iwai 3472352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 3473352f7f91STakashi Iwai .substreams = 1, 3474352f7f91STakashi Iwai .channels_min = 2, 3475352f7f91STakashi Iwai .channels_max = 2, 3476352f7f91STakashi Iwai .nid = 0, /* fill later */ 3477352f7f91STakashi Iwai .ops = { 3478352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 3479352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 3480352f7f91STakashi Iwai }, 3481352f7f91STakashi Iwai }; 3482352f7f91STakashi Iwai 3483f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 3484f873e536STakashi Iwai const char *chip_name) 3485f873e536STakashi Iwai { 3486f873e536STakashi Iwai char *p; 3487f873e536STakashi Iwai 3488f873e536STakashi Iwai if (*str) 3489f873e536STakashi Iwai return; 3490f873e536STakashi Iwai strlcpy(str, chip_name, len); 3491f873e536STakashi Iwai 3492f873e536STakashi Iwai /* drop non-alnum chars after a space */ 3493f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 3494f873e536STakashi Iwai if (!isalnum(p[1])) { 3495f873e536STakashi Iwai *p = 0; 3496f873e536STakashi Iwai break; 3497f873e536STakashi Iwai } 3498f873e536STakashi Iwai } 3499f873e536STakashi Iwai strlcat(str, sfx, len); 3500f873e536STakashi Iwai } 3501f873e536STakashi Iwai 3502352f7f91STakashi Iwai /* build PCM streams based on the parsed results */ 3503352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 3504352f7f91STakashi Iwai { 3505352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3506352f7f91STakashi Iwai struct hda_pcm *info = spec->pcm_rec; 3507352f7f91STakashi Iwai const struct hda_pcm_stream *p; 3508352f7f91STakashi Iwai bool have_multi_adcs; 3509352f7f91STakashi Iwai 35101da177e4SLinus Torvalds codec->num_pcms = 1; 35111da177e4SLinus Torvalds codec->pcm_info = info; 35121da177e4SLinus Torvalds 3513352f7f91STakashi Iwai if (spec->no_analog) 3514352f7f91STakashi Iwai goto skip_analog; 3515352f7f91STakashi Iwai 3516f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 3517f873e536STakashi Iwai sizeof(spec->stream_name_analog), 3518f873e536STakashi Iwai " Analog", codec->chip_name); 3519352f7f91STakashi Iwai info->name = spec->stream_name_analog; 3520352f7f91STakashi Iwai 3521352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 3522352f7f91STakashi Iwai p = spec->stream_analog_playback; 3523352f7f91STakashi Iwai if (!p) 3524352f7f91STakashi Iwai p = &pcm_analog_playback; 3525352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3526352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 3527352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 3528352f7f91STakashi Iwai spec->multiout.max_channels; 3529352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 3530352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 3531352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 3532352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 3533352f7f91STakashi Iwai } 3534352f7f91STakashi Iwai if (spec->num_adc_nids) { 3535352f7f91STakashi Iwai p = spec->stream_analog_capture; 3536352f7f91STakashi Iwai if (!p) { 3537352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3538352f7f91STakashi Iwai p = &dyn_adc_pcm_analog_capture; 3539352f7f91STakashi Iwai else 3540352f7f91STakashi Iwai p = &pcm_analog_capture; 3541352f7f91STakashi Iwai } 3542352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3543352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 3544352f7f91STakashi Iwai } 3545352f7f91STakashi Iwai 3546352f7f91STakashi Iwai skip_analog: 3547352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 3548352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 3549f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 3550352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 3551f873e536STakashi Iwai " Digital", codec->chip_name); 3552352f7f91STakashi Iwai codec->num_pcms = 2; 3553352f7f91STakashi Iwai codec->slave_dig_outs = spec->multiout.slave_dig_outs; 3554352f7f91STakashi Iwai info = spec->pcm_rec + 1; 3555352f7f91STakashi Iwai info->name = spec->stream_name_digital; 3556352f7f91STakashi Iwai if (spec->dig_out_type) 3557352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 3558352f7f91STakashi Iwai else 3559352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 3560352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3561352f7f91STakashi Iwai p = spec->stream_digital_playback; 3562352f7f91STakashi Iwai if (!p) 3563352f7f91STakashi Iwai p = &pcm_digital_playback; 3564352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3565352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 3566352f7f91STakashi Iwai } 3567352f7f91STakashi Iwai if (spec->dig_in_nid) { 3568352f7f91STakashi Iwai p = spec->stream_digital_capture; 3569352f7f91STakashi Iwai if (!p) 3570352f7f91STakashi Iwai p = &pcm_digital_capture; 3571352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3572352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 3573352f7f91STakashi Iwai } 3574352f7f91STakashi Iwai } 3575352f7f91STakashi Iwai 3576352f7f91STakashi Iwai if (spec->no_analog) 3577352f7f91STakashi Iwai return 0; 3578352f7f91STakashi Iwai 3579352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 3580352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 3581352f7f91STakashi Iwai */ 3582352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 3583352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 3584352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 3585352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 3586352f7f91STakashi Iwai codec->num_pcms = 3; 3587352f7f91STakashi Iwai info = spec->pcm_rec + 2; 3588352f7f91STakashi Iwai info->name = spec->stream_name_analog; 3589352f7f91STakashi Iwai if (spec->alt_dac_nid) { 3590352f7f91STakashi Iwai p = spec->stream_analog_alt_playback; 3591352f7f91STakashi Iwai if (!p) 3592352f7f91STakashi Iwai p = &pcm_analog_alt_playback; 3593352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3594352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 3595352f7f91STakashi Iwai spec->alt_dac_nid; 3596352f7f91STakashi Iwai } else { 3597352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 3598352f7f91STakashi Iwai pcm_null_stream; 3599352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; 3600352f7f91STakashi Iwai } 3601352f7f91STakashi Iwai if (have_multi_adcs) { 3602352f7f91STakashi Iwai p = spec->stream_analog_alt_capture; 3603352f7f91STakashi Iwai if (!p) 3604352f7f91STakashi Iwai p = &pcm_analog_alt_capture; 3605352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3606352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 3607352f7f91STakashi Iwai spec->adc_nids[1]; 3608352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 3609352f7f91STakashi Iwai spec->num_adc_nids - 1; 3610352f7f91STakashi Iwai } else { 3611352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = 3612352f7f91STakashi Iwai pcm_null_stream; 3613352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; 3614352f7f91STakashi Iwai } 36151da177e4SLinus Torvalds } 36161da177e4SLinus Torvalds 36171da177e4SLinus Torvalds return 0; 36181da177e4SLinus Torvalds } 3619352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); 3620352f7f91STakashi Iwai 3621352f7f91STakashi Iwai 3622352f7f91STakashi Iwai /* 3623352f7f91STakashi Iwai * Standard auto-parser initializations 3624352f7f91STakashi Iwai */ 3625352f7f91STakashi Iwai 3626352f7f91STakashi Iwai /* configure the path from the given dac to the pin as the proper output */ 3627352f7f91STakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, hda_nid_t pin, 3628196c1766STakashi Iwai int pin_type, int path_idx) 3629352f7f91STakashi Iwai { 3630352f7f91STakashi Iwai struct nid_path *path; 3631352f7f91STakashi Iwai 3632352f7f91STakashi Iwai snd_hda_set_pin_ctl_cache(codec, pin, pin_type); 3633196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 3634352f7f91STakashi Iwai if (!path) 3635352f7f91STakashi Iwai return; 3636e1284af7STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 3637e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 3638352f7f91STakashi Iwai } 3639352f7f91STakashi Iwai 3640352f7f91STakashi Iwai /* initialize primary output paths */ 3641352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 3642352f7f91STakashi Iwai { 3643352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3644196c1766STakashi Iwai hda_nid_t nid; 3645352f7f91STakashi Iwai int pin_type; 3646352f7f91STakashi Iwai int i; 3647352f7f91STakashi Iwai 3648352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 3649352f7f91STakashi Iwai pin_type = PIN_HP; 3650352f7f91STakashi Iwai else 3651352f7f91STakashi Iwai pin_type = PIN_OUT; 3652352f7f91STakashi Iwai 365364049c81STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) { 365464049c81STakashi Iwai nid = spec->autocfg.line_out_pins[i]; 3655196c1766STakashi Iwai if (nid) 3656196c1766STakashi Iwai set_output_and_unmute(codec, nid, pin_type, 3657196c1766STakashi Iwai spec->out_paths[i]); 3658352f7f91STakashi Iwai } 3659352f7f91STakashi Iwai } 3660352f7f91STakashi Iwai 3661db23fd19STakashi Iwai 3662db23fd19STakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, 3663196c1766STakashi Iwai hda_nid_t *pins, int *paths, int type) 3664352f7f91STakashi Iwai { 3665352f7f91STakashi Iwai int i; 3666196c1766STakashi Iwai hda_nid_t pin; 3667352f7f91STakashi Iwai 3668db23fd19STakashi Iwai for (i = 0; i < num_outs; i++) { 3669db23fd19STakashi Iwai pin = pins[i]; 3670352f7f91STakashi Iwai if (!pin) 3671352f7f91STakashi Iwai break; 3672196c1766STakashi Iwai set_output_and_unmute(codec, pin, type, paths[i]); 3673352f7f91STakashi Iwai } 3674352f7f91STakashi Iwai } 3675db23fd19STakashi Iwai 3676db23fd19STakashi Iwai /* initialize hp and speaker paths */ 3677db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 3678db23fd19STakashi Iwai { 3679db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3680db23fd19STakashi Iwai 3681db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 3682db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, 3683db23fd19STakashi Iwai spec->autocfg.hp_pins, 3684196c1766STakashi Iwai spec->hp_paths, PIN_HP); 3685db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 3686db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 3687db23fd19STakashi Iwai spec->autocfg.speaker_pins, 3688196c1766STakashi Iwai spec->speaker_paths, PIN_OUT); 3689352f7f91STakashi Iwai } 3690352f7f91STakashi Iwai 3691352f7f91STakashi Iwai /* initialize multi-io paths */ 3692352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 3693352f7f91STakashi Iwai { 3694352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3695352f7f91STakashi Iwai int i; 3696352f7f91STakashi Iwai 3697352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 3698352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 3699352f7f91STakashi Iwai struct nid_path *path; 3700196c1766STakashi Iwai path = get_multiio_path(codec, i); 3701352f7f91STakashi Iwai if (!path) 3702352f7f91STakashi Iwai continue; 3703352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 3704352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 3705352f7f91STakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 3706352f7f91STakashi Iwai AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 3707352f7f91STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 3708352f7f91STakashi Iwai } 3709352f7f91STakashi Iwai } 3710352f7f91STakashi Iwai 3711352f7f91STakashi Iwai /* set up the input pin config, depending on the given auto-pin type */ 3712352f7f91STakashi Iwai static void set_input_pin(struct hda_codec *codec, hda_nid_t nid, 3713352f7f91STakashi Iwai int auto_pin_type) 3714352f7f91STakashi Iwai { 3715352f7f91STakashi Iwai unsigned int val = PIN_IN; 3716352f7f91STakashi Iwai if (auto_pin_type == AUTO_PIN_MIC) 3717352f7f91STakashi Iwai val |= snd_hda_get_default_vref(codec, nid); 37187594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 3719352f7f91STakashi Iwai } 3720352f7f91STakashi Iwai 3721352f7f91STakashi Iwai /* set up input pins and loopback paths */ 3722352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 3723352f7f91STakashi Iwai { 3724352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3725352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3726352f7f91STakashi Iwai int i; 3727352f7f91STakashi Iwai 3728352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3729352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 3730352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 3731352f7f91STakashi Iwai set_input_pin(codec, nid, cfg->inputs[i].type); 3732352f7f91STakashi Iwai 3733352f7f91STakashi Iwai /* init loopback inputs */ 3734352f7f91STakashi Iwai if (spec->mixer_nid) { 3735352f7f91STakashi Iwai struct nid_path *path; 3736196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]); 3737352f7f91STakashi Iwai if (path) 3738352f7f91STakashi Iwai snd_hda_activate_path(codec, path, 3739352f7f91STakashi Iwai path->active, false); 3740352f7f91STakashi Iwai } 3741352f7f91STakashi Iwai } 3742352f7f91STakashi Iwai } 3743352f7f91STakashi Iwai 3744352f7f91STakashi Iwai /* initialize ADC paths */ 3745352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 3746352f7f91STakashi Iwai { 3747352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3748352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3749352f7f91STakashi Iwai struct nid_path *path; 3750352f7f91STakashi Iwai int i, c, nums; 3751352f7f91STakashi Iwai 3752352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3753352f7f91STakashi Iwai nums = 1; 3754352f7f91STakashi Iwai else 3755352f7f91STakashi Iwai nums = spec->num_adc_nids; 3756352f7f91STakashi Iwai 3757352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 3758352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3759352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[i], 3760352f7f91STakashi Iwai get_adc_nid(codec, c, i)); 3761352f7f91STakashi Iwai if (path) { 3762352f7f91STakashi Iwai bool active = path->active; 3763352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 3764352f7f91STakashi Iwai active = true; 3765352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 3766352f7f91STakashi Iwai } 3767352f7f91STakashi Iwai } 3768352f7f91STakashi Iwai } 3769352f7f91STakashi Iwai 3770352f7f91STakashi Iwai if (spec->shared_mic_hp) 3771352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[0]); 3772352f7f91STakashi Iwai 3773352f7f91STakashi Iwai if (spec->cap_sync_hook) 3774352f7f91STakashi Iwai spec->cap_sync_hook(codec); 3775352f7f91STakashi Iwai } 3776352f7f91STakashi Iwai 3777352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 3778352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 3779352f7f91STakashi Iwai { 3780352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3781352f7f91STakashi Iwai int i; 3782352f7f91STakashi Iwai hda_nid_t pin; 3783352f7f91STakashi Iwai 3784352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 3785352f7f91STakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 3786352f7f91STakashi Iwai if (!pin) 3787352f7f91STakashi Iwai continue; 3788196c1766STakashi Iwai set_output_and_unmute(codec, pin, PIN_OUT, 3789196c1766STakashi Iwai spec->digout_paths[i]); 3790352f7f91STakashi Iwai } 3791352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 37922430d7b7STakashi Iwai if (pin) { 37932430d7b7STakashi Iwai struct nid_path *path; 37947594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, pin, PIN_IN); 37952430d7b7STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->digin_path); 37962430d7b7STakashi Iwai if (path) 37972430d7b7STakashi Iwai snd_hda_activate_path(codec, path, path->active, false); 37982430d7b7STakashi Iwai } 3799352f7f91STakashi Iwai } 3800352f7f91STakashi Iwai 3801973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 3802973e4972STakashi Iwai * invalid unsol tags by some reason 3803973e4972STakashi Iwai */ 3804973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 3805973e4972STakashi Iwai { 3806973e4972STakashi Iwai int i; 3807973e4972STakashi Iwai 3808973e4972STakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 3809973e4972STakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 3810973e4972STakashi Iwai hda_nid_t nid = pin->nid; 3811973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 3812973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 3813973e4972STakashi Iwai snd_hda_codec_update_cache(codec, nid, 0, 3814973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 3815973e4972STakashi Iwai } 3816973e4972STakashi Iwai } 3817973e4972STakashi Iwai 3818352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 3819352f7f91STakashi Iwai { 3820352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3821352f7f91STakashi Iwai 3822352f7f91STakashi Iwai if (spec->init_hook) 3823352f7f91STakashi Iwai spec->init_hook(codec); 3824352f7f91STakashi Iwai 3825352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 3826352f7f91STakashi Iwai 38273bbcd274STakashi Iwai codec->cached_write = 1; 38283bbcd274STakashi Iwai 3829352f7f91STakashi Iwai init_multi_out(codec); 3830352f7f91STakashi Iwai init_extra_out(codec); 3831352f7f91STakashi Iwai init_multi_io(codec); 3832352f7f91STakashi Iwai init_analog_input(codec); 3833352f7f91STakashi Iwai init_input_src(codec); 3834352f7f91STakashi Iwai init_digital(codec); 3835352f7f91STakashi Iwai 3836973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 3837973e4972STakashi Iwai 3838352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 38395d550e15STakashi Iwai snd_hda_gen_hp_automute(codec, NULL); 38405d550e15STakashi Iwai snd_hda_gen_line_automute(codec, NULL); 38415d550e15STakashi Iwai snd_hda_gen_mic_autoswitch(codec, NULL); 3842352f7f91STakashi Iwai 38433bbcd274STakashi Iwai snd_hda_codec_flush_amp_cache(codec); 38443bbcd274STakashi Iwai snd_hda_codec_flush_cmd_cache(codec); 38453bbcd274STakashi Iwai 3846352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 3847352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 3848352f7f91STakashi Iwai 3849352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 3850352f7f91STakashi Iwai return 0; 3851352f7f91STakashi Iwai } 3852352f7f91STakashi Iwai EXPORT_SYMBOL(snd_hda_gen_init); 3853352f7f91STakashi Iwai 3854352f7f91STakashi Iwai 3855352f7f91STakashi Iwai /* 3856352f7f91STakashi Iwai * the generic codec support 3857352f7f91STakashi Iwai */ 38581da177e4SLinus Torvalds 385983012a7cSTakashi Iwai #ifdef CONFIG_PM 3860cb53c626STakashi Iwai static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) 3861cb53c626STakashi Iwai { 3862352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3863cb53c626STakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 3864cb53c626STakashi Iwai } 3865cb53c626STakashi Iwai #endif 3866cb53c626STakashi Iwai 3867352f7f91STakashi Iwai static void generic_free(struct hda_codec *codec) 3868352f7f91STakashi Iwai { 3869352f7f91STakashi Iwai snd_hda_gen_spec_free(codec->spec); 3870352f7f91STakashi Iwai kfree(codec->spec); 3871352f7f91STakashi Iwai codec->spec = NULL; 3872352f7f91STakashi Iwai } 38731da177e4SLinus Torvalds 3874352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 3875352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 3876352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 3877352f7f91STakashi Iwai .init = snd_hda_gen_init, 3878352f7f91STakashi Iwai .free = generic_free, 3879352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 388083012a7cSTakashi Iwai #ifdef CONFIG_PM 3881cb53c626STakashi Iwai .check_power_status = generic_check_power_status, 3882cb53c626STakashi Iwai #endif 38831da177e4SLinus Torvalds }; 38841da177e4SLinus Torvalds 38851da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec) 38861da177e4SLinus Torvalds { 3887352f7f91STakashi Iwai struct hda_gen_spec *spec; 38881da177e4SLinus Torvalds int err; 38891da177e4SLinus Torvalds 3890e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 3891352f7f91STakashi Iwai if (!spec) 38921da177e4SLinus Torvalds return -ENOMEM; 3893352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 38941da177e4SLinus Torvalds codec->spec = spec; 38951da177e4SLinus Torvalds 38969eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 38979eb413e5STakashi Iwai if (err < 0) 38989eb413e5STakashi Iwai return err; 38999eb413e5STakashi Iwai 39009eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 3901352f7f91STakashi Iwai if (err < 0) 39021da177e4SLinus Torvalds goto error; 39031da177e4SLinus Torvalds 39041da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 39051da177e4SLinus Torvalds return 0; 39061da177e4SLinus Torvalds 39071da177e4SLinus Torvalds error: 3908352f7f91STakashi Iwai generic_free(codec); 39091da177e4SLinus Torvalds return err; 39101da177e4SLinus Torvalds } 39111289e9e8STakashi Iwai EXPORT_SYMBOL(snd_hda_parse_generic_codec); 3912