xref: /kernel/linux/linux-5.10/sound/pci/ice1712/se.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *   Lowlevel functions for ONKYO WAVIO SE-90PCI and SE-200PCI
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *	Copyright (c) 2007 Shin-ya Okada  sh_okada(at)d4.dion.ne.jp
88c2ecf20Sopenharmony_ci *                                        (at) -> @
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/slab.h>
158c2ecf20Sopenharmony_ci#include <sound/core.h>
168c2ecf20Sopenharmony_ci#include <sound/tlv.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "ice1712.h"
198c2ecf20Sopenharmony_ci#include "envy24ht.h"
208c2ecf20Sopenharmony_ci#include "se.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct se_spec {
238c2ecf20Sopenharmony_ci	struct {
248c2ecf20Sopenharmony_ci		unsigned char ch1, ch2;
258c2ecf20Sopenharmony_ci	} vol[8];
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/****************************************************************************/
298c2ecf20Sopenharmony_ci/*  ONKYO WAVIO SE-200PCI                                                   */
308c2ecf20Sopenharmony_ci/****************************************************************************/
318c2ecf20Sopenharmony_ci/*
328c2ecf20Sopenharmony_ci *  system configuration ICE_EEP2_SYSCONF=0x4b
338c2ecf20Sopenharmony_ci *    XIN1 49.152MHz
348c2ecf20Sopenharmony_ci *    not have UART
358c2ecf20Sopenharmony_ci *    one stereo ADC and a S/PDIF receiver connected
368c2ecf20Sopenharmony_ci *    four stereo DACs connected
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci *  AC-Link configuration ICE_EEP2_ACLINK=0x80
398c2ecf20Sopenharmony_ci *    use I2C, not use AC97
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci *  I2S converters feature ICE_EEP2_I2S=0x78
428c2ecf20Sopenharmony_ci *    I2S codec has no volume/mute control feature
438c2ecf20Sopenharmony_ci *    I2S codec supports 96KHz and 192KHz
448c2ecf20Sopenharmony_ci *    I2S codec 24bits
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci *  S/PDIF configuration ICE_EEP2_SPDIF=0xc3
478c2ecf20Sopenharmony_ci *    Enable integrated S/PDIF transmitter
488c2ecf20Sopenharmony_ci *    internal S/PDIF out implemented
498c2ecf20Sopenharmony_ci *    S/PDIF is stereo
508c2ecf20Sopenharmony_ci *    External S/PDIF out implemented
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * ** connected chips **
548c2ecf20Sopenharmony_ci *
558c2ecf20Sopenharmony_ci *  WM8740
568c2ecf20Sopenharmony_ci *      A 2ch-DAC of main outputs.
578c2ecf20Sopenharmony_ci *      It setuped as I2S mode by wire, so no way to setup from software.
588c2ecf20Sopenharmony_ci *      The sample-rate are automatically changed.
598c2ecf20Sopenharmony_ci *          ML/I2S (28pin) --------+
608c2ecf20Sopenharmony_ci *          MC/DM1 (27pin) -- 5V   |
618c2ecf20Sopenharmony_ci *          MD/DM0 (26pin) -- GND  |
628c2ecf20Sopenharmony_ci *          MUTEB  (25pin) -- NC   |
638c2ecf20Sopenharmony_ci *          MODE   (24pin) -- GND  |
648c2ecf20Sopenharmony_ci *          CSBIW  (23pin) --------+
658c2ecf20Sopenharmony_ci *                                 |
668c2ecf20Sopenharmony_ci *          RSTB   (22pin) --R(1K)-+
678c2ecf20Sopenharmony_ci *      Probably it reduce the noise from the control line.
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci *  WM8766
708c2ecf20Sopenharmony_ci *      A 6ch-DAC for surrounds.
718c2ecf20Sopenharmony_ci *      It's control wire was connected to GPIOxx (3-wire serial interface)
728c2ecf20Sopenharmony_ci *          ML/I2S (11pin) -- GPIO18
738c2ecf20Sopenharmony_ci *          MC/IWL (12pin) -- GPIO17
748c2ecf20Sopenharmony_ci *          MD/DM  (13pin) -- GPIO16
758c2ecf20Sopenharmony_ci *          MUTE   (14pin) -- GPIO01
768c2ecf20Sopenharmony_ci *
778c2ecf20Sopenharmony_ci *  WM8776
788c2ecf20Sopenharmony_ci *     A 2ch-ADC(with 10ch-selector) plus 2ch-DAC.
798c2ecf20Sopenharmony_ci *     It's control wire was connected to SDA/SCLK (2-wire serial interface)
808c2ecf20Sopenharmony_ci *          MODE (16pin) -- R(1K) -- GND
818c2ecf20Sopenharmony_ci *          CE   (17pin) -- R(1K) -- GND  2-wire mode (address=0x34)
828c2ecf20Sopenharmony_ci *          DI   (18pin) -- SDA
838c2ecf20Sopenharmony_ci *          CL   (19pin) -- SCLK
848c2ecf20Sopenharmony_ci *
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * ** output pins and device names **
878c2ecf20Sopenharmony_ci *
888c2ecf20Sopenharmony_ci *   7.1ch name -- output connector color -- device (-D option)
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci *      FRONT 2ch                  -- green  -- plughw:0,0
918c2ecf20Sopenharmony_ci *      CENTER(Lch) SUBWOOFER(Rch) -- black  -- plughw:0,2,0
928c2ecf20Sopenharmony_ci *      SURROUND 2ch               -- orange -- plughw:0,2,1
938c2ecf20Sopenharmony_ci *      SURROUND BACK 2ch          -- white  -- plughw:0,2,2
948c2ecf20Sopenharmony_ci *
958c2ecf20Sopenharmony_ci */
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/****************************************************************************/
998c2ecf20Sopenharmony_ci/*  WM8740 interface                                                        */
1008c2ecf20Sopenharmony_ci/****************************************************************************/
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void se200pci_WM8740_init(struct snd_ice1712 *ice)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	/* nothing to do */
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic void se200pci_WM8740_set_pro_rate(struct snd_ice1712 *ice,
1098c2ecf20Sopenharmony_ci						unsigned int rate)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	/* nothing to do */
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/****************************************************************************/
1168c2ecf20Sopenharmony_ci/*  WM8766 interface                                                        */
1178c2ecf20Sopenharmony_ci/****************************************************************************/
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void se200pci_WM8766_write(struct snd_ice1712 *ice,
1208c2ecf20Sopenharmony_ci					unsigned int addr, unsigned int data)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	unsigned int st;
1238c2ecf20Sopenharmony_ci	unsigned int bits;
1248c2ecf20Sopenharmony_ci	int i;
1258c2ecf20Sopenharmony_ci	const unsigned int DATA  = 0x010000;
1268c2ecf20Sopenharmony_ci	const unsigned int CLOCK = 0x020000;
1278c2ecf20Sopenharmony_ci	const unsigned int LOAD  = 0x040000;
1288c2ecf20Sopenharmony_ci	const unsigned int ALL_MASK = (DATA | CLOCK | LOAD);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	snd_ice1712_save_gpio_status(ice);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	st = ((addr & 0x7f) << 9) | (data & 0x1ff);
1338c2ecf20Sopenharmony_ci	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | ALL_MASK);
1348c2ecf20Sopenharmony_ci	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~ALL_MASK);
1358c2ecf20Sopenharmony_ci	bits = snd_ice1712_gpio_read(ice) & ~ALL_MASK;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write(ice, bits);
1388c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++) {
1398c2ecf20Sopenharmony_ci		udelay(1);
1408c2ecf20Sopenharmony_ci		bits &= ~CLOCK;
1418c2ecf20Sopenharmony_ci		st = (st << 1);
1428c2ecf20Sopenharmony_ci		if (st & 0x10000)
1438c2ecf20Sopenharmony_ci			bits |= DATA;
1448c2ecf20Sopenharmony_ci		else
1458c2ecf20Sopenharmony_ci			bits &= ~DATA;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write(ice, bits);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci		udelay(1);
1508c2ecf20Sopenharmony_ci		bits |= CLOCK;
1518c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write(ice, bits);
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	udelay(1);
1558c2ecf20Sopenharmony_ci	bits |= LOAD;
1568c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write(ice, bits);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	udelay(1);
1598c2ecf20Sopenharmony_ci	bits |= (DATA | CLOCK);
1608c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write(ice, bits);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	snd_ice1712_restore_gpio_status(ice);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch,
1668c2ecf20Sopenharmony_ci					unsigned int vol1, unsigned int vol2)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	switch (ch) {
1698c2ecf20Sopenharmony_ci	case 0:
1708c2ecf20Sopenharmony_ci		se200pci_WM8766_write(ice, 0x000, vol1);
1718c2ecf20Sopenharmony_ci		se200pci_WM8766_write(ice, 0x001, vol2 | 0x100);
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	case 1:
1748c2ecf20Sopenharmony_ci		se200pci_WM8766_write(ice, 0x004, vol1);
1758c2ecf20Sopenharmony_ci		se200pci_WM8766_write(ice, 0x005, vol2 | 0x100);
1768c2ecf20Sopenharmony_ci		break;
1778c2ecf20Sopenharmony_ci	case 2:
1788c2ecf20Sopenharmony_ci		se200pci_WM8766_write(ice, 0x006, vol1);
1798c2ecf20Sopenharmony_ci		se200pci_WM8766_write(ice, 0x007, vol2 | 0x100);
1808c2ecf20Sopenharmony_ci		break;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic void se200pci_WM8766_init(struct snd_ice1712 *ice)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */
1878c2ecf20Sopenharmony_ci	udelay(10);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	se200pci_WM8766_set_volume(ice, 0, 0, 0); /* volume L=0 R=0 */
1908c2ecf20Sopenharmony_ci	se200pci_WM8766_set_volume(ice, 1, 0, 0); /* volume L=0 R=0 */
1918c2ecf20Sopenharmony_ci	se200pci_WM8766_set_volume(ice, 2, 0, 0); /* volume L=0 R=0 */
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	se200pci_WM8766_write(ice, 0x03, 0x022); /* serial mode I2S-24bits */
1948c2ecf20Sopenharmony_ci	se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */
1958c2ecf20Sopenharmony_ci	se200pci_WM8766_write(ice, 0x12, 0x000); /* MDP=0 */
1968c2ecf20Sopenharmony_ci	se200pci_WM8766_write(ice, 0x15, 0x000); /* MDP=0 */
1978c2ecf20Sopenharmony_ci	se200pci_WM8766_write(ice, 0x09, 0x000); /* demp=off mute=off */
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	se200pci_WM8766_write(ice, 0x02, 0x124); /* ch-assign L=L R=R RESET */
2008c2ecf20Sopenharmony_ci	se200pci_WM8766_write(ice, 0x02, 0x120); /* ch-assign L=L R=R */
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic void se200pci_WM8766_set_pro_rate(struct snd_ice1712 *ice,
2048c2ecf20Sopenharmony_ci					unsigned int rate)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	if (rate > 96000)
2078c2ecf20Sopenharmony_ci		se200pci_WM8766_write(ice, 0x0a, 0x000); /* MCLK=128fs */
2088c2ecf20Sopenharmony_ci	else
2098c2ecf20Sopenharmony_ci		se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/****************************************************************************/
2148c2ecf20Sopenharmony_ci/*  WM8776 interface                                                        */
2158c2ecf20Sopenharmony_ci/****************************************************************************/
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic void se200pci_WM8776_write(struct snd_ice1712 *ice,
2188c2ecf20Sopenharmony_ci					unsigned int addr, unsigned int data)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	unsigned int val;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	val = (addr << 9) | data;
2238c2ecf20Sopenharmony_ci	snd_vt1724_write_i2c(ice, 0x34, val >> 8, val & 0xff);
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic void se200pci_WM8776_set_output_volume(struct snd_ice1712 *ice,
2288c2ecf20Sopenharmony_ci					unsigned int vol1, unsigned int vol2)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x03, vol1);
2318c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x04, vol2 | 0x100);
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice,
2358c2ecf20Sopenharmony_ci					unsigned int vol1, unsigned int vol2)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x0e, vol1);
2388c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100);
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic const char * const se200pci_sel[] = {
2428c2ecf20Sopenharmony_ci	"LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic void se200pci_WM8776_set_input_selector(struct snd_ice1712 *ice,
2468c2ecf20Sopenharmony_ci					       unsigned int sel)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	static const unsigned char vals[] = {
2498c2ecf20Sopenharmony_ci		/* LINE, CD, MIC, ALL, GND */
2508c2ecf20Sopenharmony_ci		0x10, 0x04, 0x08, 0x1c, 0x03
2518c2ecf20Sopenharmony_ci	};
2528c2ecf20Sopenharmony_ci	if (sel > 4)
2538c2ecf20Sopenharmony_ci		sel = 4;
2548c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x15, vals[sel]);
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	/* AFL -- After Fader Listening */
2608c2ecf20Sopenharmony_ci	if (afl)
2618c2ecf20Sopenharmony_ci		se200pci_WM8776_write(ice, 0x16, 0x005);
2628c2ecf20Sopenharmony_ci	else
2638c2ecf20Sopenharmony_ci		se200pci_WM8776_write(ice, 0x16, 0x001);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic const char * const se200pci_agc[] = {
2678c2ecf20Sopenharmony_ci	"Off", "LimiterMode", "ALCMode", NULL
2688c2ecf20Sopenharmony_ci};
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	/* AGC -- Auto Gain Control of the input */
2738c2ecf20Sopenharmony_ci	switch (agc) {
2748c2ecf20Sopenharmony_ci	case 0:
2758c2ecf20Sopenharmony_ci		se200pci_WM8776_write(ice, 0x11, 0x000); /* Off */
2768c2ecf20Sopenharmony_ci		break;
2778c2ecf20Sopenharmony_ci	case 1:
2788c2ecf20Sopenharmony_ci		se200pci_WM8776_write(ice, 0x10, 0x07b);
2798c2ecf20Sopenharmony_ci		se200pci_WM8776_write(ice, 0x11, 0x100); /* LimiterMode */
2808c2ecf20Sopenharmony_ci		break;
2818c2ecf20Sopenharmony_ci	case 2:
2828c2ecf20Sopenharmony_ci		se200pci_WM8776_write(ice, 0x10, 0x1fb);
2838c2ecf20Sopenharmony_ci		se200pci_WM8776_write(ice, 0x11, 0x100); /* ALCMode */
2848c2ecf20Sopenharmony_ci		break;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic void se200pci_WM8776_init(struct snd_ice1712 *ice)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	int i;
2918c2ecf20Sopenharmony_ci	static const unsigned short default_values[] = {
2928c2ecf20Sopenharmony_ci		0x100, 0x100, 0x100,
2938c2ecf20Sopenharmony_ci		0x100, 0x100, 0x100,
2948c2ecf20Sopenharmony_ci		0x000, 0x090, 0x000, 0x000,
2958c2ecf20Sopenharmony_ci		0x022, 0x022, 0x022,
2968c2ecf20Sopenharmony_ci		0x008, 0x0cf, 0x0cf, 0x07b, 0x000,
2978c2ecf20Sopenharmony_ci		0x032, 0x000, 0x0a6, 0x001, 0x001
2988c2ecf20Sopenharmony_ci	};
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x17, 0x000); /* reset all */
3018c2ecf20Sopenharmony_ci	/* ADC and DAC interface is I2S 24bits mode */
3028c2ecf20Sopenharmony_ci 	/* The sample-rate are automatically changed */
3038c2ecf20Sopenharmony_ci	udelay(10);
3048c2ecf20Sopenharmony_ci	/* BUT my board can not do reset all, so I load all by manually. */
3058c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(default_values); i++)
3068c2ecf20Sopenharmony_ci		se200pci_WM8776_write(ice, i, default_values[i]);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	se200pci_WM8776_set_input_selector(ice, 0);
3098c2ecf20Sopenharmony_ci	se200pci_WM8776_set_afl(ice, 0);
3108c2ecf20Sopenharmony_ci	se200pci_WM8776_set_agc(ice, 0);
3118c2ecf20Sopenharmony_ci	se200pci_WM8776_set_input_volume(ice, 0, 0);
3128c2ecf20Sopenharmony_ci	se200pci_WM8776_set_output_volume(ice, 0, 0);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* head phone mute and power down */
3158c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x00, 0);
3168c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x01, 0);
3178c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x02, 0x100);
3188c2ecf20Sopenharmony_ci	se200pci_WM8776_write(ice, 0x0d, 0x080);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic void se200pci_WM8776_set_pro_rate(struct snd_ice1712 *ice,
3228c2ecf20Sopenharmony_ci						unsigned int rate)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	/* nothing to do */
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/****************************************************************************/
3298c2ecf20Sopenharmony_ci/*  runtime interface                                                       */
3308c2ecf20Sopenharmony_ci/****************************************************************************/
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	se200pci_WM8740_set_pro_rate(ice, rate);
3358c2ecf20Sopenharmony_ci	se200pci_WM8766_set_pro_rate(ice, rate);
3368c2ecf20Sopenharmony_ci	se200pci_WM8776_set_pro_rate(ice, rate);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistruct se200pci_control {
3408c2ecf20Sopenharmony_ci	const char *name;
3418c2ecf20Sopenharmony_ci	enum {
3428c2ecf20Sopenharmony_ci		WM8766,
3438c2ecf20Sopenharmony_ci		WM8776in,
3448c2ecf20Sopenharmony_ci		WM8776out,
3458c2ecf20Sopenharmony_ci		WM8776sel,
3468c2ecf20Sopenharmony_ci		WM8776agc,
3478c2ecf20Sopenharmony_ci		WM8776afl
3488c2ecf20Sopenharmony_ci	} target;
3498c2ecf20Sopenharmony_ci	enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type;
3508c2ecf20Sopenharmony_ci	int ch;
3518c2ecf20Sopenharmony_ci	const char * const *member;
3528c2ecf20Sopenharmony_ci	const char *comment;
3538c2ecf20Sopenharmony_ci};
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic const struct se200pci_control se200pci_cont[] = {
3568c2ecf20Sopenharmony_ci	{
3578c2ecf20Sopenharmony_ci		.name = "Front Playback Volume",
3588c2ecf20Sopenharmony_ci		.target = WM8776out,
3598c2ecf20Sopenharmony_ci		.type = VOLUME1,
3608c2ecf20Sopenharmony_ci		.comment = "Front(green)"
3618c2ecf20Sopenharmony_ci	},
3628c2ecf20Sopenharmony_ci	{
3638c2ecf20Sopenharmony_ci		.name = "Side Playback Volume",
3648c2ecf20Sopenharmony_ci		.target = WM8766,
3658c2ecf20Sopenharmony_ci		.type = VOLUME1,
3668c2ecf20Sopenharmony_ci		.ch = 1,
3678c2ecf20Sopenharmony_ci		.comment = "Surround(orange)"
3688c2ecf20Sopenharmony_ci	},
3698c2ecf20Sopenharmony_ci	{
3708c2ecf20Sopenharmony_ci		.name = "Surround Playback Volume",
3718c2ecf20Sopenharmony_ci		.target = WM8766,
3728c2ecf20Sopenharmony_ci		.type = VOLUME1,
3738c2ecf20Sopenharmony_ci		.ch = 2,
3748c2ecf20Sopenharmony_ci		.comment = "SurroundBack(white)"
3758c2ecf20Sopenharmony_ci	},
3768c2ecf20Sopenharmony_ci	{
3778c2ecf20Sopenharmony_ci		.name = "CLFE Playback Volume",
3788c2ecf20Sopenharmony_ci		.target = WM8766,
3798c2ecf20Sopenharmony_ci		.type = VOLUME1,
3808c2ecf20Sopenharmony_ci		.ch = 0,
3818c2ecf20Sopenharmony_ci		.comment = "Center(Lch)&SubWoofer(Rch)(black)"
3828c2ecf20Sopenharmony_ci	},
3838c2ecf20Sopenharmony_ci	{
3848c2ecf20Sopenharmony_ci		.name = "Capture Volume",
3858c2ecf20Sopenharmony_ci		.target = WM8776in,
3868c2ecf20Sopenharmony_ci		.type = VOLUME2
3878c2ecf20Sopenharmony_ci	},
3888c2ecf20Sopenharmony_ci	{
3898c2ecf20Sopenharmony_ci		.name = "Capture Select",
3908c2ecf20Sopenharmony_ci		.target = WM8776sel,
3918c2ecf20Sopenharmony_ci		.type = ENUM,
3928c2ecf20Sopenharmony_ci		.member = se200pci_sel
3938c2ecf20Sopenharmony_ci	},
3948c2ecf20Sopenharmony_ci	{
3958c2ecf20Sopenharmony_ci		.name = "AGC Capture Mode",
3968c2ecf20Sopenharmony_ci		.target = WM8776agc,
3978c2ecf20Sopenharmony_ci		.type = ENUM,
3988c2ecf20Sopenharmony_ci		.member = se200pci_agc
3998c2ecf20Sopenharmony_ci	},
4008c2ecf20Sopenharmony_ci	{
4018c2ecf20Sopenharmony_ci		.name = "AFL Bypass Playback Switch",
4028c2ecf20Sopenharmony_ci		.target = WM8776afl,
4038c2ecf20Sopenharmony_ci		.type = BOOLEAN
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic int se200pci_get_enum_count(int n)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	const char * const *member;
4108c2ecf20Sopenharmony_ci	int c;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	member = se200pci_cont[n].member;
4138c2ecf20Sopenharmony_ci	if (!member)
4148c2ecf20Sopenharmony_ci		return 0;
4158c2ecf20Sopenharmony_ci	for (c = 0; member[c]; c++)
4168c2ecf20Sopenharmony_ci		;
4178c2ecf20Sopenharmony_ci	return c;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic int se200pci_cont_volume_info(struct snd_kcontrol *kc,
4218c2ecf20Sopenharmony_ci				     struct snd_ctl_elem_info *uinfo)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
4248c2ecf20Sopenharmony_ci	uinfo->count = 2;
4258c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0; /* mute */
4268c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 0xff; /* 0dB */
4278c2ecf20Sopenharmony_ci	return 0;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci#define se200pci_cont_boolean_info	snd_ctl_boolean_mono_info
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int se200pci_cont_enum_info(struct snd_kcontrol *kc,
4338c2ecf20Sopenharmony_ci				   struct snd_ctl_elem_info *uinfo)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	int n, c;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	n = kc->private_value;
4388c2ecf20Sopenharmony_ci	c = se200pci_get_enum_count(n);
4398c2ecf20Sopenharmony_ci	if (!c)
4408c2ecf20Sopenharmony_ci		return -EINVAL;
4418c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, c, se200pci_cont[n].member);
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic int se200pci_cont_volume_get(struct snd_kcontrol *kc,
4458c2ecf20Sopenharmony_ci				    struct snd_ctl_elem_value *uc)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
4488c2ecf20Sopenharmony_ci	struct se_spec *spec = ice->spec;
4498c2ecf20Sopenharmony_ci	int n = kc->private_value;
4508c2ecf20Sopenharmony_ci	uc->value.integer.value[0] = spec->vol[n].ch1;
4518c2ecf20Sopenharmony_ci	uc->value.integer.value[1] = spec->vol[n].ch2;
4528c2ecf20Sopenharmony_ci	return 0;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic int se200pci_cont_boolean_get(struct snd_kcontrol *kc,
4568c2ecf20Sopenharmony_ci				     struct snd_ctl_elem_value *uc)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
4598c2ecf20Sopenharmony_ci	struct se_spec *spec = ice->spec;
4608c2ecf20Sopenharmony_ci	int n = kc->private_value;
4618c2ecf20Sopenharmony_ci	uc->value.integer.value[0] = spec->vol[n].ch1;
4628c2ecf20Sopenharmony_ci	return 0;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic int se200pci_cont_enum_get(struct snd_kcontrol *kc,
4668c2ecf20Sopenharmony_ci				  struct snd_ctl_elem_value *uc)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
4698c2ecf20Sopenharmony_ci	struct se_spec *spec = ice->spec;
4708c2ecf20Sopenharmony_ci	int n = kc->private_value;
4718c2ecf20Sopenharmony_ci	uc->value.enumerated.item[0] = spec->vol[n].ch1;
4728c2ecf20Sopenharmony_ci	return 0;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic void se200pci_cont_update(struct snd_ice1712 *ice, int n)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct se_spec *spec = ice->spec;
4788c2ecf20Sopenharmony_ci	switch (se200pci_cont[n].target) {
4798c2ecf20Sopenharmony_ci	case WM8766:
4808c2ecf20Sopenharmony_ci		se200pci_WM8766_set_volume(ice,
4818c2ecf20Sopenharmony_ci					   se200pci_cont[n].ch,
4828c2ecf20Sopenharmony_ci					   spec->vol[n].ch1,
4838c2ecf20Sopenharmony_ci					   spec->vol[n].ch2);
4848c2ecf20Sopenharmony_ci		break;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	case WM8776in:
4878c2ecf20Sopenharmony_ci		se200pci_WM8776_set_input_volume(ice,
4888c2ecf20Sopenharmony_ci						 spec->vol[n].ch1,
4898c2ecf20Sopenharmony_ci						 spec->vol[n].ch2);
4908c2ecf20Sopenharmony_ci		break;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	case WM8776out:
4938c2ecf20Sopenharmony_ci		se200pci_WM8776_set_output_volume(ice,
4948c2ecf20Sopenharmony_ci						  spec->vol[n].ch1,
4958c2ecf20Sopenharmony_ci						  spec->vol[n].ch2);
4968c2ecf20Sopenharmony_ci		break;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	case WM8776sel:
4998c2ecf20Sopenharmony_ci		se200pci_WM8776_set_input_selector(ice,
5008c2ecf20Sopenharmony_ci						   spec->vol[n].ch1);
5018c2ecf20Sopenharmony_ci		break;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	case WM8776agc:
5048c2ecf20Sopenharmony_ci		se200pci_WM8776_set_agc(ice, spec->vol[n].ch1);
5058c2ecf20Sopenharmony_ci		break;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	case WM8776afl:
5088c2ecf20Sopenharmony_ci		se200pci_WM8776_set_afl(ice, spec->vol[n].ch1);
5098c2ecf20Sopenharmony_ci		break;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	default:
5128c2ecf20Sopenharmony_ci		break;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic int se200pci_cont_volume_put(struct snd_kcontrol *kc,
5178c2ecf20Sopenharmony_ci				    struct snd_ctl_elem_value *uc)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
5208c2ecf20Sopenharmony_ci	struct se_spec *spec = ice->spec;
5218c2ecf20Sopenharmony_ci	int n = kc->private_value;
5228c2ecf20Sopenharmony_ci	unsigned int vol1, vol2;
5238c2ecf20Sopenharmony_ci	int changed;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	changed = 0;
5268c2ecf20Sopenharmony_ci	vol1 = uc->value.integer.value[0] & 0xff;
5278c2ecf20Sopenharmony_ci	vol2 = uc->value.integer.value[1] & 0xff;
5288c2ecf20Sopenharmony_ci	if (spec->vol[n].ch1 != vol1) {
5298c2ecf20Sopenharmony_ci		spec->vol[n].ch1 = vol1;
5308c2ecf20Sopenharmony_ci		changed = 1;
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci	if (spec->vol[n].ch2 != vol2) {
5338c2ecf20Sopenharmony_ci		spec->vol[n].ch2 = vol2;
5348c2ecf20Sopenharmony_ci		changed = 1;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci	if (changed)
5378c2ecf20Sopenharmony_ci		se200pci_cont_update(ice, n);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	return changed;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic int se200pci_cont_boolean_put(struct snd_kcontrol *kc,
5438c2ecf20Sopenharmony_ci				     struct snd_ctl_elem_value *uc)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
5468c2ecf20Sopenharmony_ci	struct se_spec *spec = ice->spec;
5478c2ecf20Sopenharmony_ci	int n = kc->private_value;
5488c2ecf20Sopenharmony_ci	unsigned int vol1;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	vol1 = !!uc->value.integer.value[0];
5518c2ecf20Sopenharmony_ci	if (spec->vol[n].ch1 != vol1) {
5528c2ecf20Sopenharmony_ci		spec->vol[n].ch1 = vol1;
5538c2ecf20Sopenharmony_ci		se200pci_cont_update(ice, n);
5548c2ecf20Sopenharmony_ci		return 1;
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci	return 0;
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cistatic int se200pci_cont_enum_put(struct snd_kcontrol *kc,
5608c2ecf20Sopenharmony_ci				  struct snd_ctl_elem_value *uc)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
5638c2ecf20Sopenharmony_ci	struct se_spec *spec = ice->spec;
5648c2ecf20Sopenharmony_ci	int n = kc->private_value;
5658c2ecf20Sopenharmony_ci	unsigned int vol1;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	vol1 = uc->value.enumerated.item[0];
5688c2ecf20Sopenharmony_ci	if (vol1 >= se200pci_get_enum_count(n))
5698c2ecf20Sopenharmony_ci		return -EINVAL;
5708c2ecf20Sopenharmony_ci	if (spec->vol[n].ch1 != vol1) {
5718c2ecf20Sopenharmony_ci		spec->vol[n].ch1 = vol1;
5728c2ecf20Sopenharmony_ci		se200pci_cont_update(ice, n);
5738c2ecf20Sopenharmony_ci		return 1;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci	return 0;
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1);
5798c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic int se200pci_add_controls(struct snd_ice1712 *ice)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	int i;
5848c2ecf20Sopenharmony_ci	struct snd_kcontrol_new cont;
5858c2ecf20Sopenharmony_ci	int err;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	memset(&cont, 0, sizeof(cont));
5888c2ecf20Sopenharmony_ci	cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
5898c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) {
5908c2ecf20Sopenharmony_ci		cont.private_value = i;
5918c2ecf20Sopenharmony_ci		cont.name = se200pci_cont[i].name;
5928c2ecf20Sopenharmony_ci		cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
5938c2ecf20Sopenharmony_ci		cont.tlv.p = NULL;
5948c2ecf20Sopenharmony_ci		switch (se200pci_cont[i].type) {
5958c2ecf20Sopenharmony_ci		case VOLUME1:
5968c2ecf20Sopenharmony_ci		case VOLUME2:
5978c2ecf20Sopenharmony_ci			cont.info = se200pci_cont_volume_info;
5988c2ecf20Sopenharmony_ci			cont.get = se200pci_cont_volume_get;
5998c2ecf20Sopenharmony_ci			cont.put = se200pci_cont_volume_put;
6008c2ecf20Sopenharmony_ci			cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
6018c2ecf20Sopenharmony_ci			if (se200pci_cont[i].type == VOLUME1)
6028c2ecf20Sopenharmony_ci				cont.tlv.p = db_scale_gain1;
6038c2ecf20Sopenharmony_ci			else
6048c2ecf20Sopenharmony_ci				cont.tlv.p = db_scale_gain2;
6058c2ecf20Sopenharmony_ci			break;
6068c2ecf20Sopenharmony_ci		case BOOLEAN:
6078c2ecf20Sopenharmony_ci			cont.info = se200pci_cont_boolean_info;
6088c2ecf20Sopenharmony_ci			cont.get = se200pci_cont_boolean_get;
6098c2ecf20Sopenharmony_ci			cont.put = se200pci_cont_boolean_put;
6108c2ecf20Sopenharmony_ci			break;
6118c2ecf20Sopenharmony_ci		case ENUM:
6128c2ecf20Sopenharmony_ci			cont.info = se200pci_cont_enum_info;
6138c2ecf20Sopenharmony_ci			cont.get = se200pci_cont_enum_get;
6148c2ecf20Sopenharmony_ci			cont.put = se200pci_cont_enum_put;
6158c2ecf20Sopenharmony_ci			break;
6168c2ecf20Sopenharmony_ci		default:
6178c2ecf20Sopenharmony_ci			snd_BUG();
6188c2ecf20Sopenharmony_ci			return -EINVAL;
6198c2ecf20Sopenharmony_ci		}
6208c2ecf20Sopenharmony_ci		err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice));
6218c2ecf20Sopenharmony_ci		if (err < 0)
6228c2ecf20Sopenharmony_ci			return err;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	return 0;
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci/****************************************************************************/
6308c2ecf20Sopenharmony_ci/*  ONKYO WAVIO SE-90PCI                                                    */
6318c2ecf20Sopenharmony_ci/****************************************************************************/
6328c2ecf20Sopenharmony_ci/*
6338c2ecf20Sopenharmony_ci *  system configuration ICE_EEP2_SYSCONF=0x4b
6348c2ecf20Sopenharmony_ci *  AC-Link configuration ICE_EEP2_ACLINK=0x80
6358c2ecf20Sopenharmony_ci *  I2S converters feature ICE_EEP2_I2S=0x78
6368c2ecf20Sopenharmony_ci *  S/PDIF configuration ICE_EEP2_SPDIF=0xc3
6378c2ecf20Sopenharmony_ci *
6388c2ecf20Sopenharmony_ci *  ** connected chip **
6398c2ecf20Sopenharmony_ci *
6408c2ecf20Sopenharmony_ci *   WM8716
6418c2ecf20Sopenharmony_ci *      A 2ch-DAC of main outputs.
6428c2ecf20Sopenharmony_ci *      It setuped as I2S mode by wire, so no way to setup from software.
6438c2ecf20Sopenharmony_ci *         ML/I2S (28pin) -- +5V
6448c2ecf20Sopenharmony_ci *         MC/DM1 (27pin) -- GND
6458c2ecf20Sopenharmony_ci *         MC/DM0 (26pin) -- GND
6468c2ecf20Sopenharmony_ci *         MUTEB  (25pin) -- open (internal pull-up)
6478c2ecf20Sopenharmony_ci *         MODE   (24pin) -- GND
6488c2ecf20Sopenharmony_ci *         CSBIWO (23pin) -- +5V
6498c2ecf20Sopenharmony_ci *
6508c2ecf20Sopenharmony_ci */
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci /* Nothing to do for this chip. */
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci/****************************************************************************/
6568c2ecf20Sopenharmony_ci/*  probe/initialize/setup                                                  */
6578c2ecf20Sopenharmony_ci/****************************************************************************/
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic int se_init(struct snd_ice1712 *ice)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	struct se_spec *spec;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
6648c2ecf20Sopenharmony_ci	if (!spec)
6658c2ecf20Sopenharmony_ci		return -ENOMEM;
6668c2ecf20Sopenharmony_ci	ice->spec = spec;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE90PCI) {
6698c2ecf20Sopenharmony_ci		ice->num_total_dacs = 2;
6708c2ecf20Sopenharmony_ci		ice->num_total_adcs = 0;
6718c2ecf20Sopenharmony_ci		ice->vt1720 = 1;
6728c2ecf20Sopenharmony_ci		return 0;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	} else if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) {
6758c2ecf20Sopenharmony_ci		ice->num_total_dacs = 8;
6768c2ecf20Sopenharmony_ci		ice->num_total_adcs = 2;
6778c2ecf20Sopenharmony_ci		se200pci_WM8740_init(ice);
6788c2ecf20Sopenharmony_ci		se200pci_WM8766_init(ice);
6798c2ecf20Sopenharmony_ci		se200pci_WM8776_init(ice);
6808c2ecf20Sopenharmony_ci		ice->gpio.set_pro_rate = se200pci_set_pro_rate;
6818c2ecf20Sopenharmony_ci		return 0;
6828c2ecf20Sopenharmony_ci	}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	return -ENOENT;
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cistatic int se_add_controls(struct snd_ice1712 *ice)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	int err;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	err = 0;
6928c2ecf20Sopenharmony_ci	/* nothing to do for VT1724_SUBDEVICE_SE90PCI */
6938c2ecf20Sopenharmony_ci	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI)
6948c2ecf20Sopenharmony_ci		err = se200pci_add_controls(ice);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	return err;
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci/****************************************************************************/
7018c2ecf20Sopenharmony_ci/*  entry point                                                             */
7028c2ecf20Sopenharmony_ci/****************************************************************************/
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic const unsigned char se200pci_eeprom[] = {
7058c2ecf20Sopenharmony_ci	[ICE_EEP2_SYSCONF]	= 0x4b,	/* 49.152Hz, spdif-in/ADC, 4DACs */
7068c2ecf20Sopenharmony_ci	[ICE_EEP2_ACLINK]	= 0x80,	/* I2S */
7078c2ecf20Sopenharmony_ci	[ICE_EEP2_I2S]		= 0x78,	/* 96k-ok, 24bit, 192k-ok */
7088c2ecf20Sopenharmony_ci	[ICE_EEP2_SPDIF]	= 0xc3,	/* out-en, out-int, spdif-in */
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_DIR]	= 0x02, /* WM8766 mute      1=output */
7118c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_DIR1]	= 0x00, /* not used */
7128c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_DIR2]	= 0x07, /* WM8766 ML/MC/MD  1=output */
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_MASK]	= 0x00, /* 0=writable */
7158c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_MASK1]	= 0x00, /* 0=writable */
7168c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_MASK2]	= 0x00, /* 0=writable */
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_STATE]	= 0x00, /* WM8766 mute=0 */
7198c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_STATE1]	= 0x00, /* not used */
7208c2ecf20Sopenharmony_ci	[ICE_EEP2_GPIO_STATE2]	= 0x07, /* WM8766 ML/MC/MD */
7218c2ecf20Sopenharmony_ci};
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_cistatic const unsigned char se90pci_eeprom[] = {
7248c2ecf20Sopenharmony_ci	[ICE_EEP2_SYSCONF]	= 0x4b,	/* 49.152Hz, spdif-in/ADC, 4DACs */
7258c2ecf20Sopenharmony_ci	[ICE_EEP2_ACLINK]	= 0x80,	/* I2S */
7268c2ecf20Sopenharmony_ci	[ICE_EEP2_I2S]		= 0x78,	/* 96k-ok, 24bit, 192k-ok */
7278c2ecf20Sopenharmony_ci	[ICE_EEP2_SPDIF]	= 0xc3,	/* out-en, out-int, spdif-in */
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	/* ALL GPIO bits are in input mode */
7308c2ecf20Sopenharmony_ci};
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_se_cards[] = {
7338c2ecf20Sopenharmony_ci	{
7348c2ecf20Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_SE200PCI,
7358c2ecf20Sopenharmony_ci		.name = "ONKYO SE200PCI",
7368c2ecf20Sopenharmony_ci		.model = "se200pci",
7378c2ecf20Sopenharmony_ci		.chip_init = se_init,
7388c2ecf20Sopenharmony_ci		.build_controls = se_add_controls,
7398c2ecf20Sopenharmony_ci		.eeprom_size = sizeof(se200pci_eeprom),
7408c2ecf20Sopenharmony_ci		.eeprom_data = se200pci_eeprom,
7418c2ecf20Sopenharmony_ci	},
7428c2ecf20Sopenharmony_ci	{
7438c2ecf20Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_SE90PCI,
7448c2ecf20Sopenharmony_ci		.name = "ONKYO SE90PCI",
7458c2ecf20Sopenharmony_ci		.model = "se90pci",
7468c2ecf20Sopenharmony_ci		.chip_init = se_init,
7478c2ecf20Sopenharmony_ci		.build_controls = se_add_controls,
7488c2ecf20Sopenharmony_ci		.eeprom_size = sizeof(se90pci_eeprom),
7498c2ecf20Sopenharmony_ci		.eeprom_data = se90pci_eeprom,
7508c2ecf20Sopenharmony_ci	},
7518c2ecf20Sopenharmony_ci	{} /*terminator*/
7528c2ecf20Sopenharmony_ci};
753