11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Universal Interface for Intel High Definition Audio Codec 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This driver is free software; you can redistribute it and/or modify 81da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 91da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 101da177e4SLinus Torvalds * (at your option) any later version. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * This driver is distributed in the hope that it will be useful, 131da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 141da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 151da177e4SLinus Torvalds * GNU General Public License for more details. 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 181da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 191da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <linux/init.h> 231da177e4SLinus Torvalds #include <linux/delay.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 251da177e4SLinus Torvalds #include <linux/pci.h> 2662932df8SIngo Molnar #include <linux/mutex.h> 271da177e4SLinus Torvalds #include <sound/core.h> 281da177e4SLinus Torvalds #include "hda_codec.h" 291da177e4SLinus Torvalds #include <sound/asoundef.h> 30302e9c5aSJaroslav Kysela #include <sound/tlv.h> 311da177e4SLinus Torvalds #include <sound/initval.h> 321da177e4SLinus Torvalds #include "hda_local.h" 332807314dSTakashi Iwai #include <sound/hda_hwdep.h> 343c9a3203SHarvey Harrison #include "hda_patch.h" /* codec presets */ 351da177e4SLinus Torvalds 36cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 37cb53c626STakashi Iwai /* define this option here to hide as static */ 387a5a27cfSTakashi Iwai static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; 39cb53c626STakashi Iwai module_param(power_save, int, 0644); 40cb53c626STakashi Iwai MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " 41cb53c626STakashi Iwai "(in second, 0 = disable)."); 42cb53c626STakashi Iwai #endif 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* 451da177e4SLinus Torvalds * vendor / preset table 461da177e4SLinus Torvalds */ 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds struct hda_vendor_id { 491da177e4SLinus Torvalds unsigned int id; 501da177e4SLinus Torvalds const char *name; 511da177e4SLinus Torvalds }; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds /* codec vendor labels */ 541da177e4SLinus Torvalds static struct hda_vendor_id hda_vendor_ids[] = { 55c8cd1281STakashi Iwai { 0x1002, "ATI" }, 56a9226251STakashi Iwai { 0x1057, "Motorola" }, 57c8cd1281STakashi Iwai { 0x1095, "Silicon Image" }, 58c8cd1281STakashi Iwai { 0x10ec, "Realtek" }, 59c577b8a1SJoseph Chan { 0x1106, "VIA" }, 607f16859aSMatthew Ranostay { 0x111d, "IDT" }, 61c8cd1281STakashi Iwai { 0x11c1, "LSI" }, 6254b903ecSTakashi Iwai { 0x11d4, "Analog Devices" }, 631da177e4SLinus Torvalds { 0x13f6, "C-Media" }, 64a9226251STakashi Iwai { 0x14f1, "Conexant" }, 65c8cd1281STakashi Iwai { 0x17e8, "Chrontel" }, 66c8cd1281STakashi Iwai { 0x1854, "LG" }, 671da177e4SLinus Torvalds { 0x434d, "C-Media" }, 682f2f4251SMatt { 0x8384, "SigmaTel" }, 691da177e4SLinus Torvalds {} /* terminator */ 701da177e4SLinus Torvalds }; 711da177e4SLinus Torvalds 723c9a3203SHarvey Harrison static const struct hda_codec_preset *hda_preset_tables[] = { 733c9a3203SHarvey Harrison #ifdef CONFIG_SND_HDA_CODEC_REALTEK 743c9a3203SHarvey Harrison snd_hda_preset_realtek, 753c9a3203SHarvey Harrison #endif 763c9a3203SHarvey Harrison #ifdef CONFIG_SND_HDA_CODEC_CMEDIA 773c9a3203SHarvey Harrison snd_hda_preset_cmedia, 783c9a3203SHarvey Harrison #endif 793c9a3203SHarvey Harrison #ifdef CONFIG_SND_HDA_CODEC_ANALOG 803c9a3203SHarvey Harrison snd_hda_preset_analog, 813c9a3203SHarvey Harrison #endif 823c9a3203SHarvey Harrison #ifdef CONFIG_SND_HDA_CODEC_SIGMATEL 833c9a3203SHarvey Harrison snd_hda_preset_sigmatel, 843c9a3203SHarvey Harrison #endif 853c9a3203SHarvey Harrison #ifdef CONFIG_SND_HDA_CODEC_SI3054 863c9a3203SHarvey Harrison snd_hda_preset_si3054, 873c9a3203SHarvey Harrison #endif 883c9a3203SHarvey Harrison #ifdef CONFIG_SND_HDA_CODEC_ATIHDMI 893c9a3203SHarvey Harrison snd_hda_preset_atihdmi, 903c9a3203SHarvey Harrison #endif 913c9a3203SHarvey Harrison #ifdef CONFIG_SND_HDA_CODEC_CONEXANT 923c9a3203SHarvey Harrison snd_hda_preset_conexant, 933c9a3203SHarvey Harrison #endif 943c9a3203SHarvey Harrison #ifdef CONFIG_SND_HDA_CODEC_VIA 953c9a3203SHarvey Harrison snd_hda_preset_via, 963c9a3203SHarvey Harrison #endif 973c9a3203SHarvey Harrison NULL 983c9a3203SHarvey Harrison }; 991da177e4SLinus Torvalds 100cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 101cb53c626STakashi Iwai static void hda_power_work(struct work_struct *work); 102cb53c626STakashi Iwai static void hda_keep_power_on(struct hda_codec *codec); 103cb53c626STakashi Iwai #else 104cb53c626STakashi Iwai static inline void hda_keep_power_on(struct hda_codec *codec) {} 105cb53c626STakashi Iwai #endif 106cb53c626STakashi Iwai 1071da177e4SLinus Torvalds /** 1081da177e4SLinus Torvalds * snd_hda_codec_read - send a command and get the response 1091da177e4SLinus Torvalds * @codec: the HDA codec 1101da177e4SLinus Torvalds * @nid: NID to send the command 1111da177e4SLinus Torvalds * @direct: direct flag 1121da177e4SLinus Torvalds * @verb: the verb to send 1131da177e4SLinus Torvalds * @parm: the parameter for the verb 1141da177e4SLinus Torvalds * 1151da177e4SLinus Torvalds * Send a single command and read the corresponding response. 1161da177e4SLinus Torvalds * 1171da177e4SLinus Torvalds * Returns the obtained response value, or -1 for an error. 1181da177e4SLinus Torvalds */ 1190ba21762STakashi Iwai unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, 1200ba21762STakashi Iwai int direct, 1211da177e4SLinus Torvalds unsigned int verb, unsigned int parm) 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds unsigned int res; 124cb53c626STakashi Iwai snd_hda_power_up(codec); 12562932df8SIngo Molnar mutex_lock(&codec->bus->cmd_mutex); 1261da177e4SLinus Torvalds if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) 1271da177e4SLinus Torvalds res = codec->bus->ops.get_response(codec); 1281da177e4SLinus Torvalds else 1291da177e4SLinus Torvalds res = (unsigned int)-1; 13062932df8SIngo Molnar mutex_unlock(&codec->bus->cmd_mutex); 131cb53c626STakashi Iwai snd_hda_power_down(codec); 1321da177e4SLinus Torvalds return res; 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /** 1361da177e4SLinus Torvalds * snd_hda_codec_write - send a single command without waiting for response 1371da177e4SLinus Torvalds * @codec: the HDA codec 1381da177e4SLinus Torvalds * @nid: NID to send the command 1391da177e4SLinus Torvalds * @direct: direct flag 1401da177e4SLinus Torvalds * @verb: the verb to send 1411da177e4SLinus Torvalds * @parm: the parameter for the verb 1421da177e4SLinus Torvalds * 1431da177e4SLinus Torvalds * Send a single command without waiting for response. 1441da177e4SLinus Torvalds * 1451da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 1461da177e4SLinus Torvalds */ 1471da177e4SLinus Torvalds int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, 1481da177e4SLinus Torvalds unsigned int verb, unsigned int parm) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds int err; 151cb53c626STakashi Iwai snd_hda_power_up(codec); 15262932df8SIngo Molnar mutex_lock(&codec->bus->cmd_mutex); 1531da177e4SLinus Torvalds err = codec->bus->ops.command(codec, nid, direct, verb, parm); 15462932df8SIngo Molnar mutex_unlock(&codec->bus->cmd_mutex); 155cb53c626STakashi Iwai snd_hda_power_down(codec); 1561da177e4SLinus Torvalds return err; 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds /** 1601da177e4SLinus Torvalds * snd_hda_sequence_write - sequence writes 1611da177e4SLinus Torvalds * @codec: the HDA codec 1621da177e4SLinus Torvalds * @seq: VERB array to send 1631da177e4SLinus Torvalds * 1641da177e4SLinus Torvalds * Send the commands sequentially from the given array. 1651da177e4SLinus Torvalds * The array must be terminated with NID=0. 1661da177e4SLinus Torvalds */ 1671da177e4SLinus Torvalds void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) 1681da177e4SLinus Torvalds { 1691da177e4SLinus Torvalds for (; seq->nid; seq++) 1701da177e4SLinus Torvalds snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /** 1741da177e4SLinus Torvalds * snd_hda_get_sub_nodes - get the range of sub nodes 1751da177e4SLinus Torvalds * @codec: the HDA codec 1761da177e4SLinus Torvalds * @nid: NID to parse 1771da177e4SLinus Torvalds * @start_id: the pointer to store the start NID 1781da177e4SLinus Torvalds * 1791da177e4SLinus Torvalds * Parse the NID and store the start NID of its sub-nodes. 1801da177e4SLinus Torvalds * Returns the number of sub-nodes. 1811da177e4SLinus Torvalds */ 1820ba21762STakashi Iwai int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, 1830ba21762STakashi Iwai hda_nid_t *start_id) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds unsigned int parm; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); 188e8a7f136SDanny Tholen if (parm == -1) 189e8a7f136SDanny Tholen return 0; 1901da177e4SLinus Torvalds *start_id = (parm >> 16) & 0x7fff; 1911da177e4SLinus Torvalds return (int)(parm & 0x7fff); 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /** 1951da177e4SLinus Torvalds * snd_hda_get_connections - get connection list 1961da177e4SLinus Torvalds * @codec: the HDA codec 1971da177e4SLinus Torvalds * @nid: NID to parse 1981da177e4SLinus Torvalds * @conn_list: connection list array 1991da177e4SLinus Torvalds * @max_conns: max. number of connections to store 2001da177e4SLinus Torvalds * 2011da177e4SLinus Torvalds * Parses the connection list of the given widget and stores the list 2021da177e4SLinus Torvalds * of NIDs. 2031da177e4SLinus Torvalds * 2041da177e4SLinus Torvalds * Returns the number of connections, or a negative error code. 2051da177e4SLinus Torvalds */ 2061da177e4SLinus Torvalds int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, 2071da177e4SLinus Torvalds hda_nid_t *conn_list, int max_conns) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds unsigned int parm; 21054d17403STakashi Iwai int i, conn_len, conns; 2111da177e4SLinus Torvalds unsigned int shift, num_elems, mask; 21254d17403STakashi Iwai hda_nid_t prev_nid; 2131da177e4SLinus Torvalds 214*da3cec35STakashi Iwai if (snd_BUG_ON(!conn_list || max_conns <= 0)) 215*da3cec35STakashi Iwai return -EINVAL; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); 2181da177e4SLinus Torvalds if (parm & AC_CLIST_LONG) { 2191da177e4SLinus Torvalds /* long form */ 2201da177e4SLinus Torvalds shift = 16; 2211da177e4SLinus Torvalds num_elems = 2; 2221da177e4SLinus Torvalds } else { 2231da177e4SLinus Torvalds /* short form */ 2241da177e4SLinus Torvalds shift = 8; 2251da177e4SLinus Torvalds num_elems = 4; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds conn_len = parm & AC_CLIST_LENGTH; 2281da177e4SLinus Torvalds mask = (1 << (shift-1)) - 1; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds if (!conn_len) 2311da177e4SLinus Torvalds return 0; /* no connection */ 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds if (conn_len == 1) { 2341da177e4SLinus Torvalds /* single connection */ 2350ba21762STakashi Iwai parm = snd_hda_codec_read(codec, nid, 0, 2360ba21762STakashi Iwai AC_VERB_GET_CONNECT_LIST, 0); 2371da177e4SLinus Torvalds conn_list[0] = parm & mask; 2381da177e4SLinus Torvalds return 1; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds /* multi connection */ 2421da177e4SLinus Torvalds conns = 0; 24354d17403STakashi Iwai prev_nid = 0; 24454d17403STakashi Iwai for (i = 0; i < conn_len; i++) { 2451da177e4SLinus Torvalds int range_val; 24654d17403STakashi Iwai hda_nid_t val, n; 24754d17403STakashi Iwai 24854d17403STakashi Iwai if (i % num_elems == 0) 24954d17403STakashi Iwai parm = snd_hda_codec_read(codec, nid, 0, 25054d17403STakashi Iwai AC_VERB_GET_CONNECT_LIST, i); 25154d17403STakashi Iwai range_val = !!(parm & (1 << (shift-1))); /* ranges */ 25254d17403STakashi Iwai val = parm & mask; 2531da177e4SLinus Torvalds parm >>= shift; 2541da177e4SLinus Torvalds if (range_val) { 25554d17403STakashi Iwai /* ranges between the previous and this one */ 25654d17403STakashi Iwai if (!prev_nid || prev_nid >= val) { 2570ba21762STakashi Iwai snd_printk(KERN_WARNING "hda_codec: " 2580ba21762STakashi Iwai "invalid dep_range_val %x:%x\n", 2590ba21762STakashi Iwai prev_nid, val); 2601da177e4SLinus Torvalds continue; 2611da177e4SLinus Torvalds } 26254d17403STakashi Iwai for (n = prev_nid + 1; n <= val; n++) { 26354d17403STakashi Iwai if (conns >= max_conns) { 2640ba21762STakashi Iwai snd_printk(KERN_ERR 2650ba21762STakashi Iwai "Too many connections\n"); 2661da177e4SLinus Torvalds return -EINVAL; 26754d17403STakashi Iwai } 2681da177e4SLinus Torvalds conn_list[conns++] = n; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds } else { 27154d17403STakashi Iwai if (conns >= max_conns) { 27254d17403STakashi Iwai snd_printk(KERN_ERR "Too many connections\n"); 2731da177e4SLinus Torvalds return -EINVAL; 2741da177e4SLinus Torvalds } 27554d17403STakashi Iwai conn_list[conns++] = val; 2761da177e4SLinus Torvalds } 27754d17403STakashi Iwai prev_nid = val; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds return conns; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds /** 2841da177e4SLinus Torvalds * snd_hda_queue_unsol_event - add an unsolicited event to queue 2851da177e4SLinus Torvalds * @bus: the BUS 2861da177e4SLinus Torvalds * @res: unsolicited event (lower 32bit of RIRB entry) 2871da177e4SLinus Torvalds * @res_ex: codec addr and flags (upper 32bit or RIRB entry) 2881da177e4SLinus Torvalds * 2891da177e4SLinus Torvalds * Adds the given event to the queue. The events are processed in 2901da177e4SLinus Torvalds * the workqueue asynchronously. Call this function in the interrupt 2911da177e4SLinus Torvalds * hanlder when RIRB receives an unsolicited event. 2921da177e4SLinus Torvalds * 2931da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 2941da177e4SLinus Torvalds */ 2951da177e4SLinus Torvalds int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds struct hda_bus_unsolicited *unsol; 2981da177e4SLinus Torvalds unsigned int wp; 2991da177e4SLinus Torvalds 3000ba21762STakashi Iwai unsol = bus->unsol; 3010ba21762STakashi Iwai if (!unsol) 3021da177e4SLinus Torvalds return 0; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE; 3051da177e4SLinus Torvalds unsol->wp = wp; 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds wp <<= 1; 3081da177e4SLinus Torvalds unsol->queue[wp] = res; 3091da177e4SLinus Torvalds unsol->queue[wp + 1] = res_ex; 3101da177e4SLinus Torvalds 311e250af29STakashi Iwai schedule_work(&unsol->work); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds return 0; 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds /* 3171da177e4SLinus Torvalds * process queueud unsolicited events 3181da177e4SLinus Torvalds */ 319c4028958SDavid Howells static void process_unsol_events(struct work_struct *work) 3201da177e4SLinus Torvalds { 321c4028958SDavid Howells struct hda_bus_unsolicited *unsol = 322c4028958SDavid Howells container_of(work, struct hda_bus_unsolicited, work); 323c4028958SDavid Howells struct hda_bus *bus = unsol->bus; 3241da177e4SLinus Torvalds struct hda_codec *codec; 3251da177e4SLinus Torvalds unsigned int rp, caddr, res; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds while (unsol->rp != unsol->wp) { 3281da177e4SLinus Torvalds rp = (unsol->rp + 1) % HDA_UNSOL_QUEUE_SIZE; 3291da177e4SLinus Torvalds unsol->rp = rp; 3301da177e4SLinus Torvalds rp <<= 1; 3311da177e4SLinus Torvalds res = unsol->queue[rp]; 3321da177e4SLinus Torvalds caddr = unsol->queue[rp + 1]; 3331da177e4SLinus Torvalds if (!(caddr & (1 << 4))) /* no unsolicited event? */ 3341da177e4SLinus Torvalds continue; 3351da177e4SLinus Torvalds codec = bus->caddr_tbl[caddr & 0x0f]; 3361da177e4SLinus Torvalds if (codec && codec->patch_ops.unsol_event) 3371da177e4SLinus Torvalds codec->patch_ops.unsol_event(codec, res); 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds /* 3421da177e4SLinus Torvalds * initialize unsolicited queue 3431da177e4SLinus Torvalds */ 344756e2b01STakashi Iwai static int __devinit init_unsol_queue(struct hda_bus *bus) 3451da177e4SLinus Torvalds { 3461da177e4SLinus Torvalds struct hda_bus_unsolicited *unsol; 3471da177e4SLinus Torvalds 3489f146bb6STakashi Iwai if (bus->unsol) /* already initialized */ 3499f146bb6STakashi Iwai return 0; 3509f146bb6STakashi Iwai 351e560d8d8STakashi Iwai unsol = kzalloc(sizeof(*unsol), GFP_KERNEL); 3521da177e4SLinus Torvalds if (!unsol) { 3530ba21762STakashi Iwai snd_printk(KERN_ERR "hda_codec: " 3540ba21762STakashi Iwai "can't allocate unsolicited queue\n"); 3551da177e4SLinus Torvalds return -ENOMEM; 3561da177e4SLinus Torvalds } 357c4028958SDavid Howells INIT_WORK(&unsol->work, process_unsol_events); 358c4028958SDavid Howells unsol->bus = bus; 3591da177e4SLinus Torvalds bus->unsol = unsol; 3601da177e4SLinus Torvalds return 0; 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds /* 3641da177e4SLinus Torvalds * destructor 3651da177e4SLinus Torvalds */ 3661da177e4SLinus Torvalds static void snd_hda_codec_free(struct hda_codec *codec); 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds static int snd_hda_bus_free(struct hda_bus *bus) 3691da177e4SLinus Torvalds { 3700ba21762STakashi Iwai struct hda_codec *codec, *n; 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds if (!bus) 3731da177e4SLinus Torvalds return 0; 3741da177e4SLinus Torvalds if (bus->unsol) { 375e250af29STakashi Iwai flush_scheduled_work(); 3761da177e4SLinus Torvalds kfree(bus->unsol); 3771da177e4SLinus Torvalds } 3780ba21762STakashi Iwai list_for_each_entry_safe(codec, n, &bus->codec_list, list) { 3791da177e4SLinus Torvalds snd_hda_codec_free(codec); 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds if (bus->ops.private_free) 3821da177e4SLinus Torvalds bus->ops.private_free(bus); 3831da177e4SLinus Torvalds kfree(bus); 3841da177e4SLinus Torvalds return 0; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds 387c8b6bf9bSTakashi Iwai static int snd_hda_bus_dev_free(struct snd_device *device) 3881da177e4SLinus Torvalds { 3891da177e4SLinus Torvalds struct hda_bus *bus = device->device_data; 3901da177e4SLinus Torvalds return snd_hda_bus_free(bus); 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds /** 3941da177e4SLinus Torvalds * snd_hda_bus_new - create a HDA bus 3951da177e4SLinus Torvalds * @card: the card entry 3961da177e4SLinus Torvalds * @temp: the template for hda_bus information 3971da177e4SLinus Torvalds * @busp: the pointer to store the created bus instance 3981da177e4SLinus Torvalds * 3991da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 4001da177e4SLinus Torvalds */ 401756e2b01STakashi Iwai int __devinit snd_hda_bus_new(struct snd_card *card, 402756e2b01STakashi Iwai const struct hda_bus_template *temp, 4031da177e4SLinus Torvalds struct hda_bus **busp) 4041da177e4SLinus Torvalds { 4051da177e4SLinus Torvalds struct hda_bus *bus; 4061da177e4SLinus Torvalds int err; 407c8b6bf9bSTakashi Iwai static struct snd_device_ops dev_ops = { 4081da177e4SLinus Torvalds .dev_free = snd_hda_bus_dev_free, 4091da177e4SLinus Torvalds }; 4101da177e4SLinus Torvalds 411*da3cec35STakashi Iwai if (snd_BUG_ON(!temp)) 412*da3cec35STakashi Iwai return -EINVAL; 413*da3cec35STakashi Iwai if (snd_BUG_ON(!temp->ops.command || !temp->ops.get_response)) 414*da3cec35STakashi Iwai return -EINVAL; 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds if (busp) 4171da177e4SLinus Torvalds *busp = NULL; 4181da177e4SLinus Torvalds 419e560d8d8STakashi Iwai bus = kzalloc(sizeof(*bus), GFP_KERNEL); 4201da177e4SLinus Torvalds if (bus == NULL) { 4211da177e4SLinus Torvalds snd_printk(KERN_ERR "can't allocate struct hda_bus\n"); 4221da177e4SLinus Torvalds return -ENOMEM; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds bus->card = card; 4261da177e4SLinus Torvalds bus->private_data = temp->private_data; 4271da177e4SLinus Torvalds bus->pci = temp->pci; 4281da177e4SLinus Torvalds bus->modelname = temp->modelname; 4291da177e4SLinus Torvalds bus->ops = temp->ops; 4301da177e4SLinus Torvalds 43162932df8SIngo Molnar mutex_init(&bus->cmd_mutex); 4321da177e4SLinus Torvalds INIT_LIST_HEAD(&bus->codec_list); 4331da177e4SLinus Torvalds 4340ba21762STakashi Iwai err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); 4350ba21762STakashi Iwai if (err < 0) { 4361da177e4SLinus Torvalds snd_hda_bus_free(bus); 4371da177e4SLinus Torvalds return err; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds if (busp) 4401da177e4SLinus Torvalds *busp = bus; 4411da177e4SLinus Torvalds return 0; 4421da177e4SLinus Torvalds } 4431da177e4SLinus Torvalds 44482467611STakashi Iwai #ifdef CONFIG_SND_HDA_GENERIC 44582467611STakashi Iwai #define is_generic_config(codec) \ 44682467611STakashi Iwai (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) 44782467611STakashi Iwai #else 44882467611STakashi Iwai #define is_generic_config(codec) 0 44982467611STakashi Iwai #endif 45082467611STakashi Iwai 4511da177e4SLinus Torvalds /* 4521da177e4SLinus Torvalds * find a matching codec preset 4531da177e4SLinus Torvalds */ 454756e2b01STakashi Iwai static const struct hda_codec_preset __devinit * 455756e2b01STakashi Iwai find_codec_preset(struct hda_codec *codec) 4561da177e4SLinus Torvalds { 4571da177e4SLinus Torvalds const struct hda_codec_preset **tbl, *preset; 4581da177e4SLinus Torvalds 45982467611STakashi Iwai if (is_generic_config(codec)) 460d5ad630bSTakashi Iwai return NULL; /* use the generic parser */ 461d5ad630bSTakashi Iwai 4621da177e4SLinus Torvalds for (tbl = hda_preset_tables; *tbl; tbl++) { 4631da177e4SLinus Torvalds for (preset = *tbl; preset->id; preset++) { 4641da177e4SLinus Torvalds u32 mask = preset->mask; 465ca7cfae9SMarc Boucher if (preset->afg && preset->afg != codec->afg) 466ca7cfae9SMarc Boucher continue; 467ca7cfae9SMarc Boucher if (preset->mfg && preset->mfg != codec->mfg) 468ca7cfae9SMarc Boucher continue; 4691da177e4SLinus Torvalds if (!mask) 4701da177e4SLinus Torvalds mask = ~0; 4719c7f852eSTakashi Iwai if (preset->id == (codec->vendor_id & mask) && 4729c7f852eSTakashi Iwai (!preset->rev || 4739c7f852eSTakashi Iwai preset->rev == codec->revision_id)) 4741da177e4SLinus Torvalds return preset; 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds return NULL; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds /* 4811da177e4SLinus Torvalds * snd_hda_get_codec_name - store the codec name 4821da177e4SLinus Torvalds */ 4831da177e4SLinus Torvalds void snd_hda_get_codec_name(struct hda_codec *codec, 4841da177e4SLinus Torvalds char *name, int namelen) 4851da177e4SLinus Torvalds { 4861da177e4SLinus Torvalds const struct hda_vendor_id *c; 4871da177e4SLinus Torvalds const char *vendor = NULL; 4881da177e4SLinus Torvalds u16 vendor_id = codec->vendor_id >> 16; 4891da177e4SLinus Torvalds char tmp[16]; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds for (c = hda_vendor_ids; c->id; c++) { 4921da177e4SLinus Torvalds if (c->id == vendor_id) { 4931da177e4SLinus Torvalds vendor = c->name; 4941da177e4SLinus Torvalds break; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds } 4971da177e4SLinus Torvalds if (!vendor) { 4981da177e4SLinus Torvalds sprintf(tmp, "Generic %04x", vendor_id); 4991da177e4SLinus Torvalds vendor = tmp; 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds if (codec->preset && codec->preset->name) 5021da177e4SLinus Torvalds snprintf(name, namelen, "%s %s", vendor, codec->preset->name); 5031da177e4SLinus Torvalds else 5040ba21762STakashi Iwai snprintf(name, namelen, "%s ID %x", vendor, 5050ba21762STakashi Iwai codec->vendor_id & 0xffff); 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds /* 509673b683aSSasha Khapyorsky * look for an AFG and MFG nodes 5101da177e4SLinus Torvalds */ 511756e2b01STakashi Iwai static void __devinit setup_fg_nodes(struct hda_codec *codec) 5121da177e4SLinus Torvalds { 5131da177e4SLinus Torvalds int i, total_nodes; 5141da177e4SLinus Torvalds hda_nid_t nid; 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); 5171da177e4SLinus Torvalds for (i = 0; i < total_nodes; i++, nid++) { 5180ba21762STakashi Iwai unsigned int func; 5190ba21762STakashi Iwai func = snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE); 5200ba21762STakashi Iwai switch (func & 0xff) { 521673b683aSSasha Khapyorsky case AC_GRP_AUDIO_FUNCTION: 522673b683aSSasha Khapyorsky codec->afg = nid; 523673b683aSSasha Khapyorsky break; 524673b683aSSasha Khapyorsky case AC_GRP_MODEM_FUNCTION: 525673b683aSSasha Khapyorsky codec->mfg = nid; 526673b683aSSasha Khapyorsky break; 527673b683aSSasha Khapyorsky default: 528673b683aSSasha Khapyorsky break; 5291da177e4SLinus Torvalds } 530673b683aSSasha Khapyorsky } 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds /* 53454d17403STakashi Iwai * read widget caps for each widget and store in cache 53554d17403STakashi Iwai */ 53654d17403STakashi Iwai static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) 53754d17403STakashi Iwai { 53854d17403STakashi Iwai int i; 53954d17403STakashi Iwai hda_nid_t nid; 54054d17403STakashi Iwai 54154d17403STakashi Iwai codec->num_nodes = snd_hda_get_sub_nodes(codec, fg_node, 54254d17403STakashi Iwai &codec->start_nid); 54354d17403STakashi Iwai codec->wcaps = kmalloc(codec->num_nodes * 4, GFP_KERNEL); 54454d17403STakashi Iwai if (!codec->wcaps) 54554d17403STakashi Iwai return -ENOMEM; 54654d17403STakashi Iwai nid = codec->start_nid; 54754d17403STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) 54854d17403STakashi Iwai codec->wcaps[i] = snd_hda_param_read(codec, nid, 54954d17403STakashi Iwai AC_PAR_AUDIO_WIDGET_CAP); 55054d17403STakashi Iwai return 0; 55154d17403STakashi Iwai } 55254d17403STakashi Iwai 55354d17403STakashi Iwai 55401751f54STakashi Iwai static void init_hda_cache(struct hda_cache_rec *cache, 55501751f54STakashi Iwai unsigned int record_size); 5561fcaee6eSTakashi Iwai static void free_hda_cache(struct hda_cache_rec *cache); 55701751f54STakashi Iwai 55854d17403STakashi Iwai /* 5591da177e4SLinus Torvalds * codec destructor 5601da177e4SLinus Torvalds */ 5611da177e4SLinus Torvalds static void snd_hda_codec_free(struct hda_codec *codec) 5621da177e4SLinus Torvalds { 5631da177e4SLinus Torvalds if (!codec) 5641da177e4SLinus Torvalds return; 565cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 566cb53c626STakashi Iwai cancel_delayed_work(&codec->power_work); 5672525fdc4STakashi Iwai flush_scheduled_work(); 568cb53c626STakashi Iwai #endif 5691da177e4SLinus Torvalds list_del(&codec->list); 5701da177e4SLinus Torvalds codec->bus->caddr_tbl[codec->addr] = NULL; 5711da177e4SLinus Torvalds if (codec->patch_ops.free) 5721da177e4SLinus Torvalds codec->patch_ops.free(codec); 57301751f54STakashi Iwai free_hda_cache(&codec->amp_cache); 574b3ac5636STakashi Iwai free_hda_cache(&codec->cmd_cache); 57554d17403STakashi Iwai kfree(codec->wcaps); 5761da177e4SLinus Torvalds kfree(codec); 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds /** 5801da177e4SLinus Torvalds * snd_hda_codec_new - create a HDA codec 5811da177e4SLinus Torvalds * @bus: the bus to assign 5821da177e4SLinus Torvalds * @codec_addr: the codec address 5831da177e4SLinus Torvalds * @codecp: the pointer to store the generated codec 5841da177e4SLinus Torvalds * 5851da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 5861da177e4SLinus Torvalds */ 587756e2b01STakashi Iwai int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, 5881da177e4SLinus Torvalds struct hda_codec **codecp) 5891da177e4SLinus Torvalds { 5901da177e4SLinus Torvalds struct hda_codec *codec; 5911da177e4SLinus Torvalds char component[13]; 5921da177e4SLinus Torvalds int err; 5931da177e4SLinus Torvalds 594*da3cec35STakashi Iwai if (snd_BUG_ON(!bus)) 595*da3cec35STakashi Iwai return -EINVAL; 596*da3cec35STakashi Iwai if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS)) 597*da3cec35STakashi Iwai return -EINVAL; 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds if (bus->caddr_tbl[codec_addr]) { 6000ba21762STakashi Iwai snd_printk(KERN_ERR "hda_codec: " 6010ba21762STakashi Iwai "address 0x%x is already occupied\n", codec_addr); 6021da177e4SLinus Torvalds return -EBUSY; 6031da177e4SLinus Torvalds } 6041da177e4SLinus Torvalds 605e560d8d8STakashi Iwai codec = kzalloc(sizeof(*codec), GFP_KERNEL); 6061da177e4SLinus Torvalds if (codec == NULL) { 6071da177e4SLinus Torvalds snd_printk(KERN_ERR "can't allocate struct hda_codec\n"); 6081da177e4SLinus Torvalds return -ENOMEM; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds codec->bus = bus; 6121da177e4SLinus Torvalds codec->addr = codec_addr; 61362932df8SIngo Molnar mutex_init(&codec->spdif_mutex); 61401751f54STakashi Iwai init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); 615b3ac5636STakashi Iwai init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); 6161da177e4SLinus Torvalds 617cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 618cb53c626STakashi Iwai INIT_DELAYED_WORK(&codec->power_work, hda_power_work); 619cb53c626STakashi Iwai /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. 620cb53c626STakashi Iwai * the caller has to power down appropriatley after initialization 621cb53c626STakashi Iwai * phase. 622cb53c626STakashi Iwai */ 623cb53c626STakashi Iwai hda_keep_power_on(codec); 624cb53c626STakashi Iwai #endif 625cb53c626STakashi Iwai 6261da177e4SLinus Torvalds list_add_tail(&codec->list, &bus->codec_list); 6271da177e4SLinus Torvalds bus->caddr_tbl[codec_addr] = codec; 6281da177e4SLinus Torvalds 6290ba21762STakashi Iwai codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, 6300ba21762STakashi Iwai AC_PAR_VENDOR_ID); 631111d3af5STakashi Iwai if (codec->vendor_id == -1) 632111d3af5STakashi Iwai /* read again, hopefully the access method was corrected 633111d3af5STakashi Iwai * in the last read... 634111d3af5STakashi Iwai */ 635111d3af5STakashi Iwai codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, 636111d3af5STakashi Iwai AC_PAR_VENDOR_ID); 6370ba21762STakashi Iwai codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, 6380ba21762STakashi Iwai AC_PAR_SUBSYSTEM_ID); 6390ba21762STakashi Iwai codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, 6400ba21762STakashi Iwai AC_PAR_REV_ID); 6411da177e4SLinus Torvalds 642673b683aSSasha Khapyorsky setup_fg_nodes(codec); 643673b683aSSasha Khapyorsky if (!codec->afg && !codec->mfg) { 644673b683aSSasha Khapyorsky snd_printdd("hda_codec: no AFG or MFG node found\n"); 6451da177e4SLinus Torvalds snd_hda_codec_free(codec); 6461da177e4SLinus Torvalds return -ENODEV; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 64954d17403STakashi Iwai if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) { 65054d17403STakashi Iwai snd_printk(KERN_ERR "hda_codec: cannot malloc\n"); 65154d17403STakashi Iwai snd_hda_codec_free(codec); 65254d17403STakashi Iwai return -ENOMEM; 65354d17403STakashi Iwai } 65454d17403STakashi Iwai 65586284e45STakashi Iwai if (!codec->subsystem_id) { 65686284e45STakashi Iwai hda_nid_t nid = codec->afg ? codec->afg : codec->mfg; 6570ba21762STakashi Iwai codec->subsystem_id = 6580ba21762STakashi Iwai snd_hda_codec_read(codec, nid, 0, 6590ba21762STakashi Iwai AC_VERB_GET_SUBSYSTEM_ID, 0); 66086284e45STakashi Iwai } 66186284e45STakashi Iwai 6621da177e4SLinus Torvalds codec->preset = find_codec_preset(codec); 66343ea1d47STakashi Iwai /* audio codec should override the mixer name */ 66443ea1d47STakashi Iwai if (codec->afg || !*bus->card->mixername) 6651da177e4SLinus Torvalds snd_hda_get_codec_name(codec, bus->card->mixername, 6661da177e4SLinus Torvalds sizeof(bus->card->mixername)); 6671da177e4SLinus Torvalds 66882467611STakashi Iwai if (is_generic_config(codec)) { 6691da177e4SLinus Torvalds err = snd_hda_parse_generic_codec(codec); 67082467611STakashi Iwai goto patched; 67182467611STakashi Iwai } 67282467611STakashi Iwai if (codec->preset && codec->preset->patch) { 67382467611STakashi Iwai err = codec->preset->patch(codec); 67482467611STakashi Iwai goto patched; 67582467611STakashi Iwai } 67682467611STakashi Iwai 67782467611STakashi Iwai /* call the default parser */ 67882467611STakashi Iwai err = snd_hda_parse_generic_codec(codec); 67935a1e0ccSTakashi Iwai if (err < 0) 68082467611STakashi Iwai printk(KERN_ERR "hda-codec: No codec parser is available\n"); 68182467611STakashi Iwai 68282467611STakashi Iwai patched: 6831da177e4SLinus Torvalds if (err < 0) { 6841da177e4SLinus Torvalds snd_hda_codec_free(codec); 6851da177e4SLinus Torvalds return err; 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds 6889f146bb6STakashi Iwai if (codec->patch_ops.unsol_event) 6899f146bb6STakashi Iwai init_unsol_queue(bus); 6909f146bb6STakashi Iwai 6911da177e4SLinus Torvalds snd_hda_codec_proc_new(codec); 6922807314dSTakashi Iwai #ifdef CONFIG_SND_HDA_HWDEP 6932807314dSTakashi Iwai snd_hda_create_hwdep(codec); 6942807314dSTakashi Iwai #endif 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds sprintf(component, "HDA:%08x", codec->vendor_id); 6971da177e4SLinus Torvalds snd_component_add(codec->bus->card, component); 6981da177e4SLinus Torvalds 6991da177e4SLinus Torvalds if (codecp) 7001da177e4SLinus Torvalds *codecp = codec; 7011da177e4SLinus Torvalds return 0; 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds /** 7051da177e4SLinus Torvalds * snd_hda_codec_setup_stream - set up the codec for streaming 7061da177e4SLinus Torvalds * @codec: the CODEC to set up 7071da177e4SLinus Torvalds * @nid: the NID to set up 7081da177e4SLinus Torvalds * @stream_tag: stream tag to pass, it's between 0x1 and 0xf. 7091da177e4SLinus Torvalds * @channel_id: channel id to pass, zero based. 7101da177e4SLinus Torvalds * @format: stream format. 7111da177e4SLinus Torvalds */ 7120ba21762STakashi Iwai void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, 7130ba21762STakashi Iwai u32 stream_tag, 7141da177e4SLinus Torvalds int channel_id, int format) 7151da177e4SLinus Torvalds { 716d21b37eaSTakashi Iwai if (!nid) 717d21b37eaSTakashi Iwai return; 718d21b37eaSTakashi Iwai 7190ba21762STakashi Iwai snd_printdd("hda_codec_setup_stream: " 7200ba21762STakashi Iwai "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", 7211da177e4SLinus Torvalds nid, stream_tag, channel_id, format); 7221da177e4SLinus Torvalds snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 7231da177e4SLinus Torvalds (stream_tag << 4) | channel_id); 7241da177e4SLinus Torvalds msleep(1); 7251da177e4SLinus Torvalds snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); 7261da177e4SLinus Torvalds } 7271da177e4SLinus Torvalds 728888afa15STakashi Iwai void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) 729888afa15STakashi Iwai { 730888afa15STakashi Iwai if (!nid) 731888afa15STakashi Iwai return; 732888afa15STakashi Iwai 733888afa15STakashi Iwai snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); 734888afa15STakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); 735888afa15STakashi Iwai #if 0 /* keep the format */ 736888afa15STakashi Iwai msleep(1); 737888afa15STakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); 738888afa15STakashi Iwai #endif 739888afa15STakashi Iwai } 740888afa15STakashi Iwai 7411da177e4SLinus Torvalds /* 7421da177e4SLinus Torvalds * amp access functions 7431da177e4SLinus Torvalds */ 7441da177e4SLinus Torvalds 7454a19faeeSTakashi Iwai /* FIXME: more better hash key? */ 7464a19faeeSTakashi Iwai #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) 7471da177e4SLinus Torvalds #define INFO_AMP_CAPS (1<<0) 7484a19faeeSTakashi Iwai #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) 7491da177e4SLinus Torvalds 7501da177e4SLinus Torvalds /* initialize the hash table */ 75101751f54STakashi Iwai static void __devinit init_hda_cache(struct hda_cache_rec *cache, 75201751f54STakashi Iwai unsigned int record_size) 7531da177e4SLinus Torvalds { 75401751f54STakashi Iwai memset(cache, 0, sizeof(*cache)); 75501751f54STakashi Iwai memset(cache->hash, 0xff, sizeof(cache->hash)); 75601751f54STakashi Iwai cache->record_size = record_size; 75701751f54STakashi Iwai } 75801751f54STakashi Iwai 7591fcaee6eSTakashi Iwai static void free_hda_cache(struct hda_cache_rec *cache) 76001751f54STakashi Iwai { 76101751f54STakashi Iwai kfree(cache->buffer); 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds /* query the hash. allocate an entry if not found. */ 76501751f54STakashi Iwai static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, 76601751f54STakashi Iwai u32 key) 7671da177e4SLinus Torvalds { 76801751f54STakashi Iwai u16 idx = key % (u16)ARRAY_SIZE(cache->hash); 76901751f54STakashi Iwai u16 cur = cache->hash[idx]; 77001751f54STakashi Iwai struct hda_cache_head *info; 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds while (cur != 0xffff) { 77301751f54STakashi Iwai info = (struct hda_cache_head *)(cache->buffer + 77401751f54STakashi Iwai cur * cache->record_size); 7751da177e4SLinus Torvalds if (info->key == key) 7761da177e4SLinus Torvalds return info; 7771da177e4SLinus Torvalds cur = info->next; 7781da177e4SLinus Torvalds } 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds /* add a new hash entry */ 78101751f54STakashi Iwai if (cache->num_entries >= cache->size) { 782d031166fSTakashi Iwai /* reallocate the array */ 78301751f54STakashi Iwai unsigned int new_size = cache->size + 64; 78401751f54STakashi Iwai void *new_buffer; 78501751f54STakashi Iwai new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); 78601751f54STakashi Iwai if (!new_buffer) { 7870ba21762STakashi Iwai snd_printk(KERN_ERR "hda_codec: " 7880ba21762STakashi Iwai "can't malloc amp_info\n"); 7891da177e4SLinus Torvalds return NULL; 7901da177e4SLinus Torvalds } 79101751f54STakashi Iwai if (cache->buffer) { 79201751f54STakashi Iwai memcpy(new_buffer, cache->buffer, 79301751f54STakashi Iwai cache->size * cache->record_size); 79401751f54STakashi Iwai kfree(cache->buffer); 795d031166fSTakashi Iwai } 79601751f54STakashi Iwai cache->size = new_size; 79701751f54STakashi Iwai cache->buffer = new_buffer; 798d031166fSTakashi Iwai } 79901751f54STakashi Iwai cur = cache->num_entries++; 80001751f54STakashi Iwai info = (struct hda_cache_head *)(cache->buffer + 80101751f54STakashi Iwai cur * cache->record_size); 8021da177e4SLinus Torvalds info->key = key; 80301751f54STakashi Iwai info->val = 0; 80401751f54STakashi Iwai info->next = cache->hash[idx]; 80501751f54STakashi Iwai cache->hash[idx] = cur; 8061da177e4SLinus Torvalds 8071da177e4SLinus Torvalds return info; 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds 81001751f54STakashi Iwai /* query and allocate an amp hash entry */ 81101751f54STakashi Iwai static inline struct hda_amp_info * 81201751f54STakashi Iwai get_alloc_amp_hash(struct hda_codec *codec, u32 key) 81301751f54STakashi Iwai { 81401751f54STakashi Iwai return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); 81501751f54STakashi Iwai } 81601751f54STakashi Iwai 8171da177e4SLinus Torvalds /* 8181da177e4SLinus Torvalds * query AMP capabilities for the given widget and direction 8191da177e4SLinus Torvalds */ 82009a99959SMatthew Ranostay u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) 8211da177e4SLinus Torvalds { 8220ba21762STakashi Iwai struct hda_amp_info *info; 8231da177e4SLinus Torvalds 8240ba21762STakashi Iwai info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); 8251da177e4SLinus Torvalds if (!info) 8261da177e4SLinus Torvalds return 0; 82701751f54STakashi Iwai if (!(info->head.val & INFO_AMP_CAPS)) { 82854d17403STakashi Iwai if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) 8291da177e4SLinus Torvalds nid = codec->afg; 8300ba21762STakashi Iwai info->amp_caps = snd_hda_param_read(codec, nid, 8310ba21762STakashi Iwai direction == HDA_OUTPUT ? 8320ba21762STakashi Iwai AC_PAR_AMP_OUT_CAP : 8330ba21762STakashi Iwai AC_PAR_AMP_IN_CAP); 834b75e53f0STakashi Iwai if (info->amp_caps) 83501751f54STakashi Iwai info->head.val |= INFO_AMP_CAPS; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds return info->amp_caps; 8381da177e4SLinus Torvalds } 8391da177e4SLinus Torvalds 840897cc188STakashi Iwai int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, 841897cc188STakashi Iwai unsigned int caps) 842897cc188STakashi Iwai { 843897cc188STakashi Iwai struct hda_amp_info *info; 844897cc188STakashi Iwai 845897cc188STakashi Iwai info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, dir, 0)); 846897cc188STakashi Iwai if (!info) 847897cc188STakashi Iwai return -EINVAL; 848897cc188STakashi Iwai info->amp_caps = caps; 84901751f54STakashi Iwai info->head.val |= INFO_AMP_CAPS; 850897cc188STakashi Iwai return 0; 851897cc188STakashi Iwai } 852897cc188STakashi Iwai 8531da177e4SLinus Torvalds /* 8541da177e4SLinus Torvalds * read the current volume to info 8554a19faeeSTakashi Iwai * if the cache exists, read the cache value. 8561da177e4SLinus Torvalds */ 8570ba21762STakashi Iwai static unsigned int get_vol_mute(struct hda_codec *codec, 8580ba21762STakashi Iwai struct hda_amp_info *info, hda_nid_t nid, 8590ba21762STakashi Iwai int ch, int direction, int index) 8601da177e4SLinus Torvalds { 8611da177e4SLinus Torvalds u32 val, parm; 8621da177e4SLinus Torvalds 86301751f54STakashi Iwai if (info->head.val & INFO_AMP_VOL(ch)) 8644a19faeeSTakashi Iwai return info->vol[ch]; 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; 8671da177e4SLinus Torvalds parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; 8681da177e4SLinus Torvalds parm |= index; 8690ba21762STakashi Iwai val = snd_hda_codec_read(codec, nid, 0, 8700ba21762STakashi Iwai AC_VERB_GET_AMP_GAIN_MUTE, parm); 8711da177e4SLinus Torvalds info->vol[ch] = val & 0xff; 87201751f54STakashi Iwai info->head.val |= INFO_AMP_VOL(ch); 8734a19faeeSTakashi Iwai return info->vol[ch]; 8741da177e4SLinus Torvalds } 8751da177e4SLinus Torvalds 8761da177e4SLinus Torvalds /* 8774a19faeeSTakashi Iwai * write the current volume in info to the h/w and update the cache 8781da177e4SLinus Torvalds */ 8794a19faeeSTakashi Iwai static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, 8800ba21762STakashi Iwai hda_nid_t nid, int ch, int direction, int index, 8810ba21762STakashi Iwai int val) 8821da177e4SLinus Torvalds { 8831da177e4SLinus Torvalds u32 parm; 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; 8861da177e4SLinus Torvalds parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; 8871da177e4SLinus Torvalds parm |= index << AC_AMP_SET_INDEX_SHIFT; 8881da177e4SLinus Torvalds parm |= val; 8891da177e4SLinus Torvalds snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); 8904a19faeeSTakashi Iwai info->vol[ch] = val; 8911da177e4SLinus Torvalds } 8921da177e4SLinus Torvalds 8931da177e4SLinus Torvalds /* 8944a19faeeSTakashi Iwai * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. 8951da177e4SLinus Torvalds */ 896834be88dSTakashi Iwai int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, 897834be88dSTakashi Iwai int direction, int index) 8981da177e4SLinus Torvalds { 8990ba21762STakashi Iwai struct hda_amp_info *info; 9000ba21762STakashi Iwai info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); 9011da177e4SLinus Torvalds if (!info) 9021da177e4SLinus Torvalds return 0; 9034a19faeeSTakashi Iwai return get_vol_mute(codec, info, nid, ch, direction, index); 9041da177e4SLinus Torvalds } 9051da177e4SLinus Torvalds 9064a19faeeSTakashi Iwai /* 9074a19faeeSTakashi Iwai * update the AMP value, mask = bit mask to set, val = the value 9084a19faeeSTakashi Iwai */ 909834be88dSTakashi Iwai int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, 910834be88dSTakashi Iwai int direction, int idx, int mask, int val) 9111da177e4SLinus Torvalds { 9120ba21762STakashi Iwai struct hda_amp_info *info; 9134a19faeeSTakashi Iwai 9140ba21762STakashi Iwai info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); 9151da177e4SLinus Torvalds if (!info) 9161da177e4SLinus Torvalds return 0; 9174a19faeeSTakashi Iwai val &= mask; 9184a19faeeSTakashi Iwai val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; 91982beb8fdSTakashi Iwai if (info->vol[ch] == val) 9201da177e4SLinus Torvalds return 0; 9214a19faeeSTakashi Iwai put_vol_mute(codec, info, nid, ch, direction, idx, val); 9221da177e4SLinus Torvalds return 1; 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds 92547fd830aSTakashi Iwai /* 92647fd830aSTakashi Iwai * update the AMP stereo with the same mask and value 92747fd830aSTakashi Iwai */ 92847fd830aSTakashi Iwai int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, 92947fd830aSTakashi Iwai int direction, int idx, int mask, int val) 93047fd830aSTakashi Iwai { 93147fd830aSTakashi Iwai int ch, ret = 0; 93247fd830aSTakashi Iwai for (ch = 0; ch < 2; ch++) 93347fd830aSTakashi Iwai ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, 93447fd830aSTakashi Iwai idx, mask, val); 93547fd830aSTakashi Iwai return ret; 93647fd830aSTakashi Iwai } 93747fd830aSTakashi Iwai 938cb53c626STakashi Iwai #ifdef SND_HDA_NEEDS_RESUME 939b3ac5636STakashi Iwai /* resume the all amp commands from the cache */ 940b3ac5636STakashi Iwai void snd_hda_codec_resume_amp(struct hda_codec *codec) 941b3ac5636STakashi Iwai { 942b3ac5636STakashi Iwai struct hda_amp_info *buffer = codec->amp_cache.buffer; 943b3ac5636STakashi Iwai int i; 944b3ac5636STakashi Iwai 945b3ac5636STakashi Iwai for (i = 0; i < codec->amp_cache.size; i++, buffer++) { 946b3ac5636STakashi Iwai u32 key = buffer->head.key; 947b3ac5636STakashi Iwai hda_nid_t nid; 948b3ac5636STakashi Iwai unsigned int idx, dir, ch; 949b3ac5636STakashi Iwai if (!key) 950b3ac5636STakashi Iwai continue; 951b3ac5636STakashi Iwai nid = key & 0xff; 952b3ac5636STakashi Iwai idx = (key >> 16) & 0xff; 953b3ac5636STakashi Iwai dir = (key >> 24) & 0xff; 954b3ac5636STakashi Iwai for (ch = 0; ch < 2; ch++) { 955b3ac5636STakashi Iwai if (!(buffer->head.val & INFO_AMP_VOL(ch))) 956b3ac5636STakashi Iwai continue; 957b3ac5636STakashi Iwai put_vol_mute(codec, buffer, nid, ch, dir, idx, 958b3ac5636STakashi Iwai buffer->vol[ch]); 959b3ac5636STakashi Iwai } 960b3ac5636STakashi Iwai } 961b3ac5636STakashi Iwai } 962cb53c626STakashi Iwai #endif /* SND_HDA_NEEDS_RESUME */ 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds /* 9651da177e4SLinus Torvalds * AMP control callbacks 9661da177e4SLinus Torvalds */ 9671da177e4SLinus Torvalds /* retrieve parameters from private_value */ 9681da177e4SLinus Torvalds #define get_amp_nid(kc) ((kc)->private_value & 0xffff) 9691da177e4SLinus Torvalds #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) 9701da177e4SLinus Torvalds #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) 9711da177e4SLinus Torvalds #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) 9721da177e4SLinus Torvalds 9731da177e4SLinus Torvalds /* volume */ 9740ba21762STakashi Iwai int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, 9750ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo) 9761da177e4SLinus Torvalds { 9771da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 9781da177e4SLinus Torvalds u16 nid = get_amp_nid(kcontrol); 9791da177e4SLinus Torvalds u8 chs = get_amp_channels(kcontrol); 9801da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 9811da177e4SLinus Torvalds u32 caps; 9821da177e4SLinus Torvalds 9831da177e4SLinus Torvalds caps = query_amp_caps(codec, nid, dir); 9840ba21762STakashi Iwai /* num steps */ 9850ba21762STakashi Iwai caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; 9861da177e4SLinus Torvalds if (!caps) { 9870ba21762STakashi Iwai printk(KERN_WARNING "hda_codec: " 9889c8f2abdSTakashi Iwai "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, 9899c8f2abdSTakashi Iwai kcontrol->id.name); 9901da177e4SLinus Torvalds return -EINVAL; 9911da177e4SLinus Torvalds } 9921da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 9931da177e4SLinus Torvalds uinfo->count = chs == 3 ? 2 : 1; 9941da177e4SLinus Torvalds uinfo->value.integer.min = 0; 9951da177e4SLinus Torvalds uinfo->value.integer.max = caps; 9961da177e4SLinus Torvalds return 0; 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds 9990ba21762STakashi Iwai int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, 10000ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10011da177e4SLinus Torvalds { 10021da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 10031da177e4SLinus Torvalds hda_nid_t nid = get_amp_nid(kcontrol); 10041da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 10051da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 10061da177e4SLinus Torvalds int idx = get_amp_index(kcontrol); 10071da177e4SLinus Torvalds long *valp = ucontrol->value.integer.value; 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds if (chs & 1) 101047fd830aSTakashi Iwai *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) 101147fd830aSTakashi Iwai & HDA_AMP_VOLMASK; 10121da177e4SLinus Torvalds if (chs & 2) 101347fd830aSTakashi Iwai *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) 101447fd830aSTakashi Iwai & HDA_AMP_VOLMASK; 10151da177e4SLinus Torvalds return 0; 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds 10180ba21762STakashi Iwai int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, 10190ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10201da177e4SLinus Torvalds { 10211da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 10221da177e4SLinus Torvalds hda_nid_t nid = get_amp_nid(kcontrol); 10231da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 10241da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 10251da177e4SLinus Torvalds int idx = get_amp_index(kcontrol); 10261da177e4SLinus Torvalds long *valp = ucontrol->value.integer.value; 10271da177e4SLinus Torvalds int change = 0; 10281da177e4SLinus Torvalds 1029cb53c626STakashi Iwai snd_hda_power_up(codec); 1030b9f5a89cSNicolas Graziano if (chs & 1) { 10314a19faeeSTakashi Iwai change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 10324a19faeeSTakashi Iwai 0x7f, *valp); 1033b9f5a89cSNicolas Graziano valp++; 1034b9f5a89cSNicolas Graziano } 10354a19faeeSTakashi Iwai if (chs & 2) 10364a19faeeSTakashi Iwai change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, 1037b9f5a89cSNicolas Graziano 0x7f, *valp); 1038cb53c626STakashi Iwai snd_hda_power_down(codec); 10391da177e4SLinus Torvalds return change; 10401da177e4SLinus Torvalds } 10411da177e4SLinus Torvalds 1042302e9c5aSJaroslav Kysela int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, 1043302e9c5aSJaroslav Kysela unsigned int size, unsigned int __user *_tlv) 1044302e9c5aSJaroslav Kysela { 1045302e9c5aSJaroslav Kysela struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1046302e9c5aSJaroslav Kysela hda_nid_t nid = get_amp_nid(kcontrol); 1047302e9c5aSJaroslav Kysela int dir = get_amp_direction(kcontrol); 1048302e9c5aSJaroslav Kysela u32 caps, val1, val2; 1049302e9c5aSJaroslav Kysela 1050302e9c5aSJaroslav Kysela if (size < 4 * sizeof(unsigned int)) 1051302e9c5aSJaroslav Kysela return -ENOMEM; 1052302e9c5aSJaroslav Kysela caps = query_amp_caps(codec, nid, dir); 10530ba21762STakashi Iwai val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; 10540ba21762STakashi Iwai val2 = (val2 + 1) * 25; 1055302e9c5aSJaroslav Kysela val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); 1056302e9c5aSJaroslav Kysela val1 = ((int)val1) * ((int)val2); 1057302e9c5aSJaroslav Kysela if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) 1058302e9c5aSJaroslav Kysela return -EFAULT; 1059302e9c5aSJaroslav Kysela if (put_user(2 * sizeof(unsigned int), _tlv + 1)) 1060302e9c5aSJaroslav Kysela return -EFAULT; 1061302e9c5aSJaroslav Kysela if (put_user(val1, _tlv + 2)) 1062302e9c5aSJaroslav Kysela return -EFAULT; 1063302e9c5aSJaroslav Kysela if (put_user(val2, _tlv + 3)) 1064302e9c5aSJaroslav Kysela return -EFAULT; 1065302e9c5aSJaroslav Kysela return 0; 1066302e9c5aSJaroslav Kysela } 1067302e9c5aSJaroslav Kysela 10682134ea4fSTakashi Iwai /* 10692134ea4fSTakashi Iwai * set (static) TLV for virtual master volume; recalculated as max 0dB 10702134ea4fSTakashi Iwai */ 10712134ea4fSTakashi Iwai void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, 10722134ea4fSTakashi Iwai unsigned int *tlv) 10732134ea4fSTakashi Iwai { 10742134ea4fSTakashi Iwai u32 caps; 10752134ea4fSTakashi Iwai int nums, step; 10762134ea4fSTakashi Iwai 10772134ea4fSTakashi Iwai caps = query_amp_caps(codec, nid, dir); 10782134ea4fSTakashi Iwai nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; 10792134ea4fSTakashi Iwai step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; 10802134ea4fSTakashi Iwai step = (step + 1) * 25; 10812134ea4fSTakashi Iwai tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; 10822134ea4fSTakashi Iwai tlv[1] = 2 * sizeof(unsigned int); 10832134ea4fSTakashi Iwai tlv[2] = -nums * step; 10842134ea4fSTakashi Iwai tlv[3] = step; 10852134ea4fSTakashi Iwai } 10862134ea4fSTakashi Iwai 10872134ea4fSTakashi Iwai /* find a mixer control element with the given name */ 108809f99701STakashi Iwai static struct snd_kcontrol * 108909f99701STakashi Iwai _snd_hda_find_mixer_ctl(struct hda_codec *codec, 109009f99701STakashi Iwai const char *name, int idx) 10912134ea4fSTakashi Iwai { 10922134ea4fSTakashi Iwai struct snd_ctl_elem_id id; 10932134ea4fSTakashi Iwai memset(&id, 0, sizeof(id)); 10942134ea4fSTakashi Iwai id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 109509f99701STakashi Iwai id.index = idx; 10962134ea4fSTakashi Iwai strcpy(id.name, name); 10972134ea4fSTakashi Iwai return snd_ctl_find_id(codec->bus->card, &id); 10982134ea4fSTakashi Iwai } 10992134ea4fSTakashi Iwai 110009f99701STakashi Iwai struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, 110109f99701STakashi Iwai const char *name) 110209f99701STakashi Iwai { 110309f99701STakashi Iwai return _snd_hda_find_mixer_ctl(codec, name, 0); 110409f99701STakashi Iwai } 110509f99701STakashi Iwai 11062134ea4fSTakashi Iwai /* create a virtual master control and add slaves */ 11072134ea4fSTakashi Iwai int snd_hda_add_vmaster(struct hda_codec *codec, char *name, 11082134ea4fSTakashi Iwai unsigned int *tlv, const char **slaves) 11092134ea4fSTakashi Iwai { 11102134ea4fSTakashi Iwai struct snd_kcontrol *kctl; 11112134ea4fSTakashi Iwai const char **s; 11122134ea4fSTakashi Iwai int err; 11132134ea4fSTakashi Iwai 11142f085549STakashi Iwai for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++) 11152f085549STakashi Iwai ; 11162f085549STakashi Iwai if (!*s) { 11172f085549STakashi Iwai snd_printdd("No slave found for %s\n", name); 11182f085549STakashi Iwai return 0; 11192f085549STakashi Iwai } 11202134ea4fSTakashi Iwai kctl = snd_ctl_make_virtual_master(name, tlv); 11212134ea4fSTakashi Iwai if (!kctl) 11222134ea4fSTakashi Iwai return -ENOMEM; 11232134ea4fSTakashi Iwai err = snd_ctl_add(codec->bus->card, kctl); 11242134ea4fSTakashi Iwai if (err < 0) 11252134ea4fSTakashi Iwai return err; 11262134ea4fSTakashi Iwai 11272134ea4fSTakashi Iwai for (s = slaves; *s; s++) { 11282134ea4fSTakashi Iwai struct snd_kcontrol *sctl; 11292134ea4fSTakashi Iwai 11302134ea4fSTakashi Iwai sctl = snd_hda_find_mixer_ctl(codec, *s); 11312134ea4fSTakashi Iwai if (!sctl) { 11322134ea4fSTakashi Iwai snd_printdd("Cannot find slave %s, skipped\n", *s); 11332134ea4fSTakashi Iwai continue; 11342134ea4fSTakashi Iwai } 11352134ea4fSTakashi Iwai err = snd_ctl_add_slave(kctl, sctl); 11362134ea4fSTakashi Iwai if (err < 0) 11372134ea4fSTakashi Iwai return err; 11382134ea4fSTakashi Iwai } 11392134ea4fSTakashi Iwai return 0; 11402134ea4fSTakashi Iwai } 11412134ea4fSTakashi Iwai 11421da177e4SLinus Torvalds /* switch */ 11430ba21762STakashi Iwai int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, 11440ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo) 11451da177e4SLinus Torvalds { 11461da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 11471da177e4SLinus Torvalds 11481da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 11491da177e4SLinus Torvalds uinfo->count = chs == 3 ? 2 : 1; 11501da177e4SLinus Torvalds uinfo->value.integer.min = 0; 11511da177e4SLinus Torvalds uinfo->value.integer.max = 1; 11521da177e4SLinus Torvalds return 0; 11531da177e4SLinus Torvalds } 11541da177e4SLinus Torvalds 11550ba21762STakashi Iwai int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, 11560ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11571da177e4SLinus Torvalds { 11581da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 11591da177e4SLinus Torvalds hda_nid_t nid = get_amp_nid(kcontrol); 11601da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 11611da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 11621da177e4SLinus Torvalds int idx = get_amp_index(kcontrol); 11631da177e4SLinus Torvalds long *valp = ucontrol->value.integer.value; 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds if (chs & 1) 11660ba21762STakashi Iwai *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 116747fd830aSTakashi Iwai HDA_AMP_MUTE) ? 0 : 1; 11681da177e4SLinus Torvalds if (chs & 2) 11690ba21762STakashi Iwai *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 117047fd830aSTakashi Iwai HDA_AMP_MUTE) ? 0 : 1; 11711da177e4SLinus Torvalds return 0; 11721da177e4SLinus Torvalds } 11731da177e4SLinus Torvalds 11740ba21762STakashi Iwai int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, 11750ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11761da177e4SLinus Torvalds { 11771da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 11781da177e4SLinus Torvalds hda_nid_t nid = get_amp_nid(kcontrol); 11791da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 11801da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 11811da177e4SLinus Torvalds int idx = get_amp_index(kcontrol); 11821da177e4SLinus Torvalds long *valp = ucontrol->value.integer.value; 11831da177e4SLinus Torvalds int change = 0; 11841da177e4SLinus Torvalds 1185cb53c626STakashi Iwai snd_hda_power_up(codec); 1186b9f5a89cSNicolas Graziano if (chs & 1) { 11874a19faeeSTakashi Iwai change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 118847fd830aSTakashi Iwai HDA_AMP_MUTE, 118947fd830aSTakashi Iwai *valp ? 0 : HDA_AMP_MUTE); 1190b9f5a89cSNicolas Graziano valp++; 1191b9f5a89cSNicolas Graziano } 11924a19faeeSTakashi Iwai if (chs & 2) 11934a19faeeSTakashi Iwai change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, 119447fd830aSTakashi Iwai HDA_AMP_MUTE, 119547fd830aSTakashi Iwai *valp ? 0 : HDA_AMP_MUTE); 1196cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 1197cb53c626STakashi Iwai if (codec->patch_ops.check_power_status) 1198cb53c626STakashi Iwai codec->patch_ops.check_power_status(codec, nid); 1199cb53c626STakashi Iwai #endif 1200cb53c626STakashi Iwai snd_hda_power_down(codec); 12011da177e4SLinus Torvalds return change; 12021da177e4SLinus Torvalds } 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds /* 1205985be54bSTakashi Iwai * bound volume controls 1206985be54bSTakashi Iwai * 1207985be54bSTakashi Iwai * bind multiple volumes (# indices, from 0) 1208985be54bSTakashi Iwai */ 1209985be54bSTakashi Iwai 1210985be54bSTakashi Iwai #define AMP_VAL_IDX_SHIFT 19 1211985be54bSTakashi Iwai #define AMP_VAL_IDX_MASK (0x0f<<19) 1212985be54bSTakashi Iwai 12130ba21762STakashi Iwai int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, 12140ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1215985be54bSTakashi Iwai { 1216985be54bSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1217985be54bSTakashi Iwai unsigned long pval; 1218985be54bSTakashi Iwai int err; 1219985be54bSTakashi Iwai 122062932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ 1221985be54bSTakashi Iwai pval = kcontrol->private_value; 1222985be54bSTakashi Iwai kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ 1223985be54bSTakashi Iwai err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); 1224985be54bSTakashi Iwai kcontrol->private_value = pval; 122562932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 1226985be54bSTakashi Iwai return err; 1227985be54bSTakashi Iwai } 1228985be54bSTakashi Iwai 12290ba21762STakashi Iwai int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, 12300ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1231985be54bSTakashi Iwai { 1232985be54bSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1233985be54bSTakashi Iwai unsigned long pval; 1234985be54bSTakashi Iwai int i, indices, err = 0, change = 0; 1235985be54bSTakashi Iwai 123662932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ 1237985be54bSTakashi Iwai pval = kcontrol->private_value; 1238985be54bSTakashi Iwai indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; 1239985be54bSTakashi Iwai for (i = 0; i < indices; i++) { 12400ba21762STakashi Iwai kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | 12410ba21762STakashi Iwai (i << AMP_VAL_IDX_SHIFT); 1242985be54bSTakashi Iwai err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 1243985be54bSTakashi Iwai if (err < 0) 1244985be54bSTakashi Iwai break; 1245985be54bSTakashi Iwai change |= err; 1246985be54bSTakashi Iwai } 1247985be54bSTakashi Iwai kcontrol->private_value = pval; 124862932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 1249985be54bSTakashi Iwai return err < 0 ? err : change; 1250985be54bSTakashi Iwai } 1251985be54bSTakashi Iwai 1252985be54bSTakashi Iwai /* 1253532d5381STakashi Iwai * generic bound volume/swtich controls 1254532d5381STakashi Iwai */ 1255532d5381STakashi Iwai int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, 1256532d5381STakashi Iwai struct snd_ctl_elem_info *uinfo) 1257532d5381STakashi Iwai { 1258532d5381STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1259532d5381STakashi Iwai struct hda_bind_ctls *c; 1260532d5381STakashi Iwai int err; 1261532d5381STakashi Iwai 1262532d5381STakashi Iwai mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ 126314c65f98SSerge A. Suchkov c = (struct hda_bind_ctls *)kcontrol->private_value; 1264532d5381STakashi Iwai kcontrol->private_value = *c->values; 1265532d5381STakashi Iwai err = c->ops->info(kcontrol, uinfo); 1266532d5381STakashi Iwai kcontrol->private_value = (long)c; 1267532d5381STakashi Iwai mutex_unlock(&codec->spdif_mutex); 1268532d5381STakashi Iwai return err; 1269532d5381STakashi Iwai } 1270532d5381STakashi Iwai 1271532d5381STakashi Iwai int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, 1272532d5381STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1273532d5381STakashi Iwai { 1274532d5381STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1275532d5381STakashi Iwai struct hda_bind_ctls *c; 1276532d5381STakashi Iwai int err; 1277532d5381STakashi Iwai 1278532d5381STakashi Iwai mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ 127914c65f98SSerge A. Suchkov c = (struct hda_bind_ctls *)kcontrol->private_value; 1280532d5381STakashi Iwai kcontrol->private_value = *c->values; 1281532d5381STakashi Iwai err = c->ops->get(kcontrol, ucontrol); 1282532d5381STakashi Iwai kcontrol->private_value = (long)c; 1283532d5381STakashi Iwai mutex_unlock(&codec->spdif_mutex); 1284532d5381STakashi Iwai return err; 1285532d5381STakashi Iwai } 1286532d5381STakashi Iwai 1287532d5381STakashi Iwai int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, 1288532d5381STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1289532d5381STakashi Iwai { 1290532d5381STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1291532d5381STakashi Iwai struct hda_bind_ctls *c; 1292532d5381STakashi Iwai unsigned long *vals; 1293532d5381STakashi Iwai int err = 0, change = 0; 1294532d5381STakashi Iwai 1295532d5381STakashi Iwai mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ 129614c65f98SSerge A. Suchkov c = (struct hda_bind_ctls *)kcontrol->private_value; 1297532d5381STakashi Iwai for (vals = c->values; *vals; vals++) { 1298532d5381STakashi Iwai kcontrol->private_value = *vals; 1299532d5381STakashi Iwai err = c->ops->put(kcontrol, ucontrol); 1300532d5381STakashi Iwai if (err < 0) 1301532d5381STakashi Iwai break; 1302532d5381STakashi Iwai change |= err; 1303532d5381STakashi Iwai } 1304532d5381STakashi Iwai kcontrol->private_value = (long)c; 1305532d5381STakashi Iwai mutex_unlock(&codec->spdif_mutex); 1306532d5381STakashi Iwai return err < 0 ? err : change; 1307532d5381STakashi Iwai } 1308532d5381STakashi Iwai 1309532d5381STakashi Iwai int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, 1310532d5381STakashi Iwai unsigned int size, unsigned int __user *tlv) 1311532d5381STakashi Iwai { 1312532d5381STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1313532d5381STakashi Iwai struct hda_bind_ctls *c; 1314532d5381STakashi Iwai int err; 1315532d5381STakashi Iwai 1316532d5381STakashi Iwai mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ 131714c65f98SSerge A. Suchkov c = (struct hda_bind_ctls *)kcontrol->private_value; 1318532d5381STakashi Iwai kcontrol->private_value = *c->values; 1319532d5381STakashi Iwai err = c->ops->tlv(kcontrol, op_flag, size, tlv); 1320532d5381STakashi Iwai kcontrol->private_value = (long)c; 1321532d5381STakashi Iwai mutex_unlock(&codec->spdif_mutex); 1322532d5381STakashi Iwai return err; 1323532d5381STakashi Iwai } 1324532d5381STakashi Iwai 1325532d5381STakashi Iwai struct hda_ctl_ops snd_hda_bind_vol = { 1326532d5381STakashi Iwai .info = snd_hda_mixer_amp_volume_info, 1327532d5381STakashi Iwai .get = snd_hda_mixer_amp_volume_get, 1328532d5381STakashi Iwai .put = snd_hda_mixer_amp_volume_put, 1329532d5381STakashi Iwai .tlv = snd_hda_mixer_amp_tlv 1330532d5381STakashi Iwai }; 1331532d5381STakashi Iwai 1332532d5381STakashi Iwai struct hda_ctl_ops snd_hda_bind_sw = { 1333532d5381STakashi Iwai .info = snd_hda_mixer_amp_switch_info, 1334532d5381STakashi Iwai .get = snd_hda_mixer_amp_switch_get, 1335532d5381STakashi Iwai .put = snd_hda_mixer_amp_switch_put, 1336532d5381STakashi Iwai .tlv = snd_hda_mixer_amp_tlv 1337532d5381STakashi Iwai }; 1338532d5381STakashi Iwai 1339532d5381STakashi Iwai /* 13401da177e4SLinus Torvalds * SPDIF out controls 13411da177e4SLinus Torvalds */ 13421da177e4SLinus Torvalds 13430ba21762STakashi Iwai static int snd_hda_spdif_mask_info(struct snd_kcontrol *kcontrol, 13440ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo) 13451da177e4SLinus Torvalds { 13461da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 13471da177e4SLinus Torvalds uinfo->count = 1; 13481da177e4SLinus Torvalds return 0; 13491da177e4SLinus Torvalds } 13501da177e4SLinus Torvalds 13510ba21762STakashi Iwai static int snd_hda_spdif_cmask_get(struct snd_kcontrol *kcontrol, 13520ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13531da177e4SLinus Torvalds { 13541da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL | 13551da177e4SLinus Torvalds IEC958_AES0_NONAUDIO | 13561da177e4SLinus Torvalds IEC958_AES0_CON_EMPHASIS_5015 | 13571da177e4SLinus Torvalds IEC958_AES0_CON_NOT_COPYRIGHT; 13581da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY | 13591da177e4SLinus Torvalds IEC958_AES1_CON_ORIGINAL; 13601da177e4SLinus Torvalds return 0; 13611da177e4SLinus Torvalds } 13621da177e4SLinus Torvalds 13630ba21762STakashi Iwai static int snd_hda_spdif_pmask_get(struct snd_kcontrol *kcontrol, 13640ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13651da177e4SLinus Torvalds { 13661da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL | 13671da177e4SLinus Torvalds IEC958_AES0_NONAUDIO | 13681da177e4SLinus Torvalds IEC958_AES0_PRO_EMPHASIS_5015; 13691da177e4SLinus Torvalds return 0; 13701da177e4SLinus Torvalds } 13711da177e4SLinus Torvalds 13720ba21762STakashi Iwai static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol, 13730ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13741da177e4SLinus Torvalds { 13751da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff; 13781da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff; 13791da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff; 13801da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff; 13811da177e4SLinus Torvalds 13821da177e4SLinus Torvalds return 0; 13831da177e4SLinus Torvalds } 13841da177e4SLinus Torvalds 13851da177e4SLinus Torvalds /* convert from SPDIF status bits to HDA SPDIF bits 13861da177e4SLinus Torvalds * bit 0 (DigEn) is always set zero (to be filled later) 13871da177e4SLinus Torvalds */ 13881da177e4SLinus Torvalds static unsigned short convert_from_spdif_status(unsigned int sbits) 13891da177e4SLinus Torvalds { 13901da177e4SLinus Torvalds unsigned short val = 0; 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds if (sbits & IEC958_AES0_PROFESSIONAL) 13930ba21762STakashi Iwai val |= AC_DIG1_PROFESSIONAL; 13941da177e4SLinus Torvalds if (sbits & IEC958_AES0_NONAUDIO) 13950ba21762STakashi Iwai val |= AC_DIG1_NONAUDIO; 13961da177e4SLinus Torvalds if (sbits & IEC958_AES0_PROFESSIONAL) { 13970ba21762STakashi Iwai if ((sbits & IEC958_AES0_PRO_EMPHASIS) == 13980ba21762STakashi Iwai IEC958_AES0_PRO_EMPHASIS_5015) 13990ba21762STakashi Iwai val |= AC_DIG1_EMPHASIS; 14001da177e4SLinus Torvalds } else { 14010ba21762STakashi Iwai if ((sbits & IEC958_AES0_CON_EMPHASIS) == 14020ba21762STakashi Iwai IEC958_AES0_CON_EMPHASIS_5015) 14030ba21762STakashi Iwai val |= AC_DIG1_EMPHASIS; 14041da177e4SLinus Torvalds if (!(sbits & IEC958_AES0_CON_NOT_COPYRIGHT)) 14050ba21762STakashi Iwai val |= AC_DIG1_COPYRIGHT; 14061da177e4SLinus Torvalds if (sbits & (IEC958_AES1_CON_ORIGINAL << 8)) 14070ba21762STakashi Iwai val |= AC_DIG1_LEVEL; 14081da177e4SLinus Torvalds val |= sbits & (IEC958_AES1_CON_CATEGORY << 8); 14091da177e4SLinus Torvalds } 14101da177e4SLinus Torvalds return val; 14111da177e4SLinus Torvalds } 14121da177e4SLinus Torvalds 14131da177e4SLinus Torvalds /* convert to SPDIF status bits from HDA SPDIF bits 14141da177e4SLinus Torvalds */ 14151da177e4SLinus Torvalds static unsigned int convert_to_spdif_status(unsigned short val) 14161da177e4SLinus Torvalds { 14171da177e4SLinus Torvalds unsigned int sbits = 0; 14181da177e4SLinus Torvalds 14190ba21762STakashi Iwai if (val & AC_DIG1_NONAUDIO) 14201da177e4SLinus Torvalds sbits |= IEC958_AES0_NONAUDIO; 14210ba21762STakashi Iwai if (val & AC_DIG1_PROFESSIONAL) 14221da177e4SLinus Torvalds sbits |= IEC958_AES0_PROFESSIONAL; 14231da177e4SLinus Torvalds if (sbits & IEC958_AES0_PROFESSIONAL) { 14240ba21762STakashi Iwai if (sbits & AC_DIG1_EMPHASIS) 14251da177e4SLinus Torvalds sbits |= IEC958_AES0_PRO_EMPHASIS_5015; 14261da177e4SLinus Torvalds } else { 14270ba21762STakashi Iwai if (val & AC_DIG1_EMPHASIS) 14281da177e4SLinus Torvalds sbits |= IEC958_AES0_CON_EMPHASIS_5015; 14290ba21762STakashi Iwai if (!(val & AC_DIG1_COPYRIGHT)) 14301da177e4SLinus Torvalds sbits |= IEC958_AES0_CON_NOT_COPYRIGHT; 14310ba21762STakashi Iwai if (val & AC_DIG1_LEVEL) 14321da177e4SLinus Torvalds sbits |= (IEC958_AES1_CON_ORIGINAL << 8); 14331da177e4SLinus Torvalds sbits |= val & (0x7f << 8); 14341da177e4SLinus Torvalds } 14351da177e4SLinus Torvalds return sbits; 14361da177e4SLinus Torvalds } 14371da177e4SLinus Torvalds 14380ba21762STakashi Iwai static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, 14390ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14401da177e4SLinus Torvalds { 14411da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 14421da177e4SLinus Torvalds hda_nid_t nid = kcontrol->private_value; 14431da177e4SLinus Torvalds unsigned short val; 14441da177e4SLinus Torvalds int change; 14451da177e4SLinus Torvalds 144662932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 14471da177e4SLinus Torvalds codec->spdif_status = ucontrol->value.iec958.status[0] | 14481da177e4SLinus Torvalds ((unsigned int)ucontrol->value.iec958.status[1] << 8) | 14491da177e4SLinus Torvalds ((unsigned int)ucontrol->value.iec958.status[2] << 16) | 14501da177e4SLinus Torvalds ((unsigned int)ucontrol->value.iec958.status[3] << 24); 14511da177e4SLinus Torvalds val = convert_from_spdif_status(codec->spdif_status); 14521da177e4SLinus Torvalds val |= codec->spdif_ctls & 1; 14531da177e4SLinus Torvalds change = codec->spdif_ctls != val; 14541da177e4SLinus Torvalds codec->spdif_ctls = val; 14551da177e4SLinus Torvalds 145682beb8fdSTakashi Iwai if (change) { 145782beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 145882beb8fdSTakashi Iwai AC_VERB_SET_DIGI_CONVERT_1, 14590ba21762STakashi Iwai val & 0xff); 146082beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 146182beb8fdSTakashi Iwai AC_VERB_SET_DIGI_CONVERT_2, 14620ba21762STakashi Iwai val >> 8); 14631da177e4SLinus Torvalds } 14641da177e4SLinus Torvalds 146562932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 14661da177e4SLinus Torvalds return change; 14671da177e4SLinus Torvalds } 14681da177e4SLinus Torvalds 1469a5ce8890STakashi Iwai #define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info 14701da177e4SLinus Torvalds 14710ba21762STakashi Iwai static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, 14720ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14731da177e4SLinus Torvalds { 14741da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 14751da177e4SLinus Torvalds 14760ba21762STakashi Iwai ucontrol->value.integer.value[0] = codec->spdif_ctls & AC_DIG1_ENABLE; 14771da177e4SLinus Torvalds return 0; 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds 14800ba21762STakashi Iwai static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, 14810ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14821da177e4SLinus Torvalds { 14831da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 14841da177e4SLinus Torvalds hda_nid_t nid = kcontrol->private_value; 14851da177e4SLinus Torvalds unsigned short val; 14861da177e4SLinus Torvalds int change; 14871da177e4SLinus Torvalds 148862932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 14890ba21762STakashi Iwai val = codec->spdif_ctls & ~AC_DIG1_ENABLE; 14901da177e4SLinus Torvalds if (ucontrol->value.integer.value[0]) 14910ba21762STakashi Iwai val |= AC_DIG1_ENABLE; 14921da177e4SLinus Torvalds change = codec->spdif_ctls != val; 149382beb8fdSTakashi Iwai if (change) { 14941da177e4SLinus Torvalds codec->spdif_ctls = val; 149582beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 149682beb8fdSTakashi Iwai AC_VERB_SET_DIGI_CONVERT_1, 14976b97eb45STakashi Iwai val & 0xff); 14980ba21762STakashi Iwai /* unmute amp switch (if any) */ 14990ba21762STakashi Iwai if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && 150047fd830aSTakashi Iwai (val & AC_DIG1_ENABLE)) 150147fd830aSTakashi Iwai snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, 150247fd830aSTakashi Iwai HDA_AMP_MUTE, 0); 15031da177e4SLinus Torvalds } 150462932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 15051da177e4SLinus Torvalds return change; 15061da177e4SLinus Torvalds } 15071da177e4SLinus Torvalds 1508c8b6bf9bSTakashi Iwai static struct snd_kcontrol_new dig_mixes[] = { 15091da177e4SLinus Torvalds { 15101da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 15111da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15121da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), 15131da177e4SLinus Torvalds .info = snd_hda_spdif_mask_info, 15141da177e4SLinus Torvalds .get = snd_hda_spdif_cmask_get, 15151da177e4SLinus Torvalds }, 15161da177e4SLinus Torvalds { 15171da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 15181da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15191da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), 15201da177e4SLinus Torvalds .info = snd_hda_spdif_mask_info, 15211da177e4SLinus Torvalds .get = snd_hda_spdif_pmask_get, 15221da177e4SLinus Torvalds }, 15231da177e4SLinus Torvalds { 15241da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15251da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 15261da177e4SLinus Torvalds .info = snd_hda_spdif_mask_info, 15271da177e4SLinus Torvalds .get = snd_hda_spdif_default_get, 15281da177e4SLinus Torvalds .put = snd_hda_spdif_default_put, 15291da177e4SLinus Torvalds }, 15301da177e4SLinus Torvalds { 15311da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15321da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 15331da177e4SLinus Torvalds .info = snd_hda_spdif_out_switch_info, 15341da177e4SLinus Torvalds .get = snd_hda_spdif_out_switch_get, 15351da177e4SLinus Torvalds .put = snd_hda_spdif_out_switch_put, 15361da177e4SLinus Torvalds }, 15371da177e4SLinus Torvalds { } /* end */ 15381da177e4SLinus Torvalds }; 15391da177e4SLinus Torvalds 154009f99701STakashi Iwai #define SPDIF_MAX_IDX 4 /* 4 instances should be enough to probe */ 154109f99701STakashi Iwai 15421da177e4SLinus Torvalds /** 15431da177e4SLinus Torvalds * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls 15441da177e4SLinus Torvalds * @codec: the HDA codec 15451da177e4SLinus Torvalds * @nid: audio out widget NID 15461da177e4SLinus Torvalds * 15471da177e4SLinus Torvalds * Creates controls related with the SPDIF output. 15481da177e4SLinus Torvalds * Called from each patch supporting the SPDIF out. 15491da177e4SLinus Torvalds * 15501da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 15511da177e4SLinus Torvalds */ 155212f288bfSTakashi Iwai int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) 15531da177e4SLinus Torvalds { 15541da177e4SLinus Torvalds int err; 1555c8b6bf9bSTakashi Iwai struct snd_kcontrol *kctl; 1556c8b6bf9bSTakashi Iwai struct snd_kcontrol_new *dig_mix; 155709f99701STakashi Iwai int idx; 15581da177e4SLinus Torvalds 155909f99701STakashi Iwai for (idx = 0; idx < SPDIF_MAX_IDX; idx++) { 156009f99701STakashi Iwai if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch", 156109f99701STakashi Iwai idx)) 156209f99701STakashi Iwai break; 156309f99701STakashi Iwai } 156409f99701STakashi Iwai if (idx >= SPDIF_MAX_IDX) { 156509f99701STakashi Iwai printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); 156609f99701STakashi Iwai return -EBUSY; 156709f99701STakashi Iwai } 15681da177e4SLinus Torvalds for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { 15691da177e4SLinus Torvalds kctl = snd_ctl_new1(dig_mix, codec); 157009f99701STakashi Iwai kctl->id.index = idx; 15711da177e4SLinus Torvalds kctl->private_value = nid; 15720ba21762STakashi Iwai err = snd_ctl_add(codec->bus->card, kctl); 15730ba21762STakashi Iwai if (err < 0) 15741da177e4SLinus Torvalds return err; 15751da177e4SLinus Torvalds } 15760ba21762STakashi Iwai codec->spdif_ctls = 15773982d17eSAndrew Paprocki snd_hda_codec_read(codec, nid, 0, 15783982d17eSAndrew Paprocki AC_VERB_GET_DIGI_CONVERT_1, 0); 15791da177e4SLinus Torvalds codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); 15801da177e4SLinus Torvalds return 0; 15811da177e4SLinus Torvalds } 15821da177e4SLinus Torvalds 15831da177e4SLinus Torvalds /* 15849a08160bSTakashi Iwai * SPDIF sharing with analog output 15859a08160bSTakashi Iwai */ 15869a08160bSTakashi Iwai static int spdif_share_sw_get(struct snd_kcontrol *kcontrol, 15879a08160bSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 15889a08160bSTakashi Iwai { 15899a08160bSTakashi Iwai struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol); 15909a08160bSTakashi Iwai ucontrol->value.integer.value[0] = mout->share_spdif; 15919a08160bSTakashi Iwai return 0; 15929a08160bSTakashi Iwai } 15939a08160bSTakashi Iwai 15949a08160bSTakashi Iwai static int spdif_share_sw_put(struct snd_kcontrol *kcontrol, 15959a08160bSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 15969a08160bSTakashi Iwai { 15979a08160bSTakashi Iwai struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol); 15989a08160bSTakashi Iwai mout->share_spdif = !!ucontrol->value.integer.value[0]; 15999a08160bSTakashi Iwai return 0; 16009a08160bSTakashi Iwai } 16019a08160bSTakashi Iwai 16029a08160bSTakashi Iwai static struct snd_kcontrol_new spdif_share_sw = { 16039a08160bSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16049a08160bSTakashi Iwai .name = "IEC958 Default PCM Playback Switch", 16059a08160bSTakashi Iwai .info = snd_ctl_boolean_mono_info, 16069a08160bSTakashi Iwai .get = spdif_share_sw_get, 16079a08160bSTakashi Iwai .put = spdif_share_sw_put, 16089a08160bSTakashi Iwai }; 16099a08160bSTakashi Iwai 16109a08160bSTakashi Iwai int snd_hda_create_spdif_share_sw(struct hda_codec *codec, 16119a08160bSTakashi Iwai struct hda_multi_out *mout) 16129a08160bSTakashi Iwai { 16139a08160bSTakashi Iwai if (!mout->dig_out_nid) 16149a08160bSTakashi Iwai return 0; 16159a08160bSTakashi Iwai /* ATTENTION: here mout is passed as private_data, instead of codec */ 16169a08160bSTakashi Iwai return snd_ctl_add(codec->bus->card, 16179a08160bSTakashi Iwai snd_ctl_new1(&spdif_share_sw, mout)); 16189a08160bSTakashi Iwai } 16199a08160bSTakashi Iwai 16209a08160bSTakashi Iwai /* 16211da177e4SLinus Torvalds * SPDIF input 16221da177e4SLinus Torvalds */ 16231da177e4SLinus Torvalds 16241da177e4SLinus Torvalds #define snd_hda_spdif_in_switch_info snd_hda_spdif_out_switch_info 16251da177e4SLinus Torvalds 16260ba21762STakashi Iwai static int snd_hda_spdif_in_switch_get(struct snd_kcontrol *kcontrol, 16270ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16281da177e4SLinus Torvalds { 16291da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 16301da177e4SLinus Torvalds 16311da177e4SLinus Torvalds ucontrol->value.integer.value[0] = codec->spdif_in_enable; 16321da177e4SLinus Torvalds return 0; 16331da177e4SLinus Torvalds } 16341da177e4SLinus Torvalds 16350ba21762STakashi Iwai static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, 16360ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16371da177e4SLinus Torvalds { 16381da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 16391da177e4SLinus Torvalds hda_nid_t nid = kcontrol->private_value; 16401da177e4SLinus Torvalds unsigned int val = !!ucontrol->value.integer.value[0]; 16411da177e4SLinus Torvalds int change; 16421da177e4SLinus Torvalds 164362932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 16441da177e4SLinus Torvalds change = codec->spdif_in_enable != val; 164582beb8fdSTakashi Iwai if (change) { 16461da177e4SLinus Torvalds codec->spdif_in_enable = val; 164782beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 164882beb8fdSTakashi Iwai AC_VERB_SET_DIGI_CONVERT_1, val); 16491da177e4SLinus Torvalds } 165062932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 16511da177e4SLinus Torvalds return change; 16521da177e4SLinus Torvalds } 16531da177e4SLinus Torvalds 16540ba21762STakashi Iwai static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol, 16550ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16561da177e4SLinus Torvalds { 16571da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 16581da177e4SLinus Torvalds hda_nid_t nid = kcontrol->private_value; 16591da177e4SLinus Torvalds unsigned short val; 16601da177e4SLinus Torvalds unsigned int sbits; 16611da177e4SLinus Torvalds 16623982d17eSAndrew Paprocki val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); 16631da177e4SLinus Torvalds sbits = convert_to_spdif_status(val); 16641da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = sbits; 16651da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = sbits >> 8; 16661da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = sbits >> 16; 16671da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = sbits >> 24; 16681da177e4SLinus Torvalds return 0; 16691da177e4SLinus Torvalds } 16701da177e4SLinus Torvalds 1671c8b6bf9bSTakashi Iwai static struct snd_kcontrol_new dig_in_ctls[] = { 16721da177e4SLinus Torvalds { 16731da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16741da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 16751da177e4SLinus Torvalds .info = snd_hda_spdif_in_switch_info, 16761da177e4SLinus Torvalds .get = snd_hda_spdif_in_switch_get, 16771da177e4SLinus Torvalds .put = snd_hda_spdif_in_switch_put, 16781da177e4SLinus Torvalds }, 16791da177e4SLinus Torvalds { 16801da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 16811da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16821da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), 16831da177e4SLinus Torvalds .info = snd_hda_spdif_mask_info, 16841da177e4SLinus Torvalds .get = snd_hda_spdif_in_status_get, 16851da177e4SLinus Torvalds }, 16861da177e4SLinus Torvalds { } /* end */ 16871da177e4SLinus Torvalds }; 16881da177e4SLinus Torvalds 16891da177e4SLinus Torvalds /** 16901da177e4SLinus Torvalds * snd_hda_create_spdif_in_ctls - create Input SPDIF-related controls 16911da177e4SLinus Torvalds * @codec: the HDA codec 16921da177e4SLinus Torvalds * @nid: audio in widget NID 16931da177e4SLinus Torvalds * 16941da177e4SLinus Torvalds * Creates controls related with the SPDIF input. 16951da177e4SLinus Torvalds * Called from each patch supporting the SPDIF in. 16961da177e4SLinus Torvalds * 16971da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 16981da177e4SLinus Torvalds */ 169912f288bfSTakashi Iwai int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) 17001da177e4SLinus Torvalds { 17011da177e4SLinus Torvalds int err; 1702c8b6bf9bSTakashi Iwai struct snd_kcontrol *kctl; 1703c8b6bf9bSTakashi Iwai struct snd_kcontrol_new *dig_mix; 170409f99701STakashi Iwai int idx; 17051da177e4SLinus Torvalds 170609f99701STakashi Iwai for (idx = 0; idx < SPDIF_MAX_IDX; idx++) { 170709f99701STakashi Iwai if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Capture Switch", 170809f99701STakashi Iwai idx)) 170909f99701STakashi Iwai break; 171009f99701STakashi Iwai } 171109f99701STakashi Iwai if (idx >= SPDIF_MAX_IDX) { 171209f99701STakashi Iwai printk(KERN_ERR "hda_codec: too many IEC958 inputs\n"); 171309f99701STakashi Iwai return -EBUSY; 171409f99701STakashi Iwai } 17151da177e4SLinus Torvalds for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { 17161da177e4SLinus Torvalds kctl = snd_ctl_new1(dig_mix, codec); 17171da177e4SLinus Torvalds kctl->private_value = nid; 17180ba21762STakashi Iwai err = snd_ctl_add(codec->bus->card, kctl); 17190ba21762STakashi Iwai if (err < 0) 17201da177e4SLinus Torvalds return err; 17211da177e4SLinus Torvalds } 17220ba21762STakashi Iwai codec->spdif_in_enable = 17233982d17eSAndrew Paprocki snd_hda_codec_read(codec, nid, 0, 17243982d17eSAndrew Paprocki AC_VERB_GET_DIGI_CONVERT_1, 0) & 17250ba21762STakashi Iwai AC_DIG1_ENABLE; 17261da177e4SLinus Torvalds return 0; 17271da177e4SLinus Torvalds } 17281da177e4SLinus Torvalds 1729cb53c626STakashi Iwai #ifdef SND_HDA_NEEDS_RESUME 173082beb8fdSTakashi Iwai /* 173182beb8fdSTakashi Iwai * command cache 173282beb8fdSTakashi Iwai */ 17331da177e4SLinus Torvalds 1734b3ac5636STakashi Iwai /* build a 32bit cache key with the widget id and the command parameter */ 1735b3ac5636STakashi Iwai #define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) 1736b3ac5636STakashi Iwai #define get_cmd_cache_nid(key) ((key) & 0xff) 1737b3ac5636STakashi Iwai #define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) 1738b3ac5636STakashi Iwai 1739b3ac5636STakashi Iwai /** 1740b3ac5636STakashi Iwai * snd_hda_codec_write_cache - send a single command with caching 1741b3ac5636STakashi Iwai * @codec: the HDA codec 1742b3ac5636STakashi Iwai * @nid: NID to send the command 1743b3ac5636STakashi Iwai * @direct: direct flag 1744b3ac5636STakashi Iwai * @verb: the verb to send 1745b3ac5636STakashi Iwai * @parm: the parameter for the verb 1746b3ac5636STakashi Iwai * 1747b3ac5636STakashi Iwai * Send a single command without waiting for response. 1748b3ac5636STakashi Iwai * 1749b3ac5636STakashi Iwai * Returns 0 if successful, or a negative error code. 1750b3ac5636STakashi Iwai */ 1751b3ac5636STakashi Iwai int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, 1752b3ac5636STakashi Iwai int direct, unsigned int verb, unsigned int parm) 1753b3ac5636STakashi Iwai { 1754b3ac5636STakashi Iwai int err; 1755cb53c626STakashi Iwai snd_hda_power_up(codec); 1756b3ac5636STakashi Iwai mutex_lock(&codec->bus->cmd_mutex); 1757b3ac5636STakashi Iwai err = codec->bus->ops.command(codec, nid, direct, verb, parm); 1758b3ac5636STakashi Iwai if (!err) { 1759b3ac5636STakashi Iwai struct hda_cache_head *c; 1760b3ac5636STakashi Iwai u32 key = build_cmd_cache_key(nid, verb); 1761b3ac5636STakashi Iwai c = get_alloc_hash(&codec->cmd_cache, key); 1762b3ac5636STakashi Iwai if (c) 1763b3ac5636STakashi Iwai c->val = parm; 1764b3ac5636STakashi Iwai } 1765b3ac5636STakashi Iwai mutex_unlock(&codec->bus->cmd_mutex); 1766cb53c626STakashi Iwai snd_hda_power_down(codec); 1767b3ac5636STakashi Iwai return err; 1768b3ac5636STakashi Iwai } 1769b3ac5636STakashi Iwai 1770b3ac5636STakashi Iwai /* resume the all commands from the cache */ 1771b3ac5636STakashi Iwai void snd_hda_codec_resume_cache(struct hda_codec *codec) 1772b3ac5636STakashi Iwai { 1773b3ac5636STakashi Iwai struct hda_cache_head *buffer = codec->cmd_cache.buffer; 1774b3ac5636STakashi Iwai int i; 1775b3ac5636STakashi Iwai 1776b3ac5636STakashi Iwai for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { 1777b3ac5636STakashi Iwai u32 key = buffer->key; 1778b3ac5636STakashi Iwai if (!key) 1779b3ac5636STakashi Iwai continue; 1780b3ac5636STakashi Iwai snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, 1781b3ac5636STakashi Iwai get_cmd_cache_cmd(key), buffer->val); 1782b3ac5636STakashi Iwai } 1783b3ac5636STakashi Iwai } 1784b3ac5636STakashi Iwai 1785b3ac5636STakashi Iwai /** 1786b3ac5636STakashi Iwai * snd_hda_sequence_write_cache - sequence writes with caching 1787b3ac5636STakashi Iwai * @codec: the HDA codec 1788b3ac5636STakashi Iwai * @seq: VERB array to send 1789b3ac5636STakashi Iwai * 1790b3ac5636STakashi Iwai * Send the commands sequentially from the given array. 1791b3ac5636STakashi Iwai * Thte commands are recorded on cache for power-save and resume. 1792b3ac5636STakashi Iwai * The array must be terminated with NID=0. 1793b3ac5636STakashi Iwai */ 1794b3ac5636STakashi Iwai void snd_hda_sequence_write_cache(struct hda_codec *codec, 1795b3ac5636STakashi Iwai const struct hda_verb *seq) 1796b3ac5636STakashi Iwai { 1797b3ac5636STakashi Iwai for (; seq->nid; seq++) 1798b3ac5636STakashi Iwai snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, 1799b3ac5636STakashi Iwai seq->param); 1800b3ac5636STakashi Iwai } 1801cb53c626STakashi Iwai #endif /* SND_HDA_NEEDS_RESUME */ 1802b3ac5636STakashi Iwai 180354d17403STakashi Iwai /* 180454d17403STakashi Iwai * set power state of the codec 180554d17403STakashi Iwai */ 180654d17403STakashi Iwai static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, 180754d17403STakashi Iwai unsigned int power_state) 180854d17403STakashi Iwai { 1809cb53c626STakashi Iwai hda_nid_t nid; 1810cb53c626STakashi Iwai int i; 181154d17403STakashi Iwai 181254d17403STakashi Iwai snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, 181354d17403STakashi Iwai power_state); 1814d2595d86SMarc Boucher msleep(10); /* partial workaround for "azx_get_response timeout" */ 181554d17403STakashi Iwai 1816cb53c626STakashi Iwai nid = codec->start_nid; 1817cb53c626STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 18187eba5c9dSTakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 18197eba5c9dSTakashi Iwai if (wcaps & AC_WCAP_POWER) { 18207eba5c9dSTakashi Iwai unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> 18217eba5c9dSTakashi Iwai AC_WCAP_TYPE_SHIFT; 18227eba5c9dSTakashi Iwai if (wid_type == AC_WID_PIN) { 18231194b5b7STakashi Iwai unsigned int pincap; 18241194b5b7STakashi Iwai /* 18257eba5c9dSTakashi Iwai * don't power down the widget if it controls 18267eba5c9dSTakashi Iwai * eapd and EAPD_BTLENABLE is set. 18271194b5b7STakashi Iwai */ 18287eba5c9dSTakashi Iwai pincap = snd_hda_param_read(codec, nid, 18297eba5c9dSTakashi Iwai AC_PAR_PIN_CAP); 18301194b5b7STakashi Iwai if (pincap & AC_PINCAP_EAPD) { 18317eba5c9dSTakashi Iwai int eapd = snd_hda_codec_read(codec, 18327eba5c9dSTakashi Iwai nid, 0, 18337eba5c9dSTakashi Iwai AC_VERB_GET_EAPD_BTLENABLE, 0); 18341194b5b7STakashi Iwai eapd &= 0x02; 18351194b5b7STakashi Iwai if (power_state == AC_PWRST_D3 && eapd) 18361194b5b7STakashi Iwai continue; 18371194b5b7STakashi Iwai } 18387eba5c9dSTakashi Iwai } 183954d17403STakashi Iwai snd_hda_codec_write(codec, nid, 0, 184054d17403STakashi Iwai AC_VERB_SET_POWER_STATE, 184154d17403STakashi Iwai power_state); 184254d17403STakashi Iwai } 18431194b5b7STakashi Iwai } 184454d17403STakashi Iwai 1845cb53c626STakashi Iwai if (power_state == AC_PWRST_D0) { 1846cb53c626STakashi Iwai unsigned long end_time; 1847cb53c626STakashi Iwai int state; 184854d17403STakashi Iwai msleep(10); 1849cb53c626STakashi Iwai /* wait until the codec reachs to D0 */ 1850cb53c626STakashi Iwai end_time = jiffies + msecs_to_jiffies(500); 1851cb53c626STakashi Iwai do { 1852cb53c626STakashi Iwai state = snd_hda_codec_read(codec, fg, 0, 1853cb53c626STakashi Iwai AC_VERB_GET_POWER_STATE, 0); 1854cb53c626STakashi Iwai if (state == power_state) 1855cb53c626STakashi Iwai break; 1856cb53c626STakashi Iwai msleep(1); 1857cb53c626STakashi Iwai } while (time_after_eq(end_time, jiffies)); 185854d17403STakashi Iwai } 1859cb53c626STakashi Iwai } 1860cb53c626STakashi Iwai 1861cb53c626STakashi Iwai #ifdef SND_HDA_NEEDS_RESUME 1862cb53c626STakashi Iwai /* 1863cb53c626STakashi Iwai * call suspend and power-down; used both from PM and power-save 1864cb53c626STakashi Iwai */ 1865cb53c626STakashi Iwai static void hda_call_codec_suspend(struct hda_codec *codec) 1866cb53c626STakashi Iwai { 1867cb53c626STakashi Iwai if (codec->patch_ops.suspend) 1868cb53c626STakashi Iwai codec->patch_ops.suspend(codec, PMSG_SUSPEND); 1869cb53c626STakashi Iwai hda_set_power_state(codec, 1870cb53c626STakashi Iwai codec->afg ? codec->afg : codec->mfg, 1871cb53c626STakashi Iwai AC_PWRST_D3); 1872cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 1873cb53c626STakashi Iwai cancel_delayed_work(&codec->power_work); 187495e99fdaSTakashi Iwai codec->power_on = 0; 1875a221e287STakashi Iwai codec->power_transition = 0; 1876cb53c626STakashi Iwai #endif 1877cb53c626STakashi Iwai } 1878cb53c626STakashi Iwai 1879cb53c626STakashi Iwai /* 1880cb53c626STakashi Iwai * kick up codec; used both from PM and power-save 1881cb53c626STakashi Iwai */ 1882cb53c626STakashi Iwai static void hda_call_codec_resume(struct hda_codec *codec) 1883cb53c626STakashi Iwai { 1884cb53c626STakashi Iwai hda_set_power_state(codec, 1885cb53c626STakashi Iwai codec->afg ? codec->afg : codec->mfg, 1886cb53c626STakashi Iwai AC_PWRST_D0); 1887cb53c626STakashi Iwai if (codec->patch_ops.resume) 1888cb53c626STakashi Iwai codec->patch_ops.resume(codec); 1889cb53c626STakashi Iwai else { 18909d99f312STakashi Iwai if (codec->patch_ops.init) 1891cb53c626STakashi Iwai codec->patch_ops.init(codec); 1892cb53c626STakashi Iwai snd_hda_codec_resume_amp(codec); 1893cb53c626STakashi Iwai snd_hda_codec_resume_cache(codec); 1894cb53c626STakashi Iwai } 1895cb53c626STakashi Iwai } 1896cb53c626STakashi Iwai #endif /* SND_HDA_NEEDS_RESUME */ 189754d17403STakashi Iwai 189854d17403STakashi Iwai 18991da177e4SLinus Torvalds /** 19001da177e4SLinus Torvalds * snd_hda_build_controls - build mixer controls 19011da177e4SLinus Torvalds * @bus: the BUS 19021da177e4SLinus Torvalds * 19031da177e4SLinus Torvalds * Creates mixer controls for each codec included in the bus. 19041da177e4SLinus Torvalds * 19051da177e4SLinus Torvalds * Returns 0 if successful, otherwise a negative error code. 19061da177e4SLinus Torvalds */ 1907756e2b01STakashi Iwai int __devinit snd_hda_build_controls(struct hda_bus *bus) 19081da177e4SLinus Torvalds { 19090ba21762STakashi Iwai struct hda_codec *codec; 19101da177e4SLinus Torvalds 19110ba21762STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 1912cb53c626STakashi Iwai int err = 0; 1913cb53c626STakashi Iwai /* fake as if already powered-on */ 1914cb53c626STakashi Iwai hda_keep_power_on(codec); 1915cb53c626STakashi Iwai /* then fire up */ 1916cb53c626STakashi Iwai hda_set_power_state(codec, 1917cb53c626STakashi Iwai codec->afg ? codec->afg : codec->mfg, 1918cb53c626STakashi Iwai AC_PWRST_D0); 1919cb53c626STakashi Iwai /* continue to initialize... */ 1920cb53c626STakashi Iwai if (codec->patch_ops.init) 1921cb53c626STakashi Iwai err = codec->patch_ops.init(codec); 1922cb53c626STakashi Iwai if (!err && codec->patch_ops.build_controls) 19231da177e4SLinus Torvalds err = codec->patch_ops.build_controls(codec); 1924cb53c626STakashi Iwai snd_hda_power_down(codec); 19251da177e4SLinus Torvalds if (err < 0) 19261da177e4SLinus Torvalds return err; 19271da177e4SLinus Torvalds } 19281da177e4SLinus Torvalds 19291da177e4SLinus Torvalds return 0; 19301da177e4SLinus Torvalds } 19311da177e4SLinus Torvalds 19321da177e4SLinus Torvalds /* 19331da177e4SLinus Torvalds * stream formats 19341da177e4SLinus Torvalds */ 1935befdf316STakashi Iwai struct hda_rate_tbl { 1936befdf316STakashi Iwai unsigned int hz; 1937befdf316STakashi Iwai unsigned int alsa_bits; 1938befdf316STakashi Iwai unsigned int hda_fmt; 1939befdf316STakashi Iwai }; 1940befdf316STakashi Iwai 1941befdf316STakashi Iwai static struct hda_rate_tbl rate_bits[] = { 19421da177e4SLinus Torvalds /* rate in Hz, ALSA rate bitmask, HDA format value */ 19439d8f53f2SNicolas Graziano 19449d8f53f2SNicolas Graziano /* autodetected value used in snd_hda_query_supported_pcm */ 19451da177e4SLinus Torvalds { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */ 19461da177e4SLinus Torvalds { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */ 19471da177e4SLinus Torvalds { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */ 19481da177e4SLinus Torvalds { 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */ 19491da177e4SLinus Torvalds { 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */ 19501da177e4SLinus Torvalds { 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */ 19511da177e4SLinus Torvalds { 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */ 19521da177e4SLinus Torvalds { 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */ 19531da177e4SLinus Torvalds { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */ 19541da177e4SLinus Torvalds { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */ 19551da177e4SLinus Torvalds { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */ 1956a961f9feSTakashi Iwai #define AC_PAR_PCM_RATE_BITS 11 1957a961f9feSTakashi Iwai /* up to bits 10, 384kHZ isn't supported properly */ 1958a961f9feSTakashi Iwai 1959a961f9feSTakashi Iwai /* not autodetected value */ 1960a961f9feSTakashi Iwai { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */ 19619d8f53f2SNicolas Graziano 1962befdf316STakashi Iwai { 0 } /* terminator */ 19631da177e4SLinus Torvalds }; 19641da177e4SLinus Torvalds 19651da177e4SLinus Torvalds /** 19661da177e4SLinus Torvalds * snd_hda_calc_stream_format - calculate format bitset 19671da177e4SLinus Torvalds * @rate: the sample rate 19681da177e4SLinus Torvalds * @channels: the number of channels 19691da177e4SLinus Torvalds * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) 19701da177e4SLinus Torvalds * @maxbps: the max. bps 19711da177e4SLinus Torvalds * 19721da177e4SLinus Torvalds * Calculate the format bitset from the given rate, channels and th PCM format. 19731da177e4SLinus Torvalds * 19741da177e4SLinus Torvalds * Return zero if invalid. 19751da177e4SLinus Torvalds */ 19761da177e4SLinus Torvalds unsigned int snd_hda_calc_stream_format(unsigned int rate, 19771da177e4SLinus Torvalds unsigned int channels, 19781da177e4SLinus Torvalds unsigned int format, 19791da177e4SLinus Torvalds unsigned int maxbps) 19801da177e4SLinus Torvalds { 19811da177e4SLinus Torvalds int i; 19821da177e4SLinus Torvalds unsigned int val = 0; 19831da177e4SLinus Torvalds 1984befdf316STakashi Iwai for (i = 0; rate_bits[i].hz; i++) 1985befdf316STakashi Iwai if (rate_bits[i].hz == rate) { 1986befdf316STakashi Iwai val = rate_bits[i].hda_fmt; 19871da177e4SLinus Torvalds break; 19881da177e4SLinus Torvalds } 1989befdf316STakashi Iwai if (!rate_bits[i].hz) { 19901da177e4SLinus Torvalds snd_printdd("invalid rate %d\n", rate); 19911da177e4SLinus Torvalds return 0; 19921da177e4SLinus Torvalds } 19931da177e4SLinus Torvalds 19941da177e4SLinus Torvalds if (channels == 0 || channels > 8) { 19951da177e4SLinus Torvalds snd_printdd("invalid channels %d\n", channels); 19961da177e4SLinus Torvalds return 0; 19971da177e4SLinus Torvalds } 19981da177e4SLinus Torvalds val |= channels - 1; 19991da177e4SLinus Torvalds 20001da177e4SLinus Torvalds switch (snd_pcm_format_width(format)) { 20011da177e4SLinus Torvalds case 8: val |= 0x00; break; 20021da177e4SLinus Torvalds case 16: val |= 0x10; break; 20031da177e4SLinus Torvalds case 20: 20041da177e4SLinus Torvalds case 24: 20051da177e4SLinus Torvalds case 32: 20061da177e4SLinus Torvalds if (maxbps >= 32) 20071da177e4SLinus Torvalds val |= 0x40; 20081da177e4SLinus Torvalds else if (maxbps >= 24) 20091da177e4SLinus Torvalds val |= 0x30; 20101da177e4SLinus Torvalds else 20111da177e4SLinus Torvalds val |= 0x20; 20121da177e4SLinus Torvalds break; 20131da177e4SLinus Torvalds default: 20140ba21762STakashi Iwai snd_printdd("invalid format width %d\n", 20150ba21762STakashi Iwai snd_pcm_format_width(format)); 20161da177e4SLinus Torvalds return 0; 20171da177e4SLinus Torvalds } 20181da177e4SLinus Torvalds 20191da177e4SLinus Torvalds return val; 20201da177e4SLinus Torvalds } 20211da177e4SLinus Torvalds 20221da177e4SLinus Torvalds /** 20231da177e4SLinus Torvalds * snd_hda_query_supported_pcm - query the supported PCM rates and formats 20241da177e4SLinus Torvalds * @codec: the HDA codec 20251da177e4SLinus Torvalds * @nid: NID to query 20261da177e4SLinus Torvalds * @ratesp: the pointer to store the detected rate bitflags 20271da177e4SLinus Torvalds * @formatsp: the pointer to store the detected formats 20281da177e4SLinus Torvalds * @bpsp: the pointer to store the detected format widths 20291da177e4SLinus Torvalds * 20301da177e4SLinus Torvalds * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp 20311da177e4SLinus Torvalds * or @bsps argument is ignored. 20321da177e4SLinus Torvalds * 20331da177e4SLinus Torvalds * Returns 0 if successful, otherwise a negative error code. 20341da177e4SLinus Torvalds */ 20351da177e4SLinus Torvalds int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, 20361da177e4SLinus Torvalds u32 *ratesp, u64 *formatsp, unsigned int *bpsp) 20371da177e4SLinus Torvalds { 20381da177e4SLinus Torvalds int i; 20391da177e4SLinus Torvalds unsigned int val, streams; 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds val = 0; 20421da177e4SLinus Torvalds if (nid != codec->afg && 204354d17403STakashi Iwai (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { 20441da177e4SLinus Torvalds val = snd_hda_param_read(codec, nid, AC_PAR_PCM); 20451da177e4SLinus Torvalds if (val == -1) 20461da177e4SLinus Torvalds return -EIO; 20471da177e4SLinus Torvalds } 20481da177e4SLinus Torvalds if (!val) 20491da177e4SLinus Torvalds val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); 20501da177e4SLinus Torvalds 20511da177e4SLinus Torvalds if (ratesp) { 20521da177e4SLinus Torvalds u32 rates = 0; 2053a961f9feSTakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { 20541da177e4SLinus Torvalds if (val & (1 << i)) 2055befdf316STakashi Iwai rates |= rate_bits[i].alsa_bits; 20561da177e4SLinus Torvalds } 20571da177e4SLinus Torvalds *ratesp = rates; 20581da177e4SLinus Torvalds } 20591da177e4SLinus Torvalds 20601da177e4SLinus Torvalds if (formatsp || bpsp) { 20611da177e4SLinus Torvalds u64 formats = 0; 20621da177e4SLinus Torvalds unsigned int bps; 20631da177e4SLinus Torvalds unsigned int wcaps; 20641da177e4SLinus Torvalds 206554d17403STakashi Iwai wcaps = get_wcaps(codec, nid); 20661da177e4SLinus Torvalds streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); 20671da177e4SLinus Torvalds if (streams == -1) 20681da177e4SLinus Torvalds return -EIO; 20691da177e4SLinus Torvalds if (!streams) { 20700ba21762STakashi Iwai streams = snd_hda_param_read(codec, codec->afg, 20710ba21762STakashi Iwai AC_PAR_STREAM); 20721da177e4SLinus Torvalds if (streams == -1) 20731da177e4SLinus Torvalds return -EIO; 20741da177e4SLinus Torvalds } 20751da177e4SLinus Torvalds 20761da177e4SLinus Torvalds bps = 0; 20771da177e4SLinus Torvalds if (streams & AC_SUPFMT_PCM) { 20781da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_8) { 20791da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_U8; 20801da177e4SLinus Torvalds bps = 8; 20811da177e4SLinus Torvalds } 20821da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_16) { 20831da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_S16_LE; 20841da177e4SLinus Torvalds bps = 16; 20851da177e4SLinus Torvalds } 20861da177e4SLinus Torvalds if (wcaps & AC_WCAP_DIGITAL) { 20871da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_32) 20881da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; 20891da177e4SLinus Torvalds if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) 20901da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_S32_LE; 20911da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_24) 20921da177e4SLinus Torvalds bps = 24; 20931da177e4SLinus Torvalds else if (val & AC_SUPPCM_BITS_20) 20941da177e4SLinus Torvalds bps = 20; 20950ba21762STakashi Iwai } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24| 20960ba21762STakashi Iwai AC_SUPPCM_BITS_32)) { 20971da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_S32_LE; 20981da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_32) 20991da177e4SLinus Torvalds bps = 32; 21001da177e4SLinus Torvalds else if (val & AC_SUPPCM_BITS_24) 21011da177e4SLinus Torvalds bps = 24; 210233ef7651SNicolas Graziano else if (val & AC_SUPPCM_BITS_20) 210333ef7651SNicolas Graziano bps = 20; 21041da177e4SLinus Torvalds } 21051da177e4SLinus Torvalds } 21060ba21762STakashi Iwai else if (streams == AC_SUPFMT_FLOAT32) { 21070ba21762STakashi Iwai /* should be exclusive */ 21081da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; 21091da177e4SLinus Torvalds bps = 32; 21100ba21762STakashi Iwai } else if (streams == AC_SUPFMT_AC3) { 21110ba21762STakashi Iwai /* should be exclusive */ 21121da177e4SLinus Torvalds /* temporary hack: we have still no proper support 21131da177e4SLinus Torvalds * for the direct AC3 stream... 21141da177e4SLinus Torvalds */ 21151da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_U8; 21161da177e4SLinus Torvalds bps = 8; 21171da177e4SLinus Torvalds } 21181da177e4SLinus Torvalds if (formatsp) 21191da177e4SLinus Torvalds *formatsp = formats; 21201da177e4SLinus Torvalds if (bpsp) 21211da177e4SLinus Torvalds *bpsp = bps; 21221da177e4SLinus Torvalds } 21231da177e4SLinus Torvalds 21241da177e4SLinus Torvalds return 0; 21251da177e4SLinus Torvalds } 21261da177e4SLinus Torvalds 21271da177e4SLinus Torvalds /** 21280ba21762STakashi Iwai * snd_hda_is_supported_format - check whether the given node supports 21290ba21762STakashi Iwai * the format val 21301da177e4SLinus Torvalds * 21311da177e4SLinus Torvalds * Returns 1 if supported, 0 if not. 21321da177e4SLinus Torvalds */ 21331da177e4SLinus Torvalds int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, 21341da177e4SLinus Torvalds unsigned int format) 21351da177e4SLinus Torvalds { 21361da177e4SLinus Torvalds int i; 21371da177e4SLinus Torvalds unsigned int val = 0, rate, stream; 21381da177e4SLinus Torvalds 21391da177e4SLinus Torvalds if (nid != codec->afg && 214054d17403STakashi Iwai (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { 21411da177e4SLinus Torvalds val = snd_hda_param_read(codec, nid, AC_PAR_PCM); 21421da177e4SLinus Torvalds if (val == -1) 21431da177e4SLinus Torvalds return 0; 21441da177e4SLinus Torvalds } 21451da177e4SLinus Torvalds if (!val) { 21461da177e4SLinus Torvalds val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); 21471da177e4SLinus Torvalds if (val == -1) 21481da177e4SLinus Torvalds return 0; 21491da177e4SLinus Torvalds } 21501da177e4SLinus Torvalds 21511da177e4SLinus Torvalds rate = format & 0xff00; 2152a961f9feSTakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) 2153befdf316STakashi Iwai if (rate_bits[i].hda_fmt == rate) { 21541da177e4SLinus Torvalds if (val & (1 << i)) 21551da177e4SLinus Torvalds break; 21561da177e4SLinus Torvalds return 0; 21571da177e4SLinus Torvalds } 2158a961f9feSTakashi Iwai if (i >= AC_PAR_PCM_RATE_BITS) 21591da177e4SLinus Torvalds return 0; 21601da177e4SLinus Torvalds 21611da177e4SLinus Torvalds stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); 21621da177e4SLinus Torvalds if (stream == -1) 21631da177e4SLinus Torvalds return 0; 21641da177e4SLinus Torvalds if (!stream && nid != codec->afg) 21651da177e4SLinus Torvalds stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); 21661da177e4SLinus Torvalds if (!stream || stream == -1) 21671da177e4SLinus Torvalds return 0; 21681da177e4SLinus Torvalds 21691da177e4SLinus Torvalds if (stream & AC_SUPFMT_PCM) { 21701da177e4SLinus Torvalds switch (format & 0xf0) { 21711da177e4SLinus Torvalds case 0x00: 21721da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_8)) 21731da177e4SLinus Torvalds return 0; 21741da177e4SLinus Torvalds break; 21751da177e4SLinus Torvalds case 0x10: 21761da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_16)) 21771da177e4SLinus Torvalds return 0; 21781da177e4SLinus Torvalds break; 21791da177e4SLinus Torvalds case 0x20: 21801da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_20)) 21811da177e4SLinus Torvalds return 0; 21821da177e4SLinus Torvalds break; 21831da177e4SLinus Torvalds case 0x30: 21841da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_24)) 21851da177e4SLinus Torvalds return 0; 21861da177e4SLinus Torvalds break; 21871da177e4SLinus Torvalds case 0x40: 21881da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_32)) 21891da177e4SLinus Torvalds return 0; 21901da177e4SLinus Torvalds break; 21911da177e4SLinus Torvalds default: 21921da177e4SLinus Torvalds return 0; 21931da177e4SLinus Torvalds } 21941da177e4SLinus Torvalds } else { 21951da177e4SLinus Torvalds /* FIXME: check for float32 and AC3? */ 21961da177e4SLinus Torvalds } 21971da177e4SLinus Torvalds 21981da177e4SLinus Torvalds return 1; 21991da177e4SLinus Torvalds } 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds /* 22021da177e4SLinus Torvalds * PCM stuff 22031da177e4SLinus Torvalds */ 22041da177e4SLinus Torvalds static int hda_pcm_default_open_close(struct hda_pcm_stream *hinfo, 22051da177e4SLinus Torvalds struct hda_codec *codec, 2206c8b6bf9bSTakashi Iwai struct snd_pcm_substream *substream) 22071da177e4SLinus Torvalds { 22081da177e4SLinus Torvalds return 0; 22091da177e4SLinus Torvalds } 22101da177e4SLinus Torvalds 22111da177e4SLinus Torvalds static int hda_pcm_default_prepare(struct hda_pcm_stream *hinfo, 22121da177e4SLinus Torvalds struct hda_codec *codec, 22131da177e4SLinus Torvalds unsigned int stream_tag, 22141da177e4SLinus Torvalds unsigned int format, 2215c8b6bf9bSTakashi Iwai struct snd_pcm_substream *substream) 22161da177e4SLinus Torvalds { 22171da177e4SLinus Torvalds snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 22181da177e4SLinus Torvalds return 0; 22191da177e4SLinus Torvalds } 22201da177e4SLinus Torvalds 22211da177e4SLinus Torvalds static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, 22221da177e4SLinus Torvalds struct hda_codec *codec, 2223c8b6bf9bSTakashi Iwai struct snd_pcm_substream *substream) 22241da177e4SLinus Torvalds { 2225888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 22261da177e4SLinus Torvalds return 0; 22271da177e4SLinus Torvalds } 22281da177e4SLinus Torvalds 22290ba21762STakashi Iwai static int __devinit set_pcm_default_values(struct hda_codec *codec, 22300ba21762STakashi Iwai struct hda_pcm_stream *info) 22311da177e4SLinus Torvalds { 22321da177e4SLinus Torvalds /* query support PCM information from the given NID */ 22330ba21762STakashi Iwai if (info->nid && (!info->rates || !info->formats)) { 22341da177e4SLinus Torvalds snd_hda_query_supported_pcm(codec, info->nid, 22351da177e4SLinus Torvalds info->rates ? NULL : &info->rates, 22361da177e4SLinus Torvalds info->formats ? NULL : &info->formats, 22371da177e4SLinus Torvalds info->maxbps ? NULL : &info->maxbps); 22381da177e4SLinus Torvalds } 22391da177e4SLinus Torvalds if (info->ops.open == NULL) 22401da177e4SLinus Torvalds info->ops.open = hda_pcm_default_open_close; 22411da177e4SLinus Torvalds if (info->ops.close == NULL) 22421da177e4SLinus Torvalds info->ops.close = hda_pcm_default_open_close; 22431da177e4SLinus Torvalds if (info->ops.prepare == NULL) { 2244*da3cec35STakashi Iwai if (snd_BUG_ON(!info->nid)) 2245*da3cec35STakashi Iwai return -EINVAL; 22461da177e4SLinus Torvalds info->ops.prepare = hda_pcm_default_prepare; 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds if (info->ops.cleanup == NULL) { 2249*da3cec35STakashi Iwai if (snd_BUG_ON(!info->nid)) 2250*da3cec35STakashi Iwai return -EINVAL; 22511da177e4SLinus Torvalds info->ops.cleanup = hda_pcm_default_cleanup; 22521da177e4SLinus Torvalds } 22531da177e4SLinus Torvalds return 0; 22541da177e4SLinus Torvalds } 22551da177e4SLinus Torvalds 22561da177e4SLinus Torvalds /** 22571da177e4SLinus Torvalds * snd_hda_build_pcms - build PCM information 22581da177e4SLinus Torvalds * @bus: the BUS 22591da177e4SLinus Torvalds * 22601da177e4SLinus Torvalds * Create PCM information for each codec included in the bus. 22611da177e4SLinus Torvalds * 22621da177e4SLinus Torvalds * The build_pcms codec patch is requested to set up codec->num_pcms and 22631da177e4SLinus Torvalds * codec->pcm_info properly. The array is referred by the top-level driver 22641da177e4SLinus Torvalds * to create its PCM instances. 22651da177e4SLinus Torvalds * The allocated codec->pcm_info should be released in codec->patch_ops.free 22661da177e4SLinus Torvalds * callback. 22671da177e4SLinus Torvalds * 22681da177e4SLinus Torvalds * At least, substreams, channels_min and channels_max must be filled for 22691da177e4SLinus Torvalds * each stream. substreams = 0 indicates that the stream doesn't exist. 22701da177e4SLinus Torvalds * When rates and/or formats are zero, the supported values are queried 22711da177e4SLinus Torvalds * from the given nid. The nid is used also by the default ops.prepare 22721da177e4SLinus Torvalds * and ops.cleanup callbacks. 22731da177e4SLinus Torvalds * 22741da177e4SLinus Torvalds * The driver needs to call ops.open in its open callback. Similarly, 22751da177e4SLinus Torvalds * ops.close is supposed to be called in the close callback. 22761da177e4SLinus Torvalds * ops.prepare should be called in the prepare or hw_params callback 22771da177e4SLinus Torvalds * with the proper parameters for set up. 22781da177e4SLinus Torvalds * ops.cleanup should be called in hw_free for clean up of streams. 22791da177e4SLinus Torvalds * 22801da177e4SLinus Torvalds * This function returns 0 if successfull, or a negative error code. 22811da177e4SLinus Torvalds */ 2282756e2b01STakashi Iwai int __devinit snd_hda_build_pcms(struct hda_bus *bus) 22831da177e4SLinus Torvalds { 22840ba21762STakashi Iwai struct hda_codec *codec; 22851da177e4SLinus Torvalds 22860ba21762STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 22871da177e4SLinus Torvalds unsigned int pcm, s; 22881da177e4SLinus Torvalds int err; 22891da177e4SLinus Torvalds if (!codec->patch_ops.build_pcms) 22901da177e4SLinus Torvalds continue; 22911da177e4SLinus Torvalds err = codec->patch_ops.build_pcms(codec); 22921da177e4SLinus Torvalds if (err < 0) 22931da177e4SLinus Torvalds return err; 22941da177e4SLinus Torvalds for (pcm = 0; pcm < codec->num_pcms; pcm++) { 22951da177e4SLinus Torvalds for (s = 0; s < 2; s++) { 22961da177e4SLinus Torvalds struct hda_pcm_stream *info; 22971da177e4SLinus Torvalds info = &codec->pcm_info[pcm].stream[s]; 22981da177e4SLinus Torvalds if (!info->substreams) 22991da177e4SLinus Torvalds continue; 23001da177e4SLinus Torvalds err = set_pcm_default_values(codec, info); 23011da177e4SLinus Torvalds if (err < 0) 23021da177e4SLinus Torvalds return err; 23031da177e4SLinus Torvalds } 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds } 23061da177e4SLinus Torvalds return 0; 23071da177e4SLinus Torvalds } 23081da177e4SLinus Torvalds 23091da177e4SLinus Torvalds /** 23101da177e4SLinus Torvalds * snd_hda_check_board_config - compare the current codec with the config table 23111da177e4SLinus Torvalds * @codec: the HDA codec 2312f5fcc13cSTakashi Iwai * @num_configs: number of config enums 2313f5fcc13cSTakashi Iwai * @models: array of model name strings 23141da177e4SLinus Torvalds * @tbl: configuration table, terminated by null entries 23151da177e4SLinus Torvalds * 23161da177e4SLinus Torvalds * Compares the modelname or PCI subsystem id of the current codec with the 23171da177e4SLinus Torvalds * given configuration table. If a matching entry is found, returns its 23181da177e4SLinus Torvalds * config value (supposed to be 0 or positive). 23191da177e4SLinus Torvalds * 23201da177e4SLinus Torvalds * If no entries are matching, the function returns a negative value. 23211da177e4SLinus Torvalds */ 232212f288bfSTakashi Iwai int snd_hda_check_board_config(struct hda_codec *codec, 2323f5fcc13cSTakashi Iwai int num_configs, const char **models, 2324f5fcc13cSTakashi Iwai const struct snd_pci_quirk *tbl) 23251da177e4SLinus Torvalds { 2326f5fcc13cSTakashi Iwai if (codec->bus->modelname && models) { 2327f5fcc13cSTakashi Iwai int i; 2328f5fcc13cSTakashi Iwai for (i = 0; i < num_configs; i++) { 2329f5fcc13cSTakashi Iwai if (models[i] && 2330f5fcc13cSTakashi Iwai !strcmp(codec->bus->modelname, models[i])) { 2331f5fcc13cSTakashi Iwai snd_printd(KERN_INFO "hda_codec: model '%s' is " 2332f5fcc13cSTakashi Iwai "selected\n", models[i]); 2333f5fcc13cSTakashi Iwai return i; 23341da177e4SLinus Torvalds } 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds } 23371da177e4SLinus Torvalds 2338f5fcc13cSTakashi Iwai if (!codec->bus->pci || !tbl) 2339f5fcc13cSTakashi Iwai return -1; 2340f5fcc13cSTakashi Iwai 2341f5fcc13cSTakashi Iwai tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl); 2342f5fcc13cSTakashi Iwai if (!tbl) 2343f5fcc13cSTakashi Iwai return -1; 2344f5fcc13cSTakashi Iwai if (tbl->value >= 0 && tbl->value < num_configs) { 234562cf872aSTakashi Iwai #ifdef CONFIG_SND_DEBUG_VERBOSE 2346f5fcc13cSTakashi Iwai char tmp[10]; 2347f5fcc13cSTakashi Iwai const char *model = NULL; 2348f5fcc13cSTakashi Iwai if (models) 2349f5fcc13cSTakashi Iwai model = models[tbl->value]; 2350f5fcc13cSTakashi Iwai if (!model) { 2351f5fcc13cSTakashi Iwai sprintf(tmp, "#%d", tbl->value); 2352f5fcc13cSTakashi Iwai model = tmp; 23531da177e4SLinus Torvalds } 2354f5fcc13cSTakashi Iwai snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " 2355f5fcc13cSTakashi Iwai "for config %x:%x (%s)\n", 2356f5fcc13cSTakashi Iwai model, tbl->subvendor, tbl->subdevice, 2357f5fcc13cSTakashi Iwai (tbl->name ? tbl->name : "Unknown device")); 2358f5fcc13cSTakashi Iwai #endif 2359f5fcc13cSTakashi Iwai return tbl->value; 2360cb8e2f83STakashi Iwai } 23611da177e4SLinus Torvalds return -1; 23621da177e4SLinus Torvalds } 23631da177e4SLinus Torvalds 23641da177e4SLinus Torvalds /** 23651da177e4SLinus Torvalds * snd_hda_add_new_ctls - create controls from the array 23661da177e4SLinus Torvalds * @codec: the HDA codec 2367c8b6bf9bSTakashi Iwai * @knew: the array of struct snd_kcontrol_new 23681da177e4SLinus Torvalds * 23691da177e4SLinus Torvalds * This helper function creates and add new controls in the given array. 23701da177e4SLinus Torvalds * The array must be terminated with an empty entry as terminator. 23711da177e4SLinus Torvalds * 23721da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 23731da177e4SLinus Torvalds */ 237412f288bfSTakashi Iwai int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) 23751da177e4SLinus Torvalds { 23761da177e4SLinus Torvalds int err; 23771da177e4SLinus Torvalds 23781da177e4SLinus Torvalds for (; knew->name; knew++) { 237954d17403STakashi Iwai struct snd_kcontrol *kctl; 238054d17403STakashi Iwai kctl = snd_ctl_new1(knew, codec); 238154d17403STakashi Iwai if (!kctl) 238254d17403STakashi Iwai return -ENOMEM; 238354d17403STakashi Iwai err = snd_ctl_add(codec->bus->card, kctl); 238454d17403STakashi Iwai if (err < 0) { 238554d17403STakashi Iwai if (!codec->addr) 23861da177e4SLinus Torvalds return err; 238754d17403STakashi Iwai kctl = snd_ctl_new1(knew, codec); 238854d17403STakashi Iwai if (!kctl) 238954d17403STakashi Iwai return -ENOMEM; 239054d17403STakashi Iwai kctl->id.device = codec->addr; 23910ba21762STakashi Iwai err = snd_ctl_add(codec->bus->card, kctl); 23920ba21762STakashi Iwai if (err < 0) 239354d17403STakashi Iwai return err; 239454d17403STakashi Iwai } 23951da177e4SLinus Torvalds } 23961da177e4SLinus Torvalds return 0; 23971da177e4SLinus Torvalds } 23981da177e4SLinus Torvalds 2399cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 2400cb53c626STakashi Iwai static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, 2401cb53c626STakashi Iwai unsigned int power_state); 2402cb53c626STakashi Iwai 2403cb53c626STakashi Iwai static void hda_power_work(struct work_struct *work) 2404cb53c626STakashi Iwai { 2405cb53c626STakashi Iwai struct hda_codec *codec = 2406cb53c626STakashi Iwai container_of(work, struct hda_codec, power_work.work); 2407cb53c626STakashi Iwai 24082e492462SMaxim Levitsky if (!codec->power_on || codec->power_count) { 24092e492462SMaxim Levitsky codec->power_transition = 0; 2410cb53c626STakashi Iwai return; 24112e492462SMaxim Levitsky } 2412cb53c626STakashi Iwai 2413cb53c626STakashi Iwai hda_call_codec_suspend(codec); 2414cb53c626STakashi Iwai if (codec->bus->ops.pm_notify) 2415cb53c626STakashi Iwai codec->bus->ops.pm_notify(codec); 2416cb53c626STakashi Iwai } 2417cb53c626STakashi Iwai 2418cb53c626STakashi Iwai static void hda_keep_power_on(struct hda_codec *codec) 2419cb53c626STakashi Iwai { 2420cb53c626STakashi Iwai codec->power_count++; 2421cb53c626STakashi Iwai codec->power_on = 1; 2422cb53c626STakashi Iwai } 2423cb53c626STakashi Iwai 2424cb53c626STakashi Iwai void snd_hda_power_up(struct hda_codec *codec) 2425cb53c626STakashi Iwai { 2426cb53c626STakashi Iwai codec->power_count++; 2427a221e287STakashi Iwai if (codec->power_on || codec->power_transition) 2428cb53c626STakashi Iwai return; 2429cb53c626STakashi Iwai 2430cb53c626STakashi Iwai codec->power_on = 1; 2431cb53c626STakashi Iwai if (codec->bus->ops.pm_notify) 2432cb53c626STakashi Iwai codec->bus->ops.pm_notify(codec); 2433cb53c626STakashi Iwai hda_call_codec_resume(codec); 2434cb53c626STakashi Iwai cancel_delayed_work(&codec->power_work); 2435a221e287STakashi Iwai codec->power_transition = 0; 2436cb53c626STakashi Iwai } 2437cb53c626STakashi Iwai 2438cb53c626STakashi Iwai void snd_hda_power_down(struct hda_codec *codec) 2439cb53c626STakashi Iwai { 2440cb53c626STakashi Iwai --codec->power_count; 2441a221e287STakashi Iwai if (!codec->power_on || codec->power_count || codec->power_transition) 2442cb53c626STakashi Iwai return; 2443a221e287STakashi Iwai if (power_save) { 2444a221e287STakashi Iwai codec->power_transition = 1; /* avoid reentrance */ 2445cb53c626STakashi Iwai schedule_delayed_work(&codec->power_work, 2446cb53c626STakashi Iwai msecs_to_jiffies(power_save * 1000)); 2447cb53c626STakashi Iwai } 2448a221e287STakashi Iwai } 2449cb53c626STakashi Iwai 2450cb53c626STakashi Iwai int snd_hda_check_amp_list_power(struct hda_codec *codec, 2451cb53c626STakashi Iwai struct hda_loopback_check *check, 2452cb53c626STakashi Iwai hda_nid_t nid) 2453cb53c626STakashi Iwai { 2454cb53c626STakashi Iwai struct hda_amp_list *p; 2455cb53c626STakashi Iwai int ch, v; 2456cb53c626STakashi Iwai 2457cb53c626STakashi Iwai if (!check->amplist) 2458cb53c626STakashi Iwai return 0; 2459cb53c626STakashi Iwai for (p = check->amplist; p->nid; p++) { 2460cb53c626STakashi Iwai if (p->nid == nid) 2461cb53c626STakashi Iwai break; 2462cb53c626STakashi Iwai } 2463cb53c626STakashi Iwai if (!p->nid) 2464cb53c626STakashi Iwai return 0; /* nothing changed */ 2465cb53c626STakashi Iwai 2466cb53c626STakashi Iwai for (p = check->amplist; p->nid; p++) { 2467cb53c626STakashi Iwai for (ch = 0; ch < 2; ch++) { 2468cb53c626STakashi Iwai v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, 2469cb53c626STakashi Iwai p->idx); 2470cb53c626STakashi Iwai if (!(v & HDA_AMP_MUTE) && v > 0) { 2471cb53c626STakashi Iwai if (!check->power_on) { 2472cb53c626STakashi Iwai check->power_on = 1; 2473cb53c626STakashi Iwai snd_hda_power_up(codec); 2474cb53c626STakashi Iwai } 2475cb53c626STakashi Iwai return 1; 2476cb53c626STakashi Iwai } 2477cb53c626STakashi Iwai } 2478cb53c626STakashi Iwai } 2479cb53c626STakashi Iwai if (check->power_on) { 2480cb53c626STakashi Iwai check->power_on = 0; 2481cb53c626STakashi Iwai snd_hda_power_down(codec); 2482cb53c626STakashi Iwai } 2483cb53c626STakashi Iwai return 0; 2484cb53c626STakashi Iwai } 2485cb53c626STakashi Iwai #endif 24861da177e4SLinus Torvalds 2487d2a6d7dcSTakashi Iwai /* 2488d2a6d7dcSTakashi Iwai * Channel mode helper 2489d2a6d7dcSTakashi Iwai */ 24900ba21762STakashi Iwai int snd_hda_ch_mode_info(struct hda_codec *codec, 24910ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo, 24920ba21762STakashi Iwai const struct hda_channel_mode *chmode, 24930ba21762STakashi Iwai int num_chmodes) 2494d2a6d7dcSTakashi Iwai { 2495d2a6d7dcSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2496d2a6d7dcSTakashi Iwai uinfo->count = 1; 2497d2a6d7dcSTakashi Iwai uinfo->value.enumerated.items = num_chmodes; 2498d2a6d7dcSTakashi Iwai if (uinfo->value.enumerated.item >= num_chmodes) 2499d2a6d7dcSTakashi Iwai uinfo->value.enumerated.item = num_chmodes - 1; 2500d2a6d7dcSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", 2501d2a6d7dcSTakashi Iwai chmode[uinfo->value.enumerated.item].channels); 2502d2a6d7dcSTakashi Iwai return 0; 2503d2a6d7dcSTakashi Iwai } 2504d2a6d7dcSTakashi Iwai 25050ba21762STakashi Iwai int snd_hda_ch_mode_get(struct hda_codec *codec, 25060ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol, 25070ba21762STakashi Iwai const struct hda_channel_mode *chmode, 25080ba21762STakashi Iwai int num_chmodes, 2509d2a6d7dcSTakashi Iwai int max_channels) 2510d2a6d7dcSTakashi Iwai { 2511d2a6d7dcSTakashi Iwai int i; 2512d2a6d7dcSTakashi Iwai 2513d2a6d7dcSTakashi Iwai for (i = 0; i < num_chmodes; i++) { 2514d2a6d7dcSTakashi Iwai if (max_channels == chmode[i].channels) { 2515d2a6d7dcSTakashi Iwai ucontrol->value.enumerated.item[0] = i; 2516d2a6d7dcSTakashi Iwai break; 2517d2a6d7dcSTakashi Iwai } 2518d2a6d7dcSTakashi Iwai } 2519d2a6d7dcSTakashi Iwai return 0; 2520d2a6d7dcSTakashi Iwai } 2521d2a6d7dcSTakashi Iwai 25220ba21762STakashi Iwai int snd_hda_ch_mode_put(struct hda_codec *codec, 25230ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol, 25240ba21762STakashi Iwai const struct hda_channel_mode *chmode, 25250ba21762STakashi Iwai int num_chmodes, 2526d2a6d7dcSTakashi Iwai int *max_channelsp) 2527d2a6d7dcSTakashi Iwai { 2528d2a6d7dcSTakashi Iwai unsigned int mode; 2529d2a6d7dcSTakashi Iwai 2530d2a6d7dcSTakashi Iwai mode = ucontrol->value.enumerated.item[0]; 253168ea7b2fSTakashi Iwai if (mode >= num_chmodes) 253268ea7b2fSTakashi Iwai return -EINVAL; 253382beb8fdSTakashi Iwai if (*max_channelsp == chmode[mode].channels) 2534d2a6d7dcSTakashi Iwai return 0; 2535d2a6d7dcSTakashi Iwai /* change the current channel setting */ 2536d2a6d7dcSTakashi Iwai *max_channelsp = chmode[mode].channels; 2537d2a6d7dcSTakashi Iwai if (chmode[mode].sequence) 253882beb8fdSTakashi Iwai snd_hda_sequence_write_cache(codec, chmode[mode].sequence); 2539d2a6d7dcSTakashi Iwai return 1; 2540d2a6d7dcSTakashi Iwai } 2541d2a6d7dcSTakashi Iwai 25421da177e4SLinus Torvalds /* 25431da177e4SLinus Torvalds * input MUX helper 25441da177e4SLinus Torvalds */ 25450ba21762STakashi Iwai int snd_hda_input_mux_info(const struct hda_input_mux *imux, 25460ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo) 25471da177e4SLinus Torvalds { 25481da177e4SLinus Torvalds unsigned int index; 25491da177e4SLinus Torvalds 25501da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 25511da177e4SLinus Torvalds uinfo->count = 1; 25521da177e4SLinus Torvalds uinfo->value.enumerated.items = imux->num_items; 25535513b0c5STakashi Iwai if (!imux->num_items) 25545513b0c5STakashi Iwai return 0; 25551da177e4SLinus Torvalds index = uinfo->value.enumerated.item; 25561da177e4SLinus Torvalds if (index >= imux->num_items) 25571da177e4SLinus Torvalds index = imux->num_items - 1; 25581da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, imux->items[index].label); 25591da177e4SLinus Torvalds return 0; 25601da177e4SLinus Torvalds } 25611da177e4SLinus Torvalds 25620ba21762STakashi Iwai int snd_hda_input_mux_put(struct hda_codec *codec, 25630ba21762STakashi Iwai const struct hda_input_mux *imux, 25640ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol, 25650ba21762STakashi Iwai hda_nid_t nid, 25661da177e4SLinus Torvalds unsigned int *cur_val) 25671da177e4SLinus Torvalds { 25681da177e4SLinus Torvalds unsigned int idx; 25691da177e4SLinus Torvalds 25705513b0c5STakashi Iwai if (!imux->num_items) 25715513b0c5STakashi Iwai return 0; 25721da177e4SLinus Torvalds idx = ucontrol->value.enumerated.item[0]; 25731da177e4SLinus Torvalds if (idx >= imux->num_items) 25741da177e4SLinus Torvalds idx = imux->num_items - 1; 257582beb8fdSTakashi Iwai if (*cur_val == idx) 25761da177e4SLinus Torvalds return 0; 257782beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, 25781da177e4SLinus Torvalds imux->items[idx].index); 25791da177e4SLinus Torvalds *cur_val = idx; 25801da177e4SLinus Torvalds return 1; 25811da177e4SLinus Torvalds } 25821da177e4SLinus Torvalds 25831da177e4SLinus Torvalds 25841da177e4SLinus Torvalds /* 25851da177e4SLinus Torvalds * Multi-channel / digital-out PCM helper functions 25861da177e4SLinus Torvalds */ 25871da177e4SLinus Torvalds 25886b97eb45STakashi Iwai /* setup SPDIF output stream */ 25896b97eb45STakashi Iwai static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, 25906b97eb45STakashi Iwai unsigned int stream_tag, unsigned int format) 25916b97eb45STakashi Iwai { 25926b97eb45STakashi Iwai /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ 25936b97eb45STakashi Iwai if (codec->spdif_ctls & AC_DIG1_ENABLE) 25946b97eb45STakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, 25956b97eb45STakashi Iwai codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); 25966b97eb45STakashi Iwai snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); 25976b97eb45STakashi Iwai /* turn on again (if needed) */ 25986b97eb45STakashi Iwai if (codec->spdif_ctls & AC_DIG1_ENABLE) 25996b97eb45STakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, 26006b97eb45STakashi Iwai codec->spdif_ctls & 0xff); 26016b97eb45STakashi Iwai } 26026b97eb45STakashi Iwai 26031da177e4SLinus Torvalds /* 26041da177e4SLinus Torvalds * open the digital out in the exclusive mode 26051da177e4SLinus Torvalds */ 26060ba21762STakashi Iwai int snd_hda_multi_out_dig_open(struct hda_codec *codec, 26070ba21762STakashi Iwai struct hda_multi_out *mout) 26081da177e4SLinus Torvalds { 260962932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 26105930ca41STakashi Iwai if (mout->dig_out_used == HDA_DIG_ANALOG_DUP) 26115930ca41STakashi Iwai /* already opened as analog dup; reset it once */ 2612888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); 26131da177e4SLinus Torvalds mout->dig_out_used = HDA_DIG_EXCLUSIVE; 261462932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 26151da177e4SLinus Torvalds return 0; 26161da177e4SLinus Torvalds } 26171da177e4SLinus Torvalds 26186b97eb45STakashi Iwai int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, 26196b97eb45STakashi Iwai struct hda_multi_out *mout, 26206b97eb45STakashi Iwai unsigned int stream_tag, 26216b97eb45STakashi Iwai unsigned int format, 26226b97eb45STakashi Iwai struct snd_pcm_substream *substream) 26236b97eb45STakashi Iwai { 26246b97eb45STakashi Iwai mutex_lock(&codec->spdif_mutex); 26256b97eb45STakashi Iwai setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); 26266b97eb45STakashi Iwai mutex_unlock(&codec->spdif_mutex); 26276b97eb45STakashi Iwai return 0; 26286b97eb45STakashi Iwai } 26296b97eb45STakashi Iwai 26301da177e4SLinus Torvalds /* 26311da177e4SLinus Torvalds * release the digital out 26321da177e4SLinus Torvalds */ 26330ba21762STakashi Iwai int snd_hda_multi_out_dig_close(struct hda_codec *codec, 26340ba21762STakashi Iwai struct hda_multi_out *mout) 26351da177e4SLinus Torvalds { 263662932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 26371da177e4SLinus Torvalds mout->dig_out_used = 0; 263862932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 26391da177e4SLinus Torvalds return 0; 26401da177e4SLinus Torvalds } 26411da177e4SLinus Torvalds 26421da177e4SLinus Torvalds /* 26431da177e4SLinus Torvalds * set up more restrictions for analog out 26441da177e4SLinus Torvalds */ 26450ba21762STakashi Iwai int snd_hda_multi_out_analog_open(struct hda_codec *codec, 26460ba21762STakashi Iwai struct hda_multi_out *mout, 26479a08160bSTakashi Iwai struct snd_pcm_substream *substream, 26489a08160bSTakashi Iwai struct hda_pcm_stream *hinfo) 26491da177e4SLinus Torvalds { 26509a08160bSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 26519a08160bSTakashi Iwai runtime->hw.channels_max = mout->max_channels; 26529a08160bSTakashi Iwai if (mout->dig_out_nid) { 26539a08160bSTakashi Iwai if (!mout->analog_rates) { 26549a08160bSTakashi Iwai mout->analog_rates = hinfo->rates; 26559a08160bSTakashi Iwai mout->analog_formats = hinfo->formats; 26569a08160bSTakashi Iwai mout->analog_maxbps = hinfo->maxbps; 26579a08160bSTakashi Iwai } else { 26589a08160bSTakashi Iwai runtime->hw.rates = mout->analog_rates; 26599a08160bSTakashi Iwai runtime->hw.formats = mout->analog_formats; 26609a08160bSTakashi Iwai hinfo->maxbps = mout->analog_maxbps; 26619a08160bSTakashi Iwai } 26629a08160bSTakashi Iwai if (!mout->spdif_rates) { 26639a08160bSTakashi Iwai snd_hda_query_supported_pcm(codec, mout->dig_out_nid, 26649a08160bSTakashi Iwai &mout->spdif_rates, 26659a08160bSTakashi Iwai &mout->spdif_formats, 26669a08160bSTakashi Iwai &mout->spdif_maxbps); 26679a08160bSTakashi Iwai } 26689a08160bSTakashi Iwai mutex_lock(&codec->spdif_mutex); 26699a08160bSTakashi Iwai if (mout->share_spdif) { 26709a08160bSTakashi Iwai runtime->hw.rates &= mout->spdif_rates; 26719a08160bSTakashi Iwai runtime->hw.formats &= mout->spdif_formats; 26729a08160bSTakashi Iwai if (mout->spdif_maxbps < hinfo->maxbps) 26739a08160bSTakashi Iwai hinfo->maxbps = mout->spdif_maxbps; 26749a08160bSTakashi Iwai } 26759a08160bSTakashi Iwai mutex_unlock(&codec->spdif_mutex); 2676eaa9985bSFrederik Deweerdt } 26771da177e4SLinus Torvalds return snd_pcm_hw_constraint_step(substream->runtime, 0, 26781da177e4SLinus Torvalds SNDRV_PCM_HW_PARAM_CHANNELS, 2); 26791da177e4SLinus Torvalds } 26801da177e4SLinus Torvalds 26811da177e4SLinus Torvalds /* 26821da177e4SLinus Torvalds * set up the i/o for analog out 26831da177e4SLinus Torvalds * when the digital out is available, copy the front out to digital out, too. 26841da177e4SLinus Torvalds */ 26850ba21762STakashi Iwai int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, 26860ba21762STakashi Iwai struct hda_multi_out *mout, 26871da177e4SLinus Torvalds unsigned int stream_tag, 26881da177e4SLinus Torvalds unsigned int format, 2689c8b6bf9bSTakashi Iwai struct snd_pcm_substream *substream) 26901da177e4SLinus Torvalds { 26911da177e4SLinus Torvalds hda_nid_t *nids = mout->dac_nids; 26921da177e4SLinus Torvalds int chs = substream->runtime->channels; 26931da177e4SLinus Torvalds int i; 26941da177e4SLinus Torvalds 269562932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 26969a08160bSTakashi Iwai if (mout->dig_out_nid && mout->share_spdif && 26979a08160bSTakashi Iwai mout->dig_out_used != HDA_DIG_EXCLUSIVE) { 26981da177e4SLinus Torvalds if (chs == 2 && 26990ba21762STakashi Iwai snd_hda_is_supported_format(codec, mout->dig_out_nid, 27000ba21762STakashi Iwai format) && 27011da177e4SLinus Torvalds !(codec->spdif_status & IEC958_AES0_NONAUDIO)) { 27021da177e4SLinus Torvalds mout->dig_out_used = HDA_DIG_ANALOG_DUP; 27036b97eb45STakashi Iwai setup_dig_out_stream(codec, mout->dig_out_nid, 27046b97eb45STakashi Iwai stream_tag, format); 27051da177e4SLinus Torvalds } else { 27061da177e4SLinus Torvalds mout->dig_out_used = 0; 2707888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); 27081da177e4SLinus Torvalds } 27091da177e4SLinus Torvalds } 271062932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 27111da177e4SLinus Torvalds 27121da177e4SLinus Torvalds /* front */ 27130ba21762STakashi Iwai snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 27140ba21762STakashi Iwai 0, format); 2715d29240ceSTakashi Iwai if (!mout->no_share_stream && 2716d29240ceSTakashi Iwai mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]) 27171da177e4SLinus Torvalds /* headphone out will just decode front left/right (stereo) */ 27180ba21762STakashi Iwai snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 27190ba21762STakashi Iwai 0, format); 272082bc955fSTakashi Iwai /* extra outputs copied from front */ 272182bc955fSTakashi Iwai for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) 2722d29240ceSTakashi Iwai if (!mout->no_share_stream && mout->extra_out_nid[i]) 272382bc955fSTakashi Iwai snd_hda_codec_setup_stream(codec, 272482bc955fSTakashi Iwai mout->extra_out_nid[i], 272582bc955fSTakashi Iwai stream_tag, 0, format); 272682bc955fSTakashi Iwai 27271da177e4SLinus Torvalds /* surrounds */ 27281da177e4SLinus Torvalds for (i = 1; i < mout->num_dacs; i++) { 27294b3acaf5STakashi Iwai if (chs >= (i + 1) * 2) /* independent out */ 27300ba21762STakashi Iwai snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 27310ba21762STakashi Iwai i * 2, format); 2732d29240ceSTakashi Iwai else if (!mout->no_share_stream) /* copy front */ 27330ba21762STakashi Iwai snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 27340ba21762STakashi Iwai 0, format); 27351da177e4SLinus Torvalds } 27361da177e4SLinus Torvalds return 0; 27371da177e4SLinus Torvalds } 27381da177e4SLinus Torvalds 27391da177e4SLinus Torvalds /* 27401da177e4SLinus Torvalds * clean up the setting for analog out 27411da177e4SLinus Torvalds */ 27420ba21762STakashi Iwai int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, 27430ba21762STakashi Iwai struct hda_multi_out *mout) 27441da177e4SLinus Torvalds { 27451da177e4SLinus Torvalds hda_nid_t *nids = mout->dac_nids; 27461da177e4SLinus Torvalds int i; 27471da177e4SLinus Torvalds 27481da177e4SLinus Torvalds for (i = 0; i < mout->num_dacs; i++) 2749888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, nids[i]); 27501da177e4SLinus Torvalds if (mout->hp_nid) 2751888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, mout->hp_nid); 275282bc955fSTakashi Iwai for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) 275382bc955fSTakashi Iwai if (mout->extra_out_nid[i]) 2754888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, 2755888afa15STakashi Iwai mout->extra_out_nid[i]); 275662932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 27571da177e4SLinus Torvalds if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { 2758888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); 27591da177e4SLinus Torvalds mout->dig_out_used = 0; 27601da177e4SLinus Torvalds } 276162932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 27621da177e4SLinus Torvalds return 0; 27631da177e4SLinus Torvalds } 27641da177e4SLinus Torvalds 2765e9edcee0STakashi Iwai /* 2766e9edcee0STakashi Iwai * Helper for automatic ping configuration 2767e9edcee0STakashi Iwai */ 2768df694daaSKailang Yang 276912f288bfSTakashi Iwai static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) 2770df694daaSKailang Yang { 2771df694daaSKailang Yang for (; *list; list++) 2772df694daaSKailang Yang if (*list == nid) 2773df694daaSKailang Yang return 1; 2774df694daaSKailang Yang return 0; 2775df694daaSKailang Yang } 2776df694daaSKailang Yang 277781937d3bSSteve Longerbeam 277881937d3bSSteve Longerbeam /* 277981937d3bSSteve Longerbeam * Sort an associated group of pins according to their sequence numbers. 278081937d3bSSteve Longerbeam */ 278181937d3bSSteve Longerbeam static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences, 278281937d3bSSteve Longerbeam int num_pins) 278381937d3bSSteve Longerbeam { 278481937d3bSSteve Longerbeam int i, j; 278581937d3bSSteve Longerbeam short seq; 278681937d3bSSteve Longerbeam hda_nid_t nid; 278781937d3bSSteve Longerbeam 278881937d3bSSteve Longerbeam for (i = 0; i < num_pins; i++) { 278981937d3bSSteve Longerbeam for (j = i + 1; j < num_pins; j++) { 279081937d3bSSteve Longerbeam if (sequences[i] > sequences[j]) { 279181937d3bSSteve Longerbeam seq = sequences[i]; 279281937d3bSSteve Longerbeam sequences[i] = sequences[j]; 279381937d3bSSteve Longerbeam sequences[j] = seq; 279481937d3bSSteve Longerbeam nid = pins[i]; 279581937d3bSSteve Longerbeam pins[i] = pins[j]; 279681937d3bSSteve Longerbeam pins[j] = nid; 279781937d3bSSteve Longerbeam } 279881937d3bSSteve Longerbeam } 279981937d3bSSteve Longerbeam } 280081937d3bSSteve Longerbeam } 280181937d3bSSteve Longerbeam 280281937d3bSSteve Longerbeam 280382bc955fSTakashi Iwai /* 280482bc955fSTakashi Iwai * Parse all pin widgets and store the useful pin nids to cfg 280582bc955fSTakashi Iwai * 280682bc955fSTakashi Iwai * The number of line-outs or any primary output is stored in line_outs, 280782bc955fSTakashi Iwai * and the corresponding output pins are assigned to line_out_pins[], 280882bc955fSTakashi Iwai * in the order of front, rear, CLFE, side, ... 280982bc955fSTakashi Iwai * 281082bc955fSTakashi Iwai * If more extra outputs (speaker and headphone) are found, the pins are 2811eb06ed8fSTakashi Iwai * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack 281282bc955fSTakashi Iwai * is detected, one of speaker of HP pins is assigned as the primary 281382bc955fSTakashi Iwai * output, i.e. to line_out_pins[0]. So, line_outs is always positive 281482bc955fSTakashi Iwai * if any analog output exists. 281582bc955fSTakashi Iwai * 281682bc955fSTakashi Iwai * The analog input pins are assigned to input_pins array. 281782bc955fSTakashi Iwai * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, 281882bc955fSTakashi Iwai * respectively. 281982bc955fSTakashi Iwai */ 282012f288bfSTakashi Iwai int snd_hda_parse_pin_def_config(struct hda_codec *codec, 2821756e2b01STakashi Iwai struct auto_pin_cfg *cfg, 2822df694daaSKailang Yang hda_nid_t *ignore_nids) 2823e9edcee0STakashi Iwai { 28240ef6ce7bSTakashi Iwai hda_nid_t nid, end_nid; 282581937d3bSSteve Longerbeam short seq, assoc_line_out, assoc_speaker; 282681937d3bSSteve Longerbeam short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; 282781937d3bSSteve Longerbeam short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; 2828f889fa91STakashi Iwai short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; 2829e9edcee0STakashi Iwai 2830e9edcee0STakashi Iwai memset(cfg, 0, sizeof(*cfg)); 2831e9edcee0STakashi Iwai 283281937d3bSSteve Longerbeam memset(sequences_line_out, 0, sizeof(sequences_line_out)); 283381937d3bSSteve Longerbeam memset(sequences_speaker, 0, sizeof(sequences_speaker)); 2834f889fa91STakashi Iwai memset(sequences_hp, 0, sizeof(sequences_hp)); 283581937d3bSSteve Longerbeam assoc_line_out = assoc_speaker = 0; 2836e9edcee0STakashi Iwai 28370ef6ce7bSTakashi Iwai end_nid = codec->start_nid + codec->num_nodes; 28380ef6ce7bSTakashi Iwai for (nid = codec->start_nid; nid < end_nid; nid++) { 283954d17403STakashi Iwai unsigned int wid_caps = get_wcaps(codec, nid); 28400ba21762STakashi Iwai unsigned int wid_type = 28410ba21762STakashi Iwai (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; 2842e9edcee0STakashi Iwai unsigned int def_conf; 2843e9edcee0STakashi Iwai short assoc, loc; 2844e9edcee0STakashi Iwai 2845e9edcee0STakashi Iwai /* read all default configuration for pin complex */ 2846e9edcee0STakashi Iwai if (wid_type != AC_WID_PIN) 2847e9edcee0STakashi Iwai continue; 2848df694daaSKailang Yang /* ignore the given nids (e.g. pc-beep returns error) */ 2849df694daaSKailang Yang if (ignore_nids && is_in_nid_list(nid, ignore_nids)) 2850df694daaSKailang Yang continue; 2851df694daaSKailang Yang 28520ba21762STakashi Iwai def_conf = snd_hda_codec_read(codec, nid, 0, 28530ba21762STakashi Iwai AC_VERB_GET_CONFIG_DEFAULT, 0); 2854e9edcee0STakashi Iwai if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) 2855e9edcee0STakashi Iwai continue; 2856e9edcee0STakashi Iwai loc = get_defcfg_location(def_conf); 2857e9edcee0STakashi Iwai switch (get_defcfg_device(def_conf)) { 2858e9edcee0STakashi Iwai case AC_JACK_LINE_OUT: 2859e9edcee0STakashi Iwai seq = get_defcfg_sequence(def_conf); 2860e9edcee0STakashi Iwai assoc = get_defcfg_association(def_conf); 286190da78bfSMatthew Ranostay 286290da78bfSMatthew Ranostay if (!(wid_caps & AC_WCAP_STEREO)) 286390da78bfSMatthew Ranostay if (!cfg->mono_out_pin) 286490da78bfSMatthew Ranostay cfg->mono_out_pin = nid; 2865e9edcee0STakashi Iwai if (!assoc) 2866e9edcee0STakashi Iwai continue; 2867e9edcee0STakashi Iwai if (!assoc_line_out) 2868e9edcee0STakashi Iwai assoc_line_out = assoc; 2869e9edcee0STakashi Iwai else if (assoc_line_out != assoc) 2870e9edcee0STakashi Iwai continue; 2871e9edcee0STakashi Iwai if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) 2872e9edcee0STakashi Iwai continue; 2873e9edcee0STakashi Iwai cfg->line_out_pins[cfg->line_outs] = nid; 287481937d3bSSteve Longerbeam sequences_line_out[cfg->line_outs] = seq; 2875e9edcee0STakashi Iwai cfg->line_outs++; 2876e9edcee0STakashi Iwai break; 28778d88bc3dSTakashi Iwai case AC_JACK_SPEAKER: 287881937d3bSSteve Longerbeam seq = get_defcfg_sequence(def_conf); 287981937d3bSSteve Longerbeam assoc = get_defcfg_association(def_conf); 288081937d3bSSteve Longerbeam if (! assoc) 288181937d3bSSteve Longerbeam continue; 288281937d3bSSteve Longerbeam if (! assoc_speaker) 288381937d3bSSteve Longerbeam assoc_speaker = assoc; 288481937d3bSSteve Longerbeam else if (assoc_speaker != assoc) 288581937d3bSSteve Longerbeam continue; 288682bc955fSTakashi Iwai if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) 288782bc955fSTakashi Iwai continue; 288882bc955fSTakashi Iwai cfg->speaker_pins[cfg->speaker_outs] = nid; 288981937d3bSSteve Longerbeam sequences_speaker[cfg->speaker_outs] = seq; 289082bc955fSTakashi Iwai cfg->speaker_outs++; 28918d88bc3dSTakashi Iwai break; 2892e9edcee0STakashi Iwai case AC_JACK_HP_OUT: 2893f889fa91STakashi Iwai seq = get_defcfg_sequence(def_conf); 2894f889fa91STakashi Iwai assoc = get_defcfg_association(def_conf); 2895eb06ed8fSTakashi Iwai if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) 2896eb06ed8fSTakashi Iwai continue; 2897eb06ed8fSTakashi Iwai cfg->hp_pins[cfg->hp_outs] = nid; 2898f889fa91STakashi Iwai sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; 2899eb06ed8fSTakashi Iwai cfg->hp_outs++; 2900e9edcee0STakashi Iwai break; 2901314634bcSTakashi Iwai case AC_JACK_MIC_IN: { 2902314634bcSTakashi Iwai int preferred, alt; 2903314634bcSTakashi Iwai if (loc == AC_JACK_LOC_FRONT) { 2904314634bcSTakashi Iwai preferred = AUTO_PIN_FRONT_MIC; 2905314634bcSTakashi Iwai alt = AUTO_PIN_MIC; 2906314634bcSTakashi Iwai } else { 2907314634bcSTakashi Iwai preferred = AUTO_PIN_MIC; 2908314634bcSTakashi Iwai alt = AUTO_PIN_FRONT_MIC; 2909314634bcSTakashi Iwai } 2910314634bcSTakashi Iwai if (!cfg->input_pins[preferred]) 2911314634bcSTakashi Iwai cfg->input_pins[preferred] = nid; 2912314634bcSTakashi Iwai else if (!cfg->input_pins[alt]) 2913314634bcSTakashi Iwai cfg->input_pins[alt] = nid; 2914e9edcee0STakashi Iwai break; 2915314634bcSTakashi Iwai } 2916e9edcee0STakashi Iwai case AC_JACK_LINE_IN: 2917e9edcee0STakashi Iwai if (loc == AC_JACK_LOC_FRONT) 2918e9edcee0STakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; 2919e9edcee0STakashi Iwai else 2920e9edcee0STakashi Iwai cfg->input_pins[AUTO_PIN_LINE] = nid; 2921e9edcee0STakashi Iwai break; 2922e9edcee0STakashi Iwai case AC_JACK_CD: 2923e9edcee0STakashi Iwai cfg->input_pins[AUTO_PIN_CD] = nid; 2924e9edcee0STakashi Iwai break; 2925e9edcee0STakashi Iwai case AC_JACK_AUX: 2926e9edcee0STakashi Iwai cfg->input_pins[AUTO_PIN_AUX] = nid; 2927e9edcee0STakashi Iwai break; 2928e9edcee0STakashi Iwai case AC_JACK_SPDIF_OUT: 2929e9edcee0STakashi Iwai cfg->dig_out_pin = nid; 2930e9edcee0STakashi Iwai break; 2931e9edcee0STakashi Iwai case AC_JACK_SPDIF_IN: 2932e9edcee0STakashi Iwai cfg->dig_in_pin = nid; 2933e9edcee0STakashi Iwai break; 2934e9edcee0STakashi Iwai } 2935e9edcee0STakashi Iwai } 2936e9edcee0STakashi Iwai 29375832fcf8STakashi Iwai /* FIX-UP: 29385832fcf8STakashi Iwai * If no line-out is defined but multiple HPs are found, 29395832fcf8STakashi Iwai * some of them might be the real line-outs. 29405832fcf8STakashi Iwai */ 29415832fcf8STakashi Iwai if (!cfg->line_outs && cfg->hp_outs > 1) { 29425832fcf8STakashi Iwai int i = 0; 29435832fcf8STakashi Iwai while (i < cfg->hp_outs) { 29445832fcf8STakashi Iwai /* The real HPs should have the sequence 0x0f */ 29455832fcf8STakashi Iwai if ((sequences_hp[i] & 0x0f) == 0x0f) { 29465832fcf8STakashi Iwai i++; 29475832fcf8STakashi Iwai continue; 29485832fcf8STakashi Iwai } 29495832fcf8STakashi Iwai /* Move it to the line-out table */ 29505832fcf8STakashi Iwai cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; 29515832fcf8STakashi Iwai sequences_line_out[cfg->line_outs] = sequences_hp[i]; 29525832fcf8STakashi Iwai cfg->line_outs++; 29535832fcf8STakashi Iwai cfg->hp_outs--; 29545832fcf8STakashi Iwai memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, 29555832fcf8STakashi Iwai sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); 29565832fcf8STakashi Iwai memmove(sequences_hp + i - 1, sequences_hp + i, 29575832fcf8STakashi Iwai sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); 29585832fcf8STakashi Iwai } 29595832fcf8STakashi Iwai } 29605832fcf8STakashi Iwai 2961e9edcee0STakashi Iwai /* sort by sequence */ 296281937d3bSSteve Longerbeam sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, 296381937d3bSSteve Longerbeam cfg->line_outs); 296481937d3bSSteve Longerbeam sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, 296581937d3bSSteve Longerbeam cfg->speaker_outs); 2966f889fa91STakashi Iwai sort_pins_by_sequence(cfg->hp_pins, sequences_hp, 2967f889fa91STakashi Iwai cfg->hp_outs); 2968f889fa91STakashi Iwai 2969f889fa91STakashi Iwai /* if we have only one mic, make it AUTO_PIN_MIC */ 2970f889fa91STakashi Iwai if (!cfg->input_pins[AUTO_PIN_MIC] && 2971f889fa91STakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_MIC]) { 2972f889fa91STakashi Iwai cfg->input_pins[AUTO_PIN_MIC] = 2973f889fa91STakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_MIC]; 2974f889fa91STakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0; 2975f889fa91STakashi Iwai } 2976f889fa91STakashi Iwai /* ditto for line-in */ 2977f889fa91STakashi Iwai if (!cfg->input_pins[AUTO_PIN_LINE] && 2978f889fa91STakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_LINE]) { 2979f889fa91STakashi Iwai cfg->input_pins[AUTO_PIN_LINE] = 2980f889fa91STakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_LINE]; 2981f889fa91STakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0; 2982f889fa91STakashi Iwai } 298381937d3bSSteve Longerbeam 298481937d3bSSteve Longerbeam /* 298581937d3bSSteve Longerbeam * FIX-UP: if no line-outs are detected, try to use speaker or HP pin 298681937d3bSSteve Longerbeam * as a primary output 298781937d3bSSteve Longerbeam */ 298881937d3bSSteve Longerbeam if (!cfg->line_outs) { 298981937d3bSSteve Longerbeam if (cfg->speaker_outs) { 299081937d3bSSteve Longerbeam cfg->line_outs = cfg->speaker_outs; 299181937d3bSSteve Longerbeam memcpy(cfg->line_out_pins, cfg->speaker_pins, 299281937d3bSSteve Longerbeam sizeof(cfg->speaker_pins)); 299381937d3bSSteve Longerbeam cfg->speaker_outs = 0; 299481937d3bSSteve Longerbeam memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 299581937d3bSSteve Longerbeam cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 299681937d3bSSteve Longerbeam } else if (cfg->hp_outs) { 299781937d3bSSteve Longerbeam cfg->line_outs = cfg->hp_outs; 299881937d3bSSteve Longerbeam memcpy(cfg->line_out_pins, cfg->hp_pins, 299981937d3bSSteve Longerbeam sizeof(cfg->hp_pins)); 300081937d3bSSteve Longerbeam cfg->hp_outs = 0; 300181937d3bSSteve Longerbeam memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 300281937d3bSSteve Longerbeam cfg->line_out_type = AUTO_PIN_HP_OUT; 300381937d3bSSteve Longerbeam } 3004e9edcee0STakashi Iwai } 3005e9edcee0STakashi Iwai 3006cb8e2f83STakashi Iwai /* Reorder the surround channels 3007cb8e2f83STakashi Iwai * ALSA sequence is front/surr/clfe/side 3008cb8e2f83STakashi Iwai * HDA sequence is: 3009cb8e2f83STakashi Iwai * 4-ch: front/surr => OK as it is 3010cb8e2f83STakashi Iwai * 6-ch: front/clfe/surr 30119422db40STakashi Iwai * 8-ch: front/clfe/rear/side|fc 3012cb8e2f83STakashi Iwai */ 3013cb8e2f83STakashi Iwai switch (cfg->line_outs) { 3014cb8e2f83STakashi Iwai case 3: 3015cb8e2f83STakashi Iwai case 4: 3016cb8e2f83STakashi Iwai nid = cfg->line_out_pins[1]; 30179422db40STakashi Iwai cfg->line_out_pins[1] = cfg->line_out_pins[2]; 3018cb8e2f83STakashi Iwai cfg->line_out_pins[2] = nid; 3019cb8e2f83STakashi Iwai break; 3020e9edcee0STakashi Iwai } 3021e9edcee0STakashi Iwai 302282bc955fSTakashi Iwai /* 302382bc955fSTakashi Iwai * debug prints of the parsed results 302482bc955fSTakashi Iwai */ 302582bc955fSTakashi Iwai snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", 302682bc955fSTakashi Iwai cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], 302782bc955fSTakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 302882bc955fSTakashi Iwai cfg->line_out_pins[4]); 302982bc955fSTakashi Iwai snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", 303082bc955fSTakashi Iwai cfg->speaker_outs, cfg->speaker_pins[0], 303182bc955fSTakashi Iwai cfg->speaker_pins[1], cfg->speaker_pins[2], 303282bc955fSTakashi Iwai cfg->speaker_pins[3], cfg->speaker_pins[4]); 3033eb06ed8fSTakashi Iwai snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", 3034eb06ed8fSTakashi Iwai cfg->hp_outs, cfg->hp_pins[0], 3035eb06ed8fSTakashi Iwai cfg->hp_pins[1], cfg->hp_pins[2], 3036eb06ed8fSTakashi Iwai cfg->hp_pins[3], cfg->hp_pins[4]); 303790da78bfSMatthew Ranostay snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); 303882bc955fSTakashi Iwai snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," 303982bc955fSTakashi Iwai " cd=0x%x, aux=0x%x\n", 304082bc955fSTakashi Iwai cfg->input_pins[AUTO_PIN_MIC], 304182bc955fSTakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_MIC], 304282bc955fSTakashi Iwai cfg->input_pins[AUTO_PIN_LINE], 304382bc955fSTakashi Iwai cfg->input_pins[AUTO_PIN_FRONT_LINE], 304482bc955fSTakashi Iwai cfg->input_pins[AUTO_PIN_CD], 304582bc955fSTakashi Iwai cfg->input_pins[AUTO_PIN_AUX]); 304682bc955fSTakashi Iwai 3047e9edcee0STakashi Iwai return 0; 3048e9edcee0STakashi Iwai } 3049e9edcee0STakashi Iwai 30504a471b7dSTakashi Iwai /* labels for input pins */ 30514a471b7dSTakashi Iwai const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { 30524a471b7dSTakashi Iwai "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" 30534a471b7dSTakashi Iwai }; 30544a471b7dSTakashi Iwai 30554a471b7dSTakashi Iwai 30561da177e4SLinus Torvalds #ifdef CONFIG_PM 30571da177e4SLinus Torvalds /* 30581da177e4SLinus Torvalds * power management 30591da177e4SLinus Torvalds */ 30601da177e4SLinus Torvalds 30611da177e4SLinus Torvalds /** 30621da177e4SLinus Torvalds * snd_hda_suspend - suspend the codecs 30631da177e4SLinus Torvalds * @bus: the HDA bus 30641da177e4SLinus Torvalds * @state: suspsend state 30651da177e4SLinus Torvalds * 30661da177e4SLinus Torvalds * Returns 0 if successful. 30671da177e4SLinus Torvalds */ 30681da177e4SLinus Torvalds int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) 30691da177e4SLinus Torvalds { 30700ba21762STakashi Iwai struct hda_codec *codec; 30711da177e4SLinus Torvalds 30720ba21762STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 30730b7a2e9cSTakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 30740b7a2e9cSTakashi Iwai if (!codec->power_on) 30750b7a2e9cSTakashi Iwai continue; 30760b7a2e9cSTakashi Iwai #endif 3077cb53c626STakashi Iwai hda_call_codec_suspend(codec); 30781da177e4SLinus Torvalds } 30791da177e4SLinus Torvalds return 0; 30801da177e4SLinus Torvalds } 30811da177e4SLinus Torvalds 30821da177e4SLinus Torvalds /** 30831da177e4SLinus Torvalds * snd_hda_resume - resume the codecs 30841da177e4SLinus Torvalds * @bus: the HDA bus 30851da177e4SLinus Torvalds * @state: resume state 30861da177e4SLinus Torvalds * 30871da177e4SLinus Torvalds * Returns 0 if successful. 3088cb53c626STakashi Iwai * 3089cb53c626STakashi Iwai * This fucntion is defined only when POWER_SAVE isn't set. 3090cb53c626STakashi Iwai * In the power-save mode, the codec is resumed dynamically. 30911da177e4SLinus Torvalds */ 30921da177e4SLinus Torvalds int snd_hda_resume(struct hda_bus *bus) 30931da177e4SLinus Torvalds { 30940ba21762STakashi Iwai struct hda_codec *codec; 30951da177e4SLinus Torvalds 30960ba21762STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 3097d804ad92SMaxim Levitsky if (snd_hda_codec_needs_resume(codec)) 3098cb53c626STakashi Iwai hda_call_codec_resume(codec); 30991da177e4SLinus Torvalds } 31001da177e4SLinus Torvalds return 0; 31011da177e4SLinus Torvalds } 3102d804ad92SMaxim Levitsky #ifdef CONFIG_SND_HDA_POWER_SAVE 3103d804ad92SMaxim Levitsky int snd_hda_codecs_inuse(struct hda_bus *bus) 3104d804ad92SMaxim Levitsky { 3105d804ad92SMaxim Levitsky struct hda_codec *codec; 31061da177e4SLinus Torvalds 3107d804ad92SMaxim Levitsky list_for_each_entry(codec, &bus->codec_list, list) { 3108d804ad92SMaxim Levitsky if (snd_hda_codec_needs_resume(codec)) 3109d804ad92SMaxim Levitsky return 1; 3110d804ad92SMaxim Levitsky } 3111d804ad92SMaxim Levitsky return 0; 3112d804ad92SMaxim Levitsky } 3113d804ad92SMaxim Levitsky #endif 31141da177e4SLinus Torvalds #endif 3115