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 2218478e8bSTakashi Iwai #include <linux/mm.h> 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/delay.h> 251da177e4SLinus Torvalds #include <linux/slab.h> 261da177e4SLinus Torvalds #include <linux/pci.h> 2762932df8SIngo Molnar #include <linux/mutex.h> 28da155d5bSPaul Gortmaker #include <linux/module.h> 291da177e4SLinus Torvalds #include <sound/core.h> 301da177e4SLinus Torvalds #include "hda_codec.h" 311da177e4SLinus Torvalds #include <sound/asoundef.h> 32302e9c5aSJaroslav Kysela #include <sound/tlv.h> 331da177e4SLinus Torvalds #include <sound/initval.h> 34cd372fb3STakashi Iwai #include <sound/jack.h> 351da177e4SLinus Torvalds #include "hda_local.h" 36123c07aeSJaroslav Kysela #include "hda_beep.h" 371835a0f9STakashi Iwai #include "hda_jack.h" 382807314dSTakashi Iwai #include <sound/hda_hwdep.h> 391da177e4SLinus Torvalds 40d66fee5dSTakashi Iwai #define CREATE_TRACE_POINTS 41d66fee5dSTakashi Iwai #include "hda_trace.h" 42d66fee5dSTakashi Iwai 431da177e4SLinus Torvalds /* 441da177e4SLinus Torvalds * vendor / preset table 451da177e4SLinus Torvalds */ 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds struct hda_vendor_id { 481da177e4SLinus Torvalds unsigned int id; 491da177e4SLinus Torvalds const char *name; 501da177e4SLinus Torvalds }; 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds /* codec vendor labels */ 531da177e4SLinus Torvalds static struct hda_vendor_id hda_vendor_ids[] = { 54c8cd1281STakashi Iwai { 0x1002, "ATI" }, 55e5f14248STakashi Iwai { 0x1013, "Cirrus Logic" }, 56a9226251STakashi Iwai { 0x1057, "Motorola" }, 57c8cd1281STakashi Iwai { 0x1095, "Silicon Image" }, 5831117b78STakashi Iwai { 0x10de, "Nvidia" }, 59c8cd1281STakashi Iwai { 0x10ec, "Realtek" }, 604e01f54bSTakashi Iwai { 0x1102, "Creative" }, 61c577b8a1SJoseph Chan { 0x1106, "VIA" }, 627f16859aSMatthew Ranostay { 0x111d, "IDT" }, 63c8cd1281STakashi Iwai { 0x11c1, "LSI" }, 6454b903ecSTakashi Iwai { 0x11d4, "Analog Devices" }, 651da177e4SLinus Torvalds { 0x13f6, "C-Media" }, 66a9226251STakashi Iwai { 0x14f1, "Conexant" }, 67c8cd1281STakashi Iwai { 0x17e8, "Chrontel" }, 68c8cd1281STakashi Iwai { 0x1854, "LG" }, 698199de3bSMark Brown { 0x1aec, "Wolfson Microelectronics" }, 701da177e4SLinus Torvalds { 0x434d, "C-Media" }, 7174c61133STakashi Iwai { 0x8086, "Intel" }, 722f2f4251SMatt { 0x8384, "SigmaTel" }, 731da177e4SLinus Torvalds {} /* terminator */ 741da177e4SLinus Torvalds }; 751da177e4SLinus Torvalds 761289e9e8STakashi Iwai static DEFINE_MUTEX(preset_mutex); 771289e9e8STakashi Iwai static LIST_HEAD(hda_preset_tables); 781289e9e8STakashi Iwai 791289e9e8STakashi Iwai int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) 801289e9e8STakashi Iwai { 811289e9e8STakashi Iwai mutex_lock(&preset_mutex); 821289e9e8STakashi Iwai list_add_tail(&preset->list, &hda_preset_tables); 831289e9e8STakashi Iwai mutex_unlock(&preset_mutex); 841289e9e8STakashi Iwai return 0; 851289e9e8STakashi Iwai } 86ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_codec_preset); 871289e9e8STakashi Iwai 881289e9e8STakashi Iwai int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) 891289e9e8STakashi Iwai { 901289e9e8STakashi Iwai mutex_lock(&preset_mutex); 911289e9e8STakashi Iwai list_del(&preset->list); 921289e9e8STakashi Iwai mutex_unlock(&preset_mutex); 931289e9e8STakashi Iwai return 0; 941289e9e8STakashi Iwai } 95ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); 961da177e4SLinus Torvalds 9783012a7cSTakashi Iwai #ifdef CONFIG_PM 98d846b174STakashi Iwai #define codec_in_pm(codec) ((codec)->in_pm) 99cb53c626STakashi Iwai static void hda_power_work(struct work_struct *work); 100cb53c626STakashi Iwai static void hda_keep_power_on(struct hda_codec *codec); 101e581f3dbSTakashi Iwai #define hda_codec_is_power_on(codec) ((codec)->power_on) 10268467f51STakashi Iwai static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up) 10368467f51STakashi Iwai { 10468467f51STakashi Iwai if (bus->ops.pm_notify) 10568467f51STakashi Iwai bus->ops.pm_notify(bus, power_up); 10668467f51STakashi Iwai } 107cb53c626STakashi Iwai #else 108d846b174STakashi Iwai #define codec_in_pm(codec) 0 109cb53c626STakashi Iwai static inline void hda_keep_power_on(struct hda_codec *codec) {} 110e581f3dbSTakashi Iwai #define hda_codec_is_power_on(codec) 1 11168467f51STakashi Iwai #define hda_call_pm_notify(bus, state) {} 112cb53c626STakashi Iwai #endif 113cb53c626STakashi Iwai 114d5191e50STakashi Iwai /** 115d5191e50STakashi Iwai * snd_hda_get_jack_location - Give a location string of the jack 116d5191e50STakashi Iwai * @cfg: pin default config value 117d5191e50STakashi Iwai * 118d5191e50STakashi Iwai * Parse the pin default config value and returns the string of the 119d5191e50STakashi Iwai * jack location, e.g. "Rear", "Front", etc. 120d5191e50STakashi Iwai */ 12150a9f790SMatthew Ranostay const char *snd_hda_get_jack_location(u32 cfg) 12250a9f790SMatthew Ranostay { 12350a9f790SMatthew Ranostay static char *bases[7] = { 12450a9f790SMatthew Ranostay "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", 12550a9f790SMatthew Ranostay }; 12650a9f790SMatthew Ranostay static unsigned char specials_idx[] = { 12750a9f790SMatthew Ranostay 0x07, 0x08, 12850a9f790SMatthew Ranostay 0x17, 0x18, 0x19, 12950a9f790SMatthew Ranostay 0x37, 0x38 13050a9f790SMatthew Ranostay }; 13150a9f790SMatthew Ranostay static char *specials[] = { 13250a9f790SMatthew Ranostay "Rear Panel", "Drive Bar", 13350a9f790SMatthew Ranostay "Riser", "HDMI", "ATAPI", 13450a9f790SMatthew Ranostay "Mobile-In", "Mobile-Out" 13550a9f790SMatthew Ranostay }; 13650a9f790SMatthew Ranostay int i; 13750a9f790SMatthew Ranostay cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; 13850a9f790SMatthew Ranostay if ((cfg & 0x0f) < 7) 13950a9f790SMatthew Ranostay return bases[cfg & 0x0f]; 14050a9f790SMatthew Ranostay for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { 14150a9f790SMatthew Ranostay if (cfg == specials_idx[i]) 14250a9f790SMatthew Ranostay return specials[i]; 14350a9f790SMatthew Ranostay } 14450a9f790SMatthew Ranostay return "UNKNOWN"; 14550a9f790SMatthew Ranostay } 146ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_jack_location); 14750a9f790SMatthew Ranostay 148d5191e50STakashi Iwai /** 149d5191e50STakashi Iwai * snd_hda_get_jack_connectivity - Give a connectivity string of the jack 150d5191e50STakashi Iwai * @cfg: pin default config value 151d5191e50STakashi Iwai * 152d5191e50STakashi Iwai * Parse the pin default config value and returns the string of the 153d5191e50STakashi Iwai * jack connectivity, i.e. external or internal connection. 154d5191e50STakashi Iwai */ 15550a9f790SMatthew Ranostay const char *snd_hda_get_jack_connectivity(u32 cfg) 15650a9f790SMatthew Ranostay { 15750a9f790SMatthew Ranostay static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; 15850a9f790SMatthew Ranostay 15950a9f790SMatthew Ranostay return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; 16050a9f790SMatthew Ranostay } 161ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity); 16250a9f790SMatthew Ranostay 163d5191e50STakashi Iwai /** 164d5191e50STakashi Iwai * snd_hda_get_jack_type - Give a type string of the jack 165d5191e50STakashi Iwai * @cfg: pin default config value 166d5191e50STakashi Iwai * 167d5191e50STakashi Iwai * Parse the pin default config value and returns the string of the 168d5191e50STakashi Iwai * jack type, i.e. the purpose of the jack, such as Line-Out or CD. 169d5191e50STakashi Iwai */ 17050a9f790SMatthew Ranostay const char *snd_hda_get_jack_type(u32 cfg) 17150a9f790SMatthew Ranostay { 17250a9f790SMatthew Ranostay static char *jack_types[16] = { 17350a9f790SMatthew Ranostay "Line Out", "Speaker", "HP Out", "CD", 17450a9f790SMatthew Ranostay "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", 17550a9f790SMatthew Ranostay "Line In", "Aux", "Mic", "Telephony", 17650a9f790SMatthew Ranostay "SPDIF In", "Digitial In", "Reserved", "Other" 17750a9f790SMatthew Ranostay }; 17850a9f790SMatthew Ranostay 17950a9f790SMatthew Ranostay return jack_types[(cfg & AC_DEFCFG_DEVICE) 18050a9f790SMatthew Ranostay >> AC_DEFCFG_DEVICE_SHIFT]; 18150a9f790SMatthew Ranostay } 182ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_jack_type); 18350a9f790SMatthew Ranostay 18433fa35edSTakashi Iwai /* 18533fa35edSTakashi Iwai * Compose a 32bit command word to be sent to the HD-audio controller 18633fa35edSTakashi Iwai */ 18733fa35edSTakashi Iwai static inline unsigned int 18833fa35edSTakashi Iwai make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, 18933fa35edSTakashi Iwai unsigned int verb, unsigned int parm) 19033fa35edSTakashi Iwai { 19133fa35edSTakashi Iwai u32 val; 19233fa35edSTakashi Iwai 19382e1b804STakashi Iwai if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) || 19482e1b804STakashi Iwai (verb & ~0xfff) || (parm & ~0xffff)) { 1956430aeebSWu Fengguang printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n", 1966430aeebSWu Fengguang codec->addr, direct, nid, verb, parm); 1976430aeebSWu Fengguang return ~0; 1986430aeebSWu Fengguang } 1996430aeebSWu Fengguang 2006430aeebSWu Fengguang val = (u32)codec->addr << 28; 20133fa35edSTakashi Iwai val |= (u32)direct << 27; 20233fa35edSTakashi Iwai val |= (u32)nid << 20; 20333fa35edSTakashi Iwai val |= verb << 8; 20433fa35edSTakashi Iwai val |= parm; 20533fa35edSTakashi Iwai return val; 20633fa35edSTakashi Iwai } 20733fa35edSTakashi Iwai 208aa2936f5STakashi Iwai /* 209aa2936f5STakashi Iwai * Send and receive a verb 210aa2936f5STakashi Iwai */ 211aa2936f5STakashi Iwai static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, 212aa2936f5STakashi Iwai unsigned int *res) 213aa2936f5STakashi Iwai { 214aa2936f5STakashi Iwai struct hda_bus *bus = codec->bus; 2158dd78330STakashi Iwai int err; 216aa2936f5STakashi Iwai 2176430aeebSWu Fengguang if (cmd == ~0) 2186430aeebSWu Fengguang return -1; 2196430aeebSWu Fengguang 220aa2936f5STakashi Iwai if (res) 221aa2936f5STakashi Iwai *res = -1; 2228dd78330STakashi Iwai again: 223aa2936f5STakashi Iwai snd_hda_power_up(codec); 224aa2936f5STakashi Iwai mutex_lock(&bus->cmd_mutex); 2253bcce5c0STakashi Iwai for (;;) { 226d66fee5dSTakashi Iwai trace_hda_send_cmd(codec, cmd); 227aa2936f5STakashi Iwai err = bus->ops.command(bus, cmd); 2283bcce5c0STakashi Iwai if (err != -EAGAIN) 2293bcce5c0STakashi Iwai break; 2303bcce5c0STakashi Iwai /* process pending verbs */ 2313bcce5c0STakashi Iwai bus->ops.get_response(bus, codec->addr); 2323bcce5c0STakashi Iwai } 233d66fee5dSTakashi Iwai if (!err && res) { 234deadff16SWu Fengguang *res = bus->ops.get_response(bus, codec->addr); 235d66fee5dSTakashi Iwai trace_hda_get_response(codec, *res); 236d66fee5dSTakashi Iwai } 237aa2936f5STakashi Iwai mutex_unlock(&bus->cmd_mutex); 238aa2936f5STakashi Iwai snd_hda_power_down(codec); 239d846b174STakashi Iwai if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) { 2408dd78330STakashi Iwai if (bus->response_reset) { 2418dd78330STakashi Iwai snd_printd("hda_codec: resetting BUS due to " 2428dd78330STakashi Iwai "fatal communication error\n"); 243d66fee5dSTakashi Iwai trace_hda_bus_reset(bus); 2448dd78330STakashi Iwai bus->ops.bus_reset(bus); 2458dd78330STakashi Iwai } 2468dd78330STakashi Iwai goto again; 2478dd78330STakashi Iwai } 2488dd78330STakashi Iwai /* clear reset-flag when the communication gets recovered */ 249d846b174STakashi Iwai if (!err || codec_in_pm(codec)) 2508dd78330STakashi Iwai bus->response_reset = 0; 251aa2936f5STakashi Iwai return err; 252aa2936f5STakashi Iwai } 253aa2936f5STakashi Iwai 2541da177e4SLinus Torvalds /** 2551da177e4SLinus Torvalds * snd_hda_codec_read - send a command and get the response 2561da177e4SLinus Torvalds * @codec: the HDA codec 2571da177e4SLinus Torvalds * @nid: NID to send the command 2581da177e4SLinus Torvalds * @direct: direct flag 2591da177e4SLinus Torvalds * @verb: the verb to send 2601da177e4SLinus Torvalds * @parm: the parameter for the verb 2611da177e4SLinus Torvalds * 2621da177e4SLinus Torvalds * Send a single command and read the corresponding response. 2631da177e4SLinus Torvalds * 2641da177e4SLinus Torvalds * Returns the obtained response value, or -1 for an error. 2651da177e4SLinus Torvalds */ 2660ba21762STakashi Iwai unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, 2670ba21762STakashi Iwai int direct, 2681da177e4SLinus Torvalds unsigned int verb, unsigned int parm) 2691da177e4SLinus Torvalds { 270aa2936f5STakashi Iwai unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); 271aa2936f5STakashi Iwai unsigned int res; 2729857edfdSGreg Thelen if (codec_exec_verb(codec, cmd, &res)) 2739857edfdSGreg Thelen return -1; 2741da177e4SLinus Torvalds return res; 2751da177e4SLinus Torvalds } 276ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_read); 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds /** 2791da177e4SLinus Torvalds * snd_hda_codec_write - send a single command without waiting for response 2801da177e4SLinus Torvalds * @codec: the HDA codec 2811da177e4SLinus Torvalds * @nid: NID to send the command 2821da177e4SLinus Torvalds * @direct: direct flag 2831da177e4SLinus Torvalds * @verb: the verb to send 2841da177e4SLinus Torvalds * @parm: the parameter for the verb 2851da177e4SLinus Torvalds * 2861da177e4SLinus Torvalds * Send a single command without waiting for response. 2871da177e4SLinus Torvalds * 2881da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, 2911da177e4SLinus Torvalds unsigned int verb, unsigned int parm) 2921da177e4SLinus Torvalds { 293aa2936f5STakashi Iwai unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); 29433fa35edSTakashi Iwai unsigned int res; 295b20f3b83STakashi Iwai return codec_exec_verb(codec, cmd, 296b20f3b83STakashi Iwai codec->bus->sync_write ? &res : NULL); 2971da177e4SLinus Torvalds } 298ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_write); 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /** 3011da177e4SLinus Torvalds * snd_hda_sequence_write - sequence writes 3021da177e4SLinus Torvalds * @codec: the HDA codec 3031da177e4SLinus Torvalds * @seq: VERB array to send 3041da177e4SLinus Torvalds * 3051da177e4SLinus Torvalds * Send the commands sequentially from the given array. 3061da177e4SLinus Torvalds * The array must be terminated with NID=0. 3071da177e4SLinus Torvalds */ 3081da177e4SLinus Torvalds void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds for (; seq->nid; seq++) 3111da177e4SLinus Torvalds snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); 3121da177e4SLinus Torvalds } 313ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_sequence_write); 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds /** 3161da177e4SLinus Torvalds * snd_hda_get_sub_nodes - get the range of sub nodes 3171da177e4SLinus Torvalds * @codec: the HDA codec 3181da177e4SLinus Torvalds * @nid: NID to parse 3191da177e4SLinus Torvalds * @start_id: the pointer to store the start NID 3201da177e4SLinus Torvalds * 3211da177e4SLinus Torvalds * Parse the NID and store the start NID of its sub-nodes. 3221da177e4SLinus Torvalds * Returns the number of sub-nodes. 3231da177e4SLinus Torvalds */ 3240ba21762STakashi Iwai int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, 3250ba21762STakashi Iwai hda_nid_t *start_id) 3261da177e4SLinus Torvalds { 3271da177e4SLinus Torvalds unsigned int parm; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); 330e8a7f136SDanny Tholen if (parm == -1) 331e8a7f136SDanny Tholen return 0; 3321da177e4SLinus Torvalds *start_id = (parm >> 16) & 0x7fff; 3331da177e4SLinus Torvalds return (int)(parm & 0x7fff); 3341da177e4SLinus Torvalds } 335ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); 3361da177e4SLinus Torvalds 337ee8e765bSTakashi Iwai /* connection list element */ 338ee8e765bSTakashi Iwai struct hda_conn_list { 339ee8e765bSTakashi Iwai struct list_head list; 340ee8e765bSTakashi Iwai int len; 341ee8e765bSTakashi Iwai hda_nid_t nid; 342ee8e765bSTakashi Iwai hda_nid_t conns[0]; 343ee8e765bSTakashi Iwai }; 344ee8e765bSTakashi Iwai 345b2f934a0STakashi Iwai /* look up the cached results */ 346ee8e765bSTakashi Iwai static struct hda_conn_list * 347ee8e765bSTakashi Iwai lookup_conn_list(struct hda_codec *codec, hda_nid_t nid) 348b2f934a0STakashi Iwai { 349ee8e765bSTakashi Iwai struct hda_conn_list *p; 350ee8e765bSTakashi Iwai list_for_each_entry(p, &codec->conn_list, list) { 351ee8e765bSTakashi Iwai if (p->nid == nid) 352b2f934a0STakashi Iwai return p; 353b2f934a0STakashi Iwai } 354b2f934a0STakashi Iwai return NULL; 355b2f934a0STakashi Iwai } 356a12d3e1eSTakashi Iwai 357ee8e765bSTakashi Iwai static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, 358ee8e765bSTakashi Iwai const hda_nid_t *list) 359ee8e765bSTakashi Iwai { 360ee8e765bSTakashi Iwai struct hda_conn_list *p; 361ee8e765bSTakashi Iwai 362ee8e765bSTakashi Iwai p = kmalloc(sizeof(*p) + len * sizeof(hda_nid_t), GFP_KERNEL); 363ee8e765bSTakashi Iwai if (!p) 364ee8e765bSTakashi Iwai return -ENOMEM; 365ee8e765bSTakashi Iwai p->len = len; 366ee8e765bSTakashi Iwai p->nid = nid; 367ee8e765bSTakashi Iwai memcpy(p->conns, list, len * sizeof(hda_nid_t)); 368ee8e765bSTakashi Iwai list_add(&p->list, &codec->conn_list); 369ee8e765bSTakashi Iwai return 0; 370ee8e765bSTakashi Iwai } 371ee8e765bSTakashi Iwai 372ee8e765bSTakashi Iwai static void remove_conn_list(struct hda_codec *codec) 373ee8e765bSTakashi Iwai { 374ee8e765bSTakashi Iwai while (!list_empty(&codec->conn_list)) { 375ee8e765bSTakashi Iwai struct hda_conn_list *p; 376ee8e765bSTakashi Iwai p = list_first_entry(&codec->conn_list, typeof(*p), list); 377ee8e765bSTakashi Iwai list_del(&p->list); 378ee8e765bSTakashi Iwai kfree(p); 379ee8e765bSTakashi Iwai } 380ee8e765bSTakashi Iwai } 381ee8e765bSTakashi Iwai 382b2f934a0STakashi Iwai /* read the connection and add to the cache */ 38309cf03b8STakashi Iwai static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) 38409cf03b8STakashi Iwai { 385*4eea3091STakashi Iwai hda_nid_t list[32]; 386*4eea3091STakashi Iwai hda_nid_t *result = list; 38709cf03b8STakashi Iwai int len; 38809cf03b8STakashi Iwai 38909cf03b8STakashi Iwai len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list)); 390*4eea3091STakashi Iwai if (len == -ENOSPC) { 391*4eea3091STakashi Iwai len = snd_hda_get_num_raw_conns(codec, nid); 392*4eea3091STakashi Iwai result = kmalloc(sizeof(hda_nid_t) * len, GFP_KERNEL); 393*4eea3091STakashi Iwai if (!result) 394*4eea3091STakashi Iwai return -ENOMEM; 395*4eea3091STakashi Iwai len = snd_hda_get_raw_connections(codec, nid, result, len); 396*4eea3091STakashi Iwai } 397*4eea3091STakashi Iwai if (len >= 0) 398*4eea3091STakashi Iwai len = snd_hda_override_conn_list(codec, nid, len, result); 399*4eea3091STakashi Iwai if (result != list) 400*4eea3091STakashi Iwai kfree(result); 401a12d3e1eSTakashi Iwai return len; 402a12d3e1eSTakashi Iwai } 403dce2079bSTakashi Iwai 404dce2079bSTakashi Iwai /** 405ee8e765bSTakashi Iwai * snd_hda_get_conn_list - get connection list 406ee8e765bSTakashi Iwai * @codec: the HDA codec 407ee8e765bSTakashi Iwai * @nid: NID to parse 408ee8e765bSTakashi Iwai * @len: number of connection list entries 409ee8e765bSTakashi Iwai * @listp: the pointer to store NID list 410ee8e765bSTakashi Iwai * 411ee8e765bSTakashi Iwai * Parses the connection list of the given widget and stores the pointer 412ee8e765bSTakashi Iwai * to the list of NIDs. 413ee8e765bSTakashi Iwai * 414ee8e765bSTakashi Iwai * Returns the number of connections, or a negative error code. 415ee8e765bSTakashi Iwai * 416ee8e765bSTakashi Iwai * Note that the returned pointer isn't protected against the list 417ee8e765bSTakashi Iwai * modification. If snd_hda_override_conn_list() might be called 418ee8e765bSTakashi Iwai * concurrently, protect with a mutex appropriately. 419ee8e765bSTakashi Iwai */ 420ee8e765bSTakashi Iwai int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, 421ee8e765bSTakashi Iwai const hda_nid_t **listp) 422ee8e765bSTakashi Iwai { 423ee8e765bSTakashi Iwai bool added = false; 424ee8e765bSTakashi Iwai 425ee8e765bSTakashi Iwai for (;;) { 426ee8e765bSTakashi Iwai int err; 427ee8e765bSTakashi Iwai const struct hda_conn_list *p; 428ee8e765bSTakashi Iwai 429ee8e765bSTakashi Iwai /* if the connection-list is already cached, read it */ 430ee8e765bSTakashi Iwai p = lookup_conn_list(codec, nid); 431ee8e765bSTakashi Iwai if (p) { 432ee8e765bSTakashi Iwai if (listp) 433ee8e765bSTakashi Iwai *listp = p->conns; 434ee8e765bSTakashi Iwai return p->len; 435ee8e765bSTakashi Iwai } 436ee8e765bSTakashi Iwai if (snd_BUG_ON(added)) 437ee8e765bSTakashi Iwai return -EINVAL; 438ee8e765bSTakashi Iwai 439ee8e765bSTakashi Iwai err = read_and_add_raw_conns(codec, nid); 440ee8e765bSTakashi Iwai if (err < 0) 441ee8e765bSTakashi Iwai return err; 442ee8e765bSTakashi Iwai added = true; 443ee8e765bSTakashi Iwai } 444ee8e765bSTakashi Iwai } 445ee8e765bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_conn_list); 446ee8e765bSTakashi Iwai 447ee8e765bSTakashi Iwai /** 448dce2079bSTakashi Iwai * snd_hda_get_connections - copy connection list 4491da177e4SLinus Torvalds * @codec: the HDA codec 4501da177e4SLinus Torvalds * @nid: NID to parse 45109cf03b8STakashi Iwai * @conn_list: connection list array; when NULL, checks only the size 4521da177e4SLinus Torvalds * @max_conns: max. number of connections to store 4531da177e4SLinus Torvalds * 4541da177e4SLinus Torvalds * Parses the connection list of the given widget and stores the list 4551da177e4SLinus Torvalds * of NIDs. 4561da177e4SLinus Torvalds * 4571da177e4SLinus Torvalds * Returns the number of connections, or a negative error code. 4581da177e4SLinus Torvalds */ 4591da177e4SLinus Torvalds int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, 4601da177e4SLinus Torvalds hda_nid_t *conn_list, int max_conns) 4611da177e4SLinus Torvalds { 462ee8e765bSTakashi Iwai const hda_nid_t *list; 463ee8e765bSTakashi Iwai int len = snd_hda_get_conn_list(codec, nid, &list); 464a12d3e1eSTakashi Iwai 465ee8e765bSTakashi Iwai if (len > 0 && conn_list) { 466ee8e765bSTakashi Iwai if (len > max_conns) { 467dce2079bSTakashi Iwai snd_printk(KERN_ERR "hda_codec: " 468dce2079bSTakashi Iwai "Too many connections %d for NID 0x%x\n", 469dce2079bSTakashi Iwai len, nid); 470dce2079bSTakashi Iwai return -EINVAL; 471dce2079bSTakashi Iwai } 472ee8e765bSTakashi Iwai memcpy(conn_list, list, len * sizeof(hda_nid_t)); 47309cf03b8STakashi Iwai } 47409cf03b8STakashi Iwai 47509cf03b8STakashi Iwai return len; 476a12d3e1eSTakashi Iwai } 477a12d3e1eSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_connections); 478a12d3e1eSTakashi Iwai 479*4eea3091STakashi Iwai /* return CONNLIST_LEN parameter of the given widget */ 480*4eea3091STakashi Iwai static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid) 481*4eea3091STakashi Iwai { 482*4eea3091STakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 483*4eea3091STakashi Iwai unsigned int parm; 484*4eea3091STakashi Iwai 485*4eea3091STakashi Iwai if (!(wcaps & AC_WCAP_CONN_LIST) && 486*4eea3091STakashi Iwai get_wcaps_type(wcaps) != AC_WID_VOL_KNB) 487*4eea3091STakashi Iwai return 0; 488*4eea3091STakashi Iwai 489*4eea3091STakashi Iwai parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); 490*4eea3091STakashi Iwai if (parm == -1) 491*4eea3091STakashi Iwai parm = 0; 492*4eea3091STakashi Iwai return parm; 493*4eea3091STakashi Iwai } 494*4eea3091STakashi Iwai 495*4eea3091STakashi Iwai int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid) 496*4eea3091STakashi Iwai { 497*4eea3091STakashi Iwai return get_num_conns(codec, nid) & AC_CLIST_LENGTH; 498*4eea3091STakashi Iwai } 499*4eea3091STakashi Iwai 5009e7717c9STakashi Iwai /** 5019e7717c9STakashi Iwai * snd_hda_get_raw_connections - copy connection list without cache 5029e7717c9STakashi Iwai * @codec: the HDA codec 5039e7717c9STakashi Iwai * @nid: NID to parse 5049e7717c9STakashi Iwai * @conn_list: connection list array 5059e7717c9STakashi Iwai * @max_conns: max. number of connections to store 5069e7717c9STakashi Iwai * 5079e7717c9STakashi Iwai * Like snd_hda_get_connections(), copy the connection list but without 5089e7717c9STakashi Iwai * checking through the connection-list cache. 5099e7717c9STakashi Iwai * Currently called only from hda_proc.c, so not exported. 5109e7717c9STakashi Iwai */ 5119e7717c9STakashi Iwai int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, 512a12d3e1eSTakashi Iwai hda_nid_t *conn_list, int max_conns) 513a12d3e1eSTakashi Iwai { 5141da177e4SLinus Torvalds unsigned int parm; 51554d17403STakashi Iwai int i, conn_len, conns; 5161da177e4SLinus Torvalds unsigned int shift, num_elems, mask; 51754d17403STakashi Iwai hda_nid_t prev_nid; 5185fdaecdbSTakashi Iwai int null_count = 0; 5191da177e4SLinus Torvalds 520da3cec35STakashi Iwai if (snd_BUG_ON(!conn_list || max_conns <= 0)) 521da3cec35STakashi Iwai return -EINVAL; 5221da177e4SLinus Torvalds 523*4eea3091STakashi Iwai parm = get_num_conns(codec, nid); 524*4eea3091STakashi Iwai if (!parm) 5258d087c76STakashi Iwai return 0; 52616a433d8SJaroslav Kysela 5271da177e4SLinus Torvalds if (parm & AC_CLIST_LONG) { 5281da177e4SLinus Torvalds /* long form */ 5291da177e4SLinus Torvalds shift = 16; 5301da177e4SLinus Torvalds num_elems = 2; 5311da177e4SLinus Torvalds } else { 5321da177e4SLinus Torvalds /* short form */ 5331da177e4SLinus Torvalds shift = 8; 5341da177e4SLinus Torvalds num_elems = 4; 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds conn_len = parm & AC_CLIST_LENGTH; 5371da177e4SLinus Torvalds mask = (1 << (shift-1)) - 1; 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds if (!conn_len) 5401da177e4SLinus Torvalds return 0; /* no connection */ 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds if (conn_len == 1) { 5431da177e4SLinus Torvalds /* single connection */ 5440ba21762STakashi Iwai parm = snd_hda_codec_read(codec, nid, 0, 5450ba21762STakashi Iwai AC_VERB_GET_CONNECT_LIST, 0); 5463c6aae44STakashi Iwai if (parm == -1 && codec->bus->rirb_error) 5473c6aae44STakashi Iwai return -EIO; 5481da177e4SLinus Torvalds conn_list[0] = parm & mask; 5491da177e4SLinus Torvalds return 1; 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds /* multi connection */ 5531da177e4SLinus Torvalds conns = 0; 55454d17403STakashi Iwai prev_nid = 0; 55554d17403STakashi Iwai for (i = 0; i < conn_len; i++) { 5561da177e4SLinus Torvalds int range_val; 55754d17403STakashi Iwai hda_nid_t val, n; 55854d17403STakashi Iwai 5593c6aae44STakashi Iwai if (i % num_elems == 0) { 56054d17403STakashi Iwai parm = snd_hda_codec_read(codec, nid, 0, 56154d17403STakashi Iwai AC_VERB_GET_CONNECT_LIST, i); 5623c6aae44STakashi Iwai if (parm == -1 && codec->bus->rirb_error) 5633c6aae44STakashi Iwai return -EIO; 5643c6aae44STakashi Iwai } 56554d17403STakashi Iwai range_val = !!(parm & (1 << (shift-1))); /* ranges */ 56654d17403STakashi Iwai val = parm & mask; 5675fdaecdbSTakashi Iwai if (val == 0 && null_count++) { /* no second chance */ 5682e9bf247SJaroslav Kysela snd_printk(KERN_WARNING "hda_codec: " 5692e9bf247SJaroslav Kysela "invalid CONNECT_LIST verb %x[%i]:%x\n", 5702e9bf247SJaroslav Kysela nid, i, parm); 5712e9bf247SJaroslav Kysela return 0; 5722e9bf247SJaroslav Kysela } 5731da177e4SLinus Torvalds parm >>= shift; 5741da177e4SLinus Torvalds if (range_val) { 57554d17403STakashi Iwai /* ranges between the previous and this one */ 57654d17403STakashi Iwai if (!prev_nid || prev_nid >= val) { 5770ba21762STakashi Iwai snd_printk(KERN_WARNING "hda_codec: " 5780ba21762STakashi Iwai "invalid dep_range_val %x:%x\n", 5790ba21762STakashi Iwai prev_nid, val); 5801da177e4SLinus Torvalds continue; 5811da177e4SLinus Torvalds } 58254d17403STakashi Iwai for (n = prev_nid + 1; n <= val; n++) { 583*4eea3091STakashi Iwai if (conns >= max_conns) 584*4eea3091STakashi Iwai return -ENOSPC; 5851da177e4SLinus Torvalds conn_list[conns++] = n; 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds } else { 588*4eea3091STakashi Iwai if (conns >= max_conns) 589*4eea3091STakashi Iwai return -ENOSPC; 59054d17403STakashi Iwai conn_list[conns++] = val; 5911da177e4SLinus Torvalds } 59254d17403STakashi Iwai prev_nid = val; 5931da177e4SLinus Torvalds } 5941da177e4SLinus Torvalds return conns; 5951da177e4SLinus Torvalds } 5961da177e4SLinus Torvalds 5971da177e4SLinus Torvalds /** 598b2f934a0STakashi Iwai * snd_hda_override_conn_list - add/modify the connection-list to cache 599b2f934a0STakashi Iwai * @codec: the HDA codec 600b2f934a0STakashi Iwai * @nid: NID to parse 601b2f934a0STakashi Iwai * @len: number of connection list entries 602b2f934a0STakashi Iwai * @list: the list of connection entries 603b2f934a0STakashi Iwai * 604b2f934a0STakashi Iwai * Add or modify the given connection-list to the cache. If the corresponding 605b2f934a0STakashi Iwai * cache already exists, invalidate it and append a new one. 606b2f934a0STakashi Iwai * 607b2f934a0STakashi Iwai * Returns zero or a negative error code. 608b2f934a0STakashi Iwai */ 609b2f934a0STakashi Iwai int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, 610b2f934a0STakashi Iwai const hda_nid_t *list) 6111da177e4SLinus Torvalds { 612ee8e765bSTakashi Iwai struct hda_conn_list *p; 613b2f934a0STakashi Iwai 614ee8e765bSTakashi Iwai p = lookup_conn_list(codec, nid); 615ee8e765bSTakashi Iwai if (p) { 616ee8e765bSTakashi Iwai list_del(&p->list); 617ee8e765bSTakashi Iwai kfree(p); 618ee8e765bSTakashi Iwai } 619b2f934a0STakashi Iwai 620ee8e765bSTakashi Iwai return add_conn_list(codec, nid, len, list); 6211da177e4SLinus Torvalds } 622b2f934a0STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); 623b2f934a0STakashi Iwai 624b2f934a0STakashi Iwai /** 6258d087c76STakashi Iwai * snd_hda_get_conn_index - get the connection index of the given NID 6268d087c76STakashi Iwai * @codec: the HDA codec 6278d087c76STakashi Iwai * @mux: NID containing the list 6288d087c76STakashi Iwai * @nid: NID to select 6298d087c76STakashi Iwai * @recursive: 1 when searching NID recursively, otherwise 0 6308d087c76STakashi Iwai * 6318d087c76STakashi Iwai * Parses the connection list of the widget @mux and checks whether the 6328d087c76STakashi Iwai * widget @nid is present. If it is, return the connection index. 6338d087c76STakashi Iwai * Otherwise it returns -1. 6348d087c76STakashi Iwai */ 6358d087c76STakashi Iwai int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, 6368d087c76STakashi Iwai hda_nid_t nid, int recursive) 6378d087c76STakashi Iwai { 638ee8e765bSTakashi Iwai const hda_nid_t *conn; 6398d087c76STakashi Iwai int i, nums; 6408d087c76STakashi Iwai 641ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, mux, &conn); 6428d087c76STakashi Iwai for (i = 0; i < nums; i++) 6438d087c76STakashi Iwai if (conn[i] == nid) 6448d087c76STakashi Iwai return i; 6458d087c76STakashi Iwai if (!recursive) 6468d087c76STakashi Iwai return -1; 647d94ddd85STakashi Iwai if (recursive > 10) { 6488d087c76STakashi Iwai snd_printd("hda_codec: too deep connection for 0x%x\n", nid); 6498d087c76STakashi Iwai return -1; 6501da177e4SLinus Torvalds } 6518d087c76STakashi Iwai recursive++; 65299e14c9dSTakashi Iwai for (i = 0; i < nums; i++) { 65399e14c9dSTakashi Iwai unsigned int type = get_wcaps_type(get_wcaps(codec, conn[i])); 65499e14c9dSTakashi Iwai if (type == AC_WID_PIN || type == AC_WID_AUD_OUT) 65599e14c9dSTakashi Iwai continue; 6568d087c76STakashi Iwai if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0) 6578d087c76STakashi Iwai return i; 65899e14c9dSTakashi Iwai } 6598d087c76STakashi Iwai return -1; 6608d087c76STakashi Iwai } 6618d087c76STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds /** 6641da177e4SLinus Torvalds * snd_hda_queue_unsol_event - add an unsolicited event to queue 6651da177e4SLinus Torvalds * @bus: the BUS 6661da177e4SLinus Torvalds * @res: unsolicited event (lower 32bit of RIRB entry) 6671da177e4SLinus Torvalds * @res_ex: codec addr and flags (upper 32bit or RIRB entry) 6681da177e4SLinus Torvalds * 6691da177e4SLinus Torvalds * Adds the given event to the queue. The events are processed in 6701da177e4SLinus Torvalds * the workqueue asynchronously. Call this function in the interrupt 6711da177e4SLinus Torvalds * hanlder when RIRB receives an unsolicited event. 6721da177e4SLinus Torvalds * 6731da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 6741da177e4SLinus Torvalds */ 6751da177e4SLinus Torvalds int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) 6761da177e4SLinus Torvalds { 6771da177e4SLinus Torvalds struct hda_bus_unsolicited *unsol; 6781da177e4SLinus Torvalds unsigned int wp; 6791da177e4SLinus Torvalds 680ecf726f5STakashi Iwai trace_hda_unsol_event(bus, res, res_ex); 6810ba21762STakashi Iwai unsol = bus->unsol; 6820ba21762STakashi Iwai if (!unsol) 6831da177e4SLinus Torvalds return 0; 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE; 6861da177e4SLinus Torvalds unsol->wp = wp; 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds wp <<= 1; 6891da177e4SLinus Torvalds unsol->queue[wp] = res; 6901da177e4SLinus Torvalds unsol->queue[wp + 1] = res_ex; 6911da177e4SLinus Torvalds 6926acaed38STakashi Iwai queue_work(bus->workq, &unsol->work); 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds return 0; 6951da177e4SLinus Torvalds } 696ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_queue_unsol_event); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds /* 6995c1d1a98SWu Fengguang * process queued unsolicited events 7001da177e4SLinus Torvalds */ 701c4028958SDavid Howells static void process_unsol_events(struct work_struct *work) 7021da177e4SLinus Torvalds { 703c4028958SDavid Howells struct hda_bus_unsolicited *unsol = 704c4028958SDavid Howells container_of(work, struct hda_bus_unsolicited, work); 705c4028958SDavid Howells struct hda_bus *bus = unsol->bus; 7061da177e4SLinus Torvalds struct hda_codec *codec; 7071da177e4SLinus Torvalds unsigned int rp, caddr, res; 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds while (unsol->rp != unsol->wp) { 7101da177e4SLinus Torvalds rp = (unsol->rp + 1) % HDA_UNSOL_QUEUE_SIZE; 7111da177e4SLinus Torvalds unsol->rp = rp; 7121da177e4SLinus Torvalds rp <<= 1; 7131da177e4SLinus Torvalds res = unsol->queue[rp]; 7141da177e4SLinus Torvalds caddr = unsol->queue[rp + 1]; 7151da177e4SLinus Torvalds if (!(caddr & (1 << 4))) /* no unsolicited event? */ 7161da177e4SLinus Torvalds continue; 7171da177e4SLinus Torvalds codec = bus->caddr_tbl[caddr & 0x0f]; 7181da177e4SLinus Torvalds if (codec && codec->patch_ops.unsol_event) 7191da177e4SLinus Torvalds codec->patch_ops.unsol_event(codec, res); 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds } 7221da177e4SLinus Torvalds 7231da177e4SLinus Torvalds /* 7241da177e4SLinus Torvalds * initialize unsolicited queue 7251da177e4SLinus Torvalds */ 7266c1f45eaSTakashi Iwai static int init_unsol_queue(struct hda_bus *bus) 7271da177e4SLinus Torvalds { 7281da177e4SLinus Torvalds struct hda_bus_unsolicited *unsol; 7291da177e4SLinus Torvalds 7309f146bb6STakashi Iwai if (bus->unsol) /* already initialized */ 7319f146bb6STakashi Iwai return 0; 7329f146bb6STakashi Iwai 733e560d8d8STakashi Iwai unsol = kzalloc(sizeof(*unsol), GFP_KERNEL); 7341da177e4SLinus Torvalds if (!unsol) { 7350ba21762STakashi Iwai snd_printk(KERN_ERR "hda_codec: " 7360ba21762STakashi Iwai "can't allocate unsolicited queue\n"); 7371da177e4SLinus Torvalds return -ENOMEM; 7381da177e4SLinus Torvalds } 739c4028958SDavid Howells INIT_WORK(&unsol->work, process_unsol_events); 740c4028958SDavid Howells unsol->bus = bus; 7411da177e4SLinus Torvalds bus->unsol = unsol; 7421da177e4SLinus Torvalds return 0; 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds /* 7461da177e4SLinus Torvalds * destructor 7471da177e4SLinus Torvalds */ 7481da177e4SLinus Torvalds static void snd_hda_codec_free(struct hda_codec *codec); 7491da177e4SLinus Torvalds 7501da177e4SLinus Torvalds static int snd_hda_bus_free(struct hda_bus *bus) 7511da177e4SLinus Torvalds { 7520ba21762STakashi Iwai struct hda_codec *codec, *n; 7531da177e4SLinus Torvalds 7541da177e4SLinus Torvalds if (!bus) 7551da177e4SLinus Torvalds return 0; 7566acaed38STakashi Iwai if (bus->workq) 7576acaed38STakashi Iwai flush_workqueue(bus->workq); 7586acaed38STakashi Iwai if (bus->unsol) 7591da177e4SLinus Torvalds kfree(bus->unsol); 7600ba21762STakashi Iwai list_for_each_entry_safe(codec, n, &bus->codec_list, list) { 7611da177e4SLinus Torvalds snd_hda_codec_free(codec); 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds if (bus->ops.private_free) 7641da177e4SLinus Torvalds bus->ops.private_free(bus); 7656acaed38STakashi Iwai if (bus->workq) 7666acaed38STakashi Iwai destroy_workqueue(bus->workq); 7671da177e4SLinus Torvalds kfree(bus); 7681da177e4SLinus Torvalds return 0; 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds 771c8b6bf9bSTakashi Iwai static int snd_hda_bus_dev_free(struct snd_device *device) 7721da177e4SLinus Torvalds { 7731da177e4SLinus Torvalds struct hda_bus *bus = device->device_data; 774b94d3539STakashi Iwai bus->shutdown = 1; 7751da177e4SLinus Torvalds return snd_hda_bus_free(bus); 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds 778d7ffba19STakashi Iwai #ifdef CONFIG_SND_HDA_HWDEP 779d7ffba19STakashi Iwai static int snd_hda_bus_dev_register(struct snd_device *device) 780d7ffba19STakashi Iwai { 781d7ffba19STakashi Iwai struct hda_bus *bus = device->device_data; 782d7ffba19STakashi Iwai struct hda_codec *codec; 783d7ffba19STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 784d7ffba19STakashi Iwai snd_hda_hwdep_add_sysfs(codec); 785a2f6309eSTakashi Iwai snd_hda_hwdep_add_power_sysfs(codec); 786d7ffba19STakashi Iwai } 787d7ffba19STakashi Iwai return 0; 788d7ffba19STakashi Iwai } 789d7ffba19STakashi Iwai #else 790d7ffba19STakashi Iwai #define snd_hda_bus_dev_register NULL 791d7ffba19STakashi Iwai #endif 792d7ffba19STakashi Iwai 7931da177e4SLinus Torvalds /** 7941da177e4SLinus Torvalds * snd_hda_bus_new - create a HDA bus 7951da177e4SLinus Torvalds * @card: the card entry 7961da177e4SLinus Torvalds * @temp: the template for hda_bus information 7971da177e4SLinus Torvalds * @busp: the pointer to store the created bus instance 7981da177e4SLinus Torvalds * 7991da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 8001da177e4SLinus Torvalds */ 8016a0f56a7STakashi Iwai int snd_hda_bus_new(struct snd_card *card, 802756e2b01STakashi Iwai const struct hda_bus_template *temp, 8031da177e4SLinus Torvalds struct hda_bus **busp) 8041da177e4SLinus Torvalds { 8051da177e4SLinus Torvalds struct hda_bus *bus; 8061da177e4SLinus Torvalds int err; 807c8b6bf9bSTakashi Iwai static struct snd_device_ops dev_ops = { 808d7ffba19STakashi Iwai .dev_register = snd_hda_bus_dev_register, 8091da177e4SLinus Torvalds .dev_free = snd_hda_bus_dev_free, 8101da177e4SLinus Torvalds }; 8111da177e4SLinus Torvalds 812da3cec35STakashi Iwai if (snd_BUG_ON(!temp)) 813da3cec35STakashi Iwai return -EINVAL; 814da3cec35STakashi Iwai if (snd_BUG_ON(!temp->ops.command || !temp->ops.get_response)) 815da3cec35STakashi Iwai return -EINVAL; 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds if (busp) 8181da177e4SLinus Torvalds *busp = NULL; 8191da177e4SLinus Torvalds 820e560d8d8STakashi Iwai bus = kzalloc(sizeof(*bus), GFP_KERNEL); 8211da177e4SLinus Torvalds if (bus == NULL) { 8221da177e4SLinus Torvalds snd_printk(KERN_ERR "can't allocate struct hda_bus\n"); 8231da177e4SLinus Torvalds return -ENOMEM; 8241da177e4SLinus Torvalds } 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds bus->card = card; 8271da177e4SLinus Torvalds bus->private_data = temp->private_data; 8281da177e4SLinus Torvalds bus->pci = temp->pci; 8291da177e4SLinus Torvalds bus->modelname = temp->modelname; 830fee2fba3STakashi Iwai bus->power_save = temp->power_save; 8311da177e4SLinus Torvalds bus->ops = temp->ops; 8321da177e4SLinus Torvalds 83362932df8SIngo Molnar mutex_init(&bus->cmd_mutex); 8343f50ac6aSTakashi Iwai mutex_init(&bus->prepare_mutex); 8351da177e4SLinus Torvalds INIT_LIST_HEAD(&bus->codec_list); 8361da177e4SLinus Torvalds 837e8c0ee5dSTakashi Iwai snprintf(bus->workq_name, sizeof(bus->workq_name), 838e8c0ee5dSTakashi Iwai "hd-audio%d", card->number); 839e8c0ee5dSTakashi Iwai bus->workq = create_singlethread_workqueue(bus->workq_name); 8406acaed38STakashi Iwai if (!bus->workq) { 841e8c0ee5dSTakashi Iwai snd_printk(KERN_ERR "cannot create workqueue %s\n", 842e8c0ee5dSTakashi Iwai bus->workq_name); 8436acaed38STakashi Iwai kfree(bus); 8446acaed38STakashi Iwai return -ENOMEM; 8456acaed38STakashi Iwai } 8466acaed38STakashi Iwai 8470ba21762STakashi Iwai err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); 8480ba21762STakashi Iwai if (err < 0) { 8491da177e4SLinus Torvalds snd_hda_bus_free(bus); 8501da177e4SLinus Torvalds return err; 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds if (busp) 8531da177e4SLinus Torvalds *busp = bus; 8541da177e4SLinus Torvalds return 0; 8551da177e4SLinus Torvalds } 856ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_bus_new); 8571da177e4SLinus Torvalds 85882467611STakashi Iwai #ifdef CONFIG_SND_HDA_GENERIC 85982467611STakashi Iwai #define is_generic_config(codec) \ 860f44ac837STakashi Iwai (codec->modelname && !strcmp(codec->modelname, "generic")) 86182467611STakashi Iwai #else 86282467611STakashi Iwai #define is_generic_config(codec) 0 86382467611STakashi Iwai #endif 86482467611STakashi Iwai 865645f10c1STakashi Iwai #ifdef MODULE 8661289e9e8STakashi Iwai #define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */ 8671289e9e8STakashi Iwai #else 868645f10c1STakashi Iwai #define HDA_MODREQ_MAX_COUNT 0 /* all presets are statically linked */ 8691289e9e8STakashi Iwai #endif 8701289e9e8STakashi Iwai 8711da177e4SLinus Torvalds /* 8721da177e4SLinus Torvalds * find a matching codec preset 8731da177e4SLinus Torvalds */ 8746c1f45eaSTakashi Iwai static const struct hda_codec_preset * 875756e2b01STakashi Iwai find_codec_preset(struct hda_codec *codec) 8761da177e4SLinus Torvalds { 8771289e9e8STakashi Iwai struct hda_codec_preset_list *tbl; 8781289e9e8STakashi Iwai const struct hda_codec_preset *preset; 8795d908ab9STakashi Iwai unsigned int mod_requested = 0; 8801da177e4SLinus Torvalds 88182467611STakashi Iwai if (is_generic_config(codec)) 882d5ad630bSTakashi Iwai return NULL; /* use the generic parser */ 883d5ad630bSTakashi Iwai 8841289e9e8STakashi Iwai again: 8851289e9e8STakashi Iwai mutex_lock(&preset_mutex); 8861289e9e8STakashi Iwai list_for_each_entry(tbl, &hda_preset_tables, list) { 8871289e9e8STakashi Iwai if (!try_module_get(tbl->owner)) { 8881289e9e8STakashi Iwai snd_printk(KERN_ERR "hda_codec: cannot module_get\n"); 8891289e9e8STakashi Iwai continue; 8901289e9e8STakashi Iwai } 8911289e9e8STakashi Iwai for (preset = tbl->preset; preset->id; preset++) { 8921da177e4SLinus Torvalds u32 mask = preset->mask; 893ca7cfae9SMarc Boucher if (preset->afg && preset->afg != codec->afg) 894ca7cfae9SMarc Boucher continue; 895ca7cfae9SMarc Boucher if (preset->mfg && preset->mfg != codec->mfg) 896ca7cfae9SMarc Boucher continue; 8971da177e4SLinus Torvalds if (!mask) 8981da177e4SLinus Torvalds mask = ~0; 8999c7f852eSTakashi Iwai if (preset->id == (codec->vendor_id & mask) && 9009c7f852eSTakashi Iwai (!preset->rev || 9011289e9e8STakashi Iwai preset->rev == codec->revision_id)) { 9021289e9e8STakashi Iwai mutex_unlock(&preset_mutex); 9031289e9e8STakashi Iwai codec->owner = tbl->owner; 9041da177e4SLinus Torvalds return preset; 9051da177e4SLinus Torvalds } 9061da177e4SLinus Torvalds } 9071289e9e8STakashi Iwai module_put(tbl->owner); 9081289e9e8STakashi Iwai } 9091289e9e8STakashi Iwai mutex_unlock(&preset_mutex); 9101289e9e8STakashi Iwai 9111289e9e8STakashi Iwai if (mod_requested < HDA_MODREQ_MAX_COUNT) { 9121289e9e8STakashi Iwai char name[32]; 9131289e9e8STakashi Iwai if (!mod_requested) 9141289e9e8STakashi Iwai snprintf(name, sizeof(name), "snd-hda-codec-id:%08x", 9151289e9e8STakashi Iwai codec->vendor_id); 9161289e9e8STakashi Iwai else 9171289e9e8STakashi Iwai snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*", 9181289e9e8STakashi Iwai (codec->vendor_id >> 16) & 0xffff); 9191289e9e8STakashi Iwai request_module(name); 9201289e9e8STakashi Iwai mod_requested++; 9211289e9e8STakashi Iwai goto again; 9221289e9e8STakashi Iwai } 9231da177e4SLinus Torvalds return NULL; 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds /* 927f44ac837STakashi Iwai * get_codec_name - store the codec name 9281da177e4SLinus Torvalds */ 929f44ac837STakashi Iwai static int get_codec_name(struct hda_codec *codec) 9301da177e4SLinus Torvalds { 9311da177e4SLinus Torvalds const struct hda_vendor_id *c; 9321da177e4SLinus Torvalds const char *vendor = NULL; 9331da177e4SLinus Torvalds u16 vendor_id = codec->vendor_id >> 16; 934812a2ccaSTakashi Iwai char tmp[16]; 935812a2ccaSTakashi Iwai 936812a2ccaSTakashi Iwai if (codec->vendor_name) 937812a2ccaSTakashi Iwai goto get_chip_name; 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds for (c = hda_vendor_ids; c->id; c++) { 9401da177e4SLinus Torvalds if (c->id == vendor_id) { 9411da177e4SLinus Torvalds vendor = c->name; 9421da177e4SLinus Torvalds break; 9431da177e4SLinus Torvalds } 9441da177e4SLinus Torvalds } 9451da177e4SLinus Torvalds if (!vendor) { 9461da177e4SLinus Torvalds sprintf(tmp, "Generic %04x", vendor_id); 9471da177e4SLinus Torvalds vendor = tmp; 9481da177e4SLinus Torvalds } 949812a2ccaSTakashi Iwai codec->vendor_name = kstrdup(vendor, GFP_KERNEL); 950812a2ccaSTakashi Iwai if (!codec->vendor_name) 951812a2ccaSTakashi Iwai return -ENOMEM; 952812a2ccaSTakashi Iwai 953812a2ccaSTakashi Iwai get_chip_name: 954812a2ccaSTakashi Iwai if (codec->chip_name) 955812a2ccaSTakashi Iwai return 0; 956812a2ccaSTakashi Iwai 9571da177e4SLinus Torvalds if (codec->preset && codec->preset->name) 958812a2ccaSTakashi Iwai codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL); 959812a2ccaSTakashi Iwai else { 960812a2ccaSTakashi Iwai sprintf(tmp, "ID %x", codec->vendor_id & 0xffff); 961812a2ccaSTakashi Iwai codec->chip_name = kstrdup(tmp, GFP_KERNEL); 962812a2ccaSTakashi Iwai } 963812a2ccaSTakashi Iwai if (!codec->chip_name) 964f44ac837STakashi Iwai return -ENOMEM; 965f44ac837STakashi Iwai return 0; 9661da177e4SLinus Torvalds } 9671da177e4SLinus Torvalds 9681da177e4SLinus Torvalds /* 969673b683aSSasha Khapyorsky * look for an AFG and MFG nodes 9701da177e4SLinus Torvalds */ 9716a0f56a7STakashi Iwai static void setup_fg_nodes(struct hda_codec *codec) 9721da177e4SLinus Torvalds { 97393e82ae7STakashi Iwai int i, total_nodes, function_id; 9741da177e4SLinus Torvalds hda_nid_t nid; 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); 9771da177e4SLinus Torvalds for (i = 0; i < total_nodes; i++, nid++) { 97893e82ae7STakashi Iwai function_id = snd_hda_param_read(codec, nid, 97979c944adSJaroslav Kysela AC_PAR_FUNCTION_TYPE); 980cd7643bfSJaroslav Kysela switch (function_id & 0xff) { 981673b683aSSasha Khapyorsky case AC_GRP_AUDIO_FUNCTION: 982673b683aSSasha Khapyorsky codec->afg = nid; 98379c944adSJaroslav Kysela codec->afg_function_id = function_id & 0xff; 98479c944adSJaroslav Kysela codec->afg_unsol = (function_id >> 8) & 1; 985673b683aSSasha Khapyorsky break; 986673b683aSSasha Khapyorsky case AC_GRP_MODEM_FUNCTION: 987673b683aSSasha Khapyorsky codec->mfg = nid; 98879c944adSJaroslav Kysela codec->mfg_function_id = function_id & 0xff; 98979c944adSJaroslav Kysela codec->mfg_unsol = (function_id >> 8) & 1; 990673b683aSSasha Khapyorsky break; 991673b683aSSasha Khapyorsky default: 992673b683aSSasha Khapyorsky break; 9931da177e4SLinus Torvalds } 994673b683aSSasha Khapyorsky } 9951da177e4SLinus Torvalds } 9961da177e4SLinus Torvalds 9971da177e4SLinus Torvalds /* 99854d17403STakashi Iwai * read widget caps for each widget and store in cache 99954d17403STakashi Iwai */ 100054d17403STakashi Iwai static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) 100154d17403STakashi Iwai { 100254d17403STakashi Iwai int i; 100354d17403STakashi Iwai hda_nid_t nid; 100454d17403STakashi Iwai 100554d17403STakashi Iwai codec->num_nodes = snd_hda_get_sub_nodes(codec, fg_node, 100654d17403STakashi Iwai &codec->start_nid); 100754d17403STakashi Iwai codec->wcaps = kmalloc(codec->num_nodes * 4, GFP_KERNEL); 100854d17403STakashi Iwai if (!codec->wcaps) 100954d17403STakashi Iwai return -ENOMEM; 101054d17403STakashi Iwai nid = codec->start_nid; 101154d17403STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) 101254d17403STakashi Iwai codec->wcaps[i] = snd_hda_param_read(codec, nid, 101354d17403STakashi Iwai AC_PAR_AUDIO_WIDGET_CAP); 101454d17403STakashi Iwai return 0; 101554d17403STakashi Iwai } 101654d17403STakashi Iwai 10173be14149STakashi Iwai /* read all pin default configurations and save codec->init_pins */ 10183be14149STakashi Iwai static int read_pin_defaults(struct hda_codec *codec) 10193be14149STakashi Iwai { 10203be14149STakashi Iwai int i; 10213be14149STakashi Iwai hda_nid_t nid = codec->start_nid; 10223be14149STakashi Iwai 10233be14149STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 10243be14149STakashi Iwai struct hda_pincfg *pin; 10253be14149STakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 1026a22d543aSTakashi Iwai unsigned int wid_type = get_wcaps_type(wcaps); 10273be14149STakashi Iwai if (wid_type != AC_WID_PIN) 10283be14149STakashi Iwai continue; 10293be14149STakashi Iwai pin = snd_array_new(&codec->init_pins); 10303be14149STakashi Iwai if (!pin) 10313be14149STakashi Iwai return -ENOMEM; 10323be14149STakashi Iwai pin->nid = nid; 10333be14149STakashi Iwai pin->cfg = snd_hda_codec_read(codec, nid, 0, 10343be14149STakashi Iwai AC_VERB_GET_CONFIG_DEFAULT, 0); 1035ac0547dcSTakashi Iwai pin->ctrl = snd_hda_codec_read(codec, nid, 0, 1036ac0547dcSTakashi Iwai AC_VERB_GET_PIN_WIDGET_CONTROL, 1037ac0547dcSTakashi Iwai 0); 10383be14149STakashi Iwai } 10393be14149STakashi Iwai return 0; 10403be14149STakashi Iwai } 10413be14149STakashi Iwai 10423be14149STakashi Iwai /* look up the given pin config list and return the item matching with NID */ 10433be14149STakashi Iwai static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec, 10443be14149STakashi Iwai struct snd_array *array, 10453be14149STakashi Iwai hda_nid_t nid) 10463be14149STakashi Iwai { 10473be14149STakashi Iwai int i; 10483be14149STakashi Iwai for (i = 0; i < array->used; i++) { 10493be14149STakashi Iwai struct hda_pincfg *pin = snd_array_elem(array, i); 10503be14149STakashi Iwai if (pin->nid == nid) 10513be14149STakashi Iwai return pin; 10523be14149STakashi Iwai } 10533be14149STakashi Iwai return NULL; 10543be14149STakashi Iwai } 10553be14149STakashi Iwai 10563be14149STakashi Iwai /* set the current pin config value for the given NID. 10573be14149STakashi Iwai * the value is cached, and read via snd_hda_codec_get_pincfg() 10583be14149STakashi Iwai */ 10593be14149STakashi Iwai int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, 10603be14149STakashi Iwai hda_nid_t nid, unsigned int cfg) 10613be14149STakashi Iwai { 10623be14149STakashi Iwai struct hda_pincfg *pin; 10633be14149STakashi Iwai 1064b82855a0STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) 1065b82855a0STakashi Iwai return -EINVAL; 1066b82855a0STakashi Iwai 10673be14149STakashi Iwai pin = look_up_pincfg(codec, list, nid); 10683be14149STakashi Iwai if (!pin) { 10693be14149STakashi Iwai pin = snd_array_new(list); 10703be14149STakashi Iwai if (!pin) 10713be14149STakashi Iwai return -ENOMEM; 10723be14149STakashi Iwai pin->nid = nid; 10733be14149STakashi Iwai } 10743be14149STakashi Iwai pin->cfg = cfg; 10753be14149STakashi Iwai return 0; 10763be14149STakashi Iwai } 10773be14149STakashi Iwai 1078d5191e50STakashi Iwai /** 1079d5191e50STakashi Iwai * snd_hda_codec_set_pincfg - Override a pin default configuration 1080d5191e50STakashi Iwai * @codec: the HDA codec 1081d5191e50STakashi Iwai * @nid: NID to set the pin config 1082d5191e50STakashi Iwai * @cfg: the pin default config value 1083d5191e50STakashi Iwai * 1084d5191e50STakashi Iwai * Override a pin default configuration value in the cache. 1085d5191e50STakashi Iwai * This value can be read by snd_hda_codec_get_pincfg() in a higher 1086d5191e50STakashi Iwai * priority than the real hardware value. 1087d5191e50STakashi Iwai */ 10883be14149STakashi Iwai int snd_hda_codec_set_pincfg(struct hda_codec *codec, 10893be14149STakashi Iwai hda_nid_t nid, unsigned int cfg) 10903be14149STakashi Iwai { 1091346ff70fSTakashi Iwai return snd_hda_add_pincfg(codec, &codec->driver_pins, nid, cfg); 10923be14149STakashi Iwai } 10933be14149STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg); 10943be14149STakashi Iwai 1095d5191e50STakashi Iwai /** 1096d5191e50STakashi Iwai * snd_hda_codec_get_pincfg - Obtain a pin-default configuration 1097d5191e50STakashi Iwai * @codec: the HDA codec 1098d5191e50STakashi Iwai * @nid: NID to get the pin config 1099d5191e50STakashi Iwai * 1100d5191e50STakashi Iwai * Get the current pin config value of the given pin NID. 1101d5191e50STakashi Iwai * If the pincfg value is cached or overridden via sysfs or driver, 1102d5191e50STakashi Iwai * returns the cached value. 1103d5191e50STakashi Iwai */ 11043be14149STakashi Iwai unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) 11053be14149STakashi Iwai { 11063be14149STakashi Iwai struct hda_pincfg *pin; 11073be14149STakashi Iwai 11083be14149STakashi Iwai #ifdef CONFIG_SND_HDA_HWDEP 110909b70e85STakashi Iwai { 111009b70e85STakashi Iwai unsigned int cfg = 0; 111109b70e85STakashi Iwai mutex_lock(&codec->user_mutex); 1112346ff70fSTakashi Iwai pin = look_up_pincfg(codec, &codec->user_pins, nid); 11133be14149STakashi Iwai if (pin) 111409b70e85STakashi Iwai cfg = pin->cfg; 111509b70e85STakashi Iwai mutex_unlock(&codec->user_mutex); 111609b70e85STakashi Iwai if (cfg) 111709b70e85STakashi Iwai return cfg; 111809b70e85STakashi Iwai } 11193be14149STakashi Iwai #endif 11205e7b8e0dSTakashi Iwai pin = look_up_pincfg(codec, &codec->driver_pins, nid); 11215e7b8e0dSTakashi Iwai if (pin) 11225e7b8e0dSTakashi Iwai return pin->cfg; 11233be14149STakashi Iwai pin = look_up_pincfg(codec, &codec->init_pins, nid); 11243be14149STakashi Iwai if (pin) 11253be14149STakashi Iwai return pin->cfg; 11263be14149STakashi Iwai return 0; 11273be14149STakashi Iwai } 11283be14149STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg); 11293be14149STakashi Iwai 1130d7fdc00aSTakashi Iwai /* remember the current pinctl target value */ 1131d7fdc00aSTakashi Iwai int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid, 1132d7fdc00aSTakashi Iwai unsigned int val) 1133d7fdc00aSTakashi Iwai { 1134d7fdc00aSTakashi Iwai struct hda_pincfg *pin; 1135d7fdc00aSTakashi Iwai 1136d7fdc00aSTakashi Iwai pin = look_up_pincfg(codec, &codec->init_pins, nid); 1137d7fdc00aSTakashi Iwai if (!pin) 1138d7fdc00aSTakashi Iwai return -EINVAL; 1139d7fdc00aSTakashi Iwai pin->target = val; 1140d7fdc00aSTakashi Iwai return 0; 1141d7fdc00aSTakashi Iwai } 1142d7fdc00aSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_set_pin_target); 1143d7fdc00aSTakashi Iwai 1144d7fdc00aSTakashi Iwai /* return the current pinctl target value */ 1145d7fdc00aSTakashi Iwai int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid) 1146d7fdc00aSTakashi Iwai { 1147d7fdc00aSTakashi Iwai struct hda_pincfg *pin; 1148d7fdc00aSTakashi Iwai 1149d7fdc00aSTakashi Iwai pin = look_up_pincfg(codec, &codec->init_pins, nid); 1150d7fdc00aSTakashi Iwai if (!pin) 1151d7fdc00aSTakashi Iwai return 0; 1152d7fdc00aSTakashi Iwai return pin->target; 1153d7fdc00aSTakashi Iwai } 1154d7fdc00aSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_get_pin_target); 1155d7fdc00aSTakashi Iwai 115692ee6162STakashi Iwai /** 115792ee6162STakashi Iwai * snd_hda_shutup_pins - Shut up all pins 115892ee6162STakashi Iwai * @codec: the HDA codec 115992ee6162STakashi Iwai * 116092ee6162STakashi Iwai * Clear all pin controls to shup up before suspend for avoiding click noise. 116192ee6162STakashi Iwai * The controls aren't cached so that they can be resumed properly. 116292ee6162STakashi Iwai */ 116392ee6162STakashi Iwai void snd_hda_shutup_pins(struct hda_codec *codec) 116492ee6162STakashi Iwai { 116592ee6162STakashi Iwai int i; 1166ac0547dcSTakashi Iwai /* don't shut up pins when unloading the driver; otherwise it breaks 1167ac0547dcSTakashi Iwai * the default pin setup at the next load of the driver 1168ac0547dcSTakashi Iwai */ 1169ac0547dcSTakashi Iwai if (codec->bus->shutdown) 1170ac0547dcSTakashi Iwai return; 117192ee6162STakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 117292ee6162STakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 117392ee6162STakashi Iwai /* use read here for syncing after issuing each verb */ 117492ee6162STakashi Iwai snd_hda_codec_read(codec, pin->nid, 0, 117592ee6162STakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, 0); 117692ee6162STakashi Iwai } 1177ac0547dcSTakashi Iwai codec->pins_shutup = 1; 117892ee6162STakashi Iwai } 117992ee6162STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); 118092ee6162STakashi Iwai 11812a43952aSTakashi Iwai #ifdef CONFIG_PM 1182ac0547dcSTakashi Iwai /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ 1183ac0547dcSTakashi Iwai static void restore_shutup_pins(struct hda_codec *codec) 1184ac0547dcSTakashi Iwai { 1185ac0547dcSTakashi Iwai int i; 1186ac0547dcSTakashi Iwai if (!codec->pins_shutup) 1187ac0547dcSTakashi Iwai return; 1188ac0547dcSTakashi Iwai if (codec->bus->shutdown) 1189ac0547dcSTakashi Iwai return; 1190ac0547dcSTakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 1191ac0547dcSTakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 1192ac0547dcSTakashi Iwai snd_hda_codec_write(codec, pin->nid, 0, 1193ac0547dcSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, 1194ac0547dcSTakashi Iwai pin->ctrl); 1195ac0547dcSTakashi Iwai } 1196ac0547dcSTakashi Iwai codec->pins_shutup = 0; 1197ac0547dcSTakashi Iwai } 11981c7276cfSMike Waychison #endif 1199ac0547dcSTakashi Iwai 120026a6cb6cSDavid Henningsson static void hda_jackpoll_work(struct work_struct *work) 120126a6cb6cSDavid Henningsson { 120226a6cb6cSDavid Henningsson struct hda_codec *codec = 120326a6cb6cSDavid Henningsson container_of(work, struct hda_codec, jackpoll_work.work); 120426a6cb6cSDavid Henningsson if (!codec->jackpoll_interval) 120526a6cb6cSDavid Henningsson return; 120626a6cb6cSDavid Henningsson 120726a6cb6cSDavid Henningsson snd_hda_jack_set_dirty_all(codec); 120826a6cb6cSDavid Henningsson snd_hda_jack_poll_all(codec); 120926a6cb6cSDavid Henningsson queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, 121026a6cb6cSDavid Henningsson codec->jackpoll_interval); 121126a6cb6cSDavid Henningsson } 121226a6cb6cSDavid Henningsson 121301751f54STakashi Iwai static void init_hda_cache(struct hda_cache_rec *cache, 121401751f54STakashi Iwai unsigned int record_size); 12151fcaee6eSTakashi Iwai static void free_hda_cache(struct hda_cache_rec *cache); 121601751f54STakashi Iwai 12173fdf1469STakashi Iwai /* release all pincfg lists */ 12183fdf1469STakashi Iwai static void free_init_pincfgs(struct hda_codec *codec) 12193be14149STakashi Iwai { 1220346ff70fSTakashi Iwai snd_array_free(&codec->driver_pins); 12213be14149STakashi Iwai #ifdef CONFIG_SND_HDA_HWDEP 1222346ff70fSTakashi Iwai snd_array_free(&codec->user_pins); 12233be14149STakashi Iwai #endif 12243be14149STakashi Iwai snd_array_free(&codec->init_pins); 12253be14149STakashi Iwai } 12263be14149STakashi Iwai 122754d17403STakashi Iwai /* 1228eb541337STakashi Iwai * audio-converter setup caches 1229eb541337STakashi Iwai */ 1230eb541337STakashi Iwai struct hda_cvt_setup { 1231eb541337STakashi Iwai hda_nid_t nid; 1232eb541337STakashi Iwai u8 stream_tag; 1233eb541337STakashi Iwai u8 channel_id; 1234eb541337STakashi Iwai u16 format_id; 1235eb541337STakashi Iwai unsigned char active; /* cvt is currently used */ 1236eb541337STakashi Iwai unsigned char dirty; /* setups should be cleared */ 1237eb541337STakashi Iwai }; 1238eb541337STakashi Iwai 1239eb541337STakashi Iwai /* get or create a cache entry for the given audio converter NID */ 1240eb541337STakashi Iwai static struct hda_cvt_setup * 1241eb541337STakashi Iwai get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) 1242eb541337STakashi Iwai { 1243eb541337STakashi Iwai struct hda_cvt_setup *p; 1244eb541337STakashi Iwai int i; 1245eb541337STakashi Iwai 1246eb541337STakashi Iwai for (i = 0; i < codec->cvt_setups.used; i++) { 1247eb541337STakashi Iwai p = snd_array_elem(&codec->cvt_setups, i); 1248eb541337STakashi Iwai if (p->nid == nid) 1249eb541337STakashi Iwai return p; 1250eb541337STakashi Iwai } 1251eb541337STakashi Iwai p = snd_array_new(&codec->cvt_setups); 1252eb541337STakashi Iwai if (p) 1253eb541337STakashi Iwai p->nid = nid; 1254eb541337STakashi Iwai return p; 1255eb541337STakashi Iwai } 1256eb541337STakashi Iwai 1257eb541337STakashi Iwai /* 12581da177e4SLinus Torvalds * codec destructor 12591da177e4SLinus Torvalds */ 12601da177e4SLinus Torvalds static void snd_hda_codec_free(struct hda_codec *codec) 12611da177e4SLinus Torvalds { 12621da177e4SLinus Torvalds if (!codec) 12631da177e4SLinus Torvalds return; 126426a6cb6cSDavid Henningsson cancel_delayed_work_sync(&codec->jackpoll_work); 126559cad16bSTakashi Iwai snd_hda_jack_tbl_clear(codec); 12663fdf1469STakashi Iwai free_init_pincfgs(codec); 126783012a7cSTakashi Iwai #ifdef CONFIG_PM 1268cb53c626STakashi Iwai cancel_delayed_work(&codec->power_work); 12696acaed38STakashi Iwai flush_workqueue(codec->bus->workq); 1270cb53c626STakashi Iwai #endif 12711da177e4SLinus Torvalds list_del(&codec->list); 1272d13bd412STakashi Iwai snd_array_free(&codec->mixers); 12735b0cb1d8SJaroslav Kysela snd_array_free(&codec->nids); 127459cad16bSTakashi Iwai snd_array_free(&codec->cvt_setups); 12757c935976SStephen Warren snd_array_free(&codec->spdif_out); 1276ee8e765bSTakashi Iwai remove_conn_list(codec); 12771da177e4SLinus Torvalds codec->bus->caddr_tbl[codec->addr] = NULL; 12781da177e4SLinus Torvalds if (codec->patch_ops.free) 12791da177e4SLinus Torvalds codec->patch_ops.free(codec); 128083012a7cSTakashi Iwai #ifdef CONFIG_PM 128108fa20aeSTakashi Iwai if (!codec->pm_down_notified) /* cancel leftover refcounts */ 128268467f51STakashi Iwai hda_call_pm_notify(codec->bus, false); 128368467f51STakashi Iwai #endif 12841289e9e8STakashi Iwai module_put(codec->owner); 128501751f54STakashi Iwai free_hda_cache(&codec->amp_cache); 1286b3ac5636STakashi Iwai free_hda_cache(&codec->cmd_cache); 1287812a2ccaSTakashi Iwai kfree(codec->vendor_name); 1288812a2ccaSTakashi Iwai kfree(codec->chip_name); 1289f44ac837STakashi Iwai kfree(codec->modelname); 129054d17403STakashi Iwai kfree(codec->wcaps); 12911da177e4SLinus Torvalds kfree(codec); 12921da177e4SLinus Torvalds } 12931da177e4SLinus Torvalds 1294b8dfc462SMengdong Lin static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, 1295b8dfc462SMengdong Lin hda_nid_t fg, unsigned int power_state); 1296b8dfc462SMengdong Lin 1297d819387eSTakashi Iwai static unsigned int hda_set_power_state(struct hda_codec *codec, 1298bb6ac72fSTakashi Iwai unsigned int power_state); 12999419ab6bSTakashi Iwai static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, 13009419ab6bSTakashi Iwai unsigned int power_state); 1301bb6ac72fSTakashi Iwai 13021da177e4SLinus Torvalds /** 13031da177e4SLinus Torvalds * snd_hda_codec_new - create a HDA codec 13041da177e4SLinus Torvalds * @bus: the bus to assign 13051da177e4SLinus Torvalds * @codec_addr: the codec address 13061da177e4SLinus Torvalds * @codecp: the pointer to store the generated codec 13071da177e4SLinus Torvalds * 13081da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 13091da177e4SLinus Torvalds */ 13106a0f56a7STakashi Iwai int snd_hda_codec_new(struct hda_bus *bus, 131128aedaf7SNorberto Lopes unsigned int codec_addr, 1312a1e21c90STakashi Iwai struct hda_codec **codecp) 13131da177e4SLinus Torvalds { 13141da177e4SLinus Torvalds struct hda_codec *codec; 1315ba443687SJaroslav Kysela char component[31]; 1316d819387eSTakashi Iwai hda_nid_t fg; 13171da177e4SLinus Torvalds int err; 13181da177e4SLinus Torvalds 1319da3cec35STakashi Iwai if (snd_BUG_ON(!bus)) 1320da3cec35STakashi Iwai return -EINVAL; 1321da3cec35STakashi Iwai if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS)) 1322da3cec35STakashi Iwai return -EINVAL; 13231da177e4SLinus Torvalds 13241da177e4SLinus Torvalds if (bus->caddr_tbl[codec_addr]) { 13250ba21762STakashi Iwai snd_printk(KERN_ERR "hda_codec: " 13260ba21762STakashi Iwai "address 0x%x is already occupied\n", codec_addr); 13271da177e4SLinus Torvalds return -EBUSY; 13281da177e4SLinus Torvalds } 13291da177e4SLinus Torvalds 1330e560d8d8STakashi Iwai codec = kzalloc(sizeof(*codec), GFP_KERNEL); 13311da177e4SLinus Torvalds if (codec == NULL) { 13321da177e4SLinus Torvalds snd_printk(KERN_ERR "can't allocate struct hda_codec\n"); 13331da177e4SLinus Torvalds return -ENOMEM; 13341da177e4SLinus Torvalds } 13351da177e4SLinus Torvalds 13361da177e4SLinus Torvalds codec->bus = bus; 13371da177e4SLinus Torvalds codec->addr = codec_addr; 133862932df8SIngo Molnar mutex_init(&codec->spdif_mutex); 13395a9e02e9SWu Fengguang mutex_init(&codec->control_mutex); 1340c3b6bcc2STakashi Iwai mutex_init(&codec->hash_mutex); 134101751f54STakashi Iwai init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); 1342b3ac5636STakashi Iwai init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); 13435b0cb1d8SJaroslav Kysela snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); 13445b0cb1d8SJaroslav Kysela snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); 13453be14149STakashi Iwai snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); 1346346ff70fSTakashi Iwai snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); 1347eb541337STakashi Iwai snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); 13487c935976SStephen Warren snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); 1349361dab3eSTakashi Iwai snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16); 1350c9ce6b26STakashi Iwai snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8); 1351ee8e765bSTakashi Iwai INIT_LIST_HEAD(&codec->conn_list); 1352ee8e765bSTakashi Iwai 135326a6cb6cSDavid Henningsson INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); 13541da177e4SLinus Torvalds 135583012a7cSTakashi Iwai #ifdef CONFIG_PM 13565536c6d6STakashi Iwai spin_lock_init(&codec->power_lock); 1357cb53c626STakashi Iwai INIT_DELAYED_WORK(&codec->power_work, hda_power_work); 1358cb53c626STakashi Iwai /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. 1359cb53c626STakashi Iwai * the caller has to power down appropriatley after initialization 1360cb53c626STakashi Iwai * phase. 1361cb53c626STakashi Iwai */ 1362cb53c626STakashi Iwai hda_keep_power_on(codec); 136368467f51STakashi Iwai hda_call_pm_notify(bus, true); 1364cb53c626STakashi Iwai #endif 1365cb53c626STakashi Iwai 1366c382a9f0STakashi Iwai if (codec->bus->modelname) { 1367c382a9f0STakashi Iwai codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); 1368c382a9f0STakashi Iwai if (!codec->modelname) { 1369c382a9f0STakashi Iwai snd_hda_codec_free(codec); 1370c382a9f0STakashi Iwai return -ENODEV; 1371c382a9f0STakashi Iwai } 1372c382a9f0STakashi Iwai } 1373c382a9f0STakashi Iwai 13741da177e4SLinus Torvalds list_add_tail(&codec->list, &bus->codec_list); 13751da177e4SLinus Torvalds bus->caddr_tbl[codec_addr] = codec; 13761da177e4SLinus Torvalds 13770ba21762STakashi Iwai codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, 13780ba21762STakashi Iwai AC_PAR_VENDOR_ID); 1379111d3af5STakashi Iwai if (codec->vendor_id == -1) 1380111d3af5STakashi Iwai /* read again, hopefully the access method was corrected 1381111d3af5STakashi Iwai * in the last read... 1382111d3af5STakashi Iwai */ 1383111d3af5STakashi Iwai codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, 1384111d3af5STakashi Iwai AC_PAR_VENDOR_ID); 13850ba21762STakashi Iwai codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, 13860ba21762STakashi Iwai AC_PAR_SUBSYSTEM_ID); 13870ba21762STakashi Iwai codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, 13880ba21762STakashi Iwai AC_PAR_REV_ID); 13891da177e4SLinus Torvalds 1390673b683aSSasha Khapyorsky setup_fg_nodes(codec); 1391673b683aSSasha Khapyorsky if (!codec->afg && !codec->mfg) { 1392673b683aSSasha Khapyorsky snd_printdd("hda_codec: no AFG or MFG node found\n"); 13933be14149STakashi Iwai err = -ENODEV; 13943be14149STakashi Iwai goto error; 13951da177e4SLinus Torvalds } 13961da177e4SLinus Torvalds 1397d819387eSTakashi Iwai fg = codec->afg ? codec->afg : codec->mfg; 1398d819387eSTakashi Iwai err = read_widget_caps(codec, fg); 13993be14149STakashi Iwai if (err < 0) { 140054d17403STakashi Iwai snd_printk(KERN_ERR "hda_codec: cannot malloc\n"); 14013be14149STakashi Iwai goto error; 140254d17403STakashi Iwai } 14033be14149STakashi Iwai err = read_pin_defaults(codec); 14043be14149STakashi Iwai if (err < 0) 14053be14149STakashi Iwai goto error; 140654d17403STakashi Iwai 140786284e45STakashi Iwai if (!codec->subsystem_id) { 14080ba21762STakashi Iwai codec->subsystem_id = 1409d819387eSTakashi Iwai snd_hda_codec_read(codec, fg, 0, 14100ba21762STakashi Iwai AC_VERB_GET_SUBSYSTEM_ID, 0); 141186284e45STakashi Iwai } 141286284e45STakashi Iwai 141383012a7cSTakashi Iwai #ifdef CONFIG_PM 1414d819387eSTakashi Iwai codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg, 1415b8dfc462SMengdong Lin AC_PWRST_CLKSTOP); 1416b8dfc462SMengdong Lin if (!codec->d3_stop_clk) 1417b8dfc462SMengdong Lin bus->power_keep_link_on = 1; 14185d6147f1SMengdong Lin #endif 1419d819387eSTakashi Iwai codec->epss = snd_hda_codec_get_supported_ps(codec, fg, 1420983f6b93STakashi Iwai AC_PWRST_EPSS); 14219419ab6bSTakashi Iwai codec->power_filter = default_power_filter; 1422b8dfc462SMengdong Lin 1423bb6ac72fSTakashi Iwai /* power-up all before initialization */ 1424d819387eSTakashi Iwai hda_set_power_state(codec, AC_PWRST_D0); 1425bb6ac72fSTakashi Iwai 14266c1f45eaSTakashi Iwai snd_hda_codec_proc_new(codec); 14276c1f45eaSTakashi Iwai 14286c1f45eaSTakashi Iwai snd_hda_create_hwdep(codec); 14296c1f45eaSTakashi Iwai 14306c1f45eaSTakashi Iwai sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, 14316c1f45eaSTakashi Iwai codec->subsystem_id, codec->revision_id); 14326c1f45eaSTakashi Iwai snd_component_add(codec->bus->card, component); 14336c1f45eaSTakashi Iwai 14346c1f45eaSTakashi Iwai if (codecp) 14356c1f45eaSTakashi Iwai *codecp = codec; 14366c1f45eaSTakashi Iwai return 0; 14373be14149STakashi Iwai 14383be14149STakashi Iwai error: 14393be14149STakashi Iwai snd_hda_codec_free(codec); 14403be14149STakashi Iwai return err; 14416c1f45eaSTakashi Iwai } 1442ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_new); 14436c1f45eaSTakashi Iwai 1444d5191e50STakashi Iwai /** 1445d5191e50STakashi Iwai * snd_hda_codec_configure - (Re-)configure the HD-audio codec 1446d5191e50STakashi Iwai * @codec: the HDA codec 1447d5191e50STakashi Iwai * 1448d5191e50STakashi Iwai * Start parsing of the given codec tree and (re-)initialize the whole 1449d5191e50STakashi Iwai * patch instance. 1450d5191e50STakashi Iwai * 1451d5191e50STakashi Iwai * Returns 0 if successful or a negative error code. 1452d5191e50STakashi Iwai */ 14536c1f45eaSTakashi Iwai int snd_hda_codec_configure(struct hda_codec *codec) 14546c1f45eaSTakashi Iwai { 14556c1f45eaSTakashi Iwai int err; 14566c1f45eaSTakashi Iwai 14571da177e4SLinus Torvalds codec->preset = find_codec_preset(codec); 1458812a2ccaSTakashi Iwai if (!codec->vendor_name || !codec->chip_name) { 1459f44ac837STakashi Iwai err = get_codec_name(codec); 1460f44ac837STakashi Iwai if (err < 0) 1461f44ac837STakashi Iwai return err; 1462f44ac837STakashi Iwai } 14631da177e4SLinus Torvalds 146482467611STakashi Iwai if (is_generic_config(codec)) { 14651da177e4SLinus Torvalds err = snd_hda_parse_generic_codec(codec); 146682467611STakashi Iwai goto patched; 146782467611STakashi Iwai } 146882467611STakashi Iwai if (codec->preset && codec->preset->patch) { 146982467611STakashi Iwai err = codec->preset->patch(codec); 147082467611STakashi Iwai goto patched; 147182467611STakashi Iwai } 147282467611STakashi Iwai 147382467611STakashi Iwai /* call the default parser */ 147482467611STakashi Iwai err = snd_hda_parse_generic_codec(codec); 147535a1e0ccSTakashi Iwai if (err < 0) 147682467611STakashi Iwai printk(KERN_ERR "hda-codec: No codec parser is available\n"); 147782467611STakashi Iwai 147882467611STakashi Iwai patched: 14796c1f45eaSTakashi Iwai if (!err && codec->patch_ops.unsol_event) 14806c1f45eaSTakashi Iwai err = init_unsol_queue(codec->bus); 1481f62faedbSTakashi Iwai /* audio codec should override the mixer name */ 1482f62faedbSTakashi Iwai if (!err && (codec->afg || !*codec->bus->card->mixername)) 1483f62faedbSTakashi Iwai snprintf(codec->bus->card->mixername, 1484f62faedbSTakashi Iwai sizeof(codec->bus->card->mixername), 1485f62faedbSTakashi Iwai "%s %s", codec->vendor_name, codec->chip_name); 14861da177e4SLinus Torvalds return err; 14871da177e4SLinus Torvalds } 1488a1e21c90STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_configure); 14891da177e4SLinus Torvalds 1490ed360813STakashi Iwai /* update the stream-id if changed */ 1491ed360813STakashi Iwai static void update_pcm_stream_id(struct hda_codec *codec, 1492ed360813STakashi Iwai struct hda_cvt_setup *p, hda_nid_t nid, 1493ed360813STakashi Iwai u32 stream_tag, int channel_id) 1494ed360813STakashi Iwai { 1495ed360813STakashi Iwai unsigned int oldval, newval; 1496ed360813STakashi Iwai 1497ed360813STakashi Iwai if (p->stream_tag != stream_tag || p->channel_id != channel_id) { 1498ed360813STakashi Iwai oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); 1499ed360813STakashi Iwai newval = (stream_tag << 4) | channel_id; 1500ed360813STakashi Iwai if (oldval != newval) 1501ed360813STakashi Iwai snd_hda_codec_write(codec, nid, 0, 1502ed360813STakashi Iwai AC_VERB_SET_CHANNEL_STREAMID, 1503ed360813STakashi Iwai newval); 1504ed360813STakashi Iwai p->stream_tag = stream_tag; 1505ed360813STakashi Iwai p->channel_id = channel_id; 1506ed360813STakashi Iwai } 1507ed360813STakashi Iwai } 1508ed360813STakashi Iwai 1509ed360813STakashi Iwai /* update the format-id if changed */ 1510ed360813STakashi Iwai static void update_pcm_format(struct hda_codec *codec, struct hda_cvt_setup *p, 1511ed360813STakashi Iwai hda_nid_t nid, int format) 1512ed360813STakashi Iwai { 1513ed360813STakashi Iwai unsigned int oldval; 1514ed360813STakashi Iwai 1515ed360813STakashi Iwai if (p->format_id != format) { 1516ed360813STakashi Iwai oldval = snd_hda_codec_read(codec, nid, 0, 1517ed360813STakashi Iwai AC_VERB_GET_STREAM_FORMAT, 0); 1518ed360813STakashi Iwai if (oldval != format) { 1519ed360813STakashi Iwai msleep(1); 1520ed360813STakashi Iwai snd_hda_codec_write(codec, nid, 0, 1521ed360813STakashi Iwai AC_VERB_SET_STREAM_FORMAT, 1522ed360813STakashi Iwai format); 1523ed360813STakashi Iwai } 1524ed360813STakashi Iwai p->format_id = format; 1525ed360813STakashi Iwai } 1526ed360813STakashi Iwai } 1527ed360813STakashi Iwai 15281da177e4SLinus Torvalds /** 15291da177e4SLinus Torvalds * snd_hda_codec_setup_stream - set up the codec for streaming 15301da177e4SLinus Torvalds * @codec: the CODEC to set up 15311da177e4SLinus Torvalds * @nid: the NID to set up 15321da177e4SLinus Torvalds * @stream_tag: stream tag to pass, it's between 0x1 and 0xf. 15331da177e4SLinus Torvalds * @channel_id: channel id to pass, zero based. 15341da177e4SLinus Torvalds * @format: stream format. 15351da177e4SLinus Torvalds */ 15360ba21762STakashi Iwai void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, 15370ba21762STakashi Iwai u32 stream_tag, 15381da177e4SLinus Torvalds int channel_id, int format) 15391da177e4SLinus Torvalds { 15403f50ac6aSTakashi Iwai struct hda_codec *c; 1541eb541337STakashi Iwai struct hda_cvt_setup *p; 154262b7e5e0STakashi Iwai int type; 1543eb541337STakashi Iwai int i; 1544eb541337STakashi Iwai 1545d21b37eaSTakashi Iwai if (!nid) 1546d21b37eaSTakashi Iwai return; 1547d21b37eaSTakashi Iwai 15480ba21762STakashi Iwai snd_printdd("hda_codec_setup_stream: " 15490ba21762STakashi Iwai "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", 15501da177e4SLinus Torvalds nid, stream_tag, channel_id, format); 1551eb541337STakashi Iwai p = get_hda_cvt_setup(codec, nid); 1552affdb62bSTakashi Iwai if (!p || p->active) 1553eb541337STakashi Iwai return; 1554ed360813STakashi Iwai 1555ed360813STakashi Iwai if (codec->pcm_format_first) 1556ed360813STakashi Iwai update_pcm_format(codec, p, nid, format); 1557ed360813STakashi Iwai update_pcm_stream_id(codec, p, nid, stream_tag, channel_id); 1558ed360813STakashi Iwai if (!codec->pcm_format_first) 1559ed360813STakashi Iwai update_pcm_format(codec, p, nid, format); 1560ed360813STakashi Iwai 1561eb541337STakashi Iwai p->active = 1; 1562eb541337STakashi Iwai p->dirty = 0; 1563eb541337STakashi Iwai 1564eb541337STakashi Iwai /* make other inactive cvts with the same stream-tag dirty */ 156562b7e5e0STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 15663f50ac6aSTakashi Iwai list_for_each_entry(c, &codec->bus->codec_list, list) { 15673f50ac6aSTakashi Iwai for (i = 0; i < c->cvt_setups.used; i++) { 15683f50ac6aSTakashi Iwai p = snd_array_elem(&c->cvt_setups, i); 156962b7e5e0STakashi Iwai if (!p->active && p->stream_tag == stream_tag && 157054c2a89fSDavid Henningsson get_wcaps_type(get_wcaps(c, p->nid)) == type) 1571eb541337STakashi Iwai p->dirty = 1; 1572eb541337STakashi Iwai } 15731da177e4SLinus Torvalds } 15743f50ac6aSTakashi Iwai } 1575ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); 15761da177e4SLinus Torvalds 1577f0cea797STakashi Iwai static void really_cleanup_stream(struct hda_codec *codec, 1578f0cea797STakashi Iwai struct hda_cvt_setup *q); 1579f0cea797STakashi Iwai 1580d5191e50STakashi Iwai /** 1581f0cea797STakashi Iwai * __snd_hda_codec_cleanup_stream - clean up the codec for closing 1582d5191e50STakashi Iwai * @codec: the CODEC to clean up 1583d5191e50STakashi Iwai * @nid: the NID to clean up 1584f0cea797STakashi Iwai * @do_now: really clean up the stream instead of clearing the active flag 1585d5191e50STakashi Iwai */ 1586f0cea797STakashi Iwai void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, 1587f0cea797STakashi Iwai int do_now) 1588888afa15STakashi Iwai { 1589eb541337STakashi Iwai struct hda_cvt_setup *p; 1590eb541337STakashi Iwai 1591888afa15STakashi Iwai if (!nid) 1592888afa15STakashi Iwai return; 1593888afa15STakashi Iwai 15940e7adbe2STakashi Iwai if (codec->no_sticky_stream) 15950e7adbe2STakashi Iwai do_now = 1; 15960e7adbe2STakashi Iwai 1597888afa15STakashi Iwai snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); 1598eb541337STakashi Iwai p = get_hda_cvt_setup(codec, nid); 1599affdb62bSTakashi Iwai if (p && p->active) { 1600f0cea797STakashi Iwai /* here we just clear the active flag when do_now isn't set; 1601f0cea797STakashi Iwai * actual clean-ups will be done later in 1602f0cea797STakashi Iwai * purify_inactive_streams() called from snd_hda_codec_prpapre() 1603f0cea797STakashi Iwai */ 1604f0cea797STakashi Iwai if (do_now) 1605f0cea797STakashi Iwai really_cleanup_stream(codec, p); 1606f0cea797STakashi Iwai else 1607eb541337STakashi Iwai p->active = 0; 1608888afa15STakashi Iwai } 1609f0cea797STakashi Iwai } 1610f0cea797STakashi Iwai EXPORT_SYMBOL_HDA(__snd_hda_codec_cleanup_stream); 1611888afa15STakashi Iwai 1612eb541337STakashi Iwai static void really_cleanup_stream(struct hda_codec *codec, 1613eb541337STakashi Iwai struct hda_cvt_setup *q) 1614eb541337STakashi Iwai { 1615eb541337STakashi Iwai hda_nid_t nid = q->nid; 1616218264aeSTakashi Iwai if (q->stream_tag || q->channel_id) 1617eb541337STakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); 1618218264aeSTakashi Iwai if (q->format_id) 1619218264aeSTakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0 1620218264aeSTakashi Iwai ); 1621eb541337STakashi Iwai memset(q, 0, sizeof(*q)); 1622eb541337STakashi Iwai q->nid = nid; 1623eb541337STakashi Iwai } 1624eb541337STakashi Iwai 1625eb541337STakashi Iwai /* clean up the all conflicting obsolete streams */ 1626eb541337STakashi Iwai static void purify_inactive_streams(struct hda_codec *codec) 1627eb541337STakashi Iwai { 16283f50ac6aSTakashi Iwai struct hda_codec *c; 1629eb541337STakashi Iwai int i; 1630eb541337STakashi Iwai 16313f50ac6aSTakashi Iwai list_for_each_entry(c, &codec->bus->codec_list, list) { 16323f50ac6aSTakashi Iwai for (i = 0; i < c->cvt_setups.used; i++) { 16333f50ac6aSTakashi Iwai struct hda_cvt_setup *p; 16343f50ac6aSTakashi Iwai p = snd_array_elem(&c->cvt_setups, i); 1635eb541337STakashi Iwai if (p->dirty) 16363f50ac6aSTakashi Iwai really_cleanup_stream(c, p); 16373f50ac6aSTakashi Iwai } 1638eb541337STakashi Iwai } 1639eb541337STakashi Iwai } 1640eb541337STakashi Iwai 16412a43952aSTakashi Iwai #ifdef CONFIG_PM 1642eb541337STakashi Iwai /* clean up all streams; called from suspend */ 1643eb541337STakashi Iwai static void hda_cleanup_all_streams(struct hda_codec *codec) 1644eb541337STakashi Iwai { 1645eb541337STakashi Iwai int i; 1646eb541337STakashi Iwai 1647eb541337STakashi Iwai for (i = 0; i < codec->cvt_setups.used; i++) { 1648eb541337STakashi Iwai struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i); 1649eb541337STakashi Iwai if (p->stream_tag) 1650eb541337STakashi Iwai really_cleanup_stream(codec, p); 1651eb541337STakashi Iwai } 1652eb541337STakashi Iwai } 16531c7276cfSMike Waychison #endif 1654eb541337STakashi Iwai 16551da177e4SLinus Torvalds /* 16561da177e4SLinus Torvalds * amp access functions 16571da177e4SLinus Torvalds */ 16581da177e4SLinus Torvalds 16594a19faeeSTakashi Iwai /* FIXME: more better hash key? */ 16604a19faeeSTakashi Iwai #define HDA_HASH_KEY(nid, dir, idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) 16611327a32bSTakashi Iwai #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) 166292c7c8a7STakashi Iwai #define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) 166392c7c8a7STakashi Iwai #define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) 16641da177e4SLinus Torvalds #define INFO_AMP_CAPS (1<<0) 16654a19faeeSTakashi Iwai #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) 16661da177e4SLinus Torvalds 16671da177e4SLinus Torvalds /* initialize the hash table */ 16686a0f56a7STakashi Iwai static void init_hda_cache(struct hda_cache_rec *cache, 166901751f54STakashi Iwai unsigned int record_size) 16701da177e4SLinus Torvalds { 167101751f54STakashi Iwai memset(cache, 0, sizeof(*cache)); 167201751f54STakashi Iwai memset(cache->hash, 0xff, sizeof(cache->hash)); 1673603c4019STakashi Iwai snd_array_init(&cache->buf, record_size, 64); 167401751f54STakashi Iwai } 167501751f54STakashi Iwai 16761fcaee6eSTakashi Iwai static void free_hda_cache(struct hda_cache_rec *cache) 167701751f54STakashi Iwai { 1678603c4019STakashi Iwai snd_array_free(&cache->buf); 16791da177e4SLinus Torvalds } 16801da177e4SLinus Torvalds 16811da177e4SLinus Torvalds /* query the hash. allocate an entry if not found. */ 1682a68d5a54STakashi Iwai static struct hda_cache_head *get_hash(struct hda_cache_rec *cache, u32 key) 16831da177e4SLinus Torvalds { 168401751f54STakashi Iwai u16 idx = key % (u16)ARRAY_SIZE(cache->hash); 168501751f54STakashi Iwai u16 cur = cache->hash[idx]; 168601751f54STakashi Iwai struct hda_cache_head *info; 16871da177e4SLinus Torvalds 16881da177e4SLinus Torvalds while (cur != 0xffff) { 1689f43aa025STakashi Iwai info = snd_array_elem(&cache->buf, cur); 16901da177e4SLinus Torvalds if (info->key == key) 16911da177e4SLinus Torvalds return info; 16921da177e4SLinus Torvalds cur = info->next; 16931da177e4SLinus Torvalds } 1694a68d5a54STakashi Iwai return NULL; 1695a68d5a54STakashi Iwai } 16961da177e4SLinus Torvalds 1697a68d5a54STakashi Iwai /* query the hash. allocate an entry if not found. */ 1698a68d5a54STakashi Iwai static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, 1699a68d5a54STakashi Iwai u32 key) 1700a68d5a54STakashi Iwai { 1701a68d5a54STakashi Iwai struct hda_cache_head *info = get_hash(cache, key); 1702a68d5a54STakashi Iwai if (!info) { 1703a68d5a54STakashi Iwai u16 idx, cur; 17041da177e4SLinus Torvalds /* add a new hash entry */ 1705603c4019STakashi Iwai info = snd_array_new(&cache->buf); 1706c217429bSTakashi Iwai if (!info) 1707c217429bSTakashi Iwai return NULL; 1708f43aa025STakashi Iwai cur = snd_array_index(&cache->buf, info); 17091da177e4SLinus Torvalds info->key = key; 171001751f54STakashi Iwai info->val = 0; 1711c370dd6eSTakashi Iwai info->dirty = 0; 1712a68d5a54STakashi Iwai idx = key % (u16)ARRAY_SIZE(cache->hash); 171301751f54STakashi Iwai info->next = cache->hash[idx]; 171401751f54STakashi Iwai cache->hash[idx] = cur; 1715a68d5a54STakashi Iwai } 17161da177e4SLinus Torvalds return info; 17171da177e4SLinus Torvalds } 17181da177e4SLinus Torvalds 171901751f54STakashi Iwai /* query and allocate an amp hash entry */ 172001751f54STakashi Iwai static inline struct hda_amp_info * 172101751f54STakashi Iwai get_alloc_amp_hash(struct hda_codec *codec, u32 key) 172201751f54STakashi Iwai { 172301751f54STakashi Iwai return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); 172401751f54STakashi Iwai } 172501751f54STakashi Iwai 1726c3b6bcc2STakashi Iwai /* overwrite the value with the key in the caps hash */ 1727c3b6bcc2STakashi Iwai static int write_caps_hash(struct hda_codec *codec, u32 key, unsigned int val) 1728c3b6bcc2STakashi Iwai { 1729c3b6bcc2STakashi Iwai struct hda_amp_info *info; 1730c3b6bcc2STakashi Iwai 1731c3b6bcc2STakashi Iwai mutex_lock(&codec->hash_mutex); 1732c3b6bcc2STakashi Iwai info = get_alloc_amp_hash(codec, key); 1733c3b6bcc2STakashi Iwai if (!info) { 1734c3b6bcc2STakashi Iwai mutex_unlock(&codec->hash_mutex); 1735c3b6bcc2STakashi Iwai return -EINVAL; 1736c3b6bcc2STakashi Iwai } 1737c3b6bcc2STakashi Iwai info->amp_caps = val; 1738c3b6bcc2STakashi Iwai info->head.val |= INFO_AMP_CAPS; 1739c3b6bcc2STakashi Iwai mutex_unlock(&codec->hash_mutex); 1740c3b6bcc2STakashi Iwai return 0; 1741c3b6bcc2STakashi Iwai } 1742c3b6bcc2STakashi Iwai 1743c3b6bcc2STakashi Iwai /* query the value from the caps hash; if not found, fetch the current 1744c3b6bcc2STakashi Iwai * value from the given function and store in the hash 1745c3b6bcc2STakashi Iwai */ 1746c3b6bcc2STakashi Iwai static unsigned int 1747c3b6bcc2STakashi Iwai query_caps_hash(struct hda_codec *codec, hda_nid_t nid, int dir, u32 key, 1748c3b6bcc2STakashi Iwai unsigned int (*func)(struct hda_codec *, hda_nid_t, int)) 1749c3b6bcc2STakashi Iwai { 1750c3b6bcc2STakashi Iwai struct hda_amp_info *info; 1751c3b6bcc2STakashi Iwai unsigned int val; 1752c3b6bcc2STakashi Iwai 1753c3b6bcc2STakashi Iwai mutex_lock(&codec->hash_mutex); 1754c3b6bcc2STakashi Iwai info = get_alloc_amp_hash(codec, key); 1755c3b6bcc2STakashi Iwai if (!info) { 1756c3b6bcc2STakashi Iwai mutex_unlock(&codec->hash_mutex); 1757c3b6bcc2STakashi Iwai return 0; 1758c3b6bcc2STakashi Iwai } 1759c3b6bcc2STakashi Iwai if (!(info->head.val & INFO_AMP_CAPS)) { 1760c3b6bcc2STakashi Iwai mutex_unlock(&codec->hash_mutex); /* for reentrance */ 1761c3b6bcc2STakashi Iwai val = func(codec, nid, dir); 1762c3b6bcc2STakashi Iwai write_caps_hash(codec, key, val); 1763c3b6bcc2STakashi Iwai } else { 1764c3b6bcc2STakashi Iwai val = info->amp_caps; 1765c3b6bcc2STakashi Iwai mutex_unlock(&codec->hash_mutex); 1766c3b6bcc2STakashi Iwai } 1767c3b6bcc2STakashi Iwai return val; 1768c3b6bcc2STakashi Iwai } 1769c3b6bcc2STakashi Iwai 1770c3b6bcc2STakashi Iwai static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid, 1771c3b6bcc2STakashi Iwai int direction) 1772c3b6bcc2STakashi Iwai { 1773c3b6bcc2STakashi Iwai if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) 1774c3b6bcc2STakashi Iwai nid = codec->afg; 1775c3b6bcc2STakashi Iwai return snd_hda_param_read(codec, nid, 1776c3b6bcc2STakashi Iwai direction == HDA_OUTPUT ? 1777c3b6bcc2STakashi Iwai AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); 1778c3b6bcc2STakashi Iwai } 1779c3b6bcc2STakashi Iwai 1780d5191e50STakashi Iwai /** 1781d5191e50STakashi Iwai * query_amp_caps - query AMP capabilities 1782d5191e50STakashi Iwai * @codec: the HD-auio codec 1783d5191e50STakashi Iwai * @nid: the NID to query 1784d5191e50STakashi Iwai * @direction: either #HDA_INPUT or #HDA_OUTPUT 1785d5191e50STakashi Iwai * 1786d5191e50STakashi Iwai * Query AMP capabilities for the given widget and direction. 1787d5191e50STakashi Iwai * Returns the obtained capability bits. 1788d5191e50STakashi Iwai * 1789d5191e50STakashi Iwai * When cap bits have been already read, this doesn't read again but 1790d5191e50STakashi Iwai * returns the cached value. 17911da177e4SLinus Torvalds */ 179209a99959SMatthew Ranostay u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) 17931da177e4SLinus Torvalds { 1794c3b6bcc2STakashi Iwai return query_caps_hash(codec, nid, direction, 1795c3b6bcc2STakashi Iwai HDA_HASH_KEY(nid, direction, 0), 1796c3b6bcc2STakashi Iwai read_amp_cap); 17971da177e4SLinus Torvalds } 1798ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(query_amp_caps); 17991da177e4SLinus Torvalds 1800d5191e50STakashi Iwai /** 1801d5191e50STakashi Iwai * snd_hda_override_amp_caps - Override the AMP capabilities 1802d5191e50STakashi Iwai * @codec: the CODEC to clean up 1803d5191e50STakashi Iwai * @nid: the NID to clean up 1804d5191e50STakashi Iwai * @direction: either #HDA_INPUT or #HDA_OUTPUT 1805d5191e50STakashi Iwai * @caps: the capability bits to set 1806d5191e50STakashi Iwai * 1807d5191e50STakashi Iwai * Override the cached AMP caps bits value by the given one. 1808d5191e50STakashi Iwai * This function is useful if the driver needs to adjust the AMP ranges, 1809d5191e50STakashi Iwai * e.g. limit to 0dB, etc. 1810d5191e50STakashi Iwai * 1811d5191e50STakashi Iwai * Returns zero if successful or a negative error code. 1812d5191e50STakashi Iwai */ 1813897cc188STakashi Iwai int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, 1814897cc188STakashi Iwai unsigned int caps) 1815897cc188STakashi Iwai { 1816c3b6bcc2STakashi Iwai return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps); 1817897cc188STakashi Iwai } 1818ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); 1819897cc188STakashi Iwai 1820c3b6bcc2STakashi Iwai static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid, 1821c3b6bcc2STakashi Iwai int dir) 182292c7c8a7STakashi Iwai { 182392c7c8a7STakashi Iwai return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); 182492c7c8a7STakashi Iwai } 182592c7c8a7STakashi Iwai 1826d5191e50STakashi Iwai /** 1827d5191e50STakashi Iwai * snd_hda_query_pin_caps - Query PIN capabilities 1828d5191e50STakashi Iwai * @codec: the HD-auio codec 1829d5191e50STakashi Iwai * @nid: the NID to query 1830d5191e50STakashi Iwai * 1831d5191e50STakashi Iwai * Query PIN capabilities for the given widget. 1832d5191e50STakashi Iwai * Returns the obtained capability bits. 1833d5191e50STakashi Iwai * 1834d5191e50STakashi Iwai * When cap bits have been already read, this doesn't read again but 1835d5191e50STakashi Iwai * returns the cached value. 1836d5191e50STakashi Iwai */ 183792c7c8a7STakashi Iwai u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) 183892c7c8a7STakashi Iwai { 1839c3b6bcc2STakashi Iwai return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid), 184092c7c8a7STakashi Iwai read_pin_cap); 184192c7c8a7STakashi Iwai } 18421327a32bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); 18431327a32bSTakashi Iwai 1844864f92beSWu Fengguang /** 1845f57c2565STakashi Iwai * snd_hda_override_pin_caps - Override the pin capabilities 1846f57c2565STakashi Iwai * @codec: the CODEC 1847f57c2565STakashi Iwai * @nid: the NID to override 1848f57c2565STakashi Iwai * @caps: the capability bits to set 1849f57c2565STakashi Iwai * 1850f57c2565STakashi Iwai * Override the cached PIN capabilitiy bits value by the given one. 1851f57c2565STakashi Iwai * 1852f57c2565STakashi Iwai * Returns zero if successful or a negative error code. 1853f57c2565STakashi Iwai */ 1854f57c2565STakashi Iwai int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, 1855f57c2565STakashi Iwai unsigned int caps) 1856f57c2565STakashi Iwai { 1857c3b6bcc2STakashi Iwai return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps); 1858f57c2565STakashi Iwai } 1859f57c2565STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps); 1860f57c2565STakashi Iwai 1861c3b6bcc2STakashi Iwai /* read or sync the hash value with the current value; 1862c3b6bcc2STakashi Iwai * call within hash_mutex 18631da177e4SLinus Torvalds */ 1864c3b6bcc2STakashi Iwai static struct hda_amp_info * 1865c3b6bcc2STakashi Iwai update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch, 1866280e57d5STakashi Iwai int direction, int index, bool init_only) 18671da177e4SLinus Torvalds { 1868c3b6bcc2STakashi Iwai struct hda_amp_info *info; 1869c3b6bcc2STakashi Iwai unsigned int parm, val = 0; 1870c3b6bcc2STakashi Iwai bool val_read = false; 18711da177e4SLinus Torvalds 1872c3b6bcc2STakashi Iwai retry: 1873c3b6bcc2STakashi Iwai info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); 1874c3b6bcc2STakashi Iwai if (!info) 1875c3b6bcc2STakashi Iwai return NULL; 1876c3b6bcc2STakashi Iwai if (!(info->head.val & INFO_AMP_VOL(ch))) { 1877c3b6bcc2STakashi Iwai if (!val_read) { 1878c3b6bcc2STakashi Iwai mutex_unlock(&codec->hash_mutex); 18791da177e4SLinus Torvalds parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; 1880c3b6bcc2STakashi Iwai parm |= direction == HDA_OUTPUT ? 1881c3b6bcc2STakashi Iwai AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; 18821da177e4SLinus Torvalds parm |= index; 18830ba21762STakashi Iwai val = snd_hda_codec_read(codec, nid, 0, 18840ba21762STakashi Iwai AC_VERB_GET_AMP_GAIN_MUTE, parm); 1885c3b6bcc2STakashi Iwai val &= 0xff; 1886c3b6bcc2STakashi Iwai val_read = true; 1887c3b6bcc2STakashi Iwai mutex_lock(&codec->hash_mutex); 1888c3b6bcc2STakashi Iwai goto retry; 1889c3b6bcc2STakashi Iwai } 1890c3b6bcc2STakashi Iwai info->vol[ch] = val; 189101751f54STakashi Iwai info->head.val |= INFO_AMP_VOL(ch); 1892280e57d5STakashi Iwai } else if (init_only) 1893280e57d5STakashi Iwai return NULL; 1894c3b6bcc2STakashi Iwai return info; 18951da177e4SLinus Torvalds } 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds /* 1898c3b6bcc2STakashi Iwai * write the current volume in info to the h/w 18991da177e4SLinus Torvalds */ 19002ce4886aSTakashi Iwai static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps, 19010ba21762STakashi Iwai hda_nid_t nid, int ch, int direction, int index, 19020ba21762STakashi Iwai int val) 19031da177e4SLinus Torvalds { 19041da177e4SLinus Torvalds u32 parm; 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; 19071da177e4SLinus Torvalds parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; 19081da177e4SLinus Torvalds parm |= index << AC_AMP_SET_INDEX_SHIFT; 19092ce4886aSTakashi Iwai if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) && 19102ce4886aSTakashi Iwai (amp_caps & AC_AMPCAP_MIN_MUTE)) 19113868137eSTakashi Iwai ; /* set the zero value as a fake mute */ 19123868137eSTakashi Iwai else 19131da177e4SLinus Torvalds parm |= val; 19141da177e4SLinus Torvalds snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds 1917d5191e50STakashi Iwai /** 1918d5191e50STakashi Iwai * snd_hda_codec_amp_read - Read AMP value 1919d5191e50STakashi Iwai * @codec: HD-audio codec 1920d5191e50STakashi Iwai * @nid: NID to read the AMP value 1921d5191e50STakashi Iwai * @ch: channel (left=0 or right=1) 1922d5191e50STakashi Iwai * @direction: #HDA_INPUT or #HDA_OUTPUT 1923d5191e50STakashi Iwai * @index: the index value (only for input direction) 1924d5191e50STakashi Iwai * 1925d5191e50STakashi Iwai * Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. 19261da177e4SLinus Torvalds */ 1927834be88dSTakashi Iwai int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, 1928834be88dSTakashi Iwai int direction, int index) 19291da177e4SLinus Torvalds { 19300ba21762STakashi Iwai struct hda_amp_info *info; 1931c3b6bcc2STakashi Iwai unsigned int val = 0; 1932c3b6bcc2STakashi Iwai 1933c3b6bcc2STakashi Iwai mutex_lock(&codec->hash_mutex); 1934280e57d5STakashi Iwai info = update_amp_hash(codec, nid, ch, direction, index, false); 1935c3b6bcc2STakashi Iwai if (info) 1936c3b6bcc2STakashi Iwai val = info->vol[ch]; 1937c3b6bcc2STakashi Iwai mutex_unlock(&codec->hash_mutex); 1938c3b6bcc2STakashi Iwai return val; 19391da177e4SLinus Torvalds } 1940ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); 19411da177e4SLinus Torvalds 1942280e57d5STakashi Iwai static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, 1943280e57d5STakashi Iwai int direction, int idx, int mask, int val, 1944280e57d5STakashi Iwai bool init_only) 1945280e57d5STakashi Iwai { 1946280e57d5STakashi Iwai struct hda_amp_info *info; 19472ce4886aSTakashi Iwai unsigned int caps; 1948de1e37b7STakashi Iwai unsigned int cache_only; 1949280e57d5STakashi Iwai 1950280e57d5STakashi Iwai if (snd_BUG_ON(mask & ~0xff)) 1951280e57d5STakashi Iwai mask &= 0xff; 1952280e57d5STakashi Iwai val &= mask; 1953280e57d5STakashi Iwai 1954280e57d5STakashi Iwai mutex_lock(&codec->hash_mutex); 1955280e57d5STakashi Iwai info = update_amp_hash(codec, nid, ch, direction, idx, init_only); 1956280e57d5STakashi Iwai if (!info) { 1957280e57d5STakashi Iwai mutex_unlock(&codec->hash_mutex); 1958280e57d5STakashi Iwai return 0; 1959280e57d5STakashi Iwai } 1960280e57d5STakashi Iwai val |= info->vol[ch] & ~mask; 1961280e57d5STakashi Iwai if (info->vol[ch] == val) { 1962280e57d5STakashi Iwai mutex_unlock(&codec->hash_mutex); 1963280e57d5STakashi Iwai return 0; 1964280e57d5STakashi Iwai } 1965280e57d5STakashi Iwai info->vol[ch] = val; 1966de1e37b7STakashi Iwai cache_only = info->head.dirty = codec->cached_write; 19672ce4886aSTakashi Iwai caps = info->amp_caps; 1968280e57d5STakashi Iwai mutex_unlock(&codec->hash_mutex); 1969de1e37b7STakashi Iwai if (!cache_only) 19702ce4886aSTakashi Iwai put_vol_mute(codec, caps, nid, ch, direction, idx, val); 1971280e57d5STakashi Iwai return 1; 1972280e57d5STakashi Iwai } 1973280e57d5STakashi Iwai 1974d5191e50STakashi Iwai /** 1975d5191e50STakashi Iwai * snd_hda_codec_amp_update - update the AMP value 1976d5191e50STakashi Iwai * @codec: HD-audio codec 1977d5191e50STakashi Iwai * @nid: NID to read the AMP value 1978d5191e50STakashi Iwai * @ch: channel (left=0 or right=1) 1979d5191e50STakashi Iwai * @direction: #HDA_INPUT or #HDA_OUTPUT 1980d5191e50STakashi Iwai * @idx: the index value (only for input direction) 1981d5191e50STakashi Iwai * @mask: bit mask to set 1982d5191e50STakashi Iwai * @val: the bits value to set 1983d5191e50STakashi Iwai * 1984d5191e50STakashi Iwai * Update the AMP value with a bit mask. 1985d5191e50STakashi Iwai * Returns 0 if the value is unchanged, 1 if changed. 19864a19faeeSTakashi Iwai */ 1987834be88dSTakashi Iwai int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, 1988834be88dSTakashi Iwai int direction, int idx, int mask, int val) 19891da177e4SLinus Torvalds { 1990280e57d5STakashi Iwai return codec_amp_update(codec, nid, ch, direction, idx, mask, val, false); 19911da177e4SLinus Torvalds } 1992ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update); 19931da177e4SLinus Torvalds 1994d5191e50STakashi Iwai /** 1995d5191e50STakashi Iwai * snd_hda_codec_amp_stereo - update the AMP stereo values 1996d5191e50STakashi Iwai * @codec: HD-audio codec 1997d5191e50STakashi Iwai * @nid: NID to read the AMP value 1998d5191e50STakashi Iwai * @direction: #HDA_INPUT or #HDA_OUTPUT 1999d5191e50STakashi Iwai * @idx: the index value (only for input direction) 2000d5191e50STakashi Iwai * @mask: bit mask to set 2001d5191e50STakashi Iwai * @val: the bits value to set 2002d5191e50STakashi Iwai * 2003d5191e50STakashi Iwai * Update the AMP values like snd_hda_codec_amp_update(), but for a 2004d5191e50STakashi Iwai * stereo widget with the same mask and value. 200547fd830aSTakashi Iwai */ 200647fd830aSTakashi Iwai int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, 200747fd830aSTakashi Iwai int direction, int idx, int mask, int val) 200847fd830aSTakashi Iwai { 200947fd830aSTakashi Iwai int ch, ret = 0; 201046712646STakashi Iwai 201146712646STakashi Iwai if (snd_BUG_ON(mask & ~0xff)) 201246712646STakashi Iwai mask &= 0xff; 201347fd830aSTakashi Iwai for (ch = 0; ch < 2; ch++) 201447fd830aSTakashi Iwai ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, 201547fd830aSTakashi Iwai idx, mask, val); 201647fd830aSTakashi Iwai return ret; 201747fd830aSTakashi Iwai } 2018ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); 201947fd830aSTakashi Iwai 2020280e57d5STakashi Iwai /* Works like snd_hda_codec_amp_update() but it writes the value only at 2021280e57d5STakashi Iwai * the first access. If the amp was already initialized / updated beforehand, 2022280e57d5STakashi Iwai * this does nothing. 2023280e57d5STakashi Iwai */ 2024280e57d5STakashi Iwai int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, 2025280e57d5STakashi Iwai int dir, int idx, int mask, int val) 2026280e57d5STakashi Iwai { 2027280e57d5STakashi Iwai return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true); 2028280e57d5STakashi Iwai } 2029280e57d5STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init); 2030280e57d5STakashi Iwai 2031280e57d5STakashi Iwai int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, 2032280e57d5STakashi Iwai int dir, int idx, int mask, int val) 2033280e57d5STakashi Iwai { 2034280e57d5STakashi Iwai int ch, ret = 0; 2035280e57d5STakashi Iwai 2036280e57d5STakashi Iwai if (snd_BUG_ON(mask & ~0xff)) 2037280e57d5STakashi Iwai mask &= 0xff; 2038280e57d5STakashi Iwai for (ch = 0; ch < 2; ch++) 2039280e57d5STakashi Iwai ret |= snd_hda_codec_amp_init(codec, nid, ch, dir, 2040280e57d5STakashi Iwai idx, mask, val); 2041280e57d5STakashi Iwai return ret; 2042280e57d5STakashi Iwai } 2043280e57d5STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init_stereo); 2044280e57d5STakashi Iwai 2045d5191e50STakashi Iwai /** 2046d5191e50STakashi Iwai * snd_hda_codec_resume_amp - Resume all AMP commands from the cache 2047d5191e50STakashi Iwai * @codec: HD-audio codec 2048d5191e50STakashi Iwai * 2049d5191e50STakashi Iwai * Resume the all amp commands from the cache. 2050d5191e50STakashi Iwai */ 2051b3ac5636STakashi Iwai void snd_hda_codec_resume_amp(struct hda_codec *codec) 2052b3ac5636STakashi Iwai { 2053b3ac5636STakashi Iwai int i; 2054b3ac5636STakashi Iwai 2055c370dd6eSTakashi Iwai mutex_lock(&codec->hash_mutex); 2056aa88a355STakashi Iwai codec->cached_write = 0; 2057c370dd6eSTakashi Iwai for (i = 0; i < codec->amp_cache.buf.used; i++) { 2058c370dd6eSTakashi Iwai struct hda_amp_info *buffer; 2059c370dd6eSTakashi Iwai u32 key; 2060b3ac5636STakashi Iwai hda_nid_t nid; 2061b3ac5636STakashi Iwai unsigned int idx, dir, ch; 20622ce4886aSTakashi Iwai struct hda_amp_info info; 2063c370dd6eSTakashi Iwai 2064c370dd6eSTakashi Iwai buffer = snd_array_elem(&codec->amp_cache.buf, i); 20658565f052STakashi Iwai if (!buffer->head.dirty) 20668565f052STakashi Iwai continue; 20678565f052STakashi Iwai buffer->head.dirty = 0; 20682ce4886aSTakashi Iwai info = *buffer; 20692ce4886aSTakashi Iwai key = info.head.key; 2070b3ac5636STakashi Iwai if (!key) 2071b3ac5636STakashi Iwai continue; 2072b3ac5636STakashi Iwai nid = key & 0xff; 2073b3ac5636STakashi Iwai idx = (key >> 16) & 0xff; 2074b3ac5636STakashi Iwai dir = (key >> 24) & 0xff; 2075b3ac5636STakashi Iwai for (ch = 0; ch < 2; ch++) { 20762ce4886aSTakashi Iwai if (!(info.head.val & INFO_AMP_VOL(ch))) 2077b3ac5636STakashi Iwai continue; 2078c370dd6eSTakashi Iwai mutex_unlock(&codec->hash_mutex); 20792ce4886aSTakashi Iwai put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx, 20802ce4886aSTakashi Iwai info.vol[ch]); 2081c370dd6eSTakashi Iwai mutex_lock(&codec->hash_mutex); 2082b3ac5636STakashi Iwai } 2083b3ac5636STakashi Iwai } 2084c370dd6eSTakashi Iwai mutex_unlock(&codec->hash_mutex); 2085b3ac5636STakashi Iwai } 2086ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); 20871da177e4SLinus Torvalds 2088afbd9b84STakashi Iwai static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, 2089afbd9b84STakashi Iwai unsigned int ofs) 2090afbd9b84STakashi Iwai { 2091afbd9b84STakashi Iwai u32 caps = query_amp_caps(codec, nid, dir); 2092afbd9b84STakashi Iwai /* get num steps */ 2093afbd9b84STakashi Iwai caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; 2094afbd9b84STakashi Iwai if (ofs < caps) 2095afbd9b84STakashi Iwai caps -= ofs; 2096afbd9b84STakashi Iwai return caps; 2097afbd9b84STakashi Iwai } 2098afbd9b84STakashi Iwai 2099d5191e50STakashi Iwai /** 2100d5191e50STakashi Iwai * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer 2101d5191e50STakashi Iwai * 2102d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2103d5191e50STakashi Iwai * set up via HDA_COMPOSE_AMP_VAL*() or related macros. 2104d5191e50STakashi Iwai */ 21050ba21762STakashi Iwai int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, 21060ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo) 21071da177e4SLinus Torvalds { 21081da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 21091da177e4SLinus Torvalds u16 nid = get_amp_nid(kcontrol); 21101da177e4SLinus Torvalds u8 chs = get_amp_channels(kcontrol); 21111da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 211229fdbec2STakashi Iwai unsigned int ofs = get_amp_offset(kcontrol); 21131da177e4SLinus Torvalds 2114afbd9b84STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2115afbd9b84STakashi Iwai uinfo->count = chs == 3 ? 2 : 1; 2116afbd9b84STakashi Iwai uinfo->value.integer.min = 0; 2117afbd9b84STakashi Iwai uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs); 2118afbd9b84STakashi Iwai if (!uinfo->value.integer.max) { 21190ba21762STakashi Iwai printk(KERN_WARNING "hda_codec: " 21209c8f2abdSTakashi Iwai "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, 21219c8f2abdSTakashi Iwai kcontrol->id.name); 21221da177e4SLinus Torvalds return -EINVAL; 21231da177e4SLinus Torvalds } 21241da177e4SLinus Torvalds return 0; 21251da177e4SLinus Torvalds } 2126ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); 21271da177e4SLinus Torvalds 212829fdbec2STakashi Iwai 212929fdbec2STakashi Iwai static inline unsigned int 213029fdbec2STakashi Iwai read_amp_value(struct hda_codec *codec, hda_nid_t nid, 213129fdbec2STakashi Iwai int ch, int dir, int idx, unsigned int ofs) 213229fdbec2STakashi Iwai { 213329fdbec2STakashi Iwai unsigned int val; 213429fdbec2STakashi Iwai val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx); 213529fdbec2STakashi Iwai val &= HDA_AMP_VOLMASK; 213629fdbec2STakashi Iwai if (val >= ofs) 213729fdbec2STakashi Iwai val -= ofs; 213829fdbec2STakashi Iwai else 213929fdbec2STakashi Iwai val = 0; 214029fdbec2STakashi Iwai return val; 214129fdbec2STakashi Iwai } 214229fdbec2STakashi Iwai 214329fdbec2STakashi Iwai static inline int 214429fdbec2STakashi Iwai update_amp_value(struct hda_codec *codec, hda_nid_t nid, 214529fdbec2STakashi Iwai int ch, int dir, int idx, unsigned int ofs, 214629fdbec2STakashi Iwai unsigned int val) 214729fdbec2STakashi Iwai { 2148afbd9b84STakashi Iwai unsigned int maxval; 2149afbd9b84STakashi Iwai 215029fdbec2STakashi Iwai if (val > 0) 215129fdbec2STakashi Iwai val += ofs; 21527ccc3efaSTakashi Iwai /* ofs = 0: raw max value */ 21537ccc3efaSTakashi Iwai maxval = get_amp_max_value(codec, nid, dir, 0); 2154afbd9b84STakashi Iwai if (val > maxval) 2155afbd9b84STakashi Iwai val = maxval; 215629fdbec2STakashi Iwai return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, 215729fdbec2STakashi Iwai HDA_AMP_VOLMASK, val); 215829fdbec2STakashi Iwai } 215929fdbec2STakashi Iwai 2160d5191e50STakashi Iwai /** 2161d5191e50STakashi Iwai * snd_hda_mixer_amp_volume_get - Get callback for a standard AMP mixer volume 2162d5191e50STakashi Iwai * 2163d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2164d5191e50STakashi Iwai * set up via HDA_COMPOSE_AMP_VAL*() or related macros. 2165d5191e50STakashi Iwai */ 21660ba21762STakashi Iwai int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, 21670ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 21681da177e4SLinus Torvalds { 21691da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 21701da177e4SLinus Torvalds hda_nid_t nid = get_amp_nid(kcontrol); 21711da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 21721da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 21731da177e4SLinus Torvalds int idx = get_amp_index(kcontrol); 217429fdbec2STakashi Iwai unsigned int ofs = get_amp_offset(kcontrol); 21751da177e4SLinus Torvalds long *valp = ucontrol->value.integer.value; 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds if (chs & 1) 217829fdbec2STakashi Iwai *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs); 21791da177e4SLinus Torvalds if (chs & 2) 218029fdbec2STakashi Iwai *valp = read_amp_value(codec, nid, 1, dir, idx, ofs); 21811da177e4SLinus Torvalds return 0; 21821da177e4SLinus Torvalds } 2183ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); 21841da177e4SLinus Torvalds 2185d5191e50STakashi Iwai /** 2186d5191e50STakashi Iwai * snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume 2187d5191e50STakashi Iwai * 2188d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2189d5191e50STakashi Iwai * set up via HDA_COMPOSE_AMP_VAL*() or related macros. 2190d5191e50STakashi Iwai */ 21910ba21762STakashi Iwai int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, 21920ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 21931da177e4SLinus Torvalds { 21941da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 21951da177e4SLinus Torvalds hda_nid_t nid = get_amp_nid(kcontrol); 21961da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 21971da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 21981da177e4SLinus Torvalds int idx = get_amp_index(kcontrol); 219929fdbec2STakashi Iwai unsigned int ofs = get_amp_offset(kcontrol); 22001da177e4SLinus Torvalds long *valp = ucontrol->value.integer.value; 22011da177e4SLinus Torvalds int change = 0; 22021da177e4SLinus Torvalds 2203cb53c626STakashi Iwai snd_hda_power_up(codec); 2204b9f5a89cSNicolas Graziano if (chs & 1) { 220529fdbec2STakashi Iwai change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); 2206b9f5a89cSNicolas Graziano valp++; 2207b9f5a89cSNicolas Graziano } 22084a19faeeSTakashi Iwai if (chs & 2) 220929fdbec2STakashi Iwai change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); 2210cb53c626STakashi Iwai snd_hda_power_down(codec); 22111da177e4SLinus Torvalds return change; 22121da177e4SLinus Torvalds } 2213ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put); 22141da177e4SLinus Torvalds 2215d5191e50STakashi Iwai /** 2216d5191e50STakashi Iwai * snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume 2217d5191e50STakashi Iwai * 2218d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2219d5191e50STakashi Iwai * set up via HDA_COMPOSE_AMP_VAL*() or related macros. 2220d5191e50STakashi Iwai */ 2221302e9c5aSJaroslav Kysela int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, 2222302e9c5aSJaroslav Kysela unsigned int size, unsigned int __user *_tlv) 2223302e9c5aSJaroslav Kysela { 2224302e9c5aSJaroslav Kysela struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2225302e9c5aSJaroslav Kysela hda_nid_t nid = get_amp_nid(kcontrol); 2226302e9c5aSJaroslav Kysela int dir = get_amp_direction(kcontrol); 222729fdbec2STakashi Iwai unsigned int ofs = get_amp_offset(kcontrol); 2228de8c85f7SClemens Ladisch bool min_mute = get_amp_min_mute(kcontrol); 2229302e9c5aSJaroslav Kysela u32 caps, val1, val2; 2230302e9c5aSJaroslav Kysela 2231302e9c5aSJaroslav Kysela if (size < 4 * sizeof(unsigned int)) 2232302e9c5aSJaroslav Kysela return -ENOMEM; 2233302e9c5aSJaroslav Kysela caps = query_amp_caps(codec, nid, dir); 22340ba21762STakashi Iwai val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; 22350ba21762STakashi Iwai val2 = (val2 + 1) * 25; 2236302e9c5aSJaroslav Kysela val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); 223729fdbec2STakashi Iwai val1 += ofs; 2238302e9c5aSJaroslav Kysela val1 = ((int)val1) * ((int)val2); 22393868137eSTakashi Iwai if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) 2240c08d9169STakashi Iwai val2 |= TLV_DB_SCALE_MUTE; 2241302e9c5aSJaroslav Kysela if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) 2242302e9c5aSJaroslav Kysela return -EFAULT; 2243302e9c5aSJaroslav Kysela if (put_user(2 * sizeof(unsigned int), _tlv + 1)) 2244302e9c5aSJaroslav Kysela return -EFAULT; 2245302e9c5aSJaroslav Kysela if (put_user(val1, _tlv + 2)) 2246302e9c5aSJaroslav Kysela return -EFAULT; 2247302e9c5aSJaroslav Kysela if (put_user(val2, _tlv + 3)) 2248302e9c5aSJaroslav Kysela return -EFAULT; 2249302e9c5aSJaroslav Kysela return 0; 2250302e9c5aSJaroslav Kysela } 2251ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv); 2252302e9c5aSJaroslav Kysela 2253d5191e50STakashi Iwai /** 2254d5191e50STakashi Iwai * snd_hda_set_vmaster_tlv - Set TLV for a virtual master control 2255d5191e50STakashi Iwai * @codec: HD-audio codec 2256d5191e50STakashi Iwai * @nid: NID of a reference widget 2257d5191e50STakashi Iwai * @dir: #HDA_INPUT or #HDA_OUTPUT 2258d5191e50STakashi Iwai * @tlv: TLV data to be stored, at least 4 elements 2259d5191e50STakashi Iwai * 2260d5191e50STakashi Iwai * Set (static) TLV data for a virtual master volume using the AMP caps 2261d5191e50STakashi Iwai * obtained from the reference NID. 2262d5191e50STakashi Iwai * The volume range is recalculated as if the max volume is 0dB. 22632134ea4fSTakashi Iwai */ 22642134ea4fSTakashi Iwai void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, 22652134ea4fSTakashi Iwai unsigned int *tlv) 22662134ea4fSTakashi Iwai { 22672134ea4fSTakashi Iwai u32 caps; 22682134ea4fSTakashi Iwai int nums, step; 22692134ea4fSTakashi Iwai 22702134ea4fSTakashi Iwai caps = query_amp_caps(codec, nid, dir); 22712134ea4fSTakashi Iwai nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; 22722134ea4fSTakashi Iwai step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; 22732134ea4fSTakashi Iwai step = (step + 1) * 25; 22742134ea4fSTakashi Iwai tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; 22752134ea4fSTakashi Iwai tlv[1] = 2 * sizeof(unsigned int); 22762134ea4fSTakashi Iwai tlv[2] = -nums * step; 22772134ea4fSTakashi Iwai tlv[3] = step; 22782134ea4fSTakashi Iwai } 2279ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv); 22802134ea4fSTakashi Iwai 22812134ea4fSTakashi Iwai /* find a mixer control element with the given name */ 228209f99701STakashi Iwai static struct snd_kcontrol * 2283dcda5806STakashi Iwai find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx) 22842134ea4fSTakashi Iwai { 22852134ea4fSTakashi Iwai struct snd_ctl_elem_id id; 22862134ea4fSTakashi Iwai memset(&id, 0, sizeof(id)); 22872134ea4fSTakashi Iwai id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 2288dcda5806STakashi Iwai id.device = dev; 228909f99701STakashi Iwai id.index = idx; 229018cb7109STakashi Iwai if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) 229118cb7109STakashi Iwai return NULL; 22922134ea4fSTakashi Iwai strcpy(id.name, name); 22932134ea4fSTakashi Iwai return snd_ctl_find_id(codec->bus->card, &id); 22942134ea4fSTakashi Iwai } 22952134ea4fSTakashi Iwai 2296d5191e50STakashi Iwai /** 2297d5191e50STakashi Iwai * snd_hda_find_mixer_ctl - Find a mixer control element with the given name 2298d5191e50STakashi Iwai * @codec: HD-audio codec 2299d5191e50STakashi Iwai * @name: ctl id name string 2300d5191e50STakashi Iwai * 2301d5191e50STakashi Iwai * Get the control element with the given id string and IFACE_MIXER. 2302d5191e50STakashi Iwai */ 230309f99701STakashi Iwai struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, 230409f99701STakashi Iwai const char *name) 230509f99701STakashi Iwai { 2306dcda5806STakashi Iwai return find_mixer_ctl(codec, name, 0, 0); 230709f99701STakashi Iwai } 2308ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); 230909f99701STakashi Iwai 2310dcda5806STakashi Iwai static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name, 2311dcda5806STakashi Iwai int dev) 23121afe206aSTakashi Iwai { 23131afe206aSTakashi Iwai int idx; 23141afe206aSTakashi Iwai for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */ 2315dcda5806STakashi Iwai if (!find_mixer_ctl(codec, name, dev, idx)) 23161afe206aSTakashi Iwai return idx; 23171afe206aSTakashi Iwai } 23181afe206aSTakashi Iwai return -EBUSY; 23191afe206aSTakashi Iwai } 23201afe206aSTakashi Iwai 2321d5191e50STakashi Iwai /** 23225b0cb1d8SJaroslav Kysela * snd_hda_ctl_add - Add a control element and assign to the codec 2323d5191e50STakashi Iwai * @codec: HD-audio codec 2324d5191e50STakashi Iwai * @nid: corresponding NID (optional) 2325d5191e50STakashi Iwai * @kctl: the control element to assign 2326d5191e50STakashi Iwai * 2327d5191e50STakashi Iwai * Add the given control element to an array inside the codec instance. 2328d5191e50STakashi Iwai * All control elements belonging to a codec are supposed to be added 2329d5191e50STakashi Iwai * by this function so that a proper clean-up works at the free or 2330d5191e50STakashi Iwai * reconfiguration time. 2331d5191e50STakashi Iwai * 2332d5191e50STakashi Iwai * If non-zero @nid is passed, the NID is assigned to the control element. 2333d5191e50STakashi Iwai * The assignment is shown in the codec proc file. 2334d5191e50STakashi Iwai * 2335d5191e50STakashi Iwai * snd_hda_ctl_add() checks the control subdev id field whether 2336d5191e50STakashi Iwai * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower 23379e3fd871SJaroslav Kysela * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit 23389e3fd871SJaroslav Kysela * specifies if kctl->private_value is a HDA amplifier value. 2339d5191e50STakashi Iwai */ 23403911a4c1SJaroslav Kysela int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, 23413911a4c1SJaroslav Kysela struct snd_kcontrol *kctl) 2342d13bd412STakashi Iwai { 2343d13bd412STakashi Iwai int err; 23449e3fd871SJaroslav Kysela unsigned short flags = 0; 23453911a4c1SJaroslav Kysela struct hda_nid_item *item; 2346d13bd412STakashi Iwai 23475e26dfd0SJaroslav Kysela if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) { 23489e3fd871SJaroslav Kysela flags |= HDA_NID_ITEM_AMP; 23495e26dfd0SJaroslav Kysela if (nid == 0) 23505e26dfd0SJaroslav Kysela nid = get_amp_nid_(kctl->private_value); 23515e26dfd0SJaroslav Kysela } 23529e3fd871SJaroslav Kysela if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0) 23534d02d1b6SJaroslav Kysela nid = kctl->id.subdevice & 0xffff; 23545e26dfd0SJaroslav Kysela if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG)) 23554d02d1b6SJaroslav Kysela kctl->id.subdevice = 0; 2356d13bd412STakashi Iwai err = snd_ctl_add(codec->bus->card, kctl); 2357d13bd412STakashi Iwai if (err < 0) 2358d13bd412STakashi Iwai return err; 23593911a4c1SJaroslav Kysela item = snd_array_new(&codec->mixers); 23603911a4c1SJaroslav Kysela if (!item) 2361d13bd412STakashi Iwai return -ENOMEM; 23623911a4c1SJaroslav Kysela item->kctl = kctl; 23633911a4c1SJaroslav Kysela item->nid = nid; 23649e3fd871SJaroslav Kysela item->flags = flags; 2365d13bd412STakashi Iwai return 0; 2366d13bd412STakashi Iwai } 2367ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_ctl_add); 2368d13bd412STakashi Iwai 2369d5191e50STakashi Iwai /** 23705b0cb1d8SJaroslav Kysela * snd_hda_add_nid - Assign a NID to a control element 23715b0cb1d8SJaroslav Kysela * @codec: HD-audio codec 23725b0cb1d8SJaroslav Kysela * @nid: corresponding NID (optional) 23735b0cb1d8SJaroslav Kysela * @kctl: the control element to assign 23745b0cb1d8SJaroslav Kysela * @index: index to kctl 23755b0cb1d8SJaroslav Kysela * 23765b0cb1d8SJaroslav Kysela * Add the given control element to an array inside the codec instance. 23775b0cb1d8SJaroslav Kysela * This function is used when #snd_hda_ctl_add cannot be used for 1:1 23785b0cb1d8SJaroslav Kysela * NID:KCTL mapping - for example "Capture Source" selector. 23795b0cb1d8SJaroslav Kysela */ 23805b0cb1d8SJaroslav Kysela int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, 23815b0cb1d8SJaroslav Kysela unsigned int index, hda_nid_t nid) 23825b0cb1d8SJaroslav Kysela { 23835b0cb1d8SJaroslav Kysela struct hda_nid_item *item; 23845b0cb1d8SJaroslav Kysela 23855b0cb1d8SJaroslav Kysela if (nid > 0) { 23865b0cb1d8SJaroslav Kysela item = snd_array_new(&codec->nids); 23875b0cb1d8SJaroslav Kysela if (!item) 23885b0cb1d8SJaroslav Kysela return -ENOMEM; 23895b0cb1d8SJaroslav Kysela item->kctl = kctl; 23905b0cb1d8SJaroslav Kysela item->index = index; 23915b0cb1d8SJaroslav Kysela item->nid = nid; 23925b0cb1d8SJaroslav Kysela return 0; 23935b0cb1d8SJaroslav Kysela } 239428d1a85eSTakashi Iwai printk(KERN_ERR "hda-codec: no NID for mapping control %s:%d:%d\n", 239528d1a85eSTakashi Iwai kctl->id.name, kctl->id.index, index); 23965b0cb1d8SJaroslav Kysela return -EINVAL; 23975b0cb1d8SJaroslav Kysela } 23985b0cb1d8SJaroslav Kysela EXPORT_SYMBOL_HDA(snd_hda_add_nid); 23995b0cb1d8SJaroslav Kysela 24005b0cb1d8SJaroslav Kysela /** 2401d5191e50STakashi Iwai * snd_hda_ctls_clear - Clear all controls assigned to the given codec 2402d5191e50STakashi Iwai * @codec: HD-audio codec 2403d5191e50STakashi Iwai */ 2404d13bd412STakashi Iwai void snd_hda_ctls_clear(struct hda_codec *codec) 2405d13bd412STakashi Iwai { 2406d13bd412STakashi Iwai int i; 24073911a4c1SJaroslav Kysela struct hda_nid_item *items = codec->mixers.list; 2408d13bd412STakashi Iwai for (i = 0; i < codec->mixers.used; i++) 24093911a4c1SJaroslav Kysela snd_ctl_remove(codec->bus->card, items[i].kctl); 2410d13bd412STakashi Iwai snd_array_free(&codec->mixers); 24115b0cb1d8SJaroslav Kysela snd_array_free(&codec->nids); 2412d13bd412STakashi Iwai } 2413d13bd412STakashi Iwai 2414a65d629cSTakashi Iwai /* pseudo device locking 2415a65d629cSTakashi Iwai * toggle card->shutdown to allow/disallow the device access (as a hack) 2416a65d629cSTakashi Iwai */ 2417d3d020bdSTakashi Iwai int snd_hda_lock_devices(struct hda_bus *bus) 24186c1f45eaSTakashi Iwai { 2419d3d020bdSTakashi Iwai struct snd_card *card = bus->card; 2420d3d020bdSTakashi Iwai struct hda_codec *codec; 2421d3d020bdSTakashi Iwai 2422a65d629cSTakashi Iwai spin_lock(&card->files_lock); 2423d3d020bdSTakashi Iwai if (card->shutdown) 2424d3d020bdSTakashi Iwai goto err_unlock; 2425d3d020bdSTakashi Iwai card->shutdown = 1; 2426d3d020bdSTakashi Iwai if (!list_empty(&card->ctl_files)) 2427d3d020bdSTakashi Iwai goto err_clear; 2428d3d020bdSTakashi Iwai 2429d3d020bdSTakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 2430d3d020bdSTakashi Iwai int pcm; 2431d3d020bdSTakashi Iwai for (pcm = 0; pcm < codec->num_pcms; pcm++) { 2432d3d020bdSTakashi Iwai struct hda_pcm *cpcm = &codec->pcm_info[pcm]; 2433d3d020bdSTakashi Iwai if (!cpcm->pcm) 2434d3d020bdSTakashi Iwai continue; 2435d3d020bdSTakashi Iwai if (cpcm->pcm->streams[0].substream_opened || 2436d3d020bdSTakashi Iwai cpcm->pcm->streams[1].substream_opened) 2437d3d020bdSTakashi Iwai goto err_clear; 2438d3d020bdSTakashi Iwai } 2439d3d020bdSTakashi Iwai } 2440d3d020bdSTakashi Iwai spin_unlock(&card->files_lock); 2441d3d020bdSTakashi Iwai return 0; 2442d3d020bdSTakashi Iwai 2443d3d020bdSTakashi Iwai err_clear: 2444d3d020bdSTakashi Iwai card->shutdown = 0; 2445d3d020bdSTakashi Iwai err_unlock: 2446a65d629cSTakashi Iwai spin_unlock(&card->files_lock); 2447a65d629cSTakashi Iwai return -EINVAL; 2448a65d629cSTakashi Iwai } 2449d3d020bdSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_lock_devices); 2450a65d629cSTakashi Iwai 2451d3d020bdSTakashi Iwai void snd_hda_unlock_devices(struct hda_bus *bus) 2452a65d629cSTakashi Iwai { 2453d3d020bdSTakashi Iwai struct snd_card *card = bus->card; 2454d3d020bdSTakashi Iwai 2455d3d020bdSTakashi Iwai card = bus->card; 2456a65d629cSTakashi Iwai spin_lock(&card->files_lock); 2457a65d629cSTakashi Iwai card->shutdown = 0; 2458a65d629cSTakashi Iwai spin_unlock(&card->files_lock); 2459a65d629cSTakashi Iwai } 2460d3d020bdSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_unlock_devices); 2461a65d629cSTakashi Iwai 2462d5191e50STakashi Iwai /** 2463d5191e50STakashi Iwai * snd_hda_codec_reset - Clear all objects assigned to the codec 2464d5191e50STakashi Iwai * @codec: HD-audio codec 2465d5191e50STakashi Iwai * 2466d5191e50STakashi Iwai * This frees the all PCM and control elements assigned to the codec, and 2467d5191e50STakashi Iwai * clears the caches and restores the pin default configurations. 2468d5191e50STakashi Iwai * 2469d5191e50STakashi Iwai * When a device is being used, it returns -EBSY. If successfully freed, 2470d5191e50STakashi Iwai * returns zero. 2471d5191e50STakashi Iwai */ 2472a65d629cSTakashi Iwai int snd_hda_codec_reset(struct hda_codec *codec) 2473a65d629cSTakashi Iwai { 2474d3d020bdSTakashi Iwai struct hda_bus *bus = codec->bus; 2475d3d020bdSTakashi Iwai struct snd_card *card = bus->card; 2476d3d020bdSTakashi Iwai int i; 2477a65d629cSTakashi Iwai 2478d3d020bdSTakashi Iwai if (snd_hda_lock_devices(bus) < 0) 2479a65d629cSTakashi Iwai return -EBUSY; 2480a65d629cSTakashi Iwai 2481a65d629cSTakashi Iwai /* OK, let it free */ 248226a6cb6cSDavid Henningsson cancel_delayed_work_sync(&codec->jackpoll_work); 248383012a7cSTakashi Iwai #ifdef CONFIG_PM 2484a2d96e77STakashi Iwai cancel_delayed_work_sync(&codec->power_work); 2485339876d7STakashi Iwai codec->power_on = 0; 2486339876d7STakashi Iwai codec->power_transition = 0; 2487339876d7STakashi Iwai codec->power_jiffies = jiffies; 2488d3d020bdSTakashi Iwai flush_workqueue(bus->workq); 24896c1f45eaSTakashi Iwai #endif 24906c1f45eaSTakashi Iwai snd_hda_ctls_clear(codec); 24916c1f45eaSTakashi Iwai /* relase PCMs */ 24926c1f45eaSTakashi Iwai for (i = 0; i < codec->num_pcms; i++) { 2493529bd6c4STakashi Iwai if (codec->pcm_info[i].pcm) { 2494a65d629cSTakashi Iwai snd_device_free(card, codec->pcm_info[i].pcm); 2495529bd6c4STakashi Iwai clear_bit(codec->pcm_info[i].device, 2496d3d020bdSTakashi Iwai bus->pcm_dev_bits); 2497529bd6c4STakashi Iwai } 24986c1f45eaSTakashi Iwai } 24996c1f45eaSTakashi Iwai if (codec->patch_ops.free) 25006c1f45eaSTakashi Iwai codec->patch_ops.free(codec); 250107dc59f0STakashi Iwai memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); 25021835a0f9STakashi Iwai snd_hda_jack_tbl_clear(codec); 250356d17712STakashi Iwai codec->proc_widget_hook = NULL; 25046c1f45eaSTakashi Iwai codec->spec = NULL; 25056c1f45eaSTakashi Iwai free_hda_cache(&codec->amp_cache); 25066c1f45eaSTakashi Iwai free_hda_cache(&codec->cmd_cache); 2507827057f5STakashi Iwai init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); 2508827057f5STakashi Iwai init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); 2509346ff70fSTakashi Iwai /* free only driver_pins so that init_pins + user_pins are restored */ 2510346ff70fSTakashi Iwai snd_array_free(&codec->driver_pins); 251109a6071bSTakashi Iwai snd_array_free(&codec->cvt_setups); 251209a6071bSTakashi Iwai snd_array_free(&codec->spdif_out); 2513c9ce6b26STakashi Iwai snd_array_free(&codec->verbs); 25146c1f45eaSTakashi Iwai codec->num_pcms = 0; 25156c1f45eaSTakashi Iwai codec->pcm_info = NULL; 25166c1f45eaSTakashi Iwai codec->preset = NULL; 2517d1f1af2dSTakashi Iwai codec->slave_dig_outs = NULL; 2518d1f1af2dSTakashi Iwai codec->spdif_status_reset = 0; 25191289e9e8STakashi Iwai module_put(codec->owner); 25201289e9e8STakashi Iwai codec->owner = NULL; 2521a65d629cSTakashi Iwai 2522a65d629cSTakashi Iwai /* allow device access again */ 2523d3d020bdSTakashi Iwai snd_hda_unlock_devices(bus); 2524a65d629cSTakashi Iwai return 0; 25256c1f45eaSTakashi Iwai } 25266c1f45eaSTakashi Iwai 2527aeb4b88eSTakashi Iwai typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *); 2528aeb4b88eSTakashi Iwai 2529aeb4b88eSTakashi Iwai /* apply the function to all matching slave ctls in the mixer list */ 2530aeb4b88eSTakashi Iwai static int map_slaves(struct hda_codec *codec, const char * const *slaves, 25319322ca54STakashi Iwai const char *suffix, map_slave_func_t func, void *data) 2532aeb4b88eSTakashi Iwai { 2533aeb4b88eSTakashi Iwai struct hda_nid_item *items; 2534aeb4b88eSTakashi Iwai const char * const *s; 2535aeb4b88eSTakashi Iwai int i, err; 2536aeb4b88eSTakashi Iwai 2537aeb4b88eSTakashi Iwai items = codec->mixers.list; 2538aeb4b88eSTakashi Iwai for (i = 0; i < codec->mixers.used; i++) { 2539aeb4b88eSTakashi Iwai struct snd_kcontrol *sctl = items[i].kctl; 2540aeb4b88eSTakashi Iwai if (!sctl || !sctl->id.name || 2541aeb4b88eSTakashi Iwai sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER) 2542aeb4b88eSTakashi Iwai continue; 2543aeb4b88eSTakashi Iwai for (s = slaves; *s; s++) { 25449322ca54STakashi Iwai char tmpname[sizeof(sctl->id.name)]; 25459322ca54STakashi Iwai const char *name = *s; 25469322ca54STakashi Iwai if (suffix) { 25479322ca54STakashi Iwai snprintf(tmpname, sizeof(tmpname), "%s %s", 25489322ca54STakashi Iwai name, suffix); 25499322ca54STakashi Iwai name = tmpname; 25509322ca54STakashi Iwai } 25519322ca54STakashi Iwai if (!strcmp(sctl->id.name, name)) { 2552aeb4b88eSTakashi Iwai err = func(data, sctl); 2553aeb4b88eSTakashi Iwai if (err) 2554aeb4b88eSTakashi Iwai return err; 2555aeb4b88eSTakashi Iwai break; 2556aeb4b88eSTakashi Iwai } 2557aeb4b88eSTakashi Iwai } 2558aeb4b88eSTakashi Iwai } 2559aeb4b88eSTakashi Iwai return 0; 2560aeb4b88eSTakashi Iwai } 2561aeb4b88eSTakashi Iwai 2562aeb4b88eSTakashi Iwai static int check_slave_present(void *data, struct snd_kcontrol *sctl) 2563aeb4b88eSTakashi Iwai { 2564aeb4b88eSTakashi Iwai return 1; 2565aeb4b88eSTakashi Iwai } 2566aeb4b88eSTakashi Iwai 256718478e8bSTakashi Iwai /* guess the value corresponding to 0dB */ 256818478e8bSTakashi Iwai static int get_kctl_0dB_offset(struct snd_kcontrol *kctl) 256918478e8bSTakashi Iwai { 257018478e8bSTakashi Iwai int _tlv[4]; 257118478e8bSTakashi Iwai const int *tlv = NULL; 257218478e8bSTakashi Iwai int val = -1; 257318478e8bSTakashi Iwai 257418478e8bSTakashi Iwai if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 257518478e8bSTakashi Iwai /* FIXME: set_fs() hack for obtaining user-space TLV data */ 257618478e8bSTakashi Iwai mm_segment_t fs = get_fs(); 257718478e8bSTakashi Iwai set_fs(get_ds()); 257818478e8bSTakashi Iwai if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv)) 257918478e8bSTakashi Iwai tlv = _tlv; 258018478e8bSTakashi Iwai set_fs(fs); 258118478e8bSTakashi Iwai } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) 258218478e8bSTakashi Iwai tlv = kctl->tlv.p; 258318478e8bSTakashi Iwai if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) 258418478e8bSTakashi Iwai val = -tlv[2] / tlv[3]; 258518478e8bSTakashi Iwai return val; 258618478e8bSTakashi Iwai } 258718478e8bSTakashi Iwai 258818478e8bSTakashi Iwai /* call kctl->put with the given value(s) */ 258918478e8bSTakashi Iwai static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) 259018478e8bSTakashi Iwai { 259118478e8bSTakashi Iwai struct snd_ctl_elem_value *ucontrol; 259218478e8bSTakashi Iwai ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); 259318478e8bSTakashi Iwai if (!ucontrol) 259418478e8bSTakashi Iwai return -ENOMEM; 259518478e8bSTakashi Iwai ucontrol->value.integer.value[0] = val; 259618478e8bSTakashi Iwai ucontrol->value.integer.value[1] = val; 259718478e8bSTakashi Iwai kctl->put(kctl, ucontrol); 259818478e8bSTakashi Iwai kfree(ucontrol); 259918478e8bSTakashi Iwai return 0; 260018478e8bSTakashi Iwai } 260118478e8bSTakashi Iwai 260218478e8bSTakashi Iwai /* initialize the slave volume with 0dB */ 260318478e8bSTakashi Iwai static int init_slave_0dB(void *data, struct snd_kcontrol *slave) 260418478e8bSTakashi Iwai { 260518478e8bSTakashi Iwai int offset = get_kctl_0dB_offset(slave); 260618478e8bSTakashi Iwai if (offset > 0) 260718478e8bSTakashi Iwai put_kctl_with_value(slave, offset); 260818478e8bSTakashi Iwai return 0; 260918478e8bSTakashi Iwai } 261018478e8bSTakashi Iwai 261118478e8bSTakashi Iwai /* unmute the slave */ 261218478e8bSTakashi Iwai static int init_slave_unmute(void *data, struct snd_kcontrol *slave) 261318478e8bSTakashi Iwai { 261418478e8bSTakashi Iwai return put_kctl_with_value(slave, 1); 261518478e8bSTakashi Iwai } 261618478e8bSTakashi Iwai 2617d5191e50STakashi Iwai /** 2618d5191e50STakashi Iwai * snd_hda_add_vmaster - create a virtual master control and add slaves 2619d5191e50STakashi Iwai * @codec: HD-audio codec 2620d5191e50STakashi Iwai * @name: vmaster control name 2621d5191e50STakashi Iwai * @tlv: TLV data (optional) 2622d5191e50STakashi Iwai * @slaves: slave control names (optional) 26239322ca54STakashi Iwai * @suffix: suffix string to each slave name (optional) 262418478e8bSTakashi Iwai * @init_slave_vol: initialize slaves to unmute/0dB 262529e5853dSTakashi Iwai * @ctl_ret: store the vmaster kcontrol in return 2626d5191e50STakashi Iwai * 2627d5191e50STakashi Iwai * Create a virtual master control with the given name. The TLV data 2628d5191e50STakashi Iwai * must be either NULL or a valid data. 2629d5191e50STakashi Iwai * 2630d5191e50STakashi Iwai * @slaves is a NULL-terminated array of strings, each of which is a 2631d5191e50STakashi Iwai * slave control name. All controls with these names are assigned to 2632d5191e50STakashi Iwai * the new virtual master control. 2633d5191e50STakashi Iwai * 2634d5191e50STakashi Iwai * This function returns zero if successful or a negative error code. 2635d5191e50STakashi Iwai */ 263618478e8bSTakashi Iwai int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, 26379322ca54STakashi Iwai unsigned int *tlv, const char * const *slaves, 263829e5853dSTakashi Iwai const char *suffix, bool init_slave_vol, 263929e5853dSTakashi Iwai struct snd_kcontrol **ctl_ret) 26402134ea4fSTakashi Iwai { 26412134ea4fSTakashi Iwai struct snd_kcontrol *kctl; 26422134ea4fSTakashi Iwai int err; 26432134ea4fSTakashi Iwai 264429e5853dSTakashi Iwai if (ctl_ret) 264529e5853dSTakashi Iwai *ctl_ret = NULL; 264629e5853dSTakashi Iwai 26479322ca54STakashi Iwai err = map_slaves(codec, slaves, suffix, check_slave_present, NULL); 2648aeb4b88eSTakashi Iwai if (err != 1) { 26492f085549STakashi Iwai snd_printdd("No slave found for %s\n", name); 26502f085549STakashi Iwai return 0; 26512f085549STakashi Iwai } 26522134ea4fSTakashi Iwai kctl = snd_ctl_make_virtual_master(name, tlv); 26532134ea4fSTakashi Iwai if (!kctl) 26542134ea4fSTakashi Iwai return -ENOMEM; 26553911a4c1SJaroslav Kysela err = snd_hda_ctl_add(codec, 0, kctl); 26562134ea4fSTakashi Iwai if (err < 0) 26572134ea4fSTakashi Iwai return err; 26582134ea4fSTakashi Iwai 26599322ca54STakashi Iwai err = map_slaves(codec, slaves, suffix, 26609322ca54STakashi Iwai (map_slave_func_t)snd_ctl_add_slave, kctl); 26612134ea4fSTakashi Iwai if (err < 0) 26622134ea4fSTakashi Iwai return err; 266318478e8bSTakashi Iwai 266418478e8bSTakashi Iwai /* init with master mute & zero volume */ 266518478e8bSTakashi Iwai put_kctl_with_value(kctl, 0); 266618478e8bSTakashi Iwai if (init_slave_vol) 266718478e8bSTakashi Iwai map_slaves(codec, slaves, suffix, 266818478e8bSTakashi Iwai tlv ? init_slave_0dB : init_slave_unmute, kctl); 266918478e8bSTakashi Iwai 267029e5853dSTakashi Iwai if (ctl_ret) 267129e5853dSTakashi Iwai *ctl_ret = kctl; 26722134ea4fSTakashi Iwai return 0; 26732134ea4fSTakashi Iwai } 267418478e8bSTakashi Iwai EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster); 26752134ea4fSTakashi Iwai 2676d2f344b5STakashi Iwai /* 2677d2f344b5STakashi Iwai * mute-LED control using vmaster 2678d2f344b5STakashi Iwai */ 2679d2f344b5STakashi Iwai static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol, 2680d2f344b5STakashi Iwai struct snd_ctl_elem_info *uinfo) 2681d2f344b5STakashi Iwai { 2682d2f344b5STakashi Iwai static const char * const texts[] = { 2683c86c2d44SDavid Henningsson "On", "Off", "Follow Master" 2684d2f344b5STakashi Iwai }; 2685d2f344b5STakashi Iwai unsigned int index; 2686d2f344b5STakashi Iwai 2687d2f344b5STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2688d2f344b5STakashi Iwai uinfo->count = 1; 2689d2f344b5STakashi Iwai uinfo->value.enumerated.items = 3; 2690d2f344b5STakashi Iwai index = uinfo->value.enumerated.item; 2691d2f344b5STakashi Iwai if (index >= 3) 2692d2f344b5STakashi Iwai index = 2; 2693d2f344b5STakashi Iwai strcpy(uinfo->value.enumerated.name, texts[index]); 2694d2f344b5STakashi Iwai return 0; 2695d2f344b5STakashi Iwai } 2696d2f344b5STakashi Iwai 2697d2f344b5STakashi Iwai static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol, 2698d2f344b5STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2699d2f344b5STakashi Iwai { 2700d2f344b5STakashi Iwai struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol); 2701d2f344b5STakashi Iwai ucontrol->value.enumerated.item[0] = hook->mute_mode; 2702d2f344b5STakashi Iwai return 0; 2703d2f344b5STakashi Iwai } 2704d2f344b5STakashi Iwai 2705d2f344b5STakashi Iwai static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol, 2706d2f344b5STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2707d2f344b5STakashi Iwai { 2708d2f344b5STakashi Iwai struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol); 2709d2f344b5STakashi Iwai unsigned int old_mode = hook->mute_mode; 2710d2f344b5STakashi Iwai 2711d2f344b5STakashi Iwai hook->mute_mode = ucontrol->value.enumerated.item[0]; 2712d2f344b5STakashi Iwai if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER) 2713d2f344b5STakashi Iwai hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; 2714d2f344b5STakashi Iwai if (old_mode == hook->mute_mode) 2715d2f344b5STakashi Iwai return 0; 2716d2f344b5STakashi Iwai snd_hda_sync_vmaster_hook(hook); 2717d2f344b5STakashi Iwai return 1; 2718d2f344b5STakashi Iwai } 2719d2f344b5STakashi Iwai 2720d2f344b5STakashi Iwai static struct snd_kcontrol_new vmaster_mute_mode = { 2721d2f344b5STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2722d2f344b5STakashi Iwai .name = "Mute-LED Mode", 2723d2f344b5STakashi Iwai .info = vmaster_mute_mode_info, 2724d2f344b5STakashi Iwai .get = vmaster_mute_mode_get, 2725d2f344b5STakashi Iwai .put = vmaster_mute_mode_put, 2726d2f344b5STakashi Iwai }; 2727d2f344b5STakashi Iwai 2728d2f344b5STakashi Iwai /* 2729d2f344b5STakashi Iwai * Add a mute-LED hook with the given vmaster switch kctl 2730d2f344b5STakashi Iwai * "Mute-LED Mode" control is automatically created and associated with 2731d2f344b5STakashi Iwai * the given hook. 2732d2f344b5STakashi Iwai */ 2733d2f344b5STakashi Iwai int snd_hda_add_vmaster_hook(struct hda_codec *codec, 2734f29735cbSTakashi Iwai struct hda_vmaster_mute_hook *hook, 2735f29735cbSTakashi Iwai bool expose_enum_ctl) 2736d2f344b5STakashi Iwai { 2737d2f344b5STakashi Iwai struct snd_kcontrol *kctl; 2738d2f344b5STakashi Iwai 2739d2f344b5STakashi Iwai if (!hook->hook || !hook->sw_kctl) 2740d2f344b5STakashi Iwai return 0; 2741d2f344b5STakashi Iwai snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec); 2742d2f344b5STakashi Iwai hook->codec = codec; 2743d2f344b5STakashi Iwai hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; 2744f29735cbSTakashi Iwai if (!expose_enum_ctl) 2745f29735cbSTakashi Iwai return 0; 2746d2f344b5STakashi Iwai kctl = snd_ctl_new1(&vmaster_mute_mode, hook); 2747d2f344b5STakashi Iwai if (!kctl) 2748d2f344b5STakashi Iwai return -ENOMEM; 2749d2f344b5STakashi Iwai return snd_hda_ctl_add(codec, 0, kctl); 2750d2f344b5STakashi Iwai } 2751d2f344b5STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook); 2752d2f344b5STakashi Iwai 2753d2f344b5STakashi Iwai /* 2754d2f344b5STakashi Iwai * Call the hook with the current value for synchronization 2755d2f344b5STakashi Iwai * Should be called in init callback 2756d2f344b5STakashi Iwai */ 2757d2f344b5STakashi Iwai void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) 2758d2f344b5STakashi Iwai { 2759d2f344b5STakashi Iwai if (!hook->hook || !hook->codec) 2760d2f344b5STakashi Iwai return; 2761d2f344b5STakashi Iwai switch (hook->mute_mode) { 2762d2f344b5STakashi Iwai case HDA_VMUTE_FOLLOW_MASTER: 2763d2f344b5STakashi Iwai snd_ctl_sync_vmaster_hook(hook->sw_kctl); 2764d2f344b5STakashi Iwai break; 2765d2f344b5STakashi Iwai default: 2766d2f344b5STakashi Iwai hook->hook(hook->codec, hook->mute_mode); 2767d2f344b5STakashi Iwai break; 2768d2f344b5STakashi Iwai } 2769d2f344b5STakashi Iwai } 2770d2f344b5STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook); 2771d2f344b5STakashi Iwai 2772d2f344b5STakashi Iwai 2773d5191e50STakashi Iwai /** 2774d5191e50STakashi Iwai * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch 2775d5191e50STakashi Iwai * 2776d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2777d5191e50STakashi Iwai * set up via HDA_COMPOSE_AMP_VAL*() or related macros. 2778d5191e50STakashi Iwai */ 27790ba21762STakashi Iwai int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, 27800ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo) 27811da177e4SLinus Torvalds { 27821da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 27831da177e4SLinus Torvalds 27841da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 27851da177e4SLinus Torvalds uinfo->count = chs == 3 ? 2 : 1; 27861da177e4SLinus Torvalds uinfo->value.integer.min = 0; 27871da177e4SLinus Torvalds uinfo->value.integer.max = 1; 27881da177e4SLinus Torvalds return 0; 27891da177e4SLinus Torvalds } 2790ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info); 27911da177e4SLinus Torvalds 2792d5191e50STakashi Iwai /** 2793d5191e50STakashi Iwai * snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch 2794d5191e50STakashi Iwai * 2795d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2796d5191e50STakashi Iwai * set up via HDA_COMPOSE_AMP_VAL*() or related macros. 2797d5191e50STakashi Iwai */ 27980ba21762STakashi Iwai int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, 27990ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 28001da177e4SLinus Torvalds { 28011da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 28021da177e4SLinus Torvalds hda_nid_t nid = get_amp_nid(kcontrol); 28031da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 28041da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 28051da177e4SLinus Torvalds int idx = get_amp_index(kcontrol); 28061da177e4SLinus Torvalds long *valp = ucontrol->value.integer.value; 28071da177e4SLinus Torvalds 28081da177e4SLinus Torvalds if (chs & 1) 28090ba21762STakashi Iwai *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 281047fd830aSTakashi Iwai HDA_AMP_MUTE) ? 0 : 1; 28111da177e4SLinus Torvalds if (chs & 2) 28120ba21762STakashi Iwai *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 281347fd830aSTakashi Iwai HDA_AMP_MUTE) ? 0 : 1; 28141da177e4SLinus Torvalds return 0; 28151da177e4SLinus Torvalds } 2816ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get); 28171da177e4SLinus Torvalds 2818d5191e50STakashi Iwai /** 2819d5191e50STakashi Iwai * snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch 2820d5191e50STakashi Iwai * 2821d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2822d5191e50STakashi Iwai * set up via HDA_COMPOSE_AMP_VAL*() or related macros. 2823d5191e50STakashi Iwai */ 28240ba21762STakashi Iwai int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, 28250ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 28261da177e4SLinus Torvalds { 28271da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 28281da177e4SLinus Torvalds hda_nid_t nid = get_amp_nid(kcontrol); 28291da177e4SLinus Torvalds int chs = get_amp_channels(kcontrol); 28301da177e4SLinus Torvalds int dir = get_amp_direction(kcontrol); 28311da177e4SLinus Torvalds int idx = get_amp_index(kcontrol); 28321da177e4SLinus Torvalds long *valp = ucontrol->value.integer.value; 28331da177e4SLinus Torvalds int change = 0; 28341da177e4SLinus Torvalds 2835cb53c626STakashi Iwai snd_hda_power_up(codec); 2836b9f5a89cSNicolas Graziano if (chs & 1) { 28374a19faeeSTakashi Iwai change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 283847fd830aSTakashi Iwai HDA_AMP_MUTE, 283947fd830aSTakashi Iwai *valp ? 0 : HDA_AMP_MUTE); 2840b9f5a89cSNicolas Graziano valp++; 2841b9f5a89cSNicolas Graziano } 28424a19faeeSTakashi Iwai if (chs & 2) 28434a19faeeSTakashi Iwai change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, 284447fd830aSTakashi Iwai HDA_AMP_MUTE, 284547fd830aSTakashi Iwai *valp ? 0 : HDA_AMP_MUTE); 28469e5341b9STakashi Iwai hda_call_check_power_status(codec, nid); 2847cb53c626STakashi Iwai snd_hda_power_down(codec); 28481da177e4SLinus Torvalds return change; 28491da177e4SLinus Torvalds } 2850ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); 28511da177e4SLinus Torvalds 28521da177e4SLinus Torvalds /* 2853985be54bSTakashi Iwai * bound volume controls 2854985be54bSTakashi Iwai * 2855985be54bSTakashi Iwai * bind multiple volumes (# indices, from 0) 2856985be54bSTakashi Iwai */ 2857985be54bSTakashi Iwai 2858985be54bSTakashi Iwai #define AMP_VAL_IDX_SHIFT 19 2859985be54bSTakashi Iwai #define AMP_VAL_IDX_MASK (0x0f<<19) 2860985be54bSTakashi Iwai 2861d5191e50STakashi Iwai /** 2862d5191e50STakashi Iwai * snd_hda_mixer_bind_switch_get - Get callback for a bound volume control 2863d5191e50STakashi Iwai * 2864d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2865d5191e50STakashi Iwai * set up via HDA_BIND_MUTE*() macros. 2866d5191e50STakashi Iwai */ 28670ba21762STakashi Iwai int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, 28680ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2869985be54bSTakashi Iwai { 2870985be54bSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2871985be54bSTakashi Iwai unsigned long pval; 2872985be54bSTakashi Iwai int err; 2873985be54bSTakashi Iwai 28745a9e02e9SWu Fengguang mutex_lock(&codec->control_mutex); 2875985be54bSTakashi Iwai pval = kcontrol->private_value; 2876985be54bSTakashi Iwai kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ 2877985be54bSTakashi Iwai err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); 2878985be54bSTakashi Iwai kcontrol->private_value = pval; 28795a9e02e9SWu Fengguang mutex_unlock(&codec->control_mutex); 2880985be54bSTakashi Iwai return err; 2881985be54bSTakashi Iwai } 2882ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); 2883985be54bSTakashi Iwai 2884d5191e50STakashi Iwai /** 2885d5191e50STakashi Iwai * snd_hda_mixer_bind_switch_put - Put callback for a bound volume control 2886d5191e50STakashi Iwai * 2887d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2888d5191e50STakashi Iwai * set up via HDA_BIND_MUTE*() macros. 2889d5191e50STakashi Iwai */ 28900ba21762STakashi Iwai int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, 28910ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2892985be54bSTakashi Iwai { 2893985be54bSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2894985be54bSTakashi Iwai unsigned long pval; 2895985be54bSTakashi Iwai int i, indices, err = 0, change = 0; 2896985be54bSTakashi Iwai 28975a9e02e9SWu Fengguang mutex_lock(&codec->control_mutex); 2898985be54bSTakashi Iwai pval = kcontrol->private_value; 2899985be54bSTakashi Iwai indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; 2900985be54bSTakashi Iwai for (i = 0; i < indices; i++) { 29010ba21762STakashi Iwai kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | 29020ba21762STakashi Iwai (i << AMP_VAL_IDX_SHIFT); 2903985be54bSTakashi Iwai err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 2904985be54bSTakashi Iwai if (err < 0) 2905985be54bSTakashi Iwai break; 2906985be54bSTakashi Iwai change |= err; 2907985be54bSTakashi Iwai } 2908985be54bSTakashi Iwai kcontrol->private_value = pval; 29095a9e02e9SWu Fengguang mutex_unlock(&codec->control_mutex); 2910985be54bSTakashi Iwai return err < 0 ? err : change; 2911985be54bSTakashi Iwai } 2912ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); 2913985be54bSTakashi Iwai 2914d5191e50STakashi Iwai /** 2915d5191e50STakashi Iwai * snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control 2916d5191e50STakashi Iwai * 2917d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2918d5191e50STakashi Iwai * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. 2919532d5381STakashi Iwai */ 2920532d5381STakashi Iwai int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, 2921532d5381STakashi Iwai struct snd_ctl_elem_info *uinfo) 2922532d5381STakashi Iwai { 2923532d5381STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2924532d5381STakashi Iwai struct hda_bind_ctls *c; 2925532d5381STakashi Iwai int err; 2926532d5381STakashi Iwai 29275a9e02e9SWu Fengguang mutex_lock(&codec->control_mutex); 292814c65f98SSerge A. Suchkov c = (struct hda_bind_ctls *)kcontrol->private_value; 2929532d5381STakashi Iwai kcontrol->private_value = *c->values; 2930532d5381STakashi Iwai err = c->ops->info(kcontrol, uinfo); 2931532d5381STakashi Iwai kcontrol->private_value = (long)c; 29325a9e02e9SWu Fengguang mutex_unlock(&codec->control_mutex); 2933532d5381STakashi Iwai return err; 2934532d5381STakashi Iwai } 2935ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); 2936532d5381STakashi Iwai 2937d5191e50STakashi Iwai /** 2938d5191e50STakashi Iwai * snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control 2939d5191e50STakashi Iwai * 2940d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2941d5191e50STakashi Iwai * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. 2942d5191e50STakashi Iwai */ 2943532d5381STakashi Iwai int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, 2944532d5381STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2945532d5381STakashi Iwai { 2946532d5381STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2947532d5381STakashi Iwai struct hda_bind_ctls *c; 2948532d5381STakashi Iwai int err; 2949532d5381STakashi Iwai 29505a9e02e9SWu Fengguang mutex_lock(&codec->control_mutex); 295114c65f98SSerge A. Suchkov c = (struct hda_bind_ctls *)kcontrol->private_value; 2952532d5381STakashi Iwai kcontrol->private_value = *c->values; 2953532d5381STakashi Iwai err = c->ops->get(kcontrol, ucontrol); 2954532d5381STakashi Iwai kcontrol->private_value = (long)c; 29555a9e02e9SWu Fengguang mutex_unlock(&codec->control_mutex); 2956532d5381STakashi Iwai return err; 2957532d5381STakashi Iwai } 2958ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); 2959532d5381STakashi Iwai 2960d5191e50STakashi Iwai /** 2961d5191e50STakashi Iwai * snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control 2962d5191e50STakashi Iwai * 2963d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2964d5191e50STakashi Iwai * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. 2965d5191e50STakashi Iwai */ 2966532d5381STakashi Iwai int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, 2967532d5381STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2968532d5381STakashi Iwai { 2969532d5381STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2970532d5381STakashi Iwai struct hda_bind_ctls *c; 2971532d5381STakashi Iwai unsigned long *vals; 2972532d5381STakashi Iwai int err = 0, change = 0; 2973532d5381STakashi Iwai 29745a9e02e9SWu Fengguang mutex_lock(&codec->control_mutex); 297514c65f98SSerge A. Suchkov c = (struct hda_bind_ctls *)kcontrol->private_value; 2976532d5381STakashi Iwai for (vals = c->values; *vals; vals++) { 2977532d5381STakashi Iwai kcontrol->private_value = *vals; 2978532d5381STakashi Iwai err = c->ops->put(kcontrol, ucontrol); 2979532d5381STakashi Iwai if (err < 0) 2980532d5381STakashi Iwai break; 2981532d5381STakashi Iwai change |= err; 2982532d5381STakashi Iwai } 2983532d5381STakashi Iwai kcontrol->private_value = (long)c; 29845a9e02e9SWu Fengguang mutex_unlock(&codec->control_mutex); 2985532d5381STakashi Iwai return err < 0 ? err : change; 2986532d5381STakashi Iwai } 2987ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); 2988532d5381STakashi Iwai 2989d5191e50STakashi Iwai /** 2990d5191e50STakashi Iwai * snd_hda_mixer_bind_tlv - TLV callback for a generic bound control 2991d5191e50STakashi Iwai * 2992d5191e50STakashi Iwai * The control element is supposed to have the private_value field 2993d5191e50STakashi Iwai * set up via HDA_BIND_VOL() macro. 2994d5191e50STakashi Iwai */ 2995532d5381STakashi Iwai int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, 2996532d5381STakashi Iwai unsigned int size, unsigned int __user *tlv) 2997532d5381STakashi Iwai { 2998532d5381STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2999532d5381STakashi Iwai struct hda_bind_ctls *c; 3000532d5381STakashi Iwai int err; 3001532d5381STakashi Iwai 30025a9e02e9SWu Fengguang mutex_lock(&codec->control_mutex); 300314c65f98SSerge A. Suchkov c = (struct hda_bind_ctls *)kcontrol->private_value; 3004532d5381STakashi Iwai kcontrol->private_value = *c->values; 3005532d5381STakashi Iwai err = c->ops->tlv(kcontrol, op_flag, size, tlv); 3006532d5381STakashi Iwai kcontrol->private_value = (long)c; 30075a9e02e9SWu Fengguang mutex_unlock(&codec->control_mutex); 3008532d5381STakashi Iwai return err; 3009532d5381STakashi Iwai } 3010ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); 3011532d5381STakashi Iwai 3012532d5381STakashi Iwai struct hda_ctl_ops snd_hda_bind_vol = { 3013532d5381STakashi Iwai .info = snd_hda_mixer_amp_volume_info, 3014532d5381STakashi Iwai .get = snd_hda_mixer_amp_volume_get, 3015532d5381STakashi Iwai .put = snd_hda_mixer_amp_volume_put, 3016532d5381STakashi Iwai .tlv = snd_hda_mixer_amp_tlv 3017532d5381STakashi Iwai }; 3018ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_bind_vol); 3019532d5381STakashi Iwai 3020532d5381STakashi Iwai struct hda_ctl_ops snd_hda_bind_sw = { 3021532d5381STakashi Iwai .info = snd_hda_mixer_amp_switch_info, 3022532d5381STakashi Iwai .get = snd_hda_mixer_amp_switch_get, 3023532d5381STakashi Iwai .put = snd_hda_mixer_amp_switch_put, 3024532d5381STakashi Iwai .tlv = snd_hda_mixer_amp_tlv 3025532d5381STakashi Iwai }; 3026ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_bind_sw); 3027532d5381STakashi Iwai 3028532d5381STakashi Iwai /* 30291da177e4SLinus Torvalds * SPDIF out controls 30301da177e4SLinus Torvalds */ 30311da177e4SLinus Torvalds 30320ba21762STakashi Iwai static int snd_hda_spdif_mask_info(struct snd_kcontrol *kcontrol, 30330ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo) 30341da177e4SLinus Torvalds { 30351da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 30361da177e4SLinus Torvalds uinfo->count = 1; 30371da177e4SLinus Torvalds return 0; 30381da177e4SLinus Torvalds } 30391da177e4SLinus Torvalds 30400ba21762STakashi Iwai static int snd_hda_spdif_cmask_get(struct snd_kcontrol *kcontrol, 30410ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 30421da177e4SLinus Torvalds { 30431da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL | 30441da177e4SLinus Torvalds IEC958_AES0_NONAUDIO | 30451da177e4SLinus Torvalds IEC958_AES0_CON_EMPHASIS_5015 | 30461da177e4SLinus Torvalds IEC958_AES0_CON_NOT_COPYRIGHT; 30471da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY | 30481da177e4SLinus Torvalds IEC958_AES1_CON_ORIGINAL; 30491da177e4SLinus Torvalds return 0; 30501da177e4SLinus Torvalds } 30511da177e4SLinus Torvalds 30520ba21762STakashi Iwai static int snd_hda_spdif_pmask_get(struct snd_kcontrol *kcontrol, 30530ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 30541da177e4SLinus Torvalds { 30551da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL | 30561da177e4SLinus Torvalds IEC958_AES0_NONAUDIO | 30571da177e4SLinus Torvalds IEC958_AES0_PRO_EMPHASIS_5015; 30581da177e4SLinus Torvalds return 0; 30591da177e4SLinus Torvalds } 30601da177e4SLinus Torvalds 30610ba21762STakashi Iwai static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol, 30620ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 30631da177e4SLinus Torvalds { 30641da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 30657c935976SStephen Warren int idx = kcontrol->private_value; 3066e3245cddSTakashi Iwai struct hda_spdif_out *spdif; 30671da177e4SLinus Torvalds 3068e3245cddSTakashi Iwai mutex_lock(&codec->spdif_mutex); 3069e3245cddSTakashi Iwai spdif = snd_array_elem(&codec->spdif_out, idx); 30707c935976SStephen Warren ucontrol->value.iec958.status[0] = spdif->status & 0xff; 30717c935976SStephen Warren ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff; 30727c935976SStephen Warren ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff; 30737c935976SStephen Warren ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff; 3074e3245cddSTakashi Iwai mutex_unlock(&codec->spdif_mutex); 30751da177e4SLinus Torvalds 30761da177e4SLinus Torvalds return 0; 30771da177e4SLinus Torvalds } 30781da177e4SLinus Torvalds 30791da177e4SLinus Torvalds /* convert from SPDIF status bits to HDA SPDIF bits 30801da177e4SLinus Torvalds * bit 0 (DigEn) is always set zero (to be filled later) 30811da177e4SLinus Torvalds */ 30821da177e4SLinus Torvalds static unsigned short convert_from_spdif_status(unsigned int sbits) 30831da177e4SLinus Torvalds { 30841da177e4SLinus Torvalds unsigned short val = 0; 30851da177e4SLinus Torvalds 30861da177e4SLinus Torvalds if (sbits & IEC958_AES0_PROFESSIONAL) 30870ba21762STakashi Iwai val |= AC_DIG1_PROFESSIONAL; 30881da177e4SLinus Torvalds if (sbits & IEC958_AES0_NONAUDIO) 30890ba21762STakashi Iwai val |= AC_DIG1_NONAUDIO; 30901da177e4SLinus Torvalds if (sbits & IEC958_AES0_PROFESSIONAL) { 30910ba21762STakashi Iwai if ((sbits & IEC958_AES0_PRO_EMPHASIS) == 30920ba21762STakashi Iwai IEC958_AES0_PRO_EMPHASIS_5015) 30930ba21762STakashi Iwai val |= AC_DIG1_EMPHASIS; 30941da177e4SLinus Torvalds } else { 30950ba21762STakashi Iwai if ((sbits & IEC958_AES0_CON_EMPHASIS) == 30960ba21762STakashi Iwai IEC958_AES0_CON_EMPHASIS_5015) 30970ba21762STakashi Iwai val |= AC_DIG1_EMPHASIS; 30981da177e4SLinus Torvalds if (!(sbits & IEC958_AES0_CON_NOT_COPYRIGHT)) 30990ba21762STakashi Iwai val |= AC_DIG1_COPYRIGHT; 31001da177e4SLinus Torvalds if (sbits & (IEC958_AES1_CON_ORIGINAL << 8)) 31010ba21762STakashi Iwai val |= AC_DIG1_LEVEL; 31021da177e4SLinus Torvalds val |= sbits & (IEC958_AES1_CON_CATEGORY << 8); 31031da177e4SLinus Torvalds } 31041da177e4SLinus Torvalds return val; 31051da177e4SLinus Torvalds } 31061da177e4SLinus Torvalds 31071da177e4SLinus Torvalds /* convert to SPDIF status bits from HDA SPDIF bits 31081da177e4SLinus Torvalds */ 31091da177e4SLinus Torvalds static unsigned int convert_to_spdif_status(unsigned short val) 31101da177e4SLinus Torvalds { 31111da177e4SLinus Torvalds unsigned int sbits = 0; 31121da177e4SLinus Torvalds 31130ba21762STakashi Iwai if (val & AC_DIG1_NONAUDIO) 31141da177e4SLinus Torvalds sbits |= IEC958_AES0_NONAUDIO; 31150ba21762STakashi Iwai if (val & AC_DIG1_PROFESSIONAL) 31161da177e4SLinus Torvalds sbits |= IEC958_AES0_PROFESSIONAL; 31171da177e4SLinus Torvalds if (sbits & IEC958_AES0_PROFESSIONAL) { 31180ba21762STakashi Iwai if (sbits & AC_DIG1_EMPHASIS) 31191da177e4SLinus Torvalds sbits |= IEC958_AES0_PRO_EMPHASIS_5015; 31201da177e4SLinus Torvalds } else { 31210ba21762STakashi Iwai if (val & AC_DIG1_EMPHASIS) 31221da177e4SLinus Torvalds sbits |= IEC958_AES0_CON_EMPHASIS_5015; 31230ba21762STakashi Iwai if (!(val & AC_DIG1_COPYRIGHT)) 31241da177e4SLinus Torvalds sbits |= IEC958_AES0_CON_NOT_COPYRIGHT; 31250ba21762STakashi Iwai if (val & AC_DIG1_LEVEL) 31261da177e4SLinus Torvalds sbits |= (IEC958_AES1_CON_ORIGINAL << 8); 31271da177e4SLinus Torvalds sbits |= val & (0x7f << 8); 31281da177e4SLinus Torvalds } 31291da177e4SLinus Torvalds return sbits; 31301da177e4SLinus Torvalds } 31311da177e4SLinus Torvalds 31322f72853cSTakashi Iwai /* set digital convert verbs both for the given NID and its slaves */ 31332f72853cSTakashi Iwai static void set_dig_out(struct hda_codec *codec, hda_nid_t nid, 31342f72853cSTakashi Iwai int verb, int val) 31352f72853cSTakashi Iwai { 3136dda14410STakashi Iwai const hda_nid_t *d; 31372f72853cSTakashi Iwai 31389e976976STakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, verb, val); 31392f72853cSTakashi Iwai d = codec->slave_dig_outs; 31402f72853cSTakashi Iwai if (!d) 31412f72853cSTakashi Iwai return; 31422f72853cSTakashi Iwai for (; *d; d++) 31439e976976STakashi Iwai snd_hda_codec_write_cache(codec, *d, 0, verb, val); 31442f72853cSTakashi Iwai } 31452f72853cSTakashi Iwai 31462f72853cSTakashi Iwai static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid, 31472f72853cSTakashi Iwai int dig1, int dig2) 31482f72853cSTakashi Iwai { 31492f72853cSTakashi Iwai if (dig1 != -1) 31502f72853cSTakashi Iwai set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1); 31512f72853cSTakashi Iwai if (dig2 != -1) 31522f72853cSTakashi Iwai set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2); 31532f72853cSTakashi Iwai } 31542f72853cSTakashi Iwai 31550ba21762STakashi Iwai static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, 31560ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 31571da177e4SLinus Torvalds { 31581da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 31597c935976SStephen Warren int idx = kcontrol->private_value; 3160e3245cddSTakashi Iwai struct hda_spdif_out *spdif; 3161e3245cddSTakashi Iwai hda_nid_t nid; 31621da177e4SLinus Torvalds unsigned short val; 31631da177e4SLinus Torvalds int change; 31641da177e4SLinus Torvalds 316562932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 3166e3245cddSTakashi Iwai spdif = snd_array_elem(&codec->spdif_out, idx); 3167e3245cddSTakashi Iwai nid = spdif->nid; 31687c935976SStephen Warren spdif->status = ucontrol->value.iec958.status[0] | 31691da177e4SLinus Torvalds ((unsigned int)ucontrol->value.iec958.status[1] << 8) | 31701da177e4SLinus Torvalds ((unsigned int)ucontrol->value.iec958.status[2] << 16) | 31711da177e4SLinus Torvalds ((unsigned int)ucontrol->value.iec958.status[3] << 24); 31727c935976SStephen Warren val = convert_from_spdif_status(spdif->status); 31737c935976SStephen Warren val |= spdif->ctls & 1; 31747c935976SStephen Warren change = spdif->ctls != val; 31757c935976SStephen Warren spdif->ctls = val; 317674b654c9SStephen Warren if (change && nid != (u16)-1) 31772f72853cSTakashi Iwai set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff); 317862932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 31791da177e4SLinus Torvalds return change; 31801da177e4SLinus Torvalds } 31811da177e4SLinus Torvalds 3182a5ce8890STakashi Iwai #define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info 31831da177e4SLinus Torvalds 31840ba21762STakashi Iwai static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, 31850ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 31861da177e4SLinus Torvalds { 31871da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 31887c935976SStephen Warren int idx = kcontrol->private_value; 3189e3245cddSTakashi Iwai struct hda_spdif_out *spdif; 31901da177e4SLinus Torvalds 3191e3245cddSTakashi Iwai mutex_lock(&codec->spdif_mutex); 3192e3245cddSTakashi Iwai spdif = snd_array_elem(&codec->spdif_out, idx); 31937c935976SStephen Warren ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE; 3194e3245cddSTakashi Iwai mutex_unlock(&codec->spdif_mutex); 31951da177e4SLinus Torvalds return 0; 31961da177e4SLinus Torvalds } 31971da177e4SLinus Torvalds 319874b654c9SStephen Warren static inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid, 319974b654c9SStephen Warren int dig1, int dig2) 320074b654c9SStephen Warren { 320174b654c9SStephen Warren set_dig_out_convert(codec, nid, dig1, dig2); 320274b654c9SStephen Warren /* unmute amp switch (if any) */ 320374b654c9SStephen Warren if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && 320474b654c9SStephen Warren (dig1 & AC_DIG1_ENABLE)) 320574b654c9SStephen Warren snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, 320674b654c9SStephen Warren HDA_AMP_MUTE, 0); 320774b654c9SStephen Warren } 320874b654c9SStephen Warren 32090ba21762STakashi Iwai static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, 32100ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 32111da177e4SLinus Torvalds { 32121da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 32137c935976SStephen Warren int idx = kcontrol->private_value; 3214e3245cddSTakashi Iwai struct hda_spdif_out *spdif; 3215e3245cddSTakashi Iwai hda_nid_t nid; 32161da177e4SLinus Torvalds unsigned short val; 32171da177e4SLinus Torvalds int change; 32181da177e4SLinus Torvalds 321962932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 3220e3245cddSTakashi Iwai spdif = snd_array_elem(&codec->spdif_out, idx); 3221e3245cddSTakashi Iwai nid = spdif->nid; 32227c935976SStephen Warren val = spdif->ctls & ~AC_DIG1_ENABLE; 32231da177e4SLinus Torvalds if (ucontrol->value.integer.value[0]) 32240ba21762STakashi Iwai val |= AC_DIG1_ENABLE; 32257c935976SStephen Warren change = spdif->ctls != val; 32267c935976SStephen Warren spdif->ctls = val; 322774b654c9SStephen Warren if (change && nid != (u16)-1) 322874b654c9SStephen Warren set_spdif_ctls(codec, nid, val & 0xff, -1); 322962932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 32301da177e4SLinus Torvalds return change; 32311da177e4SLinus Torvalds } 32321da177e4SLinus Torvalds 3233c8b6bf9bSTakashi Iwai static struct snd_kcontrol_new dig_mixes[] = { 32341da177e4SLinus Torvalds { 32351da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 32361da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 32371da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), 32381da177e4SLinus Torvalds .info = snd_hda_spdif_mask_info, 32391da177e4SLinus Torvalds .get = snd_hda_spdif_cmask_get, 32401da177e4SLinus Torvalds }, 32411da177e4SLinus Torvalds { 32421da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 32431da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 32441da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK), 32451da177e4SLinus Torvalds .info = snd_hda_spdif_mask_info, 32461da177e4SLinus Torvalds .get = snd_hda_spdif_pmask_get, 32471da177e4SLinus Torvalds }, 32481da177e4SLinus Torvalds { 32491da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 32501da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 32511da177e4SLinus Torvalds .info = snd_hda_spdif_mask_info, 32521da177e4SLinus Torvalds .get = snd_hda_spdif_default_get, 32531da177e4SLinus Torvalds .put = snd_hda_spdif_default_put, 32541da177e4SLinus Torvalds }, 32551da177e4SLinus Torvalds { 32561da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 32571da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), 32581da177e4SLinus Torvalds .info = snd_hda_spdif_out_switch_info, 32591da177e4SLinus Torvalds .get = snd_hda_spdif_out_switch_get, 32601da177e4SLinus Torvalds .put = snd_hda_spdif_out_switch_put, 32611da177e4SLinus Torvalds }, 32621da177e4SLinus Torvalds { } /* end */ 32631da177e4SLinus Torvalds }; 32641da177e4SLinus Torvalds 32651da177e4SLinus Torvalds /** 3266dcda5806STakashi Iwai * snd_hda_create_dig_out_ctls - create Output SPDIF-related controls 32671da177e4SLinus Torvalds * @codec: the HDA codec 3268dcda5806STakashi Iwai * @associated_nid: NID that new ctls associated with 3269dcda5806STakashi Iwai * @cvt_nid: converter NID 3270dcda5806STakashi Iwai * @type: HDA_PCM_TYPE_* 3271dcda5806STakashi Iwai * Creates controls related with the digital output. 3272dcda5806STakashi Iwai * Called from each patch supporting the digital out. 32731da177e4SLinus Torvalds * 32741da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 32751da177e4SLinus Torvalds */ 3276dcda5806STakashi Iwai int snd_hda_create_dig_out_ctls(struct hda_codec *codec, 327774b654c9SStephen Warren hda_nid_t associated_nid, 3278dcda5806STakashi Iwai hda_nid_t cvt_nid, 3279dcda5806STakashi Iwai int type) 32801da177e4SLinus Torvalds { 32811da177e4SLinus Torvalds int err; 3282c8b6bf9bSTakashi Iwai struct snd_kcontrol *kctl; 3283c8b6bf9bSTakashi Iwai struct snd_kcontrol_new *dig_mix; 3284dcda5806STakashi Iwai int idx, dev = 0; 3285dcda5806STakashi Iwai const int spdif_pcm_dev = 1; 32867c935976SStephen Warren struct hda_spdif_out *spdif; 32871da177e4SLinus Torvalds 3288dcda5806STakashi Iwai if (codec->primary_dig_out_type == HDA_PCM_TYPE_HDMI && 3289dcda5806STakashi Iwai type == HDA_PCM_TYPE_SPDIF) { 3290dcda5806STakashi Iwai dev = spdif_pcm_dev; 3291dcda5806STakashi Iwai } else if (codec->primary_dig_out_type == HDA_PCM_TYPE_SPDIF && 3292dcda5806STakashi Iwai type == HDA_PCM_TYPE_HDMI) { 3293dcda5806STakashi Iwai for (idx = 0; idx < codec->spdif_out.used; idx++) { 3294dcda5806STakashi Iwai spdif = snd_array_elem(&codec->spdif_out, idx); 3295dcda5806STakashi Iwai for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { 3296dcda5806STakashi Iwai kctl = find_mixer_ctl(codec, dig_mix->name, 0, idx); 3297dcda5806STakashi Iwai if (!kctl) 3298dcda5806STakashi Iwai break; 3299dcda5806STakashi Iwai kctl->id.device = spdif_pcm_dev; 3300dcda5806STakashi Iwai } 3301dcda5806STakashi Iwai } 3302dcda5806STakashi Iwai codec->primary_dig_out_type = HDA_PCM_TYPE_HDMI; 3303dcda5806STakashi Iwai } 3304dcda5806STakashi Iwai if (!codec->primary_dig_out_type) 3305dcda5806STakashi Iwai codec->primary_dig_out_type = type; 3306dcda5806STakashi Iwai 3307dcda5806STakashi Iwai idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", dev); 33081afe206aSTakashi Iwai if (idx < 0) { 330909f99701STakashi Iwai printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); 331009f99701STakashi Iwai return -EBUSY; 331109f99701STakashi Iwai } 33127c935976SStephen Warren spdif = snd_array_new(&codec->spdif_out); 33131da177e4SLinus Torvalds for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { 33141da177e4SLinus Torvalds kctl = snd_ctl_new1(dig_mix, codec); 3315b91f080fSTakashi Iwai if (!kctl) 3316b91f080fSTakashi Iwai return -ENOMEM; 3317dcda5806STakashi Iwai kctl->id.device = dev; 331809f99701STakashi Iwai kctl->id.index = idx; 33197c935976SStephen Warren kctl->private_value = codec->spdif_out.used - 1; 332074b654c9SStephen Warren err = snd_hda_ctl_add(codec, associated_nid, kctl); 33210ba21762STakashi Iwai if (err < 0) 33221da177e4SLinus Torvalds return err; 33231da177e4SLinus Torvalds } 332474b654c9SStephen Warren spdif->nid = cvt_nid; 332574b654c9SStephen Warren spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0, 33263982d17eSAndrew Paprocki AC_VERB_GET_DIGI_CONVERT_1, 0); 33277c935976SStephen Warren spdif->status = convert_to_spdif_status(spdif->ctls); 33281da177e4SLinus Torvalds return 0; 33291da177e4SLinus Torvalds } 3330dcda5806STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_create_dig_out_ctls); 33311da177e4SLinus Torvalds 3332e3245cddSTakashi Iwai /* get the hda_spdif_out entry from the given NID 3333e3245cddSTakashi Iwai * call within spdif_mutex lock 3334e3245cddSTakashi Iwai */ 33357c935976SStephen Warren struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, 33367c935976SStephen Warren hda_nid_t nid) 33377c935976SStephen Warren { 33387c935976SStephen Warren int i; 33397c935976SStephen Warren for (i = 0; i < codec->spdif_out.used; i++) { 33407c935976SStephen Warren struct hda_spdif_out *spdif = 33417c935976SStephen Warren snd_array_elem(&codec->spdif_out, i); 33427c935976SStephen Warren if (spdif->nid == nid) 33437c935976SStephen Warren return spdif; 33447c935976SStephen Warren } 33457c935976SStephen Warren return NULL; 33467c935976SStephen Warren } 33477c935976SStephen Warren EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid); 33487c935976SStephen Warren 334974b654c9SStephen Warren void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) 335074b654c9SStephen Warren { 3351e3245cddSTakashi Iwai struct hda_spdif_out *spdif; 335274b654c9SStephen Warren 335374b654c9SStephen Warren mutex_lock(&codec->spdif_mutex); 3354e3245cddSTakashi Iwai spdif = snd_array_elem(&codec->spdif_out, idx); 335574b654c9SStephen Warren spdif->nid = (u16)-1; 335674b654c9SStephen Warren mutex_unlock(&codec->spdif_mutex); 335774b654c9SStephen Warren } 335874b654c9SStephen Warren EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign); 335974b654c9SStephen Warren 336074b654c9SStephen Warren void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) 336174b654c9SStephen Warren { 3362e3245cddSTakashi Iwai struct hda_spdif_out *spdif; 336374b654c9SStephen Warren unsigned short val; 336474b654c9SStephen Warren 336574b654c9SStephen Warren mutex_lock(&codec->spdif_mutex); 3366e3245cddSTakashi Iwai spdif = snd_array_elem(&codec->spdif_out, idx); 336774b654c9SStephen Warren if (spdif->nid != nid) { 336874b654c9SStephen Warren spdif->nid = nid; 336974b654c9SStephen Warren val = spdif->ctls; 337074b654c9SStephen Warren set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff); 337174b654c9SStephen Warren } 337274b654c9SStephen Warren mutex_unlock(&codec->spdif_mutex); 337374b654c9SStephen Warren } 337474b654c9SStephen Warren EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign); 337574b654c9SStephen Warren 33761da177e4SLinus Torvalds /* 33779a08160bSTakashi Iwai * SPDIF sharing with analog output 33789a08160bSTakashi Iwai */ 33799a08160bSTakashi Iwai static int spdif_share_sw_get(struct snd_kcontrol *kcontrol, 33809a08160bSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 33819a08160bSTakashi Iwai { 33829a08160bSTakashi Iwai struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol); 33839a08160bSTakashi Iwai ucontrol->value.integer.value[0] = mout->share_spdif; 33849a08160bSTakashi Iwai return 0; 33859a08160bSTakashi Iwai } 33869a08160bSTakashi Iwai 33879a08160bSTakashi Iwai static int spdif_share_sw_put(struct snd_kcontrol *kcontrol, 33889a08160bSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 33899a08160bSTakashi Iwai { 33909a08160bSTakashi Iwai struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol); 33919a08160bSTakashi Iwai mout->share_spdif = !!ucontrol->value.integer.value[0]; 33929a08160bSTakashi Iwai return 0; 33939a08160bSTakashi Iwai } 33949a08160bSTakashi Iwai 33959a08160bSTakashi Iwai static struct snd_kcontrol_new spdif_share_sw = { 33969a08160bSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 33979a08160bSTakashi Iwai .name = "IEC958 Default PCM Playback Switch", 33989a08160bSTakashi Iwai .info = snd_ctl_boolean_mono_info, 33999a08160bSTakashi Iwai .get = spdif_share_sw_get, 34009a08160bSTakashi Iwai .put = spdif_share_sw_put, 34019a08160bSTakashi Iwai }; 34029a08160bSTakashi Iwai 3403d5191e50STakashi Iwai /** 3404d5191e50STakashi Iwai * snd_hda_create_spdif_share_sw - create Default PCM switch 3405d5191e50STakashi Iwai * @codec: the HDA codec 3406d5191e50STakashi Iwai * @mout: multi-out instance 3407d5191e50STakashi Iwai */ 34089a08160bSTakashi Iwai int snd_hda_create_spdif_share_sw(struct hda_codec *codec, 34099a08160bSTakashi Iwai struct hda_multi_out *mout) 34109a08160bSTakashi Iwai { 34119a08160bSTakashi Iwai if (!mout->dig_out_nid) 34129a08160bSTakashi Iwai return 0; 34139a08160bSTakashi Iwai /* ATTENTION: here mout is passed as private_data, instead of codec */ 34143911a4c1SJaroslav Kysela return snd_hda_ctl_add(codec, mout->dig_out_nid, 34159a08160bSTakashi Iwai snd_ctl_new1(&spdif_share_sw, mout)); 34169a08160bSTakashi Iwai } 3417ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw); 34189a08160bSTakashi Iwai 34199a08160bSTakashi Iwai /* 34201da177e4SLinus Torvalds * SPDIF input 34211da177e4SLinus Torvalds */ 34221da177e4SLinus Torvalds 34231da177e4SLinus Torvalds #define snd_hda_spdif_in_switch_info snd_hda_spdif_out_switch_info 34241da177e4SLinus Torvalds 34250ba21762STakashi Iwai static int snd_hda_spdif_in_switch_get(struct snd_kcontrol *kcontrol, 34260ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 34271da177e4SLinus Torvalds { 34281da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 34291da177e4SLinus Torvalds 34301da177e4SLinus Torvalds ucontrol->value.integer.value[0] = codec->spdif_in_enable; 34311da177e4SLinus Torvalds return 0; 34321da177e4SLinus Torvalds } 34331da177e4SLinus Torvalds 34340ba21762STakashi Iwai static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, 34350ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 34361da177e4SLinus Torvalds { 34371da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 34381da177e4SLinus Torvalds hda_nid_t nid = kcontrol->private_value; 34391da177e4SLinus Torvalds unsigned int val = !!ucontrol->value.integer.value[0]; 34401da177e4SLinus Torvalds int change; 34411da177e4SLinus Torvalds 344262932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 34431da177e4SLinus Torvalds change = codec->spdif_in_enable != val; 344482beb8fdSTakashi Iwai if (change) { 34451da177e4SLinus Torvalds codec->spdif_in_enable = val; 344682beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 344782beb8fdSTakashi Iwai AC_VERB_SET_DIGI_CONVERT_1, val); 34481da177e4SLinus Torvalds } 344962932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 34501da177e4SLinus Torvalds return change; 34511da177e4SLinus Torvalds } 34521da177e4SLinus Torvalds 34530ba21762STakashi Iwai static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol, 34540ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol) 34551da177e4SLinus Torvalds { 34561da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 34571da177e4SLinus Torvalds hda_nid_t nid = kcontrol->private_value; 34581da177e4SLinus Torvalds unsigned short val; 34591da177e4SLinus Torvalds unsigned int sbits; 34601da177e4SLinus Torvalds 34613982d17eSAndrew Paprocki val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); 34621da177e4SLinus Torvalds sbits = convert_to_spdif_status(val); 34631da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = sbits; 34641da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = sbits >> 8; 34651da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = sbits >> 16; 34661da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = sbits >> 24; 34671da177e4SLinus Torvalds return 0; 34681da177e4SLinus Torvalds } 34691da177e4SLinus Torvalds 3470c8b6bf9bSTakashi Iwai static struct snd_kcontrol_new dig_in_ctls[] = { 34711da177e4SLinus Torvalds { 34721da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 34731da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH), 34741da177e4SLinus Torvalds .info = snd_hda_spdif_in_switch_info, 34751da177e4SLinus Torvalds .get = snd_hda_spdif_in_switch_get, 34761da177e4SLinus Torvalds .put = snd_hda_spdif_in_switch_put, 34771da177e4SLinus Torvalds }, 34781da177e4SLinus Torvalds { 34791da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 34801da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 34811da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 34821da177e4SLinus Torvalds .info = snd_hda_spdif_mask_info, 34831da177e4SLinus Torvalds .get = snd_hda_spdif_in_status_get, 34841da177e4SLinus Torvalds }, 34851da177e4SLinus Torvalds { } /* end */ 34861da177e4SLinus Torvalds }; 34871da177e4SLinus Torvalds 34881da177e4SLinus Torvalds /** 34891da177e4SLinus Torvalds * snd_hda_create_spdif_in_ctls - create Input SPDIF-related controls 34901da177e4SLinus Torvalds * @codec: the HDA codec 34911da177e4SLinus Torvalds * @nid: audio in widget NID 34921da177e4SLinus Torvalds * 34931da177e4SLinus Torvalds * Creates controls related with the SPDIF input. 34941da177e4SLinus Torvalds * Called from each patch supporting the SPDIF in. 34951da177e4SLinus Torvalds * 34961da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 34971da177e4SLinus Torvalds */ 349812f288bfSTakashi Iwai int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) 34991da177e4SLinus Torvalds { 35001da177e4SLinus Torvalds int err; 3501c8b6bf9bSTakashi Iwai struct snd_kcontrol *kctl; 3502c8b6bf9bSTakashi Iwai struct snd_kcontrol_new *dig_mix; 350309f99701STakashi Iwai int idx; 35041da177e4SLinus Torvalds 3505dcda5806STakashi Iwai idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0); 35061afe206aSTakashi Iwai if (idx < 0) { 350709f99701STakashi Iwai printk(KERN_ERR "hda_codec: too many IEC958 inputs\n"); 350809f99701STakashi Iwai return -EBUSY; 350909f99701STakashi Iwai } 35101da177e4SLinus Torvalds for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { 35111da177e4SLinus Torvalds kctl = snd_ctl_new1(dig_mix, codec); 3512c8dcdf82STakashi Iwai if (!kctl) 3513c8dcdf82STakashi Iwai return -ENOMEM; 35141da177e4SLinus Torvalds kctl->private_value = nid; 35153911a4c1SJaroslav Kysela err = snd_hda_ctl_add(codec, nid, kctl); 35160ba21762STakashi Iwai if (err < 0) 35171da177e4SLinus Torvalds return err; 35181da177e4SLinus Torvalds } 35190ba21762STakashi Iwai codec->spdif_in_enable = 35203982d17eSAndrew Paprocki snd_hda_codec_read(codec, nid, 0, 35213982d17eSAndrew Paprocki AC_VERB_GET_DIGI_CONVERT_1, 0) & 35220ba21762STakashi Iwai AC_DIG1_ENABLE; 35231da177e4SLinus Torvalds return 0; 35241da177e4SLinus Torvalds } 3525ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); 35261da177e4SLinus Torvalds 352782beb8fdSTakashi Iwai /* 352882beb8fdSTakashi Iwai * command cache 352982beb8fdSTakashi Iwai */ 35301da177e4SLinus Torvalds 3531c370dd6eSTakashi Iwai /* build a 31bit cache key with the widget id and the command parameter */ 3532b3ac5636STakashi Iwai #define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) 3533b3ac5636STakashi Iwai #define get_cmd_cache_nid(key) ((key) & 0xff) 3534b3ac5636STakashi Iwai #define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) 3535b3ac5636STakashi Iwai 3536b3ac5636STakashi Iwai /** 3537b3ac5636STakashi Iwai * snd_hda_codec_write_cache - send a single command with caching 3538b3ac5636STakashi Iwai * @codec: the HDA codec 3539b3ac5636STakashi Iwai * @nid: NID to send the command 3540b3ac5636STakashi Iwai * @direct: direct flag 3541b3ac5636STakashi Iwai * @verb: the verb to send 3542b3ac5636STakashi Iwai * @parm: the parameter for the verb 3543b3ac5636STakashi Iwai * 3544b3ac5636STakashi Iwai * Send a single command without waiting for response. 3545b3ac5636STakashi Iwai * 3546b3ac5636STakashi Iwai * Returns 0 if successful, or a negative error code. 3547b3ac5636STakashi Iwai */ 3548b3ac5636STakashi Iwai int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, 3549b3ac5636STakashi Iwai int direct, unsigned int verb, unsigned int parm) 3550b3ac5636STakashi Iwai { 3551c370dd6eSTakashi Iwai int err; 3552b3ac5636STakashi Iwai struct hda_cache_head *c; 3553fcad94a4STakashi Iwai u32 key; 3554de1e37b7STakashi Iwai unsigned int cache_only; 3555aa2936f5STakashi Iwai 3556de1e37b7STakashi Iwai cache_only = codec->cached_write; 3557de1e37b7STakashi Iwai if (!cache_only) { 3558c370dd6eSTakashi Iwai err = snd_hda_codec_write(codec, nid, direct, verb, parm); 3559aa2936f5STakashi Iwai if (err < 0) 3560aa2936f5STakashi Iwai return err; 3561c370dd6eSTakashi Iwai } 3562c370dd6eSTakashi Iwai 3563fcad94a4STakashi Iwai /* parm may contain the verb stuff for get/set amp */ 3564fcad94a4STakashi Iwai verb = verb | (parm >> 8); 3565fcad94a4STakashi Iwai parm &= 0xff; 3566fcad94a4STakashi Iwai key = build_cmd_cache_key(nid, verb); 3567aa2936f5STakashi Iwai mutex_lock(&codec->bus->cmd_mutex); 3568b3ac5636STakashi Iwai c = get_alloc_hash(&codec->cmd_cache, key); 3569c370dd6eSTakashi Iwai if (c) { 3570b3ac5636STakashi Iwai c->val = parm; 3571de1e37b7STakashi Iwai c->dirty = cache_only; 3572c370dd6eSTakashi Iwai } 3573aa2936f5STakashi Iwai mutex_unlock(&codec->bus->cmd_mutex); 3574aa2936f5STakashi Iwai return 0; 3575b3ac5636STakashi Iwai } 3576ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); 3577b3ac5636STakashi Iwai 3578d5191e50STakashi Iwai /** 3579a68d5a54STakashi Iwai * snd_hda_codec_update_cache - check cache and write the cmd only when needed 3580a68d5a54STakashi Iwai * @codec: the HDA codec 3581a68d5a54STakashi Iwai * @nid: NID to send the command 3582a68d5a54STakashi Iwai * @direct: direct flag 3583a68d5a54STakashi Iwai * @verb: the verb to send 3584a68d5a54STakashi Iwai * @parm: the parameter for the verb 3585a68d5a54STakashi Iwai * 3586a68d5a54STakashi Iwai * This function works like snd_hda_codec_write_cache(), but it doesn't send 3587a68d5a54STakashi Iwai * command if the parameter is already identical with the cached value. 3588a68d5a54STakashi Iwai * If not, it sends the command and refreshes the cache. 3589a68d5a54STakashi Iwai * 3590a68d5a54STakashi Iwai * Returns 0 if successful, or a negative error code. 3591a68d5a54STakashi Iwai */ 3592a68d5a54STakashi Iwai int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, 3593a68d5a54STakashi Iwai int direct, unsigned int verb, unsigned int parm) 3594a68d5a54STakashi Iwai { 3595a68d5a54STakashi Iwai struct hda_cache_head *c; 3596a68d5a54STakashi Iwai u32 key; 3597a68d5a54STakashi Iwai 3598a68d5a54STakashi Iwai /* parm may contain the verb stuff for get/set amp */ 3599a68d5a54STakashi Iwai verb = verb | (parm >> 8); 3600a68d5a54STakashi Iwai parm &= 0xff; 3601a68d5a54STakashi Iwai key = build_cmd_cache_key(nid, verb); 3602a68d5a54STakashi Iwai mutex_lock(&codec->bus->cmd_mutex); 3603a68d5a54STakashi Iwai c = get_hash(&codec->cmd_cache, key); 3604a68d5a54STakashi Iwai if (c && c->val == parm) { 3605a68d5a54STakashi Iwai mutex_unlock(&codec->bus->cmd_mutex); 3606a68d5a54STakashi Iwai return 0; 3607a68d5a54STakashi Iwai } 3608a68d5a54STakashi Iwai mutex_unlock(&codec->bus->cmd_mutex); 3609a68d5a54STakashi Iwai return snd_hda_codec_write_cache(codec, nid, direct, verb, parm); 3610a68d5a54STakashi Iwai } 3611a68d5a54STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache); 3612a68d5a54STakashi Iwai 3613a68d5a54STakashi Iwai /** 3614d5191e50STakashi Iwai * snd_hda_codec_resume_cache - Resume the all commands from the cache 3615d5191e50STakashi Iwai * @codec: HD-audio codec 3616d5191e50STakashi Iwai * 3617d5191e50STakashi Iwai * Execute all verbs recorded in the command caches to resume. 3618d5191e50STakashi Iwai */ 3619b3ac5636STakashi Iwai void snd_hda_codec_resume_cache(struct hda_codec *codec) 3620b3ac5636STakashi Iwai { 3621b3ac5636STakashi Iwai int i; 3622b3ac5636STakashi Iwai 3623c370dd6eSTakashi Iwai mutex_lock(&codec->hash_mutex); 3624aa88a355STakashi Iwai codec->cached_write = 0; 3625c370dd6eSTakashi Iwai for (i = 0; i < codec->cmd_cache.buf.used; i++) { 3626c370dd6eSTakashi Iwai struct hda_cache_head *buffer; 3627c370dd6eSTakashi Iwai u32 key; 3628c370dd6eSTakashi Iwai 3629c370dd6eSTakashi Iwai buffer = snd_array_elem(&codec->cmd_cache.buf, i); 3630c370dd6eSTakashi Iwai key = buffer->key; 3631b3ac5636STakashi Iwai if (!key) 3632b3ac5636STakashi Iwai continue; 3633c370dd6eSTakashi Iwai if (!buffer->dirty) 3634c370dd6eSTakashi Iwai continue; 3635c370dd6eSTakashi Iwai buffer->dirty = 0; 3636c370dd6eSTakashi Iwai mutex_unlock(&codec->hash_mutex); 3637b3ac5636STakashi Iwai snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, 3638b3ac5636STakashi Iwai get_cmd_cache_cmd(key), buffer->val); 3639c370dd6eSTakashi Iwai mutex_lock(&codec->hash_mutex); 3640b3ac5636STakashi Iwai } 3641c370dd6eSTakashi Iwai mutex_unlock(&codec->hash_mutex); 3642b3ac5636STakashi Iwai } 3643ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache); 3644b3ac5636STakashi Iwai 3645b3ac5636STakashi Iwai /** 3646b3ac5636STakashi Iwai * snd_hda_sequence_write_cache - sequence writes with caching 3647b3ac5636STakashi Iwai * @codec: the HDA codec 3648b3ac5636STakashi Iwai * @seq: VERB array to send 3649b3ac5636STakashi Iwai * 3650b3ac5636STakashi Iwai * Send the commands sequentially from the given array. 3651b3ac5636STakashi Iwai * Thte commands are recorded on cache for power-save and resume. 3652b3ac5636STakashi Iwai * The array must be terminated with NID=0. 3653b3ac5636STakashi Iwai */ 3654b3ac5636STakashi Iwai void snd_hda_sequence_write_cache(struct hda_codec *codec, 3655b3ac5636STakashi Iwai const struct hda_verb *seq) 3656b3ac5636STakashi Iwai { 3657b3ac5636STakashi Iwai for (; seq->nid; seq++) 3658b3ac5636STakashi Iwai snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, 3659b3ac5636STakashi Iwai seq->param); 3660b3ac5636STakashi Iwai } 3661ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); 3662b3ac5636STakashi Iwai 3663dc870f38STakashi Iwai /** 3664dc870f38STakashi Iwai * snd_hda_codec_flush_cache - Execute all pending (cached) amps / verbs 3665dc870f38STakashi Iwai * @codec: HD-audio codec 3666dc870f38STakashi Iwai */ 3667dc870f38STakashi Iwai void snd_hda_codec_flush_cache(struct hda_codec *codec) 3668dc870f38STakashi Iwai { 3669dc870f38STakashi Iwai snd_hda_codec_resume_amp(codec); 3670dc870f38STakashi Iwai snd_hda_codec_resume_cache(codec); 3671dc870f38STakashi Iwai } 3672dc870f38STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_flush_cache); 3673dc870f38STakashi Iwai 36744d7fbdbcSTakashi Iwai void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, 36759419ab6bSTakashi Iwai unsigned int power_state) 367654d17403STakashi Iwai { 36774d7fbdbcSTakashi Iwai hda_nid_t nid = codec->start_nid; 3678cb53c626STakashi Iwai int i; 367954d17403STakashi Iwai 3680cb53c626STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 36817eba5c9dSTakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 36829419ab6bSTakashi Iwai unsigned int state = power_state; 36834d7fbdbcSTakashi Iwai if (!(wcaps & AC_WCAP_POWER)) 36844d7fbdbcSTakashi Iwai continue; 36859419ab6bSTakashi Iwai if (codec->power_filter) { 36869419ab6bSTakashi Iwai state = codec->power_filter(codec, nid, power_state); 36879419ab6bSTakashi Iwai if (state != power_state && power_state == AC_PWRST_D3) 36881194b5b7STakashi Iwai continue; 36891194b5b7STakashi Iwai } 36904d7fbdbcSTakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, 36919419ab6bSTakashi Iwai state); 369254d17403STakashi Iwai } 3693cb53c626STakashi Iwai } 36944d7fbdbcSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); 36954d7fbdbcSTakashi Iwai 36964d7fbdbcSTakashi Iwai /* 36970c7f46adSWang Xingchao * supported power states check 36980c7f46adSWang Xingchao */ 36990c7f46adSWang Xingchao static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg, 37000c7f46adSWang Xingchao unsigned int power_state) 37010c7f46adSWang Xingchao { 37020c7f46adSWang Xingchao int sup = snd_hda_param_read(codec, fg, AC_PAR_POWER_STATE); 37030c7f46adSWang Xingchao 3704e037cb4aSMengdong Lin if (sup == -1) 37050c7f46adSWang Xingchao return false; 37060c7f46adSWang Xingchao if (sup & power_state) 37070c7f46adSWang Xingchao return true; 37080c7f46adSWang Xingchao else 37090c7f46adSWang Xingchao return false; 37100c7f46adSWang Xingchao } 37110c7f46adSWang Xingchao 37120c7f46adSWang Xingchao /* 3713432c641eSTakashi Iwai * wait until the state is reached, returns the current state 3714432c641eSTakashi Iwai */ 3715432c641eSTakashi Iwai static unsigned int hda_sync_power_state(struct hda_codec *codec, 3716432c641eSTakashi Iwai hda_nid_t fg, 3717432c641eSTakashi Iwai unsigned int power_state) 3718432c641eSTakashi Iwai { 3719432c641eSTakashi Iwai unsigned long end_time = jiffies + msecs_to_jiffies(500); 3720432c641eSTakashi Iwai unsigned int state, actual_state; 3721432c641eSTakashi Iwai 3722432c641eSTakashi Iwai for (;;) { 3723432c641eSTakashi Iwai state = snd_hda_codec_read(codec, fg, 0, 3724432c641eSTakashi Iwai AC_VERB_GET_POWER_STATE, 0); 3725432c641eSTakashi Iwai if (state & AC_PWRST_ERROR) 3726432c641eSTakashi Iwai break; 3727432c641eSTakashi Iwai actual_state = (state >> 4) & 0x0f; 3728432c641eSTakashi Iwai if (actual_state == power_state) 3729432c641eSTakashi Iwai break; 3730432c641eSTakashi Iwai if (time_after_eq(jiffies, end_time)) 3731432c641eSTakashi Iwai break; 3732432c641eSTakashi Iwai /* wait until the codec reachs to the target state */ 3733432c641eSTakashi Iwai msleep(1); 3734432c641eSTakashi Iwai } 3735432c641eSTakashi Iwai return state; 3736432c641eSTakashi Iwai } 3737432c641eSTakashi Iwai 37389419ab6bSTakashi Iwai /* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */ 37399419ab6bSTakashi Iwai static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, 37409419ab6bSTakashi Iwai unsigned int power_state) 37419419ab6bSTakashi Iwai { 37429419ab6bSTakashi Iwai if (power_state == AC_PWRST_D3 && 37439419ab6bSTakashi Iwai get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN && 37449419ab6bSTakashi Iwai (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) { 37459419ab6bSTakashi Iwai int eapd = snd_hda_codec_read(codec, nid, 0, 37469419ab6bSTakashi Iwai AC_VERB_GET_EAPD_BTLENABLE, 0); 37479419ab6bSTakashi Iwai if (eapd & 0x02) 37489419ab6bSTakashi Iwai return AC_PWRST_D0; 37499419ab6bSTakashi Iwai } 37509419ab6bSTakashi Iwai return power_state; 37519419ab6bSTakashi Iwai } 37529419ab6bSTakashi Iwai 3753432c641eSTakashi Iwai /* 375408fa20aeSTakashi Iwai * set power state of the codec, and return the power state 37554d7fbdbcSTakashi Iwai */ 3756d819387eSTakashi Iwai static unsigned int hda_set_power_state(struct hda_codec *codec, 37574d7fbdbcSTakashi Iwai unsigned int power_state) 37584d7fbdbcSTakashi Iwai { 3759d819387eSTakashi Iwai hda_nid_t fg = codec->afg ? codec->afg : codec->mfg; 376009617ce4SWang Xingchao int count; 376109617ce4SWang Xingchao unsigned int state; 376209617ce4SWang Xingchao 37634d7fbdbcSTakashi Iwai /* this delay seems necessary to avoid click noise at power-down */ 37640f4ccbb0SWang Xingchao if (power_state == AC_PWRST_D3) { 37650f4ccbb0SWang Xingchao /* transition time less than 10ms for power down */ 3766983f6b93STakashi Iwai msleep(codec->epss ? 10 : 100); 37670f4ccbb0SWang Xingchao } 376809617ce4SWang Xingchao 376909617ce4SWang Xingchao /* repeat power states setting at most 10 times*/ 377009617ce4SWang Xingchao for (count = 0; count < 10; count++) { 3771432c641eSTakashi Iwai if (codec->patch_ops.set_power_state) 3772432c641eSTakashi Iwai codec->patch_ops.set_power_state(codec, fg, 37734d7fbdbcSTakashi Iwai power_state); 3774432c641eSTakashi Iwai else { 3775432c641eSTakashi Iwai snd_hda_codec_read(codec, fg, 0, 3776432c641eSTakashi Iwai AC_VERB_SET_POWER_STATE, 3777432c641eSTakashi Iwai power_state); 37789419ab6bSTakashi Iwai snd_hda_codec_set_power_to_all(codec, fg, power_state); 3779432c641eSTakashi Iwai } 3780432c641eSTakashi Iwai state = hda_sync_power_state(codec, fg, power_state); 378109617ce4SWang Xingchao if (!(state & AC_PWRST_ERROR)) 378209617ce4SWang Xingchao break; 378309617ce4SWang Xingchao } 3784b8dfc462SMengdong Lin 378508fa20aeSTakashi Iwai return state; 37864d7fbdbcSTakashi Iwai } 3787cb53c626STakashi Iwai 3788b9c590bbSTakashi Iwai /* sync power states of all widgets; 3789b9c590bbSTakashi Iwai * this is called at the end of codec parsing 3790b9c590bbSTakashi Iwai */ 3791b9c590bbSTakashi Iwai static void sync_power_up_states(struct hda_codec *codec) 3792b9c590bbSTakashi Iwai { 3793b9c590bbSTakashi Iwai hda_nid_t nid = codec->start_nid; 3794b9c590bbSTakashi Iwai int i; 3795b9c590bbSTakashi Iwai 3796b9c590bbSTakashi Iwai /* don't care if no or standard filter is used */ 3797b9c590bbSTakashi Iwai if (!codec->power_filter || codec->power_filter == default_power_filter) 3798b9c590bbSTakashi Iwai return; 3799b9c590bbSTakashi Iwai 3800b9c590bbSTakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 3801b9c590bbSTakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 38029040d102STakashi Iwai unsigned int target; 3803b9c590bbSTakashi Iwai if (!(wcaps & AC_WCAP_POWER)) 3804b9c590bbSTakashi Iwai continue; 3805b9c590bbSTakashi Iwai target = codec->power_filter(codec, nid, AC_PWRST_D0); 3806b9c590bbSTakashi Iwai if (target == AC_PWRST_D0) 3807b9c590bbSTakashi Iwai continue; 38089040d102STakashi Iwai if (!snd_hda_check_power_state(codec, nid, target)) 3809b9c590bbSTakashi Iwai snd_hda_codec_write(codec, nid, 0, 3810b9c590bbSTakashi Iwai AC_VERB_SET_POWER_STATE, target); 3811b9c590bbSTakashi Iwai } 3812b9c590bbSTakashi Iwai } 3813b9c590bbSTakashi Iwai 381411aeff08STakashi Iwai #ifdef CONFIG_SND_HDA_HWDEP 381511aeff08STakashi Iwai /* execute additional init verbs */ 381611aeff08STakashi Iwai static void hda_exec_init_verbs(struct hda_codec *codec) 381711aeff08STakashi Iwai { 381811aeff08STakashi Iwai if (codec->init_verbs.list) 381911aeff08STakashi Iwai snd_hda_sequence_write(codec, codec->init_verbs.list); 382011aeff08STakashi Iwai } 382111aeff08STakashi Iwai #else 382211aeff08STakashi Iwai static inline void hda_exec_init_verbs(struct hda_codec *codec) {} 382311aeff08STakashi Iwai #endif 382411aeff08STakashi Iwai 38252a43952aSTakashi Iwai #ifdef CONFIG_PM 3826cb53c626STakashi Iwai /* 3827cb53c626STakashi Iwai * call suspend and power-down; used both from PM and power-save 382808fa20aeSTakashi Iwai * this function returns the power state in the end 3829cb53c626STakashi Iwai */ 3830d17344b3SDylan Reid static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) 3831cb53c626STakashi Iwai { 383208fa20aeSTakashi Iwai unsigned int state; 383308fa20aeSTakashi Iwai 3834989c3187STakashi Iwai codec->in_pm = 1; 3835989c3187STakashi Iwai 3836cb53c626STakashi Iwai if (codec->patch_ops.suspend) 383768cb2b55STakashi Iwai codec->patch_ops.suspend(codec); 3838eb541337STakashi Iwai hda_cleanup_all_streams(codec); 3839d819387eSTakashi Iwai state = hda_set_power_state(codec, AC_PWRST_D3); 3840d17344b3SDylan Reid /* Cancel delayed work if we aren't currently running from it. */ 3841d17344b3SDylan Reid if (!in_wq) 3842d17344b3SDylan Reid cancel_delayed_work_sync(&codec->power_work); 3843a2d96e77STakashi Iwai spin_lock(&codec->power_lock); 3844a2d96e77STakashi Iwai snd_hda_update_power_acct(codec); 3845a2d96e77STakashi Iwai trace_hda_power_down(codec); 384695e99fdaSTakashi Iwai codec->power_on = 0; 3847a221e287STakashi Iwai codec->power_transition = 0; 3848a2f6309eSTakashi Iwai codec->power_jiffies = jiffies; 3849a2d96e77STakashi Iwai spin_unlock(&codec->power_lock); 3850989c3187STakashi Iwai codec->in_pm = 0; 385108fa20aeSTakashi Iwai return state; 3852cb53c626STakashi Iwai } 3853cb53c626STakashi Iwai 3854c370dd6eSTakashi Iwai /* mark all entries of cmd and amp caches dirty */ 3855c370dd6eSTakashi Iwai static void hda_mark_cmd_cache_dirty(struct hda_codec *codec) 3856c370dd6eSTakashi Iwai { 3857c370dd6eSTakashi Iwai int i; 3858c370dd6eSTakashi Iwai for (i = 0; i < codec->cmd_cache.buf.used; i++) { 3859c370dd6eSTakashi Iwai struct hda_cache_head *cmd; 3860c370dd6eSTakashi Iwai cmd = snd_array_elem(&codec->cmd_cache.buf, i); 3861c370dd6eSTakashi Iwai cmd->dirty = 1; 3862c370dd6eSTakashi Iwai } 3863c370dd6eSTakashi Iwai for (i = 0; i < codec->amp_cache.buf.used; i++) { 3864c370dd6eSTakashi Iwai struct hda_amp_info *amp; 3865f038fcacSDavid Henningsson amp = snd_array_elem(&codec->amp_cache.buf, i); 3866c370dd6eSTakashi Iwai amp->head.dirty = 1; 3867c370dd6eSTakashi Iwai } 3868c370dd6eSTakashi Iwai } 3869c370dd6eSTakashi Iwai 3870cb53c626STakashi Iwai /* 3871cb53c626STakashi Iwai * kick up codec; used both from PM and power-save 3872cb53c626STakashi Iwai */ 3873cb53c626STakashi Iwai static void hda_call_codec_resume(struct hda_codec *codec) 3874cb53c626STakashi Iwai { 3875989c3187STakashi Iwai codec->in_pm = 1; 3876989c3187STakashi Iwai 3877c370dd6eSTakashi Iwai hda_mark_cmd_cache_dirty(codec); 3878c370dd6eSTakashi Iwai 38797f30830bSTakashi Iwai /* set as if powered on for avoiding re-entering the resume 38807f30830bSTakashi Iwai * in the resume / power-save sequence 38817f30830bSTakashi Iwai */ 38827f30830bSTakashi Iwai hda_keep_power_on(codec); 3883d819387eSTakashi Iwai hda_set_power_state(codec, AC_PWRST_D0); 3884ac0547dcSTakashi Iwai restore_shutup_pins(codec); 388511aeff08STakashi Iwai hda_exec_init_verbs(codec); 388631614bb8STakashi Iwai snd_hda_jack_set_dirty_all(codec); 3887cb53c626STakashi Iwai if (codec->patch_ops.resume) 3888cb53c626STakashi Iwai codec->patch_ops.resume(codec); 3889cb53c626STakashi Iwai else { 38909d99f312STakashi Iwai if (codec->patch_ops.init) 3891cb53c626STakashi Iwai codec->patch_ops.init(codec); 3892cb53c626STakashi Iwai snd_hda_codec_resume_amp(codec); 3893cb53c626STakashi Iwai snd_hda_codec_resume_cache(codec); 3894cb53c626STakashi Iwai } 389526a6cb6cSDavid Henningsson 389626a6cb6cSDavid Henningsson if (codec->jackpoll_interval) 389726a6cb6cSDavid Henningsson hda_jackpoll_work(&codec->jackpoll_work.work); 389831614bb8STakashi Iwai else 38998a535414STakashi Iwai snd_hda_jack_report_sync(codec); 3900989c3187STakashi Iwai 3901989c3187STakashi Iwai codec->in_pm = 0; 39027f30830bSTakashi Iwai snd_hda_power_down(codec); /* flag down before returning */ 3903cb53c626STakashi Iwai } 39042a43952aSTakashi Iwai #endif /* CONFIG_PM */ 390554d17403STakashi Iwai 390654d17403STakashi Iwai 39071da177e4SLinus Torvalds /** 39081da177e4SLinus Torvalds * snd_hda_build_controls - build mixer controls 39091da177e4SLinus Torvalds * @bus: the BUS 39101da177e4SLinus Torvalds * 39111da177e4SLinus Torvalds * Creates mixer controls for each codec included in the bus. 39121da177e4SLinus Torvalds * 39131da177e4SLinus Torvalds * Returns 0 if successful, otherwise a negative error code. 39141da177e4SLinus Torvalds */ 39156a0f56a7STakashi Iwai int snd_hda_build_controls(struct hda_bus *bus) 39161da177e4SLinus Torvalds { 39170ba21762STakashi Iwai struct hda_codec *codec; 39181da177e4SLinus Torvalds 39190ba21762STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 39206c1f45eaSTakashi Iwai int err = snd_hda_codec_build_controls(codec); 3921f93d461bSTakashi Iwai if (err < 0) { 3922f93d461bSTakashi Iwai printk(KERN_ERR "hda_codec: cannot build controls " 3923f93d461bSTakashi Iwai "for #%d (error %d)\n", codec->addr, err); 3924f93d461bSTakashi Iwai err = snd_hda_codec_reset(codec); 3925f93d461bSTakashi Iwai if (err < 0) { 3926f93d461bSTakashi Iwai printk(KERN_ERR 3927f93d461bSTakashi Iwai "hda_codec: cannot revert codec\n"); 39286c1f45eaSTakashi Iwai return err; 39296c1f45eaSTakashi Iwai } 3930f93d461bSTakashi Iwai } 3931f93d461bSTakashi Iwai } 39326c1f45eaSTakashi Iwai return 0; 39336c1f45eaSTakashi Iwai } 3934ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_build_controls); 39356c1f45eaSTakashi Iwai 39369c9a5175STakashi Iwai /* 39379c9a5175STakashi Iwai * add standard channel maps if not specified 39389c9a5175STakashi Iwai */ 39399c9a5175STakashi Iwai static int add_std_chmaps(struct hda_codec *codec) 39409c9a5175STakashi Iwai { 39419c9a5175STakashi Iwai int i, str, err; 39429c9a5175STakashi Iwai 39439c9a5175STakashi Iwai for (i = 0; i < codec->num_pcms; i++) { 39449c9a5175STakashi Iwai for (str = 0; str < 2; str++) { 39459c9a5175STakashi Iwai struct snd_pcm *pcm = codec->pcm_info[i].pcm; 39469c9a5175STakashi Iwai struct hda_pcm_stream *hinfo = 39479c9a5175STakashi Iwai &codec->pcm_info[i].stream[str]; 39489c9a5175STakashi Iwai struct snd_pcm_chmap *chmap; 3949ee81abb6STakashi Iwai const struct snd_pcm_chmap_elem *elem; 39509c9a5175STakashi Iwai 39519c9a5175STakashi Iwai if (codec->pcm_info[i].own_chmap) 39529c9a5175STakashi Iwai continue; 39539c9a5175STakashi Iwai if (!pcm || !hinfo->substreams) 39549c9a5175STakashi Iwai continue; 3955ee81abb6STakashi Iwai elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps; 3956ee81abb6STakashi Iwai err = snd_pcm_add_chmap_ctls(pcm, str, elem, 39579c9a5175STakashi Iwai hinfo->channels_max, 39589c9a5175STakashi Iwai 0, &chmap); 39599c9a5175STakashi Iwai if (err < 0) 39609c9a5175STakashi Iwai return err; 39619c9a5175STakashi Iwai chmap->channel_mask = SND_PCM_CHMAP_MASK_2468; 39629c9a5175STakashi Iwai } 39639c9a5175STakashi Iwai } 39649c9a5175STakashi Iwai return 0; 39659c9a5175STakashi Iwai } 39669c9a5175STakashi Iwai 3967ee81abb6STakashi Iwai /* default channel maps for 2.1 speakers; 3968ee81abb6STakashi Iwai * since HD-audio supports only stereo, odd number channels are omitted 3969ee81abb6STakashi Iwai */ 3970ee81abb6STakashi Iwai const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[] = { 3971ee81abb6STakashi Iwai { .channels = 2, 3972ee81abb6STakashi Iwai .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, 3973ee81abb6STakashi Iwai { .channels = 4, 3974ee81abb6STakashi Iwai .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, 3975ee81abb6STakashi Iwai SNDRV_CHMAP_LFE, SNDRV_CHMAP_LFE } }, 3976ee81abb6STakashi Iwai { } 3977ee81abb6STakashi Iwai }; 3978ee81abb6STakashi Iwai EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps); 3979ee81abb6STakashi Iwai 39806c1f45eaSTakashi Iwai int snd_hda_codec_build_controls(struct hda_codec *codec) 39816c1f45eaSTakashi Iwai { 3982cb53c626STakashi Iwai int err = 0; 398311aeff08STakashi Iwai hda_exec_init_verbs(codec); 3984cb53c626STakashi Iwai /* continue to initialize... */ 3985cb53c626STakashi Iwai if (codec->patch_ops.init) 3986cb53c626STakashi Iwai err = codec->patch_ops.init(codec); 3987cb53c626STakashi Iwai if (!err && codec->patch_ops.build_controls) 39881da177e4SLinus Torvalds err = codec->patch_ops.build_controls(codec); 39891da177e4SLinus Torvalds if (err < 0) 39901da177e4SLinus Torvalds return err; 39919c9a5175STakashi Iwai 39929c9a5175STakashi Iwai /* we create chmaps here instead of build_pcms */ 39939c9a5175STakashi Iwai err = add_std_chmaps(codec); 39949c9a5175STakashi Iwai if (err < 0) 39959c9a5175STakashi Iwai return err; 39969c9a5175STakashi Iwai 399726a6cb6cSDavid Henningsson if (codec->jackpoll_interval) 399826a6cb6cSDavid Henningsson hda_jackpoll_work(&codec->jackpoll_work.work); 399926a6cb6cSDavid Henningsson else 40008a535414STakashi Iwai snd_hda_jack_report_sync(codec); /* call at the last init point */ 4001b9c590bbSTakashi Iwai sync_power_up_states(codec); 40021da177e4SLinus Torvalds return 0; 40031da177e4SLinus Torvalds } 40041da177e4SLinus Torvalds 40051da177e4SLinus Torvalds /* 40061da177e4SLinus Torvalds * stream formats 40071da177e4SLinus Torvalds */ 4008befdf316STakashi Iwai struct hda_rate_tbl { 4009befdf316STakashi Iwai unsigned int hz; 4010befdf316STakashi Iwai unsigned int alsa_bits; 4011befdf316STakashi Iwai unsigned int hda_fmt; 4012befdf316STakashi Iwai }; 4013befdf316STakashi Iwai 401492f10b3fSTakashi Iwai /* rate = base * mult / div */ 401592f10b3fSTakashi Iwai #define HDA_RATE(base, mult, div) \ 401692f10b3fSTakashi Iwai (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ 401792f10b3fSTakashi Iwai (((div) - 1) << AC_FMT_DIV_SHIFT)) 401892f10b3fSTakashi Iwai 4019befdf316STakashi Iwai static struct hda_rate_tbl rate_bits[] = { 40201da177e4SLinus Torvalds /* rate in Hz, ALSA rate bitmask, HDA format value */ 40219d8f53f2SNicolas Graziano 40229d8f53f2SNicolas Graziano /* autodetected value used in snd_hda_query_supported_pcm */ 402392f10b3fSTakashi Iwai { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, 402492f10b3fSTakashi Iwai { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, 402592f10b3fSTakashi Iwai { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, 402692f10b3fSTakashi Iwai { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, 402792f10b3fSTakashi Iwai { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, 402892f10b3fSTakashi Iwai { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, 402992f10b3fSTakashi Iwai { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, 403092f10b3fSTakashi Iwai { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, 403192f10b3fSTakashi Iwai { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, 403292f10b3fSTakashi Iwai { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, 403392f10b3fSTakashi Iwai { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, 4034a961f9feSTakashi Iwai #define AC_PAR_PCM_RATE_BITS 11 4035a961f9feSTakashi Iwai /* up to bits 10, 384kHZ isn't supported properly */ 4036a961f9feSTakashi Iwai 4037a961f9feSTakashi Iwai /* not autodetected value */ 403892f10b3fSTakashi Iwai { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, 40399d8f53f2SNicolas Graziano 4040befdf316STakashi Iwai { 0 } /* terminator */ 40411da177e4SLinus Torvalds }; 40421da177e4SLinus Torvalds 40431da177e4SLinus Torvalds /** 40441da177e4SLinus Torvalds * snd_hda_calc_stream_format - calculate format bitset 40451da177e4SLinus Torvalds * @rate: the sample rate 40461da177e4SLinus Torvalds * @channels: the number of channels 40471da177e4SLinus Torvalds * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) 40481da177e4SLinus Torvalds * @maxbps: the max. bps 40491da177e4SLinus Torvalds * 40501da177e4SLinus Torvalds * Calculate the format bitset from the given rate, channels and th PCM format. 40511da177e4SLinus Torvalds * 40521da177e4SLinus Torvalds * Return zero if invalid. 40531da177e4SLinus Torvalds */ 40541da177e4SLinus Torvalds unsigned int snd_hda_calc_stream_format(unsigned int rate, 40551da177e4SLinus Torvalds unsigned int channels, 40561da177e4SLinus Torvalds unsigned int format, 405732c168c8SAnssi Hannula unsigned int maxbps, 405832c168c8SAnssi Hannula unsigned short spdif_ctls) 40591da177e4SLinus Torvalds { 40601da177e4SLinus Torvalds int i; 40611da177e4SLinus Torvalds unsigned int val = 0; 40621da177e4SLinus Torvalds 4063befdf316STakashi Iwai for (i = 0; rate_bits[i].hz; i++) 4064befdf316STakashi Iwai if (rate_bits[i].hz == rate) { 4065befdf316STakashi Iwai val = rate_bits[i].hda_fmt; 40661da177e4SLinus Torvalds break; 40671da177e4SLinus Torvalds } 4068befdf316STakashi Iwai if (!rate_bits[i].hz) { 40691da177e4SLinus Torvalds snd_printdd("invalid rate %d\n", rate); 40701da177e4SLinus Torvalds return 0; 40711da177e4SLinus Torvalds } 40721da177e4SLinus Torvalds 40731da177e4SLinus Torvalds if (channels == 0 || channels > 8) { 40741da177e4SLinus Torvalds snd_printdd("invalid channels %d\n", channels); 40751da177e4SLinus Torvalds return 0; 40761da177e4SLinus Torvalds } 40771da177e4SLinus Torvalds val |= channels - 1; 40781da177e4SLinus Torvalds 40791da177e4SLinus Torvalds switch (snd_pcm_format_width(format)) { 408028aedaf7SNorberto Lopes case 8: 408192f10b3fSTakashi Iwai val |= AC_FMT_BITS_8; 408228aedaf7SNorberto Lopes break; 408328aedaf7SNorberto Lopes case 16: 408492f10b3fSTakashi Iwai val |= AC_FMT_BITS_16; 408528aedaf7SNorberto Lopes break; 40861da177e4SLinus Torvalds case 20: 40871da177e4SLinus Torvalds case 24: 40881da177e4SLinus Torvalds case 32: 4089b0bb3aa6STakashi Iwai if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) 409092f10b3fSTakashi Iwai val |= AC_FMT_BITS_32; 40911da177e4SLinus Torvalds else if (maxbps >= 24) 409292f10b3fSTakashi Iwai val |= AC_FMT_BITS_24; 40931da177e4SLinus Torvalds else 409492f10b3fSTakashi Iwai val |= AC_FMT_BITS_20; 40951da177e4SLinus Torvalds break; 40961da177e4SLinus Torvalds default: 40970ba21762STakashi Iwai snd_printdd("invalid format width %d\n", 40980ba21762STakashi Iwai snd_pcm_format_width(format)); 40991da177e4SLinus Torvalds return 0; 41001da177e4SLinus Torvalds } 41011da177e4SLinus Torvalds 410232c168c8SAnssi Hannula if (spdif_ctls & AC_DIG1_NONAUDIO) 410392f10b3fSTakashi Iwai val |= AC_FMT_TYPE_NON_PCM; 410432c168c8SAnssi Hannula 41051da177e4SLinus Torvalds return val; 41061da177e4SLinus Torvalds } 4107ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); 41081da177e4SLinus Torvalds 4109c3b6bcc2STakashi Iwai static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid, 4110c3b6bcc2STakashi Iwai int dir) 411192c7c8a7STakashi Iwai { 411292c7c8a7STakashi Iwai unsigned int val = 0; 411392c7c8a7STakashi Iwai if (nid != codec->afg && 411492c7c8a7STakashi Iwai (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) 411592c7c8a7STakashi Iwai val = snd_hda_param_read(codec, nid, AC_PAR_PCM); 411692c7c8a7STakashi Iwai if (!val || val == -1) 411792c7c8a7STakashi Iwai val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); 411892c7c8a7STakashi Iwai if (!val || val == -1) 411992c7c8a7STakashi Iwai return 0; 412092c7c8a7STakashi Iwai return val; 412192c7c8a7STakashi Iwai } 412292c7c8a7STakashi Iwai 412392c7c8a7STakashi Iwai static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) 412492c7c8a7STakashi Iwai { 4125c3b6bcc2STakashi Iwai return query_caps_hash(codec, nid, 0, HDA_HASH_PARPCM_KEY(nid), 412692c7c8a7STakashi Iwai get_pcm_param); 412792c7c8a7STakashi Iwai } 412892c7c8a7STakashi Iwai 4129c3b6bcc2STakashi Iwai static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid, 4130c3b6bcc2STakashi Iwai int dir) 413192c7c8a7STakashi Iwai { 413292c7c8a7STakashi Iwai unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); 413392c7c8a7STakashi Iwai if (!streams || streams == -1) 413492c7c8a7STakashi Iwai streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); 413592c7c8a7STakashi Iwai if (!streams || streams == -1) 413692c7c8a7STakashi Iwai return 0; 413792c7c8a7STakashi Iwai return streams; 413892c7c8a7STakashi Iwai } 413992c7c8a7STakashi Iwai 414092c7c8a7STakashi Iwai static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) 414192c7c8a7STakashi Iwai { 4142c3b6bcc2STakashi Iwai return query_caps_hash(codec, nid, 0, HDA_HASH_PARSTR_KEY(nid), 414392c7c8a7STakashi Iwai get_stream_param); 414492c7c8a7STakashi Iwai } 414592c7c8a7STakashi Iwai 41461da177e4SLinus Torvalds /** 41471da177e4SLinus Torvalds * snd_hda_query_supported_pcm - query the supported PCM rates and formats 41481da177e4SLinus Torvalds * @codec: the HDA codec 41491da177e4SLinus Torvalds * @nid: NID to query 41501da177e4SLinus Torvalds * @ratesp: the pointer to store the detected rate bitflags 41511da177e4SLinus Torvalds * @formatsp: the pointer to store the detected formats 41521da177e4SLinus Torvalds * @bpsp: the pointer to store the detected format widths 41531da177e4SLinus Torvalds * 41541da177e4SLinus Torvalds * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp 41551da177e4SLinus Torvalds * or @bsps argument is ignored. 41561da177e4SLinus Torvalds * 41571da177e4SLinus Torvalds * Returns 0 if successful, otherwise a negative error code. 41581da177e4SLinus Torvalds */ 4159384a48d7SStephen Warren int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, 41601da177e4SLinus Torvalds u32 *ratesp, u64 *formatsp, unsigned int *bpsp) 41611da177e4SLinus Torvalds { 4162ee504710SJaroslav Kysela unsigned int i, val, wcaps; 41631da177e4SLinus Torvalds 4164ee504710SJaroslav Kysela wcaps = get_wcaps(codec, nid); 416592c7c8a7STakashi Iwai val = query_pcm_param(codec, nid); 41661da177e4SLinus Torvalds 41671da177e4SLinus Torvalds if (ratesp) { 41681da177e4SLinus Torvalds u32 rates = 0; 4169a961f9feSTakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { 41701da177e4SLinus Torvalds if (val & (1 << i)) 4171befdf316STakashi Iwai rates |= rate_bits[i].alsa_bits; 41721da177e4SLinus Torvalds } 4173ee504710SJaroslav Kysela if (rates == 0) { 4174ee504710SJaroslav Kysela snd_printk(KERN_ERR "hda_codec: rates == 0 " 4175ee504710SJaroslav Kysela "(nid=0x%x, val=0x%x, ovrd=%i)\n", 4176ee504710SJaroslav Kysela nid, val, 4177ee504710SJaroslav Kysela (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); 4178ee504710SJaroslav Kysela return -EIO; 4179ee504710SJaroslav Kysela } 41801da177e4SLinus Torvalds *ratesp = rates; 41811da177e4SLinus Torvalds } 41821da177e4SLinus Torvalds 41831da177e4SLinus Torvalds if (formatsp || bpsp) { 41841da177e4SLinus Torvalds u64 formats = 0; 4185ee504710SJaroslav Kysela unsigned int streams, bps; 41861da177e4SLinus Torvalds 418792c7c8a7STakashi Iwai streams = query_stream_param(codec, nid); 418892c7c8a7STakashi Iwai if (!streams) 41891da177e4SLinus Torvalds return -EIO; 41901da177e4SLinus Torvalds 41911da177e4SLinus Torvalds bps = 0; 41921da177e4SLinus Torvalds if (streams & AC_SUPFMT_PCM) { 41931da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_8) { 41941da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_U8; 41951da177e4SLinus Torvalds bps = 8; 41961da177e4SLinus Torvalds } 41971da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_16) { 41981da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_S16_LE; 41991da177e4SLinus Torvalds bps = 16; 42001da177e4SLinus Torvalds } 42011da177e4SLinus Torvalds if (wcaps & AC_WCAP_DIGITAL) { 42021da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_32) 42031da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; 42041da177e4SLinus Torvalds if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) 42051da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_S32_LE; 42061da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_24) 42071da177e4SLinus Torvalds bps = 24; 42081da177e4SLinus Torvalds else if (val & AC_SUPPCM_BITS_20) 42091da177e4SLinus Torvalds bps = 20; 42100ba21762STakashi Iwai } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24| 42110ba21762STakashi Iwai AC_SUPPCM_BITS_32)) { 42121da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_S32_LE; 42131da177e4SLinus Torvalds if (val & AC_SUPPCM_BITS_32) 42141da177e4SLinus Torvalds bps = 32; 42151da177e4SLinus Torvalds else if (val & AC_SUPPCM_BITS_24) 42161da177e4SLinus Torvalds bps = 24; 421733ef7651SNicolas Graziano else if (val & AC_SUPPCM_BITS_20) 421833ef7651SNicolas Graziano bps = 20; 42191da177e4SLinus Torvalds } 42201da177e4SLinus Torvalds } 42218c7dd890STakashi Iwai #if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ 4222b5025c50STakashi Iwai if (streams & AC_SUPFMT_FLOAT32) { 42231da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; 4224b0bb3aa6STakashi Iwai if (!bps) 42251da177e4SLinus Torvalds bps = 32; 4226b5025c50STakashi Iwai } 42278c7dd890STakashi Iwai #endif 4228b5025c50STakashi Iwai if (streams == AC_SUPFMT_AC3) { 42290ba21762STakashi Iwai /* should be exclusive */ 42301da177e4SLinus Torvalds /* temporary hack: we have still no proper support 42311da177e4SLinus Torvalds * for the direct AC3 stream... 42321da177e4SLinus Torvalds */ 42331da177e4SLinus Torvalds formats |= SNDRV_PCM_FMTBIT_U8; 42341da177e4SLinus Torvalds bps = 8; 42351da177e4SLinus Torvalds } 4236ee504710SJaroslav Kysela if (formats == 0) { 4237ee504710SJaroslav Kysela snd_printk(KERN_ERR "hda_codec: formats == 0 " 4238ee504710SJaroslav Kysela "(nid=0x%x, val=0x%x, ovrd=%i, " 4239ee504710SJaroslav Kysela "streams=0x%x)\n", 4240ee504710SJaroslav Kysela nid, val, 4241ee504710SJaroslav Kysela (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, 4242ee504710SJaroslav Kysela streams); 4243ee504710SJaroslav Kysela return -EIO; 4244ee504710SJaroslav Kysela } 42451da177e4SLinus Torvalds if (formatsp) 42461da177e4SLinus Torvalds *formatsp = formats; 42471da177e4SLinus Torvalds if (bpsp) 42481da177e4SLinus Torvalds *bpsp = bps; 42491da177e4SLinus Torvalds } 42501da177e4SLinus Torvalds 42511da177e4SLinus Torvalds return 0; 42521da177e4SLinus Torvalds } 4253384a48d7SStephen Warren EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm); 42541da177e4SLinus Torvalds 42551da177e4SLinus Torvalds /** 4256d5191e50STakashi Iwai * snd_hda_is_supported_format - Check the validity of the format 4257d5191e50STakashi Iwai * @codec: HD-audio codec 4258d5191e50STakashi Iwai * @nid: NID to check 4259d5191e50STakashi Iwai * @format: the HD-audio format value to check 4260d5191e50STakashi Iwai * 4261d5191e50STakashi Iwai * Check whether the given node supports the format value. 42621da177e4SLinus Torvalds * 42631da177e4SLinus Torvalds * Returns 1 if supported, 0 if not. 42641da177e4SLinus Torvalds */ 42651da177e4SLinus Torvalds int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, 42661da177e4SLinus Torvalds unsigned int format) 42671da177e4SLinus Torvalds { 42681da177e4SLinus Torvalds int i; 42691da177e4SLinus Torvalds unsigned int val = 0, rate, stream; 42701da177e4SLinus Torvalds 427192c7c8a7STakashi Iwai val = query_pcm_param(codec, nid); 427292c7c8a7STakashi Iwai if (!val) 42731da177e4SLinus Torvalds return 0; 42741da177e4SLinus Torvalds 42751da177e4SLinus Torvalds rate = format & 0xff00; 4276a961f9feSTakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) 4277befdf316STakashi Iwai if (rate_bits[i].hda_fmt == rate) { 42781da177e4SLinus Torvalds if (val & (1 << i)) 42791da177e4SLinus Torvalds break; 42801da177e4SLinus Torvalds return 0; 42811da177e4SLinus Torvalds } 4282a961f9feSTakashi Iwai if (i >= AC_PAR_PCM_RATE_BITS) 42831da177e4SLinus Torvalds return 0; 42841da177e4SLinus Torvalds 428592c7c8a7STakashi Iwai stream = query_stream_param(codec, nid); 428692c7c8a7STakashi Iwai if (!stream) 42871da177e4SLinus Torvalds return 0; 42881da177e4SLinus Torvalds 42891da177e4SLinus Torvalds if (stream & AC_SUPFMT_PCM) { 42901da177e4SLinus Torvalds switch (format & 0xf0) { 42911da177e4SLinus Torvalds case 0x00: 42921da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_8)) 42931da177e4SLinus Torvalds return 0; 42941da177e4SLinus Torvalds break; 42951da177e4SLinus Torvalds case 0x10: 42961da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_16)) 42971da177e4SLinus Torvalds return 0; 42981da177e4SLinus Torvalds break; 42991da177e4SLinus Torvalds case 0x20: 43001da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_20)) 43011da177e4SLinus Torvalds return 0; 43021da177e4SLinus Torvalds break; 43031da177e4SLinus Torvalds case 0x30: 43041da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_24)) 43051da177e4SLinus Torvalds return 0; 43061da177e4SLinus Torvalds break; 43071da177e4SLinus Torvalds case 0x40: 43081da177e4SLinus Torvalds if (!(val & AC_SUPPCM_BITS_32)) 43091da177e4SLinus Torvalds return 0; 43101da177e4SLinus Torvalds break; 43111da177e4SLinus Torvalds default: 43121da177e4SLinus Torvalds return 0; 43131da177e4SLinus Torvalds } 43141da177e4SLinus Torvalds } else { 43151da177e4SLinus Torvalds /* FIXME: check for float32 and AC3? */ 43161da177e4SLinus Torvalds } 43171da177e4SLinus Torvalds 43181da177e4SLinus Torvalds return 1; 43191da177e4SLinus Torvalds } 4320ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_is_supported_format); 43211da177e4SLinus Torvalds 43221da177e4SLinus Torvalds /* 43231da177e4SLinus Torvalds * PCM stuff 43241da177e4SLinus Torvalds */ 43251da177e4SLinus Torvalds static int hda_pcm_default_open_close(struct hda_pcm_stream *hinfo, 43261da177e4SLinus Torvalds struct hda_codec *codec, 4327c8b6bf9bSTakashi Iwai struct snd_pcm_substream *substream) 43281da177e4SLinus Torvalds { 43291da177e4SLinus Torvalds return 0; 43301da177e4SLinus Torvalds } 43311da177e4SLinus Torvalds 43321da177e4SLinus Torvalds static int hda_pcm_default_prepare(struct hda_pcm_stream *hinfo, 43331da177e4SLinus Torvalds struct hda_codec *codec, 43341da177e4SLinus Torvalds unsigned int stream_tag, 43351da177e4SLinus Torvalds unsigned int format, 4336c8b6bf9bSTakashi Iwai struct snd_pcm_substream *substream) 43371da177e4SLinus Torvalds { 43381da177e4SLinus Torvalds snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 43391da177e4SLinus Torvalds return 0; 43401da177e4SLinus Torvalds } 43411da177e4SLinus Torvalds 43421da177e4SLinus Torvalds static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, 43431da177e4SLinus Torvalds struct hda_codec *codec, 4344c8b6bf9bSTakashi Iwai struct snd_pcm_substream *substream) 43451da177e4SLinus Torvalds { 4346888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 43471da177e4SLinus Torvalds return 0; 43481da177e4SLinus Torvalds } 43491da177e4SLinus Torvalds 43506c1f45eaSTakashi Iwai static int set_pcm_default_values(struct hda_codec *codec, 43510ba21762STakashi Iwai struct hda_pcm_stream *info) 43521da177e4SLinus Torvalds { 4353ee504710SJaroslav Kysela int err; 4354ee504710SJaroslav Kysela 43551da177e4SLinus Torvalds /* query support PCM information from the given NID */ 43560ba21762STakashi Iwai if (info->nid && (!info->rates || !info->formats)) { 4357ee504710SJaroslav Kysela err = snd_hda_query_supported_pcm(codec, info->nid, 43581da177e4SLinus Torvalds info->rates ? NULL : &info->rates, 43591da177e4SLinus Torvalds info->formats ? NULL : &info->formats, 43601da177e4SLinus Torvalds info->maxbps ? NULL : &info->maxbps); 4361ee504710SJaroslav Kysela if (err < 0) 4362ee504710SJaroslav Kysela return err; 43631da177e4SLinus Torvalds } 43641da177e4SLinus Torvalds if (info->ops.open == NULL) 43651da177e4SLinus Torvalds info->ops.open = hda_pcm_default_open_close; 43661da177e4SLinus Torvalds if (info->ops.close == NULL) 43671da177e4SLinus Torvalds info->ops.close = hda_pcm_default_open_close; 43681da177e4SLinus Torvalds if (info->ops.prepare == NULL) { 4369da3cec35STakashi Iwai if (snd_BUG_ON(!info->nid)) 4370da3cec35STakashi Iwai return -EINVAL; 43711da177e4SLinus Torvalds info->ops.prepare = hda_pcm_default_prepare; 43721da177e4SLinus Torvalds } 43731da177e4SLinus Torvalds if (info->ops.cleanup == NULL) { 4374da3cec35STakashi Iwai if (snd_BUG_ON(!info->nid)) 4375da3cec35STakashi Iwai return -EINVAL; 43761da177e4SLinus Torvalds info->ops.cleanup = hda_pcm_default_cleanup; 43771da177e4SLinus Torvalds } 43781da177e4SLinus Torvalds return 0; 43791da177e4SLinus Torvalds } 43801da177e4SLinus Torvalds 4381eb541337STakashi Iwai /* 4382eb541337STakashi Iwai * codec prepare/cleanup entries 4383eb541337STakashi Iwai */ 4384eb541337STakashi Iwai int snd_hda_codec_prepare(struct hda_codec *codec, 4385eb541337STakashi Iwai struct hda_pcm_stream *hinfo, 4386eb541337STakashi Iwai unsigned int stream, 4387eb541337STakashi Iwai unsigned int format, 4388eb541337STakashi Iwai struct snd_pcm_substream *substream) 4389eb541337STakashi Iwai { 4390eb541337STakashi Iwai int ret; 43913f50ac6aSTakashi Iwai mutex_lock(&codec->bus->prepare_mutex); 4392eb541337STakashi Iwai ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream); 4393eb541337STakashi Iwai if (ret >= 0) 4394eb541337STakashi Iwai purify_inactive_streams(codec); 43953f50ac6aSTakashi Iwai mutex_unlock(&codec->bus->prepare_mutex); 4396eb541337STakashi Iwai return ret; 4397eb541337STakashi Iwai } 4398eb541337STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_prepare); 4399eb541337STakashi Iwai 4400eb541337STakashi Iwai void snd_hda_codec_cleanup(struct hda_codec *codec, 4401eb541337STakashi Iwai struct hda_pcm_stream *hinfo, 4402eb541337STakashi Iwai struct snd_pcm_substream *substream) 4403eb541337STakashi Iwai { 44043f50ac6aSTakashi Iwai mutex_lock(&codec->bus->prepare_mutex); 4405eb541337STakashi Iwai hinfo->ops.cleanup(hinfo, codec, substream); 44063f50ac6aSTakashi Iwai mutex_unlock(&codec->bus->prepare_mutex); 4407eb541337STakashi Iwai } 4408eb541337STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup); 4409eb541337STakashi Iwai 4410d5191e50STakashi Iwai /* global */ 4411e3303235SJaroslav Kysela const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { 4412e3303235SJaroslav Kysela "Audio", "SPDIF", "HDMI", "Modem" 4413e3303235SJaroslav Kysela }; 4414e3303235SJaroslav Kysela 4415176d5335STakashi Iwai /* 4416529bd6c4STakashi Iwai * get the empty PCM device number to assign 4417c8936222STakashi Iwai * 4418c8936222STakashi Iwai * note the max device number is limited by HDA_MAX_PCMS, currently 10 4419529bd6c4STakashi Iwai */ 4420529bd6c4STakashi Iwai static int get_empty_pcm_device(struct hda_bus *bus, int type) 4421529bd6c4STakashi Iwai { 4422f5d6def5SWu Fengguang /* audio device indices; not linear to keep compatibility */ 4423f5d6def5SWu Fengguang static int audio_idx[HDA_PCM_NTYPES][5] = { 4424f5d6def5SWu Fengguang [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 }, 4425f5d6def5SWu Fengguang [HDA_PCM_TYPE_SPDIF] = { 1, -1 }, 442692608badSWu Fengguang [HDA_PCM_TYPE_HDMI] = { 3, 7, 8, 9, -1 }, 4427f5d6def5SWu Fengguang [HDA_PCM_TYPE_MODEM] = { 6, -1 }, 4428529bd6c4STakashi Iwai }; 4429f5d6def5SWu Fengguang int i; 4430529bd6c4STakashi Iwai 4431f5d6def5SWu Fengguang if (type >= HDA_PCM_NTYPES) { 4432529bd6c4STakashi Iwai snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); 4433529bd6c4STakashi Iwai return -EINVAL; 4434529bd6c4STakashi Iwai } 4435f5d6def5SWu Fengguang 4436f5d6def5SWu Fengguang for (i = 0; audio_idx[type][i] >= 0 ; i++) 4437f5d6def5SWu Fengguang if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits)) 4438f5d6def5SWu Fengguang return audio_idx[type][i]; 4439f5d6def5SWu Fengguang 444001b65bfbSTakashi Iwai /* non-fixed slots starting from 10 */ 444101b65bfbSTakashi Iwai for (i = 10; i < 32; i++) { 444201b65bfbSTakashi Iwai if (!test_and_set_bit(i, bus->pcm_dev_bits)) 444301b65bfbSTakashi Iwai return i; 444401b65bfbSTakashi Iwai } 444501b65bfbSTakashi Iwai 444628aedaf7SNorberto Lopes snd_printk(KERN_WARNING "Too many %s devices\n", 444728aedaf7SNorberto Lopes snd_hda_pcm_type_name[type]); 4448f5d6def5SWu Fengguang return -EAGAIN; 4449529bd6c4STakashi Iwai } 4450529bd6c4STakashi Iwai 4451529bd6c4STakashi Iwai /* 4452176d5335STakashi Iwai * attach a new PCM stream 4453176d5335STakashi Iwai */ 4454529bd6c4STakashi Iwai static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) 4455176d5335STakashi Iwai { 445633fa35edSTakashi Iwai struct hda_bus *bus = codec->bus; 4457176d5335STakashi Iwai struct hda_pcm_stream *info; 4458176d5335STakashi Iwai int stream, err; 4459176d5335STakashi Iwai 4460b91f080fSTakashi Iwai if (snd_BUG_ON(!pcm->name)) 4461176d5335STakashi Iwai return -EINVAL; 4462176d5335STakashi Iwai for (stream = 0; stream < 2; stream++) { 4463176d5335STakashi Iwai info = &pcm->stream[stream]; 4464176d5335STakashi Iwai if (info->substreams) { 4465176d5335STakashi Iwai err = set_pcm_default_values(codec, info); 4466176d5335STakashi Iwai if (err < 0) 4467176d5335STakashi Iwai return err; 4468176d5335STakashi Iwai } 4469176d5335STakashi Iwai } 447033fa35edSTakashi Iwai return bus->ops.attach_pcm(bus, codec, pcm); 4471176d5335STakashi Iwai } 4472176d5335STakashi Iwai 4473529bd6c4STakashi Iwai /* assign all PCMs of the given codec */ 4474529bd6c4STakashi Iwai int snd_hda_codec_build_pcms(struct hda_codec *codec) 4475529bd6c4STakashi Iwai { 4476529bd6c4STakashi Iwai unsigned int pcm; 4477529bd6c4STakashi Iwai int err; 4478529bd6c4STakashi Iwai 4479529bd6c4STakashi Iwai if (!codec->num_pcms) { 4480529bd6c4STakashi Iwai if (!codec->patch_ops.build_pcms) 4481529bd6c4STakashi Iwai return 0; 4482529bd6c4STakashi Iwai err = codec->patch_ops.build_pcms(codec); 44836e655bf2STakashi Iwai if (err < 0) { 44846e655bf2STakashi Iwai printk(KERN_ERR "hda_codec: cannot build PCMs" 44856e655bf2STakashi Iwai "for #%d (error %d)\n", codec->addr, err); 44866e655bf2STakashi Iwai err = snd_hda_codec_reset(codec); 44876e655bf2STakashi Iwai if (err < 0) { 44886e655bf2STakashi Iwai printk(KERN_ERR 44896e655bf2STakashi Iwai "hda_codec: cannot revert codec\n"); 4490529bd6c4STakashi Iwai return err; 4491529bd6c4STakashi Iwai } 44926e655bf2STakashi Iwai } 44936e655bf2STakashi Iwai } 4494529bd6c4STakashi Iwai for (pcm = 0; pcm < codec->num_pcms; pcm++) { 4495529bd6c4STakashi Iwai struct hda_pcm *cpcm = &codec->pcm_info[pcm]; 4496529bd6c4STakashi Iwai int dev; 4497529bd6c4STakashi Iwai 4498529bd6c4STakashi Iwai if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) 449941b5b01aSTakashi Iwai continue; /* no substreams assigned */ 4500529bd6c4STakashi Iwai 4501529bd6c4STakashi Iwai if (!cpcm->pcm) { 4502529bd6c4STakashi Iwai dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type); 4503529bd6c4STakashi Iwai if (dev < 0) 45046e655bf2STakashi Iwai continue; /* no fatal error */ 4505529bd6c4STakashi Iwai cpcm->device = dev; 4506529bd6c4STakashi Iwai err = snd_hda_attach_pcm(codec, cpcm); 45076e655bf2STakashi Iwai if (err < 0) { 45086e655bf2STakashi Iwai printk(KERN_ERR "hda_codec: cannot attach " 45096e655bf2STakashi Iwai "PCM stream %d for codec #%d\n", 45106e655bf2STakashi Iwai dev, codec->addr); 45116e655bf2STakashi Iwai continue; /* no fatal error */ 45126e655bf2STakashi Iwai } 4513529bd6c4STakashi Iwai } 4514529bd6c4STakashi Iwai } 4515529bd6c4STakashi Iwai return 0; 4516529bd6c4STakashi Iwai } 4517529bd6c4STakashi Iwai 45181da177e4SLinus Torvalds /** 45191da177e4SLinus Torvalds * snd_hda_build_pcms - build PCM information 45201da177e4SLinus Torvalds * @bus: the BUS 45211da177e4SLinus Torvalds * 45221da177e4SLinus Torvalds * Create PCM information for each codec included in the bus. 45231da177e4SLinus Torvalds * 45241da177e4SLinus Torvalds * The build_pcms codec patch is requested to set up codec->num_pcms and 45251da177e4SLinus Torvalds * codec->pcm_info properly. The array is referred by the top-level driver 45261da177e4SLinus Torvalds * to create its PCM instances. 45271da177e4SLinus Torvalds * The allocated codec->pcm_info should be released in codec->patch_ops.free 45281da177e4SLinus Torvalds * callback. 45291da177e4SLinus Torvalds * 45301da177e4SLinus Torvalds * At least, substreams, channels_min and channels_max must be filled for 45311da177e4SLinus Torvalds * each stream. substreams = 0 indicates that the stream doesn't exist. 45321da177e4SLinus Torvalds * When rates and/or formats are zero, the supported values are queried 45331da177e4SLinus Torvalds * from the given nid. The nid is used also by the default ops.prepare 45341da177e4SLinus Torvalds * and ops.cleanup callbacks. 45351da177e4SLinus Torvalds * 45361da177e4SLinus Torvalds * The driver needs to call ops.open in its open callback. Similarly, 45371da177e4SLinus Torvalds * ops.close is supposed to be called in the close callback. 45381da177e4SLinus Torvalds * ops.prepare should be called in the prepare or hw_params callback 45391da177e4SLinus Torvalds * with the proper parameters for set up. 45401da177e4SLinus Torvalds * ops.cleanup should be called in hw_free for clean up of streams. 45411da177e4SLinus Torvalds * 454225985edcSLucas De Marchi * This function returns 0 if successful, or a negative error code. 45431da177e4SLinus Torvalds */ 45445cb543dbSTakashi Iwai int snd_hda_build_pcms(struct hda_bus *bus) 45451da177e4SLinus Torvalds { 45460ba21762STakashi Iwai struct hda_codec *codec; 45471da177e4SLinus Torvalds 45480ba21762STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 4549529bd6c4STakashi Iwai int err = snd_hda_codec_build_pcms(codec); 45501da177e4SLinus Torvalds if (err < 0) 45511da177e4SLinus Torvalds return err; 45526c1f45eaSTakashi Iwai } 45531da177e4SLinus Torvalds return 0; 45541da177e4SLinus Torvalds } 4555ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_build_pcms); 45561da177e4SLinus Torvalds 45571da177e4SLinus Torvalds /** 45581da177e4SLinus Torvalds * snd_hda_check_board_config - compare the current codec with the config table 45591da177e4SLinus Torvalds * @codec: the HDA codec 4560f5fcc13cSTakashi Iwai * @num_configs: number of config enums 4561f5fcc13cSTakashi Iwai * @models: array of model name strings 45621da177e4SLinus Torvalds * @tbl: configuration table, terminated by null entries 45631da177e4SLinus Torvalds * 45641da177e4SLinus Torvalds * Compares the modelname or PCI subsystem id of the current codec with the 45651da177e4SLinus Torvalds * given configuration table. If a matching entry is found, returns its 45661da177e4SLinus Torvalds * config value (supposed to be 0 or positive). 45671da177e4SLinus Torvalds * 45681da177e4SLinus Torvalds * If no entries are matching, the function returns a negative value. 45691da177e4SLinus Torvalds */ 457012f288bfSTakashi Iwai int snd_hda_check_board_config(struct hda_codec *codec, 4571ea734963STakashi Iwai int num_configs, const char * const *models, 4572f5fcc13cSTakashi Iwai const struct snd_pci_quirk *tbl) 45731da177e4SLinus Torvalds { 4574f44ac837STakashi Iwai if (codec->modelname && models) { 4575f5fcc13cSTakashi Iwai int i; 4576f5fcc13cSTakashi Iwai for (i = 0; i < num_configs; i++) { 4577f5fcc13cSTakashi Iwai if (models[i] && 4578f44ac837STakashi Iwai !strcmp(codec->modelname, models[i])) { 4579f5fcc13cSTakashi Iwai snd_printd(KERN_INFO "hda_codec: model '%s' is " 4580f5fcc13cSTakashi Iwai "selected\n", models[i]); 4581f5fcc13cSTakashi Iwai return i; 45821da177e4SLinus Torvalds } 45831da177e4SLinus Torvalds } 45841da177e4SLinus Torvalds } 45851da177e4SLinus Torvalds 4586f5fcc13cSTakashi Iwai if (!codec->bus->pci || !tbl) 4587f5fcc13cSTakashi Iwai return -1; 4588f5fcc13cSTakashi Iwai 4589f5fcc13cSTakashi Iwai tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl); 4590f5fcc13cSTakashi Iwai if (!tbl) 4591f5fcc13cSTakashi Iwai return -1; 4592f5fcc13cSTakashi Iwai if (tbl->value >= 0 && tbl->value < num_configs) { 459362cf872aSTakashi Iwai #ifdef CONFIG_SND_DEBUG_VERBOSE 4594f5fcc13cSTakashi Iwai char tmp[10]; 4595f5fcc13cSTakashi Iwai const char *model = NULL; 4596f5fcc13cSTakashi Iwai if (models) 4597f5fcc13cSTakashi Iwai model = models[tbl->value]; 4598f5fcc13cSTakashi Iwai if (!model) { 4599f5fcc13cSTakashi Iwai sprintf(tmp, "#%d", tbl->value); 4600f5fcc13cSTakashi Iwai model = tmp; 46011da177e4SLinus Torvalds } 4602f5fcc13cSTakashi Iwai snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " 4603f5fcc13cSTakashi Iwai "for config %x:%x (%s)\n", 4604f5fcc13cSTakashi Iwai model, tbl->subvendor, tbl->subdevice, 4605f5fcc13cSTakashi Iwai (tbl->name ? tbl->name : "Unknown device")); 4606f5fcc13cSTakashi Iwai #endif 4607f5fcc13cSTakashi Iwai return tbl->value; 4608cb8e2f83STakashi Iwai } 46091da177e4SLinus Torvalds return -1; 46101da177e4SLinus Torvalds } 4611ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_check_board_config); 46121da177e4SLinus Torvalds 46131da177e4SLinus Torvalds /** 46142eda3445SMauro Carvalho Chehab * snd_hda_check_board_codec_sid_config - compare the current codec 46152eda3445SMauro Carvalho Chehab subsystem ID with the 46162eda3445SMauro Carvalho Chehab config table 46172eda3445SMauro Carvalho Chehab 46182eda3445SMauro Carvalho Chehab This is important for Gateway notebooks with SB450 HDA Audio 46192eda3445SMauro Carvalho Chehab where the vendor ID of the PCI device is: 46202eda3445SMauro Carvalho Chehab ATI Technologies Inc SB450 HDA Audio [1002:437b] 46212eda3445SMauro Carvalho Chehab and the vendor/subvendor are found only at the codec. 46222eda3445SMauro Carvalho Chehab 46232eda3445SMauro Carvalho Chehab * @codec: the HDA codec 46242eda3445SMauro Carvalho Chehab * @num_configs: number of config enums 46252eda3445SMauro Carvalho Chehab * @models: array of model name strings 46262eda3445SMauro Carvalho Chehab * @tbl: configuration table, terminated by null entries 46272eda3445SMauro Carvalho Chehab * 46282eda3445SMauro Carvalho Chehab * Compares the modelname or PCI subsystem id of the current codec with the 46292eda3445SMauro Carvalho Chehab * given configuration table. If a matching entry is found, returns its 46302eda3445SMauro Carvalho Chehab * config value (supposed to be 0 or positive). 46312eda3445SMauro Carvalho Chehab * 46322eda3445SMauro Carvalho Chehab * If no entries are matching, the function returns a negative value. 46332eda3445SMauro Carvalho Chehab */ 46342eda3445SMauro Carvalho Chehab int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, 4635ea734963STakashi Iwai int num_configs, const char * const *models, 46362eda3445SMauro Carvalho Chehab const struct snd_pci_quirk *tbl) 46372eda3445SMauro Carvalho Chehab { 46382eda3445SMauro Carvalho Chehab const struct snd_pci_quirk *q; 46392eda3445SMauro Carvalho Chehab 46402eda3445SMauro Carvalho Chehab /* Search for codec ID */ 46412eda3445SMauro Carvalho Chehab for (q = tbl; q->subvendor; q++) { 4642e2301a4dSTakashi Iwai unsigned int mask = 0xffff0000 | q->subdevice_mask; 4643e2301a4dSTakashi Iwai unsigned int id = (q->subdevice | (q->subvendor << 16)) & mask; 4644e2301a4dSTakashi Iwai if ((codec->subsystem_id & mask) == id) 46452eda3445SMauro Carvalho Chehab break; 46462eda3445SMauro Carvalho Chehab } 46472eda3445SMauro Carvalho Chehab 46482eda3445SMauro Carvalho Chehab if (!q->subvendor) 46492eda3445SMauro Carvalho Chehab return -1; 46502eda3445SMauro Carvalho Chehab 46512eda3445SMauro Carvalho Chehab tbl = q; 46522eda3445SMauro Carvalho Chehab 46532eda3445SMauro Carvalho Chehab if (tbl->value >= 0 && tbl->value < num_configs) { 4654d94ff6b7STakashi Iwai #ifdef CONFIG_SND_DEBUG_VERBOSE 46552eda3445SMauro Carvalho Chehab char tmp[10]; 46562eda3445SMauro Carvalho Chehab const char *model = NULL; 46572eda3445SMauro Carvalho Chehab if (models) 46582eda3445SMauro Carvalho Chehab model = models[tbl->value]; 46592eda3445SMauro Carvalho Chehab if (!model) { 46602eda3445SMauro Carvalho Chehab sprintf(tmp, "#%d", tbl->value); 46612eda3445SMauro Carvalho Chehab model = tmp; 46622eda3445SMauro Carvalho Chehab } 46632eda3445SMauro Carvalho Chehab snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " 46642eda3445SMauro Carvalho Chehab "for config %x:%x (%s)\n", 46652eda3445SMauro Carvalho Chehab model, tbl->subvendor, tbl->subdevice, 46662eda3445SMauro Carvalho Chehab (tbl->name ? tbl->name : "Unknown device")); 46672eda3445SMauro Carvalho Chehab #endif 46682eda3445SMauro Carvalho Chehab return tbl->value; 46692eda3445SMauro Carvalho Chehab } 46702eda3445SMauro Carvalho Chehab return -1; 46712eda3445SMauro Carvalho Chehab } 46722eda3445SMauro Carvalho Chehab EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config); 46732eda3445SMauro Carvalho Chehab 46742eda3445SMauro Carvalho Chehab /** 46751da177e4SLinus Torvalds * snd_hda_add_new_ctls - create controls from the array 46761da177e4SLinus Torvalds * @codec: the HDA codec 4677c8b6bf9bSTakashi Iwai * @knew: the array of struct snd_kcontrol_new 46781da177e4SLinus Torvalds * 46791da177e4SLinus Torvalds * This helper function creates and add new controls in the given array. 46801da177e4SLinus Torvalds * The array must be terminated with an empty entry as terminator. 46811da177e4SLinus Torvalds * 46821da177e4SLinus Torvalds * Returns 0 if successful, or a negative error code. 46831da177e4SLinus Torvalds */ 4684031024eeSTakashi Iwai int snd_hda_add_new_ctls(struct hda_codec *codec, 4685031024eeSTakashi Iwai const struct snd_kcontrol_new *knew) 46861da177e4SLinus Torvalds { 46871da177e4SLinus Torvalds int err; 46881da177e4SLinus Torvalds 46891da177e4SLinus Torvalds for (; knew->name; knew++) { 469054d17403STakashi Iwai struct snd_kcontrol *kctl; 46911afe206aSTakashi Iwai int addr = 0, idx = 0; 46925b0cb1d8SJaroslav Kysela if (knew->iface == -1) /* skip this codec private value */ 46935b0cb1d8SJaroslav Kysela continue; 46941afe206aSTakashi Iwai for (;;) { 469554d17403STakashi Iwai kctl = snd_ctl_new1(knew, codec); 469654d17403STakashi Iwai if (!kctl) 469754d17403STakashi Iwai return -ENOMEM; 46981afe206aSTakashi Iwai if (addr > 0) 46991afe206aSTakashi Iwai kctl->id.device = addr; 47001afe206aSTakashi Iwai if (idx > 0) 47011afe206aSTakashi Iwai kctl->id.index = idx; 47023911a4c1SJaroslav Kysela err = snd_hda_ctl_add(codec, 0, kctl); 47031afe206aSTakashi Iwai if (!err) 47041afe206aSTakashi Iwai break; 47051afe206aSTakashi Iwai /* try first with another device index corresponding to 47061afe206aSTakashi Iwai * the codec addr; if it still fails (or it's the 47071afe206aSTakashi Iwai * primary codec), then try another control index 47081afe206aSTakashi Iwai */ 47091afe206aSTakashi Iwai if (!addr && codec->addr) 47101afe206aSTakashi Iwai addr = codec->addr; 47111afe206aSTakashi Iwai else if (!idx && !knew->index) { 47121afe206aSTakashi Iwai idx = find_empty_mixer_ctl_idx(codec, 4713dcda5806STakashi Iwai knew->name, 0); 47141afe206aSTakashi Iwai if (idx <= 0) 47151da177e4SLinus Torvalds return err; 47161afe206aSTakashi Iwai } else 471754d17403STakashi Iwai return err; 471854d17403STakashi Iwai } 47191da177e4SLinus Torvalds } 47201da177e4SLinus Torvalds return 0; 47211da177e4SLinus Torvalds } 4722ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); 47231da177e4SLinus Torvalds 472483012a7cSTakashi Iwai #ifdef CONFIG_PM 4725cb53c626STakashi Iwai static void hda_power_work(struct work_struct *work) 4726cb53c626STakashi Iwai { 4727cb53c626STakashi Iwai struct hda_codec *codec = 4728cb53c626STakashi Iwai container_of(work, struct hda_codec, power_work.work); 472933fa35edSTakashi Iwai struct hda_bus *bus = codec->bus; 473008fa20aeSTakashi Iwai unsigned int state; 4731cb53c626STakashi Iwai 47325536c6d6STakashi Iwai spin_lock(&codec->power_lock); 4733a2d96e77STakashi Iwai if (codec->power_transition > 0) { /* during power-up sequence? */ 4734a2d96e77STakashi Iwai spin_unlock(&codec->power_lock); 4735a2d96e77STakashi Iwai return; 4736a2d96e77STakashi Iwai } 47372e492462SMaxim Levitsky if (!codec->power_on || codec->power_count) { 47382e492462SMaxim Levitsky codec->power_transition = 0; 47395536c6d6STakashi Iwai spin_unlock(&codec->power_lock); 4740cb53c626STakashi Iwai return; 47412e492462SMaxim Levitsky } 47425536c6d6STakashi Iwai spin_unlock(&codec->power_lock); 47435536c6d6STakashi Iwai 4744d17344b3SDylan Reid state = hda_call_codec_suspend(codec, true); 474508fa20aeSTakashi Iwai codec->pm_down_notified = 0; 474608fa20aeSTakashi Iwai if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) { 474708fa20aeSTakashi Iwai codec->pm_down_notified = 1; 474868467f51STakashi Iwai hda_call_pm_notify(bus, false); 4749cb53c626STakashi Iwai } 475008fa20aeSTakashi Iwai } 4751cb53c626STakashi Iwai 4752cb53c626STakashi Iwai static void hda_keep_power_on(struct hda_codec *codec) 4753cb53c626STakashi Iwai { 47545536c6d6STakashi Iwai spin_lock(&codec->power_lock); 4755cb53c626STakashi Iwai codec->power_count++; 4756cb53c626STakashi Iwai codec->power_on = 1; 4757a2f6309eSTakashi Iwai codec->power_jiffies = jiffies; 47585536c6d6STakashi Iwai spin_unlock(&codec->power_lock); 4759a2f6309eSTakashi Iwai } 4760a2f6309eSTakashi Iwai 4761d5191e50STakashi Iwai /* update the power on/off account with the current jiffies */ 4762a2f6309eSTakashi Iwai void snd_hda_update_power_acct(struct hda_codec *codec) 4763a2f6309eSTakashi Iwai { 4764a2f6309eSTakashi Iwai unsigned long delta = jiffies - codec->power_jiffies; 4765a2f6309eSTakashi Iwai if (codec->power_on) 4766a2f6309eSTakashi Iwai codec->power_on_acct += delta; 4767a2f6309eSTakashi Iwai else 4768a2f6309eSTakashi Iwai codec->power_off_acct += delta; 4769a2f6309eSTakashi Iwai codec->power_jiffies += delta; 4770cb53c626STakashi Iwai } 4771cb53c626STakashi Iwai 4772b4a91cf0SDylan Reid /* Transition to powered up, if wait_power_down then wait for a pending 4773b4a91cf0SDylan Reid * transition to D3 to complete. A pending D3 transition is indicated 4774b4a91cf0SDylan Reid * with power_transition == -1. */ 4775c376e2c7STakashi Iwai /* call this with codec->power_lock held! */ 4776b4a91cf0SDylan Reid static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) 4777cb53c626STakashi Iwai { 477833fa35edSTakashi Iwai struct hda_bus *bus = codec->bus; 477933fa35edSTakashi Iwai 4780b4a91cf0SDylan Reid /* Return if power_on or transitioning to power_on, unless currently 4781b4a91cf0SDylan Reid * powering down. */ 4782b4a91cf0SDylan Reid if ((codec->power_on || codec->power_transition > 0) && 4783c376e2c7STakashi Iwai !(wait_power_down && codec->power_transition < 0)) 4784cb53c626STakashi Iwai return; 4785a2d96e77STakashi Iwai spin_unlock(&codec->power_lock); 4786cb53c626STakashi Iwai 4787a2d96e77STakashi Iwai cancel_delayed_work_sync(&codec->power_work); 4788a2d96e77STakashi Iwai 4789a2d96e77STakashi Iwai spin_lock(&codec->power_lock); 4790b43d2247SDylan Reid /* If the power down delayed work was cancelled above before starting, 4791b43d2247SDylan Reid * then there is no need to go through power up here. 4792b43d2247SDylan Reid */ 4793b43d2247SDylan Reid if (codec->power_on) { 4794535b6c51STakashi Iwai if (codec->power_transition < 0) 4795535b6c51STakashi Iwai codec->power_transition = 0; 4796b43d2247SDylan Reid return; 4797b43d2247SDylan Reid } 4798c376e2c7STakashi Iwai 4799d66fee5dSTakashi Iwai trace_hda_power_up(codec); 4800a2f6309eSTakashi Iwai snd_hda_update_power_acct(codec); 4801cb53c626STakashi Iwai codec->power_on = 1; 4802a2f6309eSTakashi Iwai codec->power_jiffies = jiffies; 48037f30830bSTakashi Iwai codec->power_transition = 1; /* avoid reentrance */ 48045536c6d6STakashi Iwai spin_unlock(&codec->power_lock); 48055536c6d6STakashi Iwai 480608fa20aeSTakashi Iwai if (codec->pm_down_notified) { 480708fa20aeSTakashi Iwai codec->pm_down_notified = 0; 480868467f51STakashi Iwai hda_call_pm_notify(bus, true); 480908fa20aeSTakashi Iwai } 481008fa20aeSTakashi Iwai 4811cb53c626STakashi Iwai hda_call_codec_resume(codec); 48125536c6d6STakashi Iwai 48135536c6d6STakashi Iwai spin_lock(&codec->power_lock); 4814a221e287STakashi Iwai codec->power_transition = 0; 4815cb53c626STakashi Iwai } 4816b4a91cf0SDylan Reid 48171289e9e8STakashi Iwai #define power_save(codec) \ 48181289e9e8STakashi Iwai ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) 4819cb53c626STakashi Iwai 4820c376e2c7STakashi Iwai /* Transition to powered down */ 4821c376e2c7STakashi Iwai static void __snd_hda_power_down(struct hda_codec *codec) 4822cb53c626STakashi Iwai { 4823c376e2c7STakashi Iwai if (!codec->power_on || codec->power_count || codec->power_transition) 4824cb53c626STakashi Iwai return; 4825c376e2c7STakashi Iwai 4826fee2fba3STakashi Iwai if (power_save(codec)) { 4827a2d96e77STakashi Iwai codec->power_transition = -1; /* avoid reentrance */ 4828c107b41cSTakashi Iwai queue_delayed_work(codec->bus->workq, &codec->power_work, 4829fee2fba3STakashi Iwai msecs_to_jiffies(power_save(codec) * 1000)); 4830cb53c626STakashi Iwai } 4831c376e2c7STakashi Iwai } 4832c376e2c7STakashi Iwai 4833c376e2c7STakashi Iwai /** 4834c376e2c7STakashi Iwai * snd_hda_power_save - Power-up/down/sync the codec 4835c376e2c7STakashi Iwai * @codec: HD-audio codec 4836c376e2c7STakashi Iwai * @delta: the counter delta to change 4837c376e2c7STakashi Iwai * 4838c376e2c7STakashi Iwai * Change the power-up counter via @delta, and power up or down the hardware 4839c376e2c7STakashi Iwai * appropriately. For the power-down, queue to the delayed action. 4840c376e2c7STakashi Iwai * Passing zero to @delta means to synchronize the power state. 4841c376e2c7STakashi Iwai */ 4842c376e2c7STakashi Iwai void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait) 4843c376e2c7STakashi Iwai { 4844c376e2c7STakashi Iwai spin_lock(&codec->power_lock); 4845c376e2c7STakashi Iwai codec->power_count += delta; 4846c376e2c7STakashi Iwai trace_hda_power_count(codec); 4847c376e2c7STakashi Iwai if (delta > 0) 4848c376e2c7STakashi Iwai __snd_hda_power_up(codec, d3wait); 4849c376e2c7STakashi Iwai else 4850c376e2c7STakashi Iwai __snd_hda_power_down(codec); 48515536c6d6STakashi Iwai spin_unlock(&codec->power_lock); 4852a221e287STakashi Iwai } 4853c376e2c7STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_power_save); 4854cb53c626STakashi Iwai 4855d5191e50STakashi Iwai /** 4856d5191e50STakashi Iwai * snd_hda_check_amp_list_power - Check the amp list and update the power 4857d5191e50STakashi Iwai * @codec: HD-audio codec 4858d5191e50STakashi Iwai * @check: the object containing an AMP list and the status 4859d5191e50STakashi Iwai * @nid: NID to check / update 4860d5191e50STakashi Iwai * 4861d5191e50STakashi Iwai * Check whether the given NID is in the amp list. If it's in the list, 4862d5191e50STakashi Iwai * check the current AMP status, and update the the power-status according 4863d5191e50STakashi Iwai * to the mute status. 4864d5191e50STakashi Iwai * 4865d5191e50STakashi Iwai * This function is supposed to be set or called from the check_power_status 4866d5191e50STakashi Iwai * patch ops. 4867d5191e50STakashi Iwai */ 4868cb53c626STakashi Iwai int snd_hda_check_amp_list_power(struct hda_codec *codec, 4869cb53c626STakashi Iwai struct hda_loopback_check *check, 4870cb53c626STakashi Iwai hda_nid_t nid) 4871cb53c626STakashi Iwai { 4872031024eeSTakashi Iwai const struct hda_amp_list *p; 4873cb53c626STakashi Iwai int ch, v; 4874cb53c626STakashi Iwai 4875cb53c626STakashi Iwai if (!check->amplist) 4876cb53c626STakashi Iwai return 0; 4877cb53c626STakashi Iwai for (p = check->amplist; p->nid; p++) { 4878cb53c626STakashi Iwai if (p->nid == nid) 4879cb53c626STakashi Iwai break; 4880cb53c626STakashi Iwai } 4881cb53c626STakashi Iwai if (!p->nid) 4882cb53c626STakashi Iwai return 0; /* nothing changed */ 4883cb53c626STakashi Iwai 4884cb53c626STakashi Iwai for (p = check->amplist; p->nid; p++) { 4885cb53c626STakashi Iwai for (ch = 0; ch < 2; ch++) { 4886cb53c626STakashi Iwai v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, 4887cb53c626STakashi Iwai p->idx); 4888cb53c626STakashi Iwai if (!(v & HDA_AMP_MUTE) && v > 0) { 4889cb53c626STakashi Iwai if (!check->power_on) { 4890cb53c626STakashi Iwai check->power_on = 1; 4891cb53c626STakashi Iwai snd_hda_power_up(codec); 4892cb53c626STakashi Iwai } 4893cb53c626STakashi Iwai return 1; 4894cb53c626STakashi Iwai } 4895cb53c626STakashi Iwai } 4896cb53c626STakashi Iwai } 4897cb53c626STakashi Iwai if (check->power_on) { 4898cb53c626STakashi Iwai check->power_on = 0; 4899cb53c626STakashi Iwai snd_hda_power_down(codec); 4900cb53c626STakashi Iwai } 4901cb53c626STakashi Iwai return 0; 4902cb53c626STakashi Iwai } 4903ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); 4904cb53c626STakashi Iwai #endif 49051da177e4SLinus Torvalds 4906d2a6d7dcSTakashi Iwai /* 4907d2a6d7dcSTakashi Iwai * Channel mode helper 4908d2a6d7dcSTakashi Iwai */ 4909d5191e50STakashi Iwai 4910d5191e50STakashi Iwai /** 4911d5191e50STakashi Iwai * snd_hda_ch_mode_info - Info callback helper for the channel mode enum 4912d5191e50STakashi Iwai */ 49130ba21762STakashi Iwai int snd_hda_ch_mode_info(struct hda_codec *codec, 49140ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo, 49150ba21762STakashi Iwai const struct hda_channel_mode *chmode, 49160ba21762STakashi Iwai int num_chmodes) 4917d2a6d7dcSTakashi Iwai { 4918d2a6d7dcSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 4919d2a6d7dcSTakashi Iwai uinfo->count = 1; 4920d2a6d7dcSTakashi Iwai uinfo->value.enumerated.items = num_chmodes; 4921d2a6d7dcSTakashi Iwai if (uinfo->value.enumerated.item >= num_chmodes) 4922d2a6d7dcSTakashi Iwai uinfo->value.enumerated.item = num_chmodes - 1; 4923d2a6d7dcSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", 4924d2a6d7dcSTakashi Iwai chmode[uinfo->value.enumerated.item].channels); 4925d2a6d7dcSTakashi Iwai return 0; 4926d2a6d7dcSTakashi Iwai } 4927ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info); 4928d2a6d7dcSTakashi Iwai 4929d5191e50STakashi Iwai /** 4930d5191e50STakashi Iwai * snd_hda_ch_mode_get - Get callback helper for the channel mode enum 4931d5191e50STakashi Iwai */ 49320ba21762STakashi Iwai int snd_hda_ch_mode_get(struct hda_codec *codec, 49330ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol, 49340ba21762STakashi Iwai const struct hda_channel_mode *chmode, 49350ba21762STakashi Iwai int num_chmodes, 4936d2a6d7dcSTakashi Iwai int max_channels) 4937d2a6d7dcSTakashi Iwai { 4938d2a6d7dcSTakashi Iwai int i; 4939d2a6d7dcSTakashi Iwai 4940d2a6d7dcSTakashi Iwai for (i = 0; i < num_chmodes; i++) { 4941d2a6d7dcSTakashi Iwai if (max_channels == chmode[i].channels) { 4942d2a6d7dcSTakashi Iwai ucontrol->value.enumerated.item[0] = i; 4943d2a6d7dcSTakashi Iwai break; 4944d2a6d7dcSTakashi Iwai } 4945d2a6d7dcSTakashi Iwai } 4946d2a6d7dcSTakashi Iwai return 0; 4947d2a6d7dcSTakashi Iwai } 4948ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get); 4949d2a6d7dcSTakashi Iwai 4950d5191e50STakashi Iwai /** 4951d5191e50STakashi Iwai * snd_hda_ch_mode_put - Put callback helper for the channel mode enum 4952d5191e50STakashi Iwai */ 49530ba21762STakashi Iwai int snd_hda_ch_mode_put(struct hda_codec *codec, 49540ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol, 49550ba21762STakashi Iwai const struct hda_channel_mode *chmode, 49560ba21762STakashi Iwai int num_chmodes, 4957d2a6d7dcSTakashi Iwai int *max_channelsp) 4958d2a6d7dcSTakashi Iwai { 4959d2a6d7dcSTakashi Iwai unsigned int mode; 4960d2a6d7dcSTakashi Iwai 4961d2a6d7dcSTakashi Iwai mode = ucontrol->value.enumerated.item[0]; 496268ea7b2fSTakashi Iwai if (mode >= num_chmodes) 496368ea7b2fSTakashi Iwai return -EINVAL; 496482beb8fdSTakashi Iwai if (*max_channelsp == chmode[mode].channels) 4965d2a6d7dcSTakashi Iwai return 0; 4966d2a6d7dcSTakashi Iwai /* change the current channel setting */ 4967d2a6d7dcSTakashi Iwai *max_channelsp = chmode[mode].channels; 4968d2a6d7dcSTakashi Iwai if (chmode[mode].sequence) 496982beb8fdSTakashi Iwai snd_hda_sequence_write_cache(codec, chmode[mode].sequence); 4970d2a6d7dcSTakashi Iwai return 1; 4971d2a6d7dcSTakashi Iwai } 4972ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put); 4973d2a6d7dcSTakashi Iwai 49741da177e4SLinus Torvalds /* 49751da177e4SLinus Torvalds * input MUX helper 49761da177e4SLinus Torvalds */ 4977d5191e50STakashi Iwai 4978d5191e50STakashi Iwai /** 4979d5191e50STakashi Iwai * snd_hda_input_mux_info_info - Info callback helper for the input-mux enum 4980d5191e50STakashi Iwai */ 49810ba21762STakashi Iwai int snd_hda_input_mux_info(const struct hda_input_mux *imux, 49820ba21762STakashi Iwai struct snd_ctl_elem_info *uinfo) 49831da177e4SLinus Torvalds { 49841da177e4SLinus Torvalds unsigned int index; 49851da177e4SLinus Torvalds 49861da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 49871da177e4SLinus Torvalds uinfo->count = 1; 49881da177e4SLinus Torvalds uinfo->value.enumerated.items = imux->num_items; 49895513b0c5STakashi Iwai if (!imux->num_items) 49905513b0c5STakashi Iwai return 0; 49911da177e4SLinus Torvalds index = uinfo->value.enumerated.item; 49921da177e4SLinus Torvalds if (index >= imux->num_items) 49931da177e4SLinus Torvalds index = imux->num_items - 1; 49941da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, imux->items[index].label); 49951da177e4SLinus Torvalds return 0; 49961da177e4SLinus Torvalds } 4997ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_input_mux_info); 49981da177e4SLinus Torvalds 4999d5191e50STakashi Iwai /** 5000d5191e50STakashi Iwai * snd_hda_input_mux_info_put - Put callback helper for the input-mux enum 5001d5191e50STakashi Iwai */ 50020ba21762STakashi Iwai int snd_hda_input_mux_put(struct hda_codec *codec, 50030ba21762STakashi Iwai const struct hda_input_mux *imux, 50040ba21762STakashi Iwai struct snd_ctl_elem_value *ucontrol, 50050ba21762STakashi Iwai hda_nid_t nid, 50061da177e4SLinus Torvalds unsigned int *cur_val) 50071da177e4SLinus Torvalds { 50081da177e4SLinus Torvalds unsigned int idx; 50091da177e4SLinus Torvalds 50105513b0c5STakashi Iwai if (!imux->num_items) 50115513b0c5STakashi Iwai return 0; 50121da177e4SLinus Torvalds idx = ucontrol->value.enumerated.item[0]; 50131da177e4SLinus Torvalds if (idx >= imux->num_items) 50141da177e4SLinus Torvalds idx = imux->num_items - 1; 501582beb8fdSTakashi Iwai if (*cur_val == idx) 50161da177e4SLinus Torvalds return 0; 501782beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, 50181da177e4SLinus Torvalds imux->items[idx].index); 50191da177e4SLinus Torvalds *cur_val = idx; 50201da177e4SLinus Torvalds return 1; 50211da177e4SLinus Torvalds } 5022ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); 50231da177e4SLinus Torvalds 50241da177e4SLinus Torvalds 50251da177e4SLinus Torvalds /* 5026dda415d4STakashi Iwai * process kcontrol info callback of a simple string enum array 5027dda415d4STakashi Iwai * when @num_items is 0 or @texts is NULL, assume a boolean enum array 5028dda415d4STakashi Iwai */ 5029dda415d4STakashi Iwai int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, 5030dda415d4STakashi Iwai struct snd_ctl_elem_info *uinfo, 5031dda415d4STakashi Iwai int num_items, const char * const *texts) 5032dda415d4STakashi Iwai { 5033dda415d4STakashi Iwai static const char * const texts_default[] = { 5034dda415d4STakashi Iwai "Disabled", "Enabled" 5035dda415d4STakashi Iwai }; 5036dda415d4STakashi Iwai 5037dda415d4STakashi Iwai if (!texts || !num_items) { 5038dda415d4STakashi Iwai num_items = 2; 5039dda415d4STakashi Iwai texts = texts_default; 5040dda415d4STakashi Iwai } 5041dda415d4STakashi Iwai 5042dda415d4STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 5043dda415d4STakashi Iwai uinfo->count = 1; 5044dda415d4STakashi Iwai uinfo->value.enumerated.items = num_items; 5045dda415d4STakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 5046dda415d4STakashi Iwai uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 5047dda415d4STakashi Iwai strcpy(uinfo->value.enumerated.name, 5048dda415d4STakashi Iwai texts[uinfo->value.enumerated.item]); 5049dda415d4STakashi Iwai return 0; 5050dda415d4STakashi Iwai } 5051dda415d4STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_enum_helper_info); 5052dda415d4STakashi Iwai 5053dda415d4STakashi Iwai /* 50541da177e4SLinus Torvalds * Multi-channel / digital-out PCM helper functions 50551da177e4SLinus Torvalds */ 50561da177e4SLinus Torvalds 50576b97eb45STakashi Iwai /* setup SPDIF output stream */ 50586b97eb45STakashi Iwai static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, 50596b97eb45STakashi Iwai unsigned int stream_tag, unsigned int format) 50606b97eb45STakashi Iwai { 50613bef1c37SLaurence Darby struct hda_spdif_out *spdif; 50623bef1c37SLaurence Darby unsigned int curr_fmt; 50633bef1c37SLaurence Darby bool reset; 50647c935976SStephen Warren 50653bef1c37SLaurence Darby spdif = snd_hda_spdif_out_of_nid(codec, nid); 50663bef1c37SLaurence Darby curr_fmt = snd_hda_codec_read(codec, nid, 0, 50673bef1c37SLaurence Darby AC_VERB_GET_STREAM_FORMAT, 0); 50683bef1c37SLaurence Darby reset = codec->spdif_status_reset && 50693bef1c37SLaurence Darby (spdif->ctls & AC_DIG1_ENABLE) && 50703bef1c37SLaurence Darby curr_fmt != format; 50713bef1c37SLaurence Darby 50723bef1c37SLaurence Darby /* turn off SPDIF if needed; otherwise the IEC958 bits won't be 50733bef1c37SLaurence Darby updated */ 50743bef1c37SLaurence Darby if (reset) 50752f72853cSTakashi Iwai set_dig_out_convert(codec, nid, 50767c935976SStephen Warren spdif->ctls & ~AC_DIG1_ENABLE & 0xff, 50772f72853cSTakashi Iwai -1); 50786b97eb45STakashi Iwai snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); 50792f72853cSTakashi Iwai if (codec->slave_dig_outs) { 5080dda14410STakashi Iwai const hda_nid_t *d; 5081de51ca12SMatthew Ranostay for (d = codec->slave_dig_outs; *d; d++) 50822f72853cSTakashi Iwai snd_hda_codec_setup_stream(codec, *d, stream_tag, 0, 50832f72853cSTakashi Iwai format); 50842f72853cSTakashi Iwai } 50852f72853cSTakashi Iwai /* turn on again (if needed) */ 50863bef1c37SLaurence Darby if (reset) 50872f72853cSTakashi Iwai set_dig_out_convert(codec, nid, 50887c935976SStephen Warren spdif->ctls & 0xff, -1); 5089de51ca12SMatthew Ranostay } 5090de51ca12SMatthew Ranostay 50912f72853cSTakashi Iwai static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) 50922f72853cSTakashi Iwai { 50932f72853cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, nid); 50942f72853cSTakashi Iwai if (codec->slave_dig_outs) { 5095dda14410STakashi Iwai const hda_nid_t *d; 50962f72853cSTakashi Iwai for (d = codec->slave_dig_outs; *d; d++) 50972f72853cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, *d); 50982f72853cSTakashi Iwai } 50996b97eb45STakashi Iwai } 51006b97eb45STakashi Iwai 5101d5191e50STakashi Iwai /** 5102d5191e50STakashi Iwai * snd_hda_bus_reboot_notify - call the reboot notifier of each codec 5103d5191e50STakashi Iwai * @bus: HD-audio bus 5104d5191e50STakashi Iwai */ 5105fb8d1a34STakashi Iwai void snd_hda_bus_reboot_notify(struct hda_bus *bus) 5106fb8d1a34STakashi Iwai { 5107fb8d1a34STakashi Iwai struct hda_codec *codec; 5108fb8d1a34STakashi Iwai 5109fb8d1a34STakashi Iwai if (!bus) 5110fb8d1a34STakashi Iwai return; 5111fb8d1a34STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 5112e581f3dbSTakashi Iwai if (hda_codec_is_power_on(codec) && 5113e581f3dbSTakashi Iwai codec->patch_ops.reboot_notify) 5114fb8d1a34STakashi Iwai codec->patch_ops.reboot_notify(codec); 5115fb8d1a34STakashi Iwai } 5116fb8d1a34STakashi Iwai } 51178f217a22STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_bus_reboot_notify); 5118fb8d1a34STakashi Iwai 5119d5191e50STakashi Iwai /** 5120d5191e50STakashi Iwai * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode 51211da177e4SLinus Torvalds */ 51220ba21762STakashi Iwai int snd_hda_multi_out_dig_open(struct hda_codec *codec, 51230ba21762STakashi Iwai struct hda_multi_out *mout) 51241da177e4SLinus Torvalds { 512562932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 51265930ca41STakashi Iwai if (mout->dig_out_used == HDA_DIG_ANALOG_DUP) 51275930ca41STakashi Iwai /* already opened as analog dup; reset it once */ 51282f72853cSTakashi Iwai cleanup_dig_out_stream(codec, mout->dig_out_nid); 51291da177e4SLinus Torvalds mout->dig_out_used = HDA_DIG_EXCLUSIVE; 513062932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 51311da177e4SLinus Torvalds return 0; 51321da177e4SLinus Torvalds } 5133ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open); 51341da177e4SLinus Torvalds 5135d5191e50STakashi Iwai /** 5136d5191e50STakashi Iwai * snd_hda_multi_out_dig_prepare - prepare the digital out stream 5137d5191e50STakashi Iwai */ 51386b97eb45STakashi Iwai int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, 51396b97eb45STakashi Iwai struct hda_multi_out *mout, 51406b97eb45STakashi Iwai unsigned int stream_tag, 51416b97eb45STakashi Iwai unsigned int format, 51426b97eb45STakashi Iwai struct snd_pcm_substream *substream) 51436b97eb45STakashi Iwai { 51446b97eb45STakashi Iwai mutex_lock(&codec->spdif_mutex); 51456b97eb45STakashi Iwai setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); 51466b97eb45STakashi Iwai mutex_unlock(&codec->spdif_mutex); 51476b97eb45STakashi Iwai return 0; 51486b97eb45STakashi Iwai } 5149ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); 51506b97eb45STakashi Iwai 5151d5191e50STakashi Iwai /** 5152d5191e50STakashi Iwai * snd_hda_multi_out_dig_cleanup - clean-up the digital out stream 5153d5191e50STakashi Iwai */ 51549411e21cSTakashi Iwai int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, 51559411e21cSTakashi Iwai struct hda_multi_out *mout) 51569411e21cSTakashi Iwai { 51579411e21cSTakashi Iwai mutex_lock(&codec->spdif_mutex); 51589411e21cSTakashi Iwai cleanup_dig_out_stream(codec, mout->dig_out_nid); 51599411e21cSTakashi Iwai mutex_unlock(&codec->spdif_mutex); 51609411e21cSTakashi Iwai return 0; 51619411e21cSTakashi Iwai } 51629411e21cSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup); 51639411e21cSTakashi Iwai 5164d5191e50STakashi Iwai /** 5165d5191e50STakashi Iwai * snd_hda_multi_out_dig_close - release the digital out stream 51661da177e4SLinus Torvalds */ 51670ba21762STakashi Iwai int snd_hda_multi_out_dig_close(struct hda_codec *codec, 51680ba21762STakashi Iwai struct hda_multi_out *mout) 51691da177e4SLinus Torvalds { 517062932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 51711da177e4SLinus Torvalds mout->dig_out_used = 0; 517262932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 51731da177e4SLinus Torvalds return 0; 51741da177e4SLinus Torvalds } 5175ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close); 51761da177e4SLinus Torvalds 5177d5191e50STakashi Iwai /** 5178d5191e50STakashi Iwai * snd_hda_multi_out_analog_open - open analog outputs 5179d5191e50STakashi Iwai * 5180d5191e50STakashi Iwai * Open analog outputs and set up the hw-constraints. 5181d5191e50STakashi Iwai * If the digital outputs can be opened as slave, open the digital 5182d5191e50STakashi Iwai * outputs, too. 51831da177e4SLinus Torvalds */ 51840ba21762STakashi Iwai int snd_hda_multi_out_analog_open(struct hda_codec *codec, 51850ba21762STakashi Iwai struct hda_multi_out *mout, 51869a08160bSTakashi Iwai struct snd_pcm_substream *substream, 51879a08160bSTakashi Iwai struct hda_pcm_stream *hinfo) 51881da177e4SLinus Torvalds { 51899a08160bSTakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 51909a08160bSTakashi Iwai runtime->hw.channels_max = mout->max_channels; 51919a08160bSTakashi Iwai if (mout->dig_out_nid) { 51929a08160bSTakashi Iwai if (!mout->analog_rates) { 51939a08160bSTakashi Iwai mout->analog_rates = hinfo->rates; 51949a08160bSTakashi Iwai mout->analog_formats = hinfo->formats; 51959a08160bSTakashi Iwai mout->analog_maxbps = hinfo->maxbps; 51969a08160bSTakashi Iwai } else { 51979a08160bSTakashi Iwai runtime->hw.rates = mout->analog_rates; 51989a08160bSTakashi Iwai runtime->hw.formats = mout->analog_formats; 51999a08160bSTakashi Iwai hinfo->maxbps = mout->analog_maxbps; 52009a08160bSTakashi Iwai } 52019a08160bSTakashi Iwai if (!mout->spdif_rates) { 52029a08160bSTakashi Iwai snd_hda_query_supported_pcm(codec, mout->dig_out_nid, 52039a08160bSTakashi Iwai &mout->spdif_rates, 52049a08160bSTakashi Iwai &mout->spdif_formats, 52059a08160bSTakashi Iwai &mout->spdif_maxbps); 52069a08160bSTakashi Iwai } 52079a08160bSTakashi Iwai mutex_lock(&codec->spdif_mutex); 52089a08160bSTakashi Iwai if (mout->share_spdif) { 5209022b466fSTakashi Iwai if ((runtime->hw.rates & mout->spdif_rates) && 5210022b466fSTakashi Iwai (runtime->hw.formats & mout->spdif_formats)) { 52119a08160bSTakashi Iwai runtime->hw.rates &= mout->spdif_rates; 52129a08160bSTakashi Iwai runtime->hw.formats &= mout->spdif_formats; 52139a08160bSTakashi Iwai if (mout->spdif_maxbps < hinfo->maxbps) 52149a08160bSTakashi Iwai hinfo->maxbps = mout->spdif_maxbps; 5215022b466fSTakashi Iwai } else { 5216022b466fSTakashi Iwai mout->share_spdif = 0; 5217022b466fSTakashi Iwai /* FIXME: need notify? */ 5218022b466fSTakashi Iwai } 52199a08160bSTakashi Iwai } 52209a08160bSTakashi Iwai mutex_unlock(&codec->spdif_mutex); 5221eaa9985bSFrederik Deweerdt } 52221da177e4SLinus Torvalds return snd_pcm_hw_constraint_step(substream->runtime, 0, 52231da177e4SLinus Torvalds SNDRV_PCM_HW_PARAM_CHANNELS, 2); 52241da177e4SLinus Torvalds } 5225ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open); 52261da177e4SLinus Torvalds 5227d5191e50STakashi Iwai /** 5228d5191e50STakashi Iwai * snd_hda_multi_out_analog_prepare - Preapre the analog outputs. 5229d5191e50STakashi Iwai * 5230d5191e50STakashi Iwai * Set up the i/o for analog out. 5231d5191e50STakashi Iwai * When the digital out is available, copy the front out to digital out, too. 52321da177e4SLinus Torvalds */ 52330ba21762STakashi Iwai int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, 52340ba21762STakashi Iwai struct hda_multi_out *mout, 52351da177e4SLinus Torvalds unsigned int stream_tag, 52361da177e4SLinus Torvalds unsigned int format, 5237c8b6bf9bSTakashi Iwai struct snd_pcm_substream *substream) 52381da177e4SLinus Torvalds { 5239dda14410STakashi Iwai const hda_nid_t *nids = mout->dac_nids; 52401da177e4SLinus Torvalds int chs = substream->runtime->channels; 5241e3245cddSTakashi Iwai struct hda_spdif_out *spdif; 52421da177e4SLinus Torvalds int i; 52431da177e4SLinus Torvalds 524462932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 5245e3245cddSTakashi Iwai spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); 52469a08160bSTakashi Iwai if (mout->dig_out_nid && mout->share_spdif && 52479a08160bSTakashi Iwai mout->dig_out_used != HDA_DIG_EXCLUSIVE) { 52481da177e4SLinus Torvalds if (chs == 2 && 52490ba21762STakashi Iwai snd_hda_is_supported_format(codec, mout->dig_out_nid, 52500ba21762STakashi Iwai format) && 52517c935976SStephen Warren !(spdif->status & IEC958_AES0_NONAUDIO)) { 52521da177e4SLinus Torvalds mout->dig_out_used = HDA_DIG_ANALOG_DUP; 52536b97eb45STakashi Iwai setup_dig_out_stream(codec, mout->dig_out_nid, 52546b97eb45STakashi Iwai stream_tag, format); 52551da177e4SLinus Torvalds } else { 52561da177e4SLinus Torvalds mout->dig_out_used = 0; 52572f72853cSTakashi Iwai cleanup_dig_out_stream(codec, mout->dig_out_nid); 52581da177e4SLinus Torvalds } 52591da177e4SLinus Torvalds } 526062932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 52611da177e4SLinus Torvalds 52621da177e4SLinus Torvalds /* front */ 52630ba21762STakashi Iwai snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 52640ba21762STakashi Iwai 0, format); 5265d29240ceSTakashi Iwai if (!mout->no_share_stream && 5266d29240ceSTakashi Iwai mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]) 52671da177e4SLinus Torvalds /* headphone out will just decode front left/right (stereo) */ 52680ba21762STakashi Iwai snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 52690ba21762STakashi Iwai 0, format); 527082bc955fSTakashi Iwai /* extra outputs copied from front */ 5271a06dbfc2STakashi Iwai for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++) 5272a06dbfc2STakashi Iwai if (!mout->no_share_stream && mout->hp_out_nid[i]) 5273a06dbfc2STakashi Iwai snd_hda_codec_setup_stream(codec, 5274a06dbfc2STakashi Iwai mout->hp_out_nid[i], 5275a06dbfc2STakashi Iwai stream_tag, 0, format); 527682bc955fSTakashi Iwai for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) 5277d29240ceSTakashi Iwai if (!mout->no_share_stream && mout->extra_out_nid[i]) 527882bc955fSTakashi Iwai snd_hda_codec_setup_stream(codec, 527982bc955fSTakashi Iwai mout->extra_out_nid[i], 528082bc955fSTakashi Iwai stream_tag, 0, format); 528182bc955fSTakashi Iwai 52821da177e4SLinus Torvalds /* surrounds */ 52831da177e4SLinus Torvalds for (i = 1; i < mout->num_dacs; i++) { 52844b3acaf5STakashi Iwai if (chs >= (i + 1) * 2) /* independent out */ 52850ba21762STakashi Iwai snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 52860ba21762STakashi Iwai i * 2, format); 5287d29240ceSTakashi Iwai else if (!mout->no_share_stream) /* copy front */ 52880ba21762STakashi Iwai snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 52890ba21762STakashi Iwai 0, format); 52901da177e4SLinus Torvalds } 52911da177e4SLinus Torvalds return 0; 52921da177e4SLinus Torvalds } 5293ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); 52941da177e4SLinus Torvalds 5295d5191e50STakashi Iwai /** 5296d5191e50STakashi Iwai * snd_hda_multi_out_analog_cleanup - clean up the setting for analog out 52971da177e4SLinus Torvalds */ 52980ba21762STakashi Iwai int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, 52990ba21762STakashi Iwai struct hda_multi_out *mout) 53001da177e4SLinus Torvalds { 5301dda14410STakashi Iwai const hda_nid_t *nids = mout->dac_nids; 53021da177e4SLinus Torvalds int i; 53031da177e4SLinus Torvalds 53041da177e4SLinus Torvalds for (i = 0; i < mout->num_dacs; i++) 5305888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, nids[i]); 53061da177e4SLinus Torvalds if (mout->hp_nid) 5307888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, mout->hp_nid); 5308a06dbfc2STakashi Iwai for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++) 5309a06dbfc2STakashi Iwai if (mout->hp_out_nid[i]) 5310a06dbfc2STakashi Iwai snd_hda_codec_cleanup_stream(codec, 5311a06dbfc2STakashi Iwai mout->hp_out_nid[i]); 531282bc955fSTakashi Iwai for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) 531382bc955fSTakashi Iwai if (mout->extra_out_nid[i]) 5314888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, 5315888afa15STakashi Iwai mout->extra_out_nid[i]); 531662932df8SIngo Molnar mutex_lock(&codec->spdif_mutex); 53171da177e4SLinus Torvalds if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { 53182f72853cSTakashi Iwai cleanup_dig_out_stream(codec, mout->dig_out_nid); 53191da177e4SLinus Torvalds mout->dig_out_used = 0; 53201da177e4SLinus Torvalds } 532162932df8SIngo Molnar mutex_unlock(&codec->spdif_mutex); 53221da177e4SLinus Torvalds return 0; 53231da177e4SLinus Torvalds } 5324ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup); 53251da177e4SLinus Torvalds 53264740860bSTakashi Iwai /** 53274740860bSTakashi Iwai * snd_hda_get_default_vref - Get the default (mic) VREF pin bits 53284740860bSTakashi Iwai * 53294740860bSTakashi Iwai * Guess the suitable VREF pin bits to be set as the pin-control value. 53304740860bSTakashi Iwai * Note: the function doesn't set the AC_PINCTL_IN_EN bit. 53314740860bSTakashi Iwai */ 53324740860bSTakashi Iwai unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin) 53334740860bSTakashi Iwai { 53344740860bSTakashi Iwai unsigned int pincap; 53354740860bSTakashi Iwai unsigned int oldval; 53364740860bSTakashi Iwai oldval = snd_hda_codec_read(codec, pin, 0, 53374740860bSTakashi Iwai AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 53384740860bSTakashi Iwai pincap = snd_hda_query_pin_caps(codec, pin); 53394740860bSTakashi Iwai pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; 53404740860bSTakashi Iwai /* Exception: if the default pin setup is vref50, we give it priority */ 53414740860bSTakashi Iwai if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50) 53424740860bSTakashi Iwai return AC_PINCTL_VREF_80; 53434740860bSTakashi Iwai else if (pincap & AC_PINCAP_VREF_50) 53444740860bSTakashi Iwai return AC_PINCTL_VREF_50; 53454740860bSTakashi Iwai else if (pincap & AC_PINCAP_VREF_100) 53464740860bSTakashi Iwai return AC_PINCTL_VREF_100; 53474740860bSTakashi Iwai else if (pincap & AC_PINCAP_VREF_GRD) 53484740860bSTakashi Iwai return AC_PINCTL_VREF_GRD; 53494740860bSTakashi Iwai return AC_PINCTL_VREF_HIZ; 53504740860bSTakashi Iwai } 53514740860bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_default_vref); 53524740860bSTakashi Iwai 535362f3a2f7STakashi Iwai /* correct the pin ctl value for matching with the pin cap */ 535462f3a2f7STakashi Iwai unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec, 535562f3a2f7STakashi Iwai hda_nid_t pin, unsigned int val) 535662f3a2f7STakashi Iwai { 535762f3a2f7STakashi Iwai static unsigned int cap_lists[][2] = { 535862f3a2f7STakashi Iwai { AC_PINCTL_VREF_100, AC_PINCAP_VREF_100 }, 535962f3a2f7STakashi Iwai { AC_PINCTL_VREF_80, AC_PINCAP_VREF_80 }, 536062f3a2f7STakashi Iwai { AC_PINCTL_VREF_50, AC_PINCAP_VREF_50 }, 536162f3a2f7STakashi Iwai { AC_PINCTL_VREF_GRD, AC_PINCAP_VREF_GRD }, 536262f3a2f7STakashi Iwai }; 536362f3a2f7STakashi Iwai unsigned int cap; 536462f3a2f7STakashi Iwai 536562f3a2f7STakashi Iwai if (!val) 536662f3a2f7STakashi Iwai return 0; 536762f3a2f7STakashi Iwai cap = snd_hda_query_pin_caps(codec, pin); 536862f3a2f7STakashi Iwai if (!cap) 536962f3a2f7STakashi Iwai return val; /* don't know what to do... */ 537062f3a2f7STakashi Iwai 537162f3a2f7STakashi Iwai if (val & AC_PINCTL_OUT_EN) { 537262f3a2f7STakashi Iwai if (!(cap & AC_PINCAP_OUT)) 537362f3a2f7STakashi Iwai val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); 537462f3a2f7STakashi Iwai else if ((val & AC_PINCTL_HP_EN) && !(cap & AC_PINCAP_HP_DRV)) 537562f3a2f7STakashi Iwai val &= ~AC_PINCTL_HP_EN; 537662f3a2f7STakashi Iwai } 537762f3a2f7STakashi Iwai 537862f3a2f7STakashi Iwai if (val & AC_PINCTL_IN_EN) { 537962f3a2f7STakashi Iwai if (!(cap & AC_PINCAP_IN)) 538062f3a2f7STakashi Iwai val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN); 538162f3a2f7STakashi Iwai else { 538262f3a2f7STakashi Iwai unsigned int vcap, vref; 538362f3a2f7STakashi Iwai int i; 538462f3a2f7STakashi Iwai vcap = (cap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; 538562f3a2f7STakashi Iwai vref = val & AC_PINCTL_VREFEN; 538662f3a2f7STakashi Iwai for (i = 0; i < ARRAY_SIZE(cap_lists); i++) { 538762f3a2f7STakashi Iwai if (vref == cap_lists[i][0] && 538862f3a2f7STakashi Iwai !(vcap & cap_lists[i][1])) { 538962f3a2f7STakashi Iwai if (i == ARRAY_SIZE(cap_lists) - 1) 539062f3a2f7STakashi Iwai vref = AC_PINCTL_VREF_HIZ; 539162f3a2f7STakashi Iwai else 539262f3a2f7STakashi Iwai vref = cap_lists[i + 1][0]; 539362f3a2f7STakashi Iwai } 539462f3a2f7STakashi Iwai } 539562f3a2f7STakashi Iwai val &= ~AC_PINCTL_VREFEN; 539662f3a2f7STakashi Iwai val |= vref; 539762f3a2f7STakashi Iwai } 539862f3a2f7STakashi Iwai } 539962f3a2f7STakashi Iwai 540062f3a2f7STakashi Iwai return val; 540162f3a2f7STakashi Iwai } 540262f3a2f7STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_correct_pin_ctl); 540362f3a2f7STakashi Iwai 5404cdd03cedSTakashi Iwai int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, 5405cdd03cedSTakashi Iwai unsigned int val, bool cached) 5406cdd03cedSTakashi Iwai { 540762f3a2f7STakashi Iwai val = snd_hda_correct_pin_ctl(codec, pin, val); 5408d7fdc00aSTakashi Iwai snd_hda_codec_set_pin_target(codec, pin, val); 5409cdd03cedSTakashi Iwai if (cached) 5410cdd03cedSTakashi Iwai return snd_hda_codec_update_cache(codec, pin, 0, 5411cdd03cedSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, val); 5412cdd03cedSTakashi Iwai else 5413cdd03cedSTakashi Iwai return snd_hda_codec_write(codec, pin, 0, 5414cdd03cedSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, val); 5415cdd03cedSTakashi Iwai } 5416cdd03cedSTakashi Iwai EXPORT_SYMBOL_HDA(_snd_hda_set_pin_ctl); 5417cdd03cedSTakashi Iwai 5418990061c2STakashi Iwai /** 5419990061c2STakashi Iwai * snd_hda_add_imux_item - Add an item to input_mux 5420990061c2STakashi Iwai * 5421990061c2STakashi Iwai * When the same label is used already in the existing items, the number 5422990061c2STakashi Iwai * suffix is appended to the label. This label index number is stored 5423990061c2STakashi Iwai * to type_idx when non-NULL pointer is given. 5424990061c2STakashi Iwai */ 542510a20af7STakashi Iwai int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, 542610a20af7STakashi Iwai int index, int *type_idx) 542710a20af7STakashi Iwai { 542810a20af7STakashi Iwai int i, label_idx = 0; 542910a20af7STakashi Iwai if (imux->num_items >= HDA_MAX_NUM_INPUTS) { 543010a20af7STakashi Iwai snd_printd(KERN_ERR "hda_codec: Too many imux items!\n"); 543110a20af7STakashi Iwai return -EINVAL; 543210a20af7STakashi Iwai } 543310a20af7STakashi Iwai for (i = 0; i < imux->num_items; i++) { 543410a20af7STakashi Iwai if (!strncmp(label, imux->items[i].label, strlen(label))) 543510a20af7STakashi Iwai label_idx++; 543610a20af7STakashi Iwai } 543710a20af7STakashi Iwai if (type_idx) 543810a20af7STakashi Iwai *type_idx = label_idx; 543910a20af7STakashi Iwai if (label_idx > 0) 544010a20af7STakashi Iwai snprintf(imux->items[imux->num_items].label, 544110a20af7STakashi Iwai sizeof(imux->items[imux->num_items].label), 544210a20af7STakashi Iwai "%s %d", label, label_idx); 5443b5786e85STakashi Iwai else 544410a20af7STakashi Iwai strlcpy(imux->items[imux->num_items].label, label, 544510a20af7STakashi Iwai sizeof(imux->items[imux->num_items].label)); 544610a20af7STakashi Iwai imux->items[imux->num_items].index = index; 544710a20af7STakashi Iwai imux->num_items++; 544810a20af7STakashi Iwai return 0; 5449d7b1ae9dSTakashi Iwai } 545010a20af7STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_imux_item); 5451d7b1ae9dSTakashi Iwai 54524a471b7dSTakashi Iwai 54531da177e4SLinus Torvalds #ifdef CONFIG_PM 54541da177e4SLinus Torvalds /* 54551da177e4SLinus Torvalds * power management 54561da177e4SLinus Torvalds */ 54571da177e4SLinus Torvalds 54581da177e4SLinus Torvalds /** 54591da177e4SLinus Torvalds * snd_hda_suspend - suspend the codecs 54601da177e4SLinus Torvalds * @bus: the HDA bus 54611da177e4SLinus Torvalds * 54621da177e4SLinus Torvalds * Returns 0 if successful. 54631da177e4SLinus Torvalds */ 54648dd78330STakashi Iwai int snd_hda_suspend(struct hda_bus *bus) 54651da177e4SLinus Torvalds { 54660ba21762STakashi Iwai struct hda_codec *codec; 54671da177e4SLinus Torvalds 54680ba21762STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 546926a6cb6cSDavid Henningsson cancel_delayed_work_sync(&codec->jackpoll_work); 5470e581f3dbSTakashi Iwai if (hda_codec_is_power_on(codec)) 5471d17344b3SDylan Reid hda_call_codec_suspend(codec, false); 54721da177e4SLinus Torvalds } 54731da177e4SLinus Torvalds return 0; 54741da177e4SLinus Torvalds } 5475ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_suspend); 54761da177e4SLinus Torvalds 54771da177e4SLinus Torvalds /** 54781da177e4SLinus Torvalds * snd_hda_resume - resume the codecs 54791da177e4SLinus Torvalds * @bus: the HDA bus 54801da177e4SLinus Torvalds * 54811da177e4SLinus Torvalds * Returns 0 if successful. 54821da177e4SLinus Torvalds */ 54831da177e4SLinus Torvalds int snd_hda_resume(struct hda_bus *bus) 54841da177e4SLinus Torvalds { 54850ba21762STakashi Iwai struct hda_codec *codec; 54861da177e4SLinus Torvalds 54870ba21762STakashi Iwai list_for_each_entry(codec, &bus->codec_list, list) { 5488cb53c626STakashi Iwai hda_call_codec_resume(codec); 54891da177e4SLinus Torvalds } 54901da177e4SLinus Torvalds return 0; 54911da177e4SLinus Torvalds } 5492ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_resume); 54931289e9e8STakashi Iwai #endif /* CONFIG_PM */ 5494b2e18597STakashi Iwai 5495b2e18597STakashi Iwai /* 5496b2e18597STakashi Iwai * generic arrays 5497b2e18597STakashi Iwai */ 5498b2e18597STakashi Iwai 5499d5191e50STakashi Iwai /** 5500d5191e50STakashi Iwai * snd_array_new - get a new element from the given array 5501d5191e50STakashi Iwai * @array: the array object 5502d5191e50STakashi Iwai * 5503d5191e50STakashi Iwai * Get a new element from the given array. If it exceeds the 5504d5191e50STakashi Iwai * pre-allocated array size, re-allocate the array. 5505d5191e50STakashi Iwai * 5506d5191e50STakashi Iwai * Returns NULL if allocation failed. 5507b2e18597STakashi Iwai */ 5508b2e18597STakashi Iwai void *snd_array_new(struct snd_array *array) 5509b2e18597STakashi Iwai { 551012f17717STakashi Iwai if (snd_BUG_ON(!array->elem_size)) 551112f17717STakashi Iwai return NULL; 5512b2e18597STakashi Iwai if (array->used >= array->alloced) { 5513b2e18597STakashi Iwai int num = array->alloced + array->alloc_align; 55143101ba03STakashi Iwai int size = (num + 1) * array->elem_size; 551500ef9610STakashi Iwai int oldsize = array->alloced * array->elem_size; 5516b910d9aeSTakashi Iwai void *nlist; 5517b910d9aeSTakashi Iwai if (snd_BUG_ON(num >= 4096)) 5518b910d9aeSTakashi Iwai return NULL; 55193101ba03STakashi Iwai nlist = krealloc(array->list, size, GFP_KERNEL); 5520b2e18597STakashi Iwai if (!nlist) 5521b2e18597STakashi Iwai return NULL; 552200ef9610STakashi Iwai memset(nlist + oldsize, 0, size - oldsize); 5523b2e18597STakashi Iwai array->list = nlist; 5524b2e18597STakashi Iwai array->alloced = num; 5525b2e18597STakashi Iwai } 5526f43aa025STakashi Iwai return snd_array_elem(array, array->used++); 5527b2e18597STakashi Iwai } 5528ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_array_new); 5529b2e18597STakashi Iwai 5530d5191e50STakashi Iwai /** 5531d5191e50STakashi Iwai * snd_array_free - free the given array elements 5532d5191e50STakashi Iwai * @array: the array object 5533d5191e50STakashi Iwai */ 5534b2e18597STakashi Iwai void snd_array_free(struct snd_array *array) 5535b2e18597STakashi Iwai { 5536b2e18597STakashi Iwai kfree(array->list); 5537b2e18597STakashi Iwai array->used = 0; 5538b2e18597STakashi Iwai array->alloced = 0; 5539b2e18597STakashi Iwai array->list = NULL; 5540b2e18597STakashi Iwai } 5541ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_array_free); 5542b2022266STakashi Iwai 5543d5191e50STakashi Iwai /** 5544d5191e50STakashi Iwai * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer 5545d5191e50STakashi Iwai * @pcm: PCM caps bits 5546d5191e50STakashi Iwai * @buf: the string buffer to write 5547d5191e50STakashi Iwai * @buflen: the max buffer length 5548d5191e50STakashi Iwai * 5549d5191e50STakashi Iwai * used by hda_proc.c and hda_eld.c 5550d5191e50STakashi Iwai */ 5551b2022266STakashi Iwai void snd_print_pcm_bits(int pcm, char *buf, int buflen) 5552b2022266STakashi Iwai { 5553b2022266STakashi Iwai static unsigned int bits[] = { 8, 16, 20, 24, 32 }; 5554b2022266STakashi Iwai int i, j; 5555b2022266STakashi Iwai 5556b2022266STakashi Iwai for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) 5557b2022266STakashi Iwai if (pcm & (AC_SUPPCM_BITS_8 << i)) 5558b2022266STakashi Iwai j += snprintf(buf + j, buflen - j, " %d", bits[i]); 5559b2022266STakashi Iwai 5560b2022266STakashi Iwai buf[j] = '\0'; /* necessary when j == 0 */ 5561b2022266STakashi Iwai } 5562ff7a3267STakashi Iwai EXPORT_SYMBOL_HDA(snd_print_pcm_bits); 55631289e9e8STakashi Iwai 55641289e9e8STakashi Iwai MODULE_DESCRIPTION("HDA codec core"); 55651289e9e8STakashi Iwai MODULE_LICENSE("GPL"); 5566