xref: /openbmc/linux/sound/pci/oxygen/oxygen.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1*9c9cf6beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d0ce9946SClemens Ladisch /*
3873591dbSClemens Ladisch  * C-Media CMI8788 driver for C-Media's reference design and similar models
4d0ce9946SClemens Ladisch  *
5d0ce9946SClemens Ladisch  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
6d0ce9946SClemens Ladisch  */
7d0ce9946SClemens Ladisch 
8d0ce9946SClemens Ladisch /*
9dc0adf48SClemens Ladisch  * CMI8788:
10dc0adf48SClemens Ladisch  *
11d0ce9946SClemens Ladisch  *   SPI 0 -> 1st AK4396 (front)
127113e958SClemens Ladisch  *   SPI 1 -> 2nd AK4396 (surround)
13d0ce9946SClemens Ladisch  *   SPI 2 -> 3rd AK4396 (center/LFE)
14d0ce9946SClemens Ladisch  *   SPI 3 -> WM8785
157113e958SClemens Ladisch  *   SPI 4 -> 4th AK4396 (back)
16d0ce9946SClemens Ladisch  *
17d0ce9946SClemens Ladisch  *   GPIO 0 -> DFS0 of AK5385
18d0ce9946SClemens Ladisch  *   GPIO 1 -> DFS1 of AK5385
1964878dfbSClemens Ladisch  *
2064878dfbSClemens Ladisch  * X-Meridian models:
2164878dfbSClemens Ladisch  *   GPIO 4 -> enable extension S/PDIF input
2264878dfbSClemens Ladisch  *   GPIO 6 -> enable on-board S/PDIF input
2364878dfbSClemens Ladisch  *
2464878dfbSClemens Ladisch  * Claro models:
25d1d7093fSClemens Ladisch  *   GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input
2664878dfbSClemens Ladisch  *   GPIO 8 -> enable headphone amplifier
27dc0adf48SClemens Ladisch  *
28dc0adf48SClemens Ladisch  * CM9780:
29dc0adf48SClemens Ladisch  *
30de664936SClemens Ladisch  *   LINE_OUT -> input of ADC
31de664936SClemens Ladisch  *
32de664936SClemens Ladisch  *   AUX_IN <- aux
33de664936SClemens Ladisch  *   CD_IN  <- CD
34de664936SClemens Ladisch  *   MIC_IN <- mic
35de664936SClemens Ladisch  *
36dc0adf48SClemens Ladisch  *   GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
37d0ce9946SClemens Ladisch  */
38d0ce9946SClemens Ladisch 
39df91bc23SClemens Ladisch #include <linux/delay.h>
40902b05c1SClemens Ladisch #include <linux/mutex.h>
41d0ce9946SClemens Ladisch #include <linux/pci.h>
42da155d5bSPaul Gortmaker #include <linux/module.h>
43902b05c1SClemens Ladisch #include <sound/ac97_codec.h>
44ccc80fb4SClemens Ladisch #include <sound/control.h>
45d0ce9946SClemens Ladisch #include <sound/core.h>
469719fcaaSClemens Ladisch #include <sound/info.h>
47d0ce9946SClemens Ladisch #include <sound/initval.h>
48d0ce9946SClemens Ladisch #include <sound/pcm.h>
49d0ce9946SClemens Ladisch #include <sound/pcm_params.h>
50d0ce9946SClemens Ladisch #include <sound/tlv.h>
51d0ce9946SClemens Ladisch #include "oxygen.h"
5266410bfdSClemens Ladisch #include "xonar_dg.h"
53c626026dSClemens Ladisch #include "ak4396.h"
54f5b2368bSClemens Ladisch #include "wm8785.h"
55d0ce9946SClemens Ladisch 
56d0ce9946SClemens Ladisch MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
57d0ce9946SClemens Ladisch MODULE_DESCRIPTION("C-Media CMI8788 driver");
58d023dc0aSClemens Ladisch MODULE_LICENSE("GPL v2");
59d0ce9946SClemens Ladisch 
60d0ce9946SClemens Ladisch static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
61d0ce9946SClemens Ladisch static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
62a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
63d0ce9946SClemens Ladisch 
64d0ce9946SClemens Ladisch module_param_array(index, int, NULL, 0444);
65d0ce9946SClemens Ladisch MODULE_PARM_DESC(index, "card index");
66d0ce9946SClemens Ladisch module_param_array(id, charp, NULL, 0444);
67d0ce9946SClemens Ladisch MODULE_PARM_DESC(id, "ID string");
68d0ce9946SClemens Ladisch module_param_array(enable, bool, NULL, 0444);
69d0ce9946SClemens Ladisch MODULE_PARM_DESC(enable, "enable card");
70d0ce9946SClemens Ladisch 
712f1b0ec7SClemens Ladisch enum {
7218f24839SClemens Ladisch 	MODEL_CMEDIA_REF,
7318f24839SClemens Ladisch 	MODEL_MERIDIAN,
74a4b16969SClemens Ladisch 	MODEL_MERIDIAN_2G,
7518f24839SClemens Ladisch 	MODEL_CLARO,
7618f24839SClemens Ladisch 	MODEL_CLARO_HALO,
772146dcfdSClemens Ladisch 	MODEL_FANTASIA,
78a4b16969SClemens Ladisch 	MODEL_SERENADE,
792146dcfdSClemens Ladisch 	MODEL_2CH_OUTPUT,
80a4b16969SClemens Ladisch 	MODEL_HG2PCI,
8166410bfdSClemens Ladisch 	MODEL_XONAR_DG,
8276bc7a0dSClemens Ladisch 	MODEL_XONAR_DGX,
832f1b0ec7SClemens Ladisch };
842f1b0ec7SClemens Ladisch 
859baa3c34SBenoit Taine static const struct pci_device_id oxygen_ids[] = {
8618f24839SClemens Ladisch 	/* C-Media's reference design */
872f1b0ec7SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF },
888c50b759SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF },
892f1b0ec7SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF },
902f1b0ec7SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF },
912f1b0ec7SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
922f1b0ec7SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
932f1b0ec7SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
942f1b0ec7SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
9518f24839SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
9666410bfdSClemens Ladisch 	/* Asus Xonar DG */
9766410bfdSClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG },
9876bc7a0dSClemens Ladisch 	/* Asus Xonar DGX */
9976bc7a0dSClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x1043, 0x8521), .driver_data = MODEL_XONAR_DGX },
1008c50b759SClemens Ladisch 	/* PCI 2.0 HD Audio */
1018c50b759SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT },
10218f24839SClemens Ladisch 	/* Kuroutoshikou CMI8787-HG2PCI */
103a4b16969SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI },
10418f24839SClemens Ladisch 	/* TempoTec HiFier Fantasia */
1052146dcfdSClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_FANTASIA },
1062146dcfdSClemens Ladisch 	/* TempoTec HiFier Serenade */
107a4b16969SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_SERENADE },
10818f24839SClemens Ladisch 	/* AuzenTech X-Meridian */
1092f1b0ec7SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
1108443d2ebSClemens Ladisch 	/* AuzenTech X-Meridian 2G */
111a4b16969SClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN_2G },
11218f24839SClemens Ladisch 	/* HT-Omega Claro */
113873591dbSClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
11418f24839SClemens Ladisch 	/* HT-Omega Claro halo */
115873591dbSClemens Ladisch 	{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO },
116d0ce9946SClemens Ladisch 	{ }
117d0ce9946SClemens Ladisch };
118d0ce9946SClemens Ladisch MODULE_DEVICE_TABLE(pci, oxygen_ids);
119d0ce9946SClemens Ladisch 
120878ac3eeSClemens Ladisch 
121878ac3eeSClemens Ladisch #define GPIO_AK5385_DFS_MASK	0x0003
122878ac3eeSClemens Ladisch #define GPIO_AK5385_DFS_NORMAL	0x0000
123878ac3eeSClemens Ladisch #define GPIO_AK5385_DFS_DOUBLE	0x0001
124878ac3eeSClemens Ladisch #define GPIO_AK5385_DFS_QUAD	0x0002
125878ac3eeSClemens Ladisch 
12664878dfbSClemens Ladisch #define GPIO_MERIDIAN_DIG_MASK	0x0050
12764878dfbSClemens Ladisch #define GPIO_MERIDIAN_DIG_EXT	0x0010
12864878dfbSClemens Ladisch #define GPIO_MERIDIAN_DIG_BOARD	0x0040
12964878dfbSClemens Ladisch 
130d1d7093fSClemens Ladisch #define GPIO_CLARO_DIG_COAX	0x0040
131873591dbSClemens Ladisch #define GPIO_CLARO_HP		0x0100
132873591dbSClemens Ladisch 
1337ef37cd9SClemens Ladisch struct generic_data {
13445c1de8eSClemens Ladisch 	unsigned int dacs;
1356f0de3ceSClemens Ladisch 	u8 ak4396_regs[4][5];
1361ff04886SClemens Ladisch 	u16 wm8785_regs[3];
1377ef37cd9SClemens Ladisch };
1387ef37cd9SClemens Ladisch 
ak4396_write(struct oxygen * chip,unsigned int codec,u8 reg,u8 value)139d0ce9946SClemens Ladisch static void ak4396_write(struct oxygen *chip, unsigned int codec,
140d0ce9946SClemens Ladisch 			 u8 reg, u8 value)
141d0ce9946SClemens Ladisch {
142d0ce9946SClemens Ladisch 	/* maps ALSA channel pair number to SPI output */
143d0ce9946SClemens Ladisch 	static const u8 codec_spi_map[4] = {
1447113e958SClemens Ladisch 		0, 1, 2, 4
145d0ce9946SClemens Ladisch 	};
1466f0de3ceSClemens Ladisch 	struct generic_data *data = chip->model_data;
1476f0de3ceSClemens Ladisch 
148c2353a08SClemens Ladisch 	oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
149d0ce9946SClemens Ladisch 			 OXYGEN_SPI_DATA_LENGTH_2 |
1502ea85986SClemens Ladisch 			 OXYGEN_SPI_CLOCK_160 |
151d0ce9946SClemens Ladisch 			 (codec_spi_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
152c2353a08SClemens Ladisch 			 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
153d0ce9946SClemens Ladisch 			 AK4396_WRITE | (reg << 8) | value);
1546f0de3ceSClemens Ladisch 	data->ak4396_regs[codec][reg] = value;
1556f0de3ceSClemens Ladisch }
1566f0de3ceSClemens Ladisch 
ak4396_write_cached(struct oxygen * chip,unsigned int codec,u8 reg,u8 value)1576f0de3ceSClemens Ladisch static void ak4396_write_cached(struct oxygen *chip, unsigned int codec,
1586f0de3ceSClemens Ladisch 				u8 reg, u8 value)
1596f0de3ceSClemens Ladisch {
1606f0de3ceSClemens Ladisch 	struct generic_data *data = chip->model_data;
1616f0de3ceSClemens Ladisch 
1626f0de3ceSClemens Ladisch 	if (value != data->ak4396_regs[codec][reg])
1636f0de3ceSClemens Ladisch 		ak4396_write(chip, codec, reg, value);
164d0ce9946SClemens Ladisch }
165d0ce9946SClemens Ladisch 
wm8785_write(struct oxygen * chip,u8 reg,unsigned int value)166d0ce9946SClemens Ladisch static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value)
167d0ce9946SClemens Ladisch {
168e58aee95SClemens Ladisch 	struct generic_data *data = chip->model_data;
169e58aee95SClemens Ladisch 
170c2353a08SClemens Ladisch 	oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
171d0ce9946SClemens Ladisch 			 OXYGEN_SPI_DATA_LENGTH_2 |
1722ea85986SClemens Ladisch 			 OXYGEN_SPI_CLOCK_160 |
173c2353a08SClemens Ladisch 			 (3 << OXYGEN_SPI_CODEC_SHIFT) |
174c2353a08SClemens Ladisch 			 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
175d0ce9946SClemens Ladisch 			 (reg << 9) | value);
1766f0de3ceSClemens Ladisch 	if (reg < ARRAY_SIZE(data->wm8785_regs))
1776f0de3ceSClemens Ladisch 		data->wm8785_regs[reg] = value;
178bbbfb552SClemens Ladisch }
179bbbfb552SClemens Ladisch 
ak4396_registers_init(struct oxygen * chip)18075146fc0SClemens Ladisch static void ak4396_registers_init(struct oxygen *chip)
181d0ce9946SClemens Ladisch {
1827ef37cd9SClemens Ladisch 	struct generic_data *data = chip->model_data;
183d0ce9946SClemens Ladisch 	unsigned int i;
184d0ce9946SClemens Ladisch 
18545c1de8eSClemens Ladisch 	for (i = 0; i < data->dacs; ++i) {
1866f0de3ceSClemens Ladisch 		ak4396_write(chip, i, AK4396_CONTROL_1,
1876f0de3ceSClemens Ladisch 			     AK4396_DIF_24_MSB | AK4396_RSTN);
1886f0de3ceSClemens Ladisch 		ak4396_write(chip, i, AK4396_CONTROL_2,
1896f0de3ceSClemens Ladisch 			     data->ak4396_regs[0][AK4396_CONTROL_2]);
1906f0de3ceSClemens Ladisch 		ak4396_write(chip, i, AK4396_CONTROL_3,
1916f0de3ceSClemens Ladisch 			     AK4396_PCM);
1926f0de3ceSClemens Ladisch 		ak4396_write(chip, i, AK4396_LCH_ATT,
1936f0de3ceSClemens Ladisch 			     chip->dac_volume[i * 2]);
1946f0de3ceSClemens Ladisch 		ak4396_write(chip, i, AK4396_RCH_ATT,
1956f0de3ceSClemens Ladisch 			     chip->dac_volume[i * 2 + 1]);
196d0ce9946SClemens Ladisch 	}
19775146fc0SClemens Ladisch }
19875146fc0SClemens Ladisch 
ak4396_init(struct oxygen * chip)19975146fc0SClemens Ladisch static void ak4396_init(struct oxygen *chip)
20075146fc0SClemens Ladisch {
20175146fc0SClemens Ladisch 	struct generic_data *data = chip->model_data;
20275146fc0SClemens Ladisch 
2031f4d7be7SClemens Ladisch 	data->dacs = chip->model.dac_channels_pcm / 2;
2046f0de3ceSClemens Ladisch 	data->ak4396_regs[0][AK4396_CONTROL_2] =
2056f0de3ceSClemens Ladisch 		AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
20675146fc0SClemens Ladisch 	ak4396_registers_init(chip);
207d0ce9946SClemens Ladisch 	snd_component_add(chip->card, "AK4396");
208d0ce9946SClemens Ladisch }
209d0ce9946SClemens Ladisch 
ak5385_init(struct oxygen * chip)210d0ce9946SClemens Ladisch static void ak5385_init(struct oxygen *chip)
211d0ce9946SClemens Ladisch {
212878ac3eeSClemens Ladisch 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_AK5385_DFS_MASK);
213878ac3eeSClemens Ladisch 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_AK5385_DFS_MASK);
214d0ce9946SClemens Ladisch 	snd_component_add(chip->card, "AK5385");
215d0ce9946SClemens Ladisch }
216d0ce9946SClemens Ladisch 
wm8785_registers_init(struct oxygen * chip)21775146fc0SClemens Ladisch static void wm8785_registers_init(struct oxygen *chip)
21875146fc0SClemens Ladisch {
21975146fc0SClemens Ladisch 	struct generic_data *data = chip->model_data;
22075146fc0SClemens Ladisch 
22175146fc0SClemens Ladisch 	wm8785_write(chip, WM8785_R7, 0);
2226f0de3ceSClemens Ladisch 	wm8785_write(chip, WM8785_R0, data->wm8785_regs[0]);
2231ff04886SClemens Ladisch 	wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]);
22475146fc0SClemens Ladisch }
22575146fc0SClemens Ladisch 
wm8785_init(struct oxygen * chip)226d0ce9946SClemens Ladisch static void wm8785_init(struct oxygen *chip)
227d0ce9946SClemens Ladisch {
228e58aee95SClemens Ladisch 	struct generic_data *data = chip->model_data;
229e58aee95SClemens Ladisch 
2306f0de3ceSClemens Ladisch 	data->wm8785_regs[0] =
2316f0de3ceSClemens Ladisch 		WM8785_MCR_SLAVE | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST;
2321ff04886SClemens Ladisch 	data->wm8785_regs[2] = WM8785_HPFR | WM8785_HPFL;
23375146fc0SClemens Ladisch 	wm8785_registers_init(chip);
234d0ce9946SClemens Ladisch 	snd_component_add(chip->card, "WM8785");
235d0ce9946SClemens Ladisch }
236d0ce9946SClemens Ladisch 
generic_init(struct oxygen * chip)237d0ce9946SClemens Ladisch static void generic_init(struct oxygen *chip)
238d0ce9946SClemens Ladisch {
239d0ce9946SClemens Ladisch 	ak4396_init(chip);
240d0ce9946SClemens Ladisch 	wm8785_init(chip);
241d0ce9946SClemens Ladisch }
242d0ce9946SClemens Ladisch 
meridian_init(struct oxygen * chip)243d0ce9946SClemens Ladisch static void meridian_init(struct oxygen *chip)
244d0ce9946SClemens Ladisch {
24564878dfbSClemens Ladisch 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
24664878dfbSClemens Ladisch 			  GPIO_MERIDIAN_DIG_MASK);
24764878dfbSClemens Ladisch 	oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
24864878dfbSClemens Ladisch 			      GPIO_MERIDIAN_DIG_BOARD, GPIO_MERIDIAN_DIG_MASK);
249d0ce9946SClemens Ladisch 	ak4396_init(chip);
250d0ce9946SClemens Ladisch 	ak5385_init(chip);
251d0ce9946SClemens Ladisch }
252d0ce9946SClemens Ladisch 
claro_enable_hp(struct oxygen * chip)253873591dbSClemens Ladisch static void claro_enable_hp(struct oxygen *chip)
254873591dbSClemens Ladisch {
255873591dbSClemens Ladisch 	msleep(300);
256873591dbSClemens Ladisch 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_HP);
257873591dbSClemens Ladisch 	oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
258873591dbSClemens Ladisch }
259873591dbSClemens Ladisch 
claro_init(struct oxygen * chip)260873591dbSClemens Ladisch static void claro_init(struct oxygen *chip)
261873591dbSClemens Ladisch {
262d1d7093fSClemens Ladisch 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
263d1d7093fSClemens Ladisch 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
264873591dbSClemens Ladisch 	ak4396_init(chip);
265873591dbSClemens Ladisch 	wm8785_init(chip);
266873591dbSClemens Ladisch 	claro_enable_hp(chip);
267873591dbSClemens Ladisch }
268873591dbSClemens Ladisch 
claro_halo_init(struct oxygen * chip)269873591dbSClemens Ladisch static void claro_halo_init(struct oxygen *chip)
270d91b424dSClemens Ladisch {
271d1d7093fSClemens Ladisch 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
272d1d7093fSClemens Ladisch 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
273d91b424dSClemens Ladisch 	ak4396_init(chip);
274d91b424dSClemens Ladisch 	ak5385_init(chip);
275873591dbSClemens Ladisch 	claro_enable_hp(chip);
276d91b424dSClemens Ladisch }
277d91b424dSClemens Ladisch 
fantasia_init(struct oxygen * chip)2782146dcfdSClemens Ladisch static void fantasia_init(struct oxygen *chip)
27945c1de8eSClemens Ladisch {
28045c1de8eSClemens Ladisch 	ak4396_init(chip);
28145c1de8eSClemens Ladisch 	snd_component_add(chip->card, "CS5340");
28245c1de8eSClemens Ladisch }
28345c1de8eSClemens Ladisch 
stereo_output_init(struct oxygen * chip)2842146dcfdSClemens Ladisch static void stereo_output_init(struct oxygen *chip)
28531f86bacSClemens Ladisch {
28631f86bacSClemens Ladisch 	ak4396_init(chip);
28731f86bacSClemens Ladisch }
28831f86bacSClemens Ladisch 
generic_cleanup(struct oxygen * chip)289d0ce9946SClemens Ladisch static void generic_cleanup(struct oxygen *chip)
290d0ce9946SClemens Ladisch {
291d0ce9946SClemens Ladisch }
292d0ce9946SClemens Ladisch 
claro_disable_hp(struct oxygen * chip)293873591dbSClemens Ladisch static void claro_disable_hp(struct oxygen *chip)
294873591dbSClemens Ladisch {
295873591dbSClemens Ladisch 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
296873591dbSClemens Ladisch }
297873591dbSClemens Ladisch 
claro_cleanup(struct oxygen * chip)298873591dbSClemens Ladisch static void claro_cleanup(struct oxygen *chip)
299873591dbSClemens Ladisch {
300873591dbSClemens Ladisch 	claro_disable_hp(chip);
301873591dbSClemens Ladisch }
302873591dbSClemens Ladisch 
claro_suspend(struct oxygen * chip)303873591dbSClemens Ladisch static void claro_suspend(struct oxygen *chip)
304873591dbSClemens Ladisch {
305873591dbSClemens Ladisch 	claro_disable_hp(chip);
306873591dbSClemens Ladisch }
307873591dbSClemens Ladisch 
generic_resume(struct oxygen * chip)3084a4bc53bSClemens Ladisch static void generic_resume(struct oxygen *chip)
3094a4bc53bSClemens Ladisch {
3104a4bc53bSClemens Ladisch 	ak4396_registers_init(chip);
3114a4bc53bSClemens Ladisch 	wm8785_registers_init(chip);
3124a4bc53bSClemens Ladisch }
3134a4bc53bSClemens Ladisch 
meridian_resume(struct oxygen * chip)314c2bc4ff5SClemens Ladisch static void meridian_resume(struct oxygen *chip)
315c2bc4ff5SClemens Ladisch {
316c2bc4ff5SClemens Ladisch 	ak4396_registers_init(chip);
317c2bc4ff5SClemens Ladisch }
318c2bc4ff5SClemens Ladisch 
claro_resume(struct oxygen * chip)319873591dbSClemens Ladisch static void claro_resume(struct oxygen *chip)
320d91b424dSClemens Ladisch {
321d91b424dSClemens Ladisch 	ak4396_registers_init(chip);
322873591dbSClemens Ladisch 	claro_enable_hp(chip);
323d91b424dSClemens Ladisch }
324d91b424dSClemens Ladisch 
stereo_resume(struct oxygen * chip)32545c1de8eSClemens Ladisch static void stereo_resume(struct oxygen *chip)
32645c1de8eSClemens Ladisch {
32745c1de8eSClemens Ladisch 	ak4396_registers_init(chip);
32845c1de8eSClemens Ladisch }
32945c1de8eSClemens Ladisch 
set_ak4396_params(struct oxygen * chip,struct snd_pcm_hw_params * params)330d0ce9946SClemens Ladisch static void set_ak4396_params(struct oxygen *chip,
331d0ce9946SClemens Ladisch 			      struct snd_pcm_hw_params *params)
332d0ce9946SClemens Ladisch {
3337ef37cd9SClemens Ladisch 	struct generic_data *data = chip->model_data;
334d0ce9946SClemens Ladisch 	unsigned int i;
335d0ce9946SClemens Ladisch 	u8 value;
336d0ce9946SClemens Ladisch 
3376f0de3ceSClemens Ladisch 	value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
338d0ce9946SClemens Ladisch 	if (params_rate(params) <= 54000)
339d0ce9946SClemens Ladisch 		value |= AK4396_DFS_NORMAL;
340236c4920SClemens Ladisch 	else if (params_rate(params) <= 108000)
341d0ce9946SClemens Ladisch 		value |= AK4396_DFS_DOUBLE;
342d0ce9946SClemens Ladisch 	else
343d0ce9946SClemens Ladisch 		value |= AK4396_DFS_QUAD;
344df91bc23SClemens Ladisch 
345df91bc23SClemens Ladisch 	msleep(1); /* wait for the new MCLK to become stable */
346df91bc23SClemens Ladisch 
3476f0de3ceSClemens Ladisch 	if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) {
34845c1de8eSClemens Ladisch 		for (i = 0; i < data->dacs; ++i) {
3496f0de3ceSClemens Ladisch 			ak4396_write(chip, i, AK4396_CONTROL_1,
3506f0de3ceSClemens Ladisch 				     AK4396_DIF_24_MSB);
3516f0de3ceSClemens Ladisch 			ak4396_write(chip, i, AK4396_CONTROL_2, value);
3526f0de3ceSClemens Ladisch 			ak4396_write(chip, i, AK4396_CONTROL_1,
3536f0de3ceSClemens Ladisch 				     AK4396_DIF_24_MSB | AK4396_RSTN);
3546f0de3ceSClemens Ladisch 		}
3556f0de3ceSClemens Ladisch 	}
3566f0de3ceSClemens Ladisch }
3576f0de3ceSClemens Ladisch 
update_ak4396_volume(struct oxygen * chip)3586f0de3ceSClemens Ladisch static void update_ak4396_volume(struct oxygen *chip)
3596f0de3ceSClemens Ladisch {
36045c1de8eSClemens Ladisch 	struct generic_data *data = chip->model_data;
3616f0de3ceSClemens Ladisch 	unsigned int i;
3626f0de3ceSClemens Ladisch 
36345c1de8eSClemens Ladisch 	for (i = 0; i < data->dacs; ++i) {
3646f0de3ceSClemens Ladisch 		ak4396_write_cached(chip, i, AK4396_LCH_ATT,
3656f0de3ceSClemens Ladisch 				    chip->dac_volume[i * 2]);
3666f0de3ceSClemens Ladisch 		ak4396_write_cached(chip, i, AK4396_RCH_ATT,
3676f0de3ceSClemens Ladisch 				    chip->dac_volume[i * 2 + 1]);
368d0ce9946SClemens Ladisch 	}
369d0ce9946SClemens Ladisch }
370d0ce9946SClemens Ladisch 
update_ak4396_mute(struct oxygen * chip)371d0ce9946SClemens Ladisch static void update_ak4396_mute(struct oxygen *chip)
372d0ce9946SClemens Ladisch {
3737ef37cd9SClemens Ladisch 	struct generic_data *data = chip->model_data;
374d0ce9946SClemens Ladisch 	unsigned int i;
375d0ce9946SClemens Ladisch 	u8 value;
376d0ce9946SClemens Ladisch 
3776f0de3ceSClemens Ladisch 	value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE;
378d0ce9946SClemens Ladisch 	if (chip->dac_mute)
379d0ce9946SClemens Ladisch 		value |= AK4396_SMUTE;
38045c1de8eSClemens Ladisch 	for (i = 0; i < data->dacs; ++i)
3816f0de3ceSClemens Ladisch 		ak4396_write_cached(chip, i, AK4396_CONTROL_2, value);
382d0ce9946SClemens Ladisch }
383d0ce9946SClemens Ladisch 
set_wm8785_params(struct oxygen * chip,struct snd_pcm_hw_params * params)384d0ce9946SClemens Ladisch static void set_wm8785_params(struct oxygen *chip,
385d0ce9946SClemens Ladisch 			      struct snd_pcm_hw_params *params)
386d0ce9946SClemens Ladisch {
3876f0de3ceSClemens Ladisch 	struct generic_data *data = chip->model_data;
388d0ce9946SClemens Ladisch 	unsigned int value;
389d0ce9946SClemens Ladisch 
390878ac3eeSClemens Ladisch 	value = WM8785_MCR_SLAVE | WM8785_FORMAT_LJUST;
39171e22a4bSClemens Ladisch 	if (params_rate(params) <= 48000)
392d0ce9946SClemens Ladisch 		value |= WM8785_OSR_SINGLE;
39371e22a4bSClemens Ladisch 	else if (params_rate(params) <= 96000)
39471e22a4bSClemens Ladisch 		value |= WM8785_OSR_DOUBLE;
39571e22a4bSClemens Ladisch 	else
39671e22a4bSClemens Ladisch 		value |= WM8785_OSR_QUAD;
3976f0de3ceSClemens Ladisch 	if (value != data->wm8785_regs[0]) {
3986f0de3ceSClemens Ladisch 		wm8785_write(chip, WM8785_R7, 0);
399878ac3eeSClemens Ladisch 		wm8785_write(chip, WM8785_R0, value);
4001ff04886SClemens Ladisch 		wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]);
4016f0de3ceSClemens Ladisch 	}
402d0ce9946SClemens Ladisch }
403d0ce9946SClemens Ladisch 
set_ak5385_params(struct oxygen * chip,struct snd_pcm_hw_params * params)404d0ce9946SClemens Ladisch static void set_ak5385_params(struct oxygen *chip,
405d0ce9946SClemens Ladisch 			      struct snd_pcm_hw_params *params)
406d0ce9946SClemens Ladisch {
407d0ce9946SClemens Ladisch 	unsigned int value;
408d0ce9946SClemens Ladisch 
409d0ce9946SClemens Ladisch 	if (params_rate(params) <= 54000)
410878ac3eeSClemens Ladisch 		value = GPIO_AK5385_DFS_NORMAL;
411d0ce9946SClemens Ladisch 	else if (params_rate(params) <= 108000)
412878ac3eeSClemens Ladisch 		value = GPIO_AK5385_DFS_DOUBLE;
413d0ce9946SClemens Ladisch 	else
414878ac3eeSClemens Ladisch 		value = GPIO_AK5385_DFS_QUAD;
415878ac3eeSClemens Ladisch 	oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
416878ac3eeSClemens Ladisch 			      value, GPIO_AK5385_DFS_MASK);
417d0ce9946SClemens Ladisch }
418d0ce9946SClemens Ladisch 
set_no_params(struct oxygen * chip,struct snd_pcm_hw_params * params)41945c1de8eSClemens Ladisch static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params)
42045c1de8eSClemens Ladisch {
42145c1de8eSClemens Ladisch }
42245c1de8eSClemens Ladisch 
rolloff_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)4234852ad02SClemens Ladisch static int rolloff_info(struct snd_kcontrol *ctl,
4244852ad02SClemens Ladisch 			struct snd_ctl_elem_info *info)
4254852ad02SClemens Ladisch {
4264852ad02SClemens Ladisch 	static const char *const names[2] = {
4274852ad02SClemens Ladisch 		"Sharp Roll-off", "Slow Roll-off"
4284852ad02SClemens Ladisch 	};
4294852ad02SClemens Ladisch 
4309600732bSClemens Ladisch 	return snd_ctl_enum_info(info, 1, 2, names);
4314852ad02SClemens Ladisch }
4324852ad02SClemens Ladisch 
rolloff_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)4334852ad02SClemens Ladisch static int rolloff_get(struct snd_kcontrol *ctl,
4344852ad02SClemens Ladisch 		       struct snd_ctl_elem_value *value)
4354852ad02SClemens Ladisch {
4364852ad02SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
4374852ad02SClemens Ladisch 	struct generic_data *data = chip->model_data;
4384852ad02SClemens Ladisch 
4394852ad02SClemens Ladisch 	value->value.enumerated.item[0] =
4404852ad02SClemens Ladisch 		(data->ak4396_regs[0][AK4396_CONTROL_2] & AK4396_SLOW) != 0;
4414852ad02SClemens Ladisch 	return 0;
4424852ad02SClemens Ladisch }
4434852ad02SClemens Ladisch 
rolloff_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)4444852ad02SClemens Ladisch static int rolloff_put(struct snd_kcontrol *ctl,
4454852ad02SClemens Ladisch 		       struct snd_ctl_elem_value *value)
4464852ad02SClemens Ladisch {
4474852ad02SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
4484852ad02SClemens Ladisch 	struct generic_data *data = chip->model_data;
4494852ad02SClemens Ladisch 	unsigned int i;
4504852ad02SClemens Ladisch 	int changed;
4514852ad02SClemens Ladisch 	u8 reg;
4524852ad02SClemens Ladisch 
4534852ad02SClemens Ladisch 	mutex_lock(&chip->mutex);
4544852ad02SClemens Ladisch 	reg = data->ak4396_regs[0][AK4396_CONTROL_2];
4554852ad02SClemens Ladisch 	if (value->value.enumerated.item[0])
4564852ad02SClemens Ladisch 		reg |= AK4396_SLOW;
4574852ad02SClemens Ladisch 	else
4584852ad02SClemens Ladisch 		reg &= ~AK4396_SLOW;
4594852ad02SClemens Ladisch 	changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2];
4604852ad02SClemens Ladisch 	if (changed) {
46145c1de8eSClemens Ladisch 		for (i = 0; i < data->dacs; ++i)
4624852ad02SClemens Ladisch 			ak4396_write(chip, i, AK4396_CONTROL_2, reg);
4634852ad02SClemens Ladisch 	}
4644852ad02SClemens Ladisch 	mutex_unlock(&chip->mutex);
4654852ad02SClemens Ladisch 	return changed;
4664852ad02SClemens Ladisch }
4674852ad02SClemens Ladisch 
4684852ad02SClemens Ladisch static const struct snd_kcontrol_new rolloff_control = {
4694852ad02SClemens Ladisch 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4704852ad02SClemens Ladisch 	.name = "DAC Filter Playback Enum",
4714852ad02SClemens Ladisch 	.info = rolloff_info,
4724852ad02SClemens Ladisch 	.get = rolloff_get,
4734852ad02SClemens Ladisch 	.put = rolloff_put,
4744852ad02SClemens Ladisch };
4754852ad02SClemens Ladisch 
hpf_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)4761ff04886SClemens Ladisch static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
4771ff04886SClemens Ladisch {
4781ff04886SClemens Ladisch 	static const char *const names[2] = {
4791ff04886SClemens Ladisch 		"None", "High-pass Filter"
4801ff04886SClemens Ladisch 	};
4811ff04886SClemens Ladisch 
4829600732bSClemens Ladisch 	return snd_ctl_enum_info(info, 1, 2, names);
4831ff04886SClemens Ladisch }
4841ff04886SClemens Ladisch 
hpf_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)4851ff04886SClemens Ladisch static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
4861ff04886SClemens Ladisch {
4871ff04886SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
4881ff04886SClemens Ladisch 	struct generic_data *data = chip->model_data;
4891ff04886SClemens Ladisch 
4901ff04886SClemens Ladisch 	value->value.enumerated.item[0] =
4911ff04886SClemens Ladisch 		(data->wm8785_regs[WM8785_R2] & WM8785_HPFR) != 0;
4921ff04886SClemens Ladisch 	return 0;
4931ff04886SClemens Ladisch }
4941ff04886SClemens Ladisch 
hpf_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)4951ff04886SClemens Ladisch static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
4961ff04886SClemens Ladisch {
4971ff04886SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
4981ff04886SClemens Ladisch 	struct generic_data *data = chip->model_data;
4991ff04886SClemens Ladisch 	unsigned int reg;
5001ff04886SClemens Ladisch 	int changed;
5011ff04886SClemens Ladisch 
5021ff04886SClemens Ladisch 	mutex_lock(&chip->mutex);
5031ff04886SClemens Ladisch 	reg = data->wm8785_regs[WM8785_R2] & ~(WM8785_HPFR | WM8785_HPFL);
5041ff04886SClemens Ladisch 	if (value->value.enumerated.item[0])
5051ff04886SClemens Ladisch 		reg |= WM8785_HPFR | WM8785_HPFL;
5061ff04886SClemens Ladisch 	changed = reg != data->wm8785_regs[WM8785_R2];
5071ff04886SClemens Ladisch 	if (changed)
5081ff04886SClemens Ladisch 		wm8785_write(chip, WM8785_R2, reg);
5091ff04886SClemens Ladisch 	mutex_unlock(&chip->mutex);
5101ff04886SClemens Ladisch 	return changed;
5111ff04886SClemens Ladisch }
5121ff04886SClemens Ladisch 
5131ff04886SClemens Ladisch static const struct snd_kcontrol_new hpf_control = {
5141ff04886SClemens Ladisch 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5151ff04886SClemens Ladisch 	.name = "ADC Filter Capture Enum",
5161ff04886SClemens Ladisch 	.info = hpf_info,
5171ff04886SClemens Ladisch 	.get = hpf_get,
5181ff04886SClemens Ladisch 	.put = hpf_put,
5191ff04886SClemens Ladisch };
5201ff04886SClemens Ladisch 
meridian_dig_source_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)521d1d7093fSClemens Ladisch static int meridian_dig_source_info(struct snd_kcontrol *ctl,
522d1d7093fSClemens Ladisch 				    struct snd_ctl_elem_info *info)
52364878dfbSClemens Ladisch {
52464878dfbSClemens Ladisch 	static const char *const names[2] = { "On-board", "Extension" };
52564878dfbSClemens Ladisch 
52664878dfbSClemens Ladisch 	return snd_ctl_enum_info(info, 1, 2, names);
52764878dfbSClemens Ladisch }
52864878dfbSClemens Ladisch 
claro_dig_source_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)529d1d7093fSClemens Ladisch static int claro_dig_source_info(struct snd_kcontrol *ctl,
530d1d7093fSClemens Ladisch 				 struct snd_ctl_elem_info *info)
531d1d7093fSClemens Ladisch {
532d1d7093fSClemens Ladisch 	static const char *const names[2] = { "Optical", "Coaxial" };
533d1d7093fSClemens Ladisch 
534d1d7093fSClemens Ladisch 	return snd_ctl_enum_info(info, 1, 2, names);
535d1d7093fSClemens Ladisch }
536d1d7093fSClemens Ladisch 
meridian_dig_source_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)537d1d7093fSClemens Ladisch static int meridian_dig_source_get(struct snd_kcontrol *ctl,
538d1d7093fSClemens Ladisch 				   struct snd_ctl_elem_value *value)
53964878dfbSClemens Ladisch {
54064878dfbSClemens Ladisch 	struct oxygen *chip = ctl->private_data;
54164878dfbSClemens Ladisch 
54264878dfbSClemens Ladisch 	value->value.enumerated.item[0] =
54364878dfbSClemens Ladisch 		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
54464878dfbSClemens Ladisch 		   GPIO_MERIDIAN_DIG_EXT);
54564878dfbSClemens Ladisch 	return 0;
54664878dfbSClemens Ladisch }
54764878dfbSClemens Ladisch 
claro_dig_source_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)548d1d7093fSClemens Ladisch static int claro_dig_source_get(struct snd_kcontrol *ctl,
549d1d7093fSClemens Ladisch 				struct snd_ctl_elem_value *value)
550d1d7093fSClemens Ladisch {
551d1d7093fSClemens Ladisch 	struct oxygen *chip = ctl->private_data;
552d1d7093fSClemens Ladisch 
553d1d7093fSClemens Ladisch 	value->value.enumerated.item[0] =
554d1d7093fSClemens Ladisch 		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
555d1d7093fSClemens Ladisch 		   GPIO_CLARO_DIG_COAX);
556d1d7093fSClemens Ladisch 	return 0;
557d1d7093fSClemens Ladisch }
558d1d7093fSClemens Ladisch 
meridian_dig_source_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)559d1d7093fSClemens Ladisch static int meridian_dig_source_put(struct snd_kcontrol *ctl,
560d1d7093fSClemens Ladisch 				   struct snd_ctl_elem_value *value)
56164878dfbSClemens Ladisch {
56264878dfbSClemens Ladisch 	struct oxygen *chip = ctl->private_data;
56364878dfbSClemens Ladisch 	u16 old_reg, new_reg;
56464878dfbSClemens Ladisch 	int changed;
56564878dfbSClemens Ladisch 
56664878dfbSClemens Ladisch 	mutex_lock(&chip->mutex);
56764878dfbSClemens Ladisch 	old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
56864878dfbSClemens Ladisch 	new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK;
56964878dfbSClemens Ladisch 	if (value->value.enumerated.item[0] == 0)
57064878dfbSClemens Ladisch 		new_reg |= GPIO_MERIDIAN_DIG_BOARD;
57164878dfbSClemens Ladisch 	else
57264878dfbSClemens Ladisch 		new_reg |= GPIO_MERIDIAN_DIG_EXT;
57364878dfbSClemens Ladisch 	changed = new_reg != old_reg;
57464878dfbSClemens Ladisch 	if (changed)
57564878dfbSClemens Ladisch 		oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
57664878dfbSClemens Ladisch 	mutex_unlock(&chip->mutex);
57764878dfbSClemens Ladisch 	return changed;
57864878dfbSClemens Ladisch }
57964878dfbSClemens Ladisch 
claro_dig_source_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)580d1d7093fSClemens Ladisch static int claro_dig_source_put(struct snd_kcontrol *ctl,
581d1d7093fSClemens Ladisch 				struct snd_ctl_elem_value *value)
582d1d7093fSClemens Ladisch {
583d1d7093fSClemens Ladisch 	struct oxygen *chip = ctl->private_data;
584d1d7093fSClemens Ladisch 	u16 old_reg, new_reg;
585d1d7093fSClemens Ladisch 	int changed;
586d1d7093fSClemens Ladisch 
587d1d7093fSClemens Ladisch 	mutex_lock(&chip->mutex);
588d1d7093fSClemens Ladisch 	old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
589d1d7093fSClemens Ladisch 	new_reg = old_reg & ~GPIO_CLARO_DIG_COAX;
590d1d7093fSClemens Ladisch 	if (value->value.enumerated.item[0])
591d1d7093fSClemens Ladisch 		new_reg |= GPIO_CLARO_DIG_COAX;
592d1d7093fSClemens Ladisch 	changed = new_reg != old_reg;
593d1d7093fSClemens Ladisch 	if (changed)
594d1d7093fSClemens Ladisch 		oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
595d1d7093fSClemens Ladisch 	mutex_unlock(&chip->mutex);
596d1d7093fSClemens Ladisch 	return changed;
597d1d7093fSClemens Ladisch }
598d1d7093fSClemens Ladisch 
59964878dfbSClemens Ladisch static const struct snd_kcontrol_new meridian_dig_source_control = {
60064878dfbSClemens Ladisch 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
60164878dfbSClemens Ladisch 	.name = "IEC958 Source Capture Enum",
60264878dfbSClemens Ladisch 	.info = meridian_dig_source_info,
60364878dfbSClemens Ladisch 	.get = meridian_dig_source_get,
60464878dfbSClemens Ladisch 	.put = meridian_dig_source_put,
60564878dfbSClemens Ladisch };
60664878dfbSClemens Ladisch 
607d1d7093fSClemens Ladisch static const struct snd_kcontrol_new claro_dig_source_control = {
608d1d7093fSClemens Ladisch 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
609d1d7093fSClemens Ladisch 	.name = "IEC958 Source Capture Enum",
610d1d7093fSClemens Ladisch 	.info = claro_dig_source_info,
611d1d7093fSClemens Ladisch 	.get = claro_dig_source_get,
612d1d7093fSClemens Ladisch 	.put = claro_dig_source_put,
613d1d7093fSClemens Ladisch };
614d1d7093fSClemens Ladisch 
generic_mixer_init(struct oxygen * chip)6154852ad02SClemens Ladisch static int generic_mixer_init(struct oxygen *chip)
6164852ad02SClemens Ladisch {
6174852ad02SClemens Ladisch 	return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
6184852ad02SClemens Ladisch }
6194852ad02SClemens Ladisch 
generic_wm8785_mixer_init(struct oxygen * chip)6201ff04886SClemens Ladisch static int generic_wm8785_mixer_init(struct oxygen *chip)
6211ff04886SClemens Ladisch {
6221ff04886SClemens Ladisch 	int err;
6231ff04886SClemens Ladisch 
6241ff04886SClemens Ladisch 	err = generic_mixer_init(chip);
6251ff04886SClemens Ladisch 	if (err < 0)
6261ff04886SClemens Ladisch 		return err;
6271ff04886SClemens Ladisch 	err = snd_ctl_add(chip->card, snd_ctl_new1(&hpf_control, chip));
6281ff04886SClemens Ladisch 	if (err < 0)
6291ff04886SClemens Ladisch 		return err;
6301ff04886SClemens Ladisch 	return 0;
6311ff04886SClemens Ladisch }
6321ff04886SClemens Ladisch 
meridian_mixer_init(struct oxygen * chip)63364878dfbSClemens Ladisch static int meridian_mixer_init(struct oxygen *chip)
63464878dfbSClemens Ladisch {
63564878dfbSClemens Ladisch 	int err;
63664878dfbSClemens Ladisch 
63764878dfbSClemens Ladisch 	err = generic_mixer_init(chip);
63864878dfbSClemens Ladisch 	if (err < 0)
63964878dfbSClemens Ladisch 		return err;
64064878dfbSClemens Ladisch 	err = snd_ctl_add(chip->card,
64164878dfbSClemens Ladisch 			  snd_ctl_new1(&meridian_dig_source_control, chip));
64264878dfbSClemens Ladisch 	if (err < 0)
64364878dfbSClemens Ladisch 		return err;
64464878dfbSClemens Ladisch 	return 0;
64564878dfbSClemens Ladisch }
64664878dfbSClemens Ladisch 
claro_mixer_init(struct oxygen * chip)647d1d7093fSClemens Ladisch static int claro_mixer_init(struct oxygen *chip)
648d1d7093fSClemens Ladisch {
649d1d7093fSClemens Ladisch 	int err;
650d1d7093fSClemens Ladisch 
651d1d7093fSClemens Ladisch 	err = generic_wm8785_mixer_init(chip);
652d1d7093fSClemens Ladisch 	if (err < 0)
653d1d7093fSClemens Ladisch 		return err;
654d1d7093fSClemens Ladisch 	err = snd_ctl_add(chip->card,
655d1d7093fSClemens Ladisch 			  snd_ctl_new1(&claro_dig_source_control, chip));
656d1d7093fSClemens Ladisch 	if (err < 0)
657d1d7093fSClemens Ladisch 		return err;
658d1d7093fSClemens Ladisch 	return 0;
659d1d7093fSClemens Ladisch }
660d1d7093fSClemens Ladisch 
claro_halo_mixer_init(struct oxygen * chip)661d1d7093fSClemens Ladisch static int claro_halo_mixer_init(struct oxygen *chip)
662d1d7093fSClemens Ladisch {
663d1d7093fSClemens Ladisch 	int err;
664d1d7093fSClemens Ladisch 
665d1d7093fSClemens Ladisch 	err = generic_mixer_init(chip);
666d1d7093fSClemens Ladisch 	if (err < 0)
667d1d7093fSClemens Ladisch 		return err;
668d1d7093fSClemens Ladisch 	err = snd_ctl_add(chip->card,
669d1d7093fSClemens Ladisch 			  snd_ctl_new1(&claro_dig_source_control, chip));
670d1d7093fSClemens Ladisch 	if (err < 0)
671d1d7093fSClemens Ladisch 		return err;
672d1d7093fSClemens Ladisch 	return 0;
673d1d7093fSClemens Ladisch }
674d1d7093fSClemens Ladisch 
dump_ak4396_registers(struct oxygen * chip,struct snd_info_buffer * buffer)6759719fcaaSClemens Ladisch static void dump_ak4396_registers(struct oxygen *chip,
6769719fcaaSClemens Ladisch 				  struct snd_info_buffer *buffer)
6779719fcaaSClemens Ladisch {
6789719fcaaSClemens Ladisch 	struct generic_data *data = chip->model_data;
6799719fcaaSClemens Ladisch 	unsigned int dac, i;
6809719fcaaSClemens Ladisch 
6819719fcaaSClemens Ladisch 	for (dac = 0; dac < data->dacs; ++dac) {
6829719fcaaSClemens Ladisch 		snd_iprintf(buffer, "\nAK4396 %u:", dac + 1);
6839719fcaaSClemens Ladisch 		for (i = 0; i < 5; ++i)
6849719fcaaSClemens Ladisch 			snd_iprintf(buffer, " %02x", data->ak4396_regs[dac][i]);
6859719fcaaSClemens Ladisch 	}
6869719fcaaSClemens Ladisch 	snd_iprintf(buffer, "\n");
6879719fcaaSClemens Ladisch }
6889719fcaaSClemens Ladisch 
dump_wm8785_registers(struct oxygen * chip,struct snd_info_buffer * buffer)6899719fcaaSClemens Ladisch static void dump_wm8785_registers(struct oxygen *chip,
6909719fcaaSClemens Ladisch 				  struct snd_info_buffer *buffer)
6919719fcaaSClemens Ladisch {
6929719fcaaSClemens Ladisch 	struct generic_data *data = chip->model_data;
6939719fcaaSClemens Ladisch 	unsigned int i;
6949719fcaaSClemens Ladisch 
6959719fcaaSClemens Ladisch 	snd_iprintf(buffer, "\nWM8785:");
6969719fcaaSClemens Ladisch 	for (i = 0; i < 3; ++i)
6979719fcaaSClemens Ladisch 		snd_iprintf(buffer, " %03x", data->wm8785_regs[i]);
6989719fcaaSClemens Ladisch 	snd_iprintf(buffer, "\n");
6999719fcaaSClemens Ladisch }
7009719fcaaSClemens Ladisch 
dump_oxygen_registers(struct oxygen * chip,struct snd_info_buffer * buffer)7019719fcaaSClemens Ladisch static void dump_oxygen_registers(struct oxygen *chip,
7029719fcaaSClemens Ladisch 				  struct snd_info_buffer *buffer)
7039719fcaaSClemens Ladisch {
7049719fcaaSClemens Ladisch 	dump_ak4396_registers(chip, buffer);
7059719fcaaSClemens Ladisch 	dump_wm8785_registers(chip, buffer);
7069719fcaaSClemens Ladisch }
7079719fcaaSClemens Ladisch 
708d0ce9946SClemens Ladisch static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
709d0ce9946SClemens Ladisch 
710d0ce9946SClemens Ladisch static const struct oxygen_model model_generic = {
711d0ce9946SClemens Ladisch 	.shortname = "C-Media CMI8788",
712d0ce9946SClemens Ladisch 	.longname = "C-Media Oxygen HD Audio",
713d0ce9946SClemens Ladisch 	.chip = "CMI8788",
714d0ce9946SClemens Ladisch 	.init = generic_init,
7151ff04886SClemens Ladisch 	.mixer_init = generic_wm8785_mixer_init,
716d0ce9946SClemens Ladisch 	.cleanup = generic_cleanup,
7174a4bc53bSClemens Ladisch 	.resume = generic_resume,
718d0ce9946SClemens Ladisch 	.set_dac_params = set_ak4396_params,
719d0ce9946SClemens Ladisch 	.set_adc_params = set_wm8785_params,
720d0ce9946SClemens Ladisch 	.update_dac_volume = update_ak4396_volume,
721d0ce9946SClemens Ladisch 	.update_dac_mute = update_ak4396_mute,
7229719fcaaSClemens Ladisch 	.dump_registers = dump_oxygen_registers,
7234972a177SClemens Ladisch 	.dac_tlv = ak4396_db_scale,
7247ef37cd9SClemens Ladisch 	.model_data_size = sizeof(struct generic_data),
725d76596b1SClemens Ladisch 	.device_config = PLAYBACK_0_TO_I2S |
726f009ad9bSClemens Ladisch 			 PLAYBACK_1_TO_SPDIF |
727f009ad9bSClemens Ladisch 			 PLAYBACK_2_TO_AC97_1 |
728f009ad9bSClemens Ladisch 			 CAPTURE_0_FROM_I2S_1 |
729f009ad9bSClemens Ladisch 			 CAPTURE_1_FROM_SPDIF |
730b6ca8ab3SClemens Ladisch 			 CAPTURE_2_FROM_AC97_1 |
731b6ca8ab3SClemens Ladisch 			 AC97_CD_INPUT,
7321f4d7be7SClemens Ladisch 	.dac_channels_pcm = 8,
7331f4d7be7SClemens Ladisch 	.dac_channels_mixer = 8,
734193e8138SClemens Ladisch 	.dac_volume_min = 0,
735193e8138SClemens Ladisch 	.dac_volume_max = 255,
73687eedd2fSClemens Ladisch 	.function_flags = OXYGEN_FUNCTION_SPI |
73787eedd2fSClemens Ladisch 			  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
738ce2c4920SClemens Ladisch 	.dac_mclks = OXYGEN_MCLKS(256, 128, 128),
7395b8bf2a5SClemens Ladisch 	.adc_mclks = OXYGEN_MCLKS(256, 256, 128),
74005855ba3SClemens Ladisch 	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
74105855ba3SClemens Ladisch 	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
742d0ce9946SClemens Ladisch };
743d0ce9946SClemens Ladisch 
get_oxygen_model(struct oxygen * chip,const struct pci_device_id * id)744f120a6fbSBill Pemberton static int get_oxygen_model(struct oxygen *chip,
74530459d7bSClemens Ladisch 			    const struct pci_device_id *id)
74630459d7bSClemens Ladisch {
747a4b16969SClemens Ladisch 	static const char *const names[] = {
748a4b16969SClemens Ladisch 		[MODEL_MERIDIAN]	= "AuzenTech X-Meridian",
749a4b16969SClemens Ladisch 		[MODEL_MERIDIAN_2G]	= "AuzenTech X-Meridian 2G",
750a4b16969SClemens Ladisch 		[MODEL_CLARO]		= "HT-Omega Claro",
751a4b16969SClemens Ladisch 		[MODEL_CLARO_HALO]	= "HT-Omega Claro halo",
752a4b16969SClemens Ladisch 		[MODEL_FANTASIA]	= "TempoTec HiFier Fantasia",
753a4b16969SClemens Ladisch 		[MODEL_SERENADE]	= "TempoTec HiFier Serenade",
754a4b16969SClemens Ladisch 		[MODEL_HG2PCI]		= "CMI8787-HG2PCI",
755ac310dc9SClemens Ladisch 		[MODEL_XONAR_DG]        = "Xonar DG",
756ac310dc9SClemens Ladisch 		[MODEL_XONAR_DGX]       = "Xonar DGX",
757a4b16969SClemens Ladisch 	};
758a4b16969SClemens Ladisch 
75930459d7bSClemens Ladisch 	chip->model = model_generic;
76030459d7bSClemens Ladisch 	switch (id->driver_data) {
76130459d7bSClemens Ladisch 	case MODEL_MERIDIAN:
762a4b16969SClemens Ladisch 	case MODEL_MERIDIAN_2G:
76330459d7bSClemens Ladisch 		chip->model.init = meridian_init;
76464878dfbSClemens Ladisch 		chip->model.mixer_init = meridian_mixer_init;
76530459d7bSClemens Ladisch 		chip->model.resume = meridian_resume;
76630459d7bSClemens Ladisch 		chip->model.set_adc_params = set_ak5385_params;
7679719fcaaSClemens Ladisch 		chip->model.dump_registers = dump_ak4396_registers;
76830459d7bSClemens Ladisch 		chip->model.device_config = PLAYBACK_0_TO_I2S |
76930459d7bSClemens Ladisch 					    PLAYBACK_1_TO_SPDIF |
77030459d7bSClemens Ladisch 					    CAPTURE_0_FROM_I2S_2 |
77130459d7bSClemens Ladisch 					    CAPTURE_1_FROM_SPDIF;
7725fc51524SClemens Ladisch 		if (id->driver_data == MODEL_MERIDIAN)
7735fc51524SClemens Ladisch 			chip->model.device_config |= AC97_CD_INPUT;
77430459d7bSClemens Ladisch 		break;
775873591dbSClemens Ladisch 	case MODEL_CLARO:
776873591dbSClemens Ladisch 		chip->model.init = claro_init;
777d1d7093fSClemens Ladisch 		chip->model.mixer_init = claro_mixer_init;
778873591dbSClemens Ladisch 		chip->model.cleanup = claro_cleanup;
779873591dbSClemens Ladisch 		chip->model.suspend = claro_suspend;
780873591dbSClemens Ladisch 		chip->model.resume = claro_resume;
781873591dbSClemens Ladisch 		break;
782873591dbSClemens Ladisch 	case MODEL_CLARO_HALO:
783873591dbSClemens Ladisch 		chip->model.init = claro_halo_init;
784d1d7093fSClemens Ladisch 		chip->model.mixer_init = claro_halo_mixer_init;
785873591dbSClemens Ladisch 		chip->model.cleanup = claro_cleanup;
786873591dbSClemens Ladisch 		chip->model.suspend = claro_suspend;
787873591dbSClemens Ladisch 		chip->model.resume = claro_resume;
788d91b424dSClemens Ladisch 		chip->model.set_adc_params = set_ak5385_params;
7899719fcaaSClemens Ladisch 		chip->model.dump_registers = dump_ak4396_registers;
7900873a5aeSErik J. Staab 		chip->model.device_config = PLAYBACK_0_TO_I2S |
7910873a5aeSErik J. Staab 					    PLAYBACK_1_TO_SPDIF |
7920873a5aeSErik J. Staab 					    CAPTURE_0_FROM_I2S_2 |
7930873a5aeSErik J. Staab 					    CAPTURE_1_FROM_SPDIF;
794d91b424dSClemens Ladisch 		break;
7952146dcfdSClemens Ladisch 	case MODEL_FANTASIA:
796a4b16969SClemens Ladisch 	case MODEL_SERENADE:
7972146dcfdSClemens Ladisch 	case MODEL_2CH_OUTPUT:
798a4b16969SClemens Ladisch 	case MODEL_HG2PCI:
79945c1de8eSClemens Ladisch 		chip->model.shortname = "C-Media CMI8787";
80045c1de8eSClemens Ladisch 		chip->model.chip = "CMI8787";
8012146dcfdSClemens Ladisch 		if (id->driver_data == MODEL_FANTASIA)
8022146dcfdSClemens Ladisch 			chip->model.init = fantasia_init;
80331f86bacSClemens Ladisch 		else
8042146dcfdSClemens Ladisch 			chip->model.init = stereo_output_init;
80545c1de8eSClemens Ladisch 		chip->model.resume = stereo_resume;
80645c1de8eSClemens Ladisch 		chip->model.mixer_init = generic_mixer_init;
80745c1de8eSClemens Ladisch 		chip->model.set_adc_params = set_no_params;
8089719fcaaSClemens Ladisch 		chip->model.dump_registers = dump_ak4396_registers;
80945c1de8eSClemens Ladisch 		chip->model.device_config = PLAYBACK_0_TO_I2S |
81031f86bacSClemens Ladisch 					    PLAYBACK_1_TO_SPDIF;
811ce2c4920SClemens Ladisch 		if (id->driver_data == MODEL_FANTASIA) {
81231f86bacSClemens Ladisch 			chip->model.device_config |= CAPTURE_0_FROM_I2S_1;
813ce2c4920SClemens Ladisch 			chip->model.adc_mclks = OXYGEN_MCLKS(256, 128, 128);
814ce2c4920SClemens Ladisch 		}
8151f4d7be7SClemens Ladisch 		chip->model.dac_channels_pcm = 2;
8161f4d7be7SClemens Ladisch 		chip->model.dac_channels_mixer = 2;
81745c1de8eSClemens Ladisch 		break;
81866410bfdSClemens Ladisch 	case MODEL_XONAR_DG:
81976bc7a0dSClemens Ladisch 	case MODEL_XONAR_DGX:
82076bc7a0dSClemens Ladisch 		chip->model = model_xonar_dg;
82166410bfdSClemens Ladisch 		break;
82230459d7bSClemens Ladisch 	}
82330459d7bSClemens Ladisch 	if (id->driver_data == MODEL_MERIDIAN ||
8245fc51524SClemens Ladisch 	    id->driver_data == MODEL_MERIDIAN_2G ||
825873591dbSClemens Ladisch 	    id->driver_data == MODEL_CLARO_HALO) {
82630459d7bSClemens Ladisch 		chip->model.misc_flags = OXYGEN_MISC_MIDI;
82730459d7bSClemens Ladisch 		chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
82830459d7bSClemens Ladisch 	}
829a4b16969SClemens Ladisch 	if (id->driver_data < ARRAY_SIZE(names) && names[id->driver_data])
830a4b16969SClemens Ladisch 		chip->model.shortname = names[id->driver_data];
83130459d7bSClemens Ladisch 	return 0;
83230459d7bSClemens Ladisch }
83330459d7bSClemens Ladisch 
generic_oxygen_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)834f120a6fbSBill Pemberton static int generic_oxygen_probe(struct pci_dev *pci,
835d0ce9946SClemens Ladisch 				const struct pci_device_id *pci_id)
836d0ce9946SClemens Ladisch {
837d0ce9946SClemens Ladisch 	static int dev;
838d0ce9946SClemens Ladisch 	int err;
839d0ce9946SClemens Ladisch 
840d0ce9946SClemens Ladisch 	if (dev >= SNDRV_CARDS)
841d0ce9946SClemens Ladisch 		return -ENODEV;
842d0ce9946SClemens Ladisch 	if (!enable[dev]) {
843d0ce9946SClemens Ladisch 		++dev;
844d0ce9946SClemens Ladisch 		return -ENOENT;
845d0ce9946SClemens Ladisch 	}
846bb718588SClemens Ladisch 	err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
84730459d7bSClemens Ladisch 			       oxygen_ids, get_oxygen_model);
848d0ce9946SClemens Ladisch 	if (err >= 0)
849d0ce9946SClemens Ladisch 		++dev;
850d0ce9946SClemens Ladisch 	return err;
851d0ce9946SClemens Ladisch }
852d0ce9946SClemens Ladisch 
853d0ce9946SClemens Ladisch static struct pci_driver oxygen_driver = {
8543733e424STakashi Iwai 	.name = KBUILD_MODNAME,
855d0ce9946SClemens Ladisch 	.id_table = oxygen_ids,
856d0ce9946SClemens Ladisch 	.probe = generic_oxygen_probe,
857c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
85868cb2b55STakashi Iwai 	.driver = {
85968cb2b55STakashi Iwai 		.pm = &oxygen_pci_pm,
86068cb2b55STakashi Iwai 	},
8614a4bc53bSClemens Ladisch #endif
862d0ce9946SClemens Ladisch };
863d0ce9946SClemens Ladisch 
864e9f66d9bSTakashi Iwai module_pci_driver(oxygen_driver);
865