xref: /linux/sound/pci/ice1712/ice1712.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *   ALSA driver for ICEnsemble ICE1712 (Envy24)
41da177e4SLinus Torvalds  *
5c1017a4cSJaroslav Kysela  *	Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz>
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds /*
91da177e4SLinus Torvalds   NOTES:
101da177e4SLinus Torvalds   - spdif nonaudio consumer mode does not work (at least with my
111da177e4SLinus Torvalds     Sony STR-DB830)
121da177e4SLinus Torvalds */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds /*
151da177e4SLinus Torvalds  * Changes:
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *  2002.09.09	Takashi Iwai <tiwai@suse.de>
181da177e4SLinus Torvalds  *	split the code to several files.  each low-level routine
191da177e4SLinus Torvalds  *	is stored in the local file and called from registration
201da177e4SLinus Torvalds  *	function from card_info struct.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *  2002.11.26	James Stafford <jstafford@ampltd.com>
231da177e4SLinus Torvalds  *	Added support for VT1724 (Envy24HT)
241da177e4SLinus Torvalds  *	I have left out support for 176.4 and 192 KHz for the moment.
251da177e4SLinus Torvalds  *  I also haven't done anything with the internal S/PDIF transmitter or the MPU-401
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  *  2003.02.20  Taksahi Iwai <tiwai@suse.de>
281da177e4SLinus Torvalds  *	Split vt1724 part to an independent driver.
291da177e4SLinus Torvalds  *	The GPIO is accessed through the callback functions now.
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  * 2004.03.31 Doug McLain <nostar@comcast.net>
321da177e4SLinus Torvalds  *    Added support for Event Electronics EZ8 card to hoontech.c.
331da177e4SLinus Torvalds  */
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #include <linux/delay.h>
371da177e4SLinus Torvalds #include <linux/interrupt.h>
381da177e4SLinus Torvalds #include <linux/init.h>
391da177e4SLinus Torvalds #include <linux/pci.h>
409d2f928dSTobias Klauser #include <linux/dma-mapping.h>
411da177e4SLinus Torvalds #include <linux/slab.h>
4265a77217SPaul Gortmaker #include <linux/module.h>
4362932df8SIngo Molnar #include <linux/mutex.h>
44910638aeSMatthias Gehre 
451da177e4SLinus Torvalds #include <sound/core.h>
461da177e4SLinus Torvalds #include <sound/cs8427.h>
471da177e4SLinus Torvalds #include <sound/info.h>
481da177e4SLinus Torvalds #include <sound/initval.h>
49680ef792STakashi Iwai #include <sound/tlv.h>
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds #include <sound/asoundef.h>
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds #include "ice1712.h"
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds /* lowlevel routines */
561da177e4SLinus Torvalds #include "delta.h"
571da177e4SLinus Torvalds #include "ews.h"
581da177e4SLinus Torvalds #include "hoontech.h"
591da177e4SLinus Torvalds 
60c1017a4cSJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
611da177e4SLinus Torvalds MODULE_DESCRIPTION("ICEnsemble ICE1712 (Envy24)");
621da177e4SLinus Torvalds MODULE_LICENSE("GPL");
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
651da177e4SLinus Torvalds static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
66a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
671da177e4SLinus Torvalds static char *model[SNDRV_CARDS];
68a67ff6a5SRusty Russell static bool omni[SNDRV_CARDS];				/* Delta44 & 66 Omni I/O support */
697c9d440eSJoe Perches static int cs8427_timeout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 500}; /* CS8427 S/PDIF transceiver reset timeout value in msec */
7001a00e5eSAlan Horstmann static int dxr_enable[SNDRV_CARDS];			/* DXR enable for DMX6FIRE */
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds module_param_array(index, int, NULL, 0444);
731da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard.");
741da177e4SLinus Torvalds module_param_array(id, charp, NULL, 0444);
751da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for ICE1712 soundcard.");
761da177e4SLinus Torvalds module_param_array(enable, bool, NULL, 0444);
771da177e4SLinus Torvalds MODULE_PARM_DESC(enable, "Enable ICE1712 soundcard.");
781da177e4SLinus Torvalds module_param_array(omni, bool, NULL, 0444);
791da177e4SLinus Torvalds MODULE_PARM_DESC(omni, "Enable Midiman M-Audio Delta Omni I/O support.");
801da177e4SLinus Torvalds module_param_array(cs8427_timeout, int, NULL, 0444);
811da177e4SLinus Torvalds MODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec resolution.");
821da177e4SLinus Torvalds module_param_array(model, charp, NULL, 0444);
831da177e4SLinus Torvalds MODULE_PARM_DESC(model, "Use the given board model.");
84531af462SAlan Horstmann module_param_array(dxr_enable, int, NULL, 0444);
8501a00e5eSAlan Horstmann MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 
889baa3c34SBenoit Taine static const struct pci_device_id snd_ice1712_ids[] = {
8928d27aaeSJoe Perches 	{ PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 },   /* ICE1712 */
901da177e4SLinus Torvalds 	{ 0, }
911da177e4SLinus Torvalds };
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, snd_ice1712_ids);
941da177e4SLinus Torvalds 
956ca308d4STakashi Iwai static int snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice);
966ca308d4STakashi Iwai static int snd_ice1712_build_controls(struct snd_ice1712 *ice);
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds static int PRO_RATE_LOCKED;
991da177e4SLinus Torvalds static int PRO_RATE_RESET = 1;
1001da177e4SLinus Torvalds static unsigned int PRO_RATE_DEFAULT = 44100;
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds /*
1031da177e4SLinus Torvalds  *  Basic I/O
1041da177e4SLinus Torvalds  */
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds /* check whether the clock mode is spdif-in */
is_spdif_master(struct snd_ice1712 * ice)1076ca308d4STakashi Iwai static inline int is_spdif_master(struct snd_ice1712 *ice)
1081da177e4SLinus Torvalds {
1091da177e4SLinus Torvalds 	return (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER) ? 1 : 0;
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds 
is_pro_rate_locked(struct snd_ice1712 * ice)1126ca308d4STakashi Iwai static inline int is_pro_rate_locked(struct snd_ice1712 *ice)
1131da177e4SLinus Torvalds {
1141da177e4SLinus Torvalds 	return is_spdif_master(ice) || PRO_RATE_LOCKED;
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds 
snd_ice1712_ds_write(struct snd_ice1712 * ice,u8 channel,u8 addr,u32 data)1176ca308d4STakashi Iwai static inline void snd_ice1712_ds_write(struct snd_ice1712 *ice, u8 channel, u8 addr, u32 data)
1181da177e4SLinus Torvalds {
1191da177e4SLinus Torvalds 	outb((channel << 4) | addr, ICEDS(ice, INDEX));
1201da177e4SLinus Torvalds 	outl(data, ICEDS(ice, DATA));
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
snd_ice1712_ds_read(struct snd_ice1712 * ice,u8 channel,u8 addr)1236ca308d4STakashi Iwai static inline u32 snd_ice1712_ds_read(struct snd_ice1712 *ice, u8 channel, u8 addr)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	outb((channel << 4) | addr, ICEDS(ice, INDEX));
1261da177e4SLinus Torvalds 	return inl(ICEDS(ice, DATA));
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds 
snd_ice1712_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short val)1296ca308d4STakashi Iwai static void snd_ice1712_ac97_write(struct snd_ac97 *ac97,
1301da177e4SLinus Torvalds 				   unsigned short reg,
1311da177e4SLinus Torvalds 				   unsigned short val)
1321da177e4SLinus Torvalds {
1336ca308d4STakashi Iwai 	struct snd_ice1712 *ice = ac97->private_data;
1341da177e4SLinus Torvalds 	int tm;
1351da177e4SLinus Torvalds 	unsigned char old_cmd = 0;
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 	for (tm = 0; tm < 0x10000; tm++) {
1381da177e4SLinus Torvalds 		old_cmd = inb(ICEREG(ice, AC97_CMD));
1391da177e4SLinus Torvalds 		if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ))
1401da177e4SLinus Torvalds 			continue;
1411da177e4SLinus Torvalds 		if (!(old_cmd & ICE1712_AC97_READY))
1421da177e4SLinus Torvalds 			continue;
1431da177e4SLinus Torvalds 		break;
1441da177e4SLinus Torvalds 	}
1451da177e4SLinus Torvalds 	outb(reg, ICEREG(ice, AC97_INDEX));
1461da177e4SLinus Torvalds 	outw(val, ICEREG(ice, AC97_DATA));
1471da177e4SLinus Torvalds 	old_cmd &= ~(ICE1712_AC97_PBK_VSR | ICE1712_AC97_CAP_VSR);
1481da177e4SLinus Torvalds 	outb(old_cmd | ICE1712_AC97_WRITE, ICEREG(ice, AC97_CMD));
1491da177e4SLinus Torvalds 	for (tm = 0; tm < 0x10000; tm++)
1501da177e4SLinus Torvalds 		if ((inb(ICEREG(ice, AC97_CMD)) & ICE1712_AC97_WRITE) == 0)
1511da177e4SLinus Torvalds 			break;
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds 
snd_ice1712_ac97_read(struct snd_ac97 * ac97,unsigned short reg)1546ca308d4STakashi Iwai static unsigned short snd_ice1712_ac97_read(struct snd_ac97 *ac97,
1551da177e4SLinus Torvalds 					    unsigned short reg)
1561da177e4SLinus Torvalds {
1576ca308d4STakashi Iwai 	struct snd_ice1712 *ice = ac97->private_data;
1581da177e4SLinus Torvalds 	int tm;
1591da177e4SLinus Torvalds 	unsigned char old_cmd = 0;
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	for (tm = 0; tm < 0x10000; tm++) {
1621da177e4SLinus Torvalds 		old_cmd = inb(ICEREG(ice, AC97_CMD));
1631da177e4SLinus Torvalds 		if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ))
1641da177e4SLinus Torvalds 			continue;
1651da177e4SLinus Torvalds 		if (!(old_cmd & ICE1712_AC97_READY))
1661da177e4SLinus Torvalds 			continue;
1671da177e4SLinus Torvalds 		break;
1681da177e4SLinus Torvalds 	}
1691da177e4SLinus Torvalds 	outb(reg, ICEREG(ice, AC97_INDEX));
1701da177e4SLinus Torvalds 	outb(old_cmd | ICE1712_AC97_READ, ICEREG(ice, AC97_CMD));
1711da177e4SLinus Torvalds 	for (tm = 0; tm < 0x10000; tm++)
1721da177e4SLinus Torvalds 		if ((inb(ICEREG(ice, AC97_CMD)) & ICE1712_AC97_READ) == 0)
1731da177e4SLinus Torvalds 			break;
1741da177e4SLinus Torvalds 	if (tm >= 0x10000)		/* timeout */
1751da177e4SLinus Torvalds 		return ~0;
1761da177e4SLinus Torvalds 	return inw(ICEREG(ice, AC97_DATA));
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds /*
1801da177e4SLinus Torvalds  * pro ac97 section
1811da177e4SLinus Torvalds  */
1821da177e4SLinus Torvalds 
snd_ice1712_pro_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short val)1836ca308d4STakashi Iwai static void snd_ice1712_pro_ac97_write(struct snd_ac97 *ac97,
1841da177e4SLinus Torvalds 				       unsigned short reg,
1851da177e4SLinus Torvalds 				       unsigned short val)
1861da177e4SLinus Torvalds {
1876ca308d4STakashi Iwai 	struct snd_ice1712 *ice = ac97->private_data;
1881da177e4SLinus Torvalds 	int tm;
1891da177e4SLinus Torvalds 	unsigned char old_cmd = 0;
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds 	for (tm = 0; tm < 0x10000; tm++) {
1921da177e4SLinus Torvalds 		old_cmd = inb(ICEMT(ice, AC97_CMD));
1931da177e4SLinus Torvalds 		if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ))
1941da177e4SLinus Torvalds 			continue;
1951da177e4SLinus Torvalds 		if (!(old_cmd & ICE1712_AC97_READY))
1961da177e4SLinus Torvalds 			continue;
1971da177e4SLinus Torvalds 		break;
1981da177e4SLinus Torvalds 	}
1991da177e4SLinus Torvalds 	outb(reg, ICEMT(ice, AC97_INDEX));
2001da177e4SLinus Torvalds 	outw(val, ICEMT(ice, AC97_DATA));
2011da177e4SLinus Torvalds 	old_cmd &= ~(ICE1712_AC97_PBK_VSR | ICE1712_AC97_CAP_VSR);
2021da177e4SLinus Torvalds 	outb(old_cmd | ICE1712_AC97_WRITE, ICEMT(ice, AC97_CMD));
2031da177e4SLinus Torvalds 	for (tm = 0; tm < 0x10000; tm++)
2041da177e4SLinus Torvalds 		if ((inb(ICEMT(ice, AC97_CMD)) & ICE1712_AC97_WRITE) == 0)
2051da177e4SLinus Torvalds 			break;
2061da177e4SLinus Torvalds }
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 
snd_ice1712_pro_ac97_read(struct snd_ac97 * ac97,unsigned short reg)2096ca308d4STakashi Iwai static unsigned short snd_ice1712_pro_ac97_read(struct snd_ac97 *ac97,
2101da177e4SLinus Torvalds 						unsigned short reg)
2111da177e4SLinus Torvalds {
2126ca308d4STakashi Iwai 	struct snd_ice1712 *ice = ac97->private_data;
2131da177e4SLinus Torvalds 	int tm;
2141da177e4SLinus Torvalds 	unsigned char old_cmd = 0;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 	for (tm = 0; tm < 0x10000; tm++) {
2171da177e4SLinus Torvalds 		old_cmd = inb(ICEMT(ice, AC97_CMD));
2181da177e4SLinus Torvalds 		if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ))
2191da177e4SLinus Torvalds 			continue;
2201da177e4SLinus Torvalds 		if (!(old_cmd & ICE1712_AC97_READY))
2211da177e4SLinus Torvalds 			continue;
2221da177e4SLinus Torvalds 		break;
2231da177e4SLinus Torvalds 	}
2241da177e4SLinus Torvalds 	outb(reg, ICEMT(ice, AC97_INDEX));
2251da177e4SLinus Torvalds 	outb(old_cmd | ICE1712_AC97_READ, ICEMT(ice, AC97_CMD));
2261da177e4SLinus Torvalds 	for (tm = 0; tm < 0x10000; tm++)
2271da177e4SLinus Torvalds 		if ((inb(ICEMT(ice, AC97_CMD)) & ICE1712_AC97_READ) == 0)
2281da177e4SLinus Torvalds 			break;
2291da177e4SLinus Torvalds 	if (tm >= 0x10000)		/* timeout */
2301da177e4SLinus Torvalds 		return ~0;
2311da177e4SLinus Torvalds 	return inw(ICEMT(ice, AC97_DATA));
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds /*
2351da177e4SLinus Torvalds  * consumer ac97 digital mix
2361da177e4SLinus Torvalds  */
237a5ce8890STakashi Iwai #define snd_ice1712_digmix_route_ac97_info	snd_ctl_boolean_mono_info
2381da177e4SLinus Torvalds 
snd_ice1712_digmix_route_ac97_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2396ca308d4STakashi Iwai static int snd_ice1712_digmix_route_ac97_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2401da177e4SLinus Torvalds {
2416ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_ROUTECTRL)) & ICE1712_ROUTE_AC97 ? 1 : 0;
2441da177e4SLinus Torvalds 	return 0;
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds 
snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2476ca308d4STakashi Iwai static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2481da177e4SLinus Torvalds {
2496ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
2501da177e4SLinus Torvalds 	unsigned char val, nval;
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
2531da177e4SLinus Torvalds 	val = inb(ICEMT(ice, MONITOR_ROUTECTRL));
2541da177e4SLinus Torvalds 	nval = val & ~ICE1712_ROUTE_AC97;
2553d8cb466SAlexander Beregalov 	if (ucontrol->value.integer.value[0])
2563d8cb466SAlexander Beregalov 		nval |= ICE1712_ROUTE_AC97;
2571da177e4SLinus Torvalds 	outb(nval, ICEMT(ice, MONITOR_ROUTECTRL));
2581da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
2591da177e4SLinus Torvalds 	return val != nval;
2601da177e4SLinus Torvalds }
2611da177e4SLinus Torvalds 
262f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 = {
2631da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2641da177e4SLinus Torvalds 	.name = "Digital Mixer To AC97",
2651da177e4SLinus Torvalds 	.info = snd_ice1712_digmix_route_ac97_info,
2661da177e4SLinus Torvalds 	.get = snd_ice1712_digmix_route_ac97_get,
2671da177e4SLinus Torvalds 	.put = snd_ice1712_digmix_route_ac97_put,
2681da177e4SLinus Torvalds };
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds /*
2721da177e4SLinus Torvalds  * gpio operations
2731da177e4SLinus Torvalds  */
snd_ice1712_set_gpio_dir(struct snd_ice1712 * ice,unsigned int data)2746ca308d4STakashi Iwai static void snd_ice1712_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data)
2751da177e4SLinus Torvalds {
2761da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, data);
2771da177e4SLinus Torvalds 	inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds 
snd_ice1712_get_gpio_dir(struct snd_ice1712 * ice)28049470306SPavel Hofman static unsigned int snd_ice1712_get_gpio_dir(struct snd_ice1712 *ice)
28149470306SPavel Hofman {
28249470306SPavel Hofman 	return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION);
28349470306SPavel Hofman }
28449470306SPavel Hofman 
snd_ice1712_get_gpio_mask(struct snd_ice1712 * ice)28549470306SPavel Hofman static unsigned int snd_ice1712_get_gpio_mask(struct snd_ice1712 *ice)
28649470306SPavel Hofman {
28749470306SPavel Hofman 	return snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK);
28849470306SPavel Hofman }
28949470306SPavel Hofman 
snd_ice1712_set_gpio_mask(struct snd_ice1712 * ice,unsigned int data)2906ca308d4STakashi Iwai static void snd_ice1712_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, data);
2931da177e4SLinus Torvalds 	inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds 
snd_ice1712_get_gpio_data(struct snd_ice1712 * ice)2966ca308d4STakashi Iwai static unsigned int snd_ice1712_get_gpio_data(struct snd_ice1712 *ice)
2971da177e4SLinus Torvalds {
2981da177e4SLinus Torvalds 	return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds 
snd_ice1712_set_gpio_data(struct snd_ice1712 * ice,unsigned int val)3016ca308d4STakashi Iwai static void snd_ice1712_set_gpio_data(struct snd_ice1712 *ice, unsigned int val)
3021da177e4SLinus Torvalds {
3031da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, val);
3041da177e4SLinus Torvalds 	inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
3051da177e4SLinus Torvalds }
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds /*
3081da177e4SLinus Torvalds  *
3091da177e4SLinus Torvalds  * CS8427 interface
3101da177e4SLinus Torvalds  *
3111da177e4SLinus Torvalds  */
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds /*
3141da177e4SLinus Torvalds  * change the input clock selection
3151da177e4SLinus Torvalds  * spdif_clock = 1 - IEC958 input, 0 - Envy24
3161da177e4SLinus Torvalds  */
snd_ice1712_cs8427_set_input_clock(struct snd_ice1712 * ice,int spdif_clock)3176ca308d4STakashi Iwai static int snd_ice1712_cs8427_set_input_clock(struct snd_ice1712 *ice, int spdif_clock)
3181da177e4SLinus Torvalds {
3191da177e4SLinus Torvalds 	unsigned char reg[2] = { 0x80 | 4, 0 };   /* CS8427 auto increment | register number 4 + data */
3201da177e4SLinus Torvalds 	unsigned char val, nval;
3211da177e4SLinus Torvalds 	int res = 0;
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 	snd_i2c_lock(ice->i2c);
3241da177e4SLinus Torvalds 	if (snd_i2c_sendbytes(ice->cs8427, reg, 1) != 1) {
3251da177e4SLinus Torvalds 		snd_i2c_unlock(ice->i2c);
3261da177e4SLinus Torvalds 		return -EIO;
3271da177e4SLinus Torvalds 	}
3281da177e4SLinus Torvalds 	if (snd_i2c_readbytes(ice->cs8427, &val, 1) != 1) {
3291da177e4SLinus Torvalds 		snd_i2c_unlock(ice->i2c);
3301da177e4SLinus Torvalds 		return -EIO;
3311da177e4SLinus Torvalds 	}
3321da177e4SLinus Torvalds 	nval = val & 0xf0;
3331da177e4SLinus Torvalds 	if (spdif_clock)
3341da177e4SLinus Torvalds 		nval |= 0x01;
3351da177e4SLinus Torvalds 	else
3361da177e4SLinus Torvalds 		nval |= 0x04;
3371da177e4SLinus Torvalds 	if (val != nval) {
3381da177e4SLinus Torvalds 		reg[1] = nval;
3391da177e4SLinus Torvalds 		if (snd_i2c_sendbytes(ice->cs8427, reg, 2) != 2) {
3401da177e4SLinus Torvalds 			res = -EIO;
3411da177e4SLinus Torvalds 		} else {
3421da177e4SLinus Torvalds 			res++;
3431da177e4SLinus Torvalds 		}
3441da177e4SLinus Torvalds 	}
3451da177e4SLinus Torvalds 	snd_i2c_unlock(ice->i2c);
3461da177e4SLinus Torvalds 	return res;
3471da177e4SLinus Torvalds }
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds /*
3501da177e4SLinus Torvalds  * spdif callbacks
3511da177e4SLinus Torvalds  */
open_cs8427(struct snd_ice1712 * ice,struct snd_pcm_substream * substream)3526ca308d4STakashi Iwai static void open_cs8427(struct snd_ice1712 *ice, struct snd_pcm_substream *substream)
3531da177e4SLinus Torvalds {
3541da177e4SLinus Torvalds 	snd_cs8427_iec958_active(ice->cs8427, 1);
3551da177e4SLinus Torvalds }
3561da177e4SLinus Torvalds 
close_cs8427(struct snd_ice1712 * ice,struct snd_pcm_substream * substream)3576ca308d4STakashi Iwai static void close_cs8427(struct snd_ice1712 *ice, struct snd_pcm_substream *substream)
3581da177e4SLinus Torvalds {
3591da177e4SLinus Torvalds 	snd_cs8427_iec958_active(ice->cs8427, 0);
3601da177e4SLinus Torvalds }
3611da177e4SLinus Torvalds 
setup_cs8427(struct snd_ice1712 * ice,int rate)3626ca308d4STakashi Iwai static void setup_cs8427(struct snd_ice1712 *ice, int rate)
3631da177e4SLinus Torvalds {
3641da177e4SLinus Torvalds 	snd_cs8427_iec958_pcm(ice->cs8427, rate);
3651da177e4SLinus Torvalds }
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds /*
3681da177e4SLinus Torvalds  * create and initialize callbacks for cs8427 interface
3691da177e4SLinus Torvalds  */
snd_ice1712_init_cs8427(struct snd_ice1712 * ice,int addr)370e23e7a14SBill Pemberton int snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr)
3711da177e4SLinus Torvalds {
3721da177e4SLinus Torvalds 	int err;
3731da177e4SLinus Torvalds 
3743d8cb466SAlexander Beregalov 	err = snd_cs8427_create(ice->i2c, addr,
3753d8cb466SAlexander Beregalov 		(ice->cs8427_timeout * HZ) / 1000, &ice->cs8427);
3763d8cb466SAlexander Beregalov 	if (err < 0) {
3776dfb5affSTakashi Iwai 		dev_err(ice->card->dev, "CS8427 initialization failed\n");
3781da177e4SLinus Torvalds 		return err;
3791da177e4SLinus Torvalds 	}
3801da177e4SLinus Torvalds 	ice->spdif.ops.open = open_cs8427;
3811da177e4SLinus Torvalds 	ice->spdif.ops.close = close_cs8427;
3821da177e4SLinus Torvalds 	ice->spdif.ops.setup_rate = setup_cs8427;
3831da177e4SLinus Torvalds 	return 0;
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds 
snd_ice1712_set_input_clock_source(struct snd_ice1712 * ice,int spdif_is_master)386e957ebf1SJaroslav Kysela static void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdif_is_master)
387e957ebf1SJaroslav Kysela {
388e957ebf1SJaroslav Kysela 	/* change CS8427 clock source too */
389e957ebf1SJaroslav Kysela 	if (ice->cs8427)
390e957ebf1SJaroslav Kysela 		snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master);
391e957ebf1SJaroslav Kysela 	/* notify ak4524 chip as well */
392e957ebf1SJaroslav Kysela 	if (spdif_is_master) {
393e957ebf1SJaroslav Kysela 		unsigned int i;
394e957ebf1SJaroslav Kysela 		for (i = 0; i < ice->akm_codecs; i++) {
395e957ebf1SJaroslav Kysela 			if (ice->akm[i].ops.set_rate_val)
396e957ebf1SJaroslav Kysela 				ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
397e957ebf1SJaroslav Kysela 		}
398e957ebf1SJaroslav Kysela 	}
399e957ebf1SJaroslav Kysela }
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds /*
4021da177e4SLinus Torvalds  *  Interrupt handler
4031da177e4SLinus Torvalds  */
4041da177e4SLinus Torvalds 
snd_ice1712_interrupt(int irq,void * dev_id)4057d12e780SDavid Howells static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id)
4061da177e4SLinus Torvalds {
4076ca308d4STakashi Iwai 	struct snd_ice1712 *ice = dev_id;
4081da177e4SLinus Torvalds 	unsigned char status;
4091da177e4SLinus Torvalds 	int handled = 0;
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	while (1) {
4121da177e4SLinus Torvalds 		status = inb(ICEREG(ice, IRQSTAT));
4131da177e4SLinus Torvalds 		if (status == 0)
4141da177e4SLinus Torvalds 			break;
4151da177e4SLinus Torvalds 		handled = 1;
4161da177e4SLinus Torvalds 		if (status & ICE1712_IRQ_MPU1) {
4171da177e4SLinus Torvalds 			if (ice->rmidi[0])
4187d12e780SDavid Howells 				snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data);
4191da177e4SLinus Torvalds 			outb(ICE1712_IRQ_MPU1, ICEREG(ice, IRQSTAT));
4201da177e4SLinus Torvalds 			status &= ~ICE1712_IRQ_MPU1;
4211da177e4SLinus Torvalds 		}
4221da177e4SLinus Torvalds 		if (status & ICE1712_IRQ_TIMER)
4231da177e4SLinus Torvalds 			outb(ICE1712_IRQ_TIMER, ICEREG(ice, IRQSTAT));
4241da177e4SLinus Torvalds 		if (status & ICE1712_IRQ_MPU2) {
4251da177e4SLinus Torvalds 			if (ice->rmidi[1])
4267d12e780SDavid Howells 				snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data);
4271da177e4SLinus Torvalds 			outb(ICE1712_IRQ_MPU2, ICEREG(ice, IRQSTAT));
4281da177e4SLinus Torvalds 			status &= ~ICE1712_IRQ_MPU2;
4291da177e4SLinus Torvalds 		}
4301da177e4SLinus Torvalds 		if (status & ICE1712_IRQ_PROPCM) {
4311da177e4SLinus Torvalds 			unsigned char mtstat = inb(ICEMT(ice, IRQ));
4321da177e4SLinus Torvalds 			if (mtstat & ICE1712_MULTI_PBKSTATUS) {
4331da177e4SLinus Torvalds 				if (ice->playback_pro_substream)
4341da177e4SLinus Torvalds 					snd_pcm_period_elapsed(ice->playback_pro_substream);
4351da177e4SLinus Torvalds 				outb(ICE1712_MULTI_PBKSTATUS, ICEMT(ice, IRQ));
4361da177e4SLinus Torvalds 			}
4371da177e4SLinus Torvalds 			if (mtstat & ICE1712_MULTI_CAPSTATUS) {
4381da177e4SLinus Torvalds 				if (ice->capture_pro_substream)
4391da177e4SLinus Torvalds 					snd_pcm_period_elapsed(ice->capture_pro_substream);
4401da177e4SLinus Torvalds 				outb(ICE1712_MULTI_CAPSTATUS, ICEMT(ice, IRQ));
4411da177e4SLinus Torvalds 			}
4421da177e4SLinus Torvalds 		}
4431da177e4SLinus Torvalds 		if (status & ICE1712_IRQ_FM)
4441da177e4SLinus Torvalds 			outb(ICE1712_IRQ_FM, ICEREG(ice, IRQSTAT));
4451da177e4SLinus Torvalds 		if (status & ICE1712_IRQ_PBKDS) {
4461da177e4SLinus Torvalds 			u32 idx;
4471da177e4SLinus Torvalds 			u16 pbkstatus;
4486ca308d4STakashi Iwai 			struct snd_pcm_substream *substream;
4491da177e4SLinus Torvalds 			pbkstatus = inw(ICEDS(ice, INTSTAT));
4506dfb5affSTakashi Iwai 			/* dev_dbg(ice->card->dev, "pbkstatus = 0x%x\n", pbkstatus); */
4511da177e4SLinus Torvalds 			for (idx = 0; idx < 6; idx++) {
4521da177e4SLinus Torvalds 				if ((pbkstatus & (3 << (idx * 2))) == 0)
4531da177e4SLinus Torvalds 					continue;
4543d8cb466SAlexander Beregalov 				substream = ice->playback_con_substream_ds[idx];
4553d8cb466SAlexander Beregalov 				if (substream != NULL)
4561da177e4SLinus Torvalds 					snd_pcm_period_elapsed(substream);
4571da177e4SLinus Torvalds 				outw(3 << (idx * 2), ICEDS(ice, INTSTAT));
4581da177e4SLinus Torvalds 			}
4591da177e4SLinus Torvalds 			outb(ICE1712_IRQ_PBKDS, ICEREG(ice, IRQSTAT));
4601da177e4SLinus Torvalds 		}
4611da177e4SLinus Torvalds 		if (status & ICE1712_IRQ_CONCAP) {
4621da177e4SLinus Torvalds 			if (ice->capture_con_substream)
4631da177e4SLinus Torvalds 				snd_pcm_period_elapsed(ice->capture_con_substream);
4641da177e4SLinus Torvalds 			outb(ICE1712_IRQ_CONCAP, ICEREG(ice, IRQSTAT));
4651da177e4SLinus Torvalds 		}
4661da177e4SLinus Torvalds 		if (status & ICE1712_IRQ_CONPBK) {
4671da177e4SLinus Torvalds 			if (ice->playback_con_substream)
4681da177e4SLinus Torvalds 				snd_pcm_period_elapsed(ice->playback_con_substream);
4691da177e4SLinus Torvalds 			outb(ICE1712_IRQ_CONPBK, ICEREG(ice, IRQSTAT));
4701da177e4SLinus Torvalds 		}
4711da177e4SLinus Torvalds 	}
4721da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds 
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds /*
4771da177e4SLinus Torvalds  *  PCM part - consumer I/O
4781da177e4SLinus Torvalds  */
4791da177e4SLinus Torvalds 
snd_ice1712_playback_trigger(struct snd_pcm_substream * substream,int cmd)4806ca308d4STakashi Iwai static int snd_ice1712_playback_trigger(struct snd_pcm_substream *substream,
4811da177e4SLinus Torvalds 					int cmd)
4821da177e4SLinus Torvalds {
4836ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
4841da177e4SLinus Torvalds 	int result = 0;
4851da177e4SLinus Torvalds 	u32 tmp;
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	spin_lock(&ice->reg_lock);
4881da177e4SLinus Torvalds 	tmp = snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL);
4891da177e4SLinus Torvalds 	if (cmd == SNDRV_PCM_TRIGGER_START) {
4901da177e4SLinus Torvalds 		tmp |= 1;
4911da177e4SLinus Torvalds 	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
4921da177e4SLinus Torvalds 		tmp &= ~1;
4931da177e4SLinus Torvalds 	} else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) {
4941da177e4SLinus Torvalds 		tmp |= 2;
4951da177e4SLinus Torvalds 	} else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) {
4961da177e4SLinus Torvalds 		tmp &= ~2;
4971da177e4SLinus Torvalds 	} else {
4981da177e4SLinus Torvalds 		result = -EINVAL;
4991da177e4SLinus Torvalds 	}
5001da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_CTRL, tmp);
5011da177e4SLinus Torvalds 	spin_unlock(&ice->reg_lock);
5021da177e4SLinus Torvalds 	return result;
5031da177e4SLinus Torvalds }
5041da177e4SLinus Torvalds 
snd_ice1712_playback_ds_trigger(struct snd_pcm_substream * substream,int cmd)5056ca308d4STakashi Iwai static int snd_ice1712_playback_ds_trigger(struct snd_pcm_substream *substream,
5061da177e4SLinus Torvalds 					   int cmd)
5071da177e4SLinus Torvalds {
5086ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
5091da177e4SLinus Torvalds 	int result = 0;
5101da177e4SLinus Torvalds 	u32 tmp;
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 	spin_lock(&ice->reg_lock);
5131da177e4SLinus Torvalds 	tmp = snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL);
5141da177e4SLinus Torvalds 	if (cmd == SNDRV_PCM_TRIGGER_START) {
5151da177e4SLinus Torvalds 		tmp |= 1;
5161da177e4SLinus Torvalds 	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
5171da177e4SLinus Torvalds 		tmp &= ~1;
5181da177e4SLinus Torvalds 	} else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) {
5191da177e4SLinus Torvalds 		tmp |= 2;
5201da177e4SLinus Torvalds 	} else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) {
5211da177e4SLinus Torvalds 		tmp &= ~2;
5221da177e4SLinus Torvalds 	} else {
5231da177e4SLinus Torvalds 		result = -EINVAL;
5241da177e4SLinus Torvalds 	}
5251da177e4SLinus Torvalds 	snd_ice1712_ds_write(ice, substream->number * 2, ICE1712_DSC_CONTROL, tmp);
5261da177e4SLinus Torvalds 	spin_unlock(&ice->reg_lock);
5271da177e4SLinus Torvalds 	return result;
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds 
snd_ice1712_capture_trigger(struct snd_pcm_substream * substream,int cmd)5306ca308d4STakashi Iwai static int snd_ice1712_capture_trigger(struct snd_pcm_substream *substream,
5311da177e4SLinus Torvalds 				       int cmd)
5321da177e4SLinus Torvalds {
5336ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
5341da177e4SLinus Torvalds 	int result = 0;
5351da177e4SLinus Torvalds 	u8 tmp;
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds 	spin_lock(&ice->reg_lock);
5381da177e4SLinus Torvalds 	tmp = snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL);
5391da177e4SLinus Torvalds 	if (cmd == SNDRV_PCM_TRIGGER_START) {
5401da177e4SLinus Torvalds 		tmp |= 1;
5411da177e4SLinus Torvalds 	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
5421da177e4SLinus Torvalds 		tmp &= ~1;
5431da177e4SLinus Torvalds 	} else {
5441da177e4SLinus Torvalds 		result = -EINVAL;
5451da177e4SLinus Torvalds 	}
5461da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp);
5471da177e4SLinus Torvalds 	spin_unlock(&ice->reg_lock);
5481da177e4SLinus Torvalds 	return result;
5491da177e4SLinus Torvalds }
5501da177e4SLinus Torvalds 
snd_ice1712_playback_prepare(struct snd_pcm_substream * substream)5516ca308d4STakashi Iwai static int snd_ice1712_playback_prepare(struct snd_pcm_substream *substream)
5521da177e4SLinus Torvalds {
5536ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
5546ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
5551da177e4SLinus Torvalds 	u32 period_size, buf_size, rate, tmp;
5561da177e4SLinus Torvalds 
5571da177e4SLinus Torvalds 	period_size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1;
5581da177e4SLinus Torvalds 	buf_size = snd_pcm_lib_buffer_bytes(substream) - 1;
5591da177e4SLinus Torvalds 	tmp = 0x0000;
5601da177e4SLinus Torvalds 	if (snd_pcm_format_width(runtime->format) == 16)
5611da177e4SLinus Torvalds 		tmp |= 0x10;
5621da177e4SLinus Torvalds 	if (runtime->channels == 2)
5631da177e4SLinus Torvalds 		tmp |= 0x08;
5641da177e4SLinus Torvalds 	rate = (runtime->rate * 8192) / 375;
5651da177e4SLinus Torvalds 	if (rate > 0x000fffff)
5661da177e4SLinus Torvalds 		rate = 0x000fffff;
5671da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
5681da177e4SLinus Torvalds 	outb(0, ice->ddma_port + 15);
5691da177e4SLinus Torvalds 	outb(ICE1712_DMA_MODE_WRITE | ICE1712_DMA_AUTOINIT, ice->ddma_port + 0x0b);
5701da177e4SLinus Torvalds 	outl(runtime->dma_addr, ice->ddma_port + 0);
5711da177e4SLinus Torvalds 	outw(buf_size, ice->ddma_port + 4);
5721da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_LO, rate & 0xff);
5731da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_MID, (rate >> 8) & 0xff);
5741da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_HI, (rate >> 16) & 0xff);
5751da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_CTRL, tmp);
5761da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_COUNT_LO, period_size & 0xff);
5771da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_COUNT_HI, period_size >> 8);
5781da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_LEFT, 0);
5791da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PBK_RIGHT, 0);
5801da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
5811da177e4SLinus Torvalds 	return 0;
5821da177e4SLinus Torvalds }
5831da177e4SLinus Torvalds 
snd_ice1712_playback_ds_prepare(struct snd_pcm_substream * substream)5846ca308d4STakashi Iwai static int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream)
5851da177e4SLinus Torvalds {
5866ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
5876ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
588b393df01SSudip Mukherjee 	u32 period_size, rate, tmp, chn;
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 	period_size = snd_pcm_lib_period_bytes(substream) - 1;
5911da177e4SLinus Torvalds 	tmp = 0x0064;
5921da177e4SLinus Torvalds 	if (snd_pcm_format_width(runtime->format) == 16)
5931da177e4SLinus Torvalds 		tmp &= ~0x04;
5941da177e4SLinus Torvalds 	if (runtime->channels == 2)
5951da177e4SLinus Torvalds 		tmp |= 0x08;
5961da177e4SLinus Torvalds 	rate = (runtime->rate * 8192) / 375;
5971da177e4SLinus Torvalds 	if (rate > 0x000fffff)
5981da177e4SLinus Torvalds 		rate = 0x000fffff;
5991da177e4SLinus Torvalds 	ice->playback_con_active_buf[substream->number] = 0;
6001da177e4SLinus Torvalds 	ice->playback_con_virt_addr[substream->number] = runtime->dma_addr;
6011da177e4SLinus Torvalds 	chn = substream->number * 2;
6021da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
6031da177e4SLinus Torvalds 	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR0, runtime->dma_addr);
6041da177e4SLinus Torvalds 	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_COUNT0, period_size);
6051da177e4SLinus Torvalds 	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR1, runtime->dma_addr + (runtime->periods > 1 ? period_size + 1 : 0));
6061da177e4SLinus Torvalds 	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_COUNT1, period_size);
6071da177e4SLinus Torvalds 	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_RATE, rate);
6081da177e4SLinus Torvalds 	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_VOLUME, 0);
6091da177e4SLinus Torvalds 	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_CONTROL, tmp);
6101da177e4SLinus Torvalds 	if (runtime->channels == 2) {
6111da177e4SLinus Torvalds 		snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_RATE, rate);
6121da177e4SLinus Torvalds 		snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_VOLUME, 0);
6131da177e4SLinus Torvalds 	}
6141da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
6151da177e4SLinus Torvalds 	return 0;
6161da177e4SLinus Torvalds }
6171da177e4SLinus Torvalds 
snd_ice1712_capture_prepare(struct snd_pcm_substream * substream)6186ca308d4STakashi Iwai static int snd_ice1712_capture_prepare(struct snd_pcm_substream *substream)
6191da177e4SLinus Torvalds {
6206ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
6216ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
6221da177e4SLinus Torvalds 	u32 period_size, buf_size;
6231da177e4SLinus Torvalds 	u8 tmp;
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds 	period_size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1;
6261da177e4SLinus Torvalds 	buf_size = snd_pcm_lib_buffer_bytes(substream) - 1;
6271da177e4SLinus Torvalds 	tmp = 0x06;
6281da177e4SLinus Torvalds 	if (snd_pcm_format_width(runtime->format) == 16)
6291da177e4SLinus Torvalds 		tmp &= ~0x04;
6301da177e4SLinus Torvalds 	if (runtime->channels == 2)
6311da177e4SLinus Torvalds 		tmp &= ~0x02;
6321da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
6331da177e4SLinus Torvalds 	outl(ice->capture_con_virt_addr = runtime->dma_addr, ICEREG(ice, CONCAP_ADDR));
6341da177e4SLinus Torvalds 	outw(buf_size, ICEREG(ice, CONCAP_COUNT));
6351da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_HI, period_size >> 8);
6361da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_LO, period_size & 0xff);
6371da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp);
6381da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
6391da177e4SLinus Torvalds 	snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
6401da177e4SLinus Torvalds 	return 0;
6411da177e4SLinus Torvalds }
6421da177e4SLinus Torvalds 
snd_ice1712_playback_pointer(struct snd_pcm_substream * substream)6436ca308d4STakashi Iwai static snd_pcm_uframes_t snd_ice1712_playback_pointer(struct snd_pcm_substream *substream)
6441da177e4SLinus Torvalds {
6456ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
6466ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
6471da177e4SLinus Torvalds 	size_t ptr;
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds 	if (!(snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL) & 1))
6501da177e4SLinus Torvalds 		return 0;
6511da177e4SLinus Torvalds 	ptr = runtime->buffer_size - inw(ice->ddma_port + 4);
6524f8e9400STakashi Iwai 	ptr = bytes_to_frames(substream->runtime, ptr);
6531da177e4SLinus Torvalds 	if (ptr == runtime->buffer_size)
6541da177e4SLinus Torvalds 		ptr = 0;
6554f8e9400STakashi Iwai 	return ptr;
6561da177e4SLinus Torvalds }
6571da177e4SLinus Torvalds 
snd_ice1712_playback_ds_pointer(struct snd_pcm_substream * substream)6586ca308d4STakashi Iwai static snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(struct snd_pcm_substream *substream)
6591da177e4SLinus Torvalds {
6606ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
6611da177e4SLinus Torvalds 	u8 addr;
6621da177e4SLinus Torvalds 	size_t ptr;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	if (!(snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL) & 1))
6651da177e4SLinus Torvalds 		return 0;
6661da177e4SLinus Torvalds 	if (ice->playback_con_active_buf[substream->number])
6671da177e4SLinus Torvalds 		addr = ICE1712_DSC_ADDR1;
6681da177e4SLinus Torvalds 	else
6691da177e4SLinus Torvalds 		addr = ICE1712_DSC_ADDR0;
6701da177e4SLinus Torvalds 	ptr = snd_ice1712_ds_read(ice, substream->number * 2, addr) -
6711da177e4SLinus Torvalds 		ice->playback_con_virt_addr[substream->number];
6724f8e9400STakashi Iwai 	ptr = bytes_to_frames(substream->runtime, ptr);
6731da177e4SLinus Torvalds 	if (ptr == substream->runtime->buffer_size)
6741da177e4SLinus Torvalds 		ptr = 0;
6754f8e9400STakashi Iwai 	return ptr;
6761da177e4SLinus Torvalds }
6771da177e4SLinus Torvalds 
snd_ice1712_capture_pointer(struct snd_pcm_substream * substream)6786ca308d4STakashi Iwai static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *substream)
6791da177e4SLinus Torvalds {
6806ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
6811da177e4SLinus Torvalds 	size_t ptr;
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	if (!(snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL) & 1))
6841da177e4SLinus Torvalds 		return 0;
6851da177e4SLinus Torvalds 	ptr = inl(ICEREG(ice, CONCAP_ADDR)) - ice->capture_con_virt_addr;
6864f8e9400STakashi Iwai 	ptr = bytes_to_frames(substream->runtime, ptr);
6871da177e4SLinus Torvalds 	if (ptr == substream->runtime->buffer_size)
6881da177e4SLinus Torvalds 		ptr = 0;
6894f8e9400STakashi Iwai 	return ptr;
6901da177e4SLinus Torvalds }
6911da177e4SLinus Torvalds 
6923d8cb466SAlexander Beregalov static const struct snd_pcm_hardware snd_ice1712_playback = {
6931da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
6941da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
6951da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID |
6961da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_PAUSE),
6971da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
6981da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
6991da177e4SLinus Torvalds 	.rate_min =		4000,
7001da177e4SLinus Torvalds 	.rate_max =		48000,
7011da177e4SLinus Torvalds 	.channels_min =		1,
7021da177e4SLinus Torvalds 	.channels_max =		2,
7031da177e4SLinus Torvalds 	.buffer_bytes_max =	(64*1024),
7041da177e4SLinus Torvalds 	.period_bytes_min =	64,
7051da177e4SLinus Torvalds 	.period_bytes_max =	(64*1024),
7061da177e4SLinus Torvalds 	.periods_min =		1,
7071da177e4SLinus Torvalds 	.periods_max =		1024,
7081da177e4SLinus Torvalds 	.fifo_size =		0,
7091da177e4SLinus Torvalds };
7101da177e4SLinus Torvalds 
7113d8cb466SAlexander Beregalov static const struct snd_pcm_hardware snd_ice1712_playback_ds = {
7121da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
7131da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
7141da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID |
7151da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_PAUSE),
7161da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
7171da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
7181da177e4SLinus Torvalds 	.rate_min =		4000,
7191da177e4SLinus Torvalds 	.rate_max =		48000,
7201da177e4SLinus Torvalds 	.channels_min =		1,
7211da177e4SLinus Torvalds 	.channels_max =		2,
7221da177e4SLinus Torvalds 	.buffer_bytes_max =	(128*1024),
7231da177e4SLinus Torvalds 	.period_bytes_min =	64,
7241da177e4SLinus Torvalds 	.period_bytes_max =	(128*1024),
7251da177e4SLinus Torvalds 	.periods_min =		2,
7261da177e4SLinus Torvalds 	.periods_max =		2,
7271da177e4SLinus Torvalds 	.fifo_size =		0,
7281da177e4SLinus Torvalds };
7291da177e4SLinus Torvalds 
7303d8cb466SAlexander Beregalov static const struct snd_pcm_hardware snd_ice1712_capture = {
7311da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
7321da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
7331da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID),
7341da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
7351da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
7361da177e4SLinus Torvalds 	.rate_min =		4000,
7371da177e4SLinus Torvalds 	.rate_max =		48000,
7381da177e4SLinus Torvalds 	.channels_min =		1,
7391da177e4SLinus Torvalds 	.channels_max =		2,
7401da177e4SLinus Torvalds 	.buffer_bytes_max =	(64*1024),
7411da177e4SLinus Torvalds 	.period_bytes_min =	64,
7421da177e4SLinus Torvalds 	.period_bytes_max =	(64*1024),
7431da177e4SLinus Torvalds 	.periods_min =		1,
7441da177e4SLinus Torvalds 	.periods_max =		1024,
7451da177e4SLinus Torvalds 	.fifo_size =		0,
7461da177e4SLinus Torvalds };
7471da177e4SLinus Torvalds 
snd_ice1712_playback_open(struct snd_pcm_substream * substream)7486ca308d4STakashi Iwai static int snd_ice1712_playback_open(struct snd_pcm_substream *substream)
7491da177e4SLinus Torvalds {
7506ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
7516ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
7521da177e4SLinus Torvalds 
7531da177e4SLinus Torvalds 	ice->playback_con_substream = substream;
7541da177e4SLinus Torvalds 	runtime->hw = snd_ice1712_playback;
7551da177e4SLinus Torvalds 	return 0;
7561da177e4SLinus Torvalds }
7571da177e4SLinus Torvalds 
snd_ice1712_playback_ds_open(struct snd_pcm_substream * substream)7586ca308d4STakashi Iwai static int snd_ice1712_playback_ds_open(struct snd_pcm_substream *substream)
7591da177e4SLinus Torvalds {
7606ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
7616ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
7621da177e4SLinus Torvalds 	u32 tmp;
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	ice->playback_con_substream_ds[substream->number] = substream;
7651da177e4SLinus Torvalds 	runtime->hw = snd_ice1712_playback_ds;
7661da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
7671da177e4SLinus Torvalds 	tmp = inw(ICEDS(ice, INTMASK)) & ~(1 << (substream->number * 2));
7681da177e4SLinus Torvalds 	outw(tmp, ICEDS(ice, INTMASK));
7691da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
7701da177e4SLinus Torvalds 	return 0;
7711da177e4SLinus Torvalds }
7721da177e4SLinus Torvalds 
snd_ice1712_capture_open(struct snd_pcm_substream * substream)7736ca308d4STakashi Iwai static int snd_ice1712_capture_open(struct snd_pcm_substream *substream)
7741da177e4SLinus Torvalds {
7756ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
7766ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 	ice->capture_con_substream = substream;
7791da177e4SLinus Torvalds 	runtime->hw = snd_ice1712_capture;
7801da177e4SLinus Torvalds 	runtime->hw.rates = ice->ac97->rates[AC97_RATES_ADC];
7811da177e4SLinus Torvalds 	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
7821da177e4SLinus Torvalds 		runtime->hw.rate_min = 48000;
7831da177e4SLinus Torvalds 	return 0;
7841da177e4SLinus Torvalds }
7851da177e4SLinus Torvalds 
snd_ice1712_playback_close(struct snd_pcm_substream * substream)7866ca308d4STakashi Iwai static int snd_ice1712_playback_close(struct snd_pcm_substream *substream)
7871da177e4SLinus Torvalds {
7886ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 	ice->playback_con_substream = NULL;
7911da177e4SLinus Torvalds 	return 0;
7921da177e4SLinus Torvalds }
7931da177e4SLinus Torvalds 
snd_ice1712_playback_ds_close(struct snd_pcm_substream * substream)7946ca308d4STakashi Iwai static int snd_ice1712_playback_ds_close(struct snd_pcm_substream *substream)
7951da177e4SLinus Torvalds {
7966ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
7971da177e4SLinus Torvalds 	u32 tmp;
7981da177e4SLinus Torvalds 
7991da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
8001da177e4SLinus Torvalds 	tmp = inw(ICEDS(ice, INTMASK)) | (3 << (substream->number * 2));
8011da177e4SLinus Torvalds 	outw(tmp, ICEDS(ice, INTMASK));
8021da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
8031da177e4SLinus Torvalds 	ice->playback_con_substream_ds[substream->number] = NULL;
8041da177e4SLinus Torvalds 	return 0;
8051da177e4SLinus Torvalds }
8061da177e4SLinus Torvalds 
snd_ice1712_capture_close(struct snd_pcm_substream * substream)8076ca308d4STakashi Iwai static int snd_ice1712_capture_close(struct snd_pcm_substream *substream)
8081da177e4SLinus Torvalds {
8096ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds 	ice->capture_con_substream = NULL;
8121da177e4SLinus Torvalds 	return 0;
8131da177e4SLinus Torvalds }
8141da177e4SLinus Torvalds 
8156769e988SJulia Lawall static const struct snd_pcm_ops snd_ice1712_playback_ops = {
8161da177e4SLinus Torvalds 	.open =		snd_ice1712_playback_open,
8171da177e4SLinus Torvalds 	.close =	snd_ice1712_playback_close,
8181da177e4SLinus Torvalds 	.prepare =	snd_ice1712_playback_prepare,
8191da177e4SLinus Torvalds 	.trigger =	snd_ice1712_playback_trigger,
8201da177e4SLinus Torvalds 	.pointer =	snd_ice1712_playback_pointer,
8211da177e4SLinus Torvalds };
8221da177e4SLinus Torvalds 
8236769e988SJulia Lawall static const struct snd_pcm_ops snd_ice1712_playback_ds_ops = {
8241da177e4SLinus Torvalds 	.open =		snd_ice1712_playback_ds_open,
8251da177e4SLinus Torvalds 	.close =	snd_ice1712_playback_ds_close,
8261da177e4SLinus Torvalds 	.prepare =	snd_ice1712_playback_ds_prepare,
8271da177e4SLinus Torvalds 	.trigger =	snd_ice1712_playback_ds_trigger,
8281da177e4SLinus Torvalds 	.pointer =	snd_ice1712_playback_ds_pointer,
8291da177e4SLinus Torvalds };
8301da177e4SLinus Torvalds 
8316769e988SJulia Lawall static const struct snd_pcm_ops snd_ice1712_capture_ops = {
8321da177e4SLinus Torvalds 	.open =		snd_ice1712_capture_open,
8331da177e4SLinus Torvalds 	.close =	snd_ice1712_capture_close,
8341da177e4SLinus Torvalds 	.prepare =	snd_ice1712_capture_prepare,
8351da177e4SLinus Torvalds 	.trigger =	snd_ice1712_capture_trigger,
8361da177e4SLinus Torvalds 	.pointer =	snd_ice1712_capture_pointer,
8371da177e4SLinus Torvalds };
8381da177e4SLinus Torvalds 
snd_ice1712_pcm(struct snd_ice1712 * ice,int device)83908a4c10bSLars-Peter Clausen static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device)
8401da177e4SLinus Torvalds {
8416ca308d4STakashi Iwai 	struct snd_pcm *pcm;
8421da177e4SLinus Torvalds 	int err;
8431da177e4SLinus Torvalds 
8441da177e4SLinus Torvalds 	err = snd_pcm_new(ice->card, "ICE1712 consumer", device, 1, 1, &pcm);
8451da177e4SLinus Torvalds 	if (err < 0)
8461da177e4SLinus Torvalds 		return err;
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_ops);
8491da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ice1712_capture_ops);
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 	pcm->private_data = ice;
8521da177e4SLinus Torvalds 	pcm->info_flags = 0;
8531da177e4SLinus Torvalds 	strcpy(pcm->name, "ICE1712 consumer");
8541da177e4SLinus Torvalds 	ice->pcm = pcm;
8551da177e4SLinus Torvalds 
85660b8918bSTakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
85760b8918bSTakashi Iwai 				       &ice->pci->dev, 64*1024, 64*1024);
8581da177e4SLinus Torvalds 
8596dfb5affSTakashi Iwai 	dev_warn(ice->card->dev,
8606dfb5affSTakashi Iwai 		 "Consumer PCM code does not work well at the moment --jk\n");
8611da177e4SLinus Torvalds 
8621da177e4SLinus Torvalds 	return 0;
8631da177e4SLinus Torvalds }
8641da177e4SLinus Torvalds 
snd_ice1712_pcm_ds(struct snd_ice1712 * ice,int device)86508a4c10bSLars-Peter Clausen static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device)
8661da177e4SLinus Torvalds {
8676ca308d4STakashi Iwai 	struct snd_pcm *pcm;
8681da177e4SLinus Torvalds 	int err;
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds 	err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm);
8711da177e4SLinus Torvalds 	if (err < 0)
8721da177e4SLinus Torvalds 		return err;
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_ds_ops);
8751da177e4SLinus Torvalds 
8761da177e4SLinus Torvalds 	pcm->private_data = ice;
8771da177e4SLinus Torvalds 	pcm->info_flags = 0;
8781da177e4SLinus Torvalds 	strcpy(pcm->name, "ICE1712 consumer (DS)");
8791da177e4SLinus Torvalds 	ice->pcm_ds = pcm;
8801da177e4SLinus Torvalds 
88160b8918bSTakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
88260b8918bSTakashi Iwai 				       &ice->pci->dev, 64*1024, 128*1024);
8831da177e4SLinus Torvalds 
8841da177e4SLinus Torvalds 	return 0;
8851da177e4SLinus Torvalds }
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds /*
8881da177e4SLinus Torvalds  *  PCM code - professional part (multitrack)
8891da177e4SLinus Torvalds  */
8901da177e4SLinus Torvalds 
8915cf30ddfSTakashi Iwai static const unsigned int rates[] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000,
8921da177e4SLinus Torvalds 				32000, 44100, 48000, 64000, 88200, 96000 };
8931da177e4SLinus Torvalds 
8945cf30ddfSTakashi Iwai static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
8951da177e4SLinus Torvalds 	.count = ARRAY_SIZE(rates),
8961da177e4SLinus Torvalds 	.list = rates,
8971da177e4SLinus Torvalds 	.mask = 0,
8981da177e4SLinus Torvalds };
8991da177e4SLinus Torvalds 
snd_ice1712_pro_trigger(struct snd_pcm_substream * substream,int cmd)9006ca308d4STakashi Iwai static int snd_ice1712_pro_trigger(struct snd_pcm_substream *substream,
9011da177e4SLinus Torvalds 				   int cmd)
9021da177e4SLinus Torvalds {
9036ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
9041da177e4SLinus Torvalds 	switch (cmd) {
9051da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
9061da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
9071da177e4SLinus Torvalds 	{
9081da177e4SLinus Torvalds 		unsigned int what;
9091da177e4SLinus Torvalds 		unsigned int old;
9101da177e4SLinus Torvalds 		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
9111da177e4SLinus Torvalds 			return -EINVAL;
9121da177e4SLinus Torvalds 		what = ICE1712_PLAYBACK_PAUSE;
9131da177e4SLinus Torvalds 		snd_pcm_trigger_done(substream, substream);
9141da177e4SLinus Torvalds 		spin_lock(&ice->reg_lock);
9151da177e4SLinus Torvalds 		old = inl(ICEMT(ice, PLAYBACK_CONTROL));
9161da177e4SLinus Torvalds 		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
9171da177e4SLinus Torvalds 			old |= what;
9181da177e4SLinus Torvalds 		else
9191da177e4SLinus Torvalds 			old &= ~what;
9201da177e4SLinus Torvalds 		outl(old, ICEMT(ice, PLAYBACK_CONTROL));
9211da177e4SLinus Torvalds 		spin_unlock(&ice->reg_lock);
9221da177e4SLinus Torvalds 		break;
9231da177e4SLinus Torvalds 	}
9241da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
9251da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
9261da177e4SLinus Torvalds 	{
9271da177e4SLinus Torvalds 		unsigned int what = 0;
9281da177e4SLinus Torvalds 		unsigned int old;
9296ca308d4STakashi Iwai 		struct snd_pcm_substream *s;
9301da177e4SLinus Torvalds 
931ef991b95STakashi Iwai 		snd_pcm_group_for_each_entry(s, substream) {
9321da177e4SLinus Torvalds 			if (s == ice->playback_pro_substream) {
9331da177e4SLinus Torvalds 				what |= ICE1712_PLAYBACK_START;
9341da177e4SLinus Torvalds 				snd_pcm_trigger_done(s, substream);
9351da177e4SLinus Torvalds 			} else if (s == ice->capture_pro_substream) {
9361da177e4SLinus Torvalds 				what |= ICE1712_CAPTURE_START_SHADOW;
9371da177e4SLinus Torvalds 				snd_pcm_trigger_done(s, substream);
9381da177e4SLinus Torvalds 			}
9391da177e4SLinus Torvalds 		}
9401da177e4SLinus Torvalds 		spin_lock(&ice->reg_lock);
9411da177e4SLinus Torvalds 		old = inl(ICEMT(ice, PLAYBACK_CONTROL));
9421da177e4SLinus Torvalds 		if (cmd == SNDRV_PCM_TRIGGER_START)
9431da177e4SLinus Torvalds 			old |= what;
9441da177e4SLinus Torvalds 		else
9451da177e4SLinus Torvalds 			old &= ~what;
9461da177e4SLinus Torvalds 		outl(old, ICEMT(ice, PLAYBACK_CONTROL));
9471da177e4SLinus Torvalds 		spin_unlock(&ice->reg_lock);
9481da177e4SLinus Torvalds 		break;
9491da177e4SLinus Torvalds 	}
9501da177e4SLinus Torvalds 	default:
9511da177e4SLinus Torvalds 		return -EINVAL;
9521da177e4SLinus Torvalds 	}
9531da177e4SLinus Torvalds 	return 0;
9541da177e4SLinus Torvalds }
9551da177e4SLinus Torvalds 
9561da177e4SLinus Torvalds /*
9571da177e4SLinus Torvalds  */
snd_ice1712_set_pro_rate(struct snd_ice1712 * ice,unsigned int rate,int force)9586ca308d4STakashi Iwai static void snd_ice1712_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, int force)
9591da177e4SLinus Torvalds {
9601da177e4SLinus Torvalds 	unsigned long flags;
9611da177e4SLinus Torvalds 	unsigned char val, old;
9621da177e4SLinus Torvalds 	unsigned int i;
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds 	switch (rate) {
9651da177e4SLinus Torvalds 	case 8000: val = 6; break;
9661da177e4SLinus Torvalds 	case 9600: val = 3; break;
9671da177e4SLinus Torvalds 	case 11025: val = 10; break;
9681da177e4SLinus Torvalds 	case 12000: val = 2; break;
9691da177e4SLinus Torvalds 	case 16000: val = 5; break;
9701da177e4SLinus Torvalds 	case 22050: val = 9; break;
9711da177e4SLinus Torvalds 	case 24000: val = 1; break;
9721da177e4SLinus Torvalds 	case 32000: val = 4; break;
9731da177e4SLinus Torvalds 	case 44100: val = 8; break;
9741da177e4SLinus Torvalds 	case 48000: val = 0; break;
9751da177e4SLinus Torvalds 	case 64000: val = 15; break;
9761da177e4SLinus Torvalds 	case 88200: val = 11; break;
9771da177e4SLinus Torvalds 	case 96000: val = 7; break;
9781da177e4SLinus Torvalds 	default:
9791da177e4SLinus Torvalds 		snd_BUG();
9801da177e4SLinus Torvalds 		val = 0;
9811da177e4SLinus Torvalds 		rate = 48000;
9821da177e4SLinus Torvalds 		break;
9831da177e4SLinus Torvalds 	}
9841da177e4SLinus Torvalds 
9851da177e4SLinus Torvalds 	spin_lock_irqsave(&ice->reg_lock, flags);
9861da177e4SLinus Torvalds 	if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
9871da177e4SLinus Torvalds 						 ICE1712_PLAYBACK_PAUSE|
9881da177e4SLinus Torvalds 						 ICE1712_PLAYBACK_START)) {
9891da177e4SLinus Torvalds __out:
9901da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ice->reg_lock, flags);
9911da177e4SLinus Torvalds 		return;
9921da177e4SLinus Torvalds 	}
9931da177e4SLinus Torvalds 	if (!force && is_pro_rate_locked(ice))
9941da177e4SLinus Torvalds 		goto __out;
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds 	old = inb(ICEMT(ice, RATE));
9971da177e4SLinus Torvalds 	if (!force && old == val)
9981da177e4SLinus Torvalds 		goto __out;
9996ea0cae7SOndrej Zary 
10006ea0cae7SOndrej Zary 	ice->cur_rate = rate;
10011da177e4SLinus Torvalds 	outb(val, ICEMT(ice, RATE));
10021da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ice->reg_lock, flags);
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 	if (ice->gpio.set_pro_rate)
10051da177e4SLinus Torvalds 		ice->gpio.set_pro_rate(ice, rate);
10061da177e4SLinus Torvalds 	for (i = 0; i < ice->akm_codecs; i++) {
10071da177e4SLinus Torvalds 		if (ice->akm[i].ops.set_rate_val)
10081da177e4SLinus Torvalds 			ice->akm[i].ops.set_rate_val(&ice->akm[i], rate);
10091da177e4SLinus Torvalds 	}
10101da177e4SLinus Torvalds 	if (ice->spdif.ops.setup_rate)
10111da177e4SLinus Torvalds 		ice->spdif.ops.setup_rate(ice, rate);
10121da177e4SLinus Torvalds }
10131da177e4SLinus Torvalds 
snd_ice1712_playback_pro_prepare(struct snd_pcm_substream * substream)10146ca308d4STakashi Iwai static int snd_ice1712_playback_pro_prepare(struct snd_pcm_substream *substream)
10151da177e4SLinus Torvalds {
10166ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds 	ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream);
10191da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
10201da177e4SLinus Torvalds 	outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR));
10211da177e4SLinus Torvalds 	outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE));
10221da177e4SLinus Torvalds 	outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, PLAYBACK_COUNT));
10231da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
10241da177e4SLinus Torvalds 
10251da177e4SLinus Torvalds 	return 0;
10261da177e4SLinus Torvalds }
10271da177e4SLinus Torvalds 
snd_ice1712_playback_pro_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)10286ca308d4STakashi Iwai static int snd_ice1712_playback_pro_hw_params(struct snd_pcm_substream *substream,
10296ca308d4STakashi Iwai 					      struct snd_pcm_hw_params *hw_params)
10301da177e4SLinus Torvalds {
10316ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
10321da177e4SLinus Torvalds 
10331da177e4SLinus Torvalds 	snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0);
103460b8918bSTakashi Iwai 	return 0;
10351da177e4SLinus Torvalds }
10361da177e4SLinus Torvalds 
snd_ice1712_capture_pro_prepare(struct snd_pcm_substream * substream)10376ca308d4STakashi Iwai static int snd_ice1712_capture_pro_prepare(struct snd_pcm_substream *substream)
10381da177e4SLinus Torvalds {
10396ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds 	ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream);
10421da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
10431da177e4SLinus Torvalds 	outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR));
10441da177e4SLinus Torvalds 	outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE));
10451da177e4SLinus Torvalds 	outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, CAPTURE_COUNT));
10461da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
10471da177e4SLinus Torvalds 	return 0;
10481da177e4SLinus Torvalds }
10491da177e4SLinus Torvalds 
snd_ice1712_capture_pro_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)10506ca308d4STakashi Iwai static int snd_ice1712_capture_pro_hw_params(struct snd_pcm_substream *substream,
10516ca308d4STakashi Iwai 					     struct snd_pcm_hw_params *hw_params)
10521da177e4SLinus Torvalds {
10536ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
10541da177e4SLinus Torvalds 
10551da177e4SLinus Torvalds 	snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0);
105660b8918bSTakashi Iwai 	return 0;
10571da177e4SLinus Torvalds }
10581da177e4SLinus Torvalds 
snd_ice1712_playback_pro_pointer(struct snd_pcm_substream * substream)10596ca308d4STakashi Iwai static snd_pcm_uframes_t snd_ice1712_playback_pro_pointer(struct snd_pcm_substream *substream)
10601da177e4SLinus Torvalds {
10616ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
10621da177e4SLinus Torvalds 	size_t ptr;
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds 	if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START))
10651da177e4SLinus Torvalds 		return 0;
10661da177e4SLinus Torvalds 	ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2);
10674f8e9400STakashi Iwai 	ptr = bytes_to_frames(substream->runtime, ptr);
10681da177e4SLinus Torvalds 	if (ptr == substream->runtime->buffer_size)
10691da177e4SLinus Torvalds 		ptr = 0;
10704f8e9400STakashi Iwai 	return ptr;
10711da177e4SLinus Torvalds }
10721da177e4SLinus Torvalds 
snd_ice1712_capture_pro_pointer(struct snd_pcm_substream * substream)10736ca308d4STakashi Iwai static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substream *substream)
10741da177e4SLinus Torvalds {
10756ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
10761da177e4SLinus Torvalds 	size_t ptr;
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 	if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_CAPTURE_START_SHADOW))
10791da177e4SLinus Torvalds 		return 0;
10801da177e4SLinus Torvalds 	ptr = ice->capture_pro_size - (inw(ICEMT(ice, CAPTURE_SIZE)) << 2);
10814f8e9400STakashi Iwai 	ptr = bytes_to_frames(substream->runtime, ptr);
10821da177e4SLinus Torvalds 	if (ptr == substream->runtime->buffer_size)
10831da177e4SLinus Torvalds 		ptr = 0;
10844f8e9400STakashi Iwai 	return ptr;
10851da177e4SLinus Torvalds }
10861da177e4SLinus Torvalds 
10873d8cb466SAlexander Beregalov static const struct snd_pcm_hardware snd_ice1712_playback_pro = {
10881da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
10891da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
10901da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID |
10911da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
10921da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
10931da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000,
10941da177e4SLinus Torvalds 	.rate_min =		4000,
10951da177e4SLinus Torvalds 	.rate_max =		96000,
10961da177e4SLinus Torvalds 	.channels_min =		10,
10971da177e4SLinus Torvalds 	.channels_max =		10,
10981da177e4SLinus Torvalds 	.buffer_bytes_max =	(256*1024),
10991da177e4SLinus Torvalds 	.period_bytes_min =	10 * 4 * 2,
11001da177e4SLinus Torvalds 	.period_bytes_max =	131040,
11011da177e4SLinus Torvalds 	.periods_min =		1,
11021da177e4SLinus Torvalds 	.periods_max =		1024,
11031da177e4SLinus Torvalds 	.fifo_size =		0,
11041da177e4SLinus Torvalds };
11051da177e4SLinus Torvalds 
11063d8cb466SAlexander Beregalov static const struct snd_pcm_hardware snd_ice1712_capture_pro = {
11071da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
11081da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
11091da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID |
11101da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
11111da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
11121da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000,
11131da177e4SLinus Torvalds 	.rate_min =		4000,
11141da177e4SLinus Torvalds 	.rate_max =		96000,
11151da177e4SLinus Torvalds 	.channels_min =		12,
11161da177e4SLinus Torvalds 	.channels_max =		12,
11171da177e4SLinus Torvalds 	.buffer_bytes_max =	(256*1024),
11181da177e4SLinus Torvalds 	.period_bytes_min =	12 * 4 * 2,
11191da177e4SLinus Torvalds 	.period_bytes_max =	131040,
11201da177e4SLinus Torvalds 	.periods_min =		1,
11211da177e4SLinus Torvalds 	.periods_max =		1024,
11221da177e4SLinus Torvalds 	.fifo_size =		0,
11231da177e4SLinus Torvalds };
11241da177e4SLinus Torvalds 
snd_ice1712_playback_pro_open(struct snd_pcm_substream * substream)11256ca308d4STakashi Iwai static int snd_ice1712_playback_pro_open(struct snd_pcm_substream *substream)
11261da177e4SLinus Torvalds {
11276ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
11286ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
11291da177e4SLinus Torvalds 
11301da177e4SLinus Torvalds 	ice->playback_pro_substream = substream;
11311da177e4SLinus Torvalds 	runtime->hw = snd_ice1712_playback_pro;
11321da177e4SLinus Torvalds 	snd_pcm_set_sync(substream);
11331da177e4SLinus Torvalds 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
11341da177e4SLinus Torvalds 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
1135350a5147SSebastien Alaiwan 	if (is_pro_rate_locked(ice)) {
1136350a5147SSebastien Alaiwan 		runtime->hw.rate_min = PRO_RATE_DEFAULT;
1137350a5147SSebastien Alaiwan 		runtime->hw.rate_max = PRO_RATE_DEFAULT;
1138350a5147SSebastien Alaiwan 	}
11391da177e4SLinus Torvalds 
11401da177e4SLinus Torvalds 	if (ice->spdif.ops.open)
11411da177e4SLinus Torvalds 		ice->spdif.ops.open(ice, substream);
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds 	return 0;
11441da177e4SLinus Torvalds }
11451da177e4SLinus Torvalds 
snd_ice1712_capture_pro_open(struct snd_pcm_substream * substream)11466ca308d4STakashi Iwai static int snd_ice1712_capture_pro_open(struct snd_pcm_substream *substream)
11471da177e4SLinus Torvalds {
11486ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
11496ca308d4STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
11501da177e4SLinus Torvalds 
11511da177e4SLinus Torvalds 	ice->capture_pro_substream = substream;
11521da177e4SLinus Torvalds 	runtime->hw = snd_ice1712_capture_pro;
11531da177e4SLinus Torvalds 	snd_pcm_set_sync(substream);
11541da177e4SLinus Torvalds 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
11551da177e4SLinus Torvalds 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
1156350a5147SSebastien Alaiwan 	if (is_pro_rate_locked(ice)) {
1157350a5147SSebastien Alaiwan 		runtime->hw.rate_min = PRO_RATE_DEFAULT;
1158350a5147SSebastien Alaiwan 		runtime->hw.rate_max = PRO_RATE_DEFAULT;
1159350a5147SSebastien Alaiwan 	}
1160350a5147SSebastien Alaiwan 
11611da177e4SLinus Torvalds 	return 0;
11621da177e4SLinus Torvalds }
11631da177e4SLinus Torvalds 
snd_ice1712_playback_pro_close(struct snd_pcm_substream * substream)11646ca308d4STakashi Iwai static int snd_ice1712_playback_pro_close(struct snd_pcm_substream *substream)
11651da177e4SLinus Torvalds {
11666ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 	if (PRO_RATE_RESET)
11691da177e4SLinus Torvalds 		snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
11701da177e4SLinus Torvalds 	ice->playback_pro_substream = NULL;
11711da177e4SLinus Torvalds 	if (ice->spdif.ops.close)
11721da177e4SLinus Torvalds 		ice->spdif.ops.close(ice, substream);
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds 	return 0;
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds 
snd_ice1712_capture_pro_close(struct snd_pcm_substream * substream)11776ca308d4STakashi Iwai static int snd_ice1712_capture_pro_close(struct snd_pcm_substream *substream)
11781da177e4SLinus Torvalds {
11796ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
11801da177e4SLinus Torvalds 
11811da177e4SLinus Torvalds 	if (PRO_RATE_RESET)
11821da177e4SLinus Torvalds 		snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
11831da177e4SLinus Torvalds 	ice->capture_pro_substream = NULL;
11841da177e4SLinus Torvalds 	return 0;
11851da177e4SLinus Torvalds }
11861da177e4SLinus Torvalds 
11876769e988SJulia Lawall static const struct snd_pcm_ops snd_ice1712_playback_pro_ops = {
11881da177e4SLinus Torvalds 	.open =		snd_ice1712_playback_pro_open,
11891da177e4SLinus Torvalds 	.close =	snd_ice1712_playback_pro_close,
11901da177e4SLinus Torvalds 	.hw_params =	snd_ice1712_playback_pro_hw_params,
11911da177e4SLinus Torvalds 	.prepare =	snd_ice1712_playback_pro_prepare,
11921da177e4SLinus Torvalds 	.trigger =	snd_ice1712_pro_trigger,
11931da177e4SLinus Torvalds 	.pointer =	snd_ice1712_playback_pro_pointer,
11941da177e4SLinus Torvalds };
11951da177e4SLinus Torvalds 
11966769e988SJulia Lawall static const struct snd_pcm_ops snd_ice1712_capture_pro_ops = {
11971da177e4SLinus Torvalds 	.open =		snd_ice1712_capture_pro_open,
11981da177e4SLinus Torvalds 	.close =	snd_ice1712_capture_pro_close,
11991da177e4SLinus Torvalds 	.hw_params =	snd_ice1712_capture_pro_hw_params,
12001da177e4SLinus Torvalds 	.prepare =	snd_ice1712_capture_pro_prepare,
12011da177e4SLinus Torvalds 	.trigger =	snd_ice1712_pro_trigger,
12021da177e4SLinus Torvalds 	.pointer =	snd_ice1712_capture_pro_pointer,
12031da177e4SLinus Torvalds };
12041da177e4SLinus Torvalds 
snd_ice1712_pcm_profi(struct snd_ice1712 * ice,int device)120508a4c10bSLars-Peter Clausen static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device)
12061da177e4SLinus Torvalds {
12076ca308d4STakashi Iwai 	struct snd_pcm *pcm;
12081da177e4SLinus Torvalds 	int err;
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds 	err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm);
12111da177e4SLinus Torvalds 	if (err < 0)
12121da177e4SLinus Torvalds 		return err;
12131da177e4SLinus Torvalds 
12141da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_pro_ops);
12151da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ice1712_capture_pro_ops);
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 	pcm->private_data = ice;
12181da177e4SLinus Torvalds 	pcm->info_flags = 0;
12191da177e4SLinus Torvalds 	strcpy(pcm->name, "ICE1712 multi");
12201da177e4SLinus Torvalds 
122160b8918bSTakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
122260b8918bSTakashi Iwai 				       &ice->pci->dev, 256*1024, 256*1024);
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds 	ice->pcm_pro = pcm;
12251da177e4SLinus Torvalds 
12261da177e4SLinus Torvalds 	if (ice->cs8427) {
12271da177e4SLinus Torvalds 		/* assign channels to iec958 */
12281da177e4SLinus Torvalds 		err = snd_cs8427_iec958_build(ice->cs8427,
12291da177e4SLinus Torvalds 					      pcm->streams[0].substream,
12301da177e4SLinus Torvalds 					      pcm->streams[1].substream);
12311da177e4SLinus Torvalds 		if (err < 0)
12321da177e4SLinus Torvalds 			return err;
12331da177e4SLinus Torvalds 	}
12341da177e4SLinus Torvalds 
1235387417b5SSudip Mukherjee 	return snd_ice1712_build_pro_mixer(ice);
12361da177e4SLinus Torvalds }
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds /*
12391da177e4SLinus Torvalds  *  Mixer section
12401da177e4SLinus Torvalds  */
12411da177e4SLinus Torvalds 
snd_ice1712_update_volume(struct snd_ice1712 * ice,int index)12426ca308d4STakashi Iwai static void snd_ice1712_update_volume(struct snd_ice1712 *ice, int index)
12431da177e4SLinus Torvalds {
12441da177e4SLinus Torvalds 	unsigned int vol = ice->pro_volumes[index];
12451da177e4SLinus Torvalds 	unsigned short val = 0;
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 	val |= (vol & 0x8000) == 0 ? (96 - (vol & 0x7f)) : 0x7f;
12481da177e4SLinus Torvalds 	val |= ((vol & 0x80000000) == 0 ? (96 - ((vol >> 16) & 0x7f)) : 0x7f) << 8;
12491da177e4SLinus Torvalds 	outb(index, ICEMT(ice, MONITOR_INDEX));
12501da177e4SLinus Torvalds 	outw(val, ICEMT(ice, MONITOR_VOLUME));
12511da177e4SLinus Torvalds }
12521da177e4SLinus Torvalds 
1253a5ce8890STakashi Iwai #define snd_ice1712_pro_mixer_switch_info	snd_ctl_boolean_stereo_info
12541da177e4SLinus Torvalds 
snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)12556ca308d4STakashi Iwai static int snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
12561da177e4SLinus Torvalds {
12576ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
1258c3daa92dSHarvey Harrison 	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
1259c3daa92dSHarvey Harrison 		kcontrol->private_value;
12601da177e4SLinus Torvalds 
12611da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
1262c3daa92dSHarvey Harrison 	ucontrol->value.integer.value[0] =
1263c3daa92dSHarvey Harrison 		!((ice->pro_volumes[priv_idx] >> 15) & 1);
1264c3daa92dSHarvey Harrison 	ucontrol->value.integer.value[1] =
1265c3daa92dSHarvey Harrison 		!((ice->pro_volumes[priv_idx] >> 31) & 1);
12661da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
12671da177e4SLinus Torvalds 	return 0;
12681da177e4SLinus Torvalds }
12691da177e4SLinus Torvalds 
snd_ice1712_pro_mixer_switch_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)12706ca308d4STakashi Iwai static int snd_ice1712_pro_mixer_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
12711da177e4SLinus Torvalds {
12726ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
1273c3daa92dSHarvey Harrison 	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
1274c3daa92dSHarvey Harrison 		kcontrol->private_value;
12751da177e4SLinus Torvalds 	unsigned int nval, change;
12761da177e4SLinus Torvalds 
12771da177e4SLinus Torvalds 	nval = (ucontrol->value.integer.value[0] ? 0 : 0x00008000) |
12781da177e4SLinus Torvalds 	       (ucontrol->value.integer.value[1] ? 0 : 0x80000000);
12791da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
1280c3daa92dSHarvey Harrison 	nval |= ice->pro_volumes[priv_idx] & ~0x80008000;
1281c3daa92dSHarvey Harrison 	change = nval != ice->pro_volumes[priv_idx];
1282c3daa92dSHarvey Harrison 	ice->pro_volumes[priv_idx] = nval;
1283c3daa92dSHarvey Harrison 	snd_ice1712_update_volume(ice, priv_idx);
12841da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
12851da177e4SLinus Torvalds 	return change;
12861da177e4SLinus Torvalds }
12871da177e4SLinus Torvalds 
snd_ice1712_pro_mixer_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)12886ca308d4STakashi Iwai static int snd_ice1712_pro_mixer_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12891da177e4SLinus Torvalds {
12901da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12911da177e4SLinus Torvalds 	uinfo->count = 2;
12921da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12931da177e4SLinus Torvalds 	uinfo->value.integer.max = 96;
12941da177e4SLinus Torvalds 	return 0;
12951da177e4SLinus Torvalds }
12961da177e4SLinus Torvalds 
snd_ice1712_pro_mixer_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)12976ca308d4STakashi Iwai static int snd_ice1712_pro_mixer_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
12981da177e4SLinus Torvalds {
12996ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
1300c3daa92dSHarvey Harrison 	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
1301c3daa92dSHarvey Harrison 		kcontrol->private_value;
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
1304c3daa92dSHarvey Harrison 	ucontrol->value.integer.value[0] =
1305c3daa92dSHarvey Harrison 		(ice->pro_volumes[priv_idx] >> 0) & 127;
1306c3daa92dSHarvey Harrison 	ucontrol->value.integer.value[1] =
1307c3daa92dSHarvey Harrison 		(ice->pro_volumes[priv_idx] >> 16) & 127;
13081da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
13091da177e4SLinus Torvalds 	return 0;
13101da177e4SLinus Torvalds }
13111da177e4SLinus Torvalds 
snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)13126ca308d4STakashi Iwai static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
13131da177e4SLinus Torvalds {
13146ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
1315c3daa92dSHarvey Harrison 	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
1316c3daa92dSHarvey Harrison 		kcontrol->private_value;
13171da177e4SLinus Torvalds 	unsigned int nval, change;
13181da177e4SLinus Torvalds 
13191da177e4SLinus Torvalds 	nval = (ucontrol->value.integer.value[0] & 127) |
13201da177e4SLinus Torvalds 	       ((ucontrol->value.integer.value[1] & 127) << 16);
13211da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
1322c3daa92dSHarvey Harrison 	nval |= ice->pro_volumes[priv_idx] & ~0x007f007f;
1323c3daa92dSHarvey Harrison 	change = nval != ice->pro_volumes[priv_idx];
1324c3daa92dSHarvey Harrison 	ice->pro_volumes[priv_idx] = nval;
1325c3daa92dSHarvey Harrison 	snd_ice1712_update_volume(ice, priv_idx);
13261da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
13271da177e4SLinus Torvalds 	return change;
13281da177e4SLinus Torvalds }
13291da177e4SLinus Torvalds 
13300cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
13311da177e4SLinus Torvalds 
1332b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] = {
13331da177e4SLinus Torvalds 	{
13341da177e4SLinus Torvalds 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13351da177e4SLinus Torvalds 		.name = "Multi Playback Switch",
13361da177e4SLinus Torvalds 		.info = snd_ice1712_pro_mixer_switch_info,
13371da177e4SLinus Torvalds 		.get = snd_ice1712_pro_mixer_switch_get,
13381da177e4SLinus Torvalds 		.put = snd_ice1712_pro_mixer_switch_put,
13391da177e4SLinus Torvalds 		.private_value = 0,
13401da177e4SLinus Torvalds 		.count = 10,
13411da177e4SLinus Torvalds 	},
13421da177e4SLinus Torvalds 	{
13431da177e4SLinus Torvalds 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1344680ef792STakashi Iwai 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1345680ef792STakashi Iwai 			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
13461da177e4SLinus Torvalds 		.name = "Multi Playback Volume",
13471da177e4SLinus Torvalds 		.info = snd_ice1712_pro_mixer_volume_info,
13481da177e4SLinus Torvalds 		.get = snd_ice1712_pro_mixer_volume_get,
13491da177e4SLinus Torvalds 		.put = snd_ice1712_pro_mixer_volume_put,
13501da177e4SLinus Torvalds 		.private_value = 0,
13511da177e4SLinus Torvalds 		.count = 10,
1352680ef792STakashi Iwai 		.tlv = { .p = db_scale_playback }
13531da177e4SLinus Torvalds 	},
13541da177e4SLinus Torvalds };
13551da177e4SLinus Torvalds 
13566ba1ad38SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch = {
13571da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13581da177e4SLinus Torvalds 	.name = "H/W Multi Capture Switch",
13591da177e4SLinus Torvalds 	.info = snd_ice1712_pro_mixer_switch_info,
13601da177e4SLinus Torvalds 	.get = snd_ice1712_pro_mixer_switch_get,
13611da177e4SLinus Torvalds 	.put = snd_ice1712_pro_mixer_switch_put,
13621da177e4SLinus Torvalds 	.private_value = 10,
13631da177e4SLinus Torvalds };
13641da177e4SLinus Torvalds 
1365f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = {
13661da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
136710e8d78aSClemens Ladisch 	.name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH),
13681da177e4SLinus Torvalds 	.info = snd_ice1712_pro_mixer_switch_info,
13691da177e4SLinus Torvalds 	.get = snd_ice1712_pro_mixer_switch_get,
13701da177e4SLinus Torvalds 	.put = snd_ice1712_pro_mixer_switch_put,
13711da177e4SLinus Torvalds 	.private_value = 18,
13721da177e4SLinus Torvalds 	.count = 2,
13731da177e4SLinus Torvalds };
13741da177e4SLinus Torvalds 
13756ba1ad38SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume = {
13761da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1377680ef792STakashi Iwai 	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1378680ef792STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
13791da177e4SLinus Torvalds 	.name = "H/W Multi Capture Volume",
13801da177e4SLinus Torvalds 	.info = snd_ice1712_pro_mixer_volume_info,
13811da177e4SLinus Torvalds 	.get = snd_ice1712_pro_mixer_volume_get,
13821da177e4SLinus Torvalds 	.put = snd_ice1712_pro_mixer_volume_put,
13831da177e4SLinus Torvalds 	.private_value = 10,
1384680ef792STakashi Iwai 	.tlv = { .p = db_scale_playback }
13851da177e4SLinus Torvalds };
13861da177e4SLinus Torvalds 
1387f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume = {
13881da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
138910e8d78aSClemens Ladisch 	.name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME),
13901da177e4SLinus Torvalds 	.info = snd_ice1712_pro_mixer_volume_info,
13911da177e4SLinus Torvalds 	.get = snd_ice1712_pro_mixer_volume_get,
13921da177e4SLinus Torvalds 	.put = snd_ice1712_pro_mixer_volume_put,
13931da177e4SLinus Torvalds 	.private_value = 18,
13941da177e4SLinus Torvalds 	.count = 2,
13951da177e4SLinus Torvalds };
13961da177e4SLinus Torvalds 
snd_ice1712_build_pro_mixer(struct snd_ice1712 * ice)1397e23e7a14SBill Pemberton static int snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice)
13981da177e4SLinus Torvalds {
13996ca308d4STakashi Iwai 	struct snd_card *card = ice->card;
14001da177e4SLinus Torvalds 	unsigned int idx;
14011da177e4SLinus Torvalds 	int err;
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 	/* multi-channel mixer */
14041da177e4SLinus Torvalds 	for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_multi_playback_ctrls); idx++) {
14051da177e4SLinus Torvalds 		err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_playback_ctrls[idx], ice));
14061da177e4SLinus Torvalds 		if (err < 0)
14071da177e4SLinus Torvalds 			return err;
14081da177e4SLinus Torvalds 	}
14091da177e4SLinus Torvalds 
14101da177e4SLinus Torvalds 	if (ice->num_total_adcs > 0) {
14116ca308d4STakashi Iwai 		struct snd_kcontrol_new tmp = snd_ice1712_multi_capture_analog_switch;
14121da177e4SLinus Torvalds 		tmp.count = ice->num_total_adcs;
14131da177e4SLinus Torvalds 		err = snd_ctl_add(card, snd_ctl_new1(&tmp, ice));
14141da177e4SLinus Torvalds 		if (err < 0)
14151da177e4SLinus Torvalds 			return err;
14161da177e4SLinus Torvalds 	}
14171da177e4SLinus Torvalds 
14181da177e4SLinus Torvalds 	err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_capture_spdif_switch, ice));
14191da177e4SLinus Torvalds 	if (err < 0)
14201da177e4SLinus Torvalds 		return err;
14211da177e4SLinus Torvalds 
14221da177e4SLinus Torvalds 	if (ice->num_total_adcs > 0) {
14236ca308d4STakashi Iwai 		struct snd_kcontrol_new tmp = snd_ice1712_multi_capture_analog_volume;
14241da177e4SLinus Torvalds 		tmp.count = ice->num_total_adcs;
14251da177e4SLinus Torvalds 		err = snd_ctl_add(card, snd_ctl_new1(&tmp, ice));
14261da177e4SLinus Torvalds 		if (err < 0)
14271da177e4SLinus Torvalds 			return err;
14281da177e4SLinus Torvalds 	}
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 	err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_capture_spdif_volume, ice));
14311da177e4SLinus Torvalds 	if (err < 0)
14321da177e4SLinus Torvalds 		return err;
14331da177e4SLinus Torvalds 
14341da177e4SLinus Torvalds 	/* initialize volumes */
14351da177e4SLinus Torvalds 	for (idx = 0; idx < 10; idx++) {
14361da177e4SLinus Torvalds 		ice->pro_volumes[idx] = 0x80008000;	/* mute */
14371da177e4SLinus Torvalds 		snd_ice1712_update_volume(ice, idx);
14381da177e4SLinus Torvalds 	}
14391da177e4SLinus Torvalds 	for (idx = 10; idx < 10 + ice->num_total_adcs; idx++) {
14401da177e4SLinus Torvalds 		ice->pro_volumes[idx] = 0x80008000;	/* mute */
14411da177e4SLinus Torvalds 		snd_ice1712_update_volume(ice, idx);
14421da177e4SLinus Torvalds 	}
14431da177e4SLinus Torvalds 	for (idx = 18; idx < 20; idx++) {
14441da177e4SLinus Torvalds 		ice->pro_volumes[idx] = 0x80008000;	/* mute */
14451da177e4SLinus Torvalds 		snd_ice1712_update_volume(ice, idx);
14461da177e4SLinus Torvalds 	}
14471da177e4SLinus Torvalds 	return 0;
14481da177e4SLinus Torvalds }
14491da177e4SLinus Torvalds 
snd_ice1712_mixer_free_ac97(struct snd_ac97 * ac97)14506ca308d4STakashi Iwai static void snd_ice1712_mixer_free_ac97(struct snd_ac97 *ac97)
14511da177e4SLinus Torvalds {
14526ca308d4STakashi Iwai 	struct snd_ice1712 *ice = ac97->private_data;
14531da177e4SLinus Torvalds 	ice->ac97 = NULL;
14541da177e4SLinus Torvalds }
14551da177e4SLinus Torvalds 
snd_ice1712_ac97_mixer(struct snd_ice1712 * ice)1456e23e7a14SBill Pemberton static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
14571da177e4SLinus Torvalds {
14581da177e4SLinus Torvalds 	int err, bus_num = 0;
14596ca308d4STakashi Iwai 	struct snd_ac97_template ac97;
14606ca308d4STakashi Iwai 	struct snd_ac97_bus *pbus;
146151055da5STakashi Iwai 	static const struct snd_ac97_bus_ops con_ops = {
14621da177e4SLinus Torvalds 		.write = snd_ice1712_ac97_write,
14631da177e4SLinus Torvalds 		.read = snd_ice1712_ac97_read,
14641da177e4SLinus Torvalds 	};
146551055da5STakashi Iwai 	static const struct snd_ac97_bus_ops pro_ops = {
14661da177e4SLinus Torvalds 		.write = snd_ice1712_pro_ac97_write,
14671da177e4SLinus Torvalds 		.read = snd_ice1712_pro_ac97_read,
14681da177e4SLinus Torvalds 	};
14691da177e4SLinus Torvalds 
14701da177e4SLinus Torvalds 	if (ice_has_con_ac97(ice)) {
14713d8cb466SAlexander Beregalov 		err = snd_ac97_bus(ice->card, bus_num++, &con_ops, NULL, &pbus);
14723d8cb466SAlexander Beregalov 		if (err < 0)
14731da177e4SLinus Torvalds 			return err;
14741da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
14751da177e4SLinus Torvalds 		ac97.private_data = ice;
14761da177e4SLinus Torvalds 		ac97.private_free = snd_ice1712_mixer_free_ac97;
14773d8cb466SAlexander Beregalov 		err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
14783d8cb466SAlexander Beregalov 		if (err < 0)
14796dfb5affSTakashi Iwai 			dev_warn(ice->card->dev,
14806dfb5affSTakashi Iwai 				 "cannot initialize ac97 for consumer, skipped\n");
14811da177e4SLinus Torvalds 		else {
1482387417b5SSudip Mukherjee 			return snd_ctl_add(ice->card,
1483387417b5SSudip Mukherjee 			snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97,
1484387417b5SSudip Mukherjee 				     ice));
14851da177e4SLinus Torvalds 		}
14861da177e4SLinus Torvalds 	}
14871da177e4SLinus Torvalds 
14881da177e4SLinus Torvalds 	if (!(ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
14893d8cb466SAlexander Beregalov 		err = snd_ac97_bus(ice->card, bus_num, &pro_ops, NULL, &pbus);
14903d8cb466SAlexander Beregalov 		if (err < 0)
14911da177e4SLinus Torvalds 			return err;
14921da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
14931da177e4SLinus Torvalds 		ac97.private_data = ice;
14941da177e4SLinus Torvalds 		ac97.private_free = snd_ice1712_mixer_free_ac97;
14953d8cb466SAlexander Beregalov 		err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
14963d8cb466SAlexander Beregalov 		if (err < 0)
14976dfb5affSTakashi Iwai 			dev_warn(ice->card->dev,
14986dfb5affSTakashi Iwai 				 "cannot initialize pro ac97, skipped\n");
14991da177e4SLinus Torvalds 		else
15001da177e4SLinus Torvalds 			return 0;
15011da177e4SLinus Torvalds 	}
15021da177e4SLinus Torvalds 	/* I2S mixer only */
15031da177e4SLinus Torvalds 	strcat(ice->card->mixername, "ICE1712 - multitrack");
15041da177e4SLinus Torvalds 	return 0;
15051da177e4SLinus Torvalds }
15061da177e4SLinus Torvalds 
15071da177e4SLinus Torvalds /*
15081da177e4SLinus Torvalds  *
15091da177e4SLinus Torvalds  */
15101da177e4SLinus Torvalds 
eeprom_double(struct snd_ice1712 * ice,int idx)15116ca308d4STakashi Iwai static inline unsigned int eeprom_double(struct snd_ice1712 *ice, int idx)
15121da177e4SLinus Torvalds {
15131da177e4SLinus Torvalds 	return (unsigned int)ice->eeprom.data[idx] | ((unsigned int)ice->eeprom.data[idx + 1] << 8);
15141da177e4SLinus Torvalds }
15151da177e4SLinus Torvalds 
snd_ice1712_proc_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)15166ca308d4STakashi Iwai static void snd_ice1712_proc_read(struct snd_info_entry *entry,
15176ca308d4STakashi Iwai 				  struct snd_info_buffer *buffer)
15181da177e4SLinus Torvalds {
15196ca308d4STakashi Iwai 	struct snd_ice1712 *ice = entry->private_data;
15201da177e4SLinus Torvalds 	unsigned int idx;
15211da177e4SLinus Torvalds 
15221da177e4SLinus Torvalds 	snd_iprintf(buffer, "%s\n\n", ice->card->longname);
15231da177e4SLinus Torvalds 	snd_iprintf(buffer, "EEPROM:\n");
15241da177e4SLinus Torvalds 
15251da177e4SLinus Torvalds 	snd_iprintf(buffer, "  Subvendor        : 0x%x\n", ice->eeprom.subvendor);
15261da177e4SLinus Torvalds 	snd_iprintf(buffer, "  Size             : %i bytes\n", ice->eeprom.size);
15271da177e4SLinus Torvalds 	snd_iprintf(buffer, "  Version          : %i\n", ice->eeprom.version);
15281da177e4SLinus Torvalds 	snd_iprintf(buffer, "  Codec            : 0x%x\n", ice->eeprom.data[ICE_EEP1_CODEC]);
15291da177e4SLinus Torvalds 	snd_iprintf(buffer, "  ACLink           : 0x%x\n", ice->eeprom.data[ICE_EEP1_ACLINK]);
15301da177e4SLinus Torvalds 	snd_iprintf(buffer, "  I2S ID           : 0x%x\n", ice->eeprom.data[ICE_EEP1_I2SID]);
15311da177e4SLinus Torvalds 	snd_iprintf(buffer, "  S/PDIF           : 0x%x\n", ice->eeprom.data[ICE_EEP1_SPDIF]);
15321da177e4SLinus Torvalds 	snd_iprintf(buffer, "  GPIO mask        : 0x%x\n", ice->eeprom.gpiomask);
15331da177e4SLinus Torvalds 	snd_iprintf(buffer, "  GPIO state       : 0x%x\n", ice->eeprom.gpiostate);
15341da177e4SLinus Torvalds 	snd_iprintf(buffer, "  GPIO direction   : 0x%x\n", ice->eeprom.gpiodir);
15351da177e4SLinus Torvalds 	snd_iprintf(buffer, "  AC'97 main       : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_MAIN_LO));
15361da177e4SLinus Torvalds 	snd_iprintf(buffer, "  AC'97 pcm        : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_PCM_LO));
15371da177e4SLinus Torvalds 	snd_iprintf(buffer, "  AC'97 record     : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_REC_LO));
15381da177e4SLinus Torvalds 	snd_iprintf(buffer, "  AC'97 record src : 0x%x\n", ice->eeprom.data[ICE_EEP1_AC97_RECSRC]);
15391da177e4SLinus Torvalds 	for (idx = 0; idx < 4; idx++)
15401da177e4SLinus Torvalds 		snd_iprintf(buffer, "  DAC ID #%i        : 0x%x\n", idx, ice->eeprom.data[ICE_EEP1_DAC_ID + idx]);
15411da177e4SLinus Torvalds 	for (idx = 0; idx < 4; idx++)
15421da177e4SLinus Torvalds 		snd_iprintf(buffer, "  ADC ID #%i        : 0x%x\n", idx, ice->eeprom.data[ICE_EEP1_ADC_ID + idx]);
15431da177e4SLinus Torvalds 	for (idx = 0x1c; idx < ice->eeprom.size; idx++)
15441da177e4SLinus Torvalds 		snd_iprintf(buffer, "  Extra #%02i        : 0x%x\n", idx, ice->eeprom.data[idx]);
15451da177e4SLinus Torvalds 
15461da177e4SLinus Torvalds 	snd_iprintf(buffer, "\nRegisters:\n");
15471da177e4SLinus Torvalds 	snd_iprintf(buffer, "  PSDOUT03         : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_PSDOUT03)));
15481da177e4SLinus Torvalds 	snd_iprintf(buffer, "  CAPTURE          : 0x%08x\n", inl(ICEMT(ice, ROUTE_CAPTURE)));
15491da177e4SLinus Torvalds 	snd_iprintf(buffer, "  SPDOUT           : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_SPDOUT)));
15501da177e4SLinus Torvalds 	snd_iprintf(buffer, "  RATE             : 0x%02x\n", (unsigned)inb(ICEMT(ice, RATE)));
1551f7004f39SJaroslav Kysela 	snd_iprintf(buffer, "  GPIO_DATA        : 0x%02x\n", (unsigned)snd_ice1712_get_gpio_data(ice));
1552f7004f39SJaroslav Kysela 	snd_iprintf(buffer, "  GPIO_WRITE_MASK  : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK));
1553f7004f39SJaroslav Kysela 	snd_iprintf(buffer, "  GPIO_DIRECTION   : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION));
15541da177e4SLinus Torvalds }
15551da177e4SLinus Torvalds 
snd_ice1712_proc_init(struct snd_ice1712 * ice)1556e23e7a14SBill Pemberton static void snd_ice1712_proc_init(struct snd_ice1712 *ice)
15571da177e4SLinus Torvalds {
155847f2769bSTakashi Iwai 	snd_card_ro_proc_new(ice->card, "ice1712", ice, snd_ice1712_proc_read);
15591da177e4SLinus Torvalds }
15601da177e4SLinus Torvalds 
15611da177e4SLinus Torvalds /*
15621da177e4SLinus Torvalds  *
15631da177e4SLinus Torvalds  */
15641da177e4SLinus Torvalds 
snd_ice1712_eeprom_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)15656ca308d4STakashi Iwai static int snd_ice1712_eeprom_info(struct snd_kcontrol *kcontrol,
15666ca308d4STakashi Iwai 				   struct snd_ctl_elem_info *uinfo)
15671da177e4SLinus Torvalds {
15681da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
15696ca308d4STakashi Iwai 	uinfo->count = sizeof(struct snd_ice1712_eeprom);
15701da177e4SLinus Torvalds 	return 0;
15711da177e4SLinus Torvalds }
15721da177e4SLinus Torvalds 
snd_ice1712_eeprom_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)15736ca308d4STakashi Iwai static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol,
15746ca308d4STakashi Iwai 				  struct snd_ctl_elem_value *ucontrol)
15751da177e4SLinus Torvalds {
15766ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
15771da177e4SLinus Torvalds 
15781da177e4SLinus Torvalds 	memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom));
15791da177e4SLinus Torvalds 	return 0;
15801da177e4SLinus Torvalds }
15811da177e4SLinus Torvalds 
1582f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_eeprom = {
15831da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
15841da177e4SLinus Torvalds 	.name = "ICE1712 EEPROM",
15851da177e4SLinus Torvalds 	.access = SNDRV_CTL_ELEM_ACCESS_READ,
15861da177e4SLinus Torvalds 	.info = snd_ice1712_eeprom_info,
15871da177e4SLinus Torvalds 	.get = snd_ice1712_eeprom_get
15881da177e4SLinus Torvalds };
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds /*
15911da177e4SLinus Torvalds  */
snd_ice1712_spdif_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)15926ca308d4STakashi Iwai static int snd_ice1712_spdif_info(struct snd_kcontrol *kcontrol,
15936ca308d4STakashi Iwai 				  struct snd_ctl_elem_info *uinfo)
15941da177e4SLinus Torvalds {
15951da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
15961da177e4SLinus Torvalds 	uinfo->count = 1;
15971da177e4SLinus Torvalds 	return 0;
15981da177e4SLinus Torvalds }
15991da177e4SLinus Torvalds 
snd_ice1712_spdif_default_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)16006ca308d4STakashi Iwai static int snd_ice1712_spdif_default_get(struct snd_kcontrol *kcontrol,
16016ca308d4STakashi Iwai 					 struct snd_ctl_elem_value *ucontrol)
16021da177e4SLinus Torvalds {
16036ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
16041da177e4SLinus Torvalds 	if (ice->spdif.ops.default_get)
16051da177e4SLinus Torvalds 		ice->spdif.ops.default_get(ice, ucontrol);
16061da177e4SLinus Torvalds 	return 0;
16071da177e4SLinus Torvalds }
16081da177e4SLinus Torvalds 
snd_ice1712_spdif_default_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)16096ca308d4STakashi Iwai static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol,
16106ca308d4STakashi Iwai 					 struct snd_ctl_elem_value *ucontrol)
16111da177e4SLinus Torvalds {
16126ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
16131da177e4SLinus Torvalds 	if (ice->spdif.ops.default_put)
16141da177e4SLinus Torvalds 		return ice->spdif.ops.default_put(ice, ucontrol);
16151da177e4SLinus Torvalds 	return 0;
16161da177e4SLinus Torvalds }
16171da177e4SLinus Torvalds 
1618f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_spdif_default =
16191da177e4SLinus Torvalds {
16201da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
16211da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
16221da177e4SLinus Torvalds 	.info =		snd_ice1712_spdif_info,
16231da177e4SLinus Torvalds 	.get =		snd_ice1712_spdif_default_get,
16241da177e4SLinus Torvalds 	.put =		snd_ice1712_spdif_default_put
16251da177e4SLinus Torvalds };
16261da177e4SLinus Torvalds 
snd_ice1712_spdif_maskc_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)16276ca308d4STakashi Iwai static int snd_ice1712_spdif_maskc_get(struct snd_kcontrol *kcontrol,
16286ca308d4STakashi Iwai 				       struct snd_ctl_elem_value *ucontrol)
16291da177e4SLinus Torvalds {
16306ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
16311da177e4SLinus Torvalds 	if (ice->spdif.ops.default_get) {
16321da177e4SLinus Torvalds 		ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO |
16331da177e4SLinus Torvalds 						     IEC958_AES0_PROFESSIONAL |
16341da177e4SLinus Torvalds 						     IEC958_AES0_CON_NOT_COPYRIGHT |
16351da177e4SLinus Torvalds 						     IEC958_AES0_CON_EMPHASIS;
16361da177e4SLinus Torvalds 		ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL |
16371da177e4SLinus Torvalds 						     IEC958_AES1_CON_CATEGORY;
16381da177e4SLinus Torvalds 		ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
16391da177e4SLinus Torvalds 	} else {
16401da177e4SLinus Torvalds 		ucontrol->value.iec958.status[0] = 0xff;
16411da177e4SLinus Torvalds 		ucontrol->value.iec958.status[1] = 0xff;
16421da177e4SLinus Torvalds 		ucontrol->value.iec958.status[2] = 0xff;
16431da177e4SLinus Torvalds 		ucontrol->value.iec958.status[3] = 0xff;
16441da177e4SLinus Torvalds 		ucontrol->value.iec958.status[4] = 0xff;
16451da177e4SLinus Torvalds 	}
16461da177e4SLinus Torvalds 	return 0;
16471da177e4SLinus Torvalds }
16481da177e4SLinus Torvalds 
snd_ice1712_spdif_maskp_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)16496ca308d4STakashi Iwai static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol,
16506ca308d4STakashi Iwai 				       struct snd_ctl_elem_value *ucontrol)
16511da177e4SLinus Torvalds {
16526ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
16531da177e4SLinus Torvalds 	if (ice->spdif.ops.default_get) {
16541da177e4SLinus Torvalds 		ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO |
16551da177e4SLinus Torvalds 						     IEC958_AES0_PROFESSIONAL |
16561da177e4SLinus Torvalds 						     IEC958_AES0_PRO_FS |
16571da177e4SLinus Torvalds 						     IEC958_AES0_PRO_EMPHASIS;
16581da177e4SLinus Torvalds 		ucontrol->value.iec958.status[1] = IEC958_AES1_PRO_MODE;
16591da177e4SLinus Torvalds 	} else {
16601da177e4SLinus Torvalds 		ucontrol->value.iec958.status[0] = 0xff;
16611da177e4SLinus Torvalds 		ucontrol->value.iec958.status[1] = 0xff;
16621da177e4SLinus Torvalds 		ucontrol->value.iec958.status[2] = 0xff;
16631da177e4SLinus Torvalds 		ucontrol->value.iec958.status[3] = 0xff;
16641da177e4SLinus Torvalds 		ucontrol->value.iec958.status[4] = 0xff;
16651da177e4SLinus Torvalds 	}
16661da177e4SLinus Torvalds 	return 0;
16671da177e4SLinus Torvalds }
16681da177e4SLinus Torvalds 
1669f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_spdif_maskc =
16701da177e4SLinus Torvalds {
16711da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
167267ed4161SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
16731da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
16741da177e4SLinus Torvalds 	.info =		snd_ice1712_spdif_info,
16751da177e4SLinus Torvalds 	.get =		snd_ice1712_spdif_maskc_get,
16761da177e4SLinus Torvalds };
16771da177e4SLinus Torvalds 
1678f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_spdif_maskp =
16791da177e4SLinus Torvalds {
16801da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
168167ed4161SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
16821da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
16831da177e4SLinus Torvalds 	.info =		snd_ice1712_spdif_info,
16841da177e4SLinus Torvalds 	.get =		snd_ice1712_spdif_maskp_get,
16851da177e4SLinus Torvalds };
16861da177e4SLinus Torvalds 
snd_ice1712_spdif_stream_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)16876ca308d4STakashi Iwai static int snd_ice1712_spdif_stream_get(struct snd_kcontrol *kcontrol,
16886ca308d4STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16891da177e4SLinus Torvalds {
16906ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
16911da177e4SLinus Torvalds 	if (ice->spdif.ops.stream_get)
16921da177e4SLinus Torvalds 		ice->spdif.ops.stream_get(ice, ucontrol);
16931da177e4SLinus Torvalds 	return 0;
16941da177e4SLinus Torvalds }
16951da177e4SLinus Torvalds 
snd_ice1712_spdif_stream_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)16966ca308d4STakashi Iwai static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol,
16976ca308d4STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16981da177e4SLinus Torvalds {
16996ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
17001da177e4SLinus Torvalds 	if (ice->spdif.ops.stream_put)
17011da177e4SLinus Torvalds 		return ice->spdif.ops.stream_put(ice, ucontrol);
17021da177e4SLinus Torvalds 	return 0;
17031da177e4SLinus Torvalds }
17041da177e4SLinus Torvalds 
1705f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_spdif_stream =
17061da177e4SLinus Torvalds {
17076ca308d4STakashi Iwai 	.access =	(SNDRV_CTL_ELEM_ACCESS_READWRITE |
17086ca308d4STakashi Iwai 			 SNDRV_CTL_ELEM_ACCESS_INACTIVE),
17091da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
17101da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
17111da177e4SLinus Torvalds 	.info =		snd_ice1712_spdif_info,
17121da177e4SLinus Torvalds 	.get =		snd_ice1712_spdif_stream_get,
17131da177e4SLinus Torvalds 	.put =		snd_ice1712_spdif_stream_put
17141da177e4SLinus Torvalds };
17151da177e4SLinus Torvalds 
snd_ice1712_gpio_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)17166ca308d4STakashi Iwai int snd_ice1712_gpio_get(struct snd_kcontrol *kcontrol,
17176ca308d4STakashi Iwai 			 struct snd_ctl_elem_value *ucontrol)
17181da177e4SLinus Torvalds {
17196ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
17201da177e4SLinus Torvalds 	unsigned char mask = kcontrol->private_value & 0xff;
17211da177e4SLinus Torvalds 	int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0;
17221da177e4SLinus Torvalds 
17231da177e4SLinus Torvalds 	snd_ice1712_save_gpio_status(ice);
17246ca308d4STakashi Iwai 	ucontrol->value.integer.value[0] =
17256ca308d4STakashi Iwai 		(snd_ice1712_gpio_read(ice) & mask ? 1 : 0) ^ invert;
17261da177e4SLinus Torvalds 	snd_ice1712_restore_gpio_status(ice);
17271da177e4SLinus Torvalds 	return 0;
17281da177e4SLinus Torvalds }
17291da177e4SLinus Torvalds 
snd_ice1712_gpio_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)17306ca308d4STakashi Iwai int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol,
17316ca308d4STakashi Iwai 			 struct snd_ctl_elem_value *ucontrol)
17321da177e4SLinus Torvalds {
17336ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
17341da177e4SLinus Torvalds 	unsigned char mask = kcontrol->private_value & 0xff;
17351da177e4SLinus Torvalds 	int invert = (kcontrol->private_value & (1<<24)) ? mask : 0;
17361da177e4SLinus Torvalds 	unsigned int val, nval;
17371da177e4SLinus Torvalds 
17381da177e4SLinus Torvalds 	if (kcontrol->private_value & (1 << 31))
17391da177e4SLinus Torvalds 		return -EPERM;
17401da177e4SLinus Torvalds 	nval = (ucontrol->value.integer.value[0] ? mask : 0) ^ invert;
17411da177e4SLinus Torvalds 	snd_ice1712_save_gpio_status(ice);
17421da177e4SLinus Torvalds 	val = snd_ice1712_gpio_read(ice);
17431da177e4SLinus Torvalds 	nval |= val & ~mask;
17441da177e4SLinus Torvalds 	if (val != nval)
17451da177e4SLinus Torvalds 		snd_ice1712_gpio_write(ice, nval);
17461da177e4SLinus Torvalds 	snd_ice1712_restore_gpio_status(ice);
17471da177e4SLinus Torvalds 	return val != nval;
17481da177e4SLinus Torvalds }
17491da177e4SLinus Torvalds 
17501da177e4SLinus Torvalds /*
17511da177e4SLinus Torvalds  *  rate
17521da177e4SLinus Torvalds  */
snd_ice1712_pro_internal_clock_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)17536ca308d4STakashi Iwai static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
17546ca308d4STakashi Iwai 					       struct snd_ctl_elem_info *uinfo)
17551da177e4SLinus Torvalds {
175632b47da0STakashi Iwai 	static const char * const texts[] = {
17571da177e4SLinus Torvalds 		"8000",		/* 0: 6 */
17581da177e4SLinus Torvalds 		"9600",		/* 1: 3 */
17591da177e4SLinus Torvalds 		"11025",	/* 2: 10 */
17601da177e4SLinus Torvalds 		"12000",	/* 3: 2 */
17611da177e4SLinus Torvalds 		"16000",	/* 4: 5 */
17621da177e4SLinus Torvalds 		"22050",	/* 5: 9 */
17631da177e4SLinus Torvalds 		"24000",	/* 6: 1 */
17641da177e4SLinus Torvalds 		"32000",	/* 7: 4 */
17651da177e4SLinus Torvalds 		"44100",	/* 8: 8 */
17661da177e4SLinus Torvalds 		"48000",	/* 9: 0 */
17671da177e4SLinus Torvalds 		"64000",	/* 10: 15 */
17681da177e4SLinus Torvalds 		"88200",	/* 11: 11 */
17691da177e4SLinus Torvalds 		"96000",	/* 12: 7 */
17701da177e4SLinus Torvalds 		"IEC958 Input",	/* 13: -- */
17711da177e4SLinus Torvalds 	};
1772c4fa251fSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 14, texts);
17731da177e4SLinus Torvalds }
17741da177e4SLinus Torvalds 
snd_ice1712_pro_internal_clock_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)17756ca308d4STakashi Iwai static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
17766ca308d4STakashi Iwai 					      struct snd_ctl_elem_value *ucontrol)
17771da177e4SLinus Torvalds {
17786ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
177932b47da0STakashi Iwai 	static const unsigned char xlate[16] = {
17801da177e4SLinus Torvalds 		9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10
17811da177e4SLinus Torvalds 	};
17821da177e4SLinus Torvalds 	unsigned char val;
17831da177e4SLinus Torvalds 
17841da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
17851da177e4SLinus Torvalds 	if (is_spdif_master(ice)) {
17861da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 13;
17871da177e4SLinus Torvalds 	} else {
17881da177e4SLinus Torvalds 		val = xlate[inb(ICEMT(ice, RATE)) & 15];
17891da177e4SLinus Torvalds 		if (val == 255) {
17901da177e4SLinus Torvalds 			snd_BUG();
17911da177e4SLinus Torvalds 			val = 0;
17921da177e4SLinus Torvalds 		}
17931da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = val;
17941da177e4SLinus Torvalds 	}
17951da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
17961da177e4SLinus Torvalds 	return 0;
17971da177e4SLinus Torvalds }
17981da177e4SLinus Torvalds 
snd_ice1712_pro_internal_clock_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)17996ca308d4STakashi Iwai static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
18006ca308d4STakashi Iwai 					      struct snd_ctl_elem_value *ucontrol)
18011da177e4SLinus Torvalds {
18026ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
180332b47da0STakashi Iwai 	static const unsigned int xrate[13] = {
1804fe25befdSJaroslav Kysela 		8000, 9600, 11025, 12000, 16000, 22050, 24000,
18051da177e4SLinus Torvalds 		32000, 44100, 48000, 64000, 88200, 96000
18061da177e4SLinus Torvalds 	};
18071da177e4SLinus Torvalds 	unsigned char oval;
18081da177e4SLinus Torvalds 	int change = 0;
18091da177e4SLinus Torvalds 
18101da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
18111da177e4SLinus Torvalds 	oval = inb(ICEMT(ice, RATE));
18121da177e4SLinus Torvalds 	if (ucontrol->value.enumerated.item[0] == 13) {
18131da177e4SLinus Torvalds 		outb(oval | ICE1712_SPDIF_MASTER, ICEMT(ice, RATE));
18141da177e4SLinus Torvalds 	} else {
18151da177e4SLinus Torvalds 		PRO_RATE_DEFAULT = xrate[ucontrol->value.integer.value[0] % 13];
18161da177e4SLinus Torvalds 		spin_unlock_irq(&ice->reg_lock);
18171da177e4SLinus Torvalds 		snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 1);
18181da177e4SLinus Torvalds 		spin_lock_irq(&ice->reg_lock);
18191da177e4SLinus Torvalds 	}
18201da177e4SLinus Torvalds 	change = inb(ICEMT(ice, RATE)) != oval;
18211da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
18221da177e4SLinus Torvalds 
18236ca308d4STakashi Iwai 	if ((oval & ICE1712_SPDIF_MASTER) !=
1824e957ebf1SJaroslav Kysela 	    (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER))
1825e957ebf1SJaroslav Kysela 		snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice));
18261da177e4SLinus Torvalds 
18271da177e4SLinus Torvalds 	return change;
18281da177e4SLinus Torvalds }
18291da177e4SLinus Torvalds 
1830f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock = {
18311da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
18321da177e4SLinus Torvalds 	.name = "Multi Track Internal Clock",
18331da177e4SLinus Torvalds 	.info = snd_ice1712_pro_internal_clock_info,
18341da177e4SLinus Torvalds 	.get = snd_ice1712_pro_internal_clock_get,
18351da177e4SLinus Torvalds 	.put = snd_ice1712_pro_internal_clock_put
18361da177e4SLinus Torvalds };
18371da177e4SLinus Torvalds 
snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)18386ca308d4STakashi Iwai static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcontrol,
18396ca308d4STakashi Iwai 						       struct snd_ctl_elem_info *uinfo)
18401da177e4SLinus Torvalds {
184132b47da0STakashi Iwai 	static const char * const texts[] = {
18421da177e4SLinus Torvalds 		"8000",		/* 0: 6 */
18431da177e4SLinus Torvalds 		"9600",		/* 1: 3 */
18441da177e4SLinus Torvalds 		"11025",	/* 2: 10 */
18451da177e4SLinus Torvalds 		"12000",	/* 3: 2 */
18461da177e4SLinus Torvalds 		"16000",	/* 4: 5 */
18471da177e4SLinus Torvalds 		"22050",	/* 5: 9 */
18481da177e4SLinus Torvalds 		"24000",	/* 6: 1 */
18491da177e4SLinus Torvalds 		"32000",	/* 7: 4 */
18501da177e4SLinus Torvalds 		"44100",	/* 8: 8 */
18511da177e4SLinus Torvalds 		"48000",	/* 9: 0 */
18521da177e4SLinus Torvalds 		"64000",	/* 10: 15 */
18531da177e4SLinus Torvalds 		"88200",	/* 11: 11 */
18541da177e4SLinus Torvalds 		"96000",	/* 12: 7 */
18553d8cb466SAlexander Beregalov 		/* "IEC958 Input",	13: -- */
18561da177e4SLinus Torvalds 	};
1857c4fa251fSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 13, texts);
18581da177e4SLinus Torvalds }
18591da177e4SLinus Torvalds 
snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)18606ca308d4STakashi Iwai static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcontrol,
18616ca308d4STakashi Iwai 						      struct snd_ctl_elem_value *ucontrol)
18621da177e4SLinus Torvalds {
18631da177e4SLinus Torvalds 	int val;
186432b47da0STakashi Iwai 	static const unsigned int xrate[13] = {
1865fe25befdSJaroslav Kysela 		8000, 9600, 11025, 12000, 16000, 22050, 24000,
18661da177e4SLinus Torvalds 		32000, 44100, 48000, 64000, 88200, 96000
18671da177e4SLinus Torvalds 	};
18681da177e4SLinus Torvalds 
18691da177e4SLinus Torvalds 	for (val = 0; val < 13; val++) {
18701da177e4SLinus Torvalds 		if (xrate[val] == PRO_RATE_DEFAULT)
18711da177e4SLinus Torvalds 			break;
18721da177e4SLinus Torvalds 	}
18731da177e4SLinus Torvalds 
18741da177e4SLinus Torvalds 	ucontrol->value.enumerated.item[0] = val;
18751da177e4SLinus Torvalds 	return 0;
18761da177e4SLinus Torvalds }
18771da177e4SLinus Torvalds 
snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)18786ca308d4STakashi Iwai static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcontrol,
18796ca308d4STakashi Iwai 						      struct snd_ctl_elem_value *ucontrol)
18801da177e4SLinus Torvalds {
188132b47da0STakashi Iwai 	static const unsigned int xrate[13] = {
1882fe25befdSJaroslav Kysela 		8000, 9600, 11025, 12000, 16000, 22050, 24000,
18831da177e4SLinus Torvalds 		32000, 44100, 48000, 64000, 88200, 96000
18841da177e4SLinus Torvalds 	};
18851da177e4SLinus Torvalds 	unsigned char oval;
18861da177e4SLinus Torvalds 	int change = 0;
18871da177e4SLinus Torvalds 
18881da177e4SLinus Torvalds 	oval = PRO_RATE_DEFAULT;
18891da177e4SLinus Torvalds 	PRO_RATE_DEFAULT = xrate[ucontrol->value.integer.value[0] % 13];
18901da177e4SLinus Torvalds 	change = PRO_RATE_DEFAULT != oval;
18911da177e4SLinus Torvalds 
18921da177e4SLinus Torvalds 	return change;
18931da177e4SLinus Torvalds }
18941da177e4SLinus Torvalds 
1895f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default = {
18961da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
18971da177e4SLinus Torvalds 	.name = "Multi Track Internal Clock Default",
18981da177e4SLinus Torvalds 	.info = snd_ice1712_pro_internal_clock_default_info,
18991da177e4SLinus Torvalds 	.get = snd_ice1712_pro_internal_clock_default_get,
19001da177e4SLinus Torvalds 	.put = snd_ice1712_pro_internal_clock_default_put
19011da177e4SLinus Torvalds };
19021da177e4SLinus Torvalds 
1903a5ce8890STakashi Iwai #define snd_ice1712_pro_rate_locking_info	snd_ctl_boolean_mono_info
19041da177e4SLinus Torvalds 
snd_ice1712_pro_rate_locking_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)19056ca308d4STakashi Iwai static int snd_ice1712_pro_rate_locking_get(struct snd_kcontrol *kcontrol,
19066ca308d4STakashi Iwai 					    struct snd_ctl_elem_value *ucontrol)
19071da177e4SLinus Torvalds {
19081da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = PRO_RATE_LOCKED;
19091da177e4SLinus Torvalds 	return 0;
19101da177e4SLinus Torvalds }
19111da177e4SLinus Torvalds 
snd_ice1712_pro_rate_locking_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)19126ca308d4STakashi Iwai static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
19136ca308d4STakashi Iwai 					    struct snd_ctl_elem_value *ucontrol)
19141da177e4SLinus Torvalds {
19156ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
19161da177e4SLinus Torvalds 	int change = 0, nval;
19171da177e4SLinus Torvalds 
19181da177e4SLinus Torvalds 	nval = ucontrol->value.integer.value[0] ? 1 : 0;
19191da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
19201da177e4SLinus Torvalds 	change = PRO_RATE_LOCKED != nval;
19211da177e4SLinus Torvalds 	PRO_RATE_LOCKED = nval;
19221da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
19231da177e4SLinus Torvalds 	return change;
19241da177e4SLinus Torvalds }
19251da177e4SLinus Torvalds 
1926f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_pro_rate_locking = {
19271da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
19281da177e4SLinus Torvalds 	.name = "Multi Track Rate Locking",
19291da177e4SLinus Torvalds 	.info = snd_ice1712_pro_rate_locking_info,
19301da177e4SLinus Torvalds 	.get = snd_ice1712_pro_rate_locking_get,
19311da177e4SLinus Torvalds 	.put = snd_ice1712_pro_rate_locking_put
19321da177e4SLinus Torvalds };
19331da177e4SLinus Torvalds 
1934a5ce8890STakashi Iwai #define snd_ice1712_pro_rate_reset_info		snd_ctl_boolean_mono_info
19351da177e4SLinus Torvalds 
snd_ice1712_pro_rate_reset_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)19366ca308d4STakashi Iwai static int snd_ice1712_pro_rate_reset_get(struct snd_kcontrol *kcontrol,
19376ca308d4STakashi Iwai 					  struct snd_ctl_elem_value *ucontrol)
19381da177e4SLinus Torvalds {
19391da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = PRO_RATE_RESET;
19401da177e4SLinus Torvalds 	return 0;
19411da177e4SLinus Torvalds }
19421da177e4SLinus Torvalds 
snd_ice1712_pro_rate_reset_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)19436ca308d4STakashi Iwai static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
19446ca308d4STakashi Iwai 					  struct snd_ctl_elem_value *ucontrol)
19451da177e4SLinus Torvalds {
19466ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
19471da177e4SLinus Torvalds 	int change = 0, nval;
19481da177e4SLinus Torvalds 
19491da177e4SLinus Torvalds 	nval = ucontrol->value.integer.value[0] ? 1 : 0;
19501da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
19511da177e4SLinus Torvalds 	change = PRO_RATE_RESET != nval;
19521da177e4SLinus Torvalds 	PRO_RATE_RESET = nval;
19531da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
19541da177e4SLinus Torvalds 	return change;
19551da177e4SLinus Torvalds }
19561da177e4SLinus Torvalds 
1957f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_pro_rate_reset = {
19581da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
19591da177e4SLinus Torvalds 	.name = "Multi Track Rate Reset",
19601da177e4SLinus Torvalds 	.info = snd_ice1712_pro_rate_reset_info,
19611da177e4SLinus Torvalds 	.get = snd_ice1712_pro_rate_reset_get,
19621da177e4SLinus Torvalds 	.put = snd_ice1712_pro_rate_reset_put
19631da177e4SLinus Torvalds };
19641da177e4SLinus Torvalds 
19651da177e4SLinus Torvalds /*
19661da177e4SLinus Torvalds  * routing
19671da177e4SLinus Torvalds  */
snd_ice1712_pro_route_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)19686ca308d4STakashi Iwai static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol,
19696ca308d4STakashi Iwai 				      struct snd_ctl_elem_info *uinfo)
19701da177e4SLinus Torvalds {
197132b47da0STakashi Iwai 	static const char * const texts[] = {
19721da177e4SLinus Torvalds 		"PCM Out", /* 0 */
19731da177e4SLinus Torvalds 		"H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */
19741da177e4SLinus Torvalds 		"H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */
19751da177e4SLinus Torvalds 		"IEC958 In L", "IEC958 In R", /* 9-10 */
19761da177e4SLinus Torvalds 		"Digital Mixer", /* 11 - optional */
19771da177e4SLinus Torvalds 	};
1978c4fa251fSTakashi Iwai 	int num_items = snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11;
1979c4fa251fSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, num_items, texts);
19801da177e4SLinus Torvalds }
19811da177e4SLinus Torvalds 
snd_ice1712_pro_route_analog_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)19826ca308d4STakashi Iwai static int snd_ice1712_pro_route_analog_get(struct snd_kcontrol *kcontrol,
19836ca308d4STakashi Iwai 					    struct snd_ctl_elem_value *ucontrol)
19841da177e4SLinus Torvalds {
19856ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
19861da177e4SLinus Torvalds 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
19871da177e4SLinus Torvalds 	unsigned int val, cval;
19881da177e4SLinus Torvalds 
19891da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
19901da177e4SLinus Torvalds 	val = inw(ICEMT(ice, ROUTE_PSDOUT03));
19911da177e4SLinus Torvalds 	cval = inl(ICEMT(ice, ROUTE_CAPTURE));
19921da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 	val >>= ((idx % 2) * 8) + ((idx / 2) * 2);
19951da177e4SLinus Torvalds 	val &= 3;
19961da177e4SLinus Torvalds 	cval >>= ((idx / 2) * 8) + ((idx % 2) * 4);
19971da177e4SLinus Torvalds 	if (val == 1 && idx < 2)
19981da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 11;
19991da177e4SLinus Torvalds 	else if (val == 2)
20001da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = (cval & 7) + 1;
20011da177e4SLinus Torvalds 	else if (val == 3)
20021da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = ((cval >> 3) & 1) + 9;
20031da177e4SLinus Torvalds 	else
20041da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
20051da177e4SLinus Torvalds 	return 0;
20061da177e4SLinus Torvalds }
20071da177e4SLinus Torvalds 
snd_ice1712_pro_route_analog_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)20086ca308d4STakashi Iwai static int snd_ice1712_pro_route_analog_put(struct snd_kcontrol *kcontrol,
20096ca308d4STakashi Iwai 					    struct snd_ctl_elem_value *ucontrol)
20101da177e4SLinus Torvalds {
20116ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
20121da177e4SLinus Torvalds 	int change, shift;
20131da177e4SLinus Torvalds 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
20141da177e4SLinus Torvalds 	unsigned int val, old_val, nval;
20151da177e4SLinus Torvalds 
20161da177e4SLinus Torvalds 	/* update PSDOUT */
20171da177e4SLinus Torvalds 	if (ucontrol->value.enumerated.item[0] >= 11)
20181da177e4SLinus Torvalds 		nval = idx < 2 ? 1 : 0; /* dig mixer (or pcm) */
20191da177e4SLinus Torvalds 	else if (ucontrol->value.enumerated.item[0] >= 9)
20201da177e4SLinus Torvalds 		nval = 3; /* spdif in */
20211da177e4SLinus Torvalds 	else if (ucontrol->value.enumerated.item[0] >= 1)
20221da177e4SLinus Torvalds 		nval = 2; /* analog in */
20231da177e4SLinus Torvalds 	else
20241da177e4SLinus Torvalds 		nval = 0; /* pcm */
20251da177e4SLinus Torvalds 	shift = ((idx % 2) * 8) + ((idx / 2) * 2);
20261da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
20271da177e4SLinus Torvalds 	val = old_val = inw(ICEMT(ice, ROUTE_PSDOUT03));
20281da177e4SLinus Torvalds 	val &= ~(0x03 << shift);
20291da177e4SLinus Torvalds 	val |= nval << shift;
20301da177e4SLinus Torvalds 	change = val != old_val;
20311da177e4SLinus Torvalds 	if (change)
20321da177e4SLinus Torvalds 		outw(val, ICEMT(ice, ROUTE_PSDOUT03));
20331da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
20341da177e4SLinus Torvalds 	if (nval < 2) /* dig mixer of pcm */
20351da177e4SLinus Torvalds 		return change;
20361da177e4SLinus Torvalds 
20371da177e4SLinus Torvalds 	/* update CAPTURE */
20381da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
20391da177e4SLinus Torvalds 	val = old_val = inl(ICEMT(ice, ROUTE_CAPTURE));
20401da177e4SLinus Torvalds 	shift = ((idx / 2) * 8) + ((idx % 2) * 4);
20411da177e4SLinus Torvalds 	if (nval == 2) { /* analog in */
20421da177e4SLinus Torvalds 		nval = ucontrol->value.enumerated.item[0] - 1;
20431da177e4SLinus Torvalds 		val &= ~(0x07 << shift);
20441da177e4SLinus Torvalds 		val |= nval << shift;
20451da177e4SLinus Torvalds 	} else { /* spdif in */
20461da177e4SLinus Torvalds 		nval = (ucontrol->value.enumerated.item[0] - 9) << 3;
20471da177e4SLinus Torvalds 		val &= ~(0x08 << shift);
20481da177e4SLinus Torvalds 		val |= nval << shift;
20491da177e4SLinus Torvalds 	}
20501da177e4SLinus Torvalds 	if (val != old_val) {
20511da177e4SLinus Torvalds 		change = 1;
20521da177e4SLinus Torvalds 		outl(val, ICEMT(ice, ROUTE_CAPTURE));
20531da177e4SLinus Torvalds 	}
20541da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
20551da177e4SLinus Torvalds 	return change;
20561da177e4SLinus Torvalds }
20571da177e4SLinus Torvalds 
snd_ice1712_pro_route_spdif_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)20586ca308d4STakashi Iwai static int snd_ice1712_pro_route_spdif_get(struct snd_kcontrol *kcontrol,
20596ca308d4STakashi Iwai 					   struct snd_ctl_elem_value *ucontrol)
20601da177e4SLinus Torvalds {
20616ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
20621da177e4SLinus Torvalds 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
20631da177e4SLinus Torvalds 	unsigned int val, cval;
20641da177e4SLinus Torvalds 	val = inw(ICEMT(ice, ROUTE_SPDOUT));
20651da177e4SLinus Torvalds 	cval = (val >> (idx * 4 + 8)) & 0x0f;
20661da177e4SLinus Torvalds 	val = (val >> (idx * 2)) & 0x03;
20671da177e4SLinus Torvalds 	if (val == 1)
20681da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 11;
20691da177e4SLinus Torvalds 	else if (val == 2)
20701da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = (cval & 7) + 1;
20711da177e4SLinus Torvalds 	else if (val == 3)
20721da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = ((cval >> 3) & 1) + 9;
20731da177e4SLinus Torvalds 	else
20741da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
20751da177e4SLinus Torvalds 	return 0;
20761da177e4SLinus Torvalds }
20771da177e4SLinus Torvalds 
snd_ice1712_pro_route_spdif_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)20786ca308d4STakashi Iwai static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
20796ca308d4STakashi Iwai 					   struct snd_ctl_elem_value *ucontrol)
20801da177e4SLinus Torvalds {
20816ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
20821da177e4SLinus Torvalds 	int change, shift;
20831da177e4SLinus Torvalds 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
20841da177e4SLinus Torvalds 	unsigned int val, old_val, nval;
20851da177e4SLinus Torvalds 
20861da177e4SLinus Torvalds 	/* update SPDOUT */
20871da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
20881da177e4SLinus Torvalds 	val = old_val = inw(ICEMT(ice, ROUTE_SPDOUT));
20891da177e4SLinus Torvalds 	if (ucontrol->value.enumerated.item[0] >= 11)
20901da177e4SLinus Torvalds 		nval = 1;
20911da177e4SLinus Torvalds 	else if (ucontrol->value.enumerated.item[0] >= 9)
20921da177e4SLinus Torvalds 		nval = 3;
20931da177e4SLinus Torvalds 	else if (ucontrol->value.enumerated.item[0] >= 1)
20941da177e4SLinus Torvalds 		nval = 2;
20951da177e4SLinus Torvalds 	else
20961da177e4SLinus Torvalds 		nval = 0;
20971da177e4SLinus Torvalds 	shift = idx * 2;
20981da177e4SLinus Torvalds 	val &= ~(0x03 << shift);
20991da177e4SLinus Torvalds 	val |= nval << shift;
21001da177e4SLinus Torvalds 	shift = idx * 4 + 8;
21011da177e4SLinus Torvalds 	if (nval == 2) {
21021da177e4SLinus Torvalds 		nval = ucontrol->value.enumerated.item[0] - 1;
21031da177e4SLinus Torvalds 		val &= ~(0x07 << shift);
21041da177e4SLinus Torvalds 		val |= nval << shift;
21051da177e4SLinus Torvalds 	} else if (nval == 3) {
21061da177e4SLinus Torvalds 		nval = (ucontrol->value.enumerated.item[0] - 9) << 3;
21071da177e4SLinus Torvalds 		val &= ~(0x08 << shift);
21081da177e4SLinus Torvalds 		val |= nval << shift;
21091da177e4SLinus Torvalds 	}
21101da177e4SLinus Torvalds 	change = val != old_val;
21111da177e4SLinus Torvalds 	if (change)
21121da177e4SLinus Torvalds 		outw(val, ICEMT(ice, ROUTE_SPDOUT));
21131da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
21141da177e4SLinus Torvalds 	return change;
21151da177e4SLinus Torvalds }
21161da177e4SLinus Torvalds 
21176ba1ad38SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route = {
21181da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
21191da177e4SLinus Torvalds 	.name = "H/W Playback Route",
21201da177e4SLinus Torvalds 	.info = snd_ice1712_pro_route_info,
21211da177e4SLinus Torvalds 	.get = snd_ice1712_pro_route_analog_get,
21221da177e4SLinus Torvalds 	.put = snd_ice1712_pro_route_analog_put,
21231da177e4SLinus Torvalds };
21241da177e4SLinus Torvalds 
2125f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route = {
21261da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
212710e8d78aSClemens Ladisch 	.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route",
21281da177e4SLinus Torvalds 	.info = snd_ice1712_pro_route_info,
21291da177e4SLinus Torvalds 	.get = snd_ice1712_pro_route_spdif_get,
21301da177e4SLinus Torvalds 	.put = snd_ice1712_pro_route_spdif_put,
21311da177e4SLinus Torvalds 	.count = 2,
21321da177e4SLinus Torvalds };
21331da177e4SLinus Torvalds 
21341da177e4SLinus Torvalds 
snd_ice1712_pro_volume_rate_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)21356ca308d4STakashi Iwai static int snd_ice1712_pro_volume_rate_info(struct snd_kcontrol *kcontrol,
21366ca308d4STakashi Iwai 					    struct snd_ctl_elem_info *uinfo)
21371da177e4SLinus Torvalds {
21381da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
21391da177e4SLinus Torvalds 	uinfo->count = 1;
21401da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
21411da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
21421da177e4SLinus Torvalds 	return 0;
21431da177e4SLinus Torvalds }
21441da177e4SLinus Torvalds 
snd_ice1712_pro_volume_rate_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)21456ca308d4STakashi Iwai static int snd_ice1712_pro_volume_rate_get(struct snd_kcontrol *kcontrol,
21466ca308d4STakashi Iwai 					   struct snd_ctl_elem_value *ucontrol)
21471da177e4SLinus Torvalds {
21486ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
21491da177e4SLinus Torvalds 
21501da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_RATE));
21511da177e4SLinus Torvalds 	return 0;
21521da177e4SLinus Torvalds }
21531da177e4SLinus Torvalds 
snd_ice1712_pro_volume_rate_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)21546ca308d4STakashi Iwai static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol,
21556ca308d4STakashi Iwai 					   struct snd_ctl_elem_value *ucontrol)
21561da177e4SLinus Torvalds {
21576ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
21581da177e4SLinus Torvalds 	int change;
21591da177e4SLinus Torvalds 
21601da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
21611da177e4SLinus Torvalds 	change = inb(ICEMT(ice, MONITOR_RATE)) != ucontrol->value.integer.value[0];
21621da177e4SLinus Torvalds 	outb(ucontrol->value.integer.value[0], ICEMT(ice, MONITOR_RATE));
21631da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
21641da177e4SLinus Torvalds 	return change;
21651da177e4SLinus Torvalds }
21661da177e4SLinus Torvalds 
2167f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate = {
21681da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
21691da177e4SLinus Torvalds 	.name = "Multi Track Volume Rate",
21701da177e4SLinus Torvalds 	.info = snd_ice1712_pro_volume_rate_info,
21711da177e4SLinus Torvalds 	.get = snd_ice1712_pro_volume_rate_get,
21721da177e4SLinus Torvalds 	.put = snd_ice1712_pro_volume_rate_put
21731da177e4SLinus Torvalds };
21741da177e4SLinus Torvalds 
snd_ice1712_pro_peak_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)21756ca308d4STakashi Iwai static int snd_ice1712_pro_peak_info(struct snd_kcontrol *kcontrol,
21766ca308d4STakashi Iwai 				     struct snd_ctl_elem_info *uinfo)
21771da177e4SLinus Torvalds {
21781da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
21791da177e4SLinus Torvalds 	uinfo->count = 22;
21801da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
21811da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
21821da177e4SLinus Torvalds 	return 0;
21831da177e4SLinus Torvalds }
21841da177e4SLinus Torvalds 
snd_ice1712_pro_peak_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)21856ca308d4STakashi Iwai static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol,
21866ca308d4STakashi Iwai 				    struct snd_ctl_elem_value *ucontrol)
21871da177e4SLinus Torvalds {
21886ca308d4STakashi Iwai 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
21891da177e4SLinus Torvalds 	int idx;
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds 	spin_lock_irq(&ice->reg_lock);
21921da177e4SLinus Torvalds 	for (idx = 0; idx < 22; idx++) {
21931da177e4SLinus Torvalds 		outb(idx, ICEMT(ice, MONITOR_PEAKINDEX));
21941da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = inb(ICEMT(ice, MONITOR_PEAKDATA));
21951da177e4SLinus Torvalds 	}
21961da177e4SLinus Torvalds 	spin_unlock_irq(&ice->reg_lock);
21971da177e4SLinus Torvalds 	return 0;
21981da177e4SLinus Torvalds }
21991da177e4SLinus Torvalds 
2200f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak = {
22012bdf6633SPavel Hofman 	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
22021da177e4SLinus Torvalds 	.name = "Multi Track Peak",
22031da177e4SLinus Torvalds 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
22041da177e4SLinus Torvalds 	.info = snd_ice1712_pro_peak_info,
22051da177e4SLinus Torvalds 	.get = snd_ice1712_pro_peak_get
22061da177e4SLinus Torvalds };
22071da177e4SLinus Torvalds 
22081da177e4SLinus Torvalds /*
22091da177e4SLinus Torvalds  *
22101da177e4SLinus Torvalds  */
22111da177e4SLinus Torvalds 
22121da177e4SLinus Torvalds /*
22131da177e4SLinus Torvalds  * list of available boards
22141da177e4SLinus Torvalds  */
2215aeb0215cSTakashi Iwai static const struct snd_ice1712_card_info *card_tables[] = {
22161da177e4SLinus Torvalds 	snd_ice1712_hoontech_cards,
22171da177e4SLinus Torvalds 	snd_ice1712_delta_cards,
22181da177e4SLinus Torvalds 	snd_ice1712_ews_cards,
22191da177e4SLinus Torvalds 	NULL,
22201da177e4SLinus Torvalds };
22211da177e4SLinus Torvalds 
snd_ice1712_read_i2c(struct snd_ice1712 * ice,unsigned char dev,unsigned char addr)2222e23e7a14SBill Pemberton static unsigned char snd_ice1712_read_i2c(struct snd_ice1712 *ice,
22231da177e4SLinus Torvalds 					  unsigned char dev,
22241da177e4SLinus Torvalds 					  unsigned char addr)
22251da177e4SLinus Torvalds {
22261da177e4SLinus Torvalds 	long t = 0x10000;
22271da177e4SLinus Torvalds 
22281da177e4SLinus Torvalds 	outb(addr, ICEREG(ice, I2C_BYTE_ADDR));
22291da177e4SLinus Torvalds 	outb(dev & ~ICE1712_I2C_WRITE, ICEREG(ice, I2C_DEV_ADDR));
22301da177e4SLinus Torvalds 	while (t-- > 0 && (inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_BUSY)) ;
22311da177e4SLinus Torvalds 	return inb(ICEREG(ice, I2C_DATA));
22321da177e4SLinus Torvalds }
22331da177e4SLinus Torvalds 
snd_ice1712_read_eeprom(struct snd_ice1712 * ice,const char * modelname)2234e23e7a14SBill Pemberton static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
22356ca308d4STakashi Iwai 				   const char *modelname)
22361da177e4SLinus Torvalds {
22379718a29dSKonstantinos Tsimpoukas 	int dev = ICE_I2C_EEPROM_ADDR;	/* I2C EEPROM device address */
22381da177e4SLinus Torvalds 	unsigned int i, size;
2239aeb0215cSTakashi Iwai 	const struct snd_ice1712_card_info * const *tbl, *c;
22401da177e4SLinus Torvalds 
22411da177e4SLinus Torvalds 	if (!modelname || !*modelname) {
22421da177e4SLinus Torvalds 		ice->eeprom.subvendor = 0;
22431da177e4SLinus Torvalds 		if ((inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_EEPROM) != 0)
22441da177e4SLinus Torvalds 			ice->eeprom.subvendor = (snd_ice1712_read_i2c(ice, dev, 0x00) << 0) |
22451da177e4SLinus Torvalds 				(snd_ice1712_read_i2c(ice, dev, 0x01) << 8) |
22461da177e4SLinus Torvalds 				(snd_ice1712_read_i2c(ice, dev, 0x02) << 16) |
22471da177e4SLinus Torvalds 				(snd_ice1712_read_i2c(ice, dev, 0x03) << 24);
22486ca308d4STakashi Iwai 		if (ice->eeprom.subvendor == 0 ||
22496ca308d4STakashi Iwai 		    ice->eeprom.subvendor == (unsigned int)-1) {
22501da177e4SLinus Torvalds 			/* invalid subvendor from EEPROM, try the PCI subststem ID instead */
22511da177e4SLinus Torvalds 			u16 vendor, device;
22521da177e4SLinus Torvalds 			pci_read_config_word(ice->pci, PCI_SUBSYSTEM_VENDOR_ID, &vendor);
22531da177e4SLinus Torvalds 			pci_read_config_word(ice->pci, PCI_SUBSYSTEM_ID, &device);
22541da177e4SLinus Torvalds 			ice->eeprom.subvendor = ((unsigned int)swab16(vendor) << 16) | swab16(device);
22551da177e4SLinus Torvalds 			if (ice->eeprom.subvendor == 0 || ice->eeprom.subvendor == (unsigned int)-1) {
22566dfb5affSTakashi Iwai 				dev_err(ice->card->dev,
22576dfb5affSTakashi Iwai 					"No valid ID is found\n");
22581da177e4SLinus Torvalds 				return -ENXIO;
22591da177e4SLinus Torvalds 			}
22601da177e4SLinus Torvalds 		}
22611da177e4SLinus Torvalds 	}
22621da177e4SLinus Torvalds 	for (tbl = card_tables; *tbl; tbl++) {
22631da177e4SLinus Torvalds 		for (c = *tbl; c->subvendor; c++) {
22641da177e4SLinus Torvalds 			if (modelname && c->model && !strcmp(modelname, c->model)) {
22656dfb5affSTakashi Iwai 				dev_info(ice->card->dev,
22666dfb5affSTakashi Iwai 					 "Using board model %s\n", c->name);
22671da177e4SLinus Torvalds 				ice->eeprom.subvendor = c->subvendor;
22681da177e4SLinus Torvalds 			} else if (c->subvendor != ice->eeprom.subvendor)
22691da177e4SLinus Torvalds 				continue;
22701da177e4SLinus Torvalds 			if (!c->eeprom_size || !c->eeprom_data)
22711da177e4SLinus Torvalds 				goto found;
22721da177e4SLinus Torvalds 			/* if the EEPROM is given by the driver, use it */
22736dfb5affSTakashi Iwai 			dev_dbg(ice->card->dev, "using the defined eeprom..\n");
22741da177e4SLinus Torvalds 			ice->eeprom.version = 1;
22751da177e4SLinus Torvalds 			ice->eeprom.size = c->eeprom_size + 6;
22761da177e4SLinus Torvalds 			memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size);
22771da177e4SLinus Torvalds 			goto read_skipped;
22781da177e4SLinus Torvalds 		}
22791da177e4SLinus Torvalds 	}
22806dfb5affSTakashi Iwai 	dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n",
22816ca308d4STakashi Iwai 	       ice->eeprom.subvendor);
22821da177e4SLinus Torvalds 
22831da177e4SLinus Torvalds  found:
22841da177e4SLinus Torvalds 	ice->eeprom.size = snd_ice1712_read_i2c(ice, dev, 0x04);
22851da177e4SLinus Torvalds 	if (ice->eeprom.size < 6)
22861da177e4SLinus Torvalds 		ice->eeprom.size = 32; /* FIXME: any cards without the correct size? */
22871da177e4SLinus Torvalds 	else if (ice->eeprom.size > 32) {
22886dfb5affSTakashi Iwai 		dev_err(ice->card->dev,
22896dfb5affSTakashi Iwai 			"invalid EEPROM (size = %i)\n", ice->eeprom.size);
22901da177e4SLinus Torvalds 		return -EIO;
22911da177e4SLinus Torvalds 	}
22921da177e4SLinus Torvalds 	ice->eeprom.version = snd_ice1712_read_i2c(ice, dev, 0x05);
22931da177e4SLinus Torvalds 	if (ice->eeprom.version != 1) {
22946dfb5affSTakashi Iwai 		dev_err(ice->card->dev, "invalid EEPROM version %i\n",
22956ca308d4STakashi Iwai 			   ice->eeprom.version);
22961da177e4SLinus Torvalds 		/* return -EIO; */
22971da177e4SLinus Torvalds 	}
22981da177e4SLinus Torvalds 	size = ice->eeprom.size - 6;
22991da177e4SLinus Torvalds 	for (i = 0; i < size; i++)
23001da177e4SLinus Torvalds 		ice->eeprom.data[i] = snd_ice1712_read_i2c(ice, dev, i + 6);
23011da177e4SLinus Torvalds 
23021da177e4SLinus Torvalds  read_skipped:
23031da177e4SLinus Torvalds 	ice->eeprom.gpiomask = ice->eeprom.data[ICE_EEP1_GPIO_MASK];
23041da177e4SLinus Torvalds 	ice->eeprom.gpiostate = ice->eeprom.data[ICE_EEP1_GPIO_STATE];
23051da177e4SLinus Torvalds 	ice->eeprom.gpiodir = ice->eeprom.data[ICE_EEP1_GPIO_DIR];
23061da177e4SLinus Torvalds 
23071da177e4SLinus Torvalds 	return 0;
23081da177e4SLinus Torvalds }
23091da177e4SLinus Torvalds 
23101da177e4SLinus Torvalds 
23111da177e4SLinus Torvalds 
snd_ice1712_chip_init(struct snd_ice1712 * ice)2312e23e7a14SBill Pemberton static int snd_ice1712_chip_init(struct snd_ice1712 *ice)
23131da177e4SLinus Torvalds {
23141da177e4SLinus Torvalds 	outb(ICE1712_RESET | ICE1712_NATIVE, ICEREG(ice, CONTROL));
23151da177e4SLinus Torvalds 	udelay(200);
23161da177e4SLinus Torvalds 	outb(ICE1712_NATIVE, ICEREG(ice, CONTROL));
23171da177e4SLinus Torvalds 	udelay(200);
2318721b8a29SAlan Horstmann 	if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE &&
2319721b8a29SAlan Horstmann 	    !ice->dxr_enable)
2320721b8a29SAlan Horstmann 		/*  Set eeprom value to limit active ADCs and DACs to 6;
2321721b8a29SAlan Horstmann 		 *  Also disable AC97 as no hardware in standard 6fire card/box
2322721b8a29SAlan Horstmann 		 *  Note: DXR extensions are not currently supported
2323721b8a29SAlan Horstmann 		 */
2324721b8a29SAlan Horstmann 		ice->eeprom.data[ICE_EEP1_CODEC] = 0x3a;
23251da177e4SLinus Torvalds 	pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
23261da177e4SLinus Torvalds 	pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]);
23271da177e4SLinus Torvalds 	pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]);
23281da177e4SLinus Torvalds 	pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]);
2329b0cb0990SScott Bahling 	if (ice->eeprom.subvendor != ICE1712_SUBDEVICE_STDSP24 &&
2330b0cb0990SScott Bahling 	    ice->eeprom.subvendor != ICE1712_SUBDEVICE_STAUDIO_ADCIII) {
23311da177e4SLinus Torvalds 		ice->gpio.write_mask = ice->eeprom.gpiomask;
23321da177e4SLinus Torvalds 		ice->gpio.direction = ice->eeprom.gpiodir;
23336ca308d4STakashi Iwai 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK,
23346ca308d4STakashi Iwai 				  ice->eeprom.gpiomask);
23356ca308d4STakashi Iwai 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
23366ca308d4STakashi Iwai 				  ice->eeprom.gpiodir);
23376ca308d4STakashi Iwai 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA,
23386ca308d4STakashi Iwai 				  ice->eeprom.gpiostate);
23391da177e4SLinus Torvalds 	} else {
23401da177e4SLinus Torvalds 		ice->gpio.write_mask = 0xc0;
23411da177e4SLinus Torvalds 		ice->gpio.direction = 0xff;
23421da177e4SLinus Torvalds 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, 0xc0);
23431da177e4SLinus Torvalds 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 0xff);
23446ca308d4STakashi Iwai 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA,
23456ca308d4STakashi Iwai 				  ICE1712_STDSP24_CLOCK_BIT);
23461da177e4SLinus Torvalds 	}
23471da177e4SLinus Torvalds 	snd_ice1712_write(ice, ICE1712_IREG_PRO_POWERDOWN, 0);
23481da177e4SLinus Torvalds 	if (!(ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97)) {
23491da177e4SLinus Torvalds 		outb(ICE1712_AC97_WARM, ICEREG(ice, AC97_CMD));
23501da177e4SLinus Torvalds 		udelay(100);
23511da177e4SLinus Torvalds 		outb(0, ICEREG(ice, AC97_CMD));
23521da177e4SLinus Torvalds 		udelay(200);
23531da177e4SLinus Torvalds 		snd_ice1712_write(ice, ICE1712_IREG_CONSUMER_POWERDOWN, 0);
23541da177e4SLinus Torvalds 	}
23551da177e4SLinus Torvalds 	snd_ice1712_set_pro_rate(ice, 48000, 1);
2356ca051e8aSOndrej Zary 	/* unmask used interrupts */
2357ca051e8aSOndrej Zary 	outb(((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ?
2358ca051e8aSOndrej Zary 	      ICE1712_IRQ_MPU2 : 0) |
2359ca051e8aSOndrej Zary 	     ((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ?
2360ca051e8aSOndrej Zary 	      ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0),
2361ca051e8aSOndrej Zary 	     ICEREG(ice, IRQMASK));
2362ca051e8aSOndrej Zary 	outb(0x00, ICEMT(ice, IRQ));
23631da177e4SLinus Torvalds 
23641da177e4SLinus Torvalds 	return 0;
23651da177e4SLinus Torvalds }
23661da177e4SLinus Torvalds 
snd_ice1712_spdif_build_controls(struct snd_ice1712 * ice)2367e23e7a14SBill Pemberton int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice)
23681da177e4SLinus Torvalds {
23691da177e4SLinus Torvalds 	int err;
23706ca308d4STakashi Iwai 	struct snd_kcontrol *kctl;
23711da177e4SLinus Torvalds 
2372da3cec35STakashi Iwai 	if (snd_BUG_ON(!ice->pcm_pro))
2373da3cec35STakashi Iwai 		return -EIO;
2374*b9a4efd6SJaroslav Kysela 	kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice);
2375*b9a4efd6SJaroslav Kysela 	kctl->id.device = ice->pcm_pro->device;
2376*b9a4efd6SJaroslav Kysela 	err = snd_ctl_add(ice->card, kctl);
23771da177e4SLinus Torvalds 	if (err < 0)
23781da177e4SLinus Torvalds 		return err;
2379*b9a4efd6SJaroslav Kysela 	kctl = snd_ctl_new1(&snd_ice1712_spdif_maskc, ice);
23801da177e4SLinus Torvalds 	kctl->id.device = ice->pcm_pro->device;
2381*b9a4efd6SJaroslav Kysela 	err = snd_ctl_add(ice->card, kctl);
23821da177e4SLinus Torvalds 	if (err < 0)
23831da177e4SLinus Torvalds 		return err;
2384*b9a4efd6SJaroslav Kysela 	kctl = snd_ctl_new1(&snd_ice1712_spdif_maskp, ice);
23851da177e4SLinus Torvalds 	kctl->id.device = ice->pcm_pro->device;
2386*b9a4efd6SJaroslav Kysela 	err = snd_ctl_add(ice->card, kctl);
23871da177e4SLinus Torvalds 	if (err < 0)
23881da177e4SLinus Torvalds 		return err;
2389*b9a4efd6SJaroslav Kysela 	kctl = snd_ctl_new1(&snd_ice1712_spdif_stream, ice);
23901da177e4SLinus Torvalds 	kctl->id.device = ice->pcm_pro->device;
2391*b9a4efd6SJaroslav Kysela 	err = snd_ctl_add(ice->card, kctl);
23921da177e4SLinus Torvalds 	if (err < 0)
23931da177e4SLinus Torvalds 		return err;
23941da177e4SLinus Torvalds 	ice->spdif.stream_ctl = kctl;
23951da177e4SLinus Torvalds 	return 0;
23961da177e4SLinus Torvalds }
23971da177e4SLinus Torvalds 
23981da177e4SLinus Torvalds 
snd_ice1712_build_controls(struct snd_ice1712 * ice)2399e23e7a14SBill Pemberton static int snd_ice1712_build_controls(struct snd_ice1712 *ice)
24001da177e4SLinus Torvalds {
24011da177e4SLinus Torvalds 	int err;
24021da177e4SLinus Torvalds 
24031da177e4SLinus Torvalds 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_eeprom, ice));
24041da177e4SLinus Torvalds 	if (err < 0)
24051da177e4SLinus Torvalds 		return err;
24061da177e4SLinus Torvalds 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_internal_clock, ice));
24071da177e4SLinus Torvalds 	if (err < 0)
24081da177e4SLinus Torvalds 		return err;
24091da177e4SLinus Torvalds 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_internal_clock_default, ice));
24101da177e4SLinus Torvalds 	if (err < 0)
24111da177e4SLinus Torvalds 		return err;
24121da177e4SLinus Torvalds 
24131da177e4SLinus Torvalds 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_locking, ice));
24141da177e4SLinus Torvalds 	if (err < 0)
24151da177e4SLinus Torvalds 		return err;
24161da177e4SLinus Torvalds 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_reset, ice));
24171da177e4SLinus Torvalds 	if (err < 0)
24181da177e4SLinus Torvalds 		return err;
24191da177e4SLinus Torvalds 
24201da177e4SLinus Torvalds 	if (ice->num_total_dacs > 0) {
24216ca308d4STakashi Iwai 		struct snd_kcontrol_new tmp = snd_ice1712_mixer_pro_analog_route;
24221da177e4SLinus Torvalds 		tmp.count = ice->num_total_dacs;
24231da177e4SLinus Torvalds 		err = snd_ctl_add(ice->card, snd_ctl_new1(&tmp, ice));
24241da177e4SLinus Torvalds 		if (err < 0)
24251da177e4SLinus Torvalds 			return err;
24261da177e4SLinus Torvalds 	}
24271da177e4SLinus Torvalds 
24281da177e4SLinus Torvalds 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_spdif_route, ice));
24291da177e4SLinus Torvalds 	if (err < 0)
24301da177e4SLinus Torvalds 		return err;
24311da177e4SLinus Torvalds 
24321da177e4SLinus Torvalds 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice));
24331da177e4SLinus Torvalds 	if (err < 0)
24341da177e4SLinus Torvalds 		return err;
2435387417b5SSudip Mukherjee 	return snd_ctl_add(ice->card,
2436387417b5SSudip Mukherjee 			   snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
24371da177e4SLinus Torvalds }
24381da177e4SLinus Torvalds 
snd_ice1712_free(struct snd_card * card)2439ca642da4STakashi Iwai static void snd_ice1712_free(struct snd_card *card)
24401da177e4SLinus Torvalds {
2441ca642da4STakashi Iwai 	struct snd_ice1712 *ice = card->private_data;
2442ca642da4STakashi Iwai 
2443ca642da4STakashi Iwai 	if (ice->card_info && ice->card_info->chip_exit)
2444ca642da4STakashi Iwai 		ice->card_info->chip_exit(ice);
2445ca642da4STakashi Iwai 
24461da177e4SLinus Torvalds 	/* mask all interrupts */
2447890b13a3SKonstantinos Tsimpoukas 	outb(ICE1712_MULTI_CAPTURE | ICE1712_MULTI_PLAYBACK, ICEMT(ice, IRQ));
24481da177e4SLinus Torvalds 	outb(0xff, ICEREG(ice, IRQMASK));
2449f000fd80SJeff Garzik 
24501da177e4SLinus Torvalds 	snd_ice1712_akm4xxx_free(ice);
24511da177e4SLinus Torvalds }
24521da177e4SLinus Torvalds 
snd_ice1712_create(struct snd_card * card,struct pci_dev * pci,const char * modelname,int omni,int cs8427_timeout,int dxr_enable)2453e23e7a14SBill Pemberton static int snd_ice1712_create(struct snd_card *card,
24541da177e4SLinus Torvalds 			      struct pci_dev *pci,
24551da177e4SLinus Torvalds 			      const char *modelname,
24561da177e4SLinus Torvalds 			      int omni,
24571da177e4SLinus Torvalds 			      int cs8427_timeout,
2458ca642da4STakashi Iwai 			      int dxr_enable)
24591da177e4SLinus Torvalds {
2460ca642da4STakashi Iwai 	struct snd_ice1712 *ice = card->private_data;
24611da177e4SLinus Torvalds 	int err;
24621da177e4SLinus Torvalds 
24631da177e4SLinus Torvalds 	/* enable PCI device */
2464ca642da4STakashi Iwai 	err = pcim_enable_device(pci);
24653d8cb466SAlexander Beregalov 	if (err < 0)
24661da177e4SLinus Torvalds 		return err;
24671da177e4SLinus Torvalds 	/* check, if we can restrict PCI DMA transfers to 28 bits */
2468669f65eaSTakashi Iwai 	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) {
24696dfb5affSTakashi Iwai 		dev_err(card->dev,
24706dfb5affSTakashi Iwai 			"architecture does not support 28bit PCI busmaster DMA\n");
24711da177e4SLinus Torvalds 		return -ENXIO;
24721da177e4SLinus Torvalds 	}
24731da177e4SLinus Torvalds 
24741da177e4SLinus Torvalds 	ice->omni = omni ? 1 : 0;
24751da177e4SLinus Torvalds 	if (cs8427_timeout < 1)
24761da177e4SLinus Torvalds 		cs8427_timeout = 1;
24771da177e4SLinus Torvalds 	else if (cs8427_timeout > 1000)
24781da177e4SLinus Torvalds 		cs8427_timeout = 1000;
24791da177e4SLinus Torvalds 	ice->cs8427_timeout = cs8427_timeout;
2480531af462SAlan Horstmann 	ice->dxr_enable = dxr_enable;
24811da177e4SLinus Torvalds 	spin_lock_init(&ice->reg_lock);
248262932df8SIngo Molnar 	mutex_init(&ice->gpio_mutex);
248362932df8SIngo Molnar 	mutex_init(&ice->i2c_mutex);
248462932df8SIngo Molnar 	mutex_init(&ice->open_mutex);
24851da177e4SLinus Torvalds 	ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
248649470306SPavel Hofman 	ice->gpio.get_mask = snd_ice1712_get_gpio_mask;
24871da177e4SLinus Torvalds 	ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
248849470306SPavel Hofman 	ice->gpio.get_dir = snd_ice1712_get_gpio_dir;
24891da177e4SLinus Torvalds 	ice->gpio.set_data = snd_ice1712_set_gpio_data;
24901da177e4SLinus Torvalds 	ice->gpio.get_data = snd_ice1712_get_gpio_data;
24911da177e4SLinus Torvalds 
24921da177e4SLinus Torvalds 	ice->spdif.cs8403_bits =
24931da177e4SLinus Torvalds 		ice->spdif.cs8403_stream_bits = (0x01 |	/* consumer format */
24941da177e4SLinus Torvalds 						 0x10 |	/* no emphasis */
24951da177e4SLinus Torvalds 						 0x20);	/* PCM encoder/decoder */
24961da177e4SLinus Torvalds 	ice->card = card;
24971da177e4SLinus Torvalds 	ice->pci = pci;
24981da177e4SLinus Torvalds 	ice->irq = -1;
24991da177e4SLinus Torvalds 	pci_set_master(pci);
2500ca051e8aSOndrej Zary 	/* disable legacy emulation */
25011da177e4SLinus Torvalds 	pci_write_config_word(ice->pci, 0x40, 0x807f);
25021da177e4SLinus Torvalds 	pci_write_config_word(ice->pci, 0x42, 0x0006);
25031da177e4SLinus Torvalds 	snd_ice1712_proc_init(ice);
25041da177e4SLinus Torvalds 
25053d8cb466SAlexander Beregalov 	err = pci_request_regions(pci, "ICE1712");
2506ca642da4STakashi Iwai 	if (err < 0)
25071da177e4SLinus Torvalds 		return err;
25081da177e4SLinus Torvalds 	ice->port = pci_resource_start(pci, 0);
25091da177e4SLinus Torvalds 	ice->ddma_port = pci_resource_start(pci, 1);
25101da177e4SLinus Torvalds 	ice->dmapath_port = pci_resource_start(pci, 2);
25111da177e4SLinus Torvalds 	ice->profi_port = pci_resource_start(pci, 3);
25121da177e4SLinus Torvalds 
2513ca642da4STakashi Iwai 	if (devm_request_irq(&pci->dev, pci->irq, snd_ice1712_interrupt,
2514ca642da4STakashi Iwai 			     IRQF_SHARED, KBUILD_MODNAME, ice)) {
25156dfb5affSTakashi Iwai 		dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
25161da177e4SLinus Torvalds 		return -EIO;
25171da177e4SLinus Torvalds 	}
25181da177e4SLinus Torvalds 
25191da177e4SLinus Torvalds 	ice->irq = pci->irq;
25201b97a87fSTakashi Iwai 	card->sync_irq = ice->irq;
2521ca642da4STakashi Iwai 	card->private_free = snd_ice1712_free;
25221da177e4SLinus Torvalds 
2523ca642da4STakashi Iwai 	if (snd_ice1712_read_eeprom(ice, modelname) < 0)
25241da177e4SLinus Torvalds 		return -EIO;
2525ca642da4STakashi Iwai 	if (snd_ice1712_chip_init(ice) < 0)
25261da177e4SLinus Torvalds 		return -EIO;
25271da177e4SLinus Torvalds 
25281da177e4SLinus Torvalds 	return 0;
25291da177e4SLinus Torvalds }
25301da177e4SLinus Torvalds 
25311da177e4SLinus Torvalds 
25321da177e4SLinus Torvalds /*
25331da177e4SLinus Torvalds  *
25341da177e4SLinus Torvalds  * Registration
25351da177e4SLinus Torvalds  *
25361da177e4SLinus Torvalds  */
25371da177e4SLinus Torvalds 
2538e23e7a14SBill Pemberton static struct snd_ice1712_card_info no_matched;
25391da177e4SLinus Torvalds 
snd_ice1712_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)2540e23e7a14SBill Pemberton static int snd_ice1712_probe(struct pci_dev *pci,
25411da177e4SLinus Torvalds 			     const struct pci_device_id *pci_id)
25421da177e4SLinus Torvalds {
25431da177e4SLinus Torvalds 	static int dev;
25446ca308d4STakashi Iwai 	struct snd_card *card;
25456ca308d4STakashi Iwai 	struct snd_ice1712 *ice;
25461da177e4SLinus Torvalds 	int pcm_dev = 0, err;
2547aeb0215cSTakashi Iwai 	const struct snd_ice1712_card_info * const *tbl, *c;
25481da177e4SLinus Torvalds 
25491da177e4SLinus Torvalds 	if (dev >= SNDRV_CARDS)
25501da177e4SLinus Torvalds 		return -ENODEV;
25511da177e4SLinus Torvalds 	if (!enable[dev]) {
25521da177e4SLinus Torvalds 		dev++;
25531da177e4SLinus Torvalds 		return -ENOENT;
25541da177e4SLinus Torvalds 	}
25551da177e4SLinus Torvalds 
255660c5772bSTakashi Iwai 	err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
2557ca642da4STakashi Iwai 			   sizeof(*ice), &card);
2558e58de7baSTakashi Iwai 	if (err < 0)
2559e58de7baSTakashi Iwai 		return err;
2560ca642da4STakashi Iwai 	ice = card->private_data;
25611da177e4SLinus Torvalds 
25621da177e4SLinus Torvalds 	strcpy(card->driver, "ICE1712");
25631da177e4SLinus Torvalds 	strcpy(card->shortname, "ICEnsemble ICE1712");
25641da177e4SLinus Torvalds 
25653d8cb466SAlexander Beregalov 	err = snd_ice1712_create(card, pci, model[dev], omni[dev],
2566ca642da4STakashi Iwai 				 cs8427_timeout[dev], dxr_enable[dev]);
2567ca642da4STakashi Iwai 	if (err < 0)
25681da177e4SLinus Torvalds 		return err;
25691da177e4SLinus Torvalds 
25701da177e4SLinus Torvalds 	for (tbl = card_tables; *tbl; tbl++) {
25711da177e4SLinus Torvalds 		for (c = *tbl; c->subvendor; c++) {
25721da177e4SLinus Torvalds 			if (c->subvendor == ice->eeprom.subvendor) {
25731da177e4SLinus Torvalds 				strcpy(card->shortname, c->name);
25741da177e4SLinus Torvalds 				if (c->driver) /* specific driver? */
25751da177e4SLinus Torvalds 					strcpy(card->driver, c->driver);
25761da177e4SLinus Torvalds 				if (c->chip_init) {
25773d8cb466SAlexander Beregalov 					err = c->chip_init(ice);
2578ca642da4STakashi Iwai 					if (err < 0)
25791da177e4SLinus Torvalds 						return err;
25801da177e4SLinus Torvalds 				}
2581ca642da4STakashi Iwai 				ice->card_info = c;
25821da177e4SLinus Torvalds 				goto __found;
25831da177e4SLinus Torvalds 			}
25841da177e4SLinus Torvalds 		}
25851da177e4SLinus Torvalds 	}
25861da177e4SLinus Torvalds 	c = &no_matched;
25871da177e4SLinus Torvalds  __found:
25881da177e4SLinus Torvalds 
258908a4c10bSLars-Peter Clausen 	err = snd_ice1712_pcm_profi(ice, pcm_dev++);
2590ca642da4STakashi Iwai 	if (err < 0)
25911da177e4SLinus Torvalds 		return err;
25921da177e4SLinus Torvalds 
25938cd2b264SIlpo Järvinen 	if (ice_has_con_ac97(ice)) {
259408a4c10bSLars-Peter Clausen 		err = snd_ice1712_pcm(ice, pcm_dev++);
2595ca642da4STakashi Iwai 		if (err < 0)
25961da177e4SLinus Torvalds 			return err;
25971da177e4SLinus Torvalds 	}
25981da177e4SLinus Torvalds 
25993d8cb466SAlexander Beregalov 	err = snd_ice1712_ac97_mixer(ice);
2600ca642da4STakashi Iwai 	if (err < 0)
26011da177e4SLinus Torvalds 		return err;
26021da177e4SLinus Torvalds 
26033d8cb466SAlexander Beregalov 	err = snd_ice1712_build_controls(ice);
2604ca642da4STakashi Iwai 	if (err < 0)
26051da177e4SLinus Torvalds 		return err;
26061da177e4SLinus Torvalds 
26071da177e4SLinus Torvalds 	if (c->build_controls) {
26083d8cb466SAlexander Beregalov 		err = c->build_controls(ice);
2609ca642da4STakashi Iwai 		if (err < 0)
26101da177e4SLinus Torvalds 			return err;
26111da177e4SLinus Torvalds 	}
26121da177e4SLinus Torvalds 
26138cd2b264SIlpo Järvinen 	if (ice_has_con_ac97(ice)) {
261408a4c10bSLars-Peter Clausen 		err = snd_ice1712_pcm_ds(ice, pcm_dev++);
2615ca642da4STakashi Iwai 		if (err < 0)
26161da177e4SLinus Torvalds 			return err;
26171da177e4SLinus Torvalds 	}
26181da177e4SLinus Torvalds 
26191da177e4SLinus Torvalds 	if (!c->no_mpu401) {
26203d8cb466SAlexander Beregalov 		err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
2621302e4c2fSTakashi Iwai 			ICEREG(ice, MPU1_CTRL),
2622dba8b469SClemens Ladisch 			c->mpu401_1_info_flags |
2623dba8b469SClemens Ladisch 			MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
2624dba8b469SClemens Ladisch 			-1, &ice->rmidi[0]);
2625ca642da4STakashi Iwai 		if (err < 0)
26261da177e4SLinus Torvalds 			return err;
26273bef229eSAlan Horstmann 		if (c->mpu401_1_name)
262825985edcSLucas De Marchi 			/*  Preferred name available in card_info */
26293bef229eSAlan Horstmann 			snprintf(ice->rmidi[0]->name,
26303bef229eSAlan Horstmann 				 sizeof(ice->rmidi[0]->name),
26313bef229eSAlan Horstmann 				 "%s %d", c->mpu401_1_name, card->number);
26321da177e4SLinus Torvalds 
26333bef229eSAlan Horstmann 		if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) {
26343bef229eSAlan Horstmann 			/*  2nd port used  */
26353d8cb466SAlexander Beregalov 			err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
2636302e4c2fSTakashi Iwai 				ICEREG(ice, MPU2_CTRL),
2637dba8b469SClemens Ladisch 				c->mpu401_2_info_flags |
2638dba8b469SClemens Ladisch 				MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
2639dba8b469SClemens Ladisch 				-1, &ice->rmidi[1]);
26403d8cb466SAlexander Beregalov 
2641ca642da4STakashi Iwai 			if (err < 0)
26421da177e4SLinus Torvalds 				return err;
26433bef229eSAlan Horstmann 			if (c->mpu401_2_name)
264425985edcSLucas De Marchi 				/*  Preferred name available in card_info */
26453bef229eSAlan Horstmann 				snprintf(ice->rmidi[1]->name,
26463bef229eSAlan Horstmann 					 sizeof(ice->rmidi[1]->name),
26473bef229eSAlan Horstmann 					 "%s %d", c->mpu401_2_name,
26483bef229eSAlan Horstmann 					 card->number);
26493bef229eSAlan Horstmann 		}
26501da177e4SLinus Torvalds 	}
26511da177e4SLinus Torvalds 
2652e957ebf1SJaroslav Kysela 	snd_ice1712_set_input_clock_source(ice, 0);
2653e957ebf1SJaroslav Kysela 
26541da177e4SLinus Torvalds 	sprintf(card->longname, "%s at 0x%lx, irq %i",
26551da177e4SLinus Torvalds 		card->shortname, ice->port, ice->irq);
26561da177e4SLinus Torvalds 
26573d8cb466SAlexander Beregalov 	err = snd_card_register(card);
2658ca642da4STakashi Iwai 	if (err < 0)
26591da177e4SLinus Torvalds 		return err;
26601da177e4SLinus Torvalds 	pci_set_drvdata(pci, card);
26611da177e4SLinus Torvalds 	dev++;
26621da177e4SLinus Torvalds 	return 0;
26631da177e4SLinus Torvalds }
26641da177e4SLinus Torvalds 
2665ca051e8aSOndrej Zary #ifdef CONFIG_PM_SLEEP
snd_ice1712_suspend(struct device * dev)2666ca051e8aSOndrej Zary static int snd_ice1712_suspend(struct device *dev)
2667ca051e8aSOndrej Zary {
2668ca051e8aSOndrej Zary 	struct snd_card *card = dev_get_drvdata(dev);
2669ca051e8aSOndrej Zary 	struct snd_ice1712 *ice = card->private_data;
2670ca051e8aSOndrej Zary 
2671ca051e8aSOndrej Zary 	if (!ice->pm_suspend_enabled)
2672ca051e8aSOndrej Zary 		return 0;
2673ca051e8aSOndrej Zary 
2674ca051e8aSOndrej Zary 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
2675ca051e8aSOndrej Zary 
2676ca051e8aSOndrej Zary 	snd_ac97_suspend(ice->ac97);
2677ca051e8aSOndrej Zary 
26786ea0cae7SOndrej Zary 	spin_lock_irq(&ice->reg_lock);
26796ea0cae7SOndrej Zary 	ice->pm_saved_is_spdif_master = is_spdif_master(ice);
26806ea0cae7SOndrej Zary 	ice->pm_saved_spdif_ctrl = inw(ICEMT(ice, ROUTE_SPDOUT));
26816ea0cae7SOndrej Zary 	ice->pm_saved_route = inw(ICEMT(ice, ROUTE_PSDOUT03));
26826ea0cae7SOndrej Zary 	spin_unlock_irq(&ice->reg_lock);
26836ea0cae7SOndrej Zary 
2684ca051e8aSOndrej Zary 	if (ice->pm_suspend)
2685ca051e8aSOndrej Zary 		ice->pm_suspend(ice);
2686ca051e8aSOndrej Zary 	return 0;
2687ca051e8aSOndrej Zary }
2688ca051e8aSOndrej Zary 
snd_ice1712_resume(struct device * dev)2689ca051e8aSOndrej Zary static int snd_ice1712_resume(struct device *dev)
2690ca051e8aSOndrej Zary {
2691ca051e8aSOndrej Zary 	struct snd_card *card = dev_get_drvdata(dev);
2692ca051e8aSOndrej Zary 	struct snd_ice1712 *ice = card->private_data;
26936ea0cae7SOndrej Zary 	int rate;
2694ca051e8aSOndrej Zary 
2695ca051e8aSOndrej Zary 	if (!ice->pm_suspend_enabled)
2696ca051e8aSOndrej Zary 		return 0;
2697ca051e8aSOndrej Zary 
26986ea0cae7SOndrej Zary 	if (ice->cur_rate)
26996ea0cae7SOndrej Zary 		rate = ice->cur_rate;
27006ea0cae7SOndrej Zary 	else
27016ea0cae7SOndrej Zary 		rate = PRO_RATE_DEFAULT;
27026ea0cae7SOndrej Zary 
2703ca051e8aSOndrej Zary 	if (snd_ice1712_chip_init(ice) < 0) {
2704ca051e8aSOndrej Zary 		snd_card_disconnect(card);
2705ca051e8aSOndrej Zary 		return -EIO;
2706ca051e8aSOndrej Zary 	}
2707ca051e8aSOndrej Zary 
27086ea0cae7SOndrej Zary 	ice->cur_rate = rate;
27096ea0cae7SOndrej Zary 
2710ca051e8aSOndrej Zary 	if (ice->pm_resume)
2711ca051e8aSOndrej Zary 		ice->pm_resume(ice);
2712ca051e8aSOndrej Zary 
27136ea0cae7SOndrej Zary 	if (ice->pm_saved_is_spdif_master) {
27146ea0cae7SOndrej Zary 		/* switching to external clock via SPDIF */
27156ea0cae7SOndrej Zary 		spin_lock_irq(&ice->reg_lock);
27166ea0cae7SOndrej Zary 		outb(inb(ICEMT(ice, RATE)) | ICE1712_SPDIF_MASTER,
27176ea0cae7SOndrej Zary 			ICEMT(ice, RATE));
27186ea0cae7SOndrej Zary 		spin_unlock_irq(&ice->reg_lock);
27196ea0cae7SOndrej Zary 		snd_ice1712_set_input_clock_source(ice, 1);
27206ea0cae7SOndrej Zary 	} else {
27216ea0cae7SOndrej Zary 		/* internal on-card clock */
27226ea0cae7SOndrej Zary 		snd_ice1712_set_pro_rate(ice, rate, 1);
27236ea0cae7SOndrej Zary 		snd_ice1712_set_input_clock_source(ice, 0);
27246ea0cae7SOndrej Zary 	}
27256ea0cae7SOndrej Zary 
27266ea0cae7SOndrej Zary 	outw(ice->pm_saved_spdif_ctrl, ICEMT(ice, ROUTE_SPDOUT));
27276ea0cae7SOndrej Zary 	outw(ice->pm_saved_route, ICEMT(ice, ROUTE_PSDOUT03));
27286ea0cae7SOndrej Zary 
2729ca051e8aSOndrej Zary 	snd_ac97_resume(ice->ac97);
2730ca051e8aSOndrej Zary 
2731ca051e8aSOndrej Zary 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
2732ca051e8aSOndrej Zary 	return 0;
2733ca051e8aSOndrej Zary }
2734ca051e8aSOndrej Zary 
2735ca051e8aSOndrej Zary static SIMPLE_DEV_PM_OPS(snd_ice1712_pm, snd_ice1712_suspend, snd_ice1712_resume);
2736ca051e8aSOndrej Zary #define SND_VT1712_PM_OPS	&snd_ice1712_pm
2737ca051e8aSOndrej Zary #else
2738ca051e8aSOndrej Zary #define SND_VT1712_PM_OPS	NULL
2739ca051e8aSOndrej Zary #endif /* CONFIG_PM_SLEEP */
2740ca051e8aSOndrej Zary 
2741e9f66d9bSTakashi Iwai static struct pci_driver ice1712_driver = {
27423733e424STakashi Iwai 	.name = KBUILD_MODNAME,
27431da177e4SLinus Torvalds 	.id_table = snd_ice1712_ids,
27441da177e4SLinus Torvalds 	.probe = snd_ice1712_probe,
2745ca051e8aSOndrej Zary 	.driver = {
2746ca051e8aSOndrej Zary 		.pm = SND_VT1712_PM_OPS,
2747ca051e8aSOndrej Zary 	},
27481da177e4SLinus Torvalds };
27491da177e4SLinus Torvalds 
2750e9f66d9bSTakashi Iwai module_pci_driver(ice1712_driver);
2751