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