18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA driver for VT1724 ICEnsemble ICE1724 / VIA VT1724 (Envy24HT) 48c2ecf20Sopenharmony_ci * VIA VT1720 (Envy24PT) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> 78c2ecf20Sopenharmony_ci * 2002 James Stafford <jstafford@ampltd.com> 88c2ecf20Sopenharmony_ci * 2003 Takashi Iwai <tiwai@suse.de> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/mutex.h> 188c2ecf20Sopenharmony_ci#include <sound/core.h> 198c2ecf20Sopenharmony_ci#include <sound/info.h> 208c2ecf20Sopenharmony_ci#include <sound/rawmidi.h> 218c2ecf20Sopenharmony_ci#include <sound/initval.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "ice1712.h" 268c2ecf20Sopenharmony_ci#include "envy24ht.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* lowlevel routines */ 298c2ecf20Sopenharmony_ci#include "amp.h" 308c2ecf20Sopenharmony_ci#include "revo.h" 318c2ecf20Sopenharmony_ci#include "aureon.h" 328c2ecf20Sopenharmony_ci#include "vt1720_mobo.h" 338c2ecf20Sopenharmony_ci#include "pontis.h" 348c2ecf20Sopenharmony_ci#include "prodigy192.h" 358c2ecf20Sopenharmony_ci#include "prodigy_hifi.h" 368c2ecf20Sopenharmony_ci#include "juli.h" 378c2ecf20Sopenharmony_ci#include "maya44.h" 388c2ecf20Sopenharmony_ci#include "phase.h" 398c2ecf20Sopenharmony_ci#include "wtm.h" 408c2ecf20Sopenharmony_ci#include "se.h" 418c2ecf20Sopenharmony_ci#include "quartet.h" 428c2ecf20Sopenharmony_ci#include "psc724.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); 468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 478c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{" 488c2ecf20Sopenharmony_ci REVO_DEVICE_DESC 498c2ecf20Sopenharmony_ci AMP_AUDIO2000_DEVICE_DESC 508c2ecf20Sopenharmony_ci AUREON_DEVICE_DESC 518c2ecf20Sopenharmony_ci VT1720_MOBO_DEVICE_DESC 528c2ecf20Sopenharmony_ci PONTIS_DEVICE_DESC 538c2ecf20Sopenharmony_ci PRODIGY192_DEVICE_DESC 548c2ecf20Sopenharmony_ci PRODIGY_HIFI_DEVICE_DESC 558c2ecf20Sopenharmony_ci JULI_DEVICE_DESC 568c2ecf20Sopenharmony_ci MAYA44_DEVICE_DESC 578c2ecf20Sopenharmony_ci PHASE_DEVICE_DESC 588c2ecf20Sopenharmony_ci WTM_DEVICE_DESC 598c2ecf20Sopenharmony_ci SE_DEVICE_DESC 608c2ecf20Sopenharmony_ci QTET_DEVICE_DESC 618c2ecf20Sopenharmony_ci "{VIA,VT1720}," 628c2ecf20Sopenharmony_ci "{VIA,VT1724}," 638c2ecf20Sopenharmony_ci "{ICEnsemble,Generic ICE1724}," 648c2ecf20Sopenharmony_ci "{ICEnsemble,Generic Envy24HT}" 658c2ecf20Sopenharmony_ci "{ICEnsemble,Generic Envy24PT}}"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 688c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 698c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ 708c2ecf20Sopenharmony_cistatic char *model[SNDRV_CARDS]; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for ICE1724 soundcard."); 748c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for ICE1724 soundcard."); 768c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 778c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable ICE1724 soundcard."); 788c2ecf20Sopenharmony_cimodule_param_array(model, charp, NULL, 0444); 798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(model, "Use the given board model."); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* Both VT1720 and VT1724 have the same PCI IDs */ 838c2ecf20Sopenharmony_cistatic const struct pci_device_id snd_vt1724_ids[] = { 848c2ecf20Sopenharmony_ci { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 }, 858c2ecf20Sopenharmony_ci { 0, } 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_vt1724_ids); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int PRO_RATE_LOCKED; 928c2ecf20Sopenharmony_cistatic int PRO_RATE_RESET = 1; 938c2ecf20Sopenharmony_cistatic unsigned int PRO_RATE_DEFAULT = 44100; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const char * const ext_clock_names[1] = { "IEC958 In" }; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * Basic I/O 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* 1028c2ecf20Sopenharmony_ci * default rates, default clock routines 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* check whether the clock mode is spdif-in */ 1068c2ecf20Sopenharmony_cistatic inline int stdclock_is_spdif_master(struct snd_ice1712 *ice) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER) ? 1 : 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * locking rate makes sense only for internal clock mode 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_cistatic inline int is_pro_rate_locked(struct snd_ice1712 *ice) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci return (!ice->is_spdif_master(ice)) && PRO_RATE_LOCKED; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * ac97 section 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic unsigned char snd_vt1724_ac97_ready(struct snd_ice1712 *ice) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci unsigned char old_cmd; 1268c2ecf20Sopenharmony_ci int tm; 1278c2ecf20Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) { 1288c2ecf20Sopenharmony_ci old_cmd = inb(ICEMT1724(ice, AC97_CMD)); 1298c2ecf20Sopenharmony_ci if (old_cmd & (VT1724_AC97_WRITE | VT1724_AC97_READ)) 1308c2ecf20Sopenharmony_ci continue; 1318c2ecf20Sopenharmony_ci if (!(old_cmd & VT1724_AC97_READY)) 1328c2ecf20Sopenharmony_ci continue; 1338c2ecf20Sopenharmony_ci return old_cmd; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "snd_vt1724_ac97_ready: timeout\n"); 1368c2ecf20Sopenharmony_ci return old_cmd; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int snd_vt1724_ac97_wait_bit(struct snd_ice1712 *ice, unsigned char bit) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci int tm; 1428c2ecf20Sopenharmony_ci for (tm = 0; tm < 0x10000; tm++) 1438c2ecf20Sopenharmony_ci if ((inb(ICEMT1724(ice, AC97_CMD)) & bit) == 0) 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "snd_vt1724_ac97_wait_bit: timeout\n"); 1468c2ecf20Sopenharmony_ci return -EIO; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void snd_vt1724_ac97_write(struct snd_ac97 *ac97, 1508c2ecf20Sopenharmony_ci unsigned short reg, 1518c2ecf20Sopenharmony_ci unsigned short val) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = ac97->private_data; 1548c2ecf20Sopenharmony_ci unsigned char old_cmd; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci old_cmd = snd_vt1724_ac97_ready(ice); 1578c2ecf20Sopenharmony_ci old_cmd &= ~VT1724_AC97_ID_MASK; 1588c2ecf20Sopenharmony_ci old_cmd |= ac97->num; 1598c2ecf20Sopenharmony_ci outb(reg, ICEMT1724(ice, AC97_INDEX)); 1608c2ecf20Sopenharmony_ci outw(val, ICEMT1724(ice, AC97_DATA)); 1618c2ecf20Sopenharmony_ci outb(old_cmd | VT1724_AC97_WRITE, ICEMT1724(ice, AC97_CMD)); 1628c2ecf20Sopenharmony_ci snd_vt1724_ac97_wait_bit(ice, VT1724_AC97_WRITE); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic unsigned short snd_vt1724_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = ac97->private_data; 1688c2ecf20Sopenharmony_ci unsigned char old_cmd; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci old_cmd = snd_vt1724_ac97_ready(ice); 1718c2ecf20Sopenharmony_ci old_cmd &= ~VT1724_AC97_ID_MASK; 1728c2ecf20Sopenharmony_ci old_cmd |= ac97->num; 1738c2ecf20Sopenharmony_ci outb(reg, ICEMT1724(ice, AC97_INDEX)); 1748c2ecf20Sopenharmony_ci outb(old_cmd | VT1724_AC97_READ, ICEMT1724(ice, AC97_CMD)); 1758c2ecf20Sopenharmony_ci if (snd_vt1724_ac97_wait_bit(ice, VT1724_AC97_READ) < 0) 1768c2ecf20Sopenharmony_ci return ~0; 1778c2ecf20Sopenharmony_ci return inw(ICEMT1724(ice, AC97_DATA)); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * GPIO operations 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* set gpio direction 0 = read, 1 = write */ 1868c2ecf20Sopenharmony_cistatic void snd_vt1724_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci outl(data, ICEREG1724(ice, GPIO_DIRECTION)); 1898c2ecf20Sopenharmony_ci inw(ICEREG1724(ice, GPIO_DIRECTION)); /* dummy read for pci-posting */ 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* get gpio direction 0 = read, 1 = write */ 1938c2ecf20Sopenharmony_cistatic unsigned int snd_vt1724_get_gpio_dir(struct snd_ice1712 *ice) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci return inl(ICEREG1724(ice, GPIO_DIRECTION)); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* set the gpio mask (0 = writable) */ 1998c2ecf20Sopenharmony_cistatic void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci outw(data, ICEREG1724(ice, GPIO_WRITE_MASK)); 2028c2ecf20Sopenharmony_ci if (!ice->vt1720) /* VT1720 supports only 16 GPIO bits */ 2038c2ecf20Sopenharmony_ci outb((data >> 16) & 0xff, ICEREG1724(ice, GPIO_WRITE_MASK_22)); 2048c2ecf20Sopenharmony_ci inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */ 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic unsigned int snd_vt1724_get_gpio_mask(struct snd_ice1712 *ice) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci unsigned int mask; 2108c2ecf20Sopenharmony_ci if (!ice->vt1720) 2118c2ecf20Sopenharmony_ci mask = (unsigned int)inb(ICEREG1724(ice, GPIO_WRITE_MASK_22)); 2128c2ecf20Sopenharmony_ci else 2138c2ecf20Sopenharmony_ci mask = 0; 2148c2ecf20Sopenharmony_ci mask = (mask << 16) | inw(ICEREG1724(ice, GPIO_WRITE_MASK)); 2158c2ecf20Sopenharmony_ci return mask; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic void snd_vt1724_set_gpio_data(struct snd_ice1712 *ice, unsigned int data) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci outw(data, ICEREG1724(ice, GPIO_DATA)); 2218c2ecf20Sopenharmony_ci if (!ice->vt1720) 2228c2ecf20Sopenharmony_ci outb(data >> 16, ICEREG1724(ice, GPIO_DATA_22)); 2238c2ecf20Sopenharmony_ci inw(ICEREG1724(ice, GPIO_DATA)); /* dummy read for pci-posting */ 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci unsigned int data; 2298c2ecf20Sopenharmony_ci if (!ice->vt1720) 2308c2ecf20Sopenharmony_ci data = (unsigned int)inb(ICEREG1724(ice, GPIO_DATA_22)); 2318c2ecf20Sopenharmony_ci else 2328c2ecf20Sopenharmony_ci data = 0; 2338c2ecf20Sopenharmony_ci data = (data << 16) | inw(ICEREG1724(ice, GPIO_DATA)); 2348c2ecf20Sopenharmony_ci return data; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * MIDI 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void vt1724_midi_clear_rx(struct snd_ice1712 *ice) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci unsigned int count; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci for (count = inb(ICEREG1724(ice, MPU_RXFIFO)); count > 0; --count) 2468c2ecf20Sopenharmony_ci inb(ICEREG1724(ice, MPU_DATA)); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic inline struct snd_rawmidi_substream * 2508c2ecf20Sopenharmony_ciget_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci return list_first_entry(&ice->rmidi[0]->streams[stream].substreams, 2538c2ecf20Sopenharmony_ci struct snd_rawmidi_substream, list); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void enable_midi_irq(struct snd_ice1712 *ice, u8 flag, int enable); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void vt1724_midi_write(struct snd_ice1712 *ice) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *s; 2618c2ecf20Sopenharmony_ci int count, i; 2628c2ecf20Sopenharmony_ci u8 buffer[32]; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_OUTPUT); 2658c2ecf20Sopenharmony_ci count = 31 - inb(ICEREG1724(ice, MPU_TXFIFO)); 2668c2ecf20Sopenharmony_ci if (count > 0) { 2678c2ecf20Sopenharmony_ci count = snd_rawmidi_transmit(s, buffer, count); 2688c2ecf20Sopenharmony_ci for (i = 0; i < count; ++i) 2698c2ecf20Sopenharmony_ci outb(buffer[i], ICEREG1724(ice, MPU_DATA)); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci /* mask irq when all bytes have been transmitted. 2728c2ecf20Sopenharmony_ci * enabled again in output_trigger when the new data comes in. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 2758c2ecf20Sopenharmony_ci !snd_rawmidi_transmit_empty(s)); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void vt1724_midi_read(struct snd_ice1712 *ice) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *s; 2818c2ecf20Sopenharmony_ci int count, i; 2828c2ecf20Sopenharmony_ci u8 buffer[32]; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_INPUT); 2858c2ecf20Sopenharmony_ci count = inb(ICEREG1724(ice, MPU_RXFIFO)); 2868c2ecf20Sopenharmony_ci if (count > 0) { 2878c2ecf20Sopenharmony_ci count = min(count, 32); 2888c2ecf20Sopenharmony_ci for (i = 0; i < count; ++i) 2898c2ecf20Sopenharmony_ci buffer[i] = inb(ICEREG1724(ice, MPU_DATA)); 2908c2ecf20Sopenharmony_ci snd_rawmidi_receive(s, buffer, count); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/* call with ice->reg_lock */ 2958c2ecf20Sopenharmony_cistatic void enable_midi_irq(struct snd_ice1712 *ice, u8 flag, int enable) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci u8 mask = inb(ICEREG1724(ice, IRQMASK)); 2988c2ecf20Sopenharmony_ci if (enable) 2998c2ecf20Sopenharmony_ci mask &= ~flag; 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci mask |= flag; 3028c2ecf20Sopenharmony_ci outb(mask, ICEREG1724(ice, IRQMASK)); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, 3068c2ecf20Sopenharmony_ci u8 flag, int enable) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = substream->rmidi->private_data; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 3118c2ecf20Sopenharmony_ci enable_midi_irq(ice, flag, enable); 3128c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic int vt1724_midi_output_open(struct snd_rawmidi_substream *s) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int vt1724_midi_output_close(struct snd_rawmidi_substream *s) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = s->rmidi->private_data; 3288c2ecf20Sopenharmony_ci unsigned long flags; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci spin_lock_irqsave(&ice->reg_lock, flags); 3318c2ecf20Sopenharmony_ci if (up) { 3328c2ecf20Sopenharmony_ci ice->midi_output = 1; 3338c2ecf20Sopenharmony_ci vt1724_midi_write(ice); 3348c2ecf20Sopenharmony_ci } else { 3358c2ecf20Sopenharmony_ci ice->midi_output = 0; 3368c2ecf20Sopenharmony_ci enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = s->rmidi->private_data; 3448c2ecf20Sopenharmony_ci unsigned long timeout; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0); 3478c2ecf20Sopenharmony_ci /* 32 bytes should be transmitted in less than about 12 ms */ 3488c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(15); 3498c2ecf20Sopenharmony_ci do { 3508c2ecf20Sopenharmony_ci if (inb(ICEREG1724(ice, MPU_CTRL)) & VT1724_MPU_TX_EMPTY) 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 3538c2ecf20Sopenharmony_ci } while (time_after(timeout, jiffies)); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic const struct snd_rawmidi_ops vt1724_midi_output_ops = { 3578c2ecf20Sopenharmony_ci .open = vt1724_midi_output_open, 3588c2ecf20Sopenharmony_ci .close = vt1724_midi_output_close, 3598c2ecf20Sopenharmony_ci .trigger = vt1724_midi_output_trigger, 3608c2ecf20Sopenharmony_ci .drain = vt1724_midi_output_drain, 3618c2ecf20Sopenharmony_ci}; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int vt1724_midi_input_open(struct snd_rawmidi_substream *s) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci vt1724_midi_clear_rx(s->rmidi->private_data); 3668c2ecf20Sopenharmony_ci vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 1); 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int vt1724_midi_input_close(struct snd_rawmidi_substream *s) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 0); 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = s->rmidi->private_data; 3798c2ecf20Sopenharmony_ci unsigned long flags; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci spin_lock_irqsave(&ice->reg_lock, flags); 3828c2ecf20Sopenharmony_ci if (up) { 3838c2ecf20Sopenharmony_ci ice->midi_input = 1; 3848c2ecf20Sopenharmony_ci vt1724_midi_read(ice); 3858c2ecf20Sopenharmony_ci } else { 3868c2ecf20Sopenharmony_ci ice->midi_input = 0; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic const struct snd_rawmidi_ops vt1724_midi_input_ops = { 3928c2ecf20Sopenharmony_ci .open = vt1724_midi_input_open, 3938c2ecf20Sopenharmony_ci .close = vt1724_midi_input_close, 3948c2ecf20Sopenharmony_ci .trigger = vt1724_midi_input_trigger, 3958c2ecf20Sopenharmony_ci}; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci/* 3998c2ecf20Sopenharmony_ci * Interrupt handler 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = dev_id; 4058c2ecf20Sopenharmony_ci unsigned char status; 4068c2ecf20Sopenharmony_ci unsigned char status_mask = 4078c2ecf20Sopenharmony_ci VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM; 4088c2ecf20Sopenharmony_ci int handled = 0; 4098c2ecf20Sopenharmony_ci int timeout = 0; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci while (1) { 4128c2ecf20Sopenharmony_ci status = inb(ICEREG1724(ice, IRQSTAT)); 4138c2ecf20Sopenharmony_ci status &= status_mask; 4148c2ecf20Sopenharmony_ci if (status == 0) 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci spin_lock(&ice->reg_lock); 4178c2ecf20Sopenharmony_ci if (++timeout > 10) { 4188c2ecf20Sopenharmony_ci status = inb(ICEREG1724(ice, IRQSTAT)); 4198c2ecf20Sopenharmony_ci dev_err(ice->card->dev, 4208c2ecf20Sopenharmony_ci "Too long irq loop, status = 0x%x\n", status); 4218c2ecf20Sopenharmony_ci if (status & VT1724_IRQ_MPU_TX) { 4228c2ecf20Sopenharmony_ci dev_err(ice->card->dev, "Disabling MPU_TX\n"); 4238c2ecf20Sopenharmony_ci enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci spin_unlock(&ice->reg_lock); 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci handled = 1; 4298c2ecf20Sopenharmony_ci if (status & VT1724_IRQ_MPU_TX) { 4308c2ecf20Sopenharmony_ci if (ice->midi_output) 4318c2ecf20Sopenharmony_ci vt1724_midi_write(ice); 4328c2ecf20Sopenharmony_ci else 4338c2ecf20Sopenharmony_ci enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); 4348c2ecf20Sopenharmony_ci /* Due to mysterical reasons, MPU_TX is always 4358c2ecf20Sopenharmony_ci * generated (and can't be cleared) when a PCM 4368c2ecf20Sopenharmony_ci * playback is going. So let's ignore at the 4378c2ecf20Sopenharmony_ci * next loop. 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci status_mask &= ~VT1724_IRQ_MPU_TX; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci if (status & VT1724_IRQ_MPU_RX) { 4428c2ecf20Sopenharmony_ci if (ice->midi_input) 4438c2ecf20Sopenharmony_ci vt1724_midi_read(ice); 4448c2ecf20Sopenharmony_ci else 4458c2ecf20Sopenharmony_ci vt1724_midi_clear_rx(ice); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci /* ack MPU irq */ 4488c2ecf20Sopenharmony_ci outb(status, ICEREG1724(ice, IRQSTAT)); 4498c2ecf20Sopenharmony_ci spin_unlock(&ice->reg_lock); 4508c2ecf20Sopenharmony_ci if (status & VT1724_IRQ_MTPCM) { 4518c2ecf20Sopenharmony_ci /* 4528c2ecf20Sopenharmony_ci * Multi-track PCM 4538c2ecf20Sopenharmony_ci * PCM assignment are: 4548c2ecf20Sopenharmony_ci * Playback DMA0 (M/C) = playback_pro_substream 4558c2ecf20Sopenharmony_ci * Playback DMA1 = playback_con_substream_ds[0] 4568c2ecf20Sopenharmony_ci * Playback DMA2 = playback_con_substream_ds[1] 4578c2ecf20Sopenharmony_ci * Playback DMA3 = playback_con_substream_ds[2] 4588c2ecf20Sopenharmony_ci * Playback DMA4 (SPDIF) = playback_con_substream 4598c2ecf20Sopenharmony_ci * Record DMA0 = capture_pro_substream 4608c2ecf20Sopenharmony_ci * Record DMA1 = capture_con_substream 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci unsigned char mtstat = inb(ICEMT1724(ice, IRQ)); 4638c2ecf20Sopenharmony_ci if (mtstat & VT1724_MULTI_PDMA0) { 4648c2ecf20Sopenharmony_ci if (ice->playback_pro_substream) 4658c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ice->playback_pro_substream); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci if (mtstat & VT1724_MULTI_RDMA0) { 4688c2ecf20Sopenharmony_ci if (ice->capture_pro_substream) 4698c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ice->capture_pro_substream); 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci if (mtstat & VT1724_MULTI_PDMA1) { 4728c2ecf20Sopenharmony_ci if (ice->playback_con_substream_ds[0]) 4738c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ice->playback_con_substream_ds[0]); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci if (mtstat & VT1724_MULTI_PDMA2) { 4768c2ecf20Sopenharmony_ci if (ice->playback_con_substream_ds[1]) 4778c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ice->playback_con_substream_ds[1]); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci if (mtstat & VT1724_MULTI_PDMA3) { 4808c2ecf20Sopenharmony_ci if (ice->playback_con_substream_ds[2]) 4818c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ice->playback_con_substream_ds[2]); 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci if (mtstat & VT1724_MULTI_PDMA4) { 4848c2ecf20Sopenharmony_ci if (ice->playback_con_substream) 4858c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ice->playback_con_substream); 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci if (mtstat & VT1724_MULTI_RDMA1) { 4888c2ecf20Sopenharmony_ci if (ice->capture_con_substream) 4898c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ice->capture_con_substream); 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci /* ack anyway to avoid freeze */ 4928c2ecf20Sopenharmony_ci outb(mtstat, ICEMT1724(ice, IRQ)); 4938c2ecf20Sopenharmony_ci /* ought to really handle this properly */ 4948c2ecf20Sopenharmony_ci if (mtstat & VT1724_MULTI_FIFO_ERR) { 4958c2ecf20Sopenharmony_ci unsigned char fstat = inb(ICEMT1724(ice, DMA_FIFO_ERR)); 4968c2ecf20Sopenharmony_ci outb(fstat, ICEMT1724(ice, DMA_FIFO_ERR)); 4978c2ecf20Sopenharmony_ci outb(VT1724_MULTI_FIFO_ERR | inb(ICEMT1724(ice, DMA_INT_MASK)), ICEMT1724(ice, DMA_INT_MASK)); 4988c2ecf20Sopenharmony_ci /* If I don't do this, I get machine lockup due to continual interrupts */ 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci/* 5078c2ecf20Sopenharmony_ci * PCM code - professional part (multitrack) 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic const unsigned int rates[] = { 5118c2ecf20Sopenharmony_ci 8000, 9600, 11025, 12000, 16000, 22050, 24000, 5128c2ecf20Sopenharmony_ci 32000, 44100, 48000, 64000, 88200, 96000, 5138c2ecf20Sopenharmony_ci 176400, 192000, 5148c2ecf20Sopenharmony_ci}; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_rates_96 = { 5178c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(rates) - 2, /* up to 96000 */ 5188c2ecf20Sopenharmony_ci .list = rates, 5198c2ecf20Sopenharmony_ci .mask = 0, 5208c2ecf20Sopenharmony_ci}; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_rates_48 = { 5238c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(rates) - 5, /* up to 48000 */ 5248c2ecf20Sopenharmony_ci .list = rates, 5258c2ecf20Sopenharmony_ci .mask = 0, 5268c2ecf20Sopenharmony_ci}; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_rates_192 = { 5298c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(rates), 5308c2ecf20Sopenharmony_ci .list = rates, 5318c2ecf20Sopenharmony_ci .mask = 0, 5328c2ecf20Sopenharmony_ci}; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistruct vt1724_pcm_reg { 5358c2ecf20Sopenharmony_ci unsigned int addr; /* ADDR register offset */ 5368c2ecf20Sopenharmony_ci unsigned int size; /* SIZE register offset */ 5378c2ecf20Sopenharmony_ci unsigned int count; /* COUNT register offset */ 5388c2ecf20Sopenharmony_ci unsigned int start; /* start & pause bit */ 5398c2ecf20Sopenharmony_ci}; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 5448c2ecf20Sopenharmony_ci unsigned char what; 5458c2ecf20Sopenharmony_ci unsigned char old; 5468c2ecf20Sopenharmony_ci struct snd_pcm_substream *s; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci what = 0; 5498c2ecf20Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 5508c2ecf20Sopenharmony_ci if (snd_pcm_substream_chip(s) == ice) { 5518c2ecf20Sopenharmony_ci const struct vt1724_pcm_reg *reg; 5528c2ecf20Sopenharmony_ci reg = s->runtime->private_data; 5538c2ecf20Sopenharmony_ci what |= reg->start; 5548c2ecf20Sopenharmony_ci snd_pcm_trigger_done(s, substream); 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci switch (cmd) { 5598c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 5608c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 5618c2ecf20Sopenharmony_ci spin_lock(&ice->reg_lock); 5628c2ecf20Sopenharmony_ci old = inb(ICEMT1724(ice, DMA_PAUSE)); 5638c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) 5648c2ecf20Sopenharmony_ci old |= what; 5658c2ecf20Sopenharmony_ci else 5668c2ecf20Sopenharmony_ci old &= ~what; 5678c2ecf20Sopenharmony_ci outb(old, ICEMT1724(ice, DMA_PAUSE)); 5688c2ecf20Sopenharmony_ci spin_unlock(&ice->reg_lock); 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 5728c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 5738c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 5748c2ecf20Sopenharmony_ci spin_lock(&ice->reg_lock); 5758c2ecf20Sopenharmony_ci old = inb(ICEMT1724(ice, DMA_CONTROL)); 5768c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) 5778c2ecf20Sopenharmony_ci old |= what; 5788c2ecf20Sopenharmony_ci else 5798c2ecf20Sopenharmony_ci old &= ~what; 5808c2ecf20Sopenharmony_ci outb(old, ICEMT1724(ice, DMA_CONTROL)); 5818c2ecf20Sopenharmony_ci spin_unlock(&ice->reg_lock); 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 5858c2ecf20Sopenharmony_ci /* apps will have to restart stream */ 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci default: 5898c2ecf20Sopenharmony_ci return -EINVAL; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci/* 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci#define DMA_STARTS (VT1724_RDMA0_START|VT1724_PDMA0_START|VT1724_RDMA1_START|\ 5988c2ecf20Sopenharmony_ci VT1724_PDMA1_START|VT1724_PDMA2_START|VT1724_PDMA3_START|VT1724_PDMA4_START) 5998c2ecf20Sopenharmony_ci#define DMA_PAUSES (VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|\ 6008c2ecf20Sopenharmony_ci VT1724_PDMA1_PAUSE|VT1724_PDMA2_PAUSE|VT1724_PDMA3_PAUSE|VT1724_PDMA4_PAUSE) 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic const unsigned int stdclock_rate_list[16] = { 6038c2ecf20Sopenharmony_ci 48000, 24000, 12000, 9600, 32000, 16000, 8000, 96000, 44100, 6048c2ecf20Sopenharmony_ci 22050, 11025, 88200, 176400, 0, 192000, 64000 6058c2ecf20Sopenharmony_ci}; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic unsigned int stdclock_get_rate(struct snd_ice1712 *ice) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci return stdclock_rate_list[inb(ICEMT1724(ice, RATE)) & 15]; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic void stdclock_set_rate(struct snd_ice1712 *ice, unsigned int rate) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci int i; 6158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(stdclock_rate_list); i++) { 6168c2ecf20Sopenharmony_ci if (stdclock_rate_list[i] == rate) { 6178c2ecf20Sopenharmony_ci outb(i, ICEMT1724(ice, RATE)); 6188c2ecf20Sopenharmony_ci return; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic unsigned char stdclock_set_mclk(struct snd_ice1712 *ice, 6248c2ecf20Sopenharmony_ci unsigned int rate) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci unsigned char val, old; 6278c2ecf20Sopenharmony_ci /* check MT02 */ 6288c2ecf20Sopenharmony_ci if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) { 6298c2ecf20Sopenharmony_ci val = old = inb(ICEMT1724(ice, I2S_FORMAT)); 6308c2ecf20Sopenharmony_ci if (rate > 96000) 6318c2ecf20Sopenharmony_ci val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */ 6328c2ecf20Sopenharmony_ci else 6338c2ecf20Sopenharmony_ci val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */ 6348c2ecf20Sopenharmony_ci if (val != old) { 6358c2ecf20Sopenharmony_ci outb(val, ICEMT1724(ice, I2S_FORMAT)); 6368c2ecf20Sopenharmony_ci /* master clock changed */ 6378c2ecf20Sopenharmony_ci return 1; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci /* no change in master clock */ 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, 6458c2ecf20Sopenharmony_ci int force) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci unsigned long flags; 6488c2ecf20Sopenharmony_ci unsigned char mclk_change; 6498c2ecf20Sopenharmony_ci unsigned int i, old_rate; 6508c2ecf20Sopenharmony_ci bool call_set_rate = false; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (rate > ice->hw_rates->list[ice->hw_rates->count - 1]) 6538c2ecf20Sopenharmony_ci return -EINVAL; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci spin_lock_irqsave(&ice->reg_lock, flags); 6568c2ecf20Sopenharmony_ci if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || 6578c2ecf20Sopenharmony_ci (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { 6588c2ecf20Sopenharmony_ci /* running? we cannot change the rate now... */ 6598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 6608c2ecf20Sopenharmony_ci return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci if (!force && is_pro_rate_locked(ice)) { 6638c2ecf20Sopenharmony_ci /* comparing required and current rate - makes sense for 6648c2ecf20Sopenharmony_ci * internal clock only */ 6658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 6668c2ecf20Sopenharmony_ci return (rate == ice->cur_rate) ? 0 : -EBUSY; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (force || !ice->is_spdif_master(ice)) { 6708c2ecf20Sopenharmony_ci /* force means the rate was switched by ucontrol, otherwise 6718c2ecf20Sopenharmony_ci * setting clock rate for internal clock mode */ 6728c2ecf20Sopenharmony_ci old_rate = ice->get_rate(ice); 6738c2ecf20Sopenharmony_ci if (force || (old_rate != rate)) 6748c2ecf20Sopenharmony_ci call_set_rate = true; 6758c2ecf20Sopenharmony_ci else if (rate == ice->cur_rate) { 6768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci ice->cur_rate = rate; 6828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (call_set_rate) 6858c2ecf20Sopenharmony_ci ice->set_rate(ice, rate); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* setting master clock */ 6888c2ecf20Sopenharmony_ci mclk_change = ice->set_mclk(ice, rate); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (mclk_change && ice->gpio.i2s_mclk_changed) 6918c2ecf20Sopenharmony_ci ice->gpio.i2s_mclk_changed(ice); 6928c2ecf20Sopenharmony_ci if (ice->gpio.set_pro_rate) 6938c2ecf20Sopenharmony_ci ice->gpio.set_pro_rate(ice, rate); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* set up codecs */ 6968c2ecf20Sopenharmony_ci for (i = 0; i < ice->akm_codecs; i++) { 6978c2ecf20Sopenharmony_ci if (ice->akm[i].ops.set_rate_val) 6988c2ecf20Sopenharmony_ci ice->akm[i].ops.set_rate_val(&ice->akm[i], rate); 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci if (ice->spdif.ops.setup_rate) 7018c2ecf20Sopenharmony_ci ice->spdif.ops.setup_rate(ice, rate); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return 0; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, 7078c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 7108c2ecf20Sopenharmony_ci int i, chs; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci chs = params_channels(hw_params); 7138c2ecf20Sopenharmony_ci mutex_lock(&ice->open_mutex); 7148c2ecf20Sopenharmony_ci /* mark surround channels */ 7158c2ecf20Sopenharmony_ci if (substream == ice->playback_pro_substream) { 7168c2ecf20Sopenharmony_ci /* PDMA0 can be multi-channel up to 8 */ 7178c2ecf20Sopenharmony_ci chs = chs / 2 - 1; 7188c2ecf20Sopenharmony_ci for (i = 0; i < chs; i++) { 7198c2ecf20Sopenharmony_ci if (ice->pcm_reserved[i] && 7208c2ecf20Sopenharmony_ci ice->pcm_reserved[i] != substream) { 7218c2ecf20Sopenharmony_ci mutex_unlock(&ice->open_mutex); 7228c2ecf20Sopenharmony_ci return -EBUSY; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci ice->pcm_reserved[i] = substream; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci for (; i < 3; i++) { 7278c2ecf20Sopenharmony_ci if (ice->pcm_reserved[i] == substream) 7288c2ecf20Sopenharmony_ci ice->pcm_reserved[i] = NULL; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci } else { 7318c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 7328c2ecf20Sopenharmony_ci /* check individual playback stream */ 7338c2ecf20Sopenharmony_ci if (ice->playback_con_substream_ds[i] == substream) { 7348c2ecf20Sopenharmony_ci if (ice->pcm_reserved[i] && 7358c2ecf20Sopenharmony_ci ice->pcm_reserved[i] != substream) { 7368c2ecf20Sopenharmony_ci mutex_unlock(&ice->open_mutex); 7378c2ecf20Sopenharmony_ci return -EBUSY; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci ice->pcm_reserved[i] = substream; 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci mutex_unlock(&ice->open_mutex); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int snd_vt1724_pcm_hw_free(struct snd_pcm_substream *substream) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 7528c2ecf20Sopenharmony_ci int i; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci mutex_lock(&ice->open_mutex); 7558c2ecf20Sopenharmony_ci /* unmark surround channels */ 7568c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 7578c2ecf20Sopenharmony_ci if (ice->pcm_reserved[i] == substream) 7588c2ecf20Sopenharmony_ci ice->pcm_reserved[i] = NULL; 7598c2ecf20Sopenharmony_ci mutex_unlock(&ice->open_mutex); 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 7668c2ecf20Sopenharmony_ci unsigned char val; 7678c2ecf20Sopenharmony_ci unsigned int size; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 7708c2ecf20Sopenharmony_ci val = (8 - substream->runtime->channels) >> 1; 7718c2ecf20Sopenharmony_ci outb(val, ICEMT1724(ice, BURST)); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci outl(substream->runtime->dma_addr, ICEMT1724(ice, PLAYBACK_ADDR)); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci size = (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1; 7768c2ecf20Sopenharmony_ci /* outl(size, ICEMT1724(ice, PLAYBACK_SIZE)); */ 7778c2ecf20Sopenharmony_ci outw(size, ICEMT1724(ice, PLAYBACK_SIZE)); 7788c2ecf20Sopenharmony_ci outb(size >> 16, ICEMT1724(ice, PLAYBACK_SIZE) + 2); 7798c2ecf20Sopenharmony_ci size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1; 7808c2ecf20Sopenharmony_ci /* outl(size, ICEMT1724(ice, PLAYBACK_COUNT)); */ 7818c2ecf20Sopenharmony_ci outw(size, ICEMT1724(ice, PLAYBACK_COUNT)); 7828c2ecf20Sopenharmony_ci outb(size >> 16, ICEMT1724(ice, PLAYBACK_COUNT) + 2); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* 7878c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "pro prepare: ch = %d, addr = 0x%x, " 7888c2ecf20Sopenharmony_ci "buffer = 0x%x, period = 0x%x\n", 7898c2ecf20Sopenharmony_ci substream->runtime->channels, 7908c2ecf20Sopenharmony_ci (unsigned int)substream->runtime->dma_addr, 7918c2ecf20Sopenharmony_ci snd_pcm_lib_buffer_bytes(substream), 7928c2ecf20Sopenharmony_ci snd_pcm_lib_period_bytes(substream)); 7938c2ecf20Sopenharmony_ci */ 7948c2ecf20Sopenharmony_ci return 0; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substream *substream) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 8008c2ecf20Sopenharmony_ci size_t ptr; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & VT1724_PDMA0_START)) 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci#if 0 /* read PLAYBACK_ADDR */ 8058c2ecf20Sopenharmony_ci ptr = inl(ICEMT1724(ice, PLAYBACK_ADDR)); 8068c2ecf20Sopenharmony_ci if (ptr < substream->runtime->dma_addr) { 8078c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "invalid negative ptr\n"); 8088c2ecf20Sopenharmony_ci return 0; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci ptr -= substream->runtime->dma_addr; 8118c2ecf20Sopenharmony_ci ptr = bytes_to_frames(substream->runtime, ptr); 8128c2ecf20Sopenharmony_ci if (ptr >= substream->runtime->buffer_size) { 8138c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n", 8148c2ecf20Sopenharmony_ci (int)ptr, (int)substream->runtime->period_size); 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci#else /* read PLAYBACK_SIZE */ 8188c2ecf20Sopenharmony_ci ptr = inl(ICEMT1724(ice, PLAYBACK_SIZE)) & 0xffffff; 8198c2ecf20Sopenharmony_ci ptr = (ptr + 1) << 2; 8208c2ecf20Sopenharmony_ci ptr = bytes_to_frames(substream->runtime, ptr); 8218c2ecf20Sopenharmony_ci if (!ptr) 8228c2ecf20Sopenharmony_ci ; 8238c2ecf20Sopenharmony_ci else if (ptr <= substream->runtime->buffer_size) 8248c2ecf20Sopenharmony_ci ptr = substream->runtime->buffer_size - ptr; 8258c2ecf20Sopenharmony_ci else { 8268c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n", 8278c2ecf20Sopenharmony_ci (int)ptr, (int)substream->runtime->buffer_size); 8288c2ecf20Sopenharmony_ci ptr = 0; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci#endif 8318c2ecf20Sopenharmony_ci return ptr; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 8378c2ecf20Sopenharmony_ci const struct vt1724_pcm_reg *reg = substream->runtime->private_data; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 8408c2ecf20Sopenharmony_ci outl(substream->runtime->dma_addr, ice->profi_port + reg->addr); 8418c2ecf20Sopenharmony_ci outw((snd_pcm_lib_buffer_bytes(substream) >> 2) - 1, 8428c2ecf20Sopenharmony_ci ice->profi_port + reg->size); 8438c2ecf20Sopenharmony_ci outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, 8448c2ecf20Sopenharmony_ci ice->profi_port + reg->count); 8458c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substream) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 8528c2ecf20Sopenharmony_ci const struct vt1724_pcm_reg *reg = substream->runtime->private_data; 8538c2ecf20Sopenharmony_ci size_t ptr; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start)) 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci#if 0 /* use ADDR register */ 8588c2ecf20Sopenharmony_ci ptr = inl(ice->profi_port + reg->addr); 8598c2ecf20Sopenharmony_ci ptr -= substream->runtime->dma_addr; 8608c2ecf20Sopenharmony_ci return bytes_to_frames(substream->runtime, ptr); 8618c2ecf20Sopenharmony_ci#else /* use SIZE register */ 8628c2ecf20Sopenharmony_ci ptr = inw(ice->profi_port + reg->size); 8638c2ecf20Sopenharmony_ci ptr = (ptr + 1) << 2; 8648c2ecf20Sopenharmony_ci ptr = bytes_to_frames(substream->runtime, ptr); 8658c2ecf20Sopenharmony_ci if (!ptr) 8668c2ecf20Sopenharmony_ci ; 8678c2ecf20Sopenharmony_ci else if (ptr <= substream->runtime->buffer_size) 8688c2ecf20Sopenharmony_ci ptr = substream->runtime->buffer_size - ptr; 8698c2ecf20Sopenharmony_ci else { 8708c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n", 8718c2ecf20Sopenharmony_ci (int)ptr, (int)substream->runtime->buffer_size); 8728c2ecf20Sopenharmony_ci ptr = 0; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci return ptr; 8758c2ecf20Sopenharmony_ci#endif 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic const struct vt1724_pcm_reg vt1724_pdma0_reg = { 8798c2ecf20Sopenharmony_ci .addr = VT1724_MT_PLAYBACK_ADDR, 8808c2ecf20Sopenharmony_ci .size = VT1724_MT_PLAYBACK_SIZE, 8818c2ecf20Sopenharmony_ci .count = VT1724_MT_PLAYBACK_COUNT, 8828c2ecf20Sopenharmony_ci .start = VT1724_PDMA0_START, 8838c2ecf20Sopenharmony_ci}; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic const struct vt1724_pcm_reg vt1724_pdma4_reg = { 8868c2ecf20Sopenharmony_ci .addr = VT1724_MT_PDMA4_ADDR, 8878c2ecf20Sopenharmony_ci .size = VT1724_MT_PDMA4_SIZE, 8888c2ecf20Sopenharmony_ci .count = VT1724_MT_PDMA4_COUNT, 8898c2ecf20Sopenharmony_ci .start = VT1724_PDMA4_START, 8908c2ecf20Sopenharmony_ci}; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic const struct vt1724_pcm_reg vt1724_rdma0_reg = { 8938c2ecf20Sopenharmony_ci .addr = VT1724_MT_CAPTURE_ADDR, 8948c2ecf20Sopenharmony_ci .size = VT1724_MT_CAPTURE_SIZE, 8958c2ecf20Sopenharmony_ci .count = VT1724_MT_CAPTURE_COUNT, 8968c2ecf20Sopenharmony_ci .start = VT1724_RDMA0_START, 8978c2ecf20Sopenharmony_ci}; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic const struct vt1724_pcm_reg vt1724_rdma1_reg = { 9008c2ecf20Sopenharmony_ci .addr = VT1724_MT_RDMA1_ADDR, 9018c2ecf20Sopenharmony_ci .size = VT1724_MT_RDMA1_SIZE, 9028c2ecf20Sopenharmony_ci .count = VT1724_MT_RDMA1_COUNT, 9038c2ecf20Sopenharmony_ci .start = VT1724_RDMA1_START, 9048c2ecf20Sopenharmony_ci}; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci#define vt1724_playback_pro_reg vt1724_pdma0_reg 9078c2ecf20Sopenharmony_ci#define vt1724_playback_spdif_reg vt1724_pdma4_reg 9088c2ecf20Sopenharmony_ci#define vt1724_capture_pro_reg vt1724_rdma0_reg 9098c2ecf20Sopenharmony_ci#define vt1724_capture_spdif_reg vt1724_rdma1_reg 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_vt1724_playback_pro = { 9128c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 9138c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 9148c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 9158c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), 9168c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 9178c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_192000, 9188c2ecf20Sopenharmony_ci .rate_min = 8000, 9198c2ecf20Sopenharmony_ci .rate_max = 192000, 9208c2ecf20Sopenharmony_ci .channels_min = 2, 9218c2ecf20Sopenharmony_ci .channels_max = 8, 9228c2ecf20Sopenharmony_ci .buffer_bytes_max = (1UL << 21), /* 19bits dword */ 9238c2ecf20Sopenharmony_ci .period_bytes_min = 8 * 4 * 2, /* FIXME: constraints needed */ 9248c2ecf20Sopenharmony_ci .period_bytes_max = (1UL << 21), 9258c2ecf20Sopenharmony_ci .periods_min = 2, 9268c2ecf20Sopenharmony_ci .periods_max = 1024, 9278c2ecf20Sopenharmony_ci}; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_vt1724_spdif = { 9308c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 9318c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 9328c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 9338c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), 9348c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 9358c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100| 9368c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_88200| 9378c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_176400| 9388c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_192000), 9398c2ecf20Sopenharmony_ci .rate_min = 32000, 9408c2ecf20Sopenharmony_ci .rate_max = 192000, 9418c2ecf20Sopenharmony_ci .channels_min = 2, 9428c2ecf20Sopenharmony_ci .channels_max = 2, 9438c2ecf20Sopenharmony_ci .buffer_bytes_max = (1UL << 18), /* 16bits dword */ 9448c2ecf20Sopenharmony_ci .period_bytes_min = 2 * 4 * 2, 9458c2ecf20Sopenharmony_ci .period_bytes_max = (1UL << 18), 9468c2ecf20Sopenharmony_ci .periods_min = 2, 9478c2ecf20Sopenharmony_ci .periods_max = 1024, 9488c2ecf20Sopenharmony_ci}; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_vt1724_2ch_stereo = { 9518c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 9528c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 9538c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 9548c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), 9558c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 9568c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_192000, 9578c2ecf20Sopenharmony_ci .rate_min = 8000, 9588c2ecf20Sopenharmony_ci .rate_max = 192000, 9598c2ecf20Sopenharmony_ci .channels_min = 2, 9608c2ecf20Sopenharmony_ci .channels_max = 2, 9618c2ecf20Sopenharmony_ci .buffer_bytes_max = (1UL << 18), /* 16bits dword */ 9628c2ecf20Sopenharmony_ci .period_bytes_min = 2 * 4 * 2, 9638c2ecf20Sopenharmony_ci .period_bytes_max = (1UL << 18), 9648c2ecf20Sopenharmony_ci .periods_min = 2, 9658c2ecf20Sopenharmony_ci .periods_max = 1024, 9668c2ecf20Sopenharmony_ci}; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci/* 9698c2ecf20Sopenharmony_ci * set rate constraints 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_cistatic void set_std_hw_rates(struct snd_ice1712 *ice) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) { 9748c2ecf20Sopenharmony_ci /* I2S */ 9758c2ecf20Sopenharmony_ci /* VT1720 doesn't support more than 96kHz */ 9768c2ecf20Sopenharmony_ci if ((ice->eeprom.data[ICE_EEP2_I2S] & 0x08) && !ice->vt1720) 9778c2ecf20Sopenharmony_ci ice->hw_rates = &hw_constraints_rates_192; 9788c2ecf20Sopenharmony_ci else 9798c2ecf20Sopenharmony_ci ice->hw_rates = &hw_constraints_rates_96; 9808c2ecf20Sopenharmony_ci } else { 9818c2ecf20Sopenharmony_ci /* ACLINK */ 9828c2ecf20Sopenharmony_ci ice->hw_rates = &hw_constraints_rates_48; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic int set_rate_constraints(struct snd_ice1712 *ice, 9878c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci runtime->hw.rate_min = ice->hw_rates->list[0]; 9928c2ecf20Sopenharmony_ci runtime->hw.rate_max = ice->hw_rates->list[ice->hw_rates->count - 1]; 9938c2ecf20Sopenharmony_ci runtime->hw.rates = SNDRV_PCM_RATE_KNOT; 9948c2ecf20Sopenharmony_ci return snd_pcm_hw_constraint_list(runtime, 0, 9958c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 9968c2ecf20Sopenharmony_ci ice->hw_rates); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci/* if the card has the internal rate locked (is_pro_locked), limit runtime 10008c2ecf20Sopenharmony_ci hw rates to the current internal rate only. 10018c2ecf20Sopenharmony_ci*/ 10028c2ecf20Sopenharmony_cistatic void constrain_rate_if_locked(struct snd_pcm_substream *substream) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 10058c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 10068c2ecf20Sopenharmony_ci unsigned int rate; 10078c2ecf20Sopenharmony_ci if (is_pro_rate_locked(ice)) { 10088c2ecf20Sopenharmony_ci rate = ice->get_rate(ice); 10098c2ecf20Sopenharmony_ci if (rate >= runtime->hw.rate_min 10108c2ecf20Sopenharmony_ci && rate <= runtime->hw.rate_max) { 10118c2ecf20Sopenharmony_ci runtime->hw.rate_min = rate; 10128c2ecf20Sopenharmony_ci runtime->hw.rate_max = rate; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci/* multi-channel playback needs alignment 8x32bit regardless of the channels 10198c2ecf20Sopenharmony_ci * actually used 10208c2ecf20Sopenharmony_ci */ 10218c2ecf20Sopenharmony_ci#define VT1724_BUFFER_ALIGN 0x20 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 10268c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 10278c2ecf20Sopenharmony_ci int chs, num_indeps; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci runtime->private_data = (void *)&vt1724_playback_pro_reg; 10308c2ecf20Sopenharmony_ci ice->playback_pro_substream = substream; 10318c2ecf20Sopenharmony_ci runtime->hw = snd_vt1724_playback_pro; 10328c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 10338c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 10348c2ecf20Sopenharmony_ci set_rate_constraints(ice, substream); 10358c2ecf20Sopenharmony_ci mutex_lock(&ice->open_mutex); 10368c2ecf20Sopenharmony_ci /* calculate the currently available channels */ 10378c2ecf20Sopenharmony_ci num_indeps = ice->num_total_dacs / 2 - 1; 10388c2ecf20Sopenharmony_ci for (chs = 0; chs < num_indeps; chs++) { 10398c2ecf20Sopenharmony_ci if (ice->pcm_reserved[chs]) 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci chs = (chs + 1) * 2; 10438c2ecf20Sopenharmony_ci runtime->hw.channels_max = chs; 10448c2ecf20Sopenharmony_ci if (chs > 2) /* channels must be even */ 10458c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); 10468c2ecf20Sopenharmony_ci mutex_unlock(&ice->open_mutex); 10478c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 10488c2ecf20Sopenharmony_ci VT1724_BUFFER_ALIGN); 10498c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 10508c2ecf20Sopenharmony_ci VT1724_BUFFER_ALIGN); 10518c2ecf20Sopenharmony_ci constrain_rate_if_locked(substream); 10528c2ecf20Sopenharmony_ci if (ice->pro_open) 10538c2ecf20Sopenharmony_ci ice->pro_open(ice, substream); 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 10608c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci runtime->private_data = (void *)&vt1724_capture_pro_reg; 10638c2ecf20Sopenharmony_ci ice->capture_pro_substream = substream; 10648c2ecf20Sopenharmony_ci runtime->hw = snd_vt1724_2ch_stereo; 10658c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 10668c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 10678c2ecf20Sopenharmony_ci set_rate_constraints(ice, substream); 10688c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 10698c2ecf20Sopenharmony_ci VT1724_BUFFER_ALIGN); 10708c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 10718c2ecf20Sopenharmony_ci VT1724_BUFFER_ALIGN); 10728c2ecf20Sopenharmony_ci constrain_rate_if_locked(substream); 10738c2ecf20Sopenharmony_ci if (ice->pro_open) 10748c2ecf20Sopenharmony_ci ice->pro_open(ice, substream); 10758c2ecf20Sopenharmony_ci return 0; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_pro_close(struct snd_pcm_substream *substream) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (PRO_RATE_RESET) 10838c2ecf20Sopenharmony_ci snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0); 10848c2ecf20Sopenharmony_ci ice->playback_pro_substream = NULL; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci return 0; 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic int snd_vt1724_capture_pro_close(struct snd_pcm_substream *substream) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (PRO_RATE_RESET) 10948c2ecf20Sopenharmony_ci snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0); 10958c2ecf20Sopenharmony_ci ice->capture_pro_substream = NULL; 10968c2ecf20Sopenharmony_ci return 0; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_vt1724_playback_pro_ops = { 11008c2ecf20Sopenharmony_ci .open = snd_vt1724_playback_pro_open, 11018c2ecf20Sopenharmony_ci .close = snd_vt1724_playback_pro_close, 11028c2ecf20Sopenharmony_ci .hw_params = snd_vt1724_pcm_hw_params, 11038c2ecf20Sopenharmony_ci .hw_free = snd_vt1724_pcm_hw_free, 11048c2ecf20Sopenharmony_ci .prepare = snd_vt1724_playback_pro_prepare, 11058c2ecf20Sopenharmony_ci .trigger = snd_vt1724_pcm_trigger, 11068c2ecf20Sopenharmony_ci .pointer = snd_vt1724_playback_pro_pointer, 11078c2ecf20Sopenharmony_ci}; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_vt1724_capture_pro_ops = { 11108c2ecf20Sopenharmony_ci .open = snd_vt1724_capture_pro_open, 11118c2ecf20Sopenharmony_ci .close = snd_vt1724_capture_pro_close, 11128c2ecf20Sopenharmony_ci .hw_params = snd_vt1724_pcm_hw_params, 11138c2ecf20Sopenharmony_ci .hw_free = snd_vt1724_pcm_hw_free, 11148c2ecf20Sopenharmony_ci .prepare = snd_vt1724_pcm_prepare, 11158c2ecf20Sopenharmony_ci .trigger = snd_vt1724_pcm_trigger, 11168c2ecf20Sopenharmony_ci .pointer = snd_vt1724_pcm_pointer, 11178c2ecf20Sopenharmony_ci}; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_cistatic int snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 11228c2ecf20Sopenharmony_ci int capt, err; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if ((ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_ADC_MASK) == 11258c2ecf20Sopenharmony_ci VT1724_CFG_ADC_NONE) 11268c2ecf20Sopenharmony_ci capt = 0; 11278c2ecf20Sopenharmony_ci else 11288c2ecf20Sopenharmony_ci capt = 1; 11298c2ecf20Sopenharmony_ci err = snd_pcm_new(ice->card, "ICE1724", device, 1, capt, &pcm); 11308c2ecf20Sopenharmony_ci if (err < 0) 11318c2ecf20Sopenharmony_ci return err; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vt1724_playback_pro_ops); 11348c2ecf20Sopenharmony_ci if (capt) 11358c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 11368c2ecf20Sopenharmony_ci &snd_vt1724_capture_pro_ops); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci pcm->private_data = ice; 11398c2ecf20Sopenharmony_ci pcm->info_flags = 0; 11408c2ecf20Sopenharmony_ci strcpy(pcm->name, "ICE1724"); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 11438c2ecf20Sopenharmony_ci &ice->pci->dev, 256*1024, 256*1024); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci ice->pcm_pro = pcm; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci return 0; 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci/* 11528c2ecf20Sopenharmony_ci * SPDIF PCM 11538c2ecf20Sopenharmony_ci */ 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci/* update spdif control bits; call with reg_lock */ 11568c2ecf20Sopenharmony_cistatic void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci unsigned char cbit, disabled; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci cbit = inb(ICEREG1724(ice, SPDIF_CFG)); 11618c2ecf20Sopenharmony_ci disabled = cbit & ~VT1724_CFG_SPDIF_OUT_EN; 11628c2ecf20Sopenharmony_ci if (cbit != disabled) 11638c2ecf20Sopenharmony_ci outb(disabled, ICEREG1724(ice, SPDIF_CFG)); 11648c2ecf20Sopenharmony_ci outw(val, ICEMT1724(ice, SPDIF_CTRL)); 11658c2ecf20Sopenharmony_ci if (cbit != disabled) 11668c2ecf20Sopenharmony_ci outb(cbit, ICEREG1724(ice, SPDIF_CFG)); 11678c2ecf20Sopenharmony_ci outw(val, ICEMT1724(ice, SPDIF_CTRL)); 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci/* update SPDIF control bits according to the given rate */ 11718c2ecf20Sopenharmony_cistatic void update_spdif_rate(struct snd_ice1712 *ice, unsigned int rate) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci unsigned int val, nval; 11748c2ecf20Sopenharmony_ci unsigned long flags; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci spin_lock_irqsave(&ice->reg_lock, flags); 11778c2ecf20Sopenharmony_ci nval = val = inw(ICEMT1724(ice, SPDIF_CTRL)); 11788c2ecf20Sopenharmony_ci nval &= ~(7 << 12); 11798c2ecf20Sopenharmony_ci switch (rate) { 11808c2ecf20Sopenharmony_ci case 44100: break; 11818c2ecf20Sopenharmony_ci case 48000: nval |= 2 << 12; break; 11828c2ecf20Sopenharmony_ci case 32000: nval |= 3 << 12; break; 11838c2ecf20Sopenharmony_ci case 88200: nval |= 4 << 12; break; 11848c2ecf20Sopenharmony_ci case 96000: nval |= 5 << 12; break; 11858c2ecf20Sopenharmony_ci case 192000: nval |= 6 << 12; break; 11868c2ecf20Sopenharmony_ci case 176400: nval |= 7 << 12; break; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci if (val != nval) 11898c2ecf20Sopenharmony_ci update_spdif_bits(ice, nval); 11908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ice->reg_lock, flags); 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_spdif_prepare(struct snd_pcm_substream *substream) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 11968c2ecf20Sopenharmony_ci if (!ice->force_pdma4) 11978c2ecf20Sopenharmony_ci update_spdif_rate(ice, substream->runtime->rate); 11988c2ecf20Sopenharmony_ci return snd_vt1724_pcm_prepare(substream); 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 12048c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci runtime->private_data = (void *)&vt1724_playback_spdif_reg; 12078c2ecf20Sopenharmony_ci ice->playback_con_substream = substream; 12088c2ecf20Sopenharmony_ci if (ice->force_pdma4) { 12098c2ecf20Sopenharmony_ci runtime->hw = snd_vt1724_2ch_stereo; 12108c2ecf20Sopenharmony_ci set_rate_constraints(ice, substream); 12118c2ecf20Sopenharmony_ci } else 12128c2ecf20Sopenharmony_ci runtime->hw = snd_vt1724_spdif; 12138c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 12148c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 12158c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 12168c2ecf20Sopenharmony_ci VT1724_BUFFER_ALIGN); 12178c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 12188c2ecf20Sopenharmony_ci VT1724_BUFFER_ALIGN); 12198c2ecf20Sopenharmony_ci constrain_rate_if_locked(substream); 12208c2ecf20Sopenharmony_ci if (ice->spdif.ops.open) 12218c2ecf20Sopenharmony_ci ice->spdif.ops.open(ice, substream); 12228c2ecf20Sopenharmony_ci return 0; 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_spdif_close(struct snd_pcm_substream *substream) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (PRO_RATE_RESET) 12308c2ecf20Sopenharmony_ci snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0); 12318c2ecf20Sopenharmony_ci ice->playback_con_substream = NULL; 12328c2ecf20Sopenharmony_ci if (ice->spdif.ops.close) 12338c2ecf20Sopenharmony_ci ice->spdif.ops.close(ice, substream); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci return 0; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 12418c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci runtime->private_data = (void *)&vt1724_capture_spdif_reg; 12448c2ecf20Sopenharmony_ci ice->capture_con_substream = substream; 12458c2ecf20Sopenharmony_ci if (ice->force_rdma1) { 12468c2ecf20Sopenharmony_ci runtime->hw = snd_vt1724_2ch_stereo; 12478c2ecf20Sopenharmony_ci set_rate_constraints(ice, substream); 12488c2ecf20Sopenharmony_ci } else 12498c2ecf20Sopenharmony_ci runtime->hw = snd_vt1724_spdif; 12508c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 12518c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 12528c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 12538c2ecf20Sopenharmony_ci VT1724_BUFFER_ALIGN); 12548c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 12558c2ecf20Sopenharmony_ci VT1724_BUFFER_ALIGN); 12568c2ecf20Sopenharmony_ci constrain_rate_if_locked(substream); 12578c2ecf20Sopenharmony_ci if (ice->spdif.ops.open) 12588c2ecf20Sopenharmony_ci ice->spdif.ops.open(ice, substream); 12598c2ecf20Sopenharmony_ci return 0; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_cistatic int snd_vt1724_capture_spdif_close(struct snd_pcm_substream *substream) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (PRO_RATE_RESET) 12678c2ecf20Sopenharmony_ci snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0); 12688c2ecf20Sopenharmony_ci ice->capture_con_substream = NULL; 12698c2ecf20Sopenharmony_ci if (ice->spdif.ops.close) 12708c2ecf20Sopenharmony_ci ice->spdif.ops.close(ice, substream); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci return 0; 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_vt1724_playback_spdif_ops = { 12768c2ecf20Sopenharmony_ci .open = snd_vt1724_playback_spdif_open, 12778c2ecf20Sopenharmony_ci .close = snd_vt1724_playback_spdif_close, 12788c2ecf20Sopenharmony_ci .hw_params = snd_vt1724_pcm_hw_params, 12798c2ecf20Sopenharmony_ci .hw_free = snd_vt1724_pcm_hw_free, 12808c2ecf20Sopenharmony_ci .prepare = snd_vt1724_playback_spdif_prepare, 12818c2ecf20Sopenharmony_ci .trigger = snd_vt1724_pcm_trigger, 12828c2ecf20Sopenharmony_ci .pointer = snd_vt1724_pcm_pointer, 12838c2ecf20Sopenharmony_ci}; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_vt1724_capture_spdif_ops = { 12868c2ecf20Sopenharmony_ci .open = snd_vt1724_capture_spdif_open, 12878c2ecf20Sopenharmony_ci .close = snd_vt1724_capture_spdif_close, 12888c2ecf20Sopenharmony_ci .hw_params = snd_vt1724_pcm_hw_params, 12898c2ecf20Sopenharmony_ci .hw_free = snd_vt1724_pcm_hw_free, 12908c2ecf20Sopenharmony_ci .prepare = snd_vt1724_pcm_prepare, 12918c2ecf20Sopenharmony_ci .trigger = snd_vt1724_pcm_trigger, 12928c2ecf20Sopenharmony_ci .pointer = snd_vt1724_pcm_pointer, 12938c2ecf20Sopenharmony_ci}; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic int snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci char *name; 12998c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 13008c2ecf20Sopenharmony_ci int play, capt; 13018c2ecf20Sopenharmony_ci int err; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (ice->force_pdma4 || 13048c2ecf20Sopenharmony_ci (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_OUT_INT)) { 13058c2ecf20Sopenharmony_ci play = 1; 13068c2ecf20Sopenharmony_ci ice->has_spdif = 1; 13078c2ecf20Sopenharmony_ci } else 13088c2ecf20Sopenharmony_ci play = 0; 13098c2ecf20Sopenharmony_ci if (ice->force_rdma1 || 13108c2ecf20Sopenharmony_ci (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_IN)) { 13118c2ecf20Sopenharmony_ci capt = 1; 13128c2ecf20Sopenharmony_ci ice->has_spdif = 1; 13138c2ecf20Sopenharmony_ci } else 13148c2ecf20Sopenharmony_ci capt = 0; 13158c2ecf20Sopenharmony_ci if (!play && !capt) 13168c2ecf20Sopenharmony_ci return 0; /* no spdif device */ 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci if (ice->force_pdma4 || ice->force_rdma1) 13198c2ecf20Sopenharmony_ci name = "ICE1724 Secondary"; 13208c2ecf20Sopenharmony_ci else 13218c2ecf20Sopenharmony_ci name = "ICE1724 IEC958"; 13228c2ecf20Sopenharmony_ci err = snd_pcm_new(ice->card, name, device, play, capt, &pcm); 13238c2ecf20Sopenharmony_ci if (err < 0) 13248c2ecf20Sopenharmony_ci return err; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (play) 13278c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 13288c2ecf20Sopenharmony_ci &snd_vt1724_playback_spdif_ops); 13298c2ecf20Sopenharmony_ci if (capt) 13308c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 13318c2ecf20Sopenharmony_ci &snd_vt1724_capture_spdif_ops); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci pcm->private_data = ice; 13348c2ecf20Sopenharmony_ci pcm->info_flags = 0; 13358c2ecf20Sopenharmony_ci strcpy(pcm->name, name); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 13388c2ecf20Sopenharmony_ci &ice->pci->dev, 256*1024, 256*1024); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci ice->pcm = pcm; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci return 0; 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci/* 13478c2ecf20Sopenharmony_ci * independent surround PCMs 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic const struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { 13518c2ecf20Sopenharmony_ci { 13528c2ecf20Sopenharmony_ci .addr = VT1724_MT_PDMA1_ADDR, 13538c2ecf20Sopenharmony_ci .size = VT1724_MT_PDMA1_SIZE, 13548c2ecf20Sopenharmony_ci .count = VT1724_MT_PDMA1_COUNT, 13558c2ecf20Sopenharmony_ci .start = VT1724_PDMA1_START, 13568c2ecf20Sopenharmony_ci }, 13578c2ecf20Sopenharmony_ci { 13588c2ecf20Sopenharmony_ci .addr = VT1724_MT_PDMA2_ADDR, 13598c2ecf20Sopenharmony_ci .size = VT1724_MT_PDMA2_SIZE, 13608c2ecf20Sopenharmony_ci .count = VT1724_MT_PDMA2_COUNT, 13618c2ecf20Sopenharmony_ci .start = VT1724_PDMA2_START, 13628c2ecf20Sopenharmony_ci }, 13638c2ecf20Sopenharmony_ci { 13648c2ecf20Sopenharmony_ci .addr = VT1724_MT_PDMA3_ADDR, 13658c2ecf20Sopenharmony_ci .size = VT1724_MT_PDMA3_SIZE, 13668c2ecf20Sopenharmony_ci .count = VT1724_MT_PDMA3_COUNT, 13678c2ecf20Sopenharmony_ci .start = VT1724_PDMA3_START, 13688c2ecf20Sopenharmony_ci }, 13698c2ecf20Sopenharmony_ci}; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_indep_prepare(struct snd_pcm_substream *substream) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 13748c2ecf20Sopenharmony_ci unsigned char val; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 13778c2ecf20Sopenharmony_ci val = 3 - substream->number; 13788c2ecf20Sopenharmony_ci if (inb(ICEMT1724(ice, BURST)) < val) 13798c2ecf20Sopenharmony_ci outb(val, ICEMT1724(ice, BURST)); 13808c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 13818c2ecf20Sopenharmony_ci return snd_vt1724_pcm_prepare(substream); 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 13878c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci mutex_lock(&ice->open_mutex); 13908c2ecf20Sopenharmony_ci /* already used by PDMA0? */ 13918c2ecf20Sopenharmony_ci if (ice->pcm_reserved[substream->number]) { 13928c2ecf20Sopenharmony_ci mutex_unlock(&ice->open_mutex); 13938c2ecf20Sopenharmony_ci return -EBUSY; /* FIXME: should handle blocking mode properly */ 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci mutex_unlock(&ice->open_mutex); 13968c2ecf20Sopenharmony_ci runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number]; 13978c2ecf20Sopenharmony_ci ice->playback_con_substream_ds[substream->number] = substream; 13988c2ecf20Sopenharmony_ci runtime->hw = snd_vt1724_2ch_stereo; 13998c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 14008c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 14018c2ecf20Sopenharmony_ci set_rate_constraints(ice, substream); 14028c2ecf20Sopenharmony_ci return 0; 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_cistatic int snd_vt1724_playback_indep_close(struct snd_pcm_substream *substream) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (PRO_RATE_RESET) 14108c2ecf20Sopenharmony_ci snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0); 14118c2ecf20Sopenharmony_ci ice->playback_con_substream_ds[substream->number] = NULL; 14128c2ecf20Sopenharmony_ci ice->pcm_reserved[substream->number] = NULL; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci return 0; 14158c2ecf20Sopenharmony_ci} 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_vt1724_playback_indep_ops = { 14188c2ecf20Sopenharmony_ci .open = snd_vt1724_playback_indep_open, 14198c2ecf20Sopenharmony_ci .close = snd_vt1724_playback_indep_close, 14208c2ecf20Sopenharmony_ci .hw_params = snd_vt1724_pcm_hw_params, 14218c2ecf20Sopenharmony_ci .hw_free = snd_vt1724_pcm_hw_free, 14228c2ecf20Sopenharmony_ci .prepare = snd_vt1724_playback_indep_prepare, 14238c2ecf20Sopenharmony_ci .trigger = snd_vt1724_pcm_trigger, 14248c2ecf20Sopenharmony_ci .pointer = snd_vt1724_pcm_pointer, 14258c2ecf20Sopenharmony_ci}; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_cistatic int snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 14318c2ecf20Sopenharmony_ci int play; 14328c2ecf20Sopenharmony_ci int err; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci play = ice->num_total_dacs / 2 - 1; 14358c2ecf20Sopenharmony_ci if (play <= 0) 14368c2ecf20Sopenharmony_ci return 0; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci err = snd_pcm_new(ice->card, "ICE1724 Surrounds", device, play, 0, &pcm); 14398c2ecf20Sopenharmony_ci if (err < 0) 14408c2ecf20Sopenharmony_ci return err; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 14438c2ecf20Sopenharmony_ci &snd_vt1724_playback_indep_ops); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci pcm->private_data = ice; 14468c2ecf20Sopenharmony_ci pcm->info_flags = 0; 14478c2ecf20Sopenharmony_ci strcpy(pcm->name, "ICE1724 Surround PCM"); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 14508c2ecf20Sopenharmony_ci &ice->pci->dev, 256*1024, 256*1024); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci ice->pcm_ds = pcm; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci return 0; 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci/* 14598c2ecf20Sopenharmony_ci * Mixer section 14608c2ecf20Sopenharmony_ci */ 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cistatic int snd_vt1724_ac97_mixer(struct snd_ice1712 *ice) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci int err; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (!(ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) { 14678c2ecf20Sopenharmony_ci struct snd_ac97_bus *pbus; 14688c2ecf20Sopenharmony_ci struct snd_ac97_template ac97; 14698c2ecf20Sopenharmony_ci static const struct snd_ac97_bus_ops ops = { 14708c2ecf20Sopenharmony_ci .write = snd_vt1724_ac97_write, 14718c2ecf20Sopenharmony_ci .read = snd_vt1724_ac97_read, 14728c2ecf20Sopenharmony_ci }; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci /* cold reset */ 14758c2ecf20Sopenharmony_ci outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); 14768c2ecf20Sopenharmony_ci mdelay(5); /* FIXME */ 14778c2ecf20Sopenharmony_ci outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci err = snd_ac97_bus(ice->card, 0, &ops, NULL, &pbus); 14808c2ecf20Sopenharmony_ci if (err < 0) 14818c2ecf20Sopenharmony_ci return err; 14828c2ecf20Sopenharmony_ci memset(&ac97, 0, sizeof(ac97)); 14838c2ecf20Sopenharmony_ci ac97.private_data = ice; 14848c2ecf20Sopenharmony_ci err = snd_ac97_mixer(pbus, &ac97, &ice->ac97); 14858c2ecf20Sopenharmony_ci if (err < 0) 14868c2ecf20Sopenharmony_ci dev_warn(ice->card->dev, 14878c2ecf20Sopenharmony_ci "cannot initialize pro ac97, skipped\n"); 14888c2ecf20Sopenharmony_ci else 14898c2ecf20Sopenharmony_ci return 0; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci /* I2S mixer only */ 14928c2ecf20Sopenharmony_ci strcat(ice->card->mixername, "ICE1724 - multitrack"); 14938c2ecf20Sopenharmony_ci return 0; 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci/* 14978c2ecf20Sopenharmony_ci * 14988c2ecf20Sopenharmony_ci */ 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_cistatic inline unsigned int eeprom_triple(struct snd_ice1712 *ice, int idx) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci return (unsigned int)ice->eeprom.data[idx] | \ 15038c2ecf20Sopenharmony_ci ((unsigned int)ice->eeprom.data[idx + 1] << 8) | \ 15048c2ecf20Sopenharmony_ci ((unsigned int)ice->eeprom.data[idx + 2] << 16); 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic void snd_vt1724_proc_read(struct snd_info_entry *entry, 15088c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 15098c2ecf20Sopenharmony_ci{ 15108c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 15118c2ecf20Sopenharmony_ci unsigned int idx; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%s\n\n", ice->card->longname); 15148c2ecf20Sopenharmony_ci snd_iprintf(buffer, "EEPROM:\n"); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Subvendor : 0x%x\n", ice->eeprom.subvendor); 15178c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Size : %i bytes\n", ice->eeprom.size); 15188c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Version : %i\n", ice->eeprom.version); 15198c2ecf20Sopenharmony_ci snd_iprintf(buffer, " System Config : 0x%x\n", 15208c2ecf20Sopenharmony_ci ice->eeprom.data[ICE_EEP2_SYSCONF]); 15218c2ecf20Sopenharmony_ci snd_iprintf(buffer, " ACLink : 0x%x\n", 15228c2ecf20Sopenharmony_ci ice->eeprom.data[ICE_EEP2_ACLINK]); 15238c2ecf20Sopenharmony_ci snd_iprintf(buffer, " I2S : 0x%x\n", 15248c2ecf20Sopenharmony_ci ice->eeprom.data[ICE_EEP2_I2S]); 15258c2ecf20Sopenharmony_ci snd_iprintf(buffer, " S/PDIF : 0x%x\n", 15268c2ecf20Sopenharmony_ci ice->eeprom.data[ICE_EEP2_SPDIF]); 15278c2ecf20Sopenharmony_ci snd_iprintf(buffer, " GPIO direction : 0x%x\n", 15288c2ecf20Sopenharmony_ci ice->eeprom.gpiodir); 15298c2ecf20Sopenharmony_ci snd_iprintf(buffer, " GPIO mask : 0x%x\n", 15308c2ecf20Sopenharmony_ci ice->eeprom.gpiomask); 15318c2ecf20Sopenharmony_ci snd_iprintf(buffer, " GPIO state : 0x%x\n", 15328c2ecf20Sopenharmony_ci ice->eeprom.gpiostate); 15338c2ecf20Sopenharmony_ci for (idx = 0x12; idx < ice->eeprom.size; idx++) 15348c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Extra #%02i : 0x%x\n", 15358c2ecf20Sopenharmony_ci idx, ice->eeprom.data[idx]); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\nRegisters:\n"); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci snd_iprintf(buffer, " PSDOUT03 : 0x%08x\n", 15408c2ecf20Sopenharmony_ci (unsigned)inl(ICEMT1724(ice, ROUTE_PLAYBACK))); 15418c2ecf20Sopenharmony_ci for (idx = 0x0; idx < 0x20 ; idx++) 15428c2ecf20Sopenharmony_ci snd_iprintf(buffer, " CCS%02x : 0x%02x\n", 15438c2ecf20Sopenharmony_ci idx, inb(ice->port+idx)); 15448c2ecf20Sopenharmony_ci for (idx = 0x0; idx < 0x30 ; idx++) 15458c2ecf20Sopenharmony_ci snd_iprintf(buffer, " MT%02x : 0x%02x\n", 15468c2ecf20Sopenharmony_ci idx, inb(ice->profi_port+idx)); 15478c2ecf20Sopenharmony_ci} 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_cistatic void snd_vt1724_proc_init(struct snd_ice1712 *ice) 15508c2ecf20Sopenharmony_ci{ 15518c2ecf20Sopenharmony_ci snd_card_ro_proc_new(ice->card, "ice1724", ice, snd_vt1724_proc_read); 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci/* 15558c2ecf20Sopenharmony_ci * 15568c2ecf20Sopenharmony_ci */ 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic int snd_vt1724_eeprom_info(struct snd_kcontrol *kcontrol, 15598c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 15608c2ecf20Sopenharmony_ci{ 15618c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 15628c2ecf20Sopenharmony_ci uinfo->count = sizeof(struct snd_ice1712_eeprom); 15638c2ecf20Sopenharmony_ci return 0; 15648c2ecf20Sopenharmony_ci} 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_cistatic int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol, 15678c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom)); 15728c2ecf20Sopenharmony_ci return 0; 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_eeprom = { 15768c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 15778c2ecf20Sopenharmony_ci .name = "ICE1724 EEPROM", 15788c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 15798c2ecf20Sopenharmony_ci .info = snd_vt1724_eeprom_info, 15808c2ecf20Sopenharmony_ci .get = snd_vt1724_eeprom_get 15818c2ecf20Sopenharmony_ci}; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci/* 15848c2ecf20Sopenharmony_ci */ 15858c2ecf20Sopenharmony_cistatic int snd_vt1724_spdif_info(struct snd_kcontrol *kcontrol, 15868c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 15878c2ecf20Sopenharmony_ci{ 15888c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 15898c2ecf20Sopenharmony_ci uinfo->count = 1; 15908c2ecf20Sopenharmony_ci return 0; 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_cistatic unsigned int encode_spdif_bits(struct snd_aes_iec958 *diga) 15948c2ecf20Sopenharmony_ci{ 15958c2ecf20Sopenharmony_ci unsigned int val, rbits; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci val = diga->status[0] & 0x03; /* professional, non-audio */ 15988c2ecf20Sopenharmony_ci if (val & 0x01) { 15998c2ecf20Sopenharmony_ci /* professional */ 16008c2ecf20Sopenharmony_ci if ((diga->status[0] & IEC958_AES0_PRO_EMPHASIS) == 16018c2ecf20Sopenharmony_ci IEC958_AES0_PRO_EMPHASIS_5015) 16028c2ecf20Sopenharmony_ci val |= 1U << 3; 16038c2ecf20Sopenharmony_ci rbits = (diga->status[4] >> 3) & 0x0f; 16048c2ecf20Sopenharmony_ci if (rbits) { 16058c2ecf20Sopenharmony_ci switch (rbits) { 16068c2ecf20Sopenharmony_ci case 2: val |= 5 << 12; break; /* 96k */ 16078c2ecf20Sopenharmony_ci case 3: val |= 6 << 12; break; /* 192k */ 16088c2ecf20Sopenharmony_ci case 10: val |= 4 << 12; break; /* 88.2k */ 16098c2ecf20Sopenharmony_ci case 11: val |= 7 << 12; break; /* 176.4k */ 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci } else { 16128c2ecf20Sopenharmony_ci switch (diga->status[0] & IEC958_AES0_PRO_FS) { 16138c2ecf20Sopenharmony_ci case IEC958_AES0_PRO_FS_44100: 16148c2ecf20Sopenharmony_ci break; 16158c2ecf20Sopenharmony_ci case IEC958_AES0_PRO_FS_32000: 16168c2ecf20Sopenharmony_ci val |= 3U << 12; 16178c2ecf20Sopenharmony_ci break; 16188c2ecf20Sopenharmony_ci default: 16198c2ecf20Sopenharmony_ci val |= 2U << 12; 16208c2ecf20Sopenharmony_ci break; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci } else { 16248c2ecf20Sopenharmony_ci /* consumer */ 16258c2ecf20Sopenharmony_ci val |= diga->status[1] & 0x04; /* copyright */ 16268c2ecf20Sopenharmony_ci if ((diga->status[0] & IEC958_AES0_CON_EMPHASIS) == 16278c2ecf20Sopenharmony_ci IEC958_AES0_CON_EMPHASIS_5015) 16288c2ecf20Sopenharmony_ci val |= 1U << 3; 16298c2ecf20Sopenharmony_ci val |= (unsigned int)(diga->status[1] & 0x3f) << 4; /* category */ 16308c2ecf20Sopenharmony_ci val |= (unsigned int)(diga->status[3] & IEC958_AES3_CON_FS) << 12; /* fs */ 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci return val; 16338c2ecf20Sopenharmony_ci} 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_cistatic void decode_spdif_bits(struct snd_aes_iec958 *diga, unsigned int val) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci memset(diga->status, 0, sizeof(diga->status)); 16388c2ecf20Sopenharmony_ci diga->status[0] = val & 0x03; /* professional, non-audio */ 16398c2ecf20Sopenharmony_ci if (val & 0x01) { 16408c2ecf20Sopenharmony_ci /* professional */ 16418c2ecf20Sopenharmony_ci if (val & (1U << 3)) 16428c2ecf20Sopenharmony_ci diga->status[0] |= IEC958_AES0_PRO_EMPHASIS_5015; 16438c2ecf20Sopenharmony_ci switch ((val >> 12) & 0x7) { 16448c2ecf20Sopenharmony_ci case 0: 16458c2ecf20Sopenharmony_ci break; 16468c2ecf20Sopenharmony_ci case 2: 16478c2ecf20Sopenharmony_ci diga->status[0] |= IEC958_AES0_PRO_FS_32000; 16488c2ecf20Sopenharmony_ci break; 16498c2ecf20Sopenharmony_ci default: 16508c2ecf20Sopenharmony_ci diga->status[0] |= IEC958_AES0_PRO_FS_48000; 16518c2ecf20Sopenharmony_ci break; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci } else { 16548c2ecf20Sopenharmony_ci /* consumer */ 16558c2ecf20Sopenharmony_ci diga->status[0] |= val & (1U << 2); /* copyright */ 16568c2ecf20Sopenharmony_ci if (val & (1U << 3)) 16578c2ecf20Sopenharmony_ci diga->status[0] |= IEC958_AES0_CON_EMPHASIS_5015; 16588c2ecf20Sopenharmony_ci diga->status[1] |= (val >> 4) & 0x3f; /* category */ 16598c2ecf20Sopenharmony_ci diga->status[3] |= (val >> 12) & 0x07; /* fs */ 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic int snd_vt1724_spdif_default_get(struct snd_kcontrol *kcontrol, 16648c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 16678c2ecf20Sopenharmony_ci unsigned int val; 16688c2ecf20Sopenharmony_ci val = inw(ICEMT1724(ice, SPDIF_CTRL)); 16698c2ecf20Sopenharmony_ci decode_spdif_bits(&ucontrol->value.iec958, val); 16708c2ecf20Sopenharmony_ci return 0; 16718c2ecf20Sopenharmony_ci} 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_cistatic int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol, 16748c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 16758c2ecf20Sopenharmony_ci{ 16768c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 16778c2ecf20Sopenharmony_ci unsigned int val, old; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci val = encode_spdif_bits(&ucontrol->value.iec958); 16808c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 16818c2ecf20Sopenharmony_ci old = inw(ICEMT1724(ice, SPDIF_CTRL)); 16828c2ecf20Sopenharmony_ci if (val != old) 16838c2ecf20Sopenharmony_ci update_spdif_bits(ice, val); 16848c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 16858c2ecf20Sopenharmony_ci return val != old; 16868c2ecf20Sopenharmony_ci} 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_spdif_default = 16898c2ecf20Sopenharmony_ci{ 16908c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 16918c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 16928c2ecf20Sopenharmony_ci .info = snd_vt1724_spdif_info, 16938c2ecf20Sopenharmony_ci .get = snd_vt1724_spdif_default_get, 16948c2ecf20Sopenharmony_ci .put = snd_vt1724_spdif_default_put 16958c2ecf20Sopenharmony_ci}; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_cistatic int snd_vt1724_spdif_maskc_get(struct snd_kcontrol *kcontrol, 16988c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO | 17018c2ecf20Sopenharmony_ci IEC958_AES0_PROFESSIONAL | 17028c2ecf20Sopenharmony_ci IEC958_AES0_CON_NOT_COPYRIGHT | 17038c2ecf20Sopenharmony_ci IEC958_AES0_CON_EMPHASIS; 17048c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL | 17058c2ecf20Sopenharmony_ci IEC958_AES1_CON_CATEGORY; 17068c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS; 17078c2ecf20Sopenharmony_ci return 0; 17088c2ecf20Sopenharmony_ci} 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_cistatic int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol, 17118c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO | 17148c2ecf20Sopenharmony_ci IEC958_AES0_PROFESSIONAL | 17158c2ecf20Sopenharmony_ci IEC958_AES0_PRO_FS | 17168c2ecf20Sopenharmony_ci IEC958_AES0_PRO_EMPHASIS; 17178c2ecf20Sopenharmony_ci return 0; 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_spdif_maskc = 17218c2ecf20Sopenharmony_ci{ 17228c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 17238c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 17248c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), 17258c2ecf20Sopenharmony_ci .info = snd_vt1724_spdif_info, 17268c2ecf20Sopenharmony_ci .get = snd_vt1724_spdif_maskc_get, 17278c2ecf20Sopenharmony_ci}; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_spdif_maskp = 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 17328c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 17338c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK), 17348c2ecf20Sopenharmony_ci .info = snd_vt1724_spdif_info, 17358c2ecf20Sopenharmony_ci .get = snd_vt1724_spdif_maskp_get, 17368c2ecf20Sopenharmony_ci}; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci#define snd_vt1724_spdif_sw_info snd_ctl_boolean_mono_info 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_cistatic int snd_vt1724_spdif_sw_get(struct snd_kcontrol *kcontrol, 17418c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17428c2ecf20Sopenharmony_ci{ 17438c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 17448c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = inb(ICEREG1724(ice, SPDIF_CFG)) & 17458c2ecf20Sopenharmony_ci VT1724_CFG_SPDIF_OUT_EN ? 1 : 0; 17468c2ecf20Sopenharmony_ci return 0; 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol, 17508c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17518c2ecf20Sopenharmony_ci{ 17528c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 17538c2ecf20Sopenharmony_ci unsigned char old, val; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 17568c2ecf20Sopenharmony_ci old = val = inb(ICEREG1724(ice, SPDIF_CFG)); 17578c2ecf20Sopenharmony_ci val &= ~VT1724_CFG_SPDIF_OUT_EN; 17588c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0]) 17598c2ecf20Sopenharmony_ci val |= VT1724_CFG_SPDIF_OUT_EN; 17608c2ecf20Sopenharmony_ci if (old != val) 17618c2ecf20Sopenharmony_ci outb(val, ICEREG1724(ice, SPDIF_CFG)); 17628c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 17638c2ecf20Sopenharmony_ci return old != val; 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_spdif_switch = 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 17698c2ecf20Sopenharmony_ci /* FIXME: the following conflict with IEC958 Playback Route */ 17708c2ecf20Sopenharmony_ci /* .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), */ 17718c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("Output ", NONE, SWITCH), 17728c2ecf20Sopenharmony_ci .info = snd_vt1724_spdif_sw_info, 17738c2ecf20Sopenharmony_ci .get = snd_vt1724_spdif_sw_get, 17748c2ecf20Sopenharmony_ci .put = snd_vt1724_spdif_sw_put 17758c2ecf20Sopenharmony_ci}; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci#if 0 /* NOT USED YET */ 17798c2ecf20Sopenharmony_ci/* 17808c2ecf20Sopenharmony_ci * GPIO access from extern 17818c2ecf20Sopenharmony_ci */ 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci#define snd_vt1724_gpio_info snd_ctl_boolean_mono_info 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ciint snd_vt1724_gpio_get(struct snd_kcontrol *kcontrol, 17868c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 17898c2ecf20Sopenharmony_ci int shift = kcontrol->private_value & 0xff; 17908c2ecf20Sopenharmony_ci int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 17938c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 17948c2ecf20Sopenharmony_ci (snd_ice1712_gpio_read(ice) & (1 << shift) ? 1 : 0) ^ invert; 17958c2ecf20Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 17968c2ecf20Sopenharmony_ci return 0; 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ciint snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol, 18008c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 18018c2ecf20Sopenharmony_ci{ 18028c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 18038c2ecf20Sopenharmony_ci int shift = kcontrol->private_value & 0xff; 18048c2ecf20Sopenharmony_ci int invert = (kcontrol->private_value & (1<<24)) ? mask : 0; 18058c2ecf20Sopenharmony_ci unsigned int val, nval; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci if (kcontrol->private_value & (1 << 31)) 18088c2ecf20Sopenharmony_ci return -EPERM; 18098c2ecf20Sopenharmony_ci nval = (ucontrol->value.integer.value[0] ? (1 << shift) : 0) ^ invert; 18108c2ecf20Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 18118c2ecf20Sopenharmony_ci val = snd_ice1712_gpio_read(ice); 18128c2ecf20Sopenharmony_ci nval |= val & ~(1 << shift); 18138c2ecf20Sopenharmony_ci if (val != nval) 18148c2ecf20Sopenharmony_ci snd_ice1712_gpio_write(ice, nval); 18158c2ecf20Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 18168c2ecf20Sopenharmony_ci return val != nval; 18178c2ecf20Sopenharmony_ci} 18188c2ecf20Sopenharmony_ci#endif /* NOT USED YET */ 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci/* 18218c2ecf20Sopenharmony_ci * rate 18228c2ecf20Sopenharmony_ci */ 18238c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol, 18248c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 18278c2ecf20Sopenharmony_ci int hw_rates_count = ice->hw_rates->count; 18288c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 18298c2ecf20Sopenharmony_ci uinfo->count = 1; 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci /* internal clocks */ 18328c2ecf20Sopenharmony_ci uinfo->value.enumerated.items = hw_rates_count; 18338c2ecf20Sopenharmony_ci /* external clocks */ 18348c2ecf20Sopenharmony_ci if (ice->force_rdma1 || 18358c2ecf20Sopenharmony_ci (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_IN)) 18368c2ecf20Sopenharmony_ci uinfo->value.enumerated.items += ice->ext_clock_count; 18378c2ecf20Sopenharmony_ci /* upper limit - keep at top */ 18388c2ecf20Sopenharmony_ci if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 18398c2ecf20Sopenharmony_ci uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 18408c2ecf20Sopenharmony_ci if (uinfo->value.enumerated.item >= hw_rates_count) 18418c2ecf20Sopenharmony_ci /* ext_clock items */ 18428c2ecf20Sopenharmony_ci strcpy(uinfo->value.enumerated.name, 18438c2ecf20Sopenharmony_ci ice->ext_clock_names[ 18448c2ecf20Sopenharmony_ci uinfo->value.enumerated.item - hw_rates_count]); 18458c2ecf20Sopenharmony_ci else 18468c2ecf20Sopenharmony_ci /* int clock items */ 18478c2ecf20Sopenharmony_ci sprintf(uinfo->value.enumerated.name, "%d", 18488c2ecf20Sopenharmony_ci ice->hw_rates->list[uinfo->value.enumerated.item]); 18498c2ecf20Sopenharmony_ci return 0; 18508c2ecf20Sopenharmony_ci} 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol, 18538c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 18548c2ecf20Sopenharmony_ci{ 18558c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 18568c2ecf20Sopenharmony_ci unsigned int i, rate; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 18598c2ecf20Sopenharmony_ci if (ice->is_spdif_master(ice)) { 18608c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = ice->hw_rates->count + 18618c2ecf20Sopenharmony_ci ice->get_spdif_master_type(ice); 18628c2ecf20Sopenharmony_ci } else { 18638c2ecf20Sopenharmony_ci rate = ice->get_rate(ice); 18648c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 0; 18658c2ecf20Sopenharmony_ci for (i = 0; i < ice->hw_rates->count; i++) { 18668c2ecf20Sopenharmony_ci if (ice->hw_rates->list[i] == rate) { 18678c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = i; 18688c2ecf20Sopenharmony_ci break; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 18738c2ecf20Sopenharmony_ci return 0; 18748c2ecf20Sopenharmony_ci} 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_cistatic int stdclock_get_spdif_master_type(struct snd_ice1712 *ice) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci /* standard external clock - only single type - SPDIF IN */ 18798c2ecf20Sopenharmony_ci return 0; 18808c2ecf20Sopenharmony_ci} 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci/* setting clock to external - SPDIF */ 18838c2ecf20Sopenharmony_cistatic int stdclock_set_spdif_clock(struct snd_ice1712 *ice, int type) 18848c2ecf20Sopenharmony_ci{ 18858c2ecf20Sopenharmony_ci unsigned char oval; 18868c2ecf20Sopenharmony_ci unsigned char i2s_oval; 18878c2ecf20Sopenharmony_ci oval = inb(ICEMT1724(ice, RATE)); 18888c2ecf20Sopenharmony_ci outb(oval | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); 18898c2ecf20Sopenharmony_ci /* setting 256fs */ 18908c2ecf20Sopenharmony_ci i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT)); 18918c2ecf20Sopenharmony_ci outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X, ICEMT1724(ice, I2S_FORMAT)); 18928c2ecf20Sopenharmony_ci return 0; 18938c2ecf20Sopenharmony_ci} 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, 18978c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 19008c2ecf20Sopenharmony_ci unsigned int old_rate, new_rate; 19018c2ecf20Sopenharmony_ci unsigned int item = ucontrol->value.enumerated.item[0]; 19028c2ecf20Sopenharmony_ci unsigned int first_ext_clock = ice->hw_rates->count; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (item > first_ext_clock + ice->ext_clock_count - 1) 19058c2ecf20Sopenharmony_ci return -EINVAL; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci /* if rate = 0 => external clock */ 19088c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 19098c2ecf20Sopenharmony_ci if (ice->is_spdif_master(ice)) 19108c2ecf20Sopenharmony_ci old_rate = 0; 19118c2ecf20Sopenharmony_ci else 19128c2ecf20Sopenharmony_ci old_rate = ice->get_rate(ice); 19138c2ecf20Sopenharmony_ci if (item >= first_ext_clock) { 19148c2ecf20Sopenharmony_ci /* switching to external clock */ 19158c2ecf20Sopenharmony_ci ice->set_spdif_clock(ice, item - first_ext_clock); 19168c2ecf20Sopenharmony_ci new_rate = 0; 19178c2ecf20Sopenharmony_ci } else { 19188c2ecf20Sopenharmony_ci /* internal on-card clock */ 19198c2ecf20Sopenharmony_ci new_rate = ice->hw_rates->list[item]; 19208c2ecf20Sopenharmony_ci ice->pro_rate_default = new_rate; 19218c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 19228c2ecf20Sopenharmony_ci snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1); 19238c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci /* the first switch to the ext. clock mode? */ 19288c2ecf20Sopenharmony_ci if (old_rate != new_rate && !new_rate) { 19298c2ecf20Sopenharmony_ci /* notify akm chips as well */ 19308c2ecf20Sopenharmony_ci unsigned int i; 19318c2ecf20Sopenharmony_ci if (ice->gpio.set_pro_rate) 19328c2ecf20Sopenharmony_ci ice->gpio.set_pro_rate(ice, 0); 19338c2ecf20Sopenharmony_ci for (i = 0; i < ice->akm_codecs; i++) { 19348c2ecf20Sopenharmony_ci if (ice->akm[i].ops.set_rate_val) 19358c2ecf20Sopenharmony_ci ice->akm[i].ops.set_rate_val(&ice->akm[i], 0); 19368c2ecf20Sopenharmony_ci } 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci return old_rate != new_rate; 19398c2ecf20Sopenharmony_ci} 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_pro_internal_clock = { 19428c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 19438c2ecf20Sopenharmony_ci .name = "Multi Track Internal Clock", 19448c2ecf20Sopenharmony_ci .info = snd_vt1724_pro_internal_clock_info, 19458c2ecf20Sopenharmony_ci .get = snd_vt1724_pro_internal_clock_get, 19468c2ecf20Sopenharmony_ci .put = snd_vt1724_pro_internal_clock_put 19478c2ecf20Sopenharmony_ci}; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci#define snd_vt1724_pro_rate_locking_info snd_ctl_boolean_mono_info 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_rate_locking_get(struct snd_kcontrol *kcontrol, 19528c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 19538c2ecf20Sopenharmony_ci{ 19548c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = PRO_RATE_LOCKED; 19558c2ecf20Sopenharmony_ci return 0; 19568c2ecf20Sopenharmony_ci} 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol, 19598c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 19628c2ecf20Sopenharmony_ci int change = 0, nval; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci nval = ucontrol->value.integer.value[0] ? 1 : 0; 19658c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 19668c2ecf20Sopenharmony_ci change = PRO_RATE_LOCKED != nval; 19678c2ecf20Sopenharmony_ci PRO_RATE_LOCKED = nval; 19688c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 19698c2ecf20Sopenharmony_ci return change; 19708c2ecf20Sopenharmony_ci} 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_pro_rate_locking = { 19738c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 19748c2ecf20Sopenharmony_ci .name = "Multi Track Rate Locking", 19758c2ecf20Sopenharmony_ci .info = snd_vt1724_pro_rate_locking_info, 19768c2ecf20Sopenharmony_ci .get = snd_vt1724_pro_rate_locking_get, 19778c2ecf20Sopenharmony_ci .put = snd_vt1724_pro_rate_locking_put 19788c2ecf20Sopenharmony_ci}; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci#define snd_vt1724_pro_rate_reset_info snd_ctl_boolean_mono_info 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_rate_reset_get(struct snd_kcontrol *kcontrol, 19838c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 19848c2ecf20Sopenharmony_ci{ 19858c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = PRO_RATE_RESET ? 1 : 0; 19868c2ecf20Sopenharmony_ci return 0; 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol, 19908c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 19938c2ecf20Sopenharmony_ci int change = 0, nval; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci nval = ucontrol->value.integer.value[0] ? 1 : 0; 19968c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 19978c2ecf20Sopenharmony_ci change = PRO_RATE_RESET != nval; 19988c2ecf20Sopenharmony_ci PRO_RATE_RESET = nval; 19998c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 20008c2ecf20Sopenharmony_ci return change; 20018c2ecf20Sopenharmony_ci} 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_pro_rate_reset = { 20048c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 20058c2ecf20Sopenharmony_ci .name = "Multi Track Rate Reset", 20068c2ecf20Sopenharmony_ci .info = snd_vt1724_pro_rate_reset_info, 20078c2ecf20Sopenharmony_ci .get = snd_vt1724_pro_rate_reset_get, 20088c2ecf20Sopenharmony_ci .put = snd_vt1724_pro_rate_reset_put 20098c2ecf20Sopenharmony_ci}; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci/* 20138c2ecf20Sopenharmony_ci * routing 20148c2ecf20Sopenharmony_ci */ 20158c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_route_info(struct snd_kcontrol *kcontrol, 20168c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci static const char * const texts[] = { 20198c2ecf20Sopenharmony_ci "PCM Out", /* 0 */ 20208c2ecf20Sopenharmony_ci "H/W In 0", "H/W In 1", /* 1-2 */ 20218c2ecf20Sopenharmony_ci "IEC958 In L", "IEC958 In R", /* 3-4 */ 20228c2ecf20Sopenharmony_ci }; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 5, texts); 20258c2ecf20Sopenharmony_ci} 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_cistatic inline int analog_route_shift(int idx) 20288c2ecf20Sopenharmony_ci{ 20298c2ecf20Sopenharmony_ci return (idx % 2) * 12 + ((idx / 2) * 3) + 8; 20308c2ecf20Sopenharmony_ci} 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_cistatic inline int digital_route_shift(int idx) 20338c2ecf20Sopenharmony_ci{ 20348c2ecf20Sopenharmony_ci return idx * 3; 20358c2ecf20Sopenharmony_ci} 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ciint snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift) 20388c2ecf20Sopenharmony_ci{ 20398c2ecf20Sopenharmony_ci unsigned long val; 20408c2ecf20Sopenharmony_ci unsigned char eitem; 20418c2ecf20Sopenharmony_ci static const unsigned char xlate[8] = { 20428c2ecf20Sopenharmony_ci 0, 255, 1, 2, 255, 255, 3, 4, 20438c2ecf20Sopenharmony_ci }; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci val = inl(ICEMT1724(ice, ROUTE_PLAYBACK)); 20468c2ecf20Sopenharmony_ci val >>= shift; 20478c2ecf20Sopenharmony_ci val &= 7; /* we now have 3 bits per output */ 20488c2ecf20Sopenharmony_ci eitem = xlate[val]; 20498c2ecf20Sopenharmony_ci if (eitem == 255) { 20508c2ecf20Sopenharmony_ci snd_BUG(); 20518c2ecf20Sopenharmony_ci return 0; 20528c2ecf20Sopenharmony_ci } 20538c2ecf20Sopenharmony_ci return eitem; 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ciint snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val, 20578c2ecf20Sopenharmony_ci int shift) 20588c2ecf20Sopenharmony_ci{ 20598c2ecf20Sopenharmony_ci unsigned int old_val, nval; 20608c2ecf20Sopenharmony_ci int change; 20618c2ecf20Sopenharmony_ci static const unsigned char xroute[8] = { 20628c2ecf20Sopenharmony_ci 0, /* PCM */ 20638c2ecf20Sopenharmony_ci 2, /* PSDIN0 Left */ 20648c2ecf20Sopenharmony_ci 3, /* PSDIN0 Right */ 20658c2ecf20Sopenharmony_ci 6, /* SPDIN Left */ 20668c2ecf20Sopenharmony_ci 7, /* SPDIN Right */ 20678c2ecf20Sopenharmony_ci }; 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci nval = xroute[val % 5]; 20708c2ecf20Sopenharmony_ci val = old_val = inl(ICEMT1724(ice, ROUTE_PLAYBACK)); 20718c2ecf20Sopenharmony_ci val &= ~(0x07 << shift); 20728c2ecf20Sopenharmony_ci val |= nval << shift; 20738c2ecf20Sopenharmony_ci change = val != old_val; 20748c2ecf20Sopenharmony_ci if (change) 20758c2ecf20Sopenharmony_ci outl(val, ICEMT1724(ice, ROUTE_PLAYBACK)); 20768c2ecf20Sopenharmony_ci return change; 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_route_analog_get(struct snd_kcontrol *kcontrol, 20808c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 20818c2ecf20Sopenharmony_ci{ 20828c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 20838c2ecf20Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 20848c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 20858c2ecf20Sopenharmony_ci snd_ice1724_get_route_val(ice, analog_route_shift(idx)); 20868c2ecf20Sopenharmony_ci return 0; 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_route_analog_put(struct snd_kcontrol *kcontrol, 20908c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 20918c2ecf20Sopenharmony_ci{ 20928c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 20938c2ecf20Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 20948c2ecf20Sopenharmony_ci return snd_ice1724_put_route_val(ice, 20958c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0], 20968c2ecf20Sopenharmony_ci analog_route_shift(idx)); 20978c2ecf20Sopenharmony_ci} 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol, 21008c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 21018c2ecf20Sopenharmony_ci{ 21028c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 21038c2ecf20Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 21048c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 21058c2ecf20Sopenharmony_ci snd_ice1724_get_route_val(ice, digital_route_shift(idx)); 21068c2ecf20Sopenharmony_ci return 0; 21078c2ecf20Sopenharmony_ci} 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, 21108c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 21118c2ecf20Sopenharmony_ci{ 21128c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 21138c2ecf20Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 21148c2ecf20Sopenharmony_ci return snd_ice1724_put_route_val(ice, 21158c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0], 21168c2ecf20Sopenharmony_ci digital_route_shift(idx)); 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route = 21208c2ecf20Sopenharmony_ci{ 21218c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 21228c2ecf20Sopenharmony_ci .name = "H/W Playback Route", 21238c2ecf20Sopenharmony_ci .info = snd_vt1724_pro_route_info, 21248c2ecf20Sopenharmony_ci .get = snd_vt1724_pro_route_analog_get, 21258c2ecf20Sopenharmony_ci .put = snd_vt1724_pro_route_analog_put, 21268c2ecf20Sopenharmony_ci}; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route = { 21298c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 21308c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", 21318c2ecf20Sopenharmony_ci .info = snd_vt1724_pro_route_info, 21328c2ecf20Sopenharmony_ci .get = snd_vt1724_pro_route_spdif_get, 21338c2ecf20Sopenharmony_ci .put = snd_vt1724_pro_route_spdif_put, 21348c2ecf20Sopenharmony_ci .count = 2, 21358c2ecf20Sopenharmony_ci}; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_peak_info(struct snd_kcontrol *kcontrol, 21398c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 21408c2ecf20Sopenharmony_ci{ 21418c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 21428c2ecf20Sopenharmony_ci uinfo->count = 22; /* FIXME: for compatibility with ice1712... */ 21438c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 21448c2ecf20Sopenharmony_ci uinfo->value.integer.max = 255; 21458c2ecf20Sopenharmony_ci return 0; 21468c2ecf20Sopenharmony_ci} 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_cistatic int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol, 21498c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 21508c2ecf20Sopenharmony_ci{ 21518c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 21528c2ecf20Sopenharmony_ci int idx; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 21558c2ecf20Sopenharmony_ci for (idx = 0; idx < 22; idx++) { 21568c2ecf20Sopenharmony_ci outb(idx, ICEMT1724(ice, MONITOR_PEAKINDEX)); 21578c2ecf20Sopenharmony_ci ucontrol->value.integer.value[idx] = 21588c2ecf20Sopenharmony_ci inb(ICEMT1724(ice, MONITOR_PEAKDATA)); 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 21618c2ecf20Sopenharmony_ci return 0; 21628c2ecf20Sopenharmony_ci} 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_vt1724_mixer_pro_peak = { 21658c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 21668c2ecf20Sopenharmony_ci .name = "Multi Track Peak", 21678c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 21688c2ecf20Sopenharmony_ci .info = snd_vt1724_pro_peak_info, 21698c2ecf20Sopenharmony_ci .get = snd_vt1724_pro_peak_get 21708c2ecf20Sopenharmony_ci}; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci/* 21738c2ecf20Sopenharmony_ci * 21748c2ecf20Sopenharmony_ci */ 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_cistatic const struct snd_ice1712_card_info no_matched; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci/* 21808c2ecf20Sopenharmony_ci ooAoo cards with no controls 21818c2ecf20Sopenharmony_ci*/ 21828c2ecf20Sopenharmony_cistatic const unsigned char ooaoo_sq210_eeprom[] = { 21838c2ecf20Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x4c, /* 49MHz crystal, no mpu401, no ADC, 21848c2ecf20Sopenharmony_ci 1xDACs */ 21858c2ecf20Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 21868c2ecf20Sopenharmony_ci [ICE_EEP2_I2S] = 0x78, /* no volume, 96k, 24bit, 192k */ 21878c2ecf20Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc1, /* out-en, out-int, out-ext */ 21888c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0x00, /* no GPIOs are used */ 21898c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0x00, 21908c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x00, 21918c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0xff, 21928c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0xff, 21938c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0xff, 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, /* inputs */ 21968c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, /* all 1, but GPIO_CPLD_RW 21978c2ecf20Sopenharmony_ci and GPIO15 always zero */ 21988c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */ 21998c2ecf20Sopenharmony_ci}; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_cistatic const struct snd_ice1712_card_info snd_vt1724_ooaoo_cards[] = { 22038c2ecf20Sopenharmony_ci { 22048c2ecf20Sopenharmony_ci .name = "ooAoo SQ210a", 22058c2ecf20Sopenharmony_ci .model = "sq210a", 22068c2ecf20Sopenharmony_ci .eeprom_size = sizeof(ooaoo_sq210_eeprom), 22078c2ecf20Sopenharmony_ci .eeprom_data = ooaoo_sq210_eeprom, 22088c2ecf20Sopenharmony_ci }, 22098c2ecf20Sopenharmony_ci { } /* terminator */ 22108c2ecf20Sopenharmony_ci}; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_cistatic const struct snd_ice1712_card_info *card_tables[] = { 22138c2ecf20Sopenharmony_ci snd_vt1724_revo_cards, 22148c2ecf20Sopenharmony_ci snd_vt1724_amp_cards, 22158c2ecf20Sopenharmony_ci snd_vt1724_aureon_cards, 22168c2ecf20Sopenharmony_ci snd_vt1720_mobo_cards, 22178c2ecf20Sopenharmony_ci snd_vt1720_pontis_cards, 22188c2ecf20Sopenharmony_ci snd_vt1724_prodigy_hifi_cards, 22198c2ecf20Sopenharmony_ci snd_vt1724_prodigy192_cards, 22208c2ecf20Sopenharmony_ci snd_vt1724_juli_cards, 22218c2ecf20Sopenharmony_ci snd_vt1724_maya44_cards, 22228c2ecf20Sopenharmony_ci snd_vt1724_phase_cards, 22238c2ecf20Sopenharmony_ci snd_vt1724_wtm_cards, 22248c2ecf20Sopenharmony_ci snd_vt1724_se_cards, 22258c2ecf20Sopenharmony_ci snd_vt1724_qtet_cards, 22268c2ecf20Sopenharmony_ci snd_vt1724_ooaoo_cards, 22278c2ecf20Sopenharmony_ci snd_vt1724_psc724_cards, 22288c2ecf20Sopenharmony_ci NULL, 22298c2ecf20Sopenharmony_ci}; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci/* 22338c2ecf20Sopenharmony_ci */ 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_cistatic void wait_i2c_busy(struct snd_ice1712 *ice) 22368c2ecf20Sopenharmony_ci{ 22378c2ecf20Sopenharmony_ci int t = 0x10000; 22388c2ecf20Sopenharmony_ci while ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY) && t--) 22398c2ecf20Sopenharmony_ci ; 22408c2ecf20Sopenharmony_ci if (t == -1) 22418c2ecf20Sopenharmony_ci dev_err(ice->card->dev, "i2c busy timeout\n"); 22428c2ecf20Sopenharmony_ci} 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ciunsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, 22458c2ecf20Sopenharmony_ci unsigned char dev, unsigned char addr) 22468c2ecf20Sopenharmony_ci{ 22478c2ecf20Sopenharmony_ci unsigned char val; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci mutex_lock(&ice->i2c_mutex); 22508c2ecf20Sopenharmony_ci wait_i2c_busy(ice); 22518c2ecf20Sopenharmony_ci outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); 22528c2ecf20Sopenharmony_ci outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); 22538c2ecf20Sopenharmony_ci wait_i2c_busy(ice); 22548c2ecf20Sopenharmony_ci val = inb(ICEREG1724(ice, I2C_DATA)); 22558c2ecf20Sopenharmony_ci mutex_unlock(&ice->i2c_mutex); 22568c2ecf20Sopenharmony_ci /* 22578c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); 22588c2ecf20Sopenharmony_ci */ 22598c2ecf20Sopenharmony_ci return val; 22608c2ecf20Sopenharmony_ci} 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_civoid snd_vt1724_write_i2c(struct snd_ice1712 *ice, 22638c2ecf20Sopenharmony_ci unsigned char dev, unsigned char addr, unsigned char data) 22648c2ecf20Sopenharmony_ci{ 22658c2ecf20Sopenharmony_ci mutex_lock(&ice->i2c_mutex); 22668c2ecf20Sopenharmony_ci wait_i2c_busy(ice); 22678c2ecf20Sopenharmony_ci /* 22688c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); 22698c2ecf20Sopenharmony_ci */ 22708c2ecf20Sopenharmony_ci outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); 22718c2ecf20Sopenharmony_ci outb(data, ICEREG1724(ice, I2C_DATA)); 22728c2ecf20Sopenharmony_ci outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); 22738c2ecf20Sopenharmony_ci wait_i2c_busy(ice); 22748c2ecf20Sopenharmony_ci mutex_unlock(&ice->i2c_mutex); 22758c2ecf20Sopenharmony_ci} 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_cistatic int snd_vt1724_read_eeprom(struct snd_ice1712 *ice, 22788c2ecf20Sopenharmony_ci const char *modelname) 22798c2ecf20Sopenharmony_ci{ 22808c2ecf20Sopenharmony_ci const int dev = 0xa0; /* EEPROM device address */ 22818c2ecf20Sopenharmony_ci unsigned int i, size; 22828c2ecf20Sopenharmony_ci const struct snd_ice1712_card_info * const *tbl, *c; 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci if (!modelname || !*modelname) { 22858c2ecf20Sopenharmony_ci ice->eeprom.subvendor = 0; 22868c2ecf20Sopenharmony_ci if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) != 0) 22878c2ecf20Sopenharmony_ci ice->eeprom.subvendor = 22888c2ecf20Sopenharmony_ci (snd_vt1724_read_i2c(ice, dev, 0x00) << 0) | 22898c2ecf20Sopenharmony_ci (snd_vt1724_read_i2c(ice, dev, 0x01) << 8) | 22908c2ecf20Sopenharmony_ci (snd_vt1724_read_i2c(ice, dev, 0x02) << 16) | 22918c2ecf20Sopenharmony_ci (snd_vt1724_read_i2c(ice, dev, 0x03) << 24); 22928c2ecf20Sopenharmony_ci if (ice->eeprom.subvendor == 0 || 22938c2ecf20Sopenharmony_ci ice->eeprom.subvendor == (unsigned int)-1) { 22948c2ecf20Sopenharmony_ci /* invalid subvendor from EEPROM, try the PCI 22958c2ecf20Sopenharmony_ci * subststem ID instead 22968c2ecf20Sopenharmony_ci */ 22978c2ecf20Sopenharmony_ci u16 vendor, device; 22988c2ecf20Sopenharmony_ci pci_read_config_word(ice->pci, PCI_SUBSYSTEM_VENDOR_ID, 22998c2ecf20Sopenharmony_ci &vendor); 23008c2ecf20Sopenharmony_ci pci_read_config_word(ice->pci, PCI_SUBSYSTEM_ID, &device); 23018c2ecf20Sopenharmony_ci ice->eeprom.subvendor = 23028c2ecf20Sopenharmony_ci ((unsigned int)swab16(vendor) << 16) | swab16(device); 23038c2ecf20Sopenharmony_ci if (ice->eeprom.subvendor == 0 || 23048c2ecf20Sopenharmony_ci ice->eeprom.subvendor == (unsigned int)-1) { 23058c2ecf20Sopenharmony_ci dev_err(ice->card->dev, 23068c2ecf20Sopenharmony_ci "No valid ID is found\n"); 23078c2ecf20Sopenharmony_ci return -ENXIO; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci } 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci for (tbl = card_tables; *tbl; tbl++) { 23128c2ecf20Sopenharmony_ci for (c = *tbl; c->name; c++) { 23138c2ecf20Sopenharmony_ci if (modelname && c->model && 23148c2ecf20Sopenharmony_ci !strcmp(modelname, c->model)) { 23158c2ecf20Sopenharmony_ci dev_info(ice->card->dev, 23168c2ecf20Sopenharmony_ci "Using board model %s\n", 23178c2ecf20Sopenharmony_ci c->name); 23188c2ecf20Sopenharmony_ci ice->eeprom.subvendor = c->subvendor; 23198c2ecf20Sopenharmony_ci } else if (c->subvendor != ice->eeprom.subvendor) 23208c2ecf20Sopenharmony_ci continue; 23218c2ecf20Sopenharmony_ci ice->card_info = c; 23228c2ecf20Sopenharmony_ci if (!c->eeprom_size || !c->eeprom_data) 23238c2ecf20Sopenharmony_ci goto found; 23248c2ecf20Sopenharmony_ci /* if the EEPROM is given by the driver, use it */ 23258c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "using the defined eeprom..\n"); 23268c2ecf20Sopenharmony_ci ice->eeprom.version = 2; 23278c2ecf20Sopenharmony_ci ice->eeprom.size = c->eeprom_size + 6; 23288c2ecf20Sopenharmony_ci memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size); 23298c2ecf20Sopenharmony_ci goto read_skipped; 23308c2ecf20Sopenharmony_ci } 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n", 23338c2ecf20Sopenharmony_ci ice->eeprom.subvendor); 23348c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 23358c2ecf20Sopenharmony_ci /* assume AC97-only card which can suspend without additional code */ 23368c2ecf20Sopenharmony_ci ice->pm_suspend_enabled = 1; 23378c2ecf20Sopenharmony_ci#endif 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci found: 23408c2ecf20Sopenharmony_ci ice->eeprom.size = snd_vt1724_read_i2c(ice, dev, 0x04); 23418c2ecf20Sopenharmony_ci if (ice->eeprom.size < 6) 23428c2ecf20Sopenharmony_ci ice->eeprom.size = 32; 23438c2ecf20Sopenharmony_ci else if (ice->eeprom.size > 32) { 23448c2ecf20Sopenharmony_ci dev_err(ice->card->dev, "Invalid EEPROM (size = %i)\n", 23458c2ecf20Sopenharmony_ci ice->eeprom.size); 23468c2ecf20Sopenharmony_ci return -EIO; 23478c2ecf20Sopenharmony_ci } 23488c2ecf20Sopenharmony_ci ice->eeprom.version = snd_vt1724_read_i2c(ice, dev, 0x05); 23498c2ecf20Sopenharmony_ci if (ice->eeprom.version != 1 && ice->eeprom.version != 2) 23508c2ecf20Sopenharmony_ci dev_warn(ice->card->dev, "Invalid EEPROM version %i\n", 23518c2ecf20Sopenharmony_ci ice->eeprom.version); 23528c2ecf20Sopenharmony_ci size = ice->eeprom.size - 6; 23538c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 23548c2ecf20Sopenharmony_ci ice->eeprom.data[i] = snd_vt1724_read_i2c(ice, dev, i + 6); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci read_skipped: 23578c2ecf20Sopenharmony_ci ice->eeprom.gpiomask = eeprom_triple(ice, ICE_EEP2_GPIO_MASK); 23588c2ecf20Sopenharmony_ci ice->eeprom.gpiostate = eeprom_triple(ice, ICE_EEP2_GPIO_STATE); 23598c2ecf20Sopenharmony_ci ice->eeprom.gpiodir = eeprom_triple(ice, ICE_EEP2_GPIO_DIR); 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci return 0; 23628c2ecf20Sopenharmony_ci} 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_cistatic void snd_vt1724_chip_reset(struct snd_ice1712 *ice) 23678c2ecf20Sopenharmony_ci{ 23688c2ecf20Sopenharmony_ci outb(VT1724_RESET , ICEREG1724(ice, CONTROL)); 23698c2ecf20Sopenharmony_ci inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ 23708c2ecf20Sopenharmony_ci msleep(10); 23718c2ecf20Sopenharmony_ci outb(0, ICEREG1724(ice, CONTROL)); 23728c2ecf20Sopenharmony_ci inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ 23738c2ecf20Sopenharmony_ci msleep(10); 23748c2ecf20Sopenharmony_ci} 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_cistatic int snd_vt1724_chip_init(struct snd_ice1712 *ice) 23778c2ecf20Sopenharmony_ci{ 23788c2ecf20Sopenharmony_ci outb(ice->eeprom.data[ICE_EEP2_SYSCONF], ICEREG1724(ice, SYS_CFG)); 23798c2ecf20Sopenharmony_ci outb(ice->eeprom.data[ICE_EEP2_ACLINK], ICEREG1724(ice, AC97_CFG)); 23808c2ecf20Sopenharmony_ci outb(ice->eeprom.data[ICE_EEP2_I2S], ICEREG1724(ice, I2S_FEATURES)); 23818c2ecf20Sopenharmony_ci outb(ice->eeprom.data[ICE_EEP2_SPDIF], ICEREG1724(ice, SPDIF_CFG)); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci ice->gpio.write_mask = ice->eeprom.gpiomask; 23848c2ecf20Sopenharmony_ci ice->gpio.direction = ice->eeprom.gpiodir; 23858c2ecf20Sopenharmony_ci snd_vt1724_set_gpio_mask(ice, ice->eeprom.gpiomask); 23868c2ecf20Sopenharmony_ci snd_vt1724_set_gpio_dir(ice, ice->eeprom.gpiodir); 23878c2ecf20Sopenharmony_ci snd_vt1724_set_gpio_data(ice, ice->eeprom.gpiostate); 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci outb(0, ICEREG1724(ice, POWERDOWN)); 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci /* MPU_RX and TX irq masks are cleared later dynamically */ 23928c2ecf20Sopenharmony_ci outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK)); 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci /* don't handle FIFO overrun/underruns (just yet), 23958c2ecf20Sopenharmony_ci * since they cause machine lockups 23968c2ecf20Sopenharmony_ci */ 23978c2ecf20Sopenharmony_ci outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK)); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci return 0; 24008c2ecf20Sopenharmony_ci} 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_cistatic int snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) 24038c2ecf20Sopenharmony_ci{ 24048c2ecf20Sopenharmony_ci int err; 24058c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci if (snd_BUG_ON(!ice->pcm)) 24088c2ecf20Sopenharmony_ci return -EIO; 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci if (!ice->own_routing) { 24118c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, 24128c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice)); 24138c2ecf20Sopenharmony_ci if (err < 0) 24148c2ecf20Sopenharmony_ci return err; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice)); 24188c2ecf20Sopenharmony_ci if (err < 0) 24198c2ecf20Sopenharmony_ci return err; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_default, ice)); 24228c2ecf20Sopenharmony_ci if (err < 0) 24238c2ecf20Sopenharmony_ci return err; 24248c2ecf20Sopenharmony_ci kctl->id.device = ice->pcm->device; 24258c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_maskc, ice)); 24268c2ecf20Sopenharmony_ci if (err < 0) 24278c2ecf20Sopenharmony_ci return err; 24288c2ecf20Sopenharmony_ci kctl->id.device = ice->pcm->device; 24298c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_maskp, ice)); 24308c2ecf20Sopenharmony_ci if (err < 0) 24318c2ecf20Sopenharmony_ci return err; 24328c2ecf20Sopenharmony_ci kctl->id.device = ice->pcm->device; 24338c2ecf20Sopenharmony_ci#if 0 /* use default only */ 24348c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_stream, ice)); 24358c2ecf20Sopenharmony_ci if (err < 0) 24368c2ecf20Sopenharmony_ci return err; 24378c2ecf20Sopenharmony_ci kctl->id.device = ice->pcm->device; 24388c2ecf20Sopenharmony_ci ice->spdif.stream_ctl = kctl; 24398c2ecf20Sopenharmony_ci#endif 24408c2ecf20Sopenharmony_ci return 0; 24418c2ecf20Sopenharmony_ci} 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_cistatic int snd_vt1724_build_controls(struct snd_ice1712 *ice) 24458c2ecf20Sopenharmony_ci{ 24468c2ecf20Sopenharmony_ci int err; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_eeprom, ice)); 24498c2ecf20Sopenharmony_ci if (err < 0) 24508c2ecf20Sopenharmony_ci return err; 24518c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_pro_internal_clock, ice)); 24528c2ecf20Sopenharmony_ci if (err < 0) 24538c2ecf20Sopenharmony_ci return err; 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_pro_rate_locking, ice)); 24568c2ecf20Sopenharmony_ci if (err < 0) 24578c2ecf20Sopenharmony_ci return err; 24588c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_pro_rate_reset, ice)); 24598c2ecf20Sopenharmony_ci if (err < 0) 24608c2ecf20Sopenharmony_ci return err; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if (!ice->own_routing && ice->num_total_dacs > 0) { 24638c2ecf20Sopenharmony_ci struct snd_kcontrol_new tmp = snd_vt1724_mixer_pro_analog_route; 24648c2ecf20Sopenharmony_ci tmp.count = ice->num_total_dacs; 24658c2ecf20Sopenharmony_ci if (ice->vt1720 && tmp.count > 2) 24668c2ecf20Sopenharmony_ci tmp.count = 2; 24678c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&tmp, ice)); 24688c2ecf20Sopenharmony_ci if (err < 0) 24698c2ecf20Sopenharmony_ci return err; 24708c2ecf20Sopenharmony_ci } 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci return snd_ctl_add(ice->card, 24738c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_vt1724_mixer_pro_peak, ice)); 24748c2ecf20Sopenharmony_ci} 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_cistatic int snd_vt1724_free(struct snd_ice1712 *ice) 24778c2ecf20Sopenharmony_ci{ 24788c2ecf20Sopenharmony_ci if (!ice->port) 24798c2ecf20Sopenharmony_ci goto __hw_end; 24808c2ecf20Sopenharmony_ci /* mask all interrupts */ 24818c2ecf20Sopenharmony_ci outb(0xff, ICEMT1724(ice, DMA_INT_MASK)); 24828c2ecf20Sopenharmony_ci outb(0xff, ICEREG1724(ice, IRQMASK)); 24838c2ecf20Sopenharmony_ci /* --- */ 24848c2ecf20Sopenharmony_ci__hw_end: 24858c2ecf20Sopenharmony_ci if (ice->irq >= 0) 24868c2ecf20Sopenharmony_ci free_irq(ice->irq, ice); 24878c2ecf20Sopenharmony_ci pci_release_regions(ice->pci); 24888c2ecf20Sopenharmony_ci snd_ice1712_akm4xxx_free(ice); 24898c2ecf20Sopenharmony_ci pci_disable_device(ice->pci); 24908c2ecf20Sopenharmony_ci kfree(ice->spec); 24918c2ecf20Sopenharmony_ci kfree(ice); 24928c2ecf20Sopenharmony_ci return 0; 24938c2ecf20Sopenharmony_ci} 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_cistatic int snd_vt1724_dev_free(struct snd_device *device) 24968c2ecf20Sopenharmony_ci{ 24978c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = device->device_data; 24988c2ecf20Sopenharmony_ci return snd_vt1724_free(ice); 24998c2ecf20Sopenharmony_ci} 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_cistatic int snd_vt1724_create(struct snd_card *card, 25028c2ecf20Sopenharmony_ci struct pci_dev *pci, 25038c2ecf20Sopenharmony_ci const char *modelname, 25048c2ecf20Sopenharmony_ci struct snd_ice1712 **r_ice1712) 25058c2ecf20Sopenharmony_ci{ 25068c2ecf20Sopenharmony_ci struct snd_ice1712 *ice; 25078c2ecf20Sopenharmony_ci int err; 25088c2ecf20Sopenharmony_ci static const struct snd_device_ops ops = { 25098c2ecf20Sopenharmony_ci .dev_free = snd_vt1724_dev_free, 25108c2ecf20Sopenharmony_ci }; 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci *r_ice1712 = NULL; 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci /* enable PCI device */ 25158c2ecf20Sopenharmony_ci err = pci_enable_device(pci); 25168c2ecf20Sopenharmony_ci if (err < 0) 25178c2ecf20Sopenharmony_ci return err; 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci ice = kzalloc(sizeof(*ice), GFP_KERNEL); 25208c2ecf20Sopenharmony_ci if (ice == NULL) { 25218c2ecf20Sopenharmony_ci pci_disable_device(pci); 25228c2ecf20Sopenharmony_ci return -ENOMEM; 25238c2ecf20Sopenharmony_ci } 25248c2ecf20Sopenharmony_ci ice->vt1724 = 1; 25258c2ecf20Sopenharmony_ci spin_lock_init(&ice->reg_lock); 25268c2ecf20Sopenharmony_ci mutex_init(&ice->gpio_mutex); 25278c2ecf20Sopenharmony_ci mutex_init(&ice->open_mutex); 25288c2ecf20Sopenharmony_ci mutex_init(&ice->i2c_mutex); 25298c2ecf20Sopenharmony_ci ice->gpio.set_mask = snd_vt1724_set_gpio_mask; 25308c2ecf20Sopenharmony_ci ice->gpio.get_mask = snd_vt1724_get_gpio_mask; 25318c2ecf20Sopenharmony_ci ice->gpio.set_dir = snd_vt1724_set_gpio_dir; 25328c2ecf20Sopenharmony_ci ice->gpio.get_dir = snd_vt1724_get_gpio_dir; 25338c2ecf20Sopenharmony_ci ice->gpio.set_data = snd_vt1724_set_gpio_data; 25348c2ecf20Sopenharmony_ci ice->gpio.get_data = snd_vt1724_get_gpio_data; 25358c2ecf20Sopenharmony_ci ice->card = card; 25368c2ecf20Sopenharmony_ci ice->pci = pci; 25378c2ecf20Sopenharmony_ci ice->irq = -1; 25388c2ecf20Sopenharmony_ci pci_set_master(pci); 25398c2ecf20Sopenharmony_ci snd_vt1724_proc_init(ice); 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci card->private_data = ice; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci err = pci_request_regions(pci, "ICE1724"); 25448c2ecf20Sopenharmony_ci if (err < 0) { 25458c2ecf20Sopenharmony_ci kfree(ice); 25468c2ecf20Sopenharmony_ci pci_disable_device(pci); 25478c2ecf20Sopenharmony_ci return err; 25488c2ecf20Sopenharmony_ci } 25498c2ecf20Sopenharmony_ci ice->port = pci_resource_start(pci, 0); 25508c2ecf20Sopenharmony_ci ice->profi_port = pci_resource_start(pci, 1); 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci if (request_irq(pci->irq, snd_vt1724_interrupt, 25538c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, ice)) { 25548c2ecf20Sopenharmony_ci dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); 25558c2ecf20Sopenharmony_ci snd_vt1724_free(ice); 25568c2ecf20Sopenharmony_ci return -EIO; 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci ice->irq = pci->irq; 25608c2ecf20Sopenharmony_ci card->sync_irq = ice->irq; 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci snd_vt1724_chip_reset(ice); 25638c2ecf20Sopenharmony_ci if (snd_vt1724_read_eeprom(ice, modelname) < 0) { 25648c2ecf20Sopenharmony_ci snd_vt1724_free(ice); 25658c2ecf20Sopenharmony_ci return -EIO; 25668c2ecf20Sopenharmony_ci } 25678c2ecf20Sopenharmony_ci if (snd_vt1724_chip_init(ice) < 0) { 25688c2ecf20Sopenharmony_ci snd_vt1724_free(ice); 25698c2ecf20Sopenharmony_ci return -EIO; 25708c2ecf20Sopenharmony_ci } 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops); 25738c2ecf20Sopenharmony_ci if (err < 0) { 25748c2ecf20Sopenharmony_ci snd_vt1724_free(ice); 25758c2ecf20Sopenharmony_ci return err; 25768c2ecf20Sopenharmony_ci } 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci *r_ice1712 = ice; 25798c2ecf20Sopenharmony_ci return 0; 25808c2ecf20Sopenharmony_ci} 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci/* 25848c2ecf20Sopenharmony_ci * 25858c2ecf20Sopenharmony_ci * Registration 25868c2ecf20Sopenharmony_ci * 25878c2ecf20Sopenharmony_ci */ 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_cistatic int snd_vt1724_probe(struct pci_dev *pci, 25908c2ecf20Sopenharmony_ci const struct pci_device_id *pci_id) 25918c2ecf20Sopenharmony_ci{ 25928c2ecf20Sopenharmony_ci static int dev; 25938c2ecf20Sopenharmony_ci struct snd_card *card; 25948c2ecf20Sopenharmony_ci struct snd_ice1712 *ice; 25958c2ecf20Sopenharmony_ci int pcm_dev = 0, err; 25968c2ecf20Sopenharmony_ci const struct snd_ice1712_card_info * const *tbl, *c; 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci if (dev >= SNDRV_CARDS) 25998c2ecf20Sopenharmony_ci return -ENODEV; 26008c2ecf20Sopenharmony_ci if (!enable[dev]) { 26018c2ecf20Sopenharmony_ci dev++; 26028c2ecf20Sopenharmony_ci return -ENOENT; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 26068c2ecf20Sopenharmony_ci 0, &card); 26078c2ecf20Sopenharmony_ci if (err < 0) 26088c2ecf20Sopenharmony_ci return err; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci strcpy(card->driver, "ICE1724"); 26118c2ecf20Sopenharmony_ci strcpy(card->shortname, "ICEnsemble ICE1724"); 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci err = snd_vt1724_create(card, pci, model[dev], &ice); 26148c2ecf20Sopenharmony_ci if (err < 0) { 26158c2ecf20Sopenharmony_ci snd_card_free(card); 26168c2ecf20Sopenharmony_ci return err; 26178c2ecf20Sopenharmony_ci } 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci /* field init before calling chip_init */ 26208c2ecf20Sopenharmony_ci ice->ext_clock_count = 0; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci for (tbl = card_tables; *tbl; tbl++) { 26238c2ecf20Sopenharmony_ci for (c = *tbl; c->name; c++) { 26248c2ecf20Sopenharmony_ci if ((model[dev] && c->model && 26258c2ecf20Sopenharmony_ci !strcmp(model[dev], c->model)) || 26268c2ecf20Sopenharmony_ci (c->subvendor == ice->eeprom.subvendor)) { 26278c2ecf20Sopenharmony_ci strcpy(card->shortname, c->name); 26288c2ecf20Sopenharmony_ci if (c->driver) /* specific driver? */ 26298c2ecf20Sopenharmony_ci strcpy(card->driver, c->driver); 26308c2ecf20Sopenharmony_ci if (c->chip_init) { 26318c2ecf20Sopenharmony_ci err = c->chip_init(ice); 26328c2ecf20Sopenharmony_ci if (err < 0) { 26338c2ecf20Sopenharmony_ci snd_card_free(card); 26348c2ecf20Sopenharmony_ci return err; 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci } 26378c2ecf20Sopenharmony_ci goto __found; 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci } 26418c2ecf20Sopenharmony_ci c = &no_matched; 26428c2ecf20Sopenharmony_ci__found: 26438c2ecf20Sopenharmony_ci /* 26448c2ecf20Sopenharmony_ci * VT1724 has separate DMAs for the analog and the SPDIF streams while 26458c2ecf20Sopenharmony_ci * ICE1712 has only one for both (mixed up). 26468c2ecf20Sopenharmony_ci * 26478c2ecf20Sopenharmony_ci * Confusingly the analog PCM is named "professional" here because it 26488c2ecf20Sopenharmony_ci * was called so in ice1712 driver, and vt1724 driver is derived from 26498c2ecf20Sopenharmony_ci * ice1712 driver. 26508c2ecf20Sopenharmony_ci */ 26518c2ecf20Sopenharmony_ci ice->pro_rate_default = PRO_RATE_DEFAULT; 26528c2ecf20Sopenharmony_ci if (!ice->is_spdif_master) 26538c2ecf20Sopenharmony_ci ice->is_spdif_master = stdclock_is_spdif_master; 26548c2ecf20Sopenharmony_ci if (!ice->get_rate) 26558c2ecf20Sopenharmony_ci ice->get_rate = stdclock_get_rate; 26568c2ecf20Sopenharmony_ci if (!ice->set_rate) 26578c2ecf20Sopenharmony_ci ice->set_rate = stdclock_set_rate; 26588c2ecf20Sopenharmony_ci if (!ice->set_mclk) 26598c2ecf20Sopenharmony_ci ice->set_mclk = stdclock_set_mclk; 26608c2ecf20Sopenharmony_ci if (!ice->set_spdif_clock) 26618c2ecf20Sopenharmony_ci ice->set_spdif_clock = stdclock_set_spdif_clock; 26628c2ecf20Sopenharmony_ci if (!ice->get_spdif_master_type) 26638c2ecf20Sopenharmony_ci ice->get_spdif_master_type = stdclock_get_spdif_master_type; 26648c2ecf20Sopenharmony_ci if (!ice->ext_clock_names) 26658c2ecf20Sopenharmony_ci ice->ext_clock_names = ext_clock_names; 26668c2ecf20Sopenharmony_ci if (!ice->ext_clock_count) 26678c2ecf20Sopenharmony_ci ice->ext_clock_count = ARRAY_SIZE(ext_clock_names); 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci if (!ice->hw_rates) 26708c2ecf20Sopenharmony_ci set_std_hw_rates(ice); 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci err = snd_vt1724_pcm_profi(ice, pcm_dev++); 26738c2ecf20Sopenharmony_ci if (err < 0) { 26748c2ecf20Sopenharmony_ci snd_card_free(card); 26758c2ecf20Sopenharmony_ci return err; 26768c2ecf20Sopenharmony_ci } 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci err = snd_vt1724_pcm_spdif(ice, pcm_dev++); 26798c2ecf20Sopenharmony_ci if (err < 0) { 26808c2ecf20Sopenharmony_ci snd_card_free(card); 26818c2ecf20Sopenharmony_ci return err; 26828c2ecf20Sopenharmony_ci } 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci err = snd_vt1724_pcm_indep(ice, pcm_dev++); 26858c2ecf20Sopenharmony_ci if (err < 0) { 26868c2ecf20Sopenharmony_ci snd_card_free(card); 26878c2ecf20Sopenharmony_ci return err; 26888c2ecf20Sopenharmony_ci } 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci err = snd_vt1724_ac97_mixer(ice); 26918c2ecf20Sopenharmony_ci if (err < 0) { 26928c2ecf20Sopenharmony_ci snd_card_free(card); 26938c2ecf20Sopenharmony_ci return err; 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci err = snd_vt1724_build_controls(ice); 26978c2ecf20Sopenharmony_ci if (err < 0) { 26988c2ecf20Sopenharmony_ci snd_card_free(card); 26998c2ecf20Sopenharmony_ci return err; 27008c2ecf20Sopenharmony_ci } 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci if (ice->pcm && ice->has_spdif) { /* has SPDIF I/O */ 27038c2ecf20Sopenharmony_ci err = snd_vt1724_spdif_build_controls(ice); 27048c2ecf20Sopenharmony_ci if (err < 0) { 27058c2ecf20Sopenharmony_ci snd_card_free(card); 27068c2ecf20Sopenharmony_ci return err; 27078c2ecf20Sopenharmony_ci } 27088c2ecf20Sopenharmony_ci } 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci if (c->build_controls) { 27118c2ecf20Sopenharmony_ci err = c->build_controls(ice); 27128c2ecf20Sopenharmony_ci if (err < 0) { 27138c2ecf20Sopenharmony_ci snd_card_free(card); 27148c2ecf20Sopenharmony_ci return err; 27158c2ecf20Sopenharmony_ci } 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci if (!c->no_mpu401) { 27198c2ecf20Sopenharmony_ci if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { 27208c2ecf20Sopenharmony_ci struct snd_rawmidi *rmidi; 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci err = snd_rawmidi_new(card, "MIDI", 0, 1, 1, &rmidi); 27238c2ecf20Sopenharmony_ci if (err < 0) { 27248c2ecf20Sopenharmony_ci snd_card_free(card); 27258c2ecf20Sopenharmony_ci return err; 27268c2ecf20Sopenharmony_ci } 27278c2ecf20Sopenharmony_ci ice->rmidi[0] = rmidi; 27288c2ecf20Sopenharmony_ci rmidi->private_data = ice; 27298c2ecf20Sopenharmony_ci strcpy(rmidi->name, "ICE1724 MIDI"); 27308c2ecf20Sopenharmony_ci rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | 27318c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_INFO_INPUT | 27328c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_INFO_DUPLEX; 27338c2ecf20Sopenharmony_ci snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 27348c2ecf20Sopenharmony_ci &vt1724_midi_output_ops); 27358c2ecf20Sopenharmony_ci snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 27368c2ecf20Sopenharmony_ci &vt1724_midi_input_ops); 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci /* set watermarks */ 27398c2ecf20Sopenharmony_ci outb(VT1724_MPU_RX_FIFO | 0x1, 27408c2ecf20Sopenharmony_ci ICEREG1724(ice, MPU_FIFO_WM)); 27418c2ecf20Sopenharmony_ci outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); 27428c2ecf20Sopenharmony_ci /* set UART mode */ 27438c2ecf20Sopenharmony_ci outb(VT1724_MPU_UART, ICEREG1724(ice, MPU_CTRL)); 27448c2ecf20Sopenharmony_ci } 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci sprintf(card->longname, "%s at 0x%lx, irq %i", 27488c2ecf20Sopenharmony_ci card->shortname, ice->port, ice->irq); 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci err = snd_card_register(card); 27518c2ecf20Sopenharmony_ci if (err < 0) { 27528c2ecf20Sopenharmony_ci snd_card_free(card); 27538c2ecf20Sopenharmony_ci return err; 27548c2ecf20Sopenharmony_ci } 27558c2ecf20Sopenharmony_ci pci_set_drvdata(pci, card); 27568c2ecf20Sopenharmony_ci dev++; 27578c2ecf20Sopenharmony_ci return 0; 27588c2ecf20Sopenharmony_ci} 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_cistatic void snd_vt1724_remove(struct pci_dev *pci) 27618c2ecf20Sopenharmony_ci{ 27628c2ecf20Sopenharmony_ci struct snd_card *card = pci_get_drvdata(pci); 27638c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = card->private_data; 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci if (ice->card_info && ice->card_info->chip_exit) 27668c2ecf20Sopenharmony_ci ice->card_info->chip_exit(ice); 27678c2ecf20Sopenharmony_ci snd_card_free(card); 27688c2ecf20Sopenharmony_ci} 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 27718c2ecf20Sopenharmony_cistatic int snd_vt1724_suspend(struct device *dev) 27728c2ecf20Sopenharmony_ci{ 27738c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 27748c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = card->private_data; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci if (!ice->pm_suspend_enabled) 27778c2ecf20Sopenharmony_ci return 0; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci snd_ac97_suspend(ice->ac97); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci spin_lock_irq(&ice->reg_lock); 27848c2ecf20Sopenharmony_ci ice->pm_saved_is_spdif_master = ice->is_spdif_master(ice); 27858c2ecf20Sopenharmony_ci ice->pm_saved_spdif_ctrl = inw(ICEMT1724(ice, SPDIF_CTRL)); 27868c2ecf20Sopenharmony_ci ice->pm_saved_spdif_cfg = inb(ICEREG1724(ice, SPDIF_CFG)); 27878c2ecf20Sopenharmony_ci ice->pm_saved_route = inl(ICEMT1724(ice, ROUTE_PLAYBACK)); 27888c2ecf20Sopenharmony_ci spin_unlock_irq(&ice->reg_lock); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (ice->pm_suspend) 27918c2ecf20Sopenharmony_ci ice->pm_suspend(ice); 27928c2ecf20Sopenharmony_ci return 0; 27938c2ecf20Sopenharmony_ci} 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_cistatic int snd_vt1724_resume(struct device *dev) 27968c2ecf20Sopenharmony_ci{ 27978c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 27988c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = card->private_data; 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci if (!ice->pm_suspend_enabled) 28018c2ecf20Sopenharmony_ci return 0; 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci snd_vt1724_chip_reset(ice); 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci if (snd_vt1724_chip_init(ice) < 0) { 28068c2ecf20Sopenharmony_ci snd_card_disconnect(card); 28078c2ecf20Sopenharmony_ci return -EIO; 28088c2ecf20Sopenharmony_ci } 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci if (ice->pm_resume) 28118c2ecf20Sopenharmony_ci ice->pm_resume(ice); 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci if (ice->pm_saved_is_spdif_master) { 28148c2ecf20Sopenharmony_ci /* switching to external clock via SPDIF */ 28158c2ecf20Sopenharmony_ci ice->set_spdif_clock(ice, 0); 28168c2ecf20Sopenharmony_ci } else { 28178c2ecf20Sopenharmony_ci /* internal on-card clock */ 28188c2ecf20Sopenharmony_ci int rate; 28198c2ecf20Sopenharmony_ci if (ice->cur_rate) 28208c2ecf20Sopenharmony_ci rate = ice->cur_rate; 28218c2ecf20Sopenharmony_ci else 28228c2ecf20Sopenharmony_ci rate = ice->pro_rate_default; 28238c2ecf20Sopenharmony_ci snd_vt1724_set_pro_rate(ice, rate, 1); 28248c2ecf20Sopenharmony_ci } 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci update_spdif_bits(ice, ice->pm_saved_spdif_ctrl); 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci outb(ice->pm_saved_spdif_cfg, ICEREG1724(ice, SPDIF_CFG)); 28298c2ecf20Sopenharmony_ci outl(ice->pm_saved_route, ICEMT1724(ice, ROUTE_PLAYBACK)); 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci snd_ac97_resume(ice->ac97); 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D0); 28348c2ecf20Sopenharmony_ci return 0; 28358c2ecf20Sopenharmony_ci} 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(snd_vt1724_pm, snd_vt1724_suspend, snd_vt1724_resume); 28388c2ecf20Sopenharmony_ci#define SND_VT1724_PM_OPS &snd_vt1724_pm 28398c2ecf20Sopenharmony_ci#else 28408c2ecf20Sopenharmony_ci#define SND_VT1724_PM_OPS NULL 28418c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_cistatic struct pci_driver vt1724_driver = { 28448c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 28458c2ecf20Sopenharmony_ci .id_table = snd_vt1724_ids, 28468c2ecf20Sopenharmony_ci .probe = snd_vt1724_probe, 28478c2ecf20Sopenharmony_ci .remove = snd_vt1724_remove, 28488c2ecf20Sopenharmony_ci .driver = { 28498c2ecf20Sopenharmony_ci .pm = SND_VT1724_PM_OPS, 28508c2ecf20Sopenharmony_ci }, 28518c2ecf20Sopenharmony_ci}; 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_cimodule_pci_driver(vt1724_driver); 2854