162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ALSA driver for ICEnsemble ICE1712 (Envy24) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci NOTES: 1062306a36Sopenharmony_ci - spdif nonaudio consumer mode does not work (at least with my 1162306a36Sopenharmony_ci Sony STR-DB830) 1262306a36Sopenharmony_ci*/ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * Changes: 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * 2002.09.09 Takashi Iwai <tiwai@suse.de> 1862306a36Sopenharmony_ci * split the code to several files. each low-level routine 1962306a36Sopenharmony_ci * is stored in the local file and called from registration 2062306a36Sopenharmony_ci * function from card_info struct. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * 2002.11.26 James Stafford <jstafford@ampltd.com> 2362306a36Sopenharmony_ci * Added support for VT1724 (Envy24HT) 2462306a36Sopenharmony_ci * I have left out support for 176.4 and 192 KHz for the moment. 2562306a36Sopenharmony_ci * I also haven't done anything with the internal S/PDIF transmitter or the MPU-401 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * 2003.02.20 Taksahi Iwai <tiwai@suse.de> 2862306a36Sopenharmony_ci * Split vt1724 part to an independent driver. 2962306a36Sopenharmony_ci * The GPIO is accessed through the callback functions now. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * 2004.03.31 Doug McLain <nostar@comcast.net> 3262306a36Sopenharmony_ci * Added support for Event Electronics EZ8 card to hoontech.c. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/delay.h> 3762306a36Sopenharmony_ci#include <linux/interrupt.h> 3862306a36Sopenharmony_ci#include <linux/init.h> 3962306a36Sopenharmony_ci#include <linux/pci.h> 4062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 4162306a36Sopenharmony_ci#include <linux/slab.h> 4262306a36Sopenharmony_ci#include <linux/module.h> 4362306a36Sopenharmony_ci#include <linux/mutex.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include <sound/core.h> 4662306a36Sopenharmony_ci#include <sound/cs8427.h> 4762306a36Sopenharmony_ci#include <sound/info.h> 4862306a36Sopenharmony_ci#include <sound/initval.h> 4962306a36Sopenharmony_ci#include <sound/tlv.h> 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#include <sound/asoundef.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include "ice1712.h" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* lowlevel routines */ 5662306a36Sopenharmony_ci#include "delta.h" 5762306a36Sopenharmony_ci#include "ews.h" 5862306a36Sopenharmony_ci#include "hoontech.h" 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 6162306a36Sopenharmony_ciMODULE_DESCRIPTION("ICEnsemble ICE1712 (Envy24)"); 6262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 6562306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 6662306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ 6762306a36Sopenharmony_cistatic char *model[SNDRV_CARDS]; 6862306a36Sopenharmony_cistatic bool omni[SNDRV_CARDS]; /* Delta44 & 66 Omni I/O support */ 6962306a36Sopenharmony_cistatic int cs8427_timeout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 500}; /* CS8427 S/PDIF transceiver reset timeout value in msec */ 7062306a36Sopenharmony_cistatic int dxr_enable[SNDRV_CARDS]; /* DXR enable for DMX6FIRE */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 7362306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for ICE1712 soundcard."); 7462306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 7562306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for ICE1712 soundcard."); 7662306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 7762306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable ICE1712 soundcard."); 7862306a36Sopenharmony_cimodule_param_array(omni, bool, NULL, 0444); 7962306a36Sopenharmony_ciMODULE_PARM_DESC(omni, "Enable Midiman M-Audio Delta Omni I/O support."); 8062306a36Sopenharmony_cimodule_param_array(cs8427_timeout, int, NULL, 0444); 8162306a36Sopenharmony_ciMODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec resolution."); 8262306a36Sopenharmony_cimodule_param_array(model, charp, NULL, 0444); 8362306a36Sopenharmony_ciMODULE_PARM_DESC(model, "Use the given board model."); 8462306a36Sopenharmony_cimodule_param_array(dxr_enable, int, NULL, 0444); 8562306a36Sopenharmony_ciMODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic const struct pci_device_id snd_ice1712_ids[] = { 8962306a36Sopenharmony_ci { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */ 9062306a36Sopenharmony_ci { 0, } 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_ice1712_ids); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice); 9662306a36Sopenharmony_cistatic int snd_ice1712_build_controls(struct snd_ice1712 *ice); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int PRO_RATE_LOCKED; 9962306a36Sopenharmony_cistatic int PRO_RATE_RESET = 1; 10062306a36Sopenharmony_cistatic unsigned int PRO_RATE_DEFAULT = 44100; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * Basic I/O 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* check whether the clock mode is spdif-in */ 10762306a36Sopenharmony_cistatic inline int is_spdif_master(struct snd_ice1712 *ice) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER) ? 1 : 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic inline int is_pro_rate_locked(struct snd_ice1712 *ice) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci return is_spdif_master(ice) || PRO_RATE_LOCKED; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline void snd_ice1712_ds_write(struct snd_ice1712 *ice, u8 channel, u8 addr, u32 data) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci outb((channel << 4) | addr, ICEDS(ice, INDEX)); 12062306a36Sopenharmony_ci outl(data, ICEDS(ice, DATA)); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic inline u32 snd_ice1712_ds_read(struct snd_ice1712 *ice, u8 channel, u8 addr) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci outb((channel << 4) | addr, ICEDS(ice, INDEX)); 12662306a36Sopenharmony_ci return inl(ICEDS(ice, DATA)); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void snd_ice1712_ac97_write(struct snd_ac97 *ac97, 13062306a36Sopenharmony_ci unsigned short reg, 13162306a36Sopenharmony_ci unsigned short val) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct snd_ice1712 *ice = ac97->private_data; 13462306a36Sopenharmony_ci int tm; 13562306a36Sopenharmony_ci unsigned char old_cmd = 0; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) { 13862306a36Sopenharmony_ci old_cmd = inb(ICEREG(ice, AC97_CMD)); 13962306a36Sopenharmony_ci if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ)) 14062306a36Sopenharmony_ci continue; 14162306a36Sopenharmony_ci if (!(old_cmd & ICE1712_AC97_READY)) 14262306a36Sopenharmony_ci continue; 14362306a36Sopenharmony_ci break; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci outb(reg, ICEREG(ice, AC97_INDEX)); 14662306a36Sopenharmony_ci outw(val, ICEREG(ice, AC97_DATA)); 14762306a36Sopenharmony_ci old_cmd &= ~(ICE1712_AC97_PBK_VSR | ICE1712_AC97_CAP_VSR); 14862306a36Sopenharmony_ci outb(old_cmd | ICE1712_AC97_WRITE, ICEREG(ice, AC97_CMD)); 14962306a36Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) 15062306a36Sopenharmony_ci if ((inb(ICEREG(ice, AC97_CMD)) & ICE1712_AC97_WRITE) == 0) 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic unsigned short snd_ice1712_ac97_read(struct snd_ac97 *ac97, 15562306a36Sopenharmony_ci unsigned short reg) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct snd_ice1712 *ice = ac97->private_data; 15862306a36Sopenharmony_ci int tm; 15962306a36Sopenharmony_ci unsigned char old_cmd = 0; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) { 16262306a36Sopenharmony_ci old_cmd = inb(ICEREG(ice, AC97_CMD)); 16362306a36Sopenharmony_ci if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ)) 16462306a36Sopenharmony_ci continue; 16562306a36Sopenharmony_ci if (!(old_cmd & ICE1712_AC97_READY)) 16662306a36Sopenharmony_ci continue; 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci outb(reg, ICEREG(ice, AC97_INDEX)); 17062306a36Sopenharmony_ci outb(old_cmd | ICE1712_AC97_READ, ICEREG(ice, AC97_CMD)); 17162306a36Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) 17262306a36Sopenharmony_ci if ((inb(ICEREG(ice, AC97_CMD)) & ICE1712_AC97_READ) == 0) 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci if (tm >= 0x10000) /* timeout */ 17562306a36Sopenharmony_ci return ~0; 17662306a36Sopenharmony_ci return inw(ICEREG(ice, AC97_DATA)); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * pro ac97 section 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void snd_ice1712_pro_ac97_write(struct snd_ac97 *ac97, 18462306a36Sopenharmony_ci unsigned short reg, 18562306a36Sopenharmony_ci unsigned short val) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct snd_ice1712 *ice = ac97->private_data; 18862306a36Sopenharmony_ci int tm; 18962306a36Sopenharmony_ci unsigned char old_cmd = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) { 19262306a36Sopenharmony_ci old_cmd = inb(ICEMT(ice, AC97_CMD)); 19362306a36Sopenharmony_ci if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ)) 19462306a36Sopenharmony_ci continue; 19562306a36Sopenharmony_ci if (!(old_cmd & ICE1712_AC97_READY)) 19662306a36Sopenharmony_ci continue; 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci outb(reg, ICEMT(ice, AC97_INDEX)); 20062306a36Sopenharmony_ci outw(val, ICEMT(ice, AC97_DATA)); 20162306a36Sopenharmony_ci old_cmd &= ~(ICE1712_AC97_PBK_VSR | ICE1712_AC97_CAP_VSR); 20262306a36Sopenharmony_ci outb(old_cmd | ICE1712_AC97_WRITE, ICEMT(ice, AC97_CMD)); 20362306a36Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) 20462306a36Sopenharmony_ci if ((inb(ICEMT(ice, AC97_CMD)) & ICE1712_AC97_WRITE) == 0) 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic unsigned short snd_ice1712_pro_ac97_read(struct snd_ac97 *ac97, 21062306a36Sopenharmony_ci unsigned short reg) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct snd_ice1712 *ice = ac97->private_data; 21362306a36Sopenharmony_ci int tm; 21462306a36Sopenharmony_ci unsigned char old_cmd = 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) { 21762306a36Sopenharmony_ci old_cmd = inb(ICEMT(ice, AC97_CMD)); 21862306a36Sopenharmony_ci if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ)) 21962306a36Sopenharmony_ci continue; 22062306a36Sopenharmony_ci if (!(old_cmd & ICE1712_AC97_READY)) 22162306a36Sopenharmony_ci continue; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci outb(reg, ICEMT(ice, AC97_INDEX)); 22562306a36Sopenharmony_ci outb(old_cmd | ICE1712_AC97_READ, ICEMT(ice, AC97_CMD)); 22662306a36Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) 22762306a36Sopenharmony_ci if ((inb(ICEMT(ice, AC97_CMD)) & ICE1712_AC97_READ) == 0) 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci if (tm >= 0x10000) /* timeout */ 23062306a36Sopenharmony_ci return ~0; 23162306a36Sopenharmony_ci return inw(ICEMT(ice, AC97_DATA)); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/* 23562306a36Sopenharmony_ci * consumer ac97 digital mix 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci#define snd_ice1712_digmix_route_ac97_info snd_ctl_boolean_mono_info 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int snd_ice1712_digmix_route_ac97_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_ROUTECTRL)) & ICE1712_ROUTE_AC97 ? 1 : 0; 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 25062306a36Sopenharmony_ci unsigned char val, nval; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 25362306a36Sopenharmony_ci val = inb(ICEMT(ice, MONITOR_ROUTECTRL)); 25462306a36Sopenharmony_ci nval = val & ~ICE1712_ROUTE_AC97; 25562306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 25662306a36Sopenharmony_ci nval |= ICE1712_ROUTE_AC97; 25762306a36Sopenharmony_ci outb(nval, ICEMT(ice, MONITOR_ROUTECTRL)); 25862306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 25962306a36Sopenharmony_ci return val != nval; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 = { 26362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 26462306a36Sopenharmony_ci .name = "Digital Mixer To AC97", 26562306a36Sopenharmony_ci .info = snd_ice1712_digmix_route_ac97_info, 26662306a36Sopenharmony_ci .get = snd_ice1712_digmix_route_ac97_get, 26762306a36Sopenharmony_ci .put = snd_ice1712_digmix_route_ac97_put, 26862306a36Sopenharmony_ci}; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* 27262306a36Sopenharmony_ci * gpio operations 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_cistatic void snd_ice1712_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, data); 27762306a36Sopenharmony_ci inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */ 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic unsigned int snd_ice1712_get_gpio_dir(struct snd_ice1712 *ice) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic unsigned int snd_ice1712_get_gpio_mask(struct snd_ice1712 *ice) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci return snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void snd_ice1712_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, data); 29362306a36Sopenharmony_ci inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */ 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic unsigned int snd_ice1712_get_gpio_data(struct snd_ice1712 *ice) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void snd_ice1712_set_gpio_data(struct snd_ice1712 *ice, unsigned int val) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, val); 30462306a36Sopenharmony_ci inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */ 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/* 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * CS8427 interface 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/* 31462306a36Sopenharmony_ci * change the input clock selection 31562306a36Sopenharmony_ci * spdif_clock = 1 - IEC958 input, 0 - Envy24 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_cistatic int snd_ice1712_cs8427_set_input_clock(struct snd_ice1712 *ice, int spdif_clock) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci unsigned char reg[2] = { 0x80 | 4, 0 }; /* CS8427 auto increment | register number 4 + data */ 32062306a36Sopenharmony_ci unsigned char val, nval; 32162306a36Sopenharmony_ci int res = 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci snd_i2c_lock(ice->i2c); 32462306a36Sopenharmony_ci if (snd_i2c_sendbytes(ice->cs8427, reg, 1) != 1) { 32562306a36Sopenharmony_ci snd_i2c_unlock(ice->i2c); 32662306a36Sopenharmony_ci return -EIO; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci if (snd_i2c_readbytes(ice->cs8427, &val, 1) != 1) { 32962306a36Sopenharmony_ci snd_i2c_unlock(ice->i2c); 33062306a36Sopenharmony_ci return -EIO; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci nval = val & 0xf0; 33362306a36Sopenharmony_ci if (spdif_clock) 33462306a36Sopenharmony_ci nval |= 0x01; 33562306a36Sopenharmony_ci else 33662306a36Sopenharmony_ci nval |= 0x04; 33762306a36Sopenharmony_ci if (val != nval) { 33862306a36Sopenharmony_ci reg[1] = nval; 33962306a36Sopenharmony_ci if (snd_i2c_sendbytes(ice->cs8427, reg, 2) != 2) { 34062306a36Sopenharmony_ci res = -EIO; 34162306a36Sopenharmony_ci } else { 34262306a36Sopenharmony_ci res++; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci snd_i2c_unlock(ice->i2c); 34662306a36Sopenharmony_ci return res; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* 35062306a36Sopenharmony_ci * spdif callbacks 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_cistatic void open_cs8427(struct snd_ice1712 *ice, struct snd_pcm_substream *substream) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci snd_cs8427_iec958_active(ice->cs8427, 1); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void close_cs8427(struct snd_ice1712 *ice, struct snd_pcm_substream *substream) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci snd_cs8427_iec958_active(ice->cs8427, 0); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void setup_cs8427(struct snd_ice1712 *ice, int rate) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci snd_cs8427_iec958_pcm(ice->cs8427, rate); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* 36862306a36Sopenharmony_ci * create and initialize callbacks for cs8427 interface 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_ciint snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci int err; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci err = snd_cs8427_create(ice->i2c, addr, 37562306a36Sopenharmony_ci (ice->cs8427_timeout * HZ) / 1000, &ice->cs8427); 37662306a36Sopenharmony_ci if (err < 0) { 37762306a36Sopenharmony_ci dev_err(ice->card->dev, "CS8427 initialization failed\n"); 37862306a36Sopenharmony_ci return err; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci ice->spdif.ops.open = open_cs8427; 38162306a36Sopenharmony_ci ice->spdif.ops.close = close_cs8427; 38262306a36Sopenharmony_ci ice->spdif.ops.setup_rate = setup_cs8427; 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdif_is_master) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci /* change CS8427 clock source too */ 38962306a36Sopenharmony_ci if (ice->cs8427) 39062306a36Sopenharmony_ci snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master); 39162306a36Sopenharmony_ci /* notify ak4524 chip as well */ 39262306a36Sopenharmony_ci if (spdif_is_master) { 39362306a36Sopenharmony_ci unsigned int i; 39462306a36Sopenharmony_ci for (i = 0; i < ice->akm_codecs; i++) { 39562306a36Sopenharmony_ci if (ice->akm[i].ops.set_rate_val) 39662306a36Sopenharmony_ci ice->akm[i].ops.set_rate_val(&ice->akm[i], 0); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/* 40262306a36Sopenharmony_ci * Interrupt handler 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct snd_ice1712 *ice = dev_id; 40862306a36Sopenharmony_ci unsigned char status; 40962306a36Sopenharmony_ci int handled = 0; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci while (1) { 41262306a36Sopenharmony_ci status = inb(ICEREG(ice, IRQSTAT)); 41362306a36Sopenharmony_ci if (status == 0) 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci handled = 1; 41662306a36Sopenharmony_ci if (status & ICE1712_IRQ_MPU1) { 41762306a36Sopenharmony_ci if (ice->rmidi[0]) 41862306a36Sopenharmony_ci snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data); 41962306a36Sopenharmony_ci outb(ICE1712_IRQ_MPU1, ICEREG(ice, IRQSTAT)); 42062306a36Sopenharmony_ci status &= ~ICE1712_IRQ_MPU1; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci if (status & ICE1712_IRQ_TIMER) 42362306a36Sopenharmony_ci outb(ICE1712_IRQ_TIMER, ICEREG(ice, IRQSTAT)); 42462306a36Sopenharmony_ci if (status & ICE1712_IRQ_MPU2) { 42562306a36Sopenharmony_ci if (ice->rmidi[1]) 42662306a36Sopenharmony_ci snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data); 42762306a36Sopenharmony_ci outb(ICE1712_IRQ_MPU2, ICEREG(ice, IRQSTAT)); 42862306a36Sopenharmony_ci status &= ~ICE1712_IRQ_MPU2; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci if (status & ICE1712_IRQ_PROPCM) { 43162306a36Sopenharmony_ci unsigned char mtstat = inb(ICEMT(ice, IRQ)); 43262306a36Sopenharmony_ci if (mtstat & ICE1712_MULTI_PBKSTATUS) { 43362306a36Sopenharmony_ci if (ice->playback_pro_substream) 43462306a36Sopenharmony_ci snd_pcm_period_elapsed(ice->playback_pro_substream); 43562306a36Sopenharmony_ci outb(ICE1712_MULTI_PBKSTATUS, ICEMT(ice, IRQ)); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci if (mtstat & ICE1712_MULTI_CAPSTATUS) { 43862306a36Sopenharmony_ci if (ice->capture_pro_substream) 43962306a36Sopenharmony_ci snd_pcm_period_elapsed(ice->capture_pro_substream); 44062306a36Sopenharmony_ci outb(ICE1712_MULTI_CAPSTATUS, ICEMT(ice, IRQ)); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci if (status & ICE1712_IRQ_FM) 44462306a36Sopenharmony_ci outb(ICE1712_IRQ_FM, ICEREG(ice, IRQSTAT)); 44562306a36Sopenharmony_ci if (status & ICE1712_IRQ_PBKDS) { 44662306a36Sopenharmony_ci u32 idx; 44762306a36Sopenharmony_ci u16 pbkstatus; 44862306a36Sopenharmony_ci struct snd_pcm_substream *substream; 44962306a36Sopenharmony_ci pbkstatus = inw(ICEDS(ice, INTSTAT)); 45062306a36Sopenharmony_ci /* dev_dbg(ice->card->dev, "pbkstatus = 0x%x\n", pbkstatus); */ 45162306a36Sopenharmony_ci for (idx = 0; idx < 6; idx++) { 45262306a36Sopenharmony_ci if ((pbkstatus & (3 << (idx * 2))) == 0) 45362306a36Sopenharmony_ci continue; 45462306a36Sopenharmony_ci substream = ice->playback_con_substream_ds[idx]; 45562306a36Sopenharmony_ci if (substream != NULL) 45662306a36Sopenharmony_ci snd_pcm_period_elapsed(substream); 45762306a36Sopenharmony_ci outw(3 << (idx * 2), ICEDS(ice, INTSTAT)); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci outb(ICE1712_IRQ_PBKDS, ICEREG(ice, IRQSTAT)); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci if (status & ICE1712_IRQ_CONCAP) { 46262306a36Sopenharmony_ci if (ice->capture_con_substream) 46362306a36Sopenharmony_ci snd_pcm_period_elapsed(ice->capture_con_substream); 46462306a36Sopenharmony_ci outb(ICE1712_IRQ_CONCAP, ICEREG(ice, IRQSTAT)); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci if (status & ICE1712_IRQ_CONPBK) { 46762306a36Sopenharmony_ci if (ice->playback_con_substream) 46862306a36Sopenharmony_ci snd_pcm_period_elapsed(ice->playback_con_substream); 46962306a36Sopenharmony_ci outb(ICE1712_IRQ_CONPBK, ICEREG(ice, IRQSTAT)); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci return IRQ_RETVAL(handled); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/* 47762306a36Sopenharmony_ci * PCM part - consumer I/O 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int snd_ice1712_playback_trigger(struct snd_pcm_substream *substream, 48162306a36Sopenharmony_ci int cmd) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 48462306a36Sopenharmony_ci int result = 0; 48562306a36Sopenharmony_ci u32 tmp; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci spin_lock(&ice->reg_lock); 48862306a36Sopenharmony_ci tmp = snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL); 48962306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) { 49062306a36Sopenharmony_ci tmp |= 1; 49162306a36Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { 49262306a36Sopenharmony_ci tmp &= ~1; 49362306a36Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) { 49462306a36Sopenharmony_ci tmp |= 2; 49562306a36Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) { 49662306a36Sopenharmony_ci tmp &= ~2; 49762306a36Sopenharmony_ci } else { 49862306a36Sopenharmony_ci result = -EINVAL; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_CTRL, tmp); 50162306a36Sopenharmony_ci spin_unlock(&ice->reg_lock); 50262306a36Sopenharmony_ci return result; 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic int snd_ice1712_playback_ds_trigger(struct snd_pcm_substream *substream, 50662306a36Sopenharmony_ci int cmd) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 50962306a36Sopenharmony_ci int result = 0; 51062306a36Sopenharmony_ci u32 tmp; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci spin_lock(&ice->reg_lock); 51362306a36Sopenharmony_ci tmp = snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL); 51462306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) { 51562306a36Sopenharmony_ci tmp |= 1; 51662306a36Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { 51762306a36Sopenharmony_ci tmp &= ~1; 51862306a36Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) { 51962306a36Sopenharmony_ci tmp |= 2; 52062306a36Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) { 52162306a36Sopenharmony_ci tmp &= ~2; 52262306a36Sopenharmony_ci } else { 52362306a36Sopenharmony_ci result = -EINVAL; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci snd_ice1712_ds_write(ice, substream->number * 2, ICE1712_DSC_CONTROL, tmp); 52662306a36Sopenharmony_ci spin_unlock(&ice->reg_lock); 52762306a36Sopenharmony_ci return result; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic int snd_ice1712_capture_trigger(struct snd_pcm_substream *substream, 53162306a36Sopenharmony_ci int cmd) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 53462306a36Sopenharmony_ci int result = 0; 53562306a36Sopenharmony_ci u8 tmp; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci spin_lock(&ice->reg_lock); 53862306a36Sopenharmony_ci tmp = snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL); 53962306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) { 54062306a36Sopenharmony_ci tmp |= 1; 54162306a36Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { 54262306a36Sopenharmony_ci tmp &= ~1; 54362306a36Sopenharmony_ci } else { 54462306a36Sopenharmony_ci result = -EINVAL; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp); 54762306a36Sopenharmony_ci spin_unlock(&ice->reg_lock); 54862306a36Sopenharmony_ci return result; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic int snd_ice1712_playback_prepare(struct snd_pcm_substream *substream) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 55462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 55562306a36Sopenharmony_ci u32 period_size, buf_size, rate, tmp; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci period_size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1; 55862306a36Sopenharmony_ci buf_size = snd_pcm_lib_buffer_bytes(substream) - 1; 55962306a36Sopenharmony_ci tmp = 0x0000; 56062306a36Sopenharmony_ci if (snd_pcm_format_width(runtime->format) == 16) 56162306a36Sopenharmony_ci tmp |= 0x10; 56262306a36Sopenharmony_ci if (runtime->channels == 2) 56362306a36Sopenharmony_ci tmp |= 0x08; 56462306a36Sopenharmony_ci rate = (runtime->rate * 8192) / 375; 56562306a36Sopenharmony_ci if (rate > 0x000fffff) 56662306a36Sopenharmony_ci rate = 0x000fffff; 56762306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 56862306a36Sopenharmony_ci outb(0, ice->ddma_port + 15); 56962306a36Sopenharmony_ci outb(ICE1712_DMA_MODE_WRITE | ICE1712_DMA_AUTOINIT, ice->ddma_port + 0x0b); 57062306a36Sopenharmony_ci outl(runtime->dma_addr, ice->ddma_port + 0); 57162306a36Sopenharmony_ci outw(buf_size, ice->ddma_port + 4); 57262306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_LO, rate & 0xff); 57362306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_MID, (rate >> 8) & 0xff); 57462306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_HI, (rate >> 16) & 0xff); 57562306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_CTRL, tmp); 57662306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_COUNT_LO, period_size & 0xff); 57762306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_COUNT_HI, period_size >> 8); 57862306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_LEFT, 0); 57962306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PBK_RIGHT, 0); 58062306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 58762306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 58862306a36Sopenharmony_ci u32 period_size, rate, tmp, chn; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci period_size = snd_pcm_lib_period_bytes(substream) - 1; 59162306a36Sopenharmony_ci tmp = 0x0064; 59262306a36Sopenharmony_ci if (snd_pcm_format_width(runtime->format) == 16) 59362306a36Sopenharmony_ci tmp &= ~0x04; 59462306a36Sopenharmony_ci if (runtime->channels == 2) 59562306a36Sopenharmony_ci tmp |= 0x08; 59662306a36Sopenharmony_ci rate = (runtime->rate * 8192) / 375; 59762306a36Sopenharmony_ci if (rate > 0x000fffff) 59862306a36Sopenharmony_ci rate = 0x000fffff; 59962306a36Sopenharmony_ci ice->playback_con_active_buf[substream->number] = 0; 60062306a36Sopenharmony_ci ice->playback_con_virt_addr[substream->number] = runtime->dma_addr; 60162306a36Sopenharmony_ci chn = substream->number * 2; 60262306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 60362306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR0, runtime->dma_addr); 60462306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn, ICE1712_DSC_COUNT0, period_size); 60562306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR1, runtime->dma_addr + (runtime->periods > 1 ? period_size + 1 : 0)); 60662306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn, ICE1712_DSC_COUNT1, period_size); 60762306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn, ICE1712_DSC_RATE, rate); 60862306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn, ICE1712_DSC_VOLUME, 0); 60962306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn, ICE1712_DSC_CONTROL, tmp); 61062306a36Sopenharmony_ci if (runtime->channels == 2) { 61162306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_RATE, rate); 61262306a36Sopenharmony_ci snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_VOLUME, 0); 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 61562306a36Sopenharmony_ci return 0; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic int snd_ice1712_capture_prepare(struct snd_pcm_substream *substream) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 62162306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 62262306a36Sopenharmony_ci u32 period_size, buf_size; 62362306a36Sopenharmony_ci u8 tmp; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci period_size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1; 62662306a36Sopenharmony_ci buf_size = snd_pcm_lib_buffer_bytes(substream) - 1; 62762306a36Sopenharmony_ci tmp = 0x06; 62862306a36Sopenharmony_ci if (snd_pcm_format_width(runtime->format) == 16) 62962306a36Sopenharmony_ci tmp &= ~0x04; 63062306a36Sopenharmony_ci if (runtime->channels == 2) 63162306a36Sopenharmony_ci tmp &= ~0x02; 63262306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 63362306a36Sopenharmony_ci outl(ice->capture_con_virt_addr = runtime->dma_addr, ICEREG(ice, CONCAP_ADDR)); 63462306a36Sopenharmony_ci outw(buf_size, ICEREG(ice, CONCAP_COUNT)); 63562306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_HI, period_size >> 8); 63662306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_LO, period_size & 0xff); 63762306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp); 63862306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 63962306a36Sopenharmony_ci snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ice1712_playback_pointer(struct snd_pcm_substream *substream) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 64662306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 64762306a36Sopenharmony_ci size_t ptr; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (!(snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL) & 1)) 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci ptr = runtime->buffer_size - inw(ice->ddma_port + 4); 65262306a36Sopenharmony_ci ptr = bytes_to_frames(substream->runtime, ptr); 65362306a36Sopenharmony_ci if (ptr == runtime->buffer_size) 65462306a36Sopenharmony_ci ptr = 0; 65562306a36Sopenharmony_ci return ptr; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(struct snd_pcm_substream *substream) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 66162306a36Sopenharmony_ci u8 addr; 66262306a36Sopenharmony_ci size_t ptr; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (!(snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL) & 1)) 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci if (ice->playback_con_active_buf[substream->number]) 66762306a36Sopenharmony_ci addr = ICE1712_DSC_ADDR1; 66862306a36Sopenharmony_ci else 66962306a36Sopenharmony_ci addr = ICE1712_DSC_ADDR0; 67062306a36Sopenharmony_ci ptr = snd_ice1712_ds_read(ice, substream->number * 2, addr) - 67162306a36Sopenharmony_ci ice->playback_con_virt_addr[substream->number]; 67262306a36Sopenharmony_ci ptr = bytes_to_frames(substream->runtime, ptr); 67362306a36Sopenharmony_ci if (ptr == substream->runtime->buffer_size) 67462306a36Sopenharmony_ci ptr = 0; 67562306a36Sopenharmony_ci return ptr; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *substream) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 68162306a36Sopenharmony_ci size_t ptr; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (!(snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL) & 1)) 68462306a36Sopenharmony_ci return 0; 68562306a36Sopenharmony_ci ptr = inl(ICEREG(ice, CONCAP_ADDR)) - ice->capture_con_virt_addr; 68662306a36Sopenharmony_ci ptr = bytes_to_frames(substream->runtime, ptr); 68762306a36Sopenharmony_ci if (ptr == substream->runtime->buffer_size) 68862306a36Sopenharmony_ci ptr = 0; 68962306a36Sopenharmony_ci return ptr; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ice1712_playback = { 69362306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 69462306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 69562306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 69662306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE), 69762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 69862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, 69962306a36Sopenharmony_ci .rate_min = 4000, 70062306a36Sopenharmony_ci .rate_max = 48000, 70162306a36Sopenharmony_ci .channels_min = 1, 70262306a36Sopenharmony_ci .channels_max = 2, 70362306a36Sopenharmony_ci .buffer_bytes_max = (64*1024), 70462306a36Sopenharmony_ci .period_bytes_min = 64, 70562306a36Sopenharmony_ci .period_bytes_max = (64*1024), 70662306a36Sopenharmony_ci .periods_min = 1, 70762306a36Sopenharmony_ci .periods_max = 1024, 70862306a36Sopenharmony_ci .fifo_size = 0, 70962306a36Sopenharmony_ci}; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ice1712_playback_ds = { 71262306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 71362306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 71462306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 71562306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE), 71662306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 71762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, 71862306a36Sopenharmony_ci .rate_min = 4000, 71962306a36Sopenharmony_ci .rate_max = 48000, 72062306a36Sopenharmony_ci .channels_min = 1, 72162306a36Sopenharmony_ci .channels_max = 2, 72262306a36Sopenharmony_ci .buffer_bytes_max = (128*1024), 72362306a36Sopenharmony_ci .period_bytes_min = 64, 72462306a36Sopenharmony_ci .period_bytes_max = (128*1024), 72562306a36Sopenharmony_ci .periods_min = 2, 72662306a36Sopenharmony_ci .periods_max = 2, 72762306a36Sopenharmony_ci .fifo_size = 0, 72862306a36Sopenharmony_ci}; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ice1712_capture = { 73162306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 73262306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 73362306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID), 73462306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 73562306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, 73662306a36Sopenharmony_ci .rate_min = 4000, 73762306a36Sopenharmony_ci .rate_max = 48000, 73862306a36Sopenharmony_ci .channels_min = 1, 73962306a36Sopenharmony_ci .channels_max = 2, 74062306a36Sopenharmony_ci .buffer_bytes_max = (64*1024), 74162306a36Sopenharmony_ci .period_bytes_min = 64, 74262306a36Sopenharmony_ci .period_bytes_max = (64*1024), 74362306a36Sopenharmony_ci .periods_min = 1, 74462306a36Sopenharmony_ci .periods_max = 1024, 74562306a36Sopenharmony_ci .fifo_size = 0, 74662306a36Sopenharmony_ci}; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic int snd_ice1712_playback_open(struct snd_pcm_substream *substream) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 75162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci ice->playback_con_substream = substream; 75462306a36Sopenharmony_ci runtime->hw = snd_ice1712_playback; 75562306a36Sopenharmony_ci return 0; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic int snd_ice1712_playback_ds_open(struct snd_pcm_substream *substream) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 76162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 76262306a36Sopenharmony_ci u32 tmp; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci ice->playback_con_substream_ds[substream->number] = substream; 76562306a36Sopenharmony_ci runtime->hw = snd_ice1712_playback_ds; 76662306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 76762306a36Sopenharmony_ci tmp = inw(ICEDS(ice, INTMASK)) & ~(1 << (substream->number * 2)); 76862306a36Sopenharmony_ci outw(tmp, ICEDS(ice, INTMASK)); 76962306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic int snd_ice1712_capture_open(struct snd_pcm_substream *substream) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 77662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ice->capture_con_substream = substream; 77962306a36Sopenharmony_ci runtime->hw = snd_ice1712_capture; 78062306a36Sopenharmony_ci runtime->hw.rates = ice->ac97->rates[AC97_RATES_ADC]; 78162306a36Sopenharmony_ci if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000)) 78262306a36Sopenharmony_ci runtime->hw.rate_min = 48000; 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int snd_ice1712_playback_close(struct snd_pcm_substream *substream) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci ice->playback_con_substream = NULL; 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic int snd_ice1712_playback_ds_close(struct snd_pcm_substream *substream) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 79762306a36Sopenharmony_ci u32 tmp; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 80062306a36Sopenharmony_ci tmp = inw(ICEDS(ice, INTMASK)) | (3 << (substream->number * 2)); 80162306a36Sopenharmony_ci outw(tmp, ICEDS(ice, INTMASK)); 80262306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 80362306a36Sopenharmony_ci ice->playback_con_substream_ds[substream->number] = NULL; 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic int snd_ice1712_capture_close(struct snd_pcm_substream *substream) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci ice->capture_con_substream = NULL; 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ice1712_playback_ops = { 81662306a36Sopenharmony_ci .open = snd_ice1712_playback_open, 81762306a36Sopenharmony_ci .close = snd_ice1712_playback_close, 81862306a36Sopenharmony_ci .prepare = snd_ice1712_playback_prepare, 81962306a36Sopenharmony_ci .trigger = snd_ice1712_playback_trigger, 82062306a36Sopenharmony_ci .pointer = snd_ice1712_playback_pointer, 82162306a36Sopenharmony_ci}; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ice1712_playback_ds_ops = { 82462306a36Sopenharmony_ci .open = snd_ice1712_playback_ds_open, 82562306a36Sopenharmony_ci .close = snd_ice1712_playback_ds_close, 82662306a36Sopenharmony_ci .prepare = snd_ice1712_playback_ds_prepare, 82762306a36Sopenharmony_ci .trigger = snd_ice1712_playback_ds_trigger, 82862306a36Sopenharmony_ci .pointer = snd_ice1712_playback_ds_pointer, 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ice1712_capture_ops = { 83262306a36Sopenharmony_ci .open = snd_ice1712_capture_open, 83362306a36Sopenharmony_ci .close = snd_ice1712_capture_close, 83462306a36Sopenharmony_ci .prepare = snd_ice1712_capture_prepare, 83562306a36Sopenharmony_ci .trigger = snd_ice1712_capture_trigger, 83662306a36Sopenharmony_ci .pointer = snd_ice1712_capture_pointer, 83762306a36Sopenharmony_ci}; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic int snd_ice1712_pcm(struct snd_ice1712 *ice, int device) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct snd_pcm *pcm; 84262306a36Sopenharmony_ci int err; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci err = snd_pcm_new(ice->card, "ICE1712 consumer", device, 1, 1, &pcm); 84562306a36Sopenharmony_ci if (err < 0) 84662306a36Sopenharmony_ci return err; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_ops); 84962306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ice1712_capture_ops); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci pcm->private_data = ice; 85262306a36Sopenharmony_ci pcm->info_flags = 0; 85362306a36Sopenharmony_ci strcpy(pcm->name, "ICE1712 consumer"); 85462306a36Sopenharmony_ci ice->pcm = pcm; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 85762306a36Sopenharmony_ci &ice->pci->dev, 64*1024, 64*1024); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci dev_warn(ice->card->dev, 86062306a36Sopenharmony_ci "Consumer PCM code does not work well at the moment --jk\n"); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return 0; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct snd_pcm *pcm; 86862306a36Sopenharmony_ci int err; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm); 87162306a36Sopenharmony_ci if (err < 0) 87262306a36Sopenharmony_ci return err; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_ds_ops); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci pcm->private_data = ice; 87762306a36Sopenharmony_ci pcm->info_flags = 0; 87862306a36Sopenharmony_ci strcpy(pcm->name, "ICE1712 consumer (DS)"); 87962306a36Sopenharmony_ci ice->pcm_ds = pcm; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 88262306a36Sopenharmony_ci &ice->pci->dev, 64*1024, 128*1024); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci return 0; 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci/* 88862306a36Sopenharmony_ci * PCM code - professional part (multitrack) 88962306a36Sopenharmony_ci */ 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic const unsigned int rates[] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000, 89262306a36Sopenharmony_ci 32000, 44100, 48000, 64000, 88200, 96000 }; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_rates = { 89562306a36Sopenharmony_ci .count = ARRAY_SIZE(rates), 89662306a36Sopenharmony_ci .list = rates, 89762306a36Sopenharmony_ci .mask = 0, 89862306a36Sopenharmony_ci}; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistatic int snd_ice1712_pro_trigger(struct snd_pcm_substream *substream, 90162306a36Sopenharmony_ci int cmd) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 90462306a36Sopenharmony_ci switch (cmd) { 90562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 90662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 90762306a36Sopenharmony_ci { 90862306a36Sopenharmony_ci unsigned int what; 90962306a36Sopenharmony_ci unsigned int old; 91062306a36Sopenharmony_ci if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) 91162306a36Sopenharmony_ci return -EINVAL; 91262306a36Sopenharmony_ci what = ICE1712_PLAYBACK_PAUSE; 91362306a36Sopenharmony_ci snd_pcm_trigger_done(substream, substream); 91462306a36Sopenharmony_ci spin_lock(&ice->reg_lock); 91562306a36Sopenharmony_ci old = inl(ICEMT(ice, PLAYBACK_CONTROL)); 91662306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) 91762306a36Sopenharmony_ci old |= what; 91862306a36Sopenharmony_ci else 91962306a36Sopenharmony_ci old &= ~what; 92062306a36Sopenharmony_ci outl(old, ICEMT(ice, PLAYBACK_CONTROL)); 92162306a36Sopenharmony_ci spin_unlock(&ice->reg_lock); 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 92562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 92662306a36Sopenharmony_ci { 92762306a36Sopenharmony_ci unsigned int what = 0; 92862306a36Sopenharmony_ci unsigned int old; 92962306a36Sopenharmony_ci struct snd_pcm_substream *s; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 93262306a36Sopenharmony_ci if (s == ice->playback_pro_substream) { 93362306a36Sopenharmony_ci what |= ICE1712_PLAYBACK_START; 93462306a36Sopenharmony_ci snd_pcm_trigger_done(s, substream); 93562306a36Sopenharmony_ci } else if (s == ice->capture_pro_substream) { 93662306a36Sopenharmony_ci what |= ICE1712_CAPTURE_START_SHADOW; 93762306a36Sopenharmony_ci snd_pcm_trigger_done(s, substream); 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci spin_lock(&ice->reg_lock); 94162306a36Sopenharmony_ci old = inl(ICEMT(ice, PLAYBACK_CONTROL)); 94262306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) 94362306a36Sopenharmony_ci old |= what; 94462306a36Sopenharmony_ci else 94562306a36Sopenharmony_ci old &= ~what; 94662306a36Sopenharmony_ci outl(old, ICEMT(ice, PLAYBACK_CONTROL)); 94762306a36Sopenharmony_ci spin_unlock(&ice->reg_lock); 94862306a36Sopenharmony_ci break; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci default: 95162306a36Sopenharmony_ci return -EINVAL; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci return 0; 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci/* 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_cistatic void snd_ice1712_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, int force) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci unsigned long flags; 96162306a36Sopenharmony_ci unsigned char val, old; 96262306a36Sopenharmony_ci unsigned int i; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci switch (rate) { 96562306a36Sopenharmony_ci case 8000: val = 6; break; 96662306a36Sopenharmony_ci case 9600: val = 3; break; 96762306a36Sopenharmony_ci case 11025: val = 10; break; 96862306a36Sopenharmony_ci case 12000: val = 2; break; 96962306a36Sopenharmony_ci case 16000: val = 5; break; 97062306a36Sopenharmony_ci case 22050: val = 9; break; 97162306a36Sopenharmony_ci case 24000: val = 1; break; 97262306a36Sopenharmony_ci case 32000: val = 4; break; 97362306a36Sopenharmony_ci case 44100: val = 8; break; 97462306a36Sopenharmony_ci case 48000: val = 0; break; 97562306a36Sopenharmony_ci case 64000: val = 15; break; 97662306a36Sopenharmony_ci case 88200: val = 11; break; 97762306a36Sopenharmony_ci case 96000: val = 7; break; 97862306a36Sopenharmony_ci default: 97962306a36Sopenharmony_ci snd_BUG(); 98062306a36Sopenharmony_ci val = 0; 98162306a36Sopenharmony_ci rate = 48000; 98262306a36Sopenharmony_ci break; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci spin_lock_irqsave(&ice->reg_lock, flags); 98662306a36Sopenharmony_ci if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW| 98762306a36Sopenharmony_ci ICE1712_PLAYBACK_PAUSE| 98862306a36Sopenharmony_ci ICE1712_PLAYBACK_START)) { 98962306a36Sopenharmony_ci__out: 99062306a36Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 99162306a36Sopenharmony_ci return; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci if (!force && is_pro_rate_locked(ice)) 99462306a36Sopenharmony_ci goto __out; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci old = inb(ICEMT(ice, RATE)); 99762306a36Sopenharmony_ci if (!force && old == val) 99862306a36Sopenharmony_ci goto __out; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci ice->cur_rate = rate; 100162306a36Sopenharmony_ci outb(val, ICEMT(ice, RATE)); 100262306a36Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (ice->gpio.set_pro_rate) 100562306a36Sopenharmony_ci ice->gpio.set_pro_rate(ice, rate); 100662306a36Sopenharmony_ci for (i = 0; i < ice->akm_codecs; i++) { 100762306a36Sopenharmony_ci if (ice->akm[i].ops.set_rate_val) 100862306a36Sopenharmony_ci ice->akm[i].ops.set_rate_val(&ice->akm[i], rate); 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci if (ice->spdif.ops.setup_rate) 101162306a36Sopenharmony_ci ice->spdif.ops.setup_rate(ice, rate); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic int snd_ice1712_playback_pro_prepare(struct snd_pcm_substream *substream) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream); 101962306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 102062306a36Sopenharmony_ci outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR)); 102162306a36Sopenharmony_ci outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE)); 102262306a36Sopenharmony_ci outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, PLAYBACK_COUNT)); 102362306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic int snd_ice1712_playback_pro_hw_params(struct snd_pcm_substream *substream, 102962306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0); 103462306a36Sopenharmony_ci return 0; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic int snd_ice1712_capture_pro_prepare(struct snd_pcm_substream *substream) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream); 104262306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 104362306a36Sopenharmony_ci outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR)); 104462306a36Sopenharmony_ci outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE)); 104562306a36Sopenharmony_ci outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, CAPTURE_COUNT)); 104662306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 104762306a36Sopenharmony_ci return 0; 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cistatic int snd_ice1712_capture_pro_hw_params(struct snd_pcm_substream *substream, 105162306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0); 105662306a36Sopenharmony_ci return 0; 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ice1712_playback_pro_pointer(struct snd_pcm_substream *substream) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 106262306a36Sopenharmony_ci size_t ptr; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START)) 106562306a36Sopenharmony_ci return 0; 106662306a36Sopenharmony_ci ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2); 106762306a36Sopenharmony_ci ptr = bytes_to_frames(substream->runtime, ptr); 106862306a36Sopenharmony_ci if (ptr == substream->runtime->buffer_size) 106962306a36Sopenharmony_ci ptr = 0; 107062306a36Sopenharmony_ci return ptr; 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substream *substream) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 107662306a36Sopenharmony_ci size_t ptr; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_CAPTURE_START_SHADOW)) 107962306a36Sopenharmony_ci return 0; 108062306a36Sopenharmony_ci ptr = ice->capture_pro_size - (inw(ICEMT(ice, CAPTURE_SIZE)) << 2); 108162306a36Sopenharmony_ci ptr = bytes_to_frames(substream->runtime, ptr); 108262306a36Sopenharmony_ci if (ptr == substream->runtime->buffer_size) 108362306a36Sopenharmony_ci ptr = 0; 108462306a36Sopenharmony_ci return ptr; 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ice1712_playback_pro = { 108862306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 108962306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 109062306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 109162306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), 109262306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 109362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000, 109462306a36Sopenharmony_ci .rate_min = 4000, 109562306a36Sopenharmony_ci .rate_max = 96000, 109662306a36Sopenharmony_ci .channels_min = 10, 109762306a36Sopenharmony_ci .channels_max = 10, 109862306a36Sopenharmony_ci .buffer_bytes_max = (256*1024), 109962306a36Sopenharmony_ci .period_bytes_min = 10 * 4 * 2, 110062306a36Sopenharmony_ci .period_bytes_max = 131040, 110162306a36Sopenharmony_ci .periods_min = 1, 110262306a36Sopenharmony_ci .periods_max = 1024, 110362306a36Sopenharmony_ci .fifo_size = 0, 110462306a36Sopenharmony_ci}; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ice1712_capture_pro = { 110762306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 110862306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 110962306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 111062306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), 111162306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 111262306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000, 111362306a36Sopenharmony_ci .rate_min = 4000, 111462306a36Sopenharmony_ci .rate_max = 96000, 111562306a36Sopenharmony_ci .channels_min = 12, 111662306a36Sopenharmony_ci .channels_max = 12, 111762306a36Sopenharmony_ci .buffer_bytes_max = (256*1024), 111862306a36Sopenharmony_ci .period_bytes_min = 12 * 4 * 2, 111962306a36Sopenharmony_ci .period_bytes_max = 131040, 112062306a36Sopenharmony_ci .periods_min = 1, 112162306a36Sopenharmony_ci .periods_max = 1024, 112262306a36Sopenharmony_ci .fifo_size = 0, 112362306a36Sopenharmony_ci}; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic int snd_ice1712_playback_pro_open(struct snd_pcm_substream *substream) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 112862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci ice->playback_pro_substream = substream; 113162306a36Sopenharmony_ci runtime->hw = snd_ice1712_playback_pro; 113262306a36Sopenharmony_ci snd_pcm_set_sync(substream); 113362306a36Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 113462306a36Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); 113562306a36Sopenharmony_ci if (is_pro_rate_locked(ice)) { 113662306a36Sopenharmony_ci runtime->hw.rate_min = PRO_RATE_DEFAULT; 113762306a36Sopenharmony_ci runtime->hw.rate_max = PRO_RATE_DEFAULT; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci if (ice->spdif.ops.open) 114162306a36Sopenharmony_ci ice->spdif.ops.open(ice, substream); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci return 0; 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic int snd_ice1712_capture_pro_open(struct snd_pcm_substream *substream) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 114962306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci ice->capture_pro_substream = substream; 115262306a36Sopenharmony_ci runtime->hw = snd_ice1712_capture_pro; 115362306a36Sopenharmony_ci snd_pcm_set_sync(substream); 115462306a36Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 115562306a36Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); 115662306a36Sopenharmony_ci if (is_pro_rate_locked(ice)) { 115762306a36Sopenharmony_ci runtime->hw.rate_min = PRO_RATE_DEFAULT; 115862306a36Sopenharmony_ci runtime->hw.rate_max = PRO_RATE_DEFAULT; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci return 0; 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cistatic int snd_ice1712_playback_pro_close(struct snd_pcm_substream *substream) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (PRO_RATE_RESET) 116962306a36Sopenharmony_ci snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0); 117062306a36Sopenharmony_ci ice->playback_pro_substream = NULL; 117162306a36Sopenharmony_ci if (ice->spdif.ops.close) 117262306a36Sopenharmony_ci ice->spdif.ops.close(ice, substream); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci return 0; 117562306a36Sopenharmony_ci} 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cistatic int snd_ice1712_capture_pro_close(struct snd_pcm_substream *substream) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (PRO_RATE_RESET) 118262306a36Sopenharmony_ci snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0); 118362306a36Sopenharmony_ci ice->capture_pro_substream = NULL; 118462306a36Sopenharmony_ci return 0; 118562306a36Sopenharmony_ci} 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ice1712_playback_pro_ops = { 118862306a36Sopenharmony_ci .open = snd_ice1712_playback_pro_open, 118962306a36Sopenharmony_ci .close = snd_ice1712_playback_pro_close, 119062306a36Sopenharmony_ci .hw_params = snd_ice1712_playback_pro_hw_params, 119162306a36Sopenharmony_ci .prepare = snd_ice1712_playback_pro_prepare, 119262306a36Sopenharmony_ci .trigger = snd_ice1712_pro_trigger, 119362306a36Sopenharmony_ci .pointer = snd_ice1712_playback_pro_pointer, 119462306a36Sopenharmony_ci}; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ice1712_capture_pro_ops = { 119762306a36Sopenharmony_ci .open = snd_ice1712_capture_pro_open, 119862306a36Sopenharmony_ci .close = snd_ice1712_capture_pro_close, 119962306a36Sopenharmony_ci .hw_params = snd_ice1712_capture_pro_hw_params, 120062306a36Sopenharmony_ci .prepare = snd_ice1712_capture_pro_prepare, 120162306a36Sopenharmony_ci .trigger = snd_ice1712_pro_trigger, 120262306a36Sopenharmony_ci .pointer = snd_ice1712_capture_pro_pointer, 120362306a36Sopenharmony_ci}; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_cistatic int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci struct snd_pcm *pcm; 120862306a36Sopenharmony_ci int err; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm); 121162306a36Sopenharmony_ci if (err < 0) 121262306a36Sopenharmony_ci return err; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_pro_ops); 121562306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ice1712_capture_pro_ops); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci pcm->private_data = ice; 121862306a36Sopenharmony_ci pcm->info_flags = 0; 121962306a36Sopenharmony_ci strcpy(pcm->name, "ICE1712 multi"); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 122262306a36Sopenharmony_ci &ice->pci->dev, 256*1024, 256*1024); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci ice->pcm_pro = pcm; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (ice->cs8427) { 122762306a36Sopenharmony_ci /* assign channels to iec958 */ 122862306a36Sopenharmony_ci err = snd_cs8427_iec958_build(ice->cs8427, 122962306a36Sopenharmony_ci pcm->streams[0].substream, 123062306a36Sopenharmony_ci pcm->streams[1].substream); 123162306a36Sopenharmony_ci if (err < 0) 123262306a36Sopenharmony_ci return err; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return snd_ice1712_build_pro_mixer(ice); 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci/* 123962306a36Sopenharmony_ci * Mixer section 124062306a36Sopenharmony_ci */ 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_cistatic void snd_ice1712_update_volume(struct snd_ice1712 *ice, int index) 124362306a36Sopenharmony_ci{ 124462306a36Sopenharmony_ci unsigned int vol = ice->pro_volumes[index]; 124562306a36Sopenharmony_ci unsigned short val = 0; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci val |= (vol & 0x8000) == 0 ? (96 - (vol & 0x7f)) : 0x7f; 124862306a36Sopenharmony_ci val |= ((vol & 0x80000000) == 0 ? (96 - ((vol >> 16) & 0x7f)) : 0x7f) << 8; 124962306a36Sopenharmony_ci outb(index, ICEMT(ice, MONITOR_INDEX)); 125062306a36Sopenharmony_ci outw(val, ICEMT(ice, MONITOR_VOLUME)); 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci#define snd_ice1712_pro_mixer_switch_info snd_ctl_boolean_stereo_info 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic int snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 125862306a36Sopenharmony_ci int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + 125962306a36Sopenharmony_ci kcontrol->private_value; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 126262306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 126362306a36Sopenharmony_ci !((ice->pro_volumes[priv_idx] >> 15) & 1); 126462306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 126562306a36Sopenharmony_ci !((ice->pro_volumes[priv_idx] >> 31) & 1); 126662306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 126762306a36Sopenharmony_ci return 0; 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistatic int snd_ice1712_pro_mixer_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 127162306a36Sopenharmony_ci{ 127262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 127362306a36Sopenharmony_ci int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + 127462306a36Sopenharmony_ci kcontrol->private_value; 127562306a36Sopenharmony_ci unsigned int nval, change; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci nval = (ucontrol->value.integer.value[0] ? 0 : 0x00008000) | 127862306a36Sopenharmony_ci (ucontrol->value.integer.value[1] ? 0 : 0x80000000); 127962306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 128062306a36Sopenharmony_ci nval |= ice->pro_volumes[priv_idx] & ~0x80008000; 128162306a36Sopenharmony_ci change = nval != ice->pro_volumes[priv_idx]; 128262306a36Sopenharmony_ci ice->pro_volumes[priv_idx] = nval; 128362306a36Sopenharmony_ci snd_ice1712_update_volume(ice, priv_idx); 128462306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 128562306a36Sopenharmony_ci return change; 128662306a36Sopenharmony_ci} 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_cistatic int snd_ice1712_pro_mixer_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 128962306a36Sopenharmony_ci{ 129062306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 129162306a36Sopenharmony_ci uinfo->count = 2; 129262306a36Sopenharmony_ci uinfo->value.integer.min = 0; 129362306a36Sopenharmony_ci uinfo->value.integer.max = 96; 129462306a36Sopenharmony_ci return 0; 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cistatic int snd_ice1712_pro_mixer_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 130062306a36Sopenharmony_ci int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + 130162306a36Sopenharmony_ci kcontrol->private_value; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 130462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 130562306a36Sopenharmony_ci (ice->pro_volumes[priv_idx] >> 0) & 127; 130662306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 130762306a36Sopenharmony_ci (ice->pro_volumes[priv_idx] >> 16) & 127; 130862306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 130962306a36Sopenharmony_ci return 0; 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 131562306a36Sopenharmony_ci int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + 131662306a36Sopenharmony_ci kcontrol->private_value; 131762306a36Sopenharmony_ci unsigned int nval, change; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci nval = (ucontrol->value.integer.value[0] & 127) | 132062306a36Sopenharmony_ci ((ucontrol->value.integer.value[1] & 127) << 16); 132162306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 132262306a36Sopenharmony_ci nval |= ice->pro_volumes[priv_idx] & ~0x007f007f; 132362306a36Sopenharmony_ci change = nval != ice->pro_volumes[priv_idx]; 132462306a36Sopenharmony_ci ice->pro_volumes[priv_idx] = nval; 132562306a36Sopenharmony_ci snd_ice1712_update_volume(ice, priv_idx); 132662306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 132762306a36Sopenharmony_ci return change; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] = { 133362306a36Sopenharmony_ci { 133462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 133562306a36Sopenharmony_ci .name = "Multi Playback Switch", 133662306a36Sopenharmony_ci .info = snd_ice1712_pro_mixer_switch_info, 133762306a36Sopenharmony_ci .get = snd_ice1712_pro_mixer_switch_get, 133862306a36Sopenharmony_ci .put = snd_ice1712_pro_mixer_switch_put, 133962306a36Sopenharmony_ci .private_value = 0, 134062306a36Sopenharmony_ci .count = 10, 134162306a36Sopenharmony_ci }, 134262306a36Sopenharmony_ci { 134362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 134462306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 134562306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 134662306a36Sopenharmony_ci .name = "Multi Playback Volume", 134762306a36Sopenharmony_ci .info = snd_ice1712_pro_mixer_volume_info, 134862306a36Sopenharmony_ci .get = snd_ice1712_pro_mixer_volume_get, 134962306a36Sopenharmony_ci .put = snd_ice1712_pro_mixer_volume_put, 135062306a36Sopenharmony_ci .private_value = 0, 135162306a36Sopenharmony_ci .count = 10, 135262306a36Sopenharmony_ci .tlv = { .p = db_scale_playback } 135362306a36Sopenharmony_ci }, 135462306a36Sopenharmony_ci}; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch = { 135762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 135862306a36Sopenharmony_ci .name = "H/W Multi Capture Switch", 135962306a36Sopenharmony_ci .info = snd_ice1712_pro_mixer_switch_info, 136062306a36Sopenharmony_ci .get = snd_ice1712_pro_mixer_switch_get, 136162306a36Sopenharmony_ci .put = snd_ice1712_pro_mixer_switch_put, 136262306a36Sopenharmony_ci .private_value = 10, 136362306a36Sopenharmony_ci}; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = { 136662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 136762306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH), 136862306a36Sopenharmony_ci .info = snd_ice1712_pro_mixer_switch_info, 136962306a36Sopenharmony_ci .get = snd_ice1712_pro_mixer_switch_get, 137062306a36Sopenharmony_ci .put = snd_ice1712_pro_mixer_switch_put, 137162306a36Sopenharmony_ci .private_value = 18, 137262306a36Sopenharmony_ci .count = 2, 137362306a36Sopenharmony_ci}; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume = { 137662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 137762306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 137862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 137962306a36Sopenharmony_ci .name = "H/W Multi Capture Volume", 138062306a36Sopenharmony_ci .info = snd_ice1712_pro_mixer_volume_info, 138162306a36Sopenharmony_ci .get = snd_ice1712_pro_mixer_volume_get, 138262306a36Sopenharmony_ci .put = snd_ice1712_pro_mixer_volume_put, 138362306a36Sopenharmony_ci .private_value = 10, 138462306a36Sopenharmony_ci .tlv = { .p = db_scale_playback } 138562306a36Sopenharmony_ci}; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume = { 138862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 138962306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME), 139062306a36Sopenharmony_ci .info = snd_ice1712_pro_mixer_volume_info, 139162306a36Sopenharmony_ci .get = snd_ice1712_pro_mixer_volume_get, 139262306a36Sopenharmony_ci .put = snd_ice1712_pro_mixer_volume_put, 139362306a36Sopenharmony_ci .private_value = 18, 139462306a36Sopenharmony_ci .count = 2, 139562306a36Sopenharmony_ci}; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_cistatic int snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice) 139862306a36Sopenharmony_ci{ 139962306a36Sopenharmony_ci struct snd_card *card = ice->card; 140062306a36Sopenharmony_ci unsigned int idx; 140162306a36Sopenharmony_ci int err; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* multi-channel mixer */ 140462306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_multi_playback_ctrls); idx++) { 140562306a36Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_playback_ctrls[idx], ice)); 140662306a36Sopenharmony_ci if (err < 0) 140762306a36Sopenharmony_ci return err; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (ice->num_total_adcs > 0) { 141162306a36Sopenharmony_ci struct snd_kcontrol_new tmp = snd_ice1712_multi_capture_analog_switch; 141262306a36Sopenharmony_ci tmp.count = ice->num_total_adcs; 141362306a36Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&tmp, ice)); 141462306a36Sopenharmony_ci if (err < 0) 141562306a36Sopenharmony_ci return err; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_capture_spdif_switch, ice)); 141962306a36Sopenharmony_ci if (err < 0) 142062306a36Sopenharmony_ci return err; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (ice->num_total_adcs > 0) { 142362306a36Sopenharmony_ci struct snd_kcontrol_new tmp = snd_ice1712_multi_capture_analog_volume; 142462306a36Sopenharmony_ci tmp.count = ice->num_total_adcs; 142562306a36Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&tmp, ice)); 142662306a36Sopenharmony_ci if (err < 0) 142762306a36Sopenharmony_ci return err; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_capture_spdif_volume, ice)); 143162306a36Sopenharmony_ci if (err < 0) 143262306a36Sopenharmony_ci return err; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci /* initialize volumes */ 143562306a36Sopenharmony_ci for (idx = 0; idx < 10; idx++) { 143662306a36Sopenharmony_ci ice->pro_volumes[idx] = 0x80008000; /* mute */ 143762306a36Sopenharmony_ci snd_ice1712_update_volume(ice, idx); 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci for (idx = 10; idx < 10 + ice->num_total_adcs; idx++) { 144062306a36Sopenharmony_ci ice->pro_volumes[idx] = 0x80008000; /* mute */ 144162306a36Sopenharmony_ci snd_ice1712_update_volume(ice, idx); 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci for (idx = 18; idx < 20; idx++) { 144462306a36Sopenharmony_ci ice->pro_volumes[idx] = 0x80008000; /* mute */ 144562306a36Sopenharmony_ci snd_ice1712_update_volume(ice, idx); 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci return 0; 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_cistatic void snd_ice1712_mixer_free_ac97(struct snd_ac97 *ac97) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci struct snd_ice1712 *ice = ac97->private_data; 145362306a36Sopenharmony_ci ice->ac97 = NULL; 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_cistatic int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci int err, bus_num = 0; 145962306a36Sopenharmony_ci struct snd_ac97_template ac97; 146062306a36Sopenharmony_ci struct snd_ac97_bus *pbus; 146162306a36Sopenharmony_ci static const struct snd_ac97_bus_ops con_ops = { 146262306a36Sopenharmony_ci .write = snd_ice1712_ac97_write, 146362306a36Sopenharmony_ci .read = snd_ice1712_ac97_read, 146462306a36Sopenharmony_ci }; 146562306a36Sopenharmony_ci static const struct snd_ac97_bus_ops pro_ops = { 146662306a36Sopenharmony_ci .write = snd_ice1712_pro_ac97_write, 146762306a36Sopenharmony_ci .read = snd_ice1712_pro_ac97_read, 146862306a36Sopenharmony_ci }; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (ice_has_con_ac97(ice)) { 147162306a36Sopenharmony_ci err = snd_ac97_bus(ice->card, bus_num++, &con_ops, NULL, &pbus); 147262306a36Sopenharmony_ci if (err < 0) 147362306a36Sopenharmony_ci return err; 147462306a36Sopenharmony_ci memset(&ac97, 0, sizeof(ac97)); 147562306a36Sopenharmony_ci ac97.private_data = ice; 147662306a36Sopenharmony_ci ac97.private_free = snd_ice1712_mixer_free_ac97; 147762306a36Sopenharmony_ci err = snd_ac97_mixer(pbus, &ac97, &ice->ac97); 147862306a36Sopenharmony_ci if (err < 0) 147962306a36Sopenharmony_ci dev_warn(ice->card->dev, 148062306a36Sopenharmony_ci "cannot initialize ac97 for consumer, skipped\n"); 148162306a36Sopenharmony_ci else { 148262306a36Sopenharmony_ci return snd_ctl_add(ice->card, 148362306a36Sopenharmony_ci snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, 148462306a36Sopenharmony_ci ice)); 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (!(ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) { 148962306a36Sopenharmony_ci err = snd_ac97_bus(ice->card, bus_num, &pro_ops, NULL, &pbus); 149062306a36Sopenharmony_ci if (err < 0) 149162306a36Sopenharmony_ci return err; 149262306a36Sopenharmony_ci memset(&ac97, 0, sizeof(ac97)); 149362306a36Sopenharmony_ci ac97.private_data = ice; 149462306a36Sopenharmony_ci ac97.private_free = snd_ice1712_mixer_free_ac97; 149562306a36Sopenharmony_ci err = snd_ac97_mixer(pbus, &ac97, &ice->ac97); 149662306a36Sopenharmony_ci if (err < 0) 149762306a36Sopenharmony_ci dev_warn(ice->card->dev, 149862306a36Sopenharmony_ci "cannot initialize pro ac97, skipped\n"); 149962306a36Sopenharmony_ci else 150062306a36Sopenharmony_ci return 0; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci /* I2S mixer only */ 150362306a36Sopenharmony_ci strcat(ice->card->mixername, "ICE1712 - multitrack"); 150462306a36Sopenharmony_ci return 0; 150562306a36Sopenharmony_ci} 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci/* 150862306a36Sopenharmony_ci * 150962306a36Sopenharmony_ci */ 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic inline unsigned int eeprom_double(struct snd_ice1712 *ice, int idx) 151262306a36Sopenharmony_ci{ 151362306a36Sopenharmony_ci return (unsigned int)ice->eeprom.data[idx] | ((unsigned int)ice->eeprom.data[idx + 1] << 8); 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cistatic void snd_ice1712_proc_read(struct snd_info_entry *entry, 151762306a36Sopenharmony_ci struct snd_info_buffer *buffer) 151862306a36Sopenharmony_ci{ 151962306a36Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 152062306a36Sopenharmony_ci unsigned int idx; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci snd_iprintf(buffer, "%s\n\n", ice->card->longname); 152362306a36Sopenharmony_ci snd_iprintf(buffer, "EEPROM:\n"); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci snd_iprintf(buffer, " Subvendor : 0x%x\n", ice->eeprom.subvendor); 152662306a36Sopenharmony_ci snd_iprintf(buffer, " Size : %i bytes\n", ice->eeprom.size); 152762306a36Sopenharmony_ci snd_iprintf(buffer, " Version : %i\n", ice->eeprom.version); 152862306a36Sopenharmony_ci snd_iprintf(buffer, " Codec : 0x%x\n", ice->eeprom.data[ICE_EEP1_CODEC]); 152962306a36Sopenharmony_ci snd_iprintf(buffer, " ACLink : 0x%x\n", ice->eeprom.data[ICE_EEP1_ACLINK]); 153062306a36Sopenharmony_ci snd_iprintf(buffer, " I2S ID : 0x%x\n", ice->eeprom.data[ICE_EEP1_I2SID]); 153162306a36Sopenharmony_ci snd_iprintf(buffer, " S/PDIF : 0x%x\n", ice->eeprom.data[ICE_EEP1_SPDIF]); 153262306a36Sopenharmony_ci snd_iprintf(buffer, " GPIO mask : 0x%x\n", ice->eeprom.gpiomask); 153362306a36Sopenharmony_ci snd_iprintf(buffer, " GPIO state : 0x%x\n", ice->eeprom.gpiostate); 153462306a36Sopenharmony_ci snd_iprintf(buffer, " GPIO direction : 0x%x\n", ice->eeprom.gpiodir); 153562306a36Sopenharmony_ci snd_iprintf(buffer, " AC'97 main : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_MAIN_LO)); 153662306a36Sopenharmony_ci snd_iprintf(buffer, " AC'97 pcm : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_PCM_LO)); 153762306a36Sopenharmony_ci snd_iprintf(buffer, " AC'97 record : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_REC_LO)); 153862306a36Sopenharmony_ci snd_iprintf(buffer, " AC'97 record src : 0x%x\n", ice->eeprom.data[ICE_EEP1_AC97_RECSRC]); 153962306a36Sopenharmony_ci for (idx = 0; idx < 4; idx++) 154062306a36Sopenharmony_ci snd_iprintf(buffer, " DAC ID #%i : 0x%x\n", idx, ice->eeprom.data[ICE_EEP1_DAC_ID + idx]); 154162306a36Sopenharmony_ci for (idx = 0; idx < 4; idx++) 154262306a36Sopenharmony_ci snd_iprintf(buffer, " ADC ID #%i : 0x%x\n", idx, ice->eeprom.data[ICE_EEP1_ADC_ID + idx]); 154362306a36Sopenharmony_ci for (idx = 0x1c; idx < ice->eeprom.size; idx++) 154462306a36Sopenharmony_ci snd_iprintf(buffer, " Extra #%02i : 0x%x\n", idx, ice->eeprom.data[idx]); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci snd_iprintf(buffer, "\nRegisters:\n"); 154762306a36Sopenharmony_ci snd_iprintf(buffer, " PSDOUT03 : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_PSDOUT03))); 154862306a36Sopenharmony_ci snd_iprintf(buffer, " CAPTURE : 0x%08x\n", inl(ICEMT(ice, ROUTE_CAPTURE))); 154962306a36Sopenharmony_ci snd_iprintf(buffer, " SPDOUT : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_SPDOUT))); 155062306a36Sopenharmony_ci snd_iprintf(buffer, " RATE : 0x%02x\n", (unsigned)inb(ICEMT(ice, RATE))); 155162306a36Sopenharmony_ci snd_iprintf(buffer, " GPIO_DATA : 0x%02x\n", (unsigned)snd_ice1712_get_gpio_data(ice)); 155262306a36Sopenharmony_ci snd_iprintf(buffer, " GPIO_WRITE_MASK : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK)); 155362306a36Sopenharmony_ci snd_iprintf(buffer, " GPIO_DIRECTION : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION)); 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic void snd_ice1712_proc_init(struct snd_ice1712 *ice) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci snd_card_ro_proc_new(ice->card, "ice1712", ice, snd_ice1712_proc_read); 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci/* 156262306a36Sopenharmony_ci * 156362306a36Sopenharmony_ci */ 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_cistatic int snd_ice1712_eeprom_info(struct snd_kcontrol *kcontrol, 156662306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 156962306a36Sopenharmony_ci uinfo->count = sizeof(struct snd_ice1712_eeprom); 157062306a36Sopenharmony_ci return 0; 157162306a36Sopenharmony_ci} 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_cistatic int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol, 157462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 157562306a36Sopenharmony_ci{ 157662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom)); 157962306a36Sopenharmony_ci return 0; 158062306a36Sopenharmony_ci} 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_eeprom = { 158362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 158462306a36Sopenharmony_ci .name = "ICE1712 EEPROM", 158562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 158662306a36Sopenharmony_ci .info = snd_ice1712_eeprom_info, 158762306a36Sopenharmony_ci .get = snd_ice1712_eeprom_get 158862306a36Sopenharmony_ci}; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci/* 159162306a36Sopenharmony_ci */ 159262306a36Sopenharmony_cistatic int snd_ice1712_spdif_info(struct snd_kcontrol *kcontrol, 159362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 159462306a36Sopenharmony_ci{ 159562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 159662306a36Sopenharmony_ci uinfo->count = 1; 159762306a36Sopenharmony_ci return 0; 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic int snd_ice1712_spdif_default_get(struct snd_kcontrol *kcontrol, 160162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 160462306a36Sopenharmony_ci if (ice->spdif.ops.default_get) 160562306a36Sopenharmony_ci ice->spdif.ops.default_get(ice, ucontrol); 160662306a36Sopenharmony_ci return 0; 160762306a36Sopenharmony_ci} 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_cistatic int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol, 161062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 161162306a36Sopenharmony_ci{ 161262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 161362306a36Sopenharmony_ci if (ice->spdif.ops.default_put) 161462306a36Sopenharmony_ci return ice->spdif.ops.default_put(ice, ucontrol); 161562306a36Sopenharmony_ci return 0; 161662306a36Sopenharmony_ci} 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_spdif_default = 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 162162306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 162262306a36Sopenharmony_ci .info = snd_ice1712_spdif_info, 162362306a36Sopenharmony_ci .get = snd_ice1712_spdif_default_get, 162462306a36Sopenharmony_ci .put = snd_ice1712_spdif_default_put 162562306a36Sopenharmony_ci}; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_cistatic int snd_ice1712_spdif_maskc_get(struct snd_kcontrol *kcontrol, 162862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 163162306a36Sopenharmony_ci if (ice->spdif.ops.default_get) { 163262306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO | 163362306a36Sopenharmony_ci IEC958_AES0_PROFESSIONAL | 163462306a36Sopenharmony_ci IEC958_AES0_CON_NOT_COPYRIGHT | 163562306a36Sopenharmony_ci IEC958_AES0_CON_EMPHASIS; 163662306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL | 163762306a36Sopenharmony_ci IEC958_AES1_CON_CATEGORY; 163862306a36Sopenharmony_ci ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS; 163962306a36Sopenharmony_ci } else { 164062306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = 0xff; 164162306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = 0xff; 164262306a36Sopenharmony_ci ucontrol->value.iec958.status[2] = 0xff; 164362306a36Sopenharmony_ci ucontrol->value.iec958.status[3] = 0xff; 164462306a36Sopenharmony_ci ucontrol->value.iec958.status[4] = 0xff; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci return 0; 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol, 165062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 165362306a36Sopenharmony_ci if (ice->spdif.ops.default_get) { 165462306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO | 165562306a36Sopenharmony_ci IEC958_AES0_PROFESSIONAL | 165662306a36Sopenharmony_ci IEC958_AES0_PRO_FS | 165762306a36Sopenharmony_ci IEC958_AES0_PRO_EMPHASIS; 165862306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = IEC958_AES1_PRO_MODE; 165962306a36Sopenharmony_ci } else { 166062306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = 0xff; 166162306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = 0xff; 166262306a36Sopenharmony_ci ucontrol->value.iec958.status[2] = 0xff; 166362306a36Sopenharmony_ci ucontrol->value.iec958.status[3] = 0xff; 166462306a36Sopenharmony_ci ucontrol->value.iec958.status[4] = 0xff; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci return 0; 166762306a36Sopenharmony_ci} 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_spdif_maskc = 167062306a36Sopenharmony_ci{ 167162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 167262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 167362306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), 167462306a36Sopenharmony_ci .info = snd_ice1712_spdif_info, 167562306a36Sopenharmony_ci .get = snd_ice1712_spdif_maskc_get, 167662306a36Sopenharmony_ci}; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_spdif_maskp = 167962306a36Sopenharmony_ci{ 168062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 168162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 168262306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK), 168362306a36Sopenharmony_ci .info = snd_ice1712_spdif_info, 168462306a36Sopenharmony_ci .get = snd_ice1712_spdif_maskp_get, 168562306a36Sopenharmony_ci}; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_cistatic int snd_ice1712_spdif_stream_get(struct snd_kcontrol *kcontrol, 168862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 168962306a36Sopenharmony_ci{ 169062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 169162306a36Sopenharmony_ci if (ice->spdif.ops.stream_get) 169262306a36Sopenharmony_ci ice->spdif.ops.stream_get(ice, ucontrol); 169362306a36Sopenharmony_ci return 0; 169462306a36Sopenharmony_ci} 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_cistatic int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol, 169762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 169862306a36Sopenharmony_ci{ 169962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 170062306a36Sopenharmony_ci if (ice->spdif.ops.stream_put) 170162306a36Sopenharmony_ci return ice->spdif.ops.stream_put(ice, ucontrol); 170262306a36Sopenharmony_ci return 0; 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_spdif_stream = 170662306a36Sopenharmony_ci{ 170762306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 170862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_INACTIVE), 170962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 171062306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), 171162306a36Sopenharmony_ci .info = snd_ice1712_spdif_info, 171262306a36Sopenharmony_ci .get = snd_ice1712_spdif_stream_get, 171362306a36Sopenharmony_ci .put = snd_ice1712_spdif_stream_put 171462306a36Sopenharmony_ci}; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ciint snd_ice1712_gpio_get(struct snd_kcontrol *kcontrol, 171762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 172062306a36Sopenharmony_ci unsigned char mask = kcontrol->private_value & 0xff; 172162306a36Sopenharmony_ci int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 172462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 172562306a36Sopenharmony_ci (snd_ice1712_gpio_read(ice) & mask ? 1 : 0) ^ invert; 172662306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 172762306a36Sopenharmony_ci return 0; 172862306a36Sopenharmony_ci} 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ciint snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol, 173162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 173262306a36Sopenharmony_ci{ 173362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 173462306a36Sopenharmony_ci unsigned char mask = kcontrol->private_value & 0xff; 173562306a36Sopenharmony_ci int invert = (kcontrol->private_value & (1<<24)) ? mask : 0; 173662306a36Sopenharmony_ci unsigned int val, nval; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci if (kcontrol->private_value & (1 << 31)) 173962306a36Sopenharmony_ci return -EPERM; 174062306a36Sopenharmony_ci nval = (ucontrol->value.integer.value[0] ? mask : 0) ^ invert; 174162306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 174262306a36Sopenharmony_ci val = snd_ice1712_gpio_read(ice); 174362306a36Sopenharmony_ci nval |= val & ~mask; 174462306a36Sopenharmony_ci if (val != nval) 174562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, nval); 174662306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 174762306a36Sopenharmony_ci return val != nval; 174862306a36Sopenharmony_ci} 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci/* 175162306a36Sopenharmony_ci * rate 175262306a36Sopenharmony_ci */ 175362306a36Sopenharmony_cistatic int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol, 175462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 175562306a36Sopenharmony_ci{ 175662306a36Sopenharmony_ci static const char * const texts[] = { 175762306a36Sopenharmony_ci "8000", /* 0: 6 */ 175862306a36Sopenharmony_ci "9600", /* 1: 3 */ 175962306a36Sopenharmony_ci "11025", /* 2: 10 */ 176062306a36Sopenharmony_ci "12000", /* 3: 2 */ 176162306a36Sopenharmony_ci "16000", /* 4: 5 */ 176262306a36Sopenharmony_ci "22050", /* 5: 9 */ 176362306a36Sopenharmony_ci "24000", /* 6: 1 */ 176462306a36Sopenharmony_ci "32000", /* 7: 4 */ 176562306a36Sopenharmony_ci "44100", /* 8: 8 */ 176662306a36Sopenharmony_ci "48000", /* 9: 0 */ 176762306a36Sopenharmony_ci "64000", /* 10: 15 */ 176862306a36Sopenharmony_ci "88200", /* 11: 11 */ 176962306a36Sopenharmony_ci "96000", /* 12: 7 */ 177062306a36Sopenharmony_ci "IEC958 Input", /* 13: -- */ 177162306a36Sopenharmony_ci }; 177262306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 14, texts); 177362306a36Sopenharmony_ci} 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_cistatic int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol, 177662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 177762306a36Sopenharmony_ci{ 177862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 177962306a36Sopenharmony_ci static const unsigned char xlate[16] = { 178062306a36Sopenharmony_ci 9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10 178162306a36Sopenharmony_ci }; 178262306a36Sopenharmony_ci unsigned char val; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 178562306a36Sopenharmony_ci if (is_spdif_master(ice)) { 178662306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 13; 178762306a36Sopenharmony_ci } else { 178862306a36Sopenharmony_ci val = xlate[inb(ICEMT(ice, RATE)) & 15]; 178962306a36Sopenharmony_ci if (val == 255) { 179062306a36Sopenharmony_ci snd_BUG(); 179162306a36Sopenharmony_ci val = 0; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = val; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 179662306a36Sopenharmony_ci return 0; 179762306a36Sopenharmony_ci} 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_cistatic int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, 180062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 180162306a36Sopenharmony_ci{ 180262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 180362306a36Sopenharmony_ci static const unsigned int xrate[13] = { 180462306a36Sopenharmony_ci 8000, 9600, 11025, 12000, 16000, 22050, 24000, 180562306a36Sopenharmony_ci 32000, 44100, 48000, 64000, 88200, 96000 180662306a36Sopenharmony_ci }; 180762306a36Sopenharmony_ci unsigned char oval; 180862306a36Sopenharmony_ci int change = 0; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 181162306a36Sopenharmony_ci oval = inb(ICEMT(ice, RATE)); 181262306a36Sopenharmony_ci if (ucontrol->value.enumerated.item[0] == 13) { 181362306a36Sopenharmony_ci outb(oval | ICE1712_SPDIF_MASTER, ICEMT(ice, RATE)); 181462306a36Sopenharmony_ci } else { 181562306a36Sopenharmony_ci PRO_RATE_DEFAULT = xrate[ucontrol->value.integer.value[0] % 13]; 181662306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 181762306a36Sopenharmony_ci snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 1); 181862306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci change = inb(ICEMT(ice, RATE)) != oval; 182162306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci if ((oval & ICE1712_SPDIF_MASTER) != 182462306a36Sopenharmony_ci (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) 182562306a36Sopenharmony_ci snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice)); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci return change; 182862306a36Sopenharmony_ci} 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_pro_internal_clock = { 183162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 183262306a36Sopenharmony_ci .name = "Multi Track Internal Clock", 183362306a36Sopenharmony_ci .info = snd_ice1712_pro_internal_clock_info, 183462306a36Sopenharmony_ci .get = snd_ice1712_pro_internal_clock_get, 183562306a36Sopenharmony_ci .put = snd_ice1712_pro_internal_clock_put 183662306a36Sopenharmony_ci}; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_cistatic int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcontrol, 183962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 184062306a36Sopenharmony_ci{ 184162306a36Sopenharmony_ci static const char * const texts[] = { 184262306a36Sopenharmony_ci "8000", /* 0: 6 */ 184362306a36Sopenharmony_ci "9600", /* 1: 3 */ 184462306a36Sopenharmony_ci "11025", /* 2: 10 */ 184562306a36Sopenharmony_ci "12000", /* 3: 2 */ 184662306a36Sopenharmony_ci "16000", /* 4: 5 */ 184762306a36Sopenharmony_ci "22050", /* 5: 9 */ 184862306a36Sopenharmony_ci "24000", /* 6: 1 */ 184962306a36Sopenharmony_ci "32000", /* 7: 4 */ 185062306a36Sopenharmony_ci "44100", /* 8: 8 */ 185162306a36Sopenharmony_ci "48000", /* 9: 0 */ 185262306a36Sopenharmony_ci "64000", /* 10: 15 */ 185362306a36Sopenharmony_ci "88200", /* 11: 11 */ 185462306a36Sopenharmony_ci "96000", /* 12: 7 */ 185562306a36Sopenharmony_ci /* "IEC958 Input", 13: -- */ 185662306a36Sopenharmony_ci }; 185762306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 13, texts); 185862306a36Sopenharmony_ci} 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_cistatic int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcontrol, 186162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 186262306a36Sopenharmony_ci{ 186362306a36Sopenharmony_ci int val; 186462306a36Sopenharmony_ci static const unsigned int xrate[13] = { 186562306a36Sopenharmony_ci 8000, 9600, 11025, 12000, 16000, 22050, 24000, 186662306a36Sopenharmony_ci 32000, 44100, 48000, 64000, 88200, 96000 186762306a36Sopenharmony_ci }; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci for (val = 0; val < 13; val++) { 187062306a36Sopenharmony_ci if (xrate[val] == PRO_RATE_DEFAULT) 187162306a36Sopenharmony_ci break; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = val; 187562306a36Sopenharmony_ci return 0; 187662306a36Sopenharmony_ci} 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_cistatic int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcontrol, 187962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 188062306a36Sopenharmony_ci{ 188162306a36Sopenharmony_ci static const unsigned int xrate[13] = { 188262306a36Sopenharmony_ci 8000, 9600, 11025, 12000, 16000, 22050, 24000, 188362306a36Sopenharmony_ci 32000, 44100, 48000, 64000, 88200, 96000 188462306a36Sopenharmony_ci }; 188562306a36Sopenharmony_ci unsigned char oval; 188662306a36Sopenharmony_ci int change = 0; 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci oval = PRO_RATE_DEFAULT; 188962306a36Sopenharmony_ci PRO_RATE_DEFAULT = xrate[ucontrol->value.integer.value[0] % 13]; 189062306a36Sopenharmony_ci change = PRO_RATE_DEFAULT != oval; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci return change; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default = { 189662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 189762306a36Sopenharmony_ci .name = "Multi Track Internal Clock Default", 189862306a36Sopenharmony_ci .info = snd_ice1712_pro_internal_clock_default_info, 189962306a36Sopenharmony_ci .get = snd_ice1712_pro_internal_clock_default_get, 190062306a36Sopenharmony_ci .put = snd_ice1712_pro_internal_clock_default_put 190162306a36Sopenharmony_ci}; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci#define snd_ice1712_pro_rate_locking_info snd_ctl_boolean_mono_info 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_cistatic int snd_ice1712_pro_rate_locking_get(struct snd_kcontrol *kcontrol, 190662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 190762306a36Sopenharmony_ci{ 190862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = PRO_RATE_LOCKED; 190962306a36Sopenharmony_ci return 0; 191062306a36Sopenharmony_ci} 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_cistatic int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol, 191362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 191462306a36Sopenharmony_ci{ 191562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 191662306a36Sopenharmony_ci int change = 0, nval; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci nval = ucontrol->value.integer.value[0] ? 1 : 0; 191962306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 192062306a36Sopenharmony_ci change = PRO_RATE_LOCKED != nval; 192162306a36Sopenharmony_ci PRO_RATE_LOCKED = nval; 192262306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 192362306a36Sopenharmony_ci return change; 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_pro_rate_locking = { 192762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 192862306a36Sopenharmony_ci .name = "Multi Track Rate Locking", 192962306a36Sopenharmony_ci .info = snd_ice1712_pro_rate_locking_info, 193062306a36Sopenharmony_ci .get = snd_ice1712_pro_rate_locking_get, 193162306a36Sopenharmony_ci .put = snd_ice1712_pro_rate_locking_put 193262306a36Sopenharmony_ci}; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci#define snd_ice1712_pro_rate_reset_info snd_ctl_boolean_mono_info 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_cistatic int snd_ice1712_pro_rate_reset_get(struct snd_kcontrol *kcontrol, 193762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci ucontrol->value.integer.value[0] = PRO_RATE_RESET; 194062306a36Sopenharmony_ci return 0; 194162306a36Sopenharmony_ci} 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_cistatic int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol, 194462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 194562306a36Sopenharmony_ci{ 194662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 194762306a36Sopenharmony_ci int change = 0, nval; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci nval = ucontrol->value.integer.value[0] ? 1 : 0; 195062306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 195162306a36Sopenharmony_ci change = PRO_RATE_RESET != nval; 195262306a36Sopenharmony_ci PRO_RATE_RESET = nval; 195362306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 195462306a36Sopenharmony_ci return change; 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_pro_rate_reset = { 195862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 195962306a36Sopenharmony_ci .name = "Multi Track Rate Reset", 196062306a36Sopenharmony_ci .info = snd_ice1712_pro_rate_reset_info, 196162306a36Sopenharmony_ci .get = snd_ice1712_pro_rate_reset_get, 196262306a36Sopenharmony_ci .put = snd_ice1712_pro_rate_reset_put 196362306a36Sopenharmony_ci}; 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci/* 196662306a36Sopenharmony_ci * routing 196762306a36Sopenharmony_ci */ 196862306a36Sopenharmony_cistatic int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol, 196962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 197062306a36Sopenharmony_ci{ 197162306a36Sopenharmony_ci static const char * const texts[] = { 197262306a36Sopenharmony_ci "PCM Out", /* 0 */ 197362306a36Sopenharmony_ci "H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */ 197462306a36Sopenharmony_ci "H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */ 197562306a36Sopenharmony_ci "IEC958 In L", "IEC958 In R", /* 9-10 */ 197662306a36Sopenharmony_ci "Digital Mixer", /* 11 - optional */ 197762306a36Sopenharmony_ci }; 197862306a36Sopenharmony_ci int num_items = snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11; 197962306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, num_items, texts); 198062306a36Sopenharmony_ci} 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_cistatic int snd_ice1712_pro_route_analog_get(struct snd_kcontrol *kcontrol, 198362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 198462306a36Sopenharmony_ci{ 198562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 198662306a36Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 198762306a36Sopenharmony_ci unsigned int val, cval; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 199062306a36Sopenharmony_ci val = inw(ICEMT(ice, ROUTE_PSDOUT03)); 199162306a36Sopenharmony_ci cval = inl(ICEMT(ice, ROUTE_CAPTURE)); 199262306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci val >>= ((idx % 2) * 8) + ((idx / 2) * 2); 199562306a36Sopenharmony_ci val &= 3; 199662306a36Sopenharmony_ci cval >>= ((idx / 2) * 8) + ((idx % 2) * 4); 199762306a36Sopenharmony_ci if (val == 1 && idx < 2) 199862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 11; 199962306a36Sopenharmony_ci else if (val == 2) 200062306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = (cval & 7) + 1; 200162306a36Sopenharmony_ci else if (val == 3) 200262306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = ((cval >> 3) & 1) + 9; 200362306a36Sopenharmony_ci else 200462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 0; 200562306a36Sopenharmony_ci return 0; 200662306a36Sopenharmony_ci} 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_cistatic int snd_ice1712_pro_route_analog_put(struct snd_kcontrol *kcontrol, 200962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 201062306a36Sopenharmony_ci{ 201162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 201262306a36Sopenharmony_ci int change, shift; 201362306a36Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 201462306a36Sopenharmony_ci unsigned int val, old_val, nval; 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci /* update PSDOUT */ 201762306a36Sopenharmony_ci if (ucontrol->value.enumerated.item[0] >= 11) 201862306a36Sopenharmony_ci nval = idx < 2 ? 1 : 0; /* dig mixer (or pcm) */ 201962306a36Sopenharmony_ci else if (ucontrol->value.enumerated.item[0] >= 9) 202062306a36Sopenharmony_ci nval = 3; /* spdif in */ 202162306a36Sopenharmony_ci else if (ucontrol->value.enumerated.item[0] >= 1) 202262306a36Sopenharmony_ci nval = 2; /* analog in */ 202362306a36Sopenharmony_ci else 202462306a36Sopenharmony_ci nval = 0; /* pcm */ 202562306a36Sopenharmony_ci shift = ((idx % 2) * 8) + ((idx / 2) * 2); 202662306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 202762306a36Sopenharmony_ci val = old_val = inw(ICEMT(ice, ROUTE_PSDOUT03)); 202862306a36Sopenharmony_ci val &= ~(0x03 << shift); 202962306a36Sopenharmony_ci val |= nval << shift; 203062306a36Sopenharmony_ci change = val != old_val; 203162306a36Sopenharmony_ci if (change) 203262306a36Sopenharmony_ci outw(val, ICEMT(ice, ROUTE_PSDOUT03)); 203362306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 203462306a36Sopenharmony_ci if (nval < 2) /* dig mixer of pcm */ 203562306a36Sopenharmony_ci return change; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci /* update CAPTURE */ 203862306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 203962306a36Sopenharmony_ci val = old_val = inl(ICEMT(ice, ROUTE_CAPTURE)); 204062306a36Sopenharmony_ci shift = ((idx / 2) * 8) + ((idx % 2) * 4); 204162306a36Sopenharmony_ci if (nval == 2) { /* analog in */ 204262306a36Sopenharmony_ci nval = ucontrol->value.enumerated.item[0] - 1; 204362306a36Sopenharmony_ci val &= ~(0x07 << shift); 204462306a36Sopenharmony_ci val |= nval << shift; 204562306a36Sopenharmony_ci } else { /* spdif in */ 204662306a36Sopenharmony_ci nval = (ucontrol->value.enumerated.item[0] - 9) << 3; 204762306a36Sopenharmony_ci val &= ~(0x08 << shift); 204862306a36Sopenharmony_ci val |= nval << shift; 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci if (val != old_val) { 205162306a36Sopenharmony_ci change = 1; 205262306a36Sopenharmony_ci outl(val, ICEMT(ice, ROUTE_CAPTURE)); 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 205562306a36Sopenharmony_ci return change; 205662306a36Sopenharmony_ci} 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_cistatic int snd_ice1712_pro_route_spdif_get(struct snd_kcontrol *kcontrol, 205962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 206262306a36Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 206362306a36Sopenharmony_ci unsigned int val, cval; 206462306a36Sopenharmony_ci val = inw(ICEMT(ice, ROUTE_SPDOUT)); 206562306a36Sopenharmony_ci cval = (val >> (idx * 4 + 8)) & 0x0f; 206662306a36Sopenharmony_ci val = (val >> (idx * 2)) & 0x03; 206762306a36Sopenharmony_ci if (val == 1) 206862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 11; 206962306a36Sopenharmony_ci else if (val == 2) 207062306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = (cval & 7) + 1; 207162306a36Sopenharmony_ci else if (val == 3) 207262306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = ((cval >> 3) & 1) + 9; 207362306a36Sopenharmony_ci else 207462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 0; 207562306a36Sopenharmony_ci return 0; 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol, 207962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 208262306a36Sopenharmony_ci int change, shift; 208362306a36Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 208462306a36Sopenharmony_ci unsigned int val, old_val, nval; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci /* update SPDOUT */ 208762306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 208862306a36Sopenharmony_ci val = old_val = inw(ICEMT(ice, ROUTE_SPDOUT)); 208962306a36Sopenharmony_ci if (ucontrol->value.enumerated.item[0] >= 11) 209062306a36Sopenharmony_ci nval = 1; 209162306a36Sopenharmony_ci else if (ucontrol->value.enumerated.item[0] >= 9) 209262306a36Sopenharmony_ci nval = 3; 209362306a36Sopenharmony_ci else if (ucontrol->value.enumerated.item[0] >= 1) 209462306a36Sopenharmony_ci nval = 2; 209562306a36Sopenharmony_ci else 209662306a36Sopenharmony_ci nval = 0; 209762306a36Sopenharmony_ci shift = idx * 2; 209862306a36Sopenharmony_ci val &= ~(0x03 << shift); 209962306a36Sopenharmony_ci val |= nval << shift; 210062306a36Sopenharmony_ci shift = idx * 4 + 8; 210162306a36Sopenharmony_ci if (nval == 2) { 210262306a36Sopenharmony_ci nval = ucontrol->value.enumerated.item[0] - 1; 210362306a36Sopenharmony_ci val &= ~(0x07 << shift); 210462306a36Sopenharmony_ci val |= nval << shift; 210562306a36Sopenharmony_ci } else if (nval == 3) { 210662306a36Sopenharmony_ci nval = (ucontrol->value.enumerated.item[0] - 9) << 3; 210762306a36Sopenharmony_ci val &= ~(0x08 << shift); 210862306a36Sopenharmony_ci val |= nval << shift; 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci change = val != old_val; 211162306a36Sopenharmony_ci if (change) 211262306a36Sopenharmony_ci outw(val, ICEMT(ice, ROUTE_SPDOUT)); 211362306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 211462306a36Sopenharmony_ci return change; 211562306a36Sopenharmony_ci} 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route = { 211862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 211962306a36Sopenharmony_ci .name = "H/W Playback Route", 212062306a36Sopenharmony_ci .info = snd_ice1712_pro_route_info, 212162306a36Sopenharmony_ci .get = snd_ice1712_pro_route_analog_get, 212262306a36Sopenharmony_ci .put = snd_ice1712_pro_route_analog_put, 212362306a36Sopenharmony_ci}; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route = { 212662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 212762306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", 212862306a36Sopenharmony_ci .info = snd_ice1712_pro_route_info, 212962306a36Sopenharmony_ci .get = snd_ice1712_pro_route_spdif_get, 213062306a36Sopenharmony_ci .put = snd_ice1712_pro_route_spdif_put, 213162306a36Sopenharmony_ci .count = 2, 213262306a36Sopenharmony_ci}; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_cistatic int snd_ice1712_pro_volume_rate_info(struct snd_kcontrol *kcontrol, 213662306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 213762306a36Sopenharmony_ci{ 213862306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 213962306a36Sopenharmony_ci uinfo->count = 1; 214062306a36Sopenharmony_ci uinfo->value.integer.min = 0; 214162306a36Sopenharmony_ci uinfo->value.integer.max = 255; 214262306a36Sopenharmony_ci return 0; 214362306a36Sopenharmony_ci} 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_cistatic int snd_ice1712_pro_volume_rate_get(struct snd_kcontrol *kcontrol, 214662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 214762306a36Sopenharmony_ci{ 214862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_RATE)); 215162306a36Sopenharmony_ci return 0; 215262306a36Sopenharmony_ci} 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_cistatic int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol, 215562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 215662306a36Sopenharmony_ci{ 215762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 215862306a36Sopenharmony_ci int change; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 216162306a36Sopenharmony_ci change = inb(ICEMT(ice, MONITOR_RATE)) != ucontrol->value.integer.value[0]; 216262306a36Sopenharmony_ci outb(ucontrol->value.integer.value[0], ICEMT(ice, MONITOR_RATE)); 216362306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 216462306a36Sopenharmony_ci return change; 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate = { 216862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 216962306a36Sopenharmony_ci .name = "Multi Track Volume Rate", 217062306a36Sopenharmony_ci .info = snd_ice1712_pro_volume_rate_info, 217162306a36Sopenharmony_ci .get = snd_ice1712_pro_volume_rate_get, 217262306a36Sopenharmony_ci .put = snd_ice1712_pro_volume_rate_put 217362306a36Sopenharmony_ci}; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_cistatic int snd_ice1712_pro_peak_info(struct snd_kcontrol *kcontrol, 217662306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 217762306a36Sopenharmony_ci{ 217862306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 217962306a36Sopenharmony_ci uinfo->count = 22; 218062306a36Sopenharmony_ci uinfo->value.integer.min = 0; 218162306a36Sopenharmony_ci uinfo->value.integer.max = 255; 218262306a36Sopenharmony_ci return 0; 218362306a36Sopenharmony_ci} 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_cistatic int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol, 218662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 218762306a36Sopenharmony_ci{ 218862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 218962306a36Sopenharmony_ci int idx; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 219262306a36Sopenharmony_ci for (idx = 0; idx < 22; idx++) { 219362306a36Sopenharmony_ci outb(idx, ICEMT(ice, MONITOR_PEAKINDEX)); 219462306a36Sopenharmony_ci ucontrol->value.integer.value[idx] = inb(ICEMT(ice, MONITOR_PEAKDATA)); 219562306a36Sopenharmony_ci } 219662306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 219762306a36Sopenharmony_ci return 0; 219862306a36Sopenharmony_ci} 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak = { 220162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 220262306a36Sopenharmony_ci .name = "Multi Track Peak", 220362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 220462306a36Sopenharmony_ci .info = snd_ice1712_pro_peak_info, 220562306a36Sopenharmony_ci .get = snd_ice1712_pro_peak_get 220662306a36Sopenharmony_ci}; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci/* 220962306a36Sopenharmony_ci * 221062306a36Sopenharmony_ci */ 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci/* 221362306a36Sopenharmony_ci * list of available boards 221462306a36Sopenharmony_ci */ 221562306a36Sopenharmony_cistatic const struct snd_ice1712_card_info *card_tables[] = { 221662306a36Sopenharmony_ci snd_ice1712_hoontech_cards, 221762306a36Sopenharmony_ci snd_ice1712_delta_cards, 221862306a36Sopenharmony_ci snd_ice1712_ews_cards, 221962306a36Sopenharmony_ci NULL, 222062306a36Sopenharmony_ci}; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_cistatic unsigned char snd_ice1712_read_i2c(struct snd_ice1712 *ice, 222362306a36Sopenharmony_ci unsigned char dev, 222462306a36Sopenharmony_ci unsigned char addr) 222562306a36Sopenharmony_ci{ 222662306a36Sopenharmony_ci long t = 0x10000; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci outb(addr, ICEREG(ice, I2C_BYTE_ADDR)); 222962306a36Sopenharmony_ci outb(dev & ~ICE1712_I2C_WRITE, ICEREG(ice, I2C_DEV_ADDR)); 223062306a36Sopenharmony_ci while (t-- > 0 && (inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_BUSY)) ; 223162306a36Sopenharmony_ci return inb(ICEREG(ice, I2C_DATA)); 223262306a36Sopenharmony_ci} 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_cistatic int snd_ice1712_read_eeprom(struct snd_ice1712 *ice, 223562306a36Sopenharmony_ci const char *modelname) 223662306a36Sopenharmony_ci{ 223762306a36Sopenharmony_ci int dev = ICE_I2C_EEPROM_ADDR; /* I2C EEPROM device address */ 223862306a36Sopenharmony_ci unsigned int i, size; 223962306a36Sopenharmony_ci const struct snd_ice1712_card_info * const *tbl, *c; 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci if (!modelname || !*modelname) { 224262306a36Sopenharmony_ci ice->eeprom.subvendor = 0; 224362306a36Sopenharmony_ci if ((inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_EEPROM) != 0) 224462306a36Sopenharmony_ci ice->eeprom.subvendor = (snd_ice1712_read_i2c(ice, dev, 0x00) << 0) | 224562306a36Sopenharmony_ci (snd_ice1712_read_i2c(ice, dev, 0x01) << 8) | 224662306a36Sopenharmony_ci (snd_ice1712_read_i2c(ice, dev, 0x02) << 16) | 224762306a36Sopenharmony_ci (snd_ice1712_read_i2c(ice, dev, 0x03) << 24); 224862306a36Sopenharmony_ci if (ice->eeprom.subvendor == 0 || 224962306a36Sopenharmony_ci ice->eeprom.subvendor == (unsigned int)-1) { 225062306a36Sopenharmony_ci /* invalid subvendor from EEPROM, try the PCI subststem ID instead */ 225162306a36Sopenharmony_ci u16 vendor, device; 225262306a36Sopenharmony_ci pci_read_config_word(ice->pci, PCI_SUBSYSTEM_VENDOR_ID, &vendor); 225362306a36Sopenharmony_ci pci_read_config_word(ice->pci, PCI_SUBSYSTEM_ID, &device); 225462306a36Sopenharmony_ci ice->eeprom.subvendor = ((unsigned int)swab16(vendor) << 16) | swab16(device); 225562306a36Sopenharmony_ci if (ice->eeprom.subvendor == 0 || ice->eeprom.subvendor == (unsigned int)-1) { 225662306a36Sopenharmony_ci dev_err(ice->card->dev, 225762306a36Sopenharmony_ci "No valid ID is found\n"); 225862306a36Sopenharmony_ci return -ENXIO; 225962306a36Sopenharmony_ci } 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci } 226262306a36Sopenharmony_ci for (tbl = card_tables; *tbl; tbl++) { 226362306a36Sopenharmony_ci for (c = *tbl; c->subvendor; c++) { 226462306a36Sopenharmony_ci if (modelname && c->model && !strcmp(modelname, c->model)) { 226562306a36Sopenharmony_ci dev_info(ice->card->dev, 226662306a36Sopenharmony_ci "Using board model %s\n", c->name); 226762306a36Sopenharmony_ci ice->eeprom.subvendor = c->subvendor; 226862306a36Sopenharmony_ci } else if (c->subvendor != ice->eeprom.subvendor) 226962306a36Sopenharmony_ci continue; 227062306a36Sopenharmony_ci if (!c->eeprom_size || !c->eeprom_data) 227162306a36Sopenharmony_ci goto found; 227262306a36Sopenharmony_ci /* if the EEPROM is given by the driver, use it */ 227362306a36Sopenharmony_ci dev_dbg(ice->card->dev, "using the defined eeprom..\n"); 227462306a36Sopenharmony_ci ice->eeprom.version = 1; 227562306a36Sopenharmony_ci ice->eeprom.size = c->eeprom_size + 6; 227662306a36Sopenharmony_ci memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size); 227762306a36Sopenharmony_ci goto read_skipped; 227862306a36Sopenharmony_ci } 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n", 228162306a36Sopenharmony_ci ice->eeprom.subvendor); 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci found: 228462306a36Sopenharmony_ci ice->eeprom.size = snd_ice1712_read_i2c(ice, dev, 0x04); 228562306a36Sopenharmony_ci if (ice->eeprom.size < 6) 228662306a36Sopenharmony_ci ice->eeprom.size = 32; /* FIXME: any cards without the correct size? */ 228762306a36Sopenharmony_ci else if (ice->eeprom.size > 32) { 228862306a36Sopenharmony_ci dev_err(ice->card->dev, 228962306a36Sopenharmony_ci "invalid EEPROM (size = %i)\n", ice->eeprom.size); 229062306a36Sopenharmony_ci return -EIO; 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci ice->eeprom.version = snd_ice1712_read_i2c(ice, dev, 0x05); 229362306a36Sopenharmony_ci if (ice->eeprom.version != 1) { 229462306a36Sopenharmony_ci dev_err(ice->card->dev, "invalid EEPROM version %i\n", 229562306a36Sopenharmony_ci ice->eeprom.version); 229662306a36Sopenharmony_ci /* return -EIO; */ 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci size = ice->eeprom.size - 6; 229962306a36Sopenharmony_ci for (i = 0; i < size; i++) 230062306a36Sopenharmony_ci ice->eeprom.data[i] = snd_ice1712_read_i2c(ice, dev, i + 6); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci read_skipped: 230362306a36Sopenharmony_ci ice->eeprom.gpiomask = ice->eeprom.data[ICE_EEP1_GPIO_MASK]; 230462306a36Sopenharmony_ci ice->eeprom.gpiostate = ice->eeprom.data[ICE_EEP1_GPIO_STATE]; 230562306a36Sopenharmony_ci ice->eeprom.gpiodir = ice->eeprom.data[ICE_EEP1_GPIO_DIR]; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci return 0; 230862306a36Sopenharmony_ci} 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_cistatic int snd_ice1712_chip_init(struct snd_ice1712 *ice) 231362306a36Sopenharmony_ci{ 231462306a36Sopenharmony_ci outb(ICE1712_RESET | ICE1712_NATIVE, ICEREG(ice, CONTROL)); 231562306a36Sopenharmony_ci udelay(200); 231662306a36Sopenharmony_ci outb(ICE1712_NATIVE, ICEREG(ice, CONTROL)); 231762306a36Sopenharmony_ci udelay(200); 231862306a36Sopenharmony_ci if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE && 231962306a36Sopenharmony_ci !ice->dxr_enable) 232062306a36Sopenharmony_ci /* Set eeprom value to limit active ADCs and DACs to 6; 232162306a36Sopenharmony_ci * Also disable AC97 as no hardware in standard 6fire card/box 232262306a36Sopenharmony_ci * Note: DXR extensions are not currently supported 232362306a36Sopenharmony_ci */ 232462306a36Sopenharmony_ci ice->eeprom.data[ICE_EEP1_CODEC] = 0x3a; 232562306a36Sopenharmony_ci pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]); 232662306a36Sopenharmony_ci pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]); 232762306a36Sopenharmony_ci pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]); 232862306a36Sopenharmony_ci pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]); 232962306a36Sopenharmony_ci if (ice->eeprom.subvendor != ICE1712_SUBDEVICE_STDSP24 && 233062306a36Sopenharmony_ci ice->eeprom.subvendor != ICE1712_SUBDEVICE_STAUDIO_ADCIII) { 233162306a36Sopenharmony_ci ice->gpio.write_mask = ice->eeprom.gpiomask; 233262306a36Sopenharmony_ci ice->gpio.direction = ice->eeprom.gpiodir; 233362306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, 233462306a36Sopenharmony_ci ice->eeprom.gpiomask); 233562306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 233662306a36Sopenharmony_ci ice->eeprom.gpiodir); 233762306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, 233862306a36Sopenharmony_ci ice->eeprom.gpiostate); 233962306a36Sopenharmony_ci } else { 234062306a36Sopenharmony_ci ice->gpio.write_mask = 0xc0; 234162306a36Sopenharmony_ci ice->gpio.direction = 0xff; 234262306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, 0xc0); 234362306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 0xff); 234462306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, 234562306a36Sopenharmony_ci ICE1712_STDSP24_CLOCK_BIT); 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_PRO_POWERDOWN, 0); 234862306a36Sopenharmony_ci if (!(ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97)) { 234962306a36Sopenharmony_ci outb(ICE1712_AC97_WARM, ICEREG(ice, AC97_CMD)); 235062306a36Sopenharmony_ci udelay(100); 235162306a36Sopenharmony_ci outb(0, ICEREG(ice, AC97_CMD)); 235262306a36Sopenharmony_ci udelay(200); 235362306a36Sopenharmony_ci snd_ice1712_write(ice, ICE1712_IREG_CONSUMER_POWERDOWN, 0); 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci snd_ice1712_set_pro_rate(ice, 48000, 1); 235662306a36Sopenharmony_ci /* unmask used interrupts */ 235762306a36Sopenharmony_ci outb(((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ? 235862306a36Sopenharmony_ci ICE1712_IRQ_MPU2 : 0) | 235962306a36Sopenharmony_ci ((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ? 236062306a36Sopenharmony_ci ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0), 236162306a36Sopenharmony_ci ICEREG(ice, IRQMASK)); 236262306a36Sopenharmony_ci outb(0x00, ICEMT(ice, IRQ)); 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci return 0; 236562306a36Sopenharmony_ci} 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ciint snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice) 236862306a36Sopenharmony_ci{ 236962306a36Sopenharmony_ci int err; 237062306a36Sopenharmony_ci struct snd_kcontrol *kctl; 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci if (snd_BUG_ON(!ice->pcm_pro)) 237362306a36Sopenharmony_ci return -EIO; 237462306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice); 237562306a36Sopenharmony_ci kctl->id.device = ice->pcm_pro->device; 237662306a36Sopenharmony_ci err = snd_ctl_add(ice->card, kctl); 237762306a36Sopenharmony_ci if (err < 0) 237862306a36Sopenharmony_ci return err; 237962306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ice1712_spdif_maskc, ice); 238062306a36Sopenharmony_ci kctl->id.device = ice->pcm_pro->device; 238162306a36Sopenharmony_ci err = snd_ctl_add(ice->card, kctl); 238262306a36Sopenharmony_ci if (err < 0) 238362306a36Sopenharmony_ci return err; 238462306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ice1712_spdif_maskp, ice); 238562306a36Sopenharmony_ci kctl->id.device = ice->pcm_pro->device; 238662306a36Sopenharmony_ci err = snd_ctl_add(ice->card, kctl); 238762306a36Sopenharmony_ci if (err < 0) 238862306a36Sopenharmony_ci return err; 238962306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ice1712_spdif_stream, ice); 239062306a36Sopenharmony_ci kctl->id.device = ice->pcm_pro->device; 239162306a36Sopenharmony_ci err = snd_ctl_add(ice->card, kctl); 239262306a36Sopenharmony_ci if (err < 0) 239362306a36Sopenharmony_ci return err; 239462306a36Sopenharmony_ci ice->spdif.stream_ctl = kctl; 239562306a36Sopenharmony_ci return 0; 239662306a36Sopenharmony_ci} 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_cistatic int snd_ice1712_build_controls(struct snd_ice1712 *ice) 240062306a36Sopenharmony_ci{ 240162306a36Sopenharmony_ci int err; 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_eeprom, ice)); 240462306a36Sopenharmony_ci if (err < 0) 240562306a36Sopenharmony_ci return err; 240662306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_internal_clock, ice)); 240762306a36Sopenharmony_ci if (err < 0) 240862306a36Sopenharmony_ci return err; 240962306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_internal_clock_default, ice)); 241062306a36Sopenharmony_ci if (err < 0) 241162306a36Sopenharmony_ci return err; 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_locking, ice)); 241462306a36Sopenharmony_ci if (err < 0) 241562306a36Sopenharmony_ci return err; 241662306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_reset, ice)); 241762306a36Sopenharmony_ci if (err < 0) 241862306a36Sopenharmony_ci return err; 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci if (ice->num_total_dacs > 0) { 242162306a36Sopenharmony_ci struct snd_kcontrol_new tmp = snd_ice1712_mixer_pro_analog_route; 242262306a36Sopenharmony_ci tmp.count = ice->num_total_dacs; 242362306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&tmp, ice)); 242462306a36Sopenharmony_ci if (err < 0) 242562306a36Sopenharmony_ci return err; 242662306a36Sopenharmony_ci } 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_spdif_route, ice)); 242962306a36Sopenharmony_ci if (err < 0) 243062306a36Sopenharmony_ci return err; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice)); 243362306a36Sopenharmony_ci if (err < 0) 243462306a36Sopenharmony_ci return err; 243562306a36Sopenharmony_ci return snd_ctl_add(ice->card, 243662306a36Sopenharmony_ci snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice)); 243762306a36Sopenharmony_ci} 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_cistatic void snd_ice1712_free(struct snd_card *card) 244062306a36Sopenharmony_ci{ 244162306a36Sopenharmony_ci struct snd_ice1712 *ice = card->private_data; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci if (ice->card_info && ice->card_info->chip_exit) 244462306a36Sopenharmony_ci ice->card_info->chip_exit(ice); 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci /* mask all interrupts */ 244762306a36Sopenharmony_ci outb(ICE1712_MULTI_CAPTURE | ICE1712_MULTI_PLAYBACK, ICEMT(ice, IRQ)); 244862306a36Sopenharmony_ci outb(0xff, ICEREG(ice, IRQMASK)); 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci snd_ice1712_akm4xxx_free(ice); 245162306a36Sopenharmony_ci} 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_cistatic int snd_ice1712_create(struct snd_card *card, 245462306a36Sopenharmony_ci struct pci_dev *pci, 245562306a36Sopenharmony_ci const char *modelname, 245662306a36Sopenharmony_ci int omni, 245762306a36Sopenharmony_ci int cs8427_timeout, 245862306a36Sopenharmony_ci int dxr_enable) 245962306a36Sopenharmony_ci{ 246062306a36Sopenharmony_ci struct snd_ice1712 *ice = card->private_data; 246162306a36Sopenharmony_ci int err; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci /* enable PCI device */ 246462306a36Sopenharmony_ci err = pcim_enable_device(pci); 246562306a36Sopenharmony_ci if (err < 0) 246662306a36Sopenharmony_ci return err; 246762306a36Sopenharmony_ci /* check, if we can restrict PCI DMA transfers to 28 bits */ 246862306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) { 246962306a36Sopenharmony_ci dev_err(card->dev, 247062306a36Sopenharmony_ci "architecture does not support 28bit PCI busmaster DMA\n"); 247162306a36Sopenharmony_ci return -ENXIO; 247262306a36Sopenharmony_ci } 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci ice->omni = omni ? 1 : 0; 247562306a36Sopenharmony_ci if (cs8427_timeout < 1) 247662306a36Sopenharmony_ci cs8427_timeout = 1; 247762306a36Sopenharmony_ci else if (cs8427_timeout > 1000) 247862306a36Sopenharmony_ci cs8427_timeout = 1000; 247962306a36Sopenharmony_ci ice->cs8427_timeout = cs8427_timeout; 248062306a36Sopenharmony_ci ice->dxr_enable = dxr_enable; 248162306a36Sopenharmony_ci spin_lock_init(&ice->reg_lock); 248262306a36Sopenharmony_ci mutex_init(&ice->gpio_mutex); 248362306a36Sopenharmony_ci mutex_init(&ice->i2c_mutex); 248462306a36Sopenharmony_ci mutex_init(&ice->open_mutex); 248562306a36Sopenharmony_ci ice->gpio.set_mask = snd_ice1712_set_gpio_mask; 248662306a36Sopenharmony_ci ice->gpio.get_mask = snd_ice1712_get_gpio_mask; 248762306a36Sopenharmony_ci ice->gpio.set_dir = snd_ice1712_set_gpio_dir; 248862306a36Sopenharmony_ci ice->gpio.get_dir = snd_ice1712_get_gpio_dir; 248962306a36Sopenharmony_ci ice->gpio.set_data = snd_ice1712_set_gpio_data; 249062306a36Sopenharmony_ci ice->gpio.get_data = snd_ice1712_get_gpio_data; 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci ice->spdif.cs8403_bits = 249362306a36Sopenharmony_ci ice->spdif.cs8403_stream_bits = (0x01 | /* consumer format */ 249462306a36Sopenharmony_ci 0x10 | /* no emphasis */ 249562306a36Sopenharmony_ci 0x20); /* PCM encoder/decoder */ 249662306a36Sopenharmony_ci ice->card = card; 249762306a36Sopenharmony_ci ice->pci = pci; 249862306a36Sopenharmony_ci ice->irq = -1; 249962306a36Sopenharmony_ci pci_set_master(pci); 250062306a36Sopenharmony_ci /* disable legacy emulation */ 250162306a36Sopenharmony_ci pci_write_config_word(ice->pci, 0x40, 0x807f); 250262306a36Sopenharmony_ci pci_write_config_word(ice->pci, 0x42, 0x0006); 250362306a36Sopenharmony_ci snd_ice1712_proc_init(ice); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci err = pci_request_regions(pci, "ICE1712"); 250662306a36Sopenharmony_ci if (err < 0) 250762306a36Sopenharmony_ci return err; 250862306a36Sopenharmony_ci ice->port = pci_resource_start(pci, 0); 250962306a36Sopenharmony_ci ice->ddma_port = pci_resource_start(pci, 1); 251062306a36Sopenharmony_ci ice->dmapath_port = pci_resource_start(pci, 2); 251162306a36Sopenharmony_ci ice->profi_port = pci_resource_start(pci, 3); 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci if (devm_request_irq(&pci->dev, pci->irq, snd_ice1712_interrupt, 251462306a36Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, ice)) { 251562306a36Sopenharmony_ci dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); 251662306a36Sopenharmony_ci return -EIO; 251762306a36Sopenharmony_ci } 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci ice->irq = pci->irq; 252062306a36Sopenharmony_ci card->sync_irq = ice->irq; 252162306a36Sopenharmony_ci card->private_free = snd_ice1712_free; 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci if (snd_ice1712_read_eeprom(ice, modelname) < 0) 252462306a36Sopenharmony_ci return -EIO; 252562306a36Sopenharmony_ci if (snd_ice1712_chip_init(ice) < 0) 252662306a36Sopenharmony_ci return -EIO; 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci return 0; 252962306a36Sopenharmony_ci} 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci/* 253362306a36Sopenharmony_ci * 253462306a36Sopenharmony_ci * Registration 253562306a36Sopenharmony_ci * 253662306a36Sopenharmony_ci */ 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_cistatic struct snd_ice1712_card_info no_matched; 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_cistatic int snd_ice1712_probe(struct pci_dev *pci, 254162306a36Sopenharmony_ci const struct pci_device_id *pci_id) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci static int dev; 254462306a36Sopenharmony_ci struct snd_card *card; 254562306a36Sopenharmony_ci struct snd_ice1712 *ice; 254662306a36Sopenharmony_ci int pcm_dev = 0, err; 254762306a36Sopenharmony_ci const struct snd_ice1712_card_info * const *tbl, *c; 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci if (dev >= SNDRV_CARDS) 255062306a36Sopenharmony_ci return -ENODEV; 255162306a36Sopenharmony_ci if (!enable[dev]) { 255262306a36Sopenharmony_ci dev++; 255362306a36Sopenharmony_ci return -ENOENT; 255462306a36Sopenharmony_ci } 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 255762306a36Sopenharmony_ci sizeof(*ice), &card); 255862306a36Sopenharmony_ci if (err < 0) 255962306a36Sopenharmony_ci return err; 256062306a36Sopenharmony_ci ice = card->private_data; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci strcpy(card->driver, "ICE1712"); 256362306a36Sopenharmony_ci strcpy(card->shortname, "ICEnsemble ICE1712"); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci err = snd_ice1712_create(card, pci, model[dev], omni[dev], 256662306a36Sopenharmony_ci cs8427_timeout[dev], dxr_enable[dev]); 256762306a36Sopenharmony_ci if (err < 0) 256862306a36Sopenharmony_ci return err; 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci for (tbl = card_tables; *tbl; tbl++) { 257162306a36Sopenharmony_ci for (c = *tbl; c->subvendor; c++) { 257262306a36Sopenharmony_ci if (c->subvendor == ice->eeprom.subvendor) { 257362306a36Sopenharmony_ci strcpy(card->shortname, c->name); 257462306a36Sopenharmony_ci if (c->driver) /* specific driver? */ 257562306a36Sopenharmony_ci strcpy(card->driver, c->driver); 257662306a36Sopenharmony_ci if (c->chip_init) { 257762306a36Sopenharmony_ci err = c->chip_init(ice); 257862306a36Sopenharmony_ci if (err < 0) 257962306a36Sopenharmony_ci return err; 258062306a36Sopenharmony_ci } 258162306a36Sopenharmony_ci ice->card_info = c; 258262306a36Sopenharmony_ci goto __found; 258362306a36Sopenharmony_ci } 258462306a36Sopenharmony_ci } 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci c = &no_matched; 258762306a36Sopenharmony_ci __found: 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci err = snd_ice1712_pcm_profi(ice, pcm_dev++); 259062306a36Sopenharmony_ci if (err < 0) 259162306a36Sopenharmony_ci return err; 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci if (ice_has_con_ac97(ice)) { 259462306a36Sopenharmony_ci err = snd_ice1712_pcm(ice, pcm_dev++); 259562306a36Sopenharmony_ci if (err < 0) 259662306a36Sopenharmony_ci return err; 259762306a36Sopenharmony_ci } 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci err = snd_ice1712_ac97_mixer(ice); 260062306a36Sopenharmony_ci if (err < 0) 260162306a36Sopenharmony_ci return err; 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci err = snd_ice1712_build_controls(ice); 260462306a36Sopenharmony_ci if (err < 0) 260562306a36Sopenharmony_ci return err; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci if (c->build_controls) { 260862306a36Sopenharmony_ci err = c->build_controls(ice); 260962306a36Sopenharmony_ci if (err < 0) 261062306a36Sopenharmony_ci return err; 261162306a36Sopenharmony_ci } 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci if (ice_has_con_ac97(ice)) { 261462306a36Sopenharmony_ci err = snd_ice1712_pcm_ds(ice, pcm_dev++); 261562306a36Sopenharmony_ci if (err < 0) 261662306a36Sopenharmony_ci return err; 261762306a36Sopenharmony_ci } 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci if (!c->no_mpu401) { 262062306a36Sopenharmony_ci err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, 262162306a36Sopenharmony_ci ICEREG(ice, MPU1_CTRL), 262262306a36Sopenharmony_ci c->mpu401_1_info_flags | 262362306a36Sopenharmony_ci MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, 262462306a36Sopenharmony_ci -1, &ice->rmidi[0]); 262562306a36Sopenharmony_ci if (err < 0) 262662306a36Sopenharmony_ci return err; 262762306a36Sopenharmony_ci if (c->mpu401_1_name) 262862306a36Sopenharmony_ci /* Preferred name available in card_info */ 262962306a36Sopenharmony_ci snprintf(ice->rmidi[0]->name, 263062306a36Sopenharmony_ci sizeof(ice->rmidi[0]->name), 263162306a36Sopenharmony_ci "%s %d", c->mpu401_1_name, card->number); 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) { 263462306a36Sopenharmony_ci /* 2nd port used */ 263562306a36Sopenharmony_ci err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712, 263662306a36Sopenharmony_ci ICEREG(ice, MPU2_CTRL), 263762306a36Sopenharmony_ci c->mpu401_2_info_flags | 263862306a36Sopenharmony_ci MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, 263962306a36Sopenharmony_ci -1, &ice->rmidi[1]); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci if (err < 0) 264262306a36Sopenharmony_ci return err; 264362306a36Sopenharmony_ci if (c->mpu401_2_name) 264462306a36Sopenharmony_ci /* Preferred name available in card_info */ 264562306a36Sopenharmony_ci snprintf(ice->rmidi[1]->name, 264662306a36Sopenharmony_ci sizeof(ice->rmidi[1]->name), 264762306a36Sopenharmony_ci "%s %d", c->mpu401_2_name, 264862306a36Sopenharmony_ci card->number); 264962306a36Sopenharmony_ci } 265062306a36Sopenharmony_ci } 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci snd_ice1712_set_input_clock_source(ice, 0); 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci sprintf(card->longname, "%s at 0x%lx, irq %i", 265562306a36Sopenharmony_ci card->shortname, ice->port, ice->irq); 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci err = snd_card_register(card); 265862306a36Sopenharmony_ci if (err < 0) 265962306a36Sopenharmony_ci return err; 266062306a36Sopenharmony_ci pci_set_drvdata(pci, card); 266162306a36Sopenharmony_ci dev++; 266262306a36Sopenharmony_ci return 0; 266362306a36Sopenharmony_ci} 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 266662306a36Sopenharmony_cistatic int snd_ice1712_suspend(struct device *dev) 266762306a36Sopenharmony_ci{ 266862306a36Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 266962306a36Sopenharmony_ci struct snd_ice1712 *ice = card->private_data; 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci if (!ice->pm_suspend_enabled) 267262306a36Sopenharmony_ci return 0; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci snd_ac97_suspend(ice->ac97); 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 267962306a36Sopenharmony_ci ice->pm_saved_is_spdif_master = is_spdif_master(ice); 268062306a36Sopenharmony_ci ice->pm_saved_spdif_ctrl = inw(ICEMT(ice, ROUTE_SPDOUT)); 268162306a36Sopenharmony_ci ice->pm_saved_route = inw(ICEMT(ice, ROUTE_PSDOUT03)); 268262306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci if (ice->pm_suspend) 268562306a36Sopenharmony_ci ice->pm_suspend(ice); 268662306a36Sopenharmony_ci return 0; 268762306a36Sopenharmony_ci} 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_cistatic int snd_ice1712_resume(struct device *dev) 269062306a36Sopenharmony_ci{ 269162306a36Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 269262306a36Sopenharmony_ci struct snd_ice1712 *ice = card->private_data; 269362306a36Sopenharmony_ci int rate; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci if (!ice->pm_suspend_enabled) 269662306a36Sopenharmony_ci return 0; 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci if (ice->cur_rate) 269962306a36Sopenharmony_ci rate = ice->cur_rate; 270062306a36Sopenharmony_ci else 270162306a36Sopenharmony_ci rate = PRO_RATE_DEFAULT; 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci if (snd_ice1712_chip_init(ice) < 0) { 270462306a36Sopenharmony_ci snd_card_disconnect(card); 270562306a36Sopenharmony_ci return -EIO; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci ice->cur_rate = rate; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci if (ice->pm_resume) 271162306a36Sopenharmony_ci ice->pm_resume(ice); 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci if (ice->pm_saved_is_spdif_master) { 271462306a36Sopenharmony_ci /* switching to external clock via SPDIF */ 271562306a36Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 271662306a36Sopenharmony_ci outb(inb(ICEMT(ice, RATE)) | ICE1712_SPDIF_MASTER, 271762306a36Sopenharmony_ci ICEMT(ice, RATE)); 271862306a36Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 271962306a36Sopenharmony_ci snd_ice1712_set_input_clock_source(ice, 1); 272062306a36Sopenharmony_ci } else { 272162306a36Sopenharmony_ci /* internal on-card clock */ 272262306a36Sopenharmony_ci snd_ice1712_set_pro_rate(ice, rate, 1); 272362306a36Sopenharmony_ci snd_ice1712_set_input_clock_source(ice, 0); 272462306a36Sopenharmony_ci } 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci outw(ice->pm_saved_spdif_ctrl, ICEMT(ice, ROUTE_SPDOUT)); 272762306a36Sopenharmony_ci outw(ice->pm_saved_route, ICEMT(ice, ROUTE_PSDOUT03)); 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci snd_ac97_resume(ice->ac97); 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D0); 273262306a36Sopenharmony_ci return 0; 273362306a36Sopenharmony_ci} 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(snd_ice1712_pm, snd_ice1712_suspend, snd_ice1712_resume); 273662306a36Sopenharmony_ci#define SND_VT1712_PM_OPS &snd_ice1712_pm 273762306a36Sopenharmony_ci#else 273862306a36Sopenharmony_ci#define SND_VT1712_PM_OPS NULL 273962306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_cistatic struct pci_driver ice1712_driver = { 274262306a36Sopenharmony_ci .name = KBUILD_MODNAME, 274362306a36Sopenharmony_ci .id_table = snd_ice1712_ids, 274462306a36Sopenharmony_ci .probe = snd_ice1712_probe, 274562306a36Sopenharmony_ci .driver = { 274662306a36Sopenharmony_ci .pm = SND_VT1712_PM_OPS, 274762306a36Sopenharmony_ci }, 274862306a36Sopenharmony_ci}; 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_cimodule_pci_driver(ice1712_driver); 2751