xref: /OK3568_Linux_fs/kernel/sound/pci/oxygen/oxygen.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * C-Media CMI8788 driver for C-Media's reference design and similar models
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun /*
9*4882a593Smuzhiyun  * CMI8788:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *   SPI 0 -> 1st AK4396 (front)
12*4882a593Smuzhiyun  *   SPI 1 -> 2nd AK4396 (surround)
13*4882a593Smuzhiyun  *   SPI 2 -> 3rd AK4396 (center/LFE)
14*4882a593Smuzhiyun  *   SPI 3 -> WM8785
15*4882a593Smuzhiyun  *   SPI 4 -> 4th AK4396 (back)
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  *   GPIO 0 -> DFS0 of AK5385
18*4882a593Smuzhiyun  *   GPIO 1 -> DFS1 of AK5385
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  * X-Meridian models:
21*4882a593Smuzhiyun  *   GPIO 4 -> enable extension S/PDIF input
22*4882a593Smuzhiyun  *   GPIO 6 -> enable on-board S/PDIF input
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * Claro models:
25*4882a593Smuzhiyun  *   GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input
26*4882a593Smuzhiyun  *   GPIO 8 -> enable headphone amplifier
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  * CM9780:
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  *   LINE_OUT -> input of ADC
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  *   AUX_IN <- aux
33*4882a593Smuzhiyun  *   CD_IN  <- CD
34*4882a593Smuzhiyun  *   MIC_IN <- mic
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  *   GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
37*4882a593Smuzhiyun  */
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include <linux/delay.h>
40*4882a593Smuzhiyun #include <linux/mutex.h>
41*4882a593Smuzhiyun #include <linux/pci.h>
42*4882a593Smuzhiyun #include <linux/module.h>
43*4882a593Smuzhiyun #include <sound/ac97_codec.h>
44*4882a593Smuzhiyun #include <sound/control.h>
45*4882a593Smuzhiyun #include <sound/core.h>
46*4882a593Smuzhiyun #include <sound/info.h>
47*4882a593Smuzhiyun #include <sound/initval.h>
48*4882a593Smuzhiyun #include <sound/pcm.h>
49*4882a593Smuzhiyun #include <sound/pcm_params.h>
50*4882a593Smuzhiyun #include <sound/tlv.h>
51*4882a593Smuzhiyun #include "oxygen.h"
52*4882a593Smuzhiyun #include "xonar_dg.h"
53*4882a593Smuzhiyun #include "ak4396.h"
54*4882a593Smuzhiyun #include "wm8785.h"
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
57*4882a593Smuzhiyun MODULE_DESCRIPTION("C-Media CMI8788 driver");
58*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
59*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}"
60*4882a593Smuzhiyun 			",{C-Media,CMI8787}"
61*4882a593Smuzhiyun 			",{C-Media,CMI8788}}");
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
64*4882a593Smuzhiyun static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
65*4882a593Smuzhiyun static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun module_param_array(index, int, NULL, 0444);
68*4882a593Smuzhiyun MODULE_PARM_DESC(index, "card index");
69*4882a593Smuzhiyun module_param_array(id, charp, NULL, 0444);
70*4882a593Smuzhiyun MODULE_PARM_DESC(id, "ID string");
71*4882a593Smuzhiyun module_param_array(enable, bool, NULL, 0444);
72*4882a593Smuzhiyun MODULE_PARM_DESC(enable, "enable card");
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun enum {
75*4882a593Smuzhiyun 	MODEL_CMEDIA_REF,
76*4882a593Smuzhiyun 	MODEL_MERIDIAN,
77*4882a593Smuzhiyun 	MODEL_MERIDIAN_2G,
78*4882a593Smuzhiyun 	MODEL_CLARO,
79*4882a593Smuzhiyun 	MODEL_CLARO_HALO,
80*4882a593Smuzhiyun 	MODEL_FANTASIA,
81*4882a593Smuzhiyun 	MODEL_SERENADE,
82*4882a593Smuzhiyun 	MODEL_2CH_OUTPUT,
83*4882a593Smuzhiyun 	MODEL_HG2PCI,
84*4882a593Smuzhiyun 	MODEL_XONAR_DG,
85*4882a593Smuzhiyun 	MODEL_XONAR_DGX,
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static const struct pci_device_id oxygen_ids[] = {
89*4882a593Smuzhiyun 	/* C-Media's reference design */
90*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF },
91*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF },
92*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF },
93*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF },
94*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
95*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
96*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
97*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
98*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
99*4882a593Smuzhiyun 	/* Asus Xonar DG */
100*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG },
101*4882a593Smuzhiyun 	/* Asus Xonar DGX */
102*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x1043, 0x8521), .driver_data = MODEL_XONAR_DGX },
103*4882a593Smuzhiyun 	/* PCI 2.0 HD Audio */
104*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT },
105*4882a593Smuzhiyun 	/* Kuroutoshikou CMI8787-HG2PCI */
106*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI },
107*4882a593Smuzhiyun 	/* TempoTec HiFier Fantasia */
108*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_FANTASIA },
109*4882a593Smuzhiyun 	/* TempoTec HiFier Serenade */
110*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_SERENADE },
111*4882a593Smuzhiyun 	/* AuzenTech X-Meridian */
112*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
113*4882a593Smuzhiyun 	/* AuzenTech X-Meridian 2G */
114*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN_2G },
115*4882a593Smuzhiyun 	/* HT-Omega Claro */
116*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
117*4882a593Smuzhiyun 	/* HT-Omega Claro halo */
118*4882a593Smuzhiyun 	{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO },
119*4882a593Smuzhiyun 	{ }
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, oxygen_ids);
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun #define GPIO_AK5385_DFS_MASK	0x0003
125*4882a593Smuzhiyun #define GPIO_AK5385_DFS_NORMAL	0x0000
126*4882a593Smuzhiyun #define GPIO_AK5385_DFS_DOUBLE	0x0001
127*4882a593Smuzhiyun #define GPIO_AK5385_DFS_QUAD	0x0002
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun #define GPIO_MERIDIAN_DIG_MASK	0x0050
130*4882a593Smuzhiyun #define GPIO_MERIDIAN_DIG_EXT	0x0010
131*4882a593Smuzhiyun #define GPIO_MERIDIAN_DIG_BOARD	0x0040
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun #define GPIO_CLARO_DIG_COAX	0x0040
134*4882a593Smuzhiyun #define GPIO_CLARO_HP		0x0100
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun struct generic_data {
137*4882a593Smuzhiyun 	unsigned int dacs;
138*4882a593Smuzhiyun 	u8 ak4396_regs[4][5];
139*4882a593Smuzhiyun 	u16 wm8785_regs[3];
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun 
ak4396_write(struct oxygen * chip,unsigned int codec,u8 reg,u8 value)142*4882a593Smuzhiyun static void ak4396_write(struct oxygen *chip, unsigned int codec,
143*4882a593Smuzhiyun 			 u8 reg, u8 value)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	/* maps ALSA channel pair number to SPI output */
146*4882a593Smuzhiyun 	static const u8 codec_spi_map[4] = {
147*4882a593Smuzhiyun 		0, 1, 2, 4
148*4882a593Smuzhiyun 	};
149*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
152*4882a593Smuzhiyun 			 OXYGEN_SPI_DATA_LENGTH_2 |
153*4882a593Smuzhiyun 			 OXYGEN_SPI_CLOCK_160 |
154*4882a593Smuzhiyun 			 (codec_spi_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
155*4882a593Smuzhiyun 			 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
156*4882a593Smuzhiyun 			 AK4396_WRITE | (reg << 8) | value);
157*4882a593Smuzhiyun 	data->ak4396_regs[codec][reg] = value;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
ak4396_write_cached(struct oxygen * chip,unsigned int codec,u8 reg,u8 value)160*4882a593Smuzhiyun static void ak4396_write_cached(struct oxygen *chip, unsigned int codec,
161*4882a593Smuzhiyun 				u8 reg, u8 value)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (value != data->ak4396_regs[codec][reg])
166*4882a593Smuzhiyun 		ak4396_write(chip, codec, reg, value);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
wm8785_write(struct oxygen * chip,u8 reg,unsigned int value)169*4882a593Smuzhiyun static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
174*4882a593Smuzhiyun 			 OXYGEN_SPI_DATA_LENGTH_2 |
175*4882a593Smuzhiyun 			 OXYGEN_SPI_CLOCK_160 |
176*4882a593Smuzhiyun 			 (3 << OXYGEN_SPI_CODEC_SHIFT) |
177*4882a593Smuzhiyun 			 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
178*4882a593Smuzhiyun 			 (reg << 9) | value);
179*4882a593Smuzhiyun 	if (reg < ARRAY_SIZE(data->wm8785_regs))
180*4882a593Smuzhiyun 		data->wm8785_regs[reg] = value;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
ak4396_registers_init(struct oxygen * chip)183*4882a593Smuzhiyun static void ak4396_registers_init(struct oxygen *chip)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
186*4882a593Smuzhiyun 	unsigned int i;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	for (i = 0; i < data->dacs; ++i) {
189*4882a593Smuzhiyun 		ak4396_write(chip, i, AK4396_CONTROL_1,
190*4882a593Smuzhiyun 			     AK4396_DIF_24_MSB | AK4396_RSTN);
191*4882a593Smuzhiyun 		ak4396_write(chip, i, AK4396_CONTROL_2,
192*4882a593Smuzhiyun 			     data->ak4396_regs[0][AK4396_CONTROL_2]);
193*4882a593Smuzhiyun 		ak4396_write(chip, i, AK4396_CONTROL_3,
194*4882a593Smuzhiyun 			     AK4396_PCM);
195*4882a593Smuzhiyun 		ak4396_write(chip, i, AK4396_LCH_ATT,
196*4882a593Smuzhiyun 			     chip->dac_volume[i * 2]);
197*4882a593Smuzhiyun 		ak4396_write(chip, i, AK4396_RCH_ATT,
198*4882a593Smuzhiyun 			     chip->dac_volume[i * 2 + 1]);
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
ak4396_init(struct oxygen * chip)202*4882a593Smuzhiyun static void ak4396_init(struct oxygen *chip)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	data->dacs = chip->model.dac_channels_pcm / 2;
207*4882a593Smuzhiyun 	data->ak4396_regs[0][AK4396_CONTROL_2] =
208*4882a593Smuzhiyun 		AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
209*4882a593Smuzhiyun 	ak4396_registers_init(chip);
210*4882a593Smuzhiyun 	snd_component_add(chip->card, "AK4396");
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
ak5385_init(struct oxygen * chip)213*4882a593Smuzhiyun static void ak5385_init(struct oxygen *chip)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_AK5385_DFS_MASK);
216*4882a593Smuzhiyun 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_AK5385_DFS_MASK);
217*4882a593Smuzhiyun 	snd_component_add(chip->card, "AK5385");
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
wm8785_registers_init(struct oxygen * chip)220*4882a593Smuzhiyun static void wm8785_registers_init(struct oxygen *chip)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	wm8785_write(chip, WM8785_R7, 0);
225*4882a593Smuzhiyun 	wm8785_write(chip, WM8785_R0, data->wm8785_regs[0]);
226*4882a593Smuzhiyun 	wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]);
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
wm8785_init(struct oxygen * chip)229*4882a593Smuzhiyun static void wm8785_init(struct oxygen *chip)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	data->wm8785_regs[0] =
234*4882a593Smuzhiyun 		WM8785_MCR_SLAVE | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST;
235*4882a593Smuzhiyun 	data->wm8785_regs[2] = WM8785_HPFR | WM8785_HPFL;
236*4882a593Smuzhiyun 	wm8785_registers_init(chip);
237*4882a593Smuzhiyun 	snd_component_add(chip->card, "WM8785");
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
generic_init(struct oxygen * chip)240*4882a593Smuzhiyun static void generic_init(struct oxygen *chip)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	ak4396_init(chip);
243*4882a593Smuzhiyun 	wm8785_init(chip);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
meridian_init(struct oxygen * chip)246*4882a593Smuzhiyun static void meridian_init(struct oxygen *chip)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
249*4882a593Smuzhiyun 			  GPIO_MERIDIAN_DIG_MASK);
250*4882a593Smuzhiyun 	oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
251*4882a593Smuzhiyun 			      GPIO_MERIDIAN_DIG_BOARD, GPIO_MERIDIAN_DIG_MASK);
252*4882a593Smuzhiyun 	ak4396_init(chip);
253*4882a593Smuzhiyun 	ak5385_init(chip);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
claro_enable_hp(struct oxygen * chip)256*4882a593Smuzhiyun static void claro_enable_hp(struct oxygen *chip)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	msleep(300);
259*4882a593Smuzhiyun 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_HP);
260*4882a593Smuzhiyun 	oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
claro_init(struct oxygen * chip)263*4882a593Smuzhiyun static void claro_init(struct oxygen *chip)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
266*4882a593Smuzhiyun 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
267*4882a593Smuzhiyun 	ak4396_init(chip);
268*4882a593Smuzhiyun 	wm8785_init(chip);
269*4882a593Smuzhiyun 	claro_enable_hp(chip);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
claro_halo_init(struct oxygen * chip)272*4882a593Smuzhiyun static void claro_halo_init(struct oxygen *chip)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
275*4882a593Smuzhiyun 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
276*4882a593Smuzhiyun 	ak4396_init(chip);
277*4882a593Smuzhiyun 	ak5385_init(chip);
278*4882a593Smuzhiyun 	claro_enable_hp(chip);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
fantasia_init(struct oxygen * chip)281*4882a593Smuzhiyun static void fantasia_init(struct oxygen *chip)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	ak4396_init(chip);
284*4882a593Smuzhiyun 	snd_component_add(chip->card, "CS5340");
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
stereo_output_init(struct oxygen * chip)287*4882a593Smuzhiyun static void stereo_output_init(struct oxygen *chip)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	ak4396_init(chip);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
generic_cleanup(struct oxygen * chip)292*4882a593Smuzhiyun static void generic_cleanup(struct oxygen *chip)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
claro_disable_hp(struct oxygen * chip)296*4882a593Smuzhiyun static void claro_disable_hp(struct oxygen *chip)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
claro_cleanup(struct oxygen * chip)301*4882a593Smuzhiyun static void claro_cleanup(struct oxygen *chip)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	claro_disable_hp(chip);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
claro_suspend(struct oxygen * chip)306*4882a593Smuzhiyun static void claro_suspend(struct oxygen *chip)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun 	claro_disable_hp(chip);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
generic_resume(struct oxygen * chip)311*4882a593Smuzhiyun static void generic_resume(struct oxygen *chip)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	ak4396_registers_init(chip);
314*4882a593Smuzhiyun 	wm8785_registers_init(chip);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
meridian_resume(struct oxygen * chip)317*4882a593Smuzhiyun static void meridian_resume(struct oxygen *chip)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	ak4396_registers_init(chip);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
claro_resume(struct oxygen * chip)322*4882a593Smuzhiyun static void claro_resume(struct oxygen *chip)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	ak4396_registers_init(chip);
325*4882a593Smuzhiyun 	claro_enable_hp(chip);
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun 
stereo_resume(struct oxygen * chip)328*4882a593Smuzhiyun static void stereo_resume(struct oxygen *chip)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	ak4396_registers_init(chip);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
set_ak4396_params(struct oxygen * chip,struct snd_pcm_hw_params * params)333*4882a593Smuzhiyun static void set_ak4396_params(struct oxygen *chip,
334*4882a593Smuzhiyun 			      struct snd_pcm_hw_params *params)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
337*4882a593Smuzhiyun 	unsigned int i;
338*4882a593Smuzhiyun 	u8 value;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
341*4882a593Smuzhiyun 	if (params_rate(params) <= 54000)
342*4882a593Smuzhiyun 		value |= AK4396_DFS_NORMAL;
343*4882a593Smuzhiyun 	else if (params_rate(params) <= 108000)
344*4882a593Smuzhiyun 		value |= AK4396_DFS_DOUBLE;
345*4882a593Smuzhiyun 	else
346*4882a593Smuzhiyun 		value |= AK4396_DFS_QUAD;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	msleep(1); /* wait for the new MCLK to become stable */
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) {
351*4882a593Smuzhiyun 		for (i = 0; i < data->dacs; ++i) {
352*4882a593Smuzhiyun 			ak4396_write(chip, i, AK4396_CONTROL_1,
353*4882a593Smuzhiyun 				     AK4396_DIF_24_MSB);
354*4882a593Smuzhiyun 			ak4396_write(chip, i, AK4396_CONTROL_2, value);
355*4882a593Smuzhiyun 			ak4396_write(chip, i, AK4396_CONTROL_1,
356*4882a593Smuzhiyun 				     AK4396_DIF_24_MSB | AK4396_RSTN);
357*4882a593Smuzhiyun 		}
358*4882a593Smuzhiyun 	}
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
update_ak4396_volume(struct oxygen * chip)361*4882a593Smuzhiyun static void update_ak4396_volume(struct oxygen *chip)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
364*4882a593Smuzhiyun 	unsigned int i;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	for (i = 0; i < data->dacs; ++i) {
367*4882a593Smuzhiyun 		ak4396_write_cached(chip, i, AK4396_LCH_ATT,
368*4882a593Smuzhiyun 				    chip->dac_volume[i * 2]);
369*4882a593Smuzhiyun 		ak4396_write_cached(chip, i, AK4396_RCH_ATT,
370*4882a593Smuzhiyun 				    chip->dac_volume[i * 2 + 1]);
371*4882a593Smuzhiyun 	}
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
update_ak4396_mute(struct oxygen * chip)374*4882a593Smuzhiyun static void update_ak4396_mute(struct oxygen *chip)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
377*4882a593Smuzhiyun 	unsigned int i;
378*4882a593Smuzhiyun 	u8 value;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE;
381*4882a593Smuzhiyun 	if (chip->dac_mute)
382*4882a593Smuzhiyun 		value |= AK4396_SMUTE;
383*4882a593Smuzhiyun 	for (i = 0; i < data->dacs; ++i)
384*4882a593Smuzhiyun 		ak4396_write_cached(chip, i, AK4396_CONTROL_2, value);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
set_wm8785_params(struct oxygen * chip,struct snd_pcm_hw_params * params)387*4882a593Smuzhiyun static void set_wm8785_params(struct oxygen *chip,
388*4882a593Smuzhiyun 			      struct snd_pcm_hw_params *params)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
391*4882a593Smuzhiyun 	unsigned int value;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	value = WM8785_MCR_SLAVE | WM8785_FORMAT_LJUST;
394*4882a593Smuzhiyun 	if (params_rate(params) <= 48000)
395*4882a593Smuzhiyun 		value |= WM8785_OSR_SINGLE;
396*4882a593Smuzhiyun 	else if (params_rate(params) <= 96000)
397*4882a593Smuzhiyun 		value |= WM8785_OSR_DOUBLE;
398*4882a593Smuzhiyun 	else
399*4882a593Smuzhiyun 		value |= WM8785_OSR_QUAD;
400*4882a593Smuzhiyun 	if (value != data->wm8785_regs[0]) {
401*4882a593Smuzhiyun 		wm8785_write(chip, WM8785_R7, 0);
402*4882a593Smuzhiyun 		wm8785_write(chip, WM8785_R0, value);
403*4882a593Smuzhiyun 		wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]);
404*4882a593Smuzhiyun 	}
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
set_ak5385_params(struct oxygen * chip,struct snd_pcm_hw_params * params)407*4882a593Smuzhiyun static void set_ak5385_params(struct oxygen *chip,
408*4882a593Smuzhiyun 			      struct snd_pcm_hw_params *params)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun 	unsigned int value;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	if (params_rate(params) <= 54000)
413*4882a593Smuzhiyun 		value = GPIO_AK5385_DFS_NORMAL;
414*4882a593Smuzhiyun 	else if (params_rate(params) <= 108000)
415*4882a593Smuzhiyun 		value = GPIO_AK5385_DFS_DOUBLE;
416*4882a593Smuzhiyun 	else
417*4882a593Smuzhiyun 		value = GPIO_AK5385_DFS_QUAD;
418*4882a593Smuzhiyun 	oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
419*4882a593Smuzhiyun 			      value, GPIO_AK5385_DFS_MASK);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
set_no_params(struct oxygen * chip,struct snd_pcm_hw_params * params)422*4882a593Smuzhiyun static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
rolloff_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)426*4882a593Smuzhiyun static int rolloff_info(struct snd_kcontrol *ctl,
427*4882a593Smuzhiyun 			struct snd_ctl_elem_info *info)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun 	static const char *const names[2] = {
430*4882a593Smuzhiyun 		"Sharp Roll-off", "Slow Roll-off"
431*4882a593Smuzhiyun 	};
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	return snd_ctl_enum_info(info, 1, 2, names);
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
rolloff_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)436*4882a593Smuzhiyun static int rolloff_get(struct snd_kcontrol *ctl,
437*4882a593Smuzhiyun 		       struct snd_ctl_elem_value *value)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	struct oxygen *chip = ctl->private_data;
440*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	value->value.enumerated.item[0] =
443*4882a593Smuzhiyun 		(data->ak4396_regs[0][AK4396_CONTROL_2] & AK4396_SLOW) != 0;
444*4882a593Smuzhiyun 	return 0;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun 
rolloff_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)447*4882a593Smuzhiyun static int rolloff_put(struct snd_kcontrol *ctl,
448*4882a593Smuzhiyun 		       struct snd_ctl_elem_value *value)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct oxygen *chip = ctl->private_data;
451*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
452*4882a593Smuzhiyun 	unsigned int i;
453*4882a593Smuzhiyun 	int changed;
454*4882a593Smuzhiyun 	u8 reg;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	mutex_lock(&chip->mutex);
457*4882a593Smuzhiyun 	reg = data->ak4396_regs[0][AK4396_CONTROL_2];
458*4882a593Smuzhiyun 	if (value->value.enumerated.item[0])
459*4882a593Smuzhiyun 		reg |= AK4396_SLOW;
460*4882a593Smuzhiyun 	else
461*4882a593Smuzhiyun 		reg &= ~AK4396_SLOW;
462*4882a593Smuzhiyun 	changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2];
463*4882a593Smuzhiyun 	if (changed) {
464*4882a593Smuzhiyun 		for (i = 0; i < data->dacs; ++i)
465*4882a593Smuzhiyun 			ak4396_write(chip, i, AK4396_CONTROL_2, reg);
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 	mutex_unlock(&chip->mutex);
468*4882a593Smuzhiyun 	return changed;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun static const struct snd_kcontrol_new rolloff_control = {
472*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
473*4882a593Smuzhiyun 	.name = "DAC Filter Playback Enum",
474*4882a593Smuzhiyun 	.info = rolloff_info,
475*4882a593Smuzhiyun 	.get = rolloff_get,
476*4882a593Smuzhiyun 	.put = rolloff_put,
477*4882a593Smuzhiyun };
478*4882a593Smuzhiyun 
hpf_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)479*4882a593Smuzhiyun static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun 	static const char *const names[2] = {
482*4882a593Smuzhiyun 		"None", "High-pass Filter"
483*4882a593Smuzhiyun 	};
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	return snd_ctl_enum_info(info, 1, 2, names);
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
hpf_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)488*4882a593Smuzhiyun static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun 	struct oxygen *chip = ctl->private_data;
491*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	value->value.enumerated.item[0] =
494*4882a593Smuzhiyun 		(data->wm8785_regs[WM8785_R2] & WM8785_HPFR) != 0;
495*4882a593Smuzhiyun 	return 0;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
hpf_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)498*4882a593Smuzhiyun static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun 	struct oxygen *chip = ctl->private_data;
501*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
502*4882a593Smuzhiyun 	unsigned int reg;
503*4882a593Smuzhiyun 	int changed;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	mutex_lock(&chip->mutex);
506*4882a593Smuzhiyun 	reg = data->wm8785_regs[WM8785_R2] & ~(WM8785_HPFR | WM8785_HPFL);
507*4882a593Smuzhiyun 	if (value->value.enumerated.item[0])
508*4882a593Smuzhiyun 		reg |= WM8785_HPFR | WM8785_HPFL;
509*4882a593Smuzhiyun 	changed = reg != data->wm8785_regs[WM8785_R2];
510*4882a593Smuzhiyun 	if (changed)
511*4882a593Smuzhiyun 		wm8785_write(chip, WM8785_R2, reg);
512*4882a593Smuzhiyun 	mutex_unlock(&chip->mutex);
513*4882a593Smuzhiyun 	return changed;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun static const struct snd_kcontrol_new hpf_control = {
517*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
518*4882a593Smuzhiyun 	.name = "ADC Filter Capture Enum",
519*4882a593Smuzhiyun 	.info = hpf_info,
520*4882a593Smuzhiyun 	.get = hpf_get,
521*4882a593Smuzhiyun 	.put = hpf_put,
522*4882a593Smuzhiyun };
523*4882a593Smuzhiyun 
meridian_dig_source_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)524*4882a593Smuzhiyun static int meridian_dig_source_info(struct snd_kcontrol *ctl,
525*4882a593Smuzhiyun 				    struct snd_ctl_elem_info *info)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun 	static const char *const names[2] = { "On-board", "Extension" };
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	return snd_ctl_enum_info(info, 1, 2, names);
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun 
claro_dig_source_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)532*4882a593Smuzhiyun static int claro_dig_source_info(struct snd_kcontrol *ctl,
533*4882a593Smuzhiyun 				 struct snd_ctl_elem_info *info)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	static const char *const names[2] = { "Optical", "Coaxial" };
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	return snd_ctl_enum_info(info, 1, 2, names);
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
meridian_dig_source_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)540*4882a593Smuzhiyun static int meridian_dig_source_get(struct snd_kcontrol *ctl,
541*4882a593Smuzhiyun 				   struct snd_ctl_elem_value *value)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun 	struct oxygen *chip = ctl->private_data;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	value->value.enumerated.item[0] =
546*4882a593Smuzhiyun 		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
547*4882a593Smuzhiyun 		   GPIO_MERIDIAN_DIG_EXT);
548*4882a593Smuzhiyun 	return 0;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
claro_dig_source_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)551*4882a593Smuzhiyun static int claro_dig_source_get(struct snd_kcontrol *ctl,
552*4882a593Smuzhiyun 				struct snd_ctl_elem_value *value)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	struct oxygen *chip = ctl->private_data;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	value->value.enumerated.item[0] =
557*4882a593Smuzhiyun 		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
558*4882a593Smuzhiyun 		   GPIO_CLARO_DIG_COAX);
559*4882a593Smuzhiyun 	return 0;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun 
meridian_dig_source_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)562*4882a593Smuzhiyun static int meridian_dig_source_put(struct snd_kcontrol *ctl,
563*4882a593Smuzhiyun 				   struct snd_ctl_elem_value *value)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun 	struct oxygen *chip = ctl->private_data;
566*4882a593Smuzhiyun 	u16 old_reg, new_reg;
567*4882a593Smuzhiyun 	int changed;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	mutex_lock(&chip->mutex);
570*4882a593Smuzhiyun 	old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
571*4882a593Smuzhiyun 	new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK;
572*4882a593Smuzhiyun 	if (value->value.enumerated.item[0] == 0)
573*4882a593Smuzhiyun 		new_reg |= GPIO_MERIDIAN_DIG_BOARD;
574*4882a593Smuzhiyun 	else
575*4882a593Smuzhiyun 		new_reg |= GPIO_MERIDIAN_DIG_EXT;
576*4882a593Smuzhiyun 	changed = new_reg != old_reg;
577*4882a593Smuzhiyun 	if (changed)
578*4882a593Smuzhiyun 		oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
579*4882a593Smuzhiyun 	mutex_unlock(&chip->mutex);
580*4882a593Smuzhiyun 	return changed;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun 
claro_dig_source_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)583*4882a593Smuzhiyun static int claro_dig_source_put(struct snd_kcontrol *ctl,
584*4882a593Smuzhiyun 				struct snd_ctl_elem_value *value)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	struct oxygen *chip = ctl->private_data;
587*4882a593Smuzhiyun 	u16 old_reg, new_reg;
588*4882a593Smuzhiyun 	int changed;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	mutex_lock(&chip->mutex);
591*4882a593Smuzhiyun 	old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
592*4882a593Smuzhiyun 	new_reg = old_reg & ~GPIO_CLARO_DIG_COAX;
593*4882a593Smuzhiyun 	if (value->value.enumerated.item[0])
594*4882a593Smuzhiyun 		new_reg |= GPIO_CLARO_DIG_COAX;
595*4882a593Smuzhiyun 	changed = new_reg != old_reg;
596*4882a593Smuzhiyun 	if (changed)
597*4882a593Smuzhiyun 		oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
598*4882a593Smuzhiyun 	mutex_unlock(&chip->mutex);
599*4882a593Smuzhiyun 	return changed;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun static const struct snd_kcontrol_new meridian_dig_source_control = {
603*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
604*4882a593Smuzhiyun 	.name = "IEC958 Source Capture Enum",
605*4882a593Smuzhiyun 	.info = meridian_dig_source_info,
606*4882a593Smuzhiyun 	.get = meridian_dig_source_get,
607*4882a593Smuzhiyun 	.put = meridian_dig_source_put,
608*4882a593Smuzhiyun };
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun static const struct snd_kcontrol_new claro_dig_source_control = {
611*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
612*4882a593Smuzhiyun 	.name = "IEC958 Source Capture Enum",
613*4882a593Smuzhiyun 	.info = claro_dig_source_info,
614*4882a593Smuzhiyun 	.get = claro_dig_source_get,
615*4882a593Smuzhiyun 	.put = claro_dig_source_put,
616*4882a593Smuzhiyun };
617*4882a593Smuzhiyun 
generic_mixer_init(struct oxygen * chip)618*4882a593Smuzhiyun static int generic_mixer_init(struct oxygen *chip)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun 	return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun 
generic_wm8785_mixer_init(struct oxygen * chip)623*4882a593Smuzhiyun static int generic_wm8785_mixer_init(struct oxygen *chip)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	int err;
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	err = generic_mixer_init(chip);
628*4882a593Smuzhiyun 	if (err < 0)
629*4882a593Smuzhiyun 		return err;
630*4882a593Smuzhiyun 	err = snd_ctl_add(chip->card, snd_ctl_new1(&hpf_control, chip));
631*4882a593Smuzhiyun 	if (err < 0)
632*4882a593Smuzhiyun 		return err;
633*4882a593Smuzhiyun 	return 0;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun 
meridian_mixer_init(struct oxygen * chip)636*4882a593Smuzhiyun static int meridian_mixer_init(struct oxygen *chip)
637*4882a593Smuzhiyun {
638*4882a593Smuzhiyun 	int err;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	err = generic_mixer_init(chip);
641*4882a593Smuzhiyun 	if (err < 0)
642*4882a593Smuzhiyun 		return err;
643*4882a593Smuzhiyun 	err = snd_ctl_add(chip->card,
644*4882a593Smuzhiyun 			  snd_ctl_new1(&meridian_dig_source_control, chip));
645*4882a593Smuzhiyun 	if (err < 0)
646*4882a593Smuzhiyun 		return err;
647*4882a593Smuzhiyun 	return 0;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun 
claro_mixer_init(struct oxygen * chip)650*4882a593Smuzhiyun static int claro_mixer_init(struct oxygen *chip)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun 	int err;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	err = generic_wm8785_mixer_init(chip);
655*4882a593Smuzhiyun 	if (err < 0)
656*4882a593Smuzhiyun 		return err;
657*4882a593Smuzhiyun 	err = snd_ctl_add(chip->card,
658*4882a593Smuzhiyun 			  snd_ctl_new1(&claro_dig_source_control, chip));
659*4882a593Smuzhiyun 	if (err < 0)
660*4882a593Smuzhiyun 		return err;
661*4882a593Smuzhiyun 	return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
claro_halo_mixer_init(struct oxygen * chip)664*4882a593Smuzhiyun static int claro_halo_mixer_init(struct oxygen *chip)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun 	int err;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	err = generic_mixer_init(chip);
669*4882a593Smuzhiyun 	if (err < 0)
670*4882a593Smuzhiyun 		return err;
671*4882a593Smuzhiyun 	err = snd_ctl_add(chip->card,
672*4882a593Smuzhiyun 			  snd_ctl_new1(&claro_dig_source_control, chip));
673*4882a593Smuzhiyun 	if (err < 0)
674*4882a593Smuzhiyun 		return err;
675*4882a593Smuzhiyun 	return 0;
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun 
dump_ak4396_registers(struct oxygen * chip,struct snd_info_buffer * buffer)678*4882a593Smuzhiyun static void dump_ak4396_registers(struct oxygen *chip,
679*4882a593Smuzhiyun 				  struct snd_info_buffer *buffer)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
682*4882a593Smuzhiyun 	unsigned int dac, i;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	for (dac = 0; dac < data->dacs; ++dac) {
685*4882a593Smuzhiyun 		snd_iprintf(buffer, "\nAK4396 %u:", dac + 1);
686*4882a593Smuzhiyun 		for (i = 0; i < 5; ++i)
687*4882a593Smuzhiyun 			snd_iprintf(buffer, " %02x", data->ak4396_regs[dac][i]);
688*4882a593Smuzhiyun 	}
689*4882a593Smuzhiyun 	snd_iprintf(buffer, "\n");
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun 
dump_wm8785_registers(struct oxygen * chip,struct snd_info_buffer * buffer)692*4882a593Smuzhiyun static void dump_wm8785_registers(struct oxygen *chip,
693*4882a593Smuzhiyun 				  struct snd_info_buffer *buffer)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	struct generic_data *data = chip->model_data;
696*4882a593Smuzhiyun 	unsigned int i;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	snd_iprintf(buffer, "\nWM8785:");
699*4882a593Smuzhiyun 	for (i = 0; i < 3; ++i)
700*4882a593Smuzhiyun 		snd_iprintf(buffer, " %03x", data->wm8785_regs[i]);
701*4882a593Smuzhiyun 	snd_iprintf(buffer, "\n");
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
dump_oxygen_registers(struct oxygen * chip,struct snd_info_buffer * buffer)704*4882a593Smuzhiyun static void dump_oxygen_registers(struct oxygen *chip,
705*4882a593Smuzhiyun 				  struct snd_info_buffer *buffer)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun 	dump_ak4396_registers(chip, buffer);
708*4882a593Smuzhiyun 	dump_wm8785_registers(chip, buffer);
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun static const struct oxygen_model model_generic = {
714*4882a593Smuzhiyun 	.shortname = "C-Media CMI8788",
715*4882a593Smuzhiyun 	.longname = "C-Media Oxygen HD Audio",
716*4882a593Smuzhiyun 	.chip = "CMI8788",
717*4882a593Smuzhiyun 	.init = generic_init,
718*4882a593Smuzhiyun 	.mixer_init = generic_wm8785_mixer_init,
719*4882a593Smuzhiyun 	.cleanup = generic_cleanup,
720*4882a593Smuzhiyun 	.resume = generic_resume,
721*4882a593Smuzhiyun 	.set_dac_params = set_ak4396_params,
722*4882a593Smuzhiyun 	.set_adc_params = set_wm8785_params,
723*4882a593Smuzhiyun 	.update_dac_volume = update_ak4396_volume,
724*4882a593Smuzhiyun 	.update_dac_mute = update_ak4396_mute,
725*4882a593Smuzhiyun 	.dump_registers = dump_oxygen_registers,
726*4882a593Smuzhiyun 	.dac_tlv = ak4396_db_scale,
727*4882a593Smuzhiyun 	.model_data_size = sizeof(struct generic_data),
728*4882a593Smuzhiyun 	.device_config = PLAYBACK_0_TO_I2S |
729*4882a593Smuzhiyun 			 PLAYBACK_1_TO_SPDIF |
730*4882a593Smuzhiyun 			 PLAYBACK_2_TO_AC97_1 |
731*4882a593Smuzhiyun 			 CAPTURE_0_FROM_I2S_1 |
732*4882a593Smuzhiyun 			 CAPTURE_1_FROM_SPDIF |
733*4882a593Smuzhiyun 			 CAPTURE_2_FROM_AC97_1 |
734*4882a593Smuzhiyun 			 AC97_CD_INPUT,
735*4882a593Smuzhiyun 	.dac_channels_pcm = 8,
736*4882a593Smuzhiyun 	.dac_channels_mixer = 8,
737*4882a593Smuzhiyun 	.dac_volume_min = 0,
738*4882a593Smuzhiyun 	.dac_volume_max = 255,
739*4882a593Smuzhiyun 	.function_flags = OXYGEN_FUNCTION_SPI |
740*4882a593Smuzhiyun 			  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
741*4882a593Smuzhiyun 	.dac_mclks = OXYGEN_MCLKS(256, 128, 128),
742*4882a593Smuzhiyun 	.adc_mclks = OXYGEN_MCLKS(256, 256, 128),
743*4882a593Smuzhiyun 	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
744*4882a593Smuzhiyun 	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
745*4882a593Smuzhiyun };
746*4882a593Smuzhiyun 
get_oxygen_model(struct oxygen * chip,const struct pci_device_id * id)747*4882a593Smuzhiyun static int get_oxygen_model(struct oxygen *chip,
748*4882a593Smuzhiyun 			    const struct pci_device_id *id)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun 	static const char *const names[] = {
751*4882a593Smuzhiyun 		[MODEL_MERIDIAN]	= "AuzenTech X-Meridian",
752*4882a593Smuzhiyun 		[MODEL_MERIDIAN_2G]	= "AuzenTech X-Meridian 2G",
753*4882a593Smuzhiyun 		[MODEL_CLARO]		= "HT-Omega Claro",
754*4882a593Smuzhiyun 		[MODEL_CLARO_HALO]	= "HT-Omega Claro halo",
755*4882a593Smuzhiyun 		[MODEL_FANTASIA]	= "TempoTec HiFier Fantasia",
756*4882a593Smuzhiyun 		[MODEL_SERENADE]	= "TempoTec HiFier Serenade",
757*4882a593Smuzhiyun 		[MODEL_HG2PCI]		= "CMI8787-HG2PCI",
758*4882a593Smuzhiyun 		[MODEL_XONAR_DG]        = "Xonar DG",
759*4882a593Smuzhiyun 		[MODEL_XONAR_DGX]       = "Xonar DGX",
760*4882a593Smuzhiyun 	};
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	chip->model = model_generic;
763*4882a593Smuzhiyun 	switch (id->driver_data) {
764*4882a593Smuzhiyun 	case MODEL_MERIDIAN:
765*4882a593Smuzhiyun 	case MODEL_MERIDIAN_2G:
766*4882a593Smuzhiyun 		chip->model.init = meridian_init;
767*4882a593Smuzhiyun 		chip->model.mixer_init = meridian_mixer_init;
768*4882a593Smuzhiyun 		chip->model.resume = meridian_resume;
769*4882a593Smuzhiyun 		chip->model.set_adc_params = set_ak5385_params;
770*4882a593Smuzhiyun 		chip->model.dump_registers = dump_ak4396_registers;
771*4882a593Smuzhiyun 		chip->model.device_config = PLAYBACK_0_TO_I2S |
772*4882a593Smuzhiyun 					    PLAYBACK_1_TO_SPDIF |
773*4882a593Smuzhiyun 					    CAPTURE_0_FROM_I2S_2 |
774*4882a593Smuzhiyun 					    CAPTURE_1_FROM_SPDIF;
775*4882a593Smuzhiyun 		if (id->driver_data == MODEL_MERIDIAN)
776*4882a593Smuzhiyun 			chip->model.device_config |= AC97_CD_INPUT;
777*4882a593Smuzhiyun 		break;
778*4882a593Smuzhiyun 	case MODEL_CLARO:
779*4882a593Smuzhiyun 		chip->model.init = claro_init;
780*4882a593Smuzhiyun 		chip->model.mixer_init = claro_mixer_init;
781*4882a593Smuzhiyun 		chip->model.cleanup = claro_cleanup;
782*4882a593Smuzhiyun 		chip->model.suspend = claro_suspend;
783*4882a593Smuzhiyun 		chip->model.resume = claro_resume;
784*4882a593Smuzhiyun 		break;
785*4882a593Smuzhiyun 	case MODEL_CLARO_HALO:
786*4882a593Smuzhiyun 		chip->model.init = claro_halo_init;
787*4882a593Smuzhiyun 		chip->model.mixer_init = claro_halo_mixer_init;
788*4882a593Smuzhiyun 		chip->model.cleanup = claro_cleanup;
789*4882a593Smuzhiyun 		chip->model.suspend = claro_suspend;
790*4882a593Smuzhiyun 		chip->model.resume = claro_resume;
791*4882a593Smuzhiyun 		chip->model.set_adc_params = set_ak5385_params;
792*4882a593Smuzhiyun 		chip->model.dump_registers = dump_ak4396_registers;
793*4882a593Smuzhiyun 		chip->model.device_config = PLAYBACK_0_TO_I2S |
794*4882a593Smuzhiyun 					    PLAYBACK_1_TO_SPDIF |
795*4882a593Smuzhiyun 					    CAPTURE_0_FROM_I2S_2 |
796*4882a593Smuzhiyun 					    CAPTURE_1_FROM_SPDIF;
797*4882a593Smuzhiyun 		break;
798*4882a593Smuzhiyun 	case MODEL_FANTASIA:
799*4882a593Smuzhiyun 	case MODEL_SERENADE:
800*4882a593Smuzhiyun 	case MODEL_2CH_OUTPUT:
801*4882a593Smuzhiyun 	case MODEL_HG2PCI:
802*4882a593Smuzhiyun 		chip->model.shortname = "C-Media CMI8787";
803*4882a593Smuzhiyun 		chip->model.chip = "CMI8787";
804*4882a593Smuzhiyun 		if (id->driver_data == MODEL_FANTASIA)
805*4882a593Smuzhiyun 			chip->model.init = fantasia_init;
806*4882a593Smuzhiyun 		else
807*4882a593Smuzhiyun 			chip->model.init = stereo_output_init;
808*4882a593Smuzhiyun 		chip->model.resume = stereo_resume;
809*4882a593Smuzhiyun 		chip->model.mixer_init = generic_mixer_init;
810*4882a593Smuzhiyun 		chip->model.set_adc_params = set_no_params;
811*4882a593Smuzhiyun 		chip->model.dump_registers = dump_ak4396_registers;
812*4882a593Smuzhiyun 		chip->model.device_config = PLAYBACK_0_TO_I2S |
813*4882a593Smuzhiyun 					    PLAYBACK_1_TO_SPDIF;
814*4882a593Smuzhiyun 		if (id->driver_data == MODEL_FANTASIA) {
815*4882a593Smuzhiyun 			chip->model.device_config |= CAPTURE_0_FROM_I2S_1;
816*4882a593Smuzhiyun 			chip->model.adc_mclks = OXYGEN_MCLKS(256, 128, 128);
817*4882a593Smuzhiyun 		}
818*4882a593Smuzhiyun 		chip->model.dac_channels_pcm = 2;
819*4882a593Smuzhiyun 		chip->model.dac_channels_mixer = 2;
820*4882a593Smuzhiyun 		break;
821*4882a593Smuzhiyun 	case MODEL_XONAR_DG:
822*4882a593Smuzhiyun 	case MODEL_XONAR_DGX:
823*4882a593Smuzhiyun 		chip->model = model_xonar_dg;
824*4882a593Smuzhiyun 		break;
825*4882a593Smuzhiyun 	}
826*4882a593Smuzhiyun 	if (id->driver_data == MODEL_MERIDIAN ||
827*4882a593Smuzhiyun 	    id->driver_data == MODEL_MERIDIAN_2G ||
828*4882a593Smuzhiyun 	    id->driver_data == MODEL_CLARO_HALO) {
829*4882a593Smuzhiyun 		chip->model.misc_flags = OXYGEN_MISC_MIDI;
830*4882a593Smuzhiyun 		chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
831*4882a593Smuzhiyun 	}
832*4882a593Smuzhiyun 	if (id->driver_data < ARRAY_SIZE(names) && names[id->driver_data])
833*4882a593Smuzhiyun 		chip->model.shortname = names[id->driver_data];
834*4882a593Smuzhiyun 	return 0;
835*4882a593Smuzhiyun }
836*4882a593Smuzhiyun 
generic_oxygen_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)837*4882a593Smuzhiyun static int generic_oxygen_probe(struct pci_dev *pci,
838*4882a593Smuzhiyun 				const struct pci_device_id *pci_id)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun 	static int dev;
841*4882a593Smuzhiyun 	int err;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	if (dev >= SNDRV_CARDS)
844*4882a593Smuzhiyun 		return -ENODEV;
845*4882a593Smuzhiyun 	if (!enable[dev]) {
846*4882a593Smuzhiyun 		++dev;
847*4882a593Smuzhiyun 		return -ENOENT;
848*4882a593Smuzhiyun 	}
849*4882a593Smuzhiyun 	err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
850*4882a593Smuzhiyun 			       oxygen_ids, get_oxygen_model);
851*4882a593Smuzhiyun 	if (err >= 0)
852*4882a593Smuzhiyun 		++dev;
853*4882a593Smuzhiyun 	return err;
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun static struct pci_driver oxygen_driver = {
857*4882a593Smuzhiyun 	.name = KBUILD_MODNAME,
858*4882a593Smuzhiyun 	.id_table = oxygen_ids,
859*4882a593Smuzhiyun 	.probe = generic_oxygen_probe,
860*4882a593Smuzhiyun 	.remove = oxygen_pci_remove,
861*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
862*4882a593Smuzhiyun 	.driver = {
863*4882a593Smuzhiyun 		.pm = &oxygen_pci_pm,
864*4882a593Smuzhiyun 	},
865*4882a593Smuzhiyun #endif
866*4882a593Smuzhiyun };
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun module_pci_driver(oxygen_driver);
869