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