blob: 71e38f48c6723b70eaf00c852149defd61c41718 [file] [log] [blame]
Clemens Ladisch1b8ff222007-12-23 19:52:08 +01001/*
2 * C-Media CMI8788 driver for Asus Xonar cards
3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 *
6 *
7 * This driver is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2.
9 *
10 * This driver is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this driver; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
Clemens Ladischa9d3cc42008-04-07 10:29:44 +020021 * Xonar D2/D2X
22 * ------------
23 *
Clemens Ladisch878ac3e2008-01-21 08:50:19 +010024 * CMI8788:
25 *
Clemens Ladisch1b8ff222007-12-23 19:52:08 +010026 * SPI 0 -> 1st PCM1796 (front)
Clemens Ladisch7113e952008-01-14 08:55:03 +010027 * SPI 1 -> 2nd PCM1796 (surround)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +010028 * SPI 2 -> 3rd PCM1796 (center/LFE)
Clemens Ladisch6ce6c472009-02-17 09:50:30 +010029 * SPI 4 -> 4th PCM1796 (back)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +010030 *
31 * GPIO 2 -> M0 of CS5381
32 * GPIO 3 -> M1 of CS5381
Clemens Ladisch878ac3e2008-01-21 08:50:19 +010033 * GPIO 5 <- external power present (D2X only)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +010034 * GPIO 7 -> ALT
Clemens Ladisch878ac3e2008-01-21 08:50:19 +010035 * GPIO 8 -> enable output to speakers
Clemens Ladisch1b8ff222007-12-23 19:52:08 +010036 */
37
Clemens Ladischa9d3cc42008-04-07 10:29:44 +020038/*
Clemens Ladisch5430c722008-07-28 10:28:43 +020039 * Xonar D1/DX
40 * -----------
Clemens Ladischa9d3cc42008-04-07 10:29:44 +020041 *
42 * CMI8788:
43 *
44 * I²C <-> CS4398 (front)
45 * <-> CS4362A (surround, center/LFE, back)
46 *
Clemens Ladisch5430c722008-07-28 10:28:43 +020047 * GPI 0 <- external power present (DX only)
Clemens Ladischa9d3cc42008-04-07 10:29:44 +020048 *
49 * GPIO 0 -> enable output to speakers
Clemens Ladischa8bb1ba2008-04-15 08:57:31 +020050 * GPIO 1 -> enable front panel I/O
Clemens Ladischa9d3cc42008-04-07 10:29:44 +020051 * GPIO 2 -> M0 of CS5361
52 * GPIO 3 -> M1 of CS5361
Clemens Ladisch11864b42008-04-09 09:16:14 +020053 * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
Clemens Ladischa9d3cc42008-04-07 10:29:44 +020054 *
55 * CS4398:
56 *
57 * AD0 <- 1
58 * AD1 <- 1
59 *
60 * CS4362A:
61 *
62 * AD0 <- 0
63 */
64
Clemens Ladisch7407a2e2008-09-22 09:12:11 +020065/*
66 * Xonar HDAV1.3 (Deluxe)
67 * ----------------------
68 *
69 * CMI8788:
70 *
71 * I²C <-> PCM1796 (front)
72 *
73 * GPI 0 <- external power present
74 *
75 * GPIO 0 -> enable output to speakers
76 * GPIO 2 -> M0 of CS5381
77 * GPIO 3 -> M1 of CS5381
78 * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
79 *
80 * TXD -> HDMI controller
81 * RXD <- HDMI controller
82 *
83 * PCM1796 front: AD1,0 <- 0,0
84 *
85 * no daughterboard
86 * ----------------
87 *
88 * GPIO 4 <- 1
89 *
90 * H6 daughterboard
91 * ----------------
92 *
93 * GPIO 4 <- 0
94 * GPIO 5 <- 0
95 *
96 * I²C <-> PCM1796 (surround)
97 * <-> PCM1796 (center/LFE)
98 * <-> PCM1796 (back)
99 *
100 * PCM1796 surround: AD1,0 <- 0,1
101 * PCM1796 center/LFE: AD1,0 <- 1,0
102 * PCM1796 back: AD1,0 <- 1,1
103 *
104 * unknown daughterboard
105 * ---------------------
106 *
107 * GPIO 4 <- 0
108 * GPIO 5 <- 1
109 *
110 * I²C <-> CS4362A (surround, center/LFE, back)
111 *
112 * CS4362A: AD0 <- 0
113 */
114
Clemens Ladisch930738d2009-02-26 09:27:20 +0100115/*
116 * Xonar Essence STX
117 * -----------------
118 *
119 * CMI8788:
120 *
121 * I²C <-> PCM1792A
122 *
123 * GPI 0 <- external power present
124 *
125 * GPIO 0 -> enable output to speakers
126 * GPIO 1 -> route HP to front panel (0) or rear jack (1)
127 * GPIO 2 -> M0 of CS5381
128 * GPIO 3 -> M1 of CS5381
129 * GPIO 7 -> route output to speaker jacks (0) or HP (1)
130 * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
131 *
132 * PCM1792A:
133 *
134 * AD0 <- 0
135 *
136 * H6 daughterboard
137 * ----------------
138 *
139 * GPIO 4 <- 0
140 * GPIO 5 <- 0
141 */
142
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100143#include <linux/pci.h>
144#include <linux/delay.h>
Clemens Ladischccc80fb2008-01-16 08:32:08 +0100145#include <linux/mutex.h>
146#include <sound/ac97_codec.h>
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200147#include <sound/asoundef.h>
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100148#include <sound/control.h>
149#include <sound/core.h>
150#include <sound/initval.h>
151#include <sound/pcm.h>
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200152#include <sound/pcm_params.h>
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100153#include <sound/tlv.h>
154#include "oxygen.h"
Clemens Ladisch878ac3e2008-01-21 08:50:19 +0100155#include "cm9780.h"
Clemens Ladisch33fa7242008-03-19 08:16:40 +0100156#include "pcm1796.h"
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200157#include "cs4398.h"
158#include "cs4362a.h"
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100159
160MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200161MODULE_DESCRIPTION("Asus AVx00 driver");
Clemens Ladischd023dc02008-05-13 09:18:27 +0200162MODULE_LICENSE("GPL v2");
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200163MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100164
165static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
166static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
167static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
168
169module_param_array(index, int, NULL, 0444);
170MODULE_PARM_DESC(index, "card index");
171module_param_array(id, charp, NULL, 0444);
172MODULE_PARM_DESC(id, "ID string");
173module_param_array(enable, bool, NULL, 0444);
174MODULE_PARM_DESC(enable, "enable card");
175
Clemens Ladisch271ebfc2008-04-07 10:24:22 +0200176enum {
177 MODEL_D2,
178 MODEL_D2X,
Clemens Ladisch5430c722008-07-28 10:28:43 +0200179 MODEL_D1,
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200180 MODEL_DX,
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200181 MODEL_HDAV, /* without daughterboard */
182 MODEL_HDAV_H6, /* with H6 daughterboard */
Clemens Ladisch930738d2009-02-26 09:27:20 +0100183 MODEL_STX,
Clemens Ladisch271ebfc2008-04-07 10:24:22 +0200184};
185
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100186static struct pci_device_id xonar_ids[] __devinitdata = {
Clemens Ladisch271ebfc2008-04-07 10:24:22 +0200187 { OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 },
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200188 { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX },
Clemens Ladisch271ebfc2008-04-07 10:24:22 +0200189 { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X },
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200190 { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV },
Clemens Ladisch53bb7052009-05-25 10:05:43 +0200191 { OXYGEN_PCI_SUBID(0x1043, 0x8327), .driver_data = MODEL_DX },
Clemens Ladisch5430c722008-07-28 10:28:43 +0200192 { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 },
Clemens Ladisch930738d2009-02-26 09:27:20 +0100193 { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX },
Clemens Ladisch30459d72009-02-19 08:42:44 +0100194 { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100195 { }
196};
197MODULE_DEVICE_TABLE(pci, xonar_ids);
198
Clemens Ladisch878ac3e2008-01-21 08:50:19 +0100199
Clemens Ladischa694a6a2008-04-07 10:25:30 +0200200#define GPIO_CS53x1_M_MASK 0x000c
201#define GPIO_CS53x1_M_SINGLE 0x0000
202#define GPIO_CS53x1_M_DOUBLE 0x0004
203#define GPIO_CS53x1_M_QUAD 0x0008
204
Clemens Ladischaf9af172008-04-07 10:26:03 +0200205#define GPIO_D2X_EXT_POWER 0x0020
206#define GPIO_D2_ALT 0x0080
207#define GPIO_D2_OUTPUT_ENABLE 0x0100
Clemens Ladisch878ac3e2008-01-21 08:50:19 +0100208
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200209#define GPI_DX_EXT_POWER 0x01
210#define GPIO_DX_OUTPUT_ENABLE 0x0001
Clemens Ladischa8bb1ba2008-04-15 08:57:31 +0200211#define GPIO_DX_FRONT_PANEL 0x0002
Clemens Ladisch11864b42008-04-09 09:16:14 +0200212#define GPIO_DX_INPUT_ROUTE 0x0100
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200213
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200214#define GPIO_HDAV_DB_MASK 0x0030
215#define GPIO_HDAV_DB_H6 0x0000
216#define GPIO_HDAV_DB_XX 0x0020
217
Clemens Ladisch930738d2009-02-26 09:27:20 +0100218#define GPIO_ST_HP_REAR 0x0002
219#define GPIO_ST_HP 0x0080
220
Clemens Ladisch4f50d2f2008-09-22 09:06:04 +0200221#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200222#define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */
223#define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */
224
Clemens Ladisch7c014152008-01-28 08:36:55 +0100225struct xonar_data {
Clemens Ladischaf9af172008-04-07 10:26:03 +0200226 unsigned int anti_pop_delay;
Clemens Ladisch70c27d32008-09-22 09:06:38 +0200227 unsigned int dacs;
Clemens Ladischaf9af172008-04-07 10:26:03 +0200228 u16 output_enable_bit;
229 u8 ext_power_reg;
230 u8 ext_power_int_reg;
231 u8 ext_power_bit;
Clemens Ladisch7c014152008-01-28 08:36:55 +0100232 u8 has_power;
Clemens Ladische58aee92008-05-13 09:20:51 +0200233 u8 pcm1796_oversampling;
234 u8 cs4398_fm;
235 u8 cs4362a_fm;
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200236 u8 hdmi_params[5];
Clemens Ladisch7c014152008-01-28 08:36:55 +0100237};
238
Clemens Ladischfe106622008-09-22 09:00:30 +0200239static void xonar_gpio_changed(struct oxygen *chip);
240
Clemens Ladisch4f50d2f2008-09-22 09:06:04 +0200241static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
242 u8 reg, u8 value)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100243{
244 /* maps ALSA channel pair number to SPI output */
245 static const u8 codec_map[4] = {
Clemens Ladisch7113e952008-01-14 08:55:03 +0100246 0, 1, 2, 4
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100247 };
Clemens Ladischc2353a02008-01-18 09:17:53 +0100248 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100249 OXYGEN_SPI_DATA_LENGTH_2 |
Clemens Ladischc2353a02008-01-18 09:17:53 +0100250 OXYGEN_SPI_CLOCK_160 |
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100251 (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
Clemens Ladischc2353a02008-01-18 09:17:53 +0100252 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100253 (reg << 8) | value);
254}
255
Clemens Ladisch4f50d2f2008-09-22 09:06:04 +0200256static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
257 u8 reg, u8 value)
258{
259 oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);
260}
261
262static void pcm1796_write(struct oxygen *chip, unsigned int codec,
263 u8 reg, u8 value)
264{
265 if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
266 OXYGEN_FUNCTION_SPI)
267 pcm1796_write_spi(chip, codec, reg, value);
268 else
269 pcm1796_write_i2c(chip, codec, reg, value);
270}
271
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200272static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
273{
274 oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value);
275}
276
277static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value)
278{
279 oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
280}
281
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200282static void hdmi_write_command(struct oxygen *chip, u8 command,
283 unsigned int count, const u8 *params)
284{
285 unsigned int i;
286 u8 checksum;
287
288 oxygen_write_uart(chip, 0xfb);
289 oxygen_write_uart(chip, 0xef);
290 oxygen_write_uart(chip, command);
291 oxygen_write_uart(chip, count);
292 for (i = 0; i < count; ++i)
293 oxygen_write_uart(chip, params[i]);
294 checksum = 0xfb + 0xef + command + count;
295 for (i = 0; i < count; ++i)
296 checksum += params[i];
297 oxygen_write_uart(chip, checksum);
298}
299
Clemens Ladisch92215f32008-05-13 09:23:02 +0200300static void xonar_enable_output(struct oxygen *chip)
301{
302 struct xonar_data *data = chip->model_data;
303
304 msleep(data->anti_pop_delay);
305 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
306}
307
Clemens Ladischaf9af172008-04-07 10:26:03 +0200308static void xonar_common_init(struct oxygen *chip)
309{
310 struct xonar_data *data = chip->model_data;
311
312 if (data->ext_power_reg) {
313 oxygen_set_bits8(chip, data->ext_power_int_reg,
314 data->ext_power_bit);
315 chip->interrupt_mask |= OXYGEN_INT_GPIO;
Clemens Ladischfe106622008-09-22 09:00:30 +0200316 chip->model.gpio_changed = xonar_gpio_changed;
Clemens Ladischaf9af172008-04-07 10:26:03 +0200317 data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
318 & data->ext_power_bit);
319 }
Clemens Ladisch92215f32008-05-13 09:23:02 +0200320 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
321 GPIO_CS53x1_M_MASK | data->output_enable_bit);
Clemens Ladischaf9af172008-04-07 10:26:03 +0200322 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
323 GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK);
324 oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
Clemens Ladisch92215f32008-05-13 09:23:02 +0200325 xonar_enable_output(chip);
Clemens Ladischaf9af172008-04-07 10:26:03 +0200326}
327
Clemens Ladischbbbfb552008-05-13 09:21:48 +0200328static void update_pcm1796_volume(struct oxygen *chip)
329{
Clemens Ladisch70c27d32008-09-22 09:06:38 +0200330 struct xonar_data *data = chip->model_data;
Clemens Ladischbbbfb552008-05-13 09:21:48 +0200331 unsigned int i;
332
Clemens Ladisch70c27d32008-09-22 09:06:38 +0200333 for (i = 0; i < data->dacs; ++i) {
Clemens Ladischbbbfb552008-05-13 09:21:48 +0200334 pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]);
335 pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]);
336 }
337}
338
339static void update_pcm1796_mute(struct oxygen *chip)
340{
Clemens Ladisch70c27d32008-09-22 09:06:38 +0200341 struct xonar_data *data = chip->model_data;
Clemens Ladischbbbfb552008-05-13 09:21:48 +0200342 unsigned int i;
343 u8 value;
344
345 value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
346 if (chip->dac_mute)
347 value |= PCM1796_MUTE;
Clemens Ladisch70c27d32008-09-22 09:06:38 +0200348 for (i = 0; i < data->dacs; ++i)
Clemens Ladischbbbfb552008-05-13 09:21:48 +0200349 pcm1796_write(chip, i, 18, value);
350}
351
Clemens Ladisch75146fc2008-05-13 09:22:43 +0200352static void pcm1796_init(struct oxygen *chip)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100353{
Clemens Ladischaf9af172008-04-07 10:26:03 +0200354 struct xonar_data *data = chip->model_data;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100355 unsigned int i;
356
Clemens Ladisch70c27d32008-09-22 09:06:38 +0200357 for (i = 0; i < data->dacs; ++i) {
Clemens Ladisch878ac3e2008-01-21 08:50:19 +0100358 pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
Clemens Ladische58aee92008-05-13 09:20:51 +0200359 pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
Clemens Ladisch878ac3e2008-01-21 08:50:19 +0100360 pcm1796_write(chip, i, 21, 0);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100361 }
Clemens Ladischbbbfb552008-05-13 09:21:48 +0200362 update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */
363 update_pcm1796_volume(chip);
Clemens Ladisch75146fc2008-05-13 09:22:43 +0200364}
365
366static void xonar_d2_init(struct oxygen *chip)
367{
368 struct xonar_data *data = chip->model_data;
369
370 data->anti_pop_delay = 300;
Clemens Ladisch30459d72009-02-19 08:42:44 +0100371 data->dacs = 4;
Clemens Ladisch75146fc2008-05-13 09:22:43 +0200372 data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
373 data->pcm1796_oversampling = PCM1796_OS_64;
374
375 pcm1796_init(chip);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100376
Clemens Ladischaf9af172008-04-07 10:26:03 +0200377 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);
378 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);
379
380 xonar_common_init(chip);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100381
382 snd_component_add(chip->card, "PCM1796");
383 snd_component_add(chip->card, "CS5381");
384}
385
Clemens Ladisch30459d72009-02-19 08:42:44 +0100386static void xonar_d2x_init(struct oxygen *chip)
387{
388 struct xonar_data *data = chip->model_data;
389
390 data->ext_power_reg = OXYGEN_GPIO_DATA;
391 data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
392 data->ext_power_bit = GPIO_D2X_EXT_POWER;
393 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
394
395 xonar_d2_init(chip);
396}
397
Clemens Ladischbbbfb552008-05-13 09:21:48 +0200398static void update_cs4362a_volumes(struct oxygen *chip)
399{
400 u8 mute;
401
402 mute = chip->dac_mute ? CS4362A_MUTE : 0;
403 cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute);
404 cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute);
405 cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute);
406 cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute);
407 cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute);
408 cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute);
409}
410
411static void update_cs43xx_volume(struct oxygen *chip)
412{
413 cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2);
414 cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2);
415 update_cs4362a_volumes(chip);
416}
417
418static void update_cs43xx_mute(struct oxygen *chip)
419{
420 u8 reg;
421
422 reg = CS4398_MUTEP_LOW | CS4398_PAMUTE;
423 if (chip->dac_mute)
424 reg |= CS4398_MUTE_B | CS4398_MUTE_A;
425 cs4398_write(chip, 4, reg);
426 update_cs4362a_volumes(chip);
427}
428
Clemens Ladisch75146fc2008-05-13 09:22:43 +0200429static void cs43xx_init(struct oxygen *chip)
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200430{
431 struct xonar_data *data = chip->model_data;
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200432
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200433 /* set CPEN (control port mode) and power down */
434 cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN);
435 cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
436 /* configure */
Clemens Ladische58aee92008-05-13 09:20:51 +0200437 cs4398_write(chip, 2, data->cs4398_fm);
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200438 cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L);
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200439 cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP |
440 CS4398_ZERO_CROSS | CS4398_SOFT_RAMP);
441 cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST);
442 cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE |
443 CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP);
444 cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE);
445 cs4362a_write(chip, 0x05, 0);
Clemens Ladische58aee92008-05-13 09:20:51 +0200446 cs4362a_write(chip, 0x06, data->cs4362a_fm);
Clemens Ladische58aee92008-05-13 09:20:51 +0200447 cs4362a_write(chip, 0x09, data->cs4362a_fm);
Clemens Ladische58aee92008-05-13 09:20:51 +0200448 cs4362a_write(chip, 0x0c, data->cs4362a_fm);
Clemens Ladischbbbfb552008-05-13 09:21:48 +0200449 update_cs43xx_volume(chip);
450 update_cs43xx_mute(chip);
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200451 /* clear power down */
452 cs4398_write(chip, 8, CS4398_CPEN);
453 cs4362a_write(chip, 0x01, CS4362A_CPEN);
Clemens Ladisch75146fc2008-05-13 09:22:43 +0200454}
455
Clemens Ladisch5430c722008-07-28 10:28:43 +0200456static void xonar_d1_init(struct oxygen *chip)
Clemens Ladisch75146fc2008-05-13 09:22:43 +0200457{
458 struct xonar_data *data = chip->model_data;
459
460 data->anti_pop_delay = 800;
461 data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
Clemens Ladisch75146fc2008-05-13 09:22:43 +0200462 data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
463 data->cs4362a_fm = CS4362A_FM_SINGLE |
464 CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
465
466 oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
467 OXYGEN_2WIRE_LENGTH_8 |
468 OXYGEN_2WIRE_INTERRUPT_MASK |
469 OXYGEN_2WIRE_SPEED_FAST);
470
471 cs43xx_init(chip);
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200472
473 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
Clemens Ladischa8bb1ba2008-04-15 08:57:31 +0200474 GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
475 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
476 GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200477
478 xonar_common_init(chip);
479
480 snd_component_add(chip->card, "CS4398");
481 snd_component_add(chip->card, "CS4362A");
482 snd_component_add(chip->card, "CS5361");
483}
484
Clemens Ladisch30459d72009-02-19 08:42:44 +0100485static void xonar_dx_init(struct oxygen *chip)
486{
487 struct xonar_data *data = chip->model_data;
488
489 data->ext_power_reg = OXYGEN_GPI_DATA;
490 data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
491 data->ext_power_bit = GPI_DX_EXT_POWER;
492
493 xonar_d1_init(chip);
494}
495
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200496static void xonar_hdav_init(struct oxygen *chip)
497{
498 struct xonar_data *data = chip->model_data;
499 u8 param;
500
501 oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
502 OXYGEN_2WIRE_LENGTH_8 |
503 OXYGEN_2WIRE_INTERRUPT_MASK |
504 OXYGEN_2WIRE_SPEED_FAST);
505
506 data->anti_pop_delay = 100;
Clemens Ladisch30459d72009-02-19 08:42:44 +0100507 data->dacs = chip->model.private_data == MODEL_HDAV_H6 ? 4 : 1;
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200508 data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
509 data->ext_power_reg = OXYGEN_GPI_DATA;
510 data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
511 data->ext_power_bit = GPI_DX_EXT_POWER;
512 data->pcm1796_oversampling = PCM1796_OS_64;
513
514 pcm1796_init(chip);
515
516 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DX_INPUT_ROUTE);
517 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DX_INPUT_ROUTE);
518
519 oxygen_reset_uart(chip);
520 param = 0;
521 hdmi_write_command(chip, 0x61, 1, &param);
522 param = 1;
523 hdmi_write_command(chip, 0x74, 1, &param);
524 data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
525 data->hdmi_params[4] = 1;
526 hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
527
528 xonar_common_init(chip);
529
530 snd_component_add(chip->card, "PCM1796");
531 snd_component_add(chip->card, "CS5381");
532}
533
Clemens Ladisch930738d2009-02-26 09:27:20 +0100534static void xonar_stx_init(struct oxygen *chip)
535{
536 struct xonar_data *data = chip->model_data;
537
538 oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
539 OXYGEN_2WIRE_LENGTH_8 |
540 OXYGEN_2WIRE_INTERRUPT_MASK |
541 OXYGEN_2WIRE_SPEED_FAST);
542
543 data->anti_pop_delay = 100;
544 data->dacs = 1;
545 data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
546 data->ext_power_reg = OXYGEN_GPI_DATA;
547 data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
548 data->ext_power_bit = GPI_DX_EXT_POWER;
549 data->pcm1796_oversampling = PCM1796_OS_64;
550
551 pcm1796_init(chip);
552
553 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
554 GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
555 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
556 GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
557
558 xonar_common_init(chip);
559
560 snd_component_add(chip->card, "PCM1792A");
561 snd_component_add(chip->card, "CS5381");
562}
563
Clemens Ladischc2bc4ff2008-09-22 09:05:29 +0200564static void xonar_disable_output(struct oxygen *chip)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100565{
Clemens Ladischaf9af172008-04-07 10:26:03 +0200566 struct xonar_data *data = chip->model_data;
567
568 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100569}
570
Clemens Ladischc2bc4ff2008-09-22 09:05:29 +0200571static void xonar_d2_cleanup(struct oxygen *chip)
572{
573 xonar_disable_output(chip);
574}
575
Clemens Ladisch5430c722008-07-28 10:28:43 +0200576static void xonar_d1_cleanup(struct oxygen *chip)
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200577{
Clemens Ladischc2bc4ff2008-09-22 09:05:29 +0200578 xonar_disable_output(chip);
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200579 cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
580 oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
581}
582
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200583static void xonar_hdav_cleanup(struct oxygen *chip)
584{
585 u8 param = 0;
586
587 hdmi_write_command(chip, 0x74, 1, &param);
588 xonar_disable_output(chip);
589}
590
Clemens Ladisch930738d2009-02-26 09:27:20 +0100591static void xonar_st_cleanup(struct oxygen *chip)
592{
593 xonar_disable_output(chip);
594}
595
Clemens Ladischc2bc4ff2008-09-22 09:05:29 +0200596static void xonar_d2_suspend(struct oxygen *chip)
597{
598 xonar_d2_cleanup(chip);
599}
600
601static void xonar_d1_suspend(struct oxygen *chip)
602{
603 xonar_d1_cleanup(chip);
604}
605
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200606static void xonar_hdav_suspend(struct oxygen *chip)
607{
608 xonar_hdav_cleanup(chip);
609 msleep(2);
610}
611
Clemens Ladisch930738d2009-02-26 09:27:20 +0100612static void xonar_st_suspend(struct oxygen *chip)
613{
614 xonar_st_cleanup(chip);
615}
616
Clemens Ladisch4a4bc532008-05-13 09:24:39 +0200617static void xonar_d2_resume(struct oxygen *chip)
618{
619 pcm1796_init(chip);
620 xonar_enable_output(chip);
621}
622
Clemens Ladisch5430c722008-07-28 10:28:43 +0200623static void xonar_d1_resume(struct oxygen *chip)
Clemens Ladisch4a4bc532008-05-13 09:24:39 +0200624{
625 cs43xx_init(chip);
626 xonar_enable_output(chip);
627}
628
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200629static void xonar_hdav_resume(struct oxygen *chip)
630{
631 struct xonar_data *data = chip->model_data;
632 u8 param;
633
634 oxygen_reset_uart(chip);
635 param = 0;
636 hdmi_write_command(chip, 0x61, 1, &param);
637 param = 1;
638 hdmi_write_command(chip, 0x74, 1, &param);
639 hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
640 pcm1796_init(chip);
641 xonar_enable_output(chip);
642}
643
Clemens Ladisch930738d2009-02-26 09:27:20 +0100644static void xonar_st_resume(struct oxygen *chip)
645{
646 pcm1796_init(chip);
647 xonar_enable_output(chip);
648}
649
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200650static void xonar_hdav_pcm_hardware_filter(unsigned int channel,
651 struct snd_pcm_hardware *hardware)
652{
653 if (channel == PCM_MULTICH) {
654 hardware->rates = SNDRV_PCM_RATE_44100 |
655 SNDRV_PCM_RATE_48000 |
656 SNDRV_PCM_RATE_96000 |
657 SNDRV_PCM_RATE_192000;
658 hardware->rate_min = 44100;
659 }
660}
661
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100662static void set_pcm1796_params(struct oxygen *chip,
663 struct snd_pcm_hw_params *params)
664{
Clemens Ladische58aee92008-05-13 09:20:51 +0200665 struct xonar_data *data = chip->model_data;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100666 unsigned int i;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100667
Clemens Ladische58aee92008-05-13 09:20:51 +0200668 data->pcm1796_oversampling =
669 params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
Clemens Ladisch70c27d32008-09-22 09:06:38 +0200670 for (i = 0; i < data->dacs; ++i)
Clemens Ladische58aee92008-05-13 09:20:51 +0200671 pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100672}
673
Clemens Ladischa694a6a2008-04-07 10:25:30 +0200674static void set_cs53x1_params(struct oxygen *chip,
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100675 struct snd_pcm_hw_params *params)
676{
677 unsigned int value;
678
679 if (params_rate(params) <= 54000)
Clemens Ladischa694a6a2008-04-07 10:25:30 +0200680 value = GPIO_CS53x1_M_SINGLE;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100681 else if (params_rate(params) <= 108000)
Clemens Ladischa694a6a2008-04-07 10:25:30 +0200682 value = GPIO_CS53x1_M_DOUBLE;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100683 else
Clemens Ladischa694a6a2008-04-07 10:25:30 +0200684 value = GPIO_CS53x1_M_QUAD;
Clemens Ladisch878ac3e2008-01-21 08:50:19 +0100685 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
Clemens Ladischa694a6a2008-04-07 10:25:30 +0200686 value, GPIO_CS53x1_M_MASK);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100687}
688
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200689static void set_cs43xx_params(struct oxygen *chip,
690 struct snd_pcm_hw_params *params)
691{
Clemens Ladische58aee92008-05-13 09:20:51 +0200692 struct xonar_data *data = chip->model_data;
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200693
Clemens Ladische58aee92008-05-13 09:20:51 +0200694 data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST;
695 data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200696 if (params_rate(params) <= 50000) {
Clemens Ladische58aee92008-05-13 09:20:51 +0200697 data->cs4398_fm |= CS4398_FM_SINGLE;
698 data->cs4362a_fm |= CS4362A_FM_SINGLE;
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200699 } else if (params_rate(params) <= 100000) {
Clemens Ladische58aee92008-05-13 09:20:51 +0200700 data->cs4398_fm |= CS4398_FM_DOUBLE;
701 data->cs4362a_fm |= CS4362A_FM_DOUBLE;
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200702 } else {
Clemens Ladische58aee92008-05-13 09:20:51 +0200703 data->cs4398_fm |= CS4398_FM_QUAD;
704 data->cs4362a_fm |= CS4362A_FM_QUAD;
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200705 }
Clemens Ladische58aee92008-05-13 09:20:51 +0200706 cs4398_write(chip, 2, data->cs4398_fm);
707 cs4362a_write(chip, 0x06, data->cs4362a_fm);
708 cs4362a_write(chip, 0x09, data->cs4362a_fm);
709 cs4362a_write(chip, 0x0c, data->cs4362a_fm);
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200710}
711
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200712static void set_hdmi_params(struct oxygen *chip,
713 struct snd_pcm_hw_params *params)
714{
715 struct xonar_data *data = chip->model_data;
716
717 data->hdmi_params[0] = 0; /* 1 = non-audio */
718 switch (params_rate(params)) {
719 case 44100:
720 data->hdmi_params[1] = IEC958_AES3_CON_FS_44100;
721 break;
722 case 48000:
723 data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
724 break;
725 default: /* 96000 */
726 data->hdmi_params[1] = IEC958_AES3_CON_FS_96000;
727 break;
728 case 192000:
729 data->hdmi_params[1] = IEC958_AES3_CON_FS_192000;
730 break;
731 }
732 data->hdmi_params[2] = params_channels(params) / 2 - 1;
733 if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
734 data->hdmi_params[3] = 0;
735 else
736 data->hdmi_params[3] = 0xc0;
737 data->hdmi_params[4] = 1; /* ? */
738 hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
739}
740
741static void set_hdav_params(struct oxygen *chip,
742 struct snd_pcm_hw_params *params)
743{
744 set_pcm1796_params(chip, params);
745 set_hdmi_params(chip, params);
746}
747
Clemens Ladisch7c014152008-01-28 08:36:55 +0100748static void xonar_gpio_changed(struct oxygen *chip)
749{
750 struct xonar_data *data = chip->model_data;
751 u8 has_power;
752
Clemens Ladischaf9af172008-04-07 10:26:03 +0200753 has_power = !!(oxygen_read8(chip, data->ext_power_reg)
754 & data->ext_power_bit);
Clemens Ladisch7c014152008-01-28 08:36:55 +0100755 if (has_power != data->has_power) {
756 data->has_power = has_power;
757 if (has_power) {
758 snd_printk(KERN_NOTICE "power restored\n");
759 } else {
760 snd_printk(KERN_CRIT
761 "Hey! Don't unplug the power cable!\n");
762 /* TODO: stop PCMs */
763 }
764 }
765}
766
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200767static void xonar_hdav_uart_input(struct oxygen *chip)
768{
769 if (chip->uart_input_count >= 2 &&
770 chip->uart_input[chip->uart_input_count - 2] == 'O' &&
771 chip->uart_input[chip->uart_input_count - 1] == 'K') {
Clemens Ladisch45bf8102009-01-19 10:07:58 +0100772 printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:\n");
Clemens Ladisch7407a2e2008-09-22 09:12:11 +0200773 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
774 chip->uart_input, chip->uart_input_count);
775 chip->uart_input_count = 0;
776 }
777}
778
Clemens Ladischc3f00732008-09-22 09:01:11 +0200779static int gpio_bit_switch_get(struct snd_kcontrol *ctl,
780 struct snd_ctl_elem_value *value)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100781{
782 struct oxygen *chip = ctl->private_data;
Clemens Ladischc3f00732008-09-22 09:01:11 +0200783 u16 bit = ctl->private_value;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100784
785 value->value.integer.value[0] =
Clemens Ladischc3f00732008-09-22 09:01:11 +0200786 !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100787 return 0;
788}
789
Clemens Ladischc3f00732008-09-22 09:01:11 +0200790static int gpio_bit_switch_put(struct snd_kcontrol *ctl,
791 struct snd_ctl_elem_value *value)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100792{
793 struct oxygen *chip = ctl->private_data;
Clemens Ladischc3f00732008-09-22 09:01:11 +0200794 u16 bit = ctl->private_value;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100795 u16 old_bits, new_bits;
796 int changed;
797
798 spin_lock_irq(&chip->reg_lock);
799 old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
800 if (value->value.integer.value[0])
Clemens Ladischc3f00732008-09-22 09:01:11 +0200801 new_bits = old_bits | bit;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100802 else
Clemens Ladischc3f00732008-09-22 09:01:11 +0200803 new_bits = old_bits & ~bit;
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100804 changed = new_bits != old_bits;
805 if (changed)
806 oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
807 spin_unlock_irq(&chip->reg_lock);
808 return changed;
809}
810
811static const struct snd_kcontrol_new alt_switch = {
812 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
813 .name = "Analog Loopback Switch",
814 .info = snd_ctl_boolean_mono_info,
Clemens Ladischc3f00732008-09-22 09:01:11 +0200815 .get = gpio_bit_switch_get,
816 .put = gpio_bit_switch_put,
817 .private_value = GPIO_D2_ALT,
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100818};
819
Clemens Ladischa8bb1ba2008-04-15 08:57:31 +0200820static const struct snd_kcontrol_new front_panel_switch = {
Clemens Ladisch387fb6a2008-04-11 10:24:48 +0200821 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Clemens Ladischa8bb1ba2008-04-15 08:57:31 +0200822 .name = "Front Panel Switch",
823 .info = snd_ctl_boolean_mono_info,
Clemens Ladischc3f00732008-09-22 09:01:11 +0200824 .get = gpio_bit_switch_get,
825 .put = gpio_bit_switch_put,
826 .private_value = GPIO_DX_FRONT_PANEL,
Clemens Ladisch387fb6a2008-04-11 10:24:48 +0200827};
828
Clemens Ladisch930738d2009-02-26 09:27:20 +0100829static int st_output_switch_info(struct snd_kcontrol *ctl,
830 struct snd_ctl_elem_info *info)
831{
832 static const char *const names[3] = {
833 "Speakers", "Headphones", "FP Headphones"
834 };
835
836 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
837 info->count = 1;
838 info->value.enumerated.items = 3;
839 if (info->value.enumerated.item >= 3)
840 info->value.enumerated.item = 2;
841 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
842 return 0;
843}
844
845static int st_output_switch_get(struct snd_kcontrol *ctl,
846 struct snd_ctl_elem_value *value)
847{
848 struct oxygen *chip = ctl->private_data;
849 u16 gpio;
850
851 gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
852 if (!(gpio & GPIO_ST_HP))
853 value->value.enumerated.item[0] = 0;
854 else if (gpio & GPIO_ST_HP_REAR)
855 value->value.enumerated.item[0] = 1;
856 else
857 value->value.enumerated.item[0] = 2;
858 return 0;
859}
860
861
862static int st_output_switch_put(struct snd_kcontrol *ctl,
863 struct snd_ctl_elem_value *value)
864{
865 struct oxygen *chip = ctl->private_data;
866 u16 gpio_old, gpio;
867
868 mutex_lock(&chip->mutex);
869 gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
870 gpio = gpio_old;
871 switch (value->value.enumerated.item[0]) {
872 case 0:
873 gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);
874 break;
875 case 1:
876 gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;
877 break;
878 case 2:
879 gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;
880 break;
881 }
882 oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
883 mutex_unlock(&chip->mutex);
884 return gpio != gpio_old;
885}
886
887static const struct snd_kcontrol_new st_output_switch = {
888 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
889 .name = "Analog Output",
890 .info = st_output_switch_info,
891 .get = st_output_switch_get,
892 .put = st_output_switch_put,
893};
894
Clemens Ladischc871c4a2008-09-22 09:07:20 +0200895static void xonar_line_mic_ac97_switch(struct oxygen *chip,
896 unsigned int reg, unsigned int mute)
Clemens Ladisch11864b42008-04-09 09:16:14 +0200897{
898 if (reg == AC97_LINE) {
899 spin_lock_irq(&chip->reg_lock);
900 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
901 mute ? GPIO_DX_INPUT_ROUTE : 0,
902 GPIO_DX_INPUT_ROUTE);
903 spin_unlock_irq(&chip->reg_lock);
904 }
905}
906
Clemens Ladischeacbb9d2009-02-20 09:33:40 +0100907static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
908static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100909
Clemens Ladischaf9af172008-04-07 10:26:03 +0200910static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
Clemens Ladischccc80fb2008-01-16 08:32:08 +0100911{
Clemens Ladisch4972a172008-04-16 09:15:45 +0200912 if (!strncmp(template->name, "CD Capture ", 11))
Clemens Ladisch911b4992008-01-28 08:33:44 +0100913 /* CD in is actually connected to the video in pin */
Clemens Ladischccc80fb2008-01-16 08:32:08 +0100914 template->private_value ^= AC97_CD ^ AC97_VIDEO;
Clemens Ladischccc80fb2008-01-16 08:32:08 +0100915 return 0;
916}
917
Clemens Ladisch5430c722008-07-28 10:28:43 +0200918static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200919{
Clemens Ladisch4972a172008-04-16 09:15:45 +0200920 if (!strncmp(template->name, "CD Capture ", 11))
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200921 return 1; /* no CD input */
Clemens Ladischa9d3cc42008-04-07 10:29:44 +0200922 return 0;
923}
924
Clemens Ladisch930738d2009-02-26 09:27:20 +0100925static int xonar_st_control_filter(struct snd_kcontrol_new *template)
926{
927 if (!strncmp(template->name, "CD Capture ", 11))
928 return 1; /* no CD input */
929 if (!strcmp(template->name, "Stereo Upmixing"))
930 return 1; /* stereo only - we don't need upmixing */
931 return 0;
932}
933
Clemens Ladischfe106622008-09-22 09:00:30 +0200934static int xonar_d2_mixer_init(struct oxygen *chip)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +0100935{
936 return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
937}
938
Clemens Ladisch5430c722008-07-28 10:28:43 +0200939static int xonar_d1_mixer_init(struct oxygen *chip)
Clemens Ladisch387fb6a2008-04-11 10:24:48 +0200940{
Clemens Ladischa8bb1ba2008-04-15 08:57:31 +0200941 return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
Clemens Ladisch387fb6a2008-04-11 10:24:48 +0200942}
943
Clemens Ladisch930738d2009-02-26 09:27:20 +0100944static int xonar_st_mixer_init(struct oxygen *chip)
945{
946 return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip));
947}
948
Clemens Ladischfe106622008-09-22 09:00:30 +0200949static const struct oxygen_model model_xonar_d2 = {
950 .longname = "Asus Virtuoso 200",
951 .chip = "AV200",
Clemens Ladischfe106622008-09-22 09:00:30 +0200952 .init = xonar_d2_init,
953 .control_filter = xonar_d2_control_filter,
954 .mixer_init = xonar_d2_mixer_init,
Clemens Ladischc2bc4ff2008-09-22 09:05:29 +0200955 .cleanup = xonar_d2_cleanup,
956 .suspend = xonar_d2_suspend,
Clemens Ladischfe106622008-09-22 09:00:30 +0200957 .resume = xonar_d2_resume,
958 .set_dac_params = set_pcm1796_params,
959 .set_adc_params = set_cs53x1_params,
960 .update_dac_volume = update_pcm1796_volume,
961 .update_dac_mute = update_pcm1796_mute,
962 .dac_tlv = pcm1796_db_scale,
963 .model_data_size = sizeof(struct xonar_data),
Clemens Ladischd76596b2008-09-22 09:02:08 +0200964 .device_config = PLAYBACK_0_TO_I2S |
965 PLAYBACK_1_TO_SPDIF |
966 CAPTURE_0_FROM_I2S_2 |
Clemens Ladischdbbbd672008-09-22 09:03:42 +0200967 CAPTURE_1_FROM_SPDIF |
968 MIDI_OUTPUT |
969 MIDI_INPUT,
Clemens Ladischfe106622008-09-22 09:00:30 +0200970 .dac_channels = 8,
Clemens Ladischeacbb9d2009-02-20 09:33:40 +0100971 .dac_volume_min = 255 - 2*60,
972 .dac_volume_max = 255,
Clemens Ladischfe106622008-09-22 09:00:30 +0200973 .misc_flags = OXYGEN_MISC_MIDI,
Clemens Ladisch6ce6c472009-02-17 09:50:30 +0100974 .function_flags = OXYGEN_FUNCTION_SPI |
975 OXYGEN_FUNCTION_ENABLE_SPI_4_5,
976 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
Clemens Ladischfe106622008-09-22 09:00:30 +0200977 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
978};
979
980static const struct oxygen_model model_xonar_d1 = {
981 .longname = "Asus Virtuoso 100",
982 .chip = "AV200",
Clemens Ladischfe106622008-09-22 09:00:30 +0200983 .init = xonar_d1_init,
984 .control_filter = xonar_d1_control_filter,
985 .mixer_init = xonar_d1_mixer_init,
986 .cleanup = xonar_d1_cleanup,
Clemens Ladischc2bc4ff2008-09-22 09:05:29 +0200987 .suspend = xonar_d1_suspend,
Clemens Ladischfe106622008-09-22 09:00:30 +0200988 .resume = xonar_d1_resume,
989 .set_dac_params = set_cs43xx_params,
990 .set_adc_params = set_cs53x1_params,
991 .update_dac_volume = update_cs43xx_volume,
992 .update_dac_mute = update_cs43xx_mute,
Clemens Ladischc871c4a2008-09-22 09:07:20 +0200993 .ac97_switch = xonar_line_mic_ac97_switch,
Clemens Ladischfe106622008-09-22 09:00:30 +0200994 .dac_tlv = cs4362a_db_scale,
995 .model_data_size = sizeof(struct xonar_data),
Clemens Ladischd76596b2008-09-22 09:02:08 +0200996 .device_config = PLAYBACK_0_TO_I2S |
997 PLAYBACK_1_TO_SPDIF |
998 CAPTURE_0_FROM_I2S_2,
Clemens Ladischfe106622008-09-22 09:00:30 +0200999 .dac_channels = 8,
Clemens Ladischeacbb9d2009-02-20 09:33:40 +01001000 .dac_volume_min = 127 - 60,
Clemens Ladischfe106622008-09-22 09:00:30 +02001001 .dac_volume_max = 127,
1002 .function_flags = OXYGEN_FUNCTION_2WIRE,
1003 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1004 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
Clemens Ladisch1b8ff222007-12-23 19:52:08 +01001005};
1006
Clemens Ladisch7407a2e2008-09-22 09:12:11 +02001007static const struct oxygen_model model_xonar_hdav = {
1008 .longname = "Asus Virtuoso 200",
1009 .chip = "AV200",
Clemens Ladisch7407a2e2008-09-22 09:12:11 +02001010 .init = xonar_hdav_init,
1011 .cleanup = xonar_hdav_cleanup,
1012 .suspend = xonar_hdav_suspend,
1013 .resume = xonar_hdav_resume,
1014 .pcm_hardware_filter = xonar_hdav_pcm_hardware_filter,
1015 .set_dac_params = set_hdav_params,
1016 .set_adc_params = set_cs53x1_params,
1017 .update_dac_volume = update_pcm1796_volume,
1018 .update_dac_mute = update_pcm1796_mute,
1019 .uart_input = xonar_hdav_uart_input,
1020 .ac97_switch = xonar_line_mic_ac97_switch,
1021 .dac_tlv = pcm1796_db_scale,
1022 .model_data_size = sizeof(struct xonar_data),
1023 .device_config = PLAYBACK_0_TO_I2S |
1024 PLAYBACK_1_TO_SPDIF |
Clemens Ladischb990ae92009-05-25 10:06:22 +02001025 CAPTURE_0_FROM_I2S_2 |
1026 CAPTURE_1_FROM_SPDIF,
Clemens Ladisch7407a2e2008-09-22 09:12:11 +02001027 .dac_channels = 8,
Clemens Ladischeacbb9d2009-02-20 09:33:40 +01001028 .dac_volume_min = 255 - 2*60,
1029 .dac_volume_max = 255,
Clemens Ladisch22c73372009-01-19 10:07:21 +01001030 .misc_flags = OXYGEN_MISC_MIDI,
Clemens Ladisch7407a2e2008-09-22 09:12:11 +02001031 .function_flags = OXYGEN_FUNCTION_2WIRE,
1032 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1033 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1034};
1035
Clemens Ladisch930738d2009-02-26 09:27:20 +01001036static const struct oxygen_model model_xonar_st = {
1037 .longname = "Asus Virtuoso 100",
1038 .chip = "AV200",
1039 .init = xonar_stx_init,
1040 .control_filter = xonar_st_control_filter,
1041 .mixer_init = xonar_st_mixer_init,
1042 .cleanup = xonar_st_cleanup,
1043 .suspend = xonar_st_suspend,
1044 .resume = xonar_st_resume,
1045 .set_dac_params = set_pcm1796_params,
1046 .set_adc_params = set_cs53x1_params,
1047 .update_dac_volume = update_pcm1796_volume,
1048 .update_dac_mute = update_pcm1796_mute,
1049 .ac97_switch = xonar_line_mic_ac97_switch,
1050 .dac_tlv = pcm1796_db_scale,
1051 .model_data_size = sizeof(struct xonar_data),
1052 .device_config = PLAYBACK_0_TO_I2S |
1053 PLAYBACK_1_TO_SPDIF |
1054 CAPTURE_0_FROM_I2S_2,
1055 .dac_channels = 2,
1056 .dac_volume_min = 255 - 2*60,
1057 .dac_volume_max = 255,
1058 .function_flags = OXYGEN_FUNCTION_2WIRE,
1059 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1060 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1061};
1062
Clemens Ladisch30459d72009-02-19 08:42:44 +01001063static int __devinit get_xonar_model(struct oxygen *chip,
1064 const struct pci_device_id *id)
Clemens Ladisch1b8ff222007-12-23 19:52:08 +01001065{
Clemens Ladischfe106622008-09-22 09:00:30 +02001066 static const struct oxygen_model *const models[] = {
1067 [MODEL_D1] = &model_xonar_d1,
1068 [MODEL_DX] = &model_xonar_d1,
1069 [MODEL_D2] = &model_xonar_d2,
1070 [MODEL_D2X] = &model_xonar_d2,
Clemens Ladisch7407a2e2008-09-22 09:12:11 +02001071 [MODEL_HDAV] = &model_xonar_hdav,
Clemens Ladisch930738d2009-02-26 09:27:20 +01001072 [MODEL_STX] = &model_xonar_st,
Clemens Ladischfe106622008-09-22 09:00:30 +02001073 };
Clemens Ladisch30459d72009-02-19 08:42:44 +01001074 static const char *const names[] = {
1075 [MODEL_D1] = "Xonar D1",
1076 [MODEL_DX] = "Xonar DX",
1077 [MODEL_D2] = "Xonar D2",
1078 [MODEL_D2X] = "Xonar D2X",
1079 [MODEL_HDAV] = "Xonar HDAV1.3",
1080 [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6",
Clemens Ladisch930738d2009-02-26 09:27:20 +01001081 [MODEL_STX] = "Xonar Essence STX",
Clemens Ladisch30459d72009-02-19 08:42:44 +01001082 };
1083 unsigned int model = id->driver_data;
1084
1085 if (model >= ARRAY_SIZE(models) || !models[model])
1086 return -EINVAL;
1087 chip->model = *models[model];
1088
1089 switch (model) {
1090 case MODEL_D2X:
1091 chip->model.init = xonar_d2x_init;
1092 break;
1093 case MODEL_DX:
1094 chip->model.init = xonar_dx_init;
1095 break;
1096 case MODEL_HDAV:
1097 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
1098 GPIO_HDAV_DB_MASK);
1099 switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
1100 GPIO_HDAV_DB_MASK) {
1101 case GPIO_HDAV_DB_H6:
1102 model = MODEL_HDAV_H6;
1103 break;
1104 case GPIO_HDAV_DB_XX:
1105 snd_printk(KERN_ERR "unknown daughterboard\n");
1106 return -ENODEV;
1107 }
1108 break;
Clemens Ladisch930738d2009-02-26 09:27:20 +01001109 case MODEL_STX:
1110 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
1111 GPIO_HDAV_DB_MASK);
1112 break;
Clemens Ladisch30459d72009-02-19 08:42:44 +01001113 }
1114
1115 chip->model.shortname = names[model];
1116 chip->model.private_data = model;
1117 return 0;
1118}
1119
1120static int __devinit xonar_probe(struct pci_dev *pci,
1121 const struct pci_device_id *pci_id)
1122{
Clemens Ladisch1b8ff222007-12-23 19:52:08 +01001123 static int dev;
1124 int err;
1125
1126 if (dev >= SNDRV_CARDS)
1127 return -ENODEV;
1128 if (!enable[dev]) {
1129 ++dev;
1130 return -ENOENT;
1131 }
Clemens Ladischbb718582009-02-19 08:37:13 +01001132 err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
Clemens Ladisch30459d72009-02-19 08:42:44 +01001133 xonar_ids, get_xonar_model);
Clemens Ladisch1b8ff222007-12-23 19:52:08 +01001134 if (err >= 0)
1135 ++dev;
1136 return err;
1137}
1138
1139static struct pci_driver xonar_driver = {
1140 .name = "AV200",
1141 .id_table = xonar_ids,
1142 .probe = xonar_probe,
1143 .remove = __devexit_p(oxygen_pci_remove),
Clemens Ladisch4a4bc532008-05-13 09:24:39 +02001144#ifdef CONFIG_PM
1145 .suspend = oxygen_pci_suspend,
1146 .resume = oxygen_pci_resume,
1147#endif
Clemens Ladisch1b8ff222007-12-23 19:52:08 +01001148};
1149
1150static int __init alsa_card_xonar_init(void)
1151{
1152 return pci_register_driver(&xonar_driver);
1153}
1154
1155static void __exit alsa_card_xonar_exit(void)
1156{
1157 pci_unregister_driver(&xonar_driver);
1158}
1159
1160module_init(alsa_card_xonar_init)
1161module_exit(alsa_card_xonar_exit)