diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/pci/oxygen | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r-- | sound/pci/oxygen/Makefile | 4 | ||||
-rw-r--r-- | sound/pci/oxygen/cs4245.h | 107 | ||||
-rw-r--r-- | sound/pci/oxygen/hifier.c | 239 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen.c | 358 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen.h | 22 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_io.c | 4 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 126 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_mixer.c | 117 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_pcm.c | 67 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_regs.h | 26 | ||||
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 5 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar.h | 2 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_cs43xx.c | 92 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_dg.c | 608 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_dg.h | 8 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_hdmi.c | 2 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_lib.c | 6 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 478 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_wm87x6.c | 412 |
19 files changed, 1959 insertions, 724 deletions
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index acd8f15f7bff..0f8726551fde 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile | |||
@@ -1,10 +1,8 @@ | |||
1 | snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o | 1 | snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o |
2 | snd-hifier-objs := hifier.o | 2 | snd-oxygen-objs := oxygen.o xonar_dg.o |
3 | snd-oxygen-objs := oxygen.o | ||
4 | snd-virtuoso-objs := virtuoso.o xonar_lib.o \ | 3 | snd-virtuoso-objs := virtuoso.o xonar_lib.o \ |
5 | xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o | 4 | xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o |
6 | 5 | ||
7 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o | 6 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o |
8 | obj-$(CONFIG_SND_HIFIER) += snd-hifier.o | ||
9 | obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o | 7 | obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o |
10 | obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o | 8 | obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o |
diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h new file mode 100644 index 000000000000..5e0197e07dd1 --- /dev/null +++ b/sound/pci/oxygen/cs4245.h | |||
@@ -0,0 +1,107 @@ | |||
1 | #define CS4245_CHIP_ID 0x01 | ||
2 | #define CS4245_POWER_CTRL 0x02 | ||
3 | #define CS4245_DAC_CTRL_1 0x03 | ||
4 | #define CS4245_ADC_CTRL 0x04 | ||
5 | #define CS4245_MCLK_FREQ 0x05 | ||
6 | #define CS4245_SIGNAL_SEL 0x06 | ||
7 | #define CS4245_PGA_B_CTRL 0x07 | ||
8 | #define CS4245_PGA_A_CTRL 0x08 | ||
9 | #define CS4245_ANALOG_IN 0x09 | ||
10 | #define CS4245_DAC_A_CTRL 0x0a | ||
11 | #define CS4245_DAC_B_CTRL 0x0b | ||
12 | #define CS4245_DAC_CTRL_2 0x0c | ||
13 | #define CS4245_INT_STATUS 0x0d | ||
14 | #define CS4245_INT_MASK 0x0e | ||
15 | #define CS4245_INT_MODE_MSB 0x0f | ||
16 | #define CS4245_INT_MODE_LSB 0x10 | ||
17 | |||
18 | /* Chip ID */ | ||
19 | #define CS4245_CHIP_PART_MASK 0xf0 | ||
20 | #define CS4245_CHIP_REV_MASK 0x0f | ||
21 | |||
22 | /* Power Control */ | ||
23 | #define CS4245_FREEZE 0x80 | ||
24 | #define CS4245_PDN_MIC 0x08 | ||
25 | #define CS4245_PDN_ADC 0x04 | ||
26 | #define CS4245_PDN_DAC 0x02 | ||
27 | #define CS4245_PDN 0x01 | ||
28 | |||
29 | /* DAC Control */ | ||
30 | #define CS4245_DAC_FM_MASK 0xc0 | ||
31 | #define CS4245_DAC_FM_SINGLE 0x00 | ||
32 | #define CS4245_DAC_FM_DOUBLE 0x40 | ||
33 | #define CS4245_DAC_FM_QUAD 0x80 | ||
34 | #define CS4245_DAC_DIF_MASK 0x30 | ||
35 | #define CS4245_DAC_DIF_LJUST 0x00 | ||
36 | #define CS4245_DAC_DIF_I2S 0x10 | ||
37 | #define CS4245_DAC_DIF_RJUST_16 0x20 | ||
38 | #define CS4245_DAC_DIF_RJUST_24 0x30 | ||
39 | #define CS4245_RESERVED_1 0x08 | ||
40 | #define CS4245_MUTE_DAC 0x04 | ||
41 | #define CS4245_DEEMPH 0x02 | ||
42 | #define CS4245_DAC_MASTER 0x01 | ||
43 | |||
44 | /* ADC Control */ | ||
45 | #define CS4245_ADC_FM_MASK 0xc0 | ||
46 | #define CS4245_ADC_FM_SINGLE 0x00 | ||
47 | #define CS4245_ADC_FM_DOUBLE 0x40 | ||
48 | #define CS4245_ADC_FM_QUAD 0x80 | ||
49 | #define CS4245_ADC_DIF_MASK 0x10 | ||
50 | #define CS4245_ADC_DIF_LJUST 0x00 | ||
51 | #define CS4245_ADC_DIF_I2S 0x10 | ||
52 | #define CS4245_MUTE_ADC 0x04 | ||
53 | #define CS4245_HPF_FREEZE 0x02 | ||
54 | #define CS4245_ADC_MASTER 0x01 | ||
55 | |||
56 | /* MCLK Frequency */ | ||
57 | #define CS4245_MCLK1_MASK 0x70 | ||
58 | #define CS4245_MCLK1_SHIFT 4 | ||
59 | #define CS4245_MCLK2_MASK 0x07 | ||
60 | #define CS4245_MCLK2_SHIFT 0 | ||
61 | #define CS4245_MCLK_1 0 | ||
62 | #define CS4245_MCLK_1_5 1 | ||
63 | #define CS4245_MCLK_2 2 | ||
64 | #define CS4245_MCLK_3 3 | ||
65 | #define CS4245_MCLK_4 4 | ||
66 | |||
67 | /* Signal Selection */ | ||
68 | #define CS4245_A_OUT_SEL_MASK 0x60 | ||
69 | #define CS4245_A_OUT_SEL_HIZ 0x00 | ||
70 | #define CS4245_A_OUT_SEL_DAC 0x20 | ||
71 | #define CS4245_A_OUT_SEL_PGA 0x40 | ||
72 | #define CS4245_LOOP 0x02 | ||
73 | #define CS4245_ASYNCH 0x01 | ||
74 | |||
75 | /* Channel B/A PGA Control */ | ||
76 | #define CS4245_PGA_GAIN_MASK 0x3f | ||
77 | |||
78 | /* ADC Input Control */ | ||
79 | #define CS4245_PGA_SOFT 0x10 | ||
80 | #define CS4245_PGA_ZERO 0x08 | ||
81 | #define CS4245_SEL_MASK 0x07 | ||
82 | #define CS4245_SEL_MIC 0x00 | ||
83 | #define CS4245_SEL_INPUT_1 0x01 | ||
84 | #define CS4245_SEL_INPUT_2 0x02 | ||
85 | #define CS4245_SEL_INPUT_3 0x03 | ||
86 | #define CS4245_SEL_INPUT_4 0x04 | ||
87 | #define CS4245_SEL_INPUT_5 0x05 | ||
88 | #define CS4245_SEL_INPUT_6 0x06 | ||
89 | |||
90 | /* DAC Channel A/B Volume Control */ | ||
91 | #define CS4245_VOL_MASK 0xff | ||
92 | |||
93 | /* DAC Control 2 */ | ||
94 | #define CS4245_DAC_SOFT 0x80 | ||
95 | #define CS4245_DAC_ZERO 0x40 | ||
96 | #define CS4245_INVERT_DAC 0x20 | ||
97 | #define CS4245_INT_ACTIVE_HIGH 0x01 | ||
98 | |||
99 | /* Interrupt Status/Mask/Mode */ | ||
100 | #define CS4245_ADC_CLK_ERR 0x08 | ||
101 | #define CS4245_DAC_CLK_ERR 0x04 | ||
102 | #define CS4245_ADC_OVFL 0x02 | ||
103 | #define CS4245_ADC_UNDRFL 0x01 | ||
104 | |||
105 | |||
106 | #define CS4245_SPI_ADDRESS (0x9e << 16) | ||
107 | #define CS4245_SPI_WRITE (0 << 16) | ||
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c deleted file mode 100644 index 5a87d683691f..000000000000 --- a/sound/pci/oxygen/hifier.c +++ /dev/null | |||
@@ -1,239 +0,0 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia | ||
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 | /* | ||
21 | * CMI8788: | ||
22 | * | ||
23 | * SPI 0 -> AK4396 | ||
24 | */ | ||
25 | |||
26 | #include <linux/delay.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <sound/control.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/tlv.h> | ||
33 | #include "oxygen.h" | ||
34 | #include "ak4396.h" | ||
35 | |||
36 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
37 | MODULE_DESCRIPTION("TempoTec HiFier driver"); | ||
38 | MODULE_LICENSE("GPL v2"); | ||
39 | |||
40 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
41 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
42 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
43 | |||
44 | module_param_array(index, int, NULL, 0444); | ||
45 | MODULE_PARM_DESC(index, "card index"); | ||
46 | module_param_array(id, charp, NULL, 0444); | ||
47 | MODULE_PARM_DESC(id, "ID string"); | ||
48 | module_param_array(enable, bool, NULL, 0444); | ||
49 | MODULE_PARM_DESC(enable, "enable card"); | ||
50 | |||
51 | static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = { | ||
52 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, | ||
53 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, | ||
54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | ||
55 | { } | ||
56 | }; | ||
57 | MODULE_DEVICE_TABLE(pci, hifier_ids); | ||
58 | |||
59 | struct hifier_data { | ||
60 | u8 ak4396_regs[5]; | ||
61 | }; | ||
62 | |||
63 | static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) | ||
64 | { | ||
65 | struct hifier_data *data = chip->model_data; | ||
66 | |||
67 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
68 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
69 | OXYGEN_SPI_CLOCK_160 | | ||
70 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | ||
71 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
72 | AK4396_WRITE | (reg << 8) | value); | ||
73 | data->ak4396_regs[reg] = value; | ||
74 | } | ||
75 | |||
76 | static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value) | ||
77 | { | ||
78 | struct hifier_data *data = chip->model_data; | ||
79 | |||
80 | if (value != data->ak4396_regs[reg]) | ||
81 | ak4396_write(chip, reg, value); | ||
82 | } | ||
83 | |||
84 | static void hifier_registers_init(struct oxygen *chip) | ||
85 | { | ||
86 | struct hifier_data *data = chip->model_data; | ||
87 | |||
88 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
89 | ak4396_write(chip, AK4396_CONTROL_2, | ||
90 | data->ak4396_regs[AK4396_CONTROL_2]); | ||
91 | ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); | ||
92 | ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
93 | ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
94 | } | ||
95 | |||
96 | static void hifier_init(struct oxygen *chip) | ||
97 | { | ||
98 | struct hifier_data *data = chip->model_data; | ||
99 | |||
100 | data->ak4396_regs[AK4396_CONTROL_2] = | ||
101 | AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
102 | hifier_registers_init(chip); | ||
103 | |||
104 | snd_component_add(chip->card, "AK4396"); | ||
105 | snd_component_add(chip->card, "CS5340"); | ||
106 | } | ||
107 | |||
108 | static void hifier_cleanup(struct oxygen *chip) | ||
109 | { | ||
110 | } | ||
111 | |||
112 | static void hifier_resume(struct oxygen *chip) | ||
113 | { | ||
114 | hifier_registers_init(chip); | ||
115 | } | ||
116 | |||
117 | static void set_ak4396_params(struct oxygen *chip, | ||
118 | struct snd_pcm_hw_params *params) | ||
119 | { | ||
120 | struct hifier_data *data = chip->model_data; | ||
121 | u8 value; | ||
122 | |||
123 | value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK; | ||
124 | if (params_rate(params) <= 54000) | ||
125 | value |= AK4396_DFS_NORMAL; | ||
126 | else if (params_rate(params) <= 108000) | ||
127 | value |= AK4396_DFS_DOUBLE; | ||
128 | else | ||
129 | value |= AK4396_DFS_QUAD; | ||
130 | |||
131 | msleep(1); /* wait for the new MCLK to become stable */ | ||
132 | |||
133 | if (value != data->ak4396_regs[AK4396_CONTROL_2]) { | ||
134 | ak4396_write(chip, AK4396_CONTROL_1, | ||
135 | AK4396_DIF_24_MSB); | ||
136 | ak4396_write(chip, AK4396_CONTROL_2, value); | ||
137 | ak4396_write(chip, AK4396_CONTROL_1, | ||
138 | AK4396_DIF_24_MSB | AK4396_RSTN); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static void update_ak4396_volume(struct oxygen *chip) | ||
143 | { | ||
144 | ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
145 | ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
146 | } | ||
147 | |||
148 | static void update_ak4396_mute(struct oxygen *chip) | ||
149 | { | ||
150 | struct hifier_data *data = chip->model_data; | ||
151 | u8 value; | ||
152 | |||
153 | value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE; | ||
154 | if (chip->dac_mute) | ||
155 | value |= AK4396_SMUTE; | ||
156 | ak4396_write_cached(chip, AK4396_CONTROL_2, value); | ||
157 | } | ||
158 | |||
159 | static void set_cs5340_params(struct oxygen *chip, | ||
160 | struct snd_pcm_hw_params *params) | ||
161 | { | ||
162 | } | ||
163 | |||
164 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | ||
165 | |||
166 | static const struct oxygen_model model_hifier = { | ||
167 | .shortname = "C-Media CMI8787", | ||
168 | .longname = "C-Media Oxygen HD Audio", | ||
169 | .chip = "CMI8788", | ||
170 | .init = hifier_init, | ||
171 | .cleanup = hifier_cleanup, | ||
172 | .resume = hifier_resume, | ||
173 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
174 | .set_dac_params = set_ak4396_params, | ||
175 | .set_adc_params = set_cs5340_params, | ||
176 | .update_dac_volume = update_ak4396_volume, | ||
177 | .update_dac_mute = update_ak4396_mute, | ||
178 | .dac_tlv = ak4396_db_scale, | ||
179 | .model_data_size = sizeof(struct hifier_data), | ||
180 | .device_config = PLAYBACK_0_TO_I2S | | ||
181 | PLAYBACK_1_TO_SPDIF | | ||
182 | CAPTURE_0_FROM_I2S_1, | ||
183 | .dac_channels = 2, | ||
184 | .dac_volume_min = 0, | ||
185 | .dac_volume_max = 255, | ||
186 | .function_flags = OXYGEN_FUNCTION_SPI, | ||
187 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
188 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
189 | }; | ||
190 | |||
191 | static int __devinit get_hifier_model(struct oxygen *chip, | ||
192 | const struct pci_device_id *id) | ||
193 | { | ||
194 | chip->model = model_hifier; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int __devinit hifier_probe(struct pci_dev *pci, | ||
199 | const struct pci_device_id *pci_id) | ||
200 | { | ||
201 | static int dev; | ||
202 | int err; | ||
203 | |||
204 | if (dev >= SNDRV_CARDS) | ||
205 | return -ENODEV; | ||
206 | if (!enable[dev]) { | ||
207 | ++dev; | ||
208 | return -ENOENT; | ||
209 | } | ||
210 | err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, | ||
211 | hifier_ids, get_hifier_model); | ||
212 | if (err >= 0) | ||
213 | ++dev; | ||
214 | return err; | ||
215 | } | ||
216 | |||
217 | static struct pci_driver hifier_driver = { | ||
218 | .name = "CMI8787HiFier", | ||
219 | .id_table = hifier_ids, | ||
220 | .probe = hifier_probe, | ||
221 | .remove = __devexit_p(oxygen_pci_remove), | ||
222 | #ifdef CONFIG_PM | ||
223 | .suspend = oxygen_pci_suspend, | ||
224 | .resume = oxygen_pci_resume, | ||
225 | #endif | ||
226 | }; | ||
227 | |||
228 | static int __init alsa_card_hifier_init(void) | ||
229 | { | ||
230 | return pci_register_driver(&hifier_driver); | ||
231 | } | ||
232 | |||
233 | static void __exit alsa_card_hifier_exit(void) | ||
234 | { | ||
235 | pci_unregister_driver(&hifier_driver); | ||
236 | } | ||
237 | |||
238 | module_init(alsa_card_hifier_init) | ||
239 | module_exit(alsa_card_hifier_exit) | ||
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 6c0a11adb2a8..d7e8ddd9a67b 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -20,19 +20,32 @@ | |||
20 | /* | 20 | /* |
21 | * CMI8788: | 21 | * CMI8788: |
22 | * | 22 | * |
23 | * SPI 0 -> 1st AK4396 (front) | 23 | * SPI 0 -> 1st AK4396 (front) |
24 | * SPI 1 -> 2nd AK4396 (surround) | 24 | * SPI 1 -> 2nd AK4396 (surround) |
25 | * SPI 2 -> 3rd AK4396 (center/LFE) | 25 | * SPI 2 -> 3rd AK4396 (center/LFE) |
26 | * SPI 3 -> WM8785 | 26 | * SPI 3 -> WM8785 |
27 | * SPI 4 -> 4th AK4396 (back) | 27 | * SPI 4 -> 4th AK4396 (back) |
28 | * | 28 | * |
29 | * GPIO 0 -> DFS0 of AK5385 | 29 | * GPIO 0 -> DFS0 of AK5385 |
30 | * GPIO 1 -> DFS1 of AK5385 | 30 | * GPIO 1 -> DFS1 of AK5385 |
31 | * GPIO 8 -> enable headphone amplifier on HT-Omega models | 31 | * |
32 | * X-Meridian models: | ||
33 | * GPIO 4 -> enable extension S/PDIF input | ||
34 | * GPIO 6 -> enable on-board S/PDIF input | ||
35 | * | ||
36 | * Claro models: | ||
37 | * GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input | ||
38 | * GPIO 8 -> enable headphone amplifier | ||
32 | * | 39 | * |
33 | * CM9780: | 40 | * CM9780: |
34 | * | 41 | * |
35 | * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input | 42 | * LINE_OUT -> input of ADC |
43 | * | ||
44 | * AUX_IN <- aux | ||
45 | * CD_IN <- CD | ||
46 | * MIC_IN <- mic | ||
47 | * | ||
48 | * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input | ||
36 | */ | 49 | */ |
37 | 50 | ||
38 | #include <linux/delay.h> | 51 | #include <linux/delay.h> |
@@ -41,18 +54,22 @@ | |||
41 | #include <sound/ac97_codec.h> | 54 | #include <sound/ac97_codec.h> |
42 | #include <sound/control.h> | 55 | #include <sound/control.h> |
43 | #include <sound/core.h> | 56 | #include <sound/core.h> |
57 | #include <sound/info.h> | ||
44 | #include <sound/initval.h> | 58 | #include <sound/initval.h> |
45 | #include <sound/pcm.h> | 59 | #include <sound/pcm.h> |
46 | #include <sound/pcm_params.h> | 60 | #include <sound/pcm_params.h> |
47 | #include <sound/tlv.h> | 61 | #include <sound/tlv.h> |
48 | #include "oxygen.h" | 62 | #include "oxygen.h" |
63 | #include "xonar_dg.h" | ||
49 | #include "ak4396.h" | 64 | #include "ak4396.h" |
50 | #include "wm8785.h" | 65 | #include "wm8785.h" |
51 | 66 | ||
52 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 67 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
53 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); | 68 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); |
54 | MODULE_LICENSE("GPL v2"); | 69 | MODULE_LICENSE("GPL v2"); |
55 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); | 70 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}" |
71 | ",{C-Media,CMI8787}" | ||
72 | ",{C-Media,CMI8788}}"); | ||
56 | 73 | ||
57 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 74 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
58 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 75 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
@@ -66,14 +83,22 @@ module_param_array(enable, bool, NULL, 0444); | |||
66 | MODULE_PARM_DESC(enable, "enable card"); | 83 | MODULE_PARM_DESC(enable, "enable card"); |
67 | 84 | ||
68 | enum { | 85 | enum { |
69 | MODEL_CMEDIA_REF, /* C-Media's reference design */ | 86 | MODEL_CMEDIA_REF, |
70 | MODEL_MERIDIAN, /* AuzenTech X-Meridian */ | 87 | MODEL_MERIDIAN, |
71 | MODEL_CLARO, /* HT-Omega Claro */ | 88 | MODEL_MERIDIAN_2G, |
72 | MODEL_CLARO_HALO, /* HT-Omega Claro halo */ | 89 | MODEL_CLARO, |
90 | MODEL_CLARO_HALO, | ||
91 | MODEL_FANTASIA, | ||
92 | MODEL_SERENADE, | ||
93 | MODEL_2CH_OUTPUT, | ||
94 | MODEL_HG2PCI, | ||
95 | MODEL_XONAR_DG, | ||
73 | }; | 96 | }; |
74 | 97 | ||
75 | static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { | 98 | static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { |
99 | /* C-Media's reference design */ | ||
76 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, | 100 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, |
101 | { OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF }, | ||
77 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, | 102 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, |
78 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, | 103 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, |
79 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, | 104 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, |
@@ -81,8 +106,23 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { | |||
81 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, | 106 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, |
82 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, | 107 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, |
83 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, | 108 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, |
109 | /* Asus Xonar DG */ | ||
110 | { OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG }, | ||
111 | /* PCI 2.0 HD Audio */ | ||
112 | { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT }, | ||
113 | /* Kuroutoshikou CMI8787-HG2PCI */ | ||
114 | { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI }, | ||
115 | /* TempoTec HiFier Fantasia */ | ||
116 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_FANTASIA }, | ||
117 | /* TempoTec HiFier Serenade */ | ||
118 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_SERENADE }, | ||
119 | /* AuzenTech X-Meridian */ | ||
84 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, | 120 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, |
121 | /* AuzenTech X-Meridian 2G */ | ||
122 | { OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN_2G }, | ||
123 | /* HT-Omega Claro */ | ||
85 | { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, | 124 | { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, |
125 | /* HT-Omega Claro halo */ | ||
86 | { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO }, | 126 | { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO }, |
87 | { } | 127 | { } |
88 | }; | 128 | }; |
@@ -94,9 +134,15 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); | |||
94 | #define GPIO_AK5385_DFS_DOUBLE 0x0001 | 134 | #define GPIO_AK5385_DFS_DOUBLE 0x0001 |
95 | #define GPIO_AK5385_DFS_QUAD 0x0002 | 135 | #define GPIO_AK5385_DFS_QUAD 0x0002 |
96 | 136 | ||
137 | #define GPIO_MERIDIAN_DIG_MASK 0x0050 | ||
138 | #define GPIO_MERIDIAN_DIG_EXT 0x0010 | ||
139 | #define GPIO_MERIDIAN_DIG_BOARD 0x0040 | ||
140 | |||
141 | #define GPIO_CLARO_DIG_COAX 0x0040 | ||
97 | #define GPIO_CLARO_HP 0x0100 | 142 | #define GPIO_CLARO_HP 0x0100 |
98 | 143 | ||
99 | struct generic_data { | 144 | struct generic_data { |
145 | unsigned int dacs; | ||
100 | u8 ak4396_regs[4][5]; | 146 | u8 ak4396_regs[4][5]; |
101 | u16 wm8785_regs[3]; | 147 | u16 wm8785_regs[3]; |
102 | }; | 148 | }; |
@@ -147,7 +193,7 @@ static void ak4396_registers_init(struct oxygen *chip) | |||
147 | struct generic_data *data = chip->model_data; | 193 | struct generic_data *data = chip->model_data; |
148 | unsigned int i; | 194 | unsigned int i; |
149 | 195 | ||
150 | for (i = 0; i < 4; ++i) { | 196 | for (i = 0; i < data->dacs; ++i) { |
151 | ak4396_write(chip, i, AK4396_CONTROL_1, | 197 | ak4396_write(chip, i, AK4396_CONTROL_1, |
152 | AK4396_DIF_24_MSB | AK4396_RSTN); | 198 | AK4396_DIF_24_MSB | AK4396_RSTN); |
153 | ak4396_write(chip, i, AK4396_CONTROL_2, | 199 | ak4396_write(chip, i, AK4396_CONTROL_2, |
@@ -165,6 +211,7 @@ static void ak4396_init(struct oxygen *chip) | |||
165 | { | 211 | { |
166 | struct generic_data *data = chip->model_data; | 212 | struct generic_data *data = chip->model_data; |
167 | 213 | ||
214 | data->dacs = chip->model.dac_channels_pcm / 2; | ||
168 | data->ak4396_regs[0][AK4396_CONTROL_2] = | 215 | data->ak4396_regs[0][AK4396_CONTROL_2] = |
169 | AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | 216 | AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; |
170 | ak4396_registers_init(chip); | 217 | ak4396_registers_init(chip); |
@@ -206,6 +253,10 @@ static void generic_init(struct oxygen *chip) | |||
206 | 253 | ||
207 | static void meridian_init(struct oxygen *chip) | 254 | static void meridian_init(struct oxygen *chip) |
208 | { | 255 | { |
256 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
257 | GPIO_MERIDIAN_DIG_MASK); | ||
258 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
259 | GPIO_MERIDIAN_DIG_BOARD, GPIO_MERIDIAN_DIG_MASK); | ||
209 | ak4396_init(chip); | 260 | ak4396_init(chip); |
210 | ak5385_init(chip); | 261 | ak5385_init(chip); |
211 | } | 262 | } |
@@ -219,6 +270,8 @@ static void claro_enable_hp(struct oxygen *chip) | |||
219 | 270 | ||
220 | static void claro_init(struct oxygen *chip) | 271 | static void claro_init(struct oxygen *chip) |
221 | { | 272 | { |
273 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX); | ||
274 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX); | ||
222 | ak4396_init(chip); | 275 | ak4396_init(chip); |
223 | wm8785_init(chip); | 276 | wm8785_init(chip); |
224 | claro_enable_hp(chip); | 277 | claro_enable_hp(chip); |
@@ -226,11 +279,24 @@ static void claro_init(struct oxygen *chip) | |||
226 | 279 | ||
227 | static void claro_halo_init(struct oxygen *chip) | 280 | static void claro_halo_init(struct oxygen *chip) |
228 | { | 281 | { |
282 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX); | ||
283 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX); | ||
229 | ak4396_init(chip); | 284 | ak4396_init(chip); |
230 | ak5385_init(chip); | 285 | ak5385_init(chip); |
231 | claro_enable_hp(chip); | 286 | claro_enable_hp(chip); |
232 | } | 287 | } |
233 | 288 | ||
289 | static void fantasia_init(struct oxygen *chip) | ||
290 | { | ||
291 | ak4396_init(chip); | ||
292 | snd_component_add(chip->card, "CS5340"); | ||
293 | } | ||
294 | |||
295 | static void stereo_output_init(struct oxygen *chip) | ||
296 | { | ||
297 | ak4396_init(chip); | ||
298 | } | ||
299 | |||
234 | static void generic_cleanup(struct oxygen *chip) | 300 | static void generic_cleanup(struct oxygen *chip) |
235 | { | 301 | { |
236 | } | 302 | } |
@@ -267,6 +333,11 @@ static void claro_resume(struct oxygen *chip) | |||
267 | claro_enable_hp(chip); | 333 | claro_enable_hp(chip); |
268 | } | 334 | } |
269 | 335 | ||
336 | static void stereo_resume(struct oxygen *chip) | ||
337 | { | ||
338 | ak4396_registers_init(chip); | ||
339 | } | ||
340 | |||
270 | static void set_ak4396_params(struct oxygen *chip, | 341 | static void set_ak4396_params(struct oxygen *chip, |
271 | struct snd_pcm_hw_params *params) | 342 | struct snd_pcm_hw_params *params) |
272 | { | 343 | { |
@@ -285,7 +356,7 @@ static void set_ak4396_params(struct oxygen *chip, | |||
285 | msleep(1); /* wait for the new MCLK to become stable */ | 356 | msleep(1); /* wait for the new MCLK to become stable */ |
286 | 357 | ||
287 | if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) { | 358 | if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) { |
288 | for (i = 0; i < 4; ++i) { | 359 | for (i = 0; i < data->dacs; ++i) { |
289 | ak4396_write(chip, i, AK4396_CONTROL_1, | 360 | ak4396_write(chip, i, AK4396_CONTROL_1, |
290 | AK4396_DIF_24_MSB); | 361 | AK4396_DIF_24_MSB); |
291 | ak4396_write(chip, i, AK4396_CONTROL_2, value); | 362 | ak4396_write(chip, i, AK4396_CONTROL_2, value); |
@@ -297,9 +368,10 @@ static void set_ak4396_params(struct oxygen *chip, | |||
297 | 368 | ||
298 | static void update_ak4396_volume(struct oxygen *chip) | 369 | static void update_ak4396_volume(struct oxygen *chip) |
299 | { | 370 | { |
371 | struct generic_data *data = chip->model_data; | ||
300 | unsigned int i; | 372 | unsigned int i; |
301 | 373 | ||
302 | for (i = 0; i < 4; ++i) { | 374 | for (i = 0; i < data->dacs; ++i) { |
303 | ak4396_write_cached(chip, i, AK4396_LCH_ATT, | 375 | ak4396_write_cached(chip, i, AK4396_LCH_ATT, |
304 | chip->dac_volume[i * 2]); | 376 | chip->dac_volume[i * 2]); |
305 | ak4396_write_cached(chip, i, AK4396_RCH_ATT, | 377 | ak4396_write_cached(chip, i, AK4396_RCH_ATT, |
@@ -316,7 +388,7 @@ static void update_ak4396_mute(struct oxygen *chip) | |||
316 | value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE; | 388 | value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE; |
317 | if (chip->dac_mute) | 389 | if (chip->dac_mute) |
318 | value |= AK4396_SMUTE; | 390 | value |= AK4396_SMUTE; |
319 | for (i = 0; i < 4; ++i) | 391 | for (i = 0; i < data->dacs; ++i) |
320 | ak4396_write_cached(chip, i, AK4396_CONTROL_2, value); | 392 | ak4396_write_cached(chip, i, AK4396_CONTROL_2, value); |
321 | } | 393 | } |
322 | 394 | ||
@@ -355,6 +427,10 @@ static void set_ak5385_params(struct oxygen *chip, | |||
355 | value, GPIO_AK5385_DFS_MASK); | 427 | value, GPIO_AK5385_DFS_MASK); |
356 | } | 428 | } |
357 | 429 | ||
430 | static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params) | ||
431 | { | ||
432 | } | ||
433 | |||
358 | static int rolloff_info(struct snd_kcontrol *ctl, | 434 | static int rolloff_info(struct snd_kcontrol *ctl, |
359 | struct snd_ctl_elem_info *info) | 435 | struct snd_ctl_elem_info *info) |
360 | { | 436 | { |
@@ -362,13 +438,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, | |||
362 | "Sharp Roll-off", "Slow Roll-off" | 438 | "Sharp Roll-off", "Slow Roll-off" |
363 | }; | 439 | }; |
364 | 440 | ||
365 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 441 | return snd_ctl_enum_info(info, 1, 2, names); |
366 | info->count = 1; | ||
367 | info->value.enumerated.items = 2; | ||
368 | if (info->value.enumerated.item >= 2) | ||
369 | info->value.enumerated.item = 1; | ||
370 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
371 | return 0; | ||
372 | } | 442 | } |
373 | 443 | ||
374 | static int rolloff_get(struct snd_kcontrol *ctl, | 444 | static int rolloff_get(struct snd_kcontrol *ctl, |
@@ -399,7 +469,7 @@ static int rolloff_put(struct snd_kcontrol *ctl, | |||
399 | reg &= ~AK4396_SLOW; | 469 | reg &= ~AK4396_SLOW; |
400 | changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2]; | 470 | changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2]; |
401 | if (changed) { | 471 | if (changed) { |
402 | for (i = 0; i < 4; ++i) | 472 | for (i = 0; i < data->dacs; ++i) |
403 | ak4396_write(chip, i, AK4396_CONTROL_2, reg); | 473 | ak4396_write(chip, i, AK4396_CONTROL_2, reg); |
404 | } | 474 | } |
405 | mutex_unlock(&chip->mutex); | 475 | mutex_unlock(&chip->mutex); |
@@ -420,13 +490,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | |||
420 | "None", "High-pass Filter" | 490 | "None", "High-pass Filter" |
421 | }; | 491 | }; |
422 | 492 | ||
423 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 493 | return snd_ctl_enum_info(info, 1, 2, names); |
424 | info->count = 1; | ||
425 | info->value.enumerated.items = 2; | ||
426 | if (info->value.enumerated.item >= 2) | ||
427 | info->value.enumerated.item = 1; | ||
428 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
429 | return 0; | ||
430 | } | 494 | } |
431 | 495 | ||
432 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 496 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) |
@@ -465,6 +529,100 @@ static const struct snd_kcontrol_new hpf_control = { | |||
465 | .put = hpf_put, | 529 | .put = hpf_put, |
466 | }; | 530 | }; |
467 | 531 | ||
532 | static int meridian_dig_source_info(struct snd_kcontrol *ctl, | ||
533 | struct snd_ctl_elem_info *info) | ||
534 | { | ||
535 | static const char *const names[2] = { "On-board", "Extension" }; | ||
536 | |||
537 | return snd_ctl_enum_info(info, 1, 2, names); | ||
538 | } | ||
539 | |||
540 | static int claro_dig_source_info(struct snd_kcontrol *ctl, | ||
541 | struct snd_ctl_elem_info *info) | ||
542 | { | ||
543 | static const char *const names[2] = { "Optical", "Coaxial" }; | ||
544 | |||
545 | return snd_ctl_enum_info(info, 1, 2, names); | ||
546 | } | ||
547 | |||
548 | static int meridian_dig_source_get(struct snd_kcontrol *ctl, | ||
549 | struct snd_ctl_elem_value *value) | ||
550 | { | ||
551 | struct oxygen *chip = ctl->private_data; | ||
552 | |||
553 | value->value.enumerated.item[0] = | ||
554 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
555 | GPIO_MERIDIAN_DIG_EXT); | ||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int claro_dig_source_get(struct snd_kcontrol *ctl, | ||
560 | struct snd_ctl_elem_value *value) | ||
561 | { | ||
562 | struct oxygen *chip = ctl->private_data; | ||
563 | |||
564 | value->value.enumerated.item[0] = | ||
565 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
566 | GPIO_CLARO_DIG_COAX); | ||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static int meridian_dig_source_put(struct snd_kcontrol *ctl, | ||
571 | struct snd_ctl_elem_value *value) | ||
572 | { | ||
573 | struct oxygen *chip = ctl->private_data; | ||
574 | u16 old_reg, new_reg; | ||
575 | int changed; | ||
576 | |||
577 | mutex_lock(&chip->mutex); | ||
578 | old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
579 | new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK; | ||
580 | if (value->value.enumerated.item[0] == 0) | ||
581 | new_reg |= GPIO_MERIDIAN_DIG_BOARD; | ||
582 | else | ||
583 | new_reg |= GPIO_MERIDIAN_DIG_EXT; | ||
584 | changed = new_reg != old_reg; | ||
585 | if (changed) | ||
586 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); | ||
587 | mutex_unlock(&chip->mutex); | ||
588 | return changed; | ||
589 | } | ||
590 | |||
591 | static int claro_dig_source_put(struct snd_kcontrol *ctl, | ||
592 | struct snd_ctl_elem_value *value) | ||
593 | { | ||
594 | struct oxygen *chip = ctl->private_data; | ||
595 | u16 old_reg, new_reg; | ||
596 | int changed; | ||
597 | |||
598 | mutex_lock(&chip->mutex); | ||
599 | old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
600 | new_reg = old_reg & ~GPIO_CLARO_DIG_COAX; | ||
601 | if (value->value.enumerated.item[0]) | ||
602 | new_reg |= GPIO_CLARO_DIG_COAX; | ||
603 | changed = new_reg != old_reg; | ||
604 | if (changed) | ||
605 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); | ||
606 | mutex_unlock(&chip->mutex); | ||
607 | return changed; | ||
608 | } | ||
609 | |||
610 | static const struct snd_kcontrol_new meridian_dig_source_control = { | ||
611 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
612 | .name = "IEC958 Source Capture Enum", | ||
613 | .info = meridian_dig_source_info, | ||
614 | .get = meridian_dig_source_get, | ||
615 | .put = meridian_dig_source_put, | ||
616 | }; | ||
617 | |||
618 | static const struct snd_kcontrol_new claro_dig_source_control = { | ||
619 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
620 | .name = "IEC958 Source Capture Enum", | ||
621 | .info = claro_dig_source_info, | ||
622 | .get = claro_dig_source_get, | ||
623 | .put = claro_dig_source_put, | ||
624 | }; | ||
625 | |||
468 | static int generic_mixer_init(struct oxygen *chip) | 626 | static int generic_mixer_init(struct oxygen *chip) |
469 | { | 627 | { |
470 | return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | 628 | return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); |
@@ -483,6 +641,81 @@ static int generic_wm8785_mixer_init(struct oxygen *chip) | |||
483 | return 0; | 641 | return 0; |
484 | } | 642 | } |
485 | 643 | ||
644 | static int meridian_mixer_init(struct oxygen *chip) | ||
645 | { | ||
646 | int err; | ||
647 | |||
648 | err = generic_mixer_init(chip); | ||
649 | if (err < 0) | ||
650 | return err; | ||
651 | err = snd_ctl_add(chip->card, | ||
652 | snd_ctl_new1(&meridian_dig_source_control, chip)); | ||
653 | if (err < 0) | ||
654 | return err; | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int claro_mixer_init(struct oxygen *chip) | ||
659 | { | ||
660 | int err; | ||
661 | |||
662 | err = generic_wm8785_mixer_init(chip); | ||
663 | if (err < 0) | ||
664 | return err; | ||
665 | err = snd_ctl_add(chip->card, | ||
666 | snd_ctl_new1(&claro_dig_source_control, chip)); | ||
667 | if (err < 0) | ||
668 | return err; | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int claro_halo_mixer_init(struct oxygen *chip) | ||
673 | { | ||
674 | int err; | ||
675 | |||
676 | err = generic_mixer_init(chip); | ||
677 | if (err < 0) | ||
678 | return err; | ||
679 | err = snd_ctl_add(chip->card, | ||
680 | snd_ctl_new1(&claro_dig_source_control, chip)); | ||
681 | if (err < 0) | ||
682 | return err; | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static void dump_ak4396_registers(struct oxygen *chip, | ||
687 | struct snd_info_buffer *buffer) | ||
688 | { | ||
689 | struct generic_data *data = chip->model_data; | ||
690 | unsigned int dac, i; | ||
691 | |||
692 | for (dac = 0; dac < data->dacs; ++dac) { | ||
693 | snd_iprintf(buffer, "\nAK4396 %u:", dac + 1); | ||
694 | for (i = 0; i < 5; ++i) | ||
695 | snd_iprintf(buffer, " %02x", data->ak4396_regs[dac][i]); | ||
696 | } | ||
697 | snd_iprintf(buffer, "\n"); | ||
698 | } | ||
699 | |||
700 | static void dump_wm8785_registers(struct oxygen *chip, | ||
701 | struct snd_info_buffer *buffer) | ||
702 | { | ||
703 | struct generic_data *data = chip->model_data; | ||
704 | unsigned int i; | ||
705 | |||
706 | snd_iprintf(buffer, "\nWM8785:"); | ||
707 | for (i = 0; i < 3; ++i) | ||
708 | snd_iprintf(buffer, " %03x", data->wm8785_regs[i]); | ||
709 | snd_iprintf(buffer, "\n"); | ||
710 | } | ||
711 | |||
712 | static void dump_oxygen_registers(struct oxygen *chip, | ||
713 | struct snd_info_buffer *buffer) | ||
714 | { | ||
715 | dump_ak4396_registers(chip, buffer); | ||
716 | dump_wm8785_registers(chip, buffer); | ||
717 | } | ||
718 | |||
486 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | 719 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); |
487 | 720 | ||
488 | static const struct oxygen_model model_generic = { | 721 | static const struct oxygen_model model_generic = { |
@@ -493,11 +726,11 @@ static const struct oxygen_model model_generic = { | |||
493 | .mixer_init = generic_wm8785_mixer_init, | 726 | .mixer_init = generic_wm8785_mixer_init, |
494 | .cleanup = generic_cleanup, | 727 | .cleanup = generic_cleanup, |
495 | .resume = generic_resume, | 728 | .resume = generic_resume, |
496 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
497 | .set_dac_params = set_ak4396_params, | 729 | .set_dac_params = set_ak4396_params, |
498 | .set_adc_params = set_wm8785_params, | 730 | .set_adc_params = set_wm8785_params, |
499 | .update_dac_volume = update_ak4396_volume, | 731 | .update_dac_volume = update_ak4396_volume, |
500 | .update_dac_mute = update_ak4396_mute, | 732 | .update_dac_mute = update_ak4396_mute, |
733 | .dump_registers = dump_oxygen_registers, | ||
501 | .dac_tlv = ak4396_db_scale, | 734 | .dac_tlv = ak4396_db_scale, |
502 | .model_data_size = sizeof(struct generic_data), | 735 | .model_data_size = sizeof(struct generic_data), |
503 | .device_config = PLAYBACK_0_TO_I2S | | 736 | .device_config = PLAYBACK_0_TO_I2S | |
@@ -505,12 +738,16 @@ static const struct oxygen_model model_generic = { | |||
505 | PLAYBACK_2_TO_AC97_1 | | 738 | PLAYBACK_2_TO_AC97_1 | |
506 | CAPTURE_0_FROM_I2S_1 | | 739 | CAPTURE_0_FROM_I2S_1 | |
507 | CAPTURE_1_FROM_SPDIF | | 740 | CAPTURE_1_FROM_SPDIF | |
508 | CAPTURE_2_FROM_AC97_1, | 741 | CAPTURE_2_FROM_AC97_1 | |
509 | .dac_channels = 8, | 742 | AC97_CD_INPUT, |
743 | .dac_channels_pcm = 8, | ||
744 | .dac_channels_mixer = 8, | ||
510 | .dac_volume_min = 0, | 745 | .dac_volume_min = 0, |
511 | .dac_volume_max = 255, | 746 | .dac_volume_max = 255, |
512 | .function_flags = OXYGEN_FUNCTION_SPI | | 747 | .function_flags = OXYGEN_FUNCTION_SPI | |
513 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | 748 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, |
749 | .dac_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
750 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
514 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 751 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
515 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 752 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
516 | }; | 753 | }; |
@@ -518,42 +755,87 @@ static const struct oxygen_model model_generic = { | |||
518 | static int __devinit get_oxygen_model(struct oxygen *chip, | 755 | static int __devinit get_oxygen_model(struct oxygen *chip, |
519 | const struct pci_device_id *id) | 756 | const struct pci_device_id *id) |
520 | { | 757 | { |
758 | static const char *const names[] = { | ||
759 | [MODEL_MERIDIAN] = "AuzenTech X-Meridian", | ||
760 | [MODEL_MERIDIAN_2G] = "AuzenTech X-Meridian 2G", | ||
761 | [MODEL_CLARO] = "HT-Omega Claro", | ||
762 | [MODEL_CLARO_HALO] = "HT-Omega Claro halo", | ||
763 | [MODEL_FANTASIA] = "TempoTec HiFier Fantasia", | ||
764 | [MODEL_SERENADE] = "TempoTec HiFier Serenade", | ||
765 | [MODEL_HG2PCI] = "CMI8787-HG2PCI", | ||
766 | }; | ||
767 | |||
521 | chip->model = model_generic; | 768 | chip->model = model_generic; |
522 | switch (id->driver_data) { | 769 | switch (id->driver_data) { |
523 | case MODEL_MERIDIAN: | 770 | case MODEL_MERIDIAN: |
771 | case MODEL_MERIDIAN_2G: | ||
524 | chip->model.init = meridian_init; | 772 | chip->model.init = meridian_init; |
525 | chip->model.mixer_init = generic_mixer_init; | 773 | chip->model.mixer_init = meridian_mixer_init; |
526 | chip->model.resume = meridian_resume; | 774 | chip->model.resume = meridian_resume; |
527 | chip->model.set_adc_params = set_ak5385_params; | 775 | chip->model.set_adc_params = set_ak5385_params; |
776 | chip->model.dump_registers = dump_ak4396_registers; | ||
528 | chip->model.device_config = PLAYBACK_0_TO_I2S | | 777 | chip->model.device_config = PLAYBACK_0_TO_I2S | |
529 | PLAYBACK_1_TO_SPDIF | | 778 | PLAYBACK_1_TO_SPDIF | |
530 | CAPTURE_0_FROM_I2S_2 | | 779 | CAPTURE_0_FROM_I2S_2 | |
531 | CAPTURE_1_FROM_SPDIF; | 780 | CAPTURE_1_FROM_SPDIF; |
781 | if (id->driver_data == MODEL_MERIDIAN) | ||
782 | chip->model.device_config |= AC97_CD_INPUT; | ||
532 | break; | 783 | break; |
533 | case MODEL_CLARO: | 784 | case MODEL_CLARO: |
534 | chip->model.init = claro_init; | 785 | chip->model.init = claro_init; |
786 | chip->model.mixer_init = claro_mixer_init; | ||
535 | chip->model.cleanup = claro_cleanup; | 787 | chip->model.cleanup = claro_cleanup; |
536 | chip->model.suspend = claro_suspend; | 788 | chip->model.suspend = claro_suspend; |
537 | chip->model.resume = claro_resume; | 789 | chip->model.resume = claro_resume; |
538 | break; | 790 | break; |
539 | case MODEL_CLARO_HALO: | 791 | case MODEL_CLARO_HALO: |
540 | chip->model.init = claro_halo_init; | 792 | chip->model.init = claro_halo_init; |
541 | chip->model.mixer_init = generic_mixer_init; | 793 | chip->model.mixer_init = claro_halo_mixer_init; |
542 | chip->model.cleanup = claro_cleanup; | 794 | chip->model.cleanup = claro_cleanup; |
543 | chip->model.suspend = claro_suspend; | 795 | chip->model.suspend = claro_suspend; |
544 | chip->model.resume = claro_resume; | 796 | chip->model.resume = claro_resume; |
545 | chip->model.set_adc_params = set_ak5385_params; | 797 | chip->model.set_adc_params = set_ak5385_params; |
798 | chip->model.dump_registers = dump_ak4396_registers; | ||
546 | chip->model.device_config = PLAYBACK_0_TO_I2S | | 799 | chip->model.device_config = PLAYBACK_0_TO_I2S | |
547 | PLAYBACK_1_TO_SPDIF | | 800 | PLAYBACK_1_TO_SPDIF | |
548 | CAPTURE_0_FROM_I2S_2 | | 801 | CAPTURE_0_FROM_I2S_2 | |
549 | CAPTURE_1_FROM_SPDIF; | 802 | CAPTURE_1_FROM_SPDIF; |
550 | break; | 803 | break; |
804 | case MODEL_FANTASIA: | ||
805 | case MODEL_SERENADE: | ||
806 | case MODEL_2CH_OUTPUT: | ||
807 | case MODEL_HG2PCI: | ||
808 | chip->model.shortname = "C-Media CMI8787"; | ||
809 | chip->model.chip = "CMI8787"; | ||
810 | if (id->driver_data == MODEL_FANTASIA) | ||
811 | chip->model.init = fantasia_init; | ||
812 | else | ||
813 | chip->model.init = stereo_output_init; | ||
814 | chip->model.resume = stereo_resume; | ||
815 | chip->model.mixer_init = generic_mixer_init; | ||
816 | chip->model.set_adc_params = set_no_params; | ||
817 | chip->model.dump_registers = dump_ak4396_registers; | ||
818 | chip->model.device_config = PLAYBACK_0_TO_I2S | | ||
819 | PLAYBACK_1_TO_SPDIF; | ||
820 | if (id->driver_data == MODEL_FANTASIA) { | ||
821 | chip->model.device_config |= CAPTURE_0_FROM_I2S_1; | ||
822 | chip->model.adc_mclks = OXYGEN_MCLKS(256, 128, 128); | ||
823 | } | ||
824 | chip->model.dac_channels_pcm = 2; | ||
825 | chip->model.dac_channels_mixer = 2; | ||
826 | break; | ||
827 | case MODEL_XONAR_DG: | ||
828 | chip->model = model_xonar_dg; | ||
829 | break; | ||
551 | } | 830 | } |
552 | if (id->driver_data == MODEL_MERIDIAN || | 831 | if (id->driver_data == MODEL_MERIDIAN || |
832 | id->driver_data == MODEL_MERIDIAN_2G || | ||
553 | id->driver_data == MODEL_CLARO_HALO) { | 833 | id->driver_data == MODEL_CLARO_HALO) { |
554 | chip->model.misc_flags = OXYGEN_MISC_MIDI; | 834 | chip->model.misc_flags = OXYGEN_MISC_MIDI; |
555 | chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; | 835 | chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; |
556 | } | 836 | } |
837 | if (id->driver_data < ARRAY_SIZE(names) && names[id->driver_data]) | ||
838 | chip->model.shortname = names[id->driver_data]; | ||
557 | return 0; | 839 | return 0; |
558 | } | 840 | } |
559 | 841 | ||
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index a3409edcfb50..f53897a708b4 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -16,6 +16,10 @@ | |||
16 | #define PCM_AC97 5 | 16 | #define PCM_AC97 5 |
17 | #define PCM_COUNT 6 | 17 | #define PCM_COUNT 6 |
18 | 18 | ||
19 | #define OXYGEN_MCLKS(f_single, f_double, f_quad) ((MCLK_##f_single << 0) | \ | ||
20 | (MCLK_##f_double << 2) | \ | ||
21 | (MCLK_##f_quad << 4)) | ||
22 | |||
19 | #define OXYGEN_IO_SIZE 0x100 | 23 | #define OXYGEN_IO_SIZE 0x100 |
20 | 24 | ||
21 | #define OXYGEN_EEPROM_ID 0x434d /* "CM" */ | 25 | #define OXYGEN_EEPROM_ID 0x434d /* "CM" */ |
@@ -34,6 +38,8 @@ | |||
34 | /* CAPTURE_3_FROM_I2S_3 not implemented */ | 38 | /* CAPTURE_3_FROM_I2S_3 not implemented */ |
35 | #define MIDI_OUTPUT 0x0800 | 39 | #define MIDI_OUTPUT 0x0800 |
36 | #define MIDI_INPUT 0x1000 | 40 | #define MIDI_INPUT 0x1000 |
41 | #define AC97_CD_INPUT 0x2000 | ||
42 | #define AC97_FMIC_SWITCH 0x4000 | ||
37 | 43 | ||
38 | enum { | 44 | enum { |
39 | CONTROL_SPDIF_PCM, | 45 | CONTROL_SPDIF_PCM, |
@@ -64,6 +70,7 @@ struct snd_pcm_hardware; | |||
64 | struct snd_pcm_hw_params; | 70 | struct snd_pcm_hw_params; |
65 | struct snd_kcontrol_new; | 71 | struct snd_kcontrol_new; |
66 | struct snd_rawmidi; | 72 | struct snd_rawmidi; |
73 | struct snd_info_buffer; | ||
67 | struct oxygen; | 74 | struct oxygen; |
68 | 75 | ||
69 | struct oxygen_model { | 76 | struct oxygen_model { |
@@ -78,8 +85,6 @@ struct oxygen_model { | |||
78 | void (*resume)(struct oxygen *chip); | 85 | void (*resume)(struct oxygen *chip); |
79 | void (*pcm_hardware_filter)(unsigned int channel, | 86 | void (*pcm_hardware_filter)(unsigned int channel, |
80 | struct snd_pcm_hardware *hardware); | 87 | struct snd_pcm_hardware *hardware); |
81 | unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel, | ||
82 | struct snd_pcm_hw_params *hw_params); | ||
83 | void (*set_dac_params)(struct oxygen *chip, | 88 | void (*set_dac_params)(struct oxygen *chip, |
84 | struct snd_pcm_hw_params *params); | 89 | struct snd_pcm_hw_params *params); |
85 | void (*set_adc_params)(struct oxygen *chip, | 90 | void (*set_adc_params)(struct oxygen *chip, |
@@ -87,19 +92,25 @@ struct oxygen_model { | |||
87 | void (*update_dac_volume)(struct oxygen *chip); | 92 | void (*update_dac_volume)(struct oxygen *chip); |
88 | void (*update_dac_mute)(struct oxygen *chip); | 93 | void (*update_dac_mute)(struct oxygen *chip); |
89 | void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed); | 94 | void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed); |
95 | unsigned int (*adjust_dac_routing)(struct oxygen *chip, | ||
96 | unsigned int play_routing); | ||
90 | void (*gpio_changed)(struct oxygen *chip); | 97 | void (*gpio_changed)(struct oxygen *chip); |
91 | void (*uart_input)(struct oxygen *chip); | 98 | void (*uart_input)(struct oxygen *chip); |
92 | void (*ac97_switch)(struct oxygen *chip, | 99 | void (*ac97_switch)(struct oxygen *chip, |
93 | unsigned int reg, unsigned int mute); | 100 | unsigned int reg, unsigned int mute); |
101 | void (*dump_registers)(struct oxygen *chip, | ||
102 | struct snd_info_buffer *buffer); | ||
94 | const unsigned int *dac_tlv; | 103 | const unsigned int *dac_tlv; |
95 | unsigned long private_data; | ||
96 | size_t model_data_size; | 104 | size_t model_data_size; |
97 | unsigned int device_config; | 105 | unsigned int device_config; |
98 | u8 dac_channels; | 106 | u8 dac_channels_pcm; |
107 | u8 dac_channels_mixer; | ||
99 | u8 dac_volume_min; | 108 | u8 dac_volume_min; |
100 | u8 dac_volume_max; | 109 | u8 dac_volume_max; |
101 | u8 misc_flags; | 110 | u8 misc_flags; |
102 | u8 function_flags; | 111 | u8 function_flags; |
112 | u8 dac_mclks; | ||
113 | u8 adc_mclks; | ||
103 | u16 dac_i2s_format; | 114 | u16 dac_i2s_format; |
104 | u16 adc_i2s_format; | 115 | u16 adc_i2s_format; |
105 | }; | 116 | }; |
@@ -120,7 +131,6 @@ struct oxygen { | |||
120 | u8 pcm_running; | 131 | u8 pcm_running; |
121 | u8 dac_routing; | 132 | u8 dac_routing; |
122 | u8 spdif_playback_enable; | 133 | u8 spdif_playback_enable; |
123 | u8 revision; | ||
124 | u8 has_ac97_0; | 134 | u8 has_ac97_0; |
125 | u8 has_ac97_1; | 135 | u8 has_ac97_1; |
126 | u32 spdif_bits; | 136 | u32 spdif_bits; |
@@ -166,8 +176,6 @@ void oxygen_update_spdif_source(struct oxygen *chip); | |||
166 | /* oxygen_pcm.c */ | 176 | /* oxygen_pcm.c */ |
167 | 177 | ||
168 | int oxygen_pcm_init(struct oxygen *chip); | 178 | int oxygen_pcm_init(struct oxygen *chip); |
169 | unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel, | ||
170 | struct snd_pcm_hw_params *hw_params); | ||
171 | 179 | ||
172 | /* oxygen_io.c */ | 180 | /* oxygen_io.c */ |
173 | 181 | ||
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 09b2b2a36df5..f5164b1e1c80 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c | |||
@@ -197,11 +197,11 @@ void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) | |||
197 | { | 197 | { |
198 | unsigned int count; | 198 | unsigned int count; |
199 | 199 | ||
200 | /* should not need more than 7.68 us (24 * 320 ns) */ | 200 | /* should not need more than 30.72 us (24 * 1.28 us) */ |
201 | count = 10; | 201 | count = 10; |
202 | while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) | 202 | while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) |
203 | && count > 0) { | 203 | && count > 0) { |
204 | udelay(1); | 204 | udelay(4); |
205 | --count; | 205 | --count; |
206 | } | 206 | } |
207 | 207 | ||
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 7e93cf884437..70b739816fcc 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -202,7 +202,13 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
202 | struct oxygen *chip = entry->private_data; | 202 | struct oxygen *chip = entry->private_data; |
203 | int i, j; | 203 | int i, j; |
204 | 204 | ||
205 | snd_iprintf(buffer, "CMI8788\n\n"); | 205 | switch (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_PACKAGE_ID_MASK) { |
206 | case OXYGEN_PACKAGE_ID_8786: i = '6'; break; | ||
207 | case OXYGEN_PACKAGE_ID_8787: i = '7'; break; | ||
208 | case OXYGEN_PACKAGE_ID_8788: i = '8'; break; | ||
209 | default: i = '?'; break; | ||
210 | } | ||
211 | snd_iprintf(buffer, "CMI878%c:\n", i); | ||
206 | for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { | 212 | for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { |
207 | snd_iprintf(buffer, "%02x:", i); | 213 | snd_iprintf(buffer, "%02x:", i); |
208 | for (j = 0; j < 0x10; ++j) | 214 | for (j = 0; j < 0x10; ++j) |
@@ -212,7 +218,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
212 | if (mutex_lock_interruptible(&chip->mutex) < 0) | 218 | if (mutex_lock_interruptible(&chip->mutex) < 0) |
213 | return; | 219 | return; |
214 | if (chip->has_ac97_0) { | 220 | if (chip->has_ac97_0) { |
215 | snd_iprintf(buffer, "\nAC97\n"); | 221 | snd_iprintf(buffer, "\nAC97:\n"); |
216 | for (i = 0; i < 0x80; i += 0x10) { | 222 | for (i = 0; i < 0x80; i += 0x10) { |
217 | snd_iprintf(buffer, "%02x:", i); | 223 | snd_iprintf(buffer, "%02x:", i); |
218 | for (j = 0; j < 0x10; j += 2) | 224 | for (j = 0; j < 0x10; j += 2) |
@@ -222,7 +228,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
222 | } | 228 | } |
223 | } | 229 | } |
224 | if (chip->has_ac97_1) { | 230 | if (chip->has_ac97_1) { |
225 | snd_iprintf(buffer, "\nAC97 2\n"); | 231 | snd_iprintf(buffer, "\nAC97 2:\n"); |
226 | for (i = 0; i < 0x80; i += 0x10) { | 232 | for (i = 0; i < 0x80; i += 0x10) { |
227 | snd_iprintf(buffer, "%02x:", i); | 233 | snd_iprintf(buffer, "%02x:", i); |
228 | for (j = 0; j < 0x10; j += 2) | 234 | for (j = 0; j < 0x10; j += 2) |
@@ -232,13 +238,15 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
232 | } | 238 | } |
233 | } | 239 | } |
234 | mutex_unlock(&chip->mutex); | 240 | mutex_unlock(&chip->mutex); |
241 | if (chip->model.dump_registers) | ||
242 | chip->model.dump_registers(chip, buffer); | ||
235 | } | 243 | } |
236 | 244 | ||
237 | static void oxygen_proc_init(struct oxygen *chip) | 245 | static void oxygen_proc_init(struct oxygen *chip) |
238 | { | 246 | { |
239 | struct snd_info_entry *entry; | 247 | struct snd_info_entry *entry; |
240 | 248 | ||
241 | if (!snd_card_proc_new(chip->card, "cmi8788", &entry)) | 249 | if (!snd_card_proc_new(chip->card, "oxygen", &entry)) |
242 | snd_info_set_text_ops(entry, chip, oxygen_proc_read); | 250 | snd_info_set_text_ops(entry, chip, oxygen_proc_read); |
243 | } | 251 | } |
244 | #else | 252 | #else |
@@ -262,7 +270,7 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[]) | |||
262 | */ | 270 | */ |
263 | subdevice = oxygen_read_eeprom(chip, 2); | 271 | subdevice = oxygen_read_eeprom(chip, 2); |
264 | /* use default ID if EEPROM is missing */ | 272 | /* use default ID if EEPROM is missing */ |
265 | if (subdevice == 0xffff) | 273 | if (subdevice == 0xffff && oxygen_read_eeprom(chip, 1) == 0xffff) |
266 | subdevice = 0x8788; | 274 | subdevice = 0x8788; |
267 | /* | 275 | /* |
268 | * We use only the subsystem device ID for searching because it is | 276 | * We use only the subsystem device ID for searching because it is |
@@ -308,25 +316,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip, | |||
308 | } | 316 | } |
309 | } | 317 | } |
310 | 318 | ||
311 | static void pci_bridge_magic(void) | 319 | static void configure_pcie_bridge(struct pci_dev *pci) |
312 | { | 320 | { |
313 | struct pci_dev *pci = NULL; | 321 | enum { PEX811X, PI7C9X110 }; |
322 | static const struct pci_device_id bridge_ids[] = { | ||
323 | { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X }, | ||
324 | { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X }, | ||
325 | { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 }, | ||
326 | { } | ||
327 | }; | ||
328 | struct pci_dev *bridge; | ||
329 | const struct pci_device_id *id; | ||
314 | u32 tmp; | 330 | u32 tmp; |
315 | 331 | ||
316 | for (;;) { | 332 | if (!pci->bus || !pci->bus->self) |
317 | /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */ | 333 | return; |
318 | pci = pci_get_device(0x12d8, 0xe110, pci); | 334 | bridge = pci->bus->self; |
319 | if (!pci) | 335 | |
320 | break; | 336 | id = pci_match_id(bridge_ids, bridge); |
321 | /* | 337 | if (!id) |
322 | * ... configure its secondary internal arbiter to park to | 338 | return; |
323 | * the secondary port, instead of to the last master. | 339 | |
324 | */ | 340 | switch (id->driver_data) { |
325 | if (!pci_read_config_dword(pci, 0x40, &tmp)) { | 341 | case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */ |
326 | tmp |= 1; | 342 | pci_read_config_dword(bridge, 0x48, &tmp); |
327 | pci_write_config_dword(pci, 0x40, tmp); | 343 | tmp |= 1; /* enable blind prefetching */ |
328 | } | 344 | tmp |= 1 << 11; /* enable beacon generation */ |
329 | /* Why? Try asking C-Media. */ | 345 | pci_write_config_dword(bridge, 0x48, tmp); |
346 | |||
347 | pci_write_config_dword(bridge, 0x84, 0x0c); | ||
348 | pci_read_config_dword(bridge, 0x88, &tmp); | ||
349 | tmp &= ~(7 << 27); | ||
350 | tmp |= 2 << 27; /* set prefetch size to 128 bytes */ | ||
351 | pci_write_config_dword(bridge, 0x88, tmp); | ||
352 | break; | ||
353 | |||
354 | case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */ | ||
355 | pci_read_config_dword(bridge, 0x40, &tmp); | ||
356 | tmp |= 1; /* park the PCI arbiter to the sound chip */ | ||
357 | pci_write_config_dword(bridge, 0x40, tmp); | ||
358 | break; | ||
330 | } | 359 | } |
331 | } | 360 | } |
332 | 361 | ||
@@ -343,12 +372,7 @@ static void oxygen_init(struct oxygen *chip) | |||
343 | (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT); | 372 | (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT); |
344 | chip->spdif_pcm_bits = chip->spdif_bits; | 373 | chip->spdif_pcm_bits = chip->spdif_bits; |
345 | 374 | ||
346 | if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2) | 375 | if (!(oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2)) |
347 | chip->revision = 2; | ||
348 | else | ||
349 | chip->revision = 1; | ||
350 | |||
351 | if (chip->revision == 1) | ||
352 | oxygen_set_bits8(chip, OXYGEN_MISC, | 376 | oxygen_set_bits8(chip, OXYGEN_MISC, |
353 | OXYGEN_MISC_PCI_MEM_W_1_CLOCK); | 377 | OXYGEN_MISC_PCI_MEM_W_1_CLOCK); |
354 | 378 | ||
@@ -385,28 +409,40 @@ static void oxygen_init(struct oxygen *chip) | |||
385 | (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT)); | 409 | (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT)); |
386 | oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2); | 410 | oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2); |
387 | oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT, | 411 | oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT, |
388 | OXYGEN_RATE_48000 | chip->model.dac_i2s_format | | 412 | OXYGEN_RATE_48000 | |
389 | OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | | 413 | chip->model.dac_i2s_format | |
390 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | 414 | OXYGEN_I2S_MCLK(chip->model.dac_mclks) | |
415 | OXYGEN_I2S_BITS_16 | | ||
416 | OXYGEN_I2S_MASTER | | ||
417 | OXYGEN_I2S_BCLK_64); | ||
391 | if (chip->model.device_config & CAPTURE_0_FROM_I2S_1) | 418 | if (chip->model.device_config & CAPTURE_0_FROM_I2S_1) |
392 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | 419 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, |
393 | OXYGEN_RATE_48000 | chip->model.adc_i2s_format | | 420 | OXYGEN_RATE_48000 | |
394 | OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | | 421 | chip->model.adc_i2s_format | |
395 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | 422 | OXYGEN_I2S_MCLK(chip->model.adc_mclks) | |
423 | OXYGEN_I2S_BITS_16 | | ||
424 | OXYGEN_I2S_MASTER | | ||
425 | OXYGEN_I2S_BCLK_64); | ||
396 | else | 426 | else |
397 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | 427 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, |
398 | OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); | 428 | OXYGEN_I2S_MASTER | |
429 | OXYGEN_I2S_MUTE_MCLK); | ||
399 | if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 | | 430 | if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 | |
400 | CAPTURE_2_FROM_I2S_2)) | 431 | CAPTURE_2_FROM_I2S_2)) |
401 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, | 432 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, |
402 | OXYGEN_RATE_48000 | chip->model.adc_i2s_format | | 433 | OXYGEN_RATE_48000 | |
403 | OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | | 434 | chip->model.adc_i2s_format | |
404 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | 435 | OXYGEN_I2S_MCLK(chip->model.adc_mclks) | |
436 | OXYGEN_I2S_BITS_16 | | ||
437 | OXYGEN_I2S_MASTER | | ||
438 | OXYGEN_I2S_BCLK_64); | ||
405 | else | 439 | else |
406 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, | 440 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, |
407 | OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); | 441 | OXYGEN_I2S_MASTER | |
442 | OXYGEN_I2S_MUTE_MCLK); | ||
408 | oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, | 443 | oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, |
409 | OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); | 444 | OXYGEN_I2S_MASTER | |
445 | OXYGEN_I2S_MUTE_MCLK); | ||
410 | oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, | 446 | oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, |
411 | OXYGEN_SPDIF_OUT_ENABLE | | 447 | OXYGEN_SPDIF_OUT_ENABLE | |
412 | OXYGEN_SPDIF_LOOPBACK); | 448 | OXYGEN_SPDIF_LOOPBACK); |
@@ -536,7 +572,8 @@ static void oxygen_card_free(struct snd_card *card) | |||
536 | oxygen_shutdown(chip); | 572 | oxygen_shutdown(chip); |
537 | if (chip->irq >= 0) | 573 | if (chip->irq >= 0) |
538 | free_irq(chip->irq, chip); | 574 | free_irq(chip->irq, chip); |
539 | flush_scheduled_work(); | 575 | flush_work_sync(&chip->spdif_input_bits_work); |
576 | flush_work_sync(&chip->gpio_work); | ||
540 | chip->model.cleanup(chip); | 577 | chip->model.cleanup(chip); |
541 | kfree(chip->model_data); | 578 | kfree(chip->model_data); |
542 | mutex_destroy(&chip->mutex); | 579 | mutex_destroy(&chip->mutex); |
@@ -613,7 +650,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
613 | snd_card_set_dev(card, &pci->dev); | 650 | snd_card_set_dev(card, &pci->dev); |
614 | card->private_free = oxygen_card_free; | 651 | card->private_free = oxygen_card_free; |
615 | 652 | ||
616 | pci_bridge_magic(); | 653 | configure_pcie_bridge(pci); |
617 | oxygen_init(chip); | 654 | oxygen_init(chip); |
618 | chip->model.init(chip); | 655 | chip->model.init(chip); |
619 | 656 | ||
@@ -627,8 +664,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
627 | 664 | ||
628 | strcpy(card->driver, chip->model.chip); | 665 | strcpy(card->driver, chip->model.chip); |
629 | strcpy(card->shortname, chip->model.shortname); | 666 | strcpy(card->shortname, chip->model.shortname); |
630 | sprintf(card->longname, "%s (rev %u) at %#lx, irq %i", | 667 | sprintf(card->longname, "%s at %#lx, irq %i", |
631 | chip->model.longname, chip->revision, chip->addr, chip->irq); | 668 | chip->model.longname, chip->addr, chip->irq); |
632 | strcpy(card->mixername, chip->model.chip); | 669 | strcpy(card->mixername, chip->model.chip); |
633 | snd_component_add(card, chip->model.chip); | 670 | snd_component_add(card, chip->model.chip); |
634 | 671 | ||
@@ -712,7 +749,8 @@ int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state) | |||
712 | spin_unlock_irq(&chip->reg_lock); | 749 | spin_unlock_irq(&chip->reg_lock); |
713 | 750 | ||
714 | synchronize_irq(chip->irq); | 751 | synchronize_irq(chip->irq); |
715 | flush_scheduled_work(); | 752 | flush_work_sync(&chip->spdif_input_bits_work); |
753 | flush_work_sync(&chip->gpio_work); | ||
716 | chip->interrupt_mask = saved_interrupt_mask; | 754 | chip->interrupt_mask = saved_interrupt_mask; |
717 | 755 | ||
718 | pci_disable_device(pci); | 756 | pci_disable_device(pci); |
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index f375b8a27862..26c7e8bcb229 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
@@ -31,7 +31,7 @@ static int dac_volume_info(struct snd_kcontrol *ctl, | |||
31 | struct oxygen *chip = ctl->private_data; | 31 | struct oxygen *chip = ctl->private_data; |
32 | 32 | ||
33 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 33 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
34 | info->count = chip->model.dac_channels; | 34 | info->count = chip->model.dac_channels_mixer; |
35 | info->value.integer.min = chip->model.dac_volume_min; | 35 | info->value.integer.min = chip->model.dac_volume_min; |
36 | info->value.integer.max = chip->model.dac_volume_max; | 36 | info->value.integer.max = chip->model.dac_volume_max; |
37 | return 0; | 37 | return 0; |
@@ -44,7 +44,7 @@ static int dac_volume_get(struct snd_kcontrol *ctl, | |||
44 | unsigned int i; | 44 | unsigned int i; |
45 | 45 | ||
46 | mutex_lock(&chip->mutex); | 46 | mutex_lock(&chip->mutex); |
47 | for (i = 0; i < chip->model.dac_channels; ++i) | 47 | for (i = 0; i < chip->model.dac_channels_mixer; ++i) |
48 | value->value.integer.value[i] = chip->dac_volume[i]; | 48 | value->value.integer.value[i] = chip->dac_volume[i]; |
49 | mutex_unlock(&chip->mutex); | 49 | mutex_unlock(&chip->mutex); |
50 | return 0; | 50 | return 0; |
@@ -59,7 +59,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl, | |||
59 | 59 | ||
60 | changed = 0; | 60 | changed = 0; |
61 | mutex_lock(&chip->mutex); | 61 | mutex_lock(&chip->mutex); |
62 | for (i = 0; i < chip->model.dac_channels; ++i) | 62 | for (i = 0; i < chip->model.dac_channels_mixer; ++i) |
63 | if (value->value.integer.value[i] != chip->dac_volume[i]) { | 63 | if (value->value.integer.value[i] != chip->dac_volume[i]) { |
64 | chip->dac_volume[i] = value->value.integer.value[i]; | 64 | chip->dac_volume[i] = value->value.integer.value[i]; |
65 | changed = 1; | 65 | changed = 1; |
@@ -97,6 +97,16 @@ static int dac_mute_put(struct snd_kcontrol *ctl, | |||
97 | return changed; | 97 | return changed; |
98 | } | 98 | } |
99 | 99 | ||
100 | static unsigned int upmix_item_count(struct oxygen *chip) | ||
101 | { | ||
102 | if (chip->model.dac_channels_pcm < 8) | ||
103 | return 2; | ||
104 | else if (chip->model.update_center_lfe_mix) | ||
105 | return 5; | ||
106 | else | ||
107 | return 3; | ||
108 | } | ||
109 | |||
100 | static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | 110 | static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) |
101 | { | 111 | { |
102 | static const char *const names[5] = { | 112 | static const char *const names[5] = { |
@@ -107,15 +117,9 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | |||
107 | "Front+Surround+Center/LFE+Back", | 117 | "Front+Surround+Center/LFE+Back", |
108 | }; | 118 | }; |
109 | struct oxygen *chip = ctl->private_data; | 119 | struct oxygen *chip = ctl->private_data; |
110 | unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; | 120 | unsigned int count = upmix_item_count(chip); |
111 | 121 | ||
112 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 122 | return snd_ctl_enum_info(info, 1, count, names); |
113 | info->count = 1; | ||
114 | info->value.enumerated.items = count; | ||
115 | if (info->value.enumerated.item >= count) | ||
116 | info->value.enumerated.item = count - 1; | ||
117 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
118 | return 0; | ||
119 | } | 123 | } |
120 | 124 | ||
121 | static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 125 | static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) |
@@ -176,6 +180,8 @@ void oxygen_update_dac_routing(struct oxygen *chip) | |||
176 | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | 180 | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | |
177 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | 181 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | |
178 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); | 182 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); |
183 | if (chip->model.adjust_dac_routing) | ||
184 | reg_value = chip->model.adjust_dac_routing(chip, reg_value); | ||
179 | oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, | 185 | oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, |
180 | OXYGEN_PLAY_DAC0_SOURCE_MASK | | 186 | OXYGEN_PLAY_DAC0_SOURCE_MASK | |
181 | OXYGEN_PLAY_DAC1_SOURCE_MASK | | 187 | OXYGEN_PLAY_DAC1_SOURCE_MASK | |
@@ -188,7 +194,7 @@ void oxygen_update_dac_routing(struct oxygen *chip) | |||
188 | static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 194 | static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) |
189 | { | 195 | { |
190 | struct oxygen *chip = ctl->private_data; | 196 | struct oxygen *chip = ctl->private_data; |
191 | unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; | 197 | unsigned int count = upmix_item_count(chip); |
192 | int changed; | 198 | int changed; |
193 | 199 | ||
194 | if (value->value.enumerated.item[0] >= count) | 200 | if (value->value.enumerated.item[0] >= count) |
@@ -430,30 +436,31 @@ static int spdif_input_default_get(struct snd_kcontrol *ctl, | |||
430 | return 0; | 436 | return 0; |
431 | } | 437 | } |
432 | 438 | ||
433 | static int spdif_loopback_get(struct snd_kcontrol *ctl, | 439 | static int spdif_bit_switch_get(struct snd_kcontrol *ctl, |
434 | struct snd_ctl_elem_value *value) | 440 | struct snd_ctl_elem_value *value) |
435 | { | 441 | { |
436 | struct oxygen *chip = ctl->private_data; | 442 | struct oxygen *chip = ctl->private_data; |
443 | u32 bit = ctl->private_value; | ||
437 | 444 | ||
438 | value->value.integer.value[0] = | 445 | value->value.integer.value[0] = |
439 | !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) | 446 | !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) & bit); |
440 | & OXYGEN_SPDIF_LOOPBACK); | ||
441 | return 0; | 447 | return 0; |
442 | } | 448 | } |
443 | 449 | ||
444 | static int spdif_loopback_put(struct snd_kcontrol *ctl, | 450 | static int spdif_bit_switch_put(struct snd_kcontrol *ctl, |
445 | struct snd_ctl_elem_value *value) | 451 | struct snd_ctl_elem_value *value) |
446 | { | 452 | { |
447 | struct oxygen *chip = ctl->private_data; | 453 | struct oxygen *chip = ctl->private_data; |
454 | u32 bit = ctl->private_value; | ||
448 | u32 oldreg, newreg; | 455 | u32 oldreg, newreg; |
449 | int changed; | 456 | int changed; |
450 | 457 | ||
451 | spin_lock_irq(&chip->reg_lock); | 458 | spin_lock_irq(&chip->reg_lock); |
452 | oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | 459 | oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); |
453 | if (value->value.integer.value[0]) | 460 | if (value->value.integer.value[0]) |
454 | newreg = oldreg | OXYGEN_SPDIF_LOOPBACK; | 461 | newreg = oldreg | bit; |
455 | else | 462 | else |
456 | newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK; | 463 | newreg = oldreg & ~bit; |
457 | changed = newreg != oldreg; | 464 | changed = newreg != oldreg; |
458 | if (changed) | 465 | if (changed) |
459 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); | 466 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); |
@@ -644,6 +651,46 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, | |||
644 | return change; | 651 | return change; |
645 | } | 652 | } |
646 | 653 | ||
654 | static int mic_fmic_source_info(struct snd_kcontrol *ctl, | ||
655 | struct snd_ctl_elem_info *info) | ||
656 | { | ||
657 | static const char *const names[] = { "Mic Jack", "Front Panel" }; | ||
658 | |||
659 | return snd_ctl_enum_info(info, 1, 2, names); | ||
660 | } | ||
661 | |||
662 | static int mic_fmic_source_get(struct snd_kcontrol *ctl, | ||
663 | struct snd_ctl_elem_value *value) | ||
664 | { | ||
665 | struct oxygen *chip = ctl->private_data; | ||
666 | |||
667 | mutex_lock(&chip->mutex); | ||
668 | value->value.enumerated.item[0] = | ||
669 | !!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC); | ||
670 | mutex_unlock(&chip->mutex); | ||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | static int mic_fmic_source_put(struct snd_kcontrol *ctl, | ||
675 | struct snd_ctl_elem_value *value) | ||
676 | { | ||
677 | struct oxygen *chip = ctl->private_data; | ||
678 | u16 oldreg, newreg; | ||
679 | int change; | ||
680 | |||
681 | mutex_lock(&chip->mutex); | ||
682 | oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK); | ||
683 | if (value->value.enumerated.item[0]) | ||
684 | newreg = oldreg | CM9780_FMIC2MIC; | ||
685 | else | ||
686 | newreg = oldreg & ~CM9780_FMIC2MIC; | ||
687 | change = newreg != oldreg; | ||
688 | if (change) | ||
689 | oxygen_write_ac97(chip, 0, CM9780_JACK, newreg); | ||
690 | mutex_unlock(&chip->mutex); | ||
691 | return change; | ||
692 | } | ||
693 | |||
647 | static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, | 694 | static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, |
648 | struct snd_ctl_elem_info *info) | 695 | struct snd_ctl_elem_info *info) |
649 | { | 696 | { |
@@ -708,7 +755,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, | |||
708 | .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ | 755 | .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ |
709 | } | 756 | } |
710 | 757 | ||
711 | static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0); | 758 | static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0); |
712 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); | 759 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); |
713 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); | 760 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); |
714 | 761 | ||
@@ -791,8 +838,17 @@ static const struct snd_kcontrol_new spdif_input_controls[] = { | |||
791 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 838 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
792 | .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH), | 839 | .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH), |
793 | .info = snd_ctl_boolean_mono_info, | 840 | .info = snd_ctl_boolean_mono_info, |
794 | .get = spdif_loopback_get, | 841 | .get = spdif_bit_switch_get, |
795 | .put = spdif_loopback_put, | 842 | .put = spdif_bit_switch_put, |
843 | .private_value = OXYGEN_SPDIF_LOOPBACK, | ||
844 | }, | ||
845 | { | ||
846 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
847 | .name = SNDRV_CTL_NAME_IEC958("Validity Check ",CAPTURE,SWITCH), | ||
848 | .info = snd_ctl_boolean_mono_info, | ||
849 | .get = spdif_bit_switch_get, | ||
850 | .put = spdif_bit_switch_put, | ||
851 | .private_value = OXYGEN_SPDIF_SPDVALID, | ||
796 | }, | 852 | }, |
797 | }; | 853 | }; |
798 | 854 | ||
@@ -908,6 +964,13 @@ static const struct snd_kcontrol_new ac97_controls[] = { | |||
908 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0), | 964 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0), |
909 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), | 965 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), |
910 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), | 966 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), |
967 | { | ||
968 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
969 | .name = "Mic Source Capture Enum", | ||
970 | .info = mic_fmic_source_info, | ||
971 | .get = mic_fmic_source_get, | ||
972 | .put = mic_fmic_source_put, | ||
973 | }, | ||
911 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), | 974 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), |
912 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1), | 975 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1), |
913 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), | 976 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), |
@@ -970,7 +1033,13 @@ static int add_controls(struct oxygen *chip, | |||
970 | continue; | 1033 | continue; |
971 | } | 1034 | } |
972 | if (!strcmp(template.name, "Stereo Upmixing") && | 1035 | if (!strcmp(template.name, "Stereo Upmixing") && |
973 | chip->model.dac_channels == 2) | 1036 | chip->model.dac_channels_pcm == 2) |
1037 | continue; | ||
1038 | if (!strcmp(template.name, "Mic Source Capture Enum") && | ||
1039 | !(chip->model.device_config & AC97_FMIC_SWITCH)) | ||
1040 | continue; | ||
1041 | if (!strncmp(template.name, "CD Capture ", 11) && | ||
1042 | !(chip->model.device_config & AC97_CD_INPUT)) | ||
974 | continue; | 1043 | continue; |
975 | if (!strcmp(template.name, "Master Playback Volume") && | 1044 | if (!strcmp(template.name, "Master Playback Volume") && |
976 | chip->model.dac_tlv) { | 1045 | chip->model.dac_tlv) { |
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 9dff6954c397..d5533e34ece9 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
@@ -39,7 +39,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { | |||
39 | SNDRV_PCM_INFO_MMAP_VALID | | 39 | SNDRV_PCM_INFO_MMAP_VALID | |
40 | SNDRV_PCM_INFO_INTERLEAVED | | 40 | SNDRV_PCM_INFO_INTERLEAVED | |
41 | SNDRV_PCM_INFO_PAUSE | | 41 | SNDRV_PCM_INFO_PAUSE | |
42 | SNDRV_PCM_INFO_SYNC_START, | 42 | SNDRV_PCM_INFO_SYNC_START | |
43 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
43 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 44 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
44 | SNDRV_PCM_FMTBIT_S32_LE, | 45 | SNDRV_PCM_FMTBIT_S32_LE, |
45 | .rates = SNDRV_PCM_RATE_32000 | | 46 | .rates = SNDRV_PCM_RATE_32000 | |
@@ -56,8 +57,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { | |||
56 | .channels_max = 2, | 57 | .channels_max = 2, |
57 | .buffer_bytes_max = BUFFER_BYTES_MAX, | 58 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
58 | .period_bytes_min = PERIOD_BYTES_MIN, | 59 | .period_bytes_min = PERIOD_BYTES_MIN, |
59 | .period_bytes_max = BUFFER_BYTES_MAX / 2, | 60 | .period_bytes_max = BUFFER_BYTES_MAX, |
60 | .periods_min = 2, | 61 | .periods_min = 1, |
61 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | 62 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
62 | }; | 63 | }; |
63 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | 64 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { |
@@ -65,7 +66,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | |||
65 | SNDRV_PCM_INFO_MMAP_VALID | | 66 | SNDRV_PCM_INFO_MMAP_VALID | |
66 | SNDRV_PCM_INFO_INTERLEAVED | | 67 | SNDRV_PCM_INFO_INTERLEAVED | |
67 | SNDRV_PCM_INFO_PAUSE | | 68 | SNDRV_PCM_INFO_PAUSE | |
68 | SNDRV_PCM_INFO_SYNC_START, | 69 | SNDRV_PCM_INFO_SYNC_START | |
70 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
69 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 71 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
70 | SNDRV_PCM_FMTBIT_S32_LE, | 72 | SNDRV_PCM_FMTBIT_S32_LE, |
71 | .rates = SNDRV_PCM_RATE_32000 | | 73 | .rates = SNDRV_PCM_RATE_32000 | |
@@ -82,8 +84,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | |||
82 | .channels_max = 8, | 84 | .channels_max = 8, |
83 | .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, | 85 | .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, |
84 | .period_bytes_min = PERIOD_BYTES_MIN, | 86 | .period_bytes_min = PERIOD_BYTES_MIN, |
85 | .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2, | 87 | .period_bytes_max = BUFFER_BYTES_MAX_MULTICH, |
86 | .periods_min = 2, | 88 | .periods_min = 1, |
87 | .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, | 89 | .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, |
88 | }; | 90 | }; |
89 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { | 91 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { |
@@ -91,7 +93,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { | |||
91 | SNDRV_PCM_INFO_MMAP_VALID | | 93 | SNDRV_PCM_INFO_MMAP_VALID | |
92 | SNDRV_PCM_INFO_INTERLEAVED | | 94 | SNDRV_PCM_INFO_INTERLEAVED | |
93 | SNDRV_PCM_INFO_PAUSE | | 95 | SNDRV_PCM_INFO_PAUSE | |
94 | SNDRV_PCM_INFO_SYNC_START, | 96 | SNDRV_PCM_INFO_SYNC_START | |
97 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
95 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 98 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
96 | .rates = SNDRV_PCM_RATE_48000, | 99 | .rates = SNDRV_PCM_RATE_48000, |
97 | .rate_min = 48000, | 100 | .rate_min = 48000, |
@@ -100,8 +103,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { | |||
100 | .channels_max = 2, | 103 | .channels_max = 2, |
101 | .buffer_bytes_max = BUFFER_BYTES_MAX, | 104 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
102 | .period_bytes_min = PERIOD_BYTES_MIN, | 105 | .period_bytes_min = PERIOD_BYTES_MIN, |
103 | .period_bytes_max = BUFFER_BYTES_MAX / 2, | 106 | .period_bytes_max = BUFFER_BYTES_MAX, |
104 | .periods_min = 2, | 107 | .periods_min = 1, |
105 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | 108 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
106 | }; | 109 | }; |
107 | 110 | ||
@@ -140,7 +143,7 @@ static int oxygen_open(struct snd_pcm_substream *substream, | |||
140 | runtime->hw.rate_min = 44100; | 143 | runtime->hw.rate_min = 44100; |
141 | break; | 144 | break; |
142 | case PCM_MULTICH: | 145 | case PCM_MULTICH: |
143 | runtime->hw.channels_max = chip->model.dac_channels; | 146 | runtime->hw.channels_max = chip->model.dac_channels_pcm; |
144 | break; | 147 | break; |
145 | } | 148 | } |
146 | if (chip->model.pcm_hardware_filter) | 149 | if (chip->model.pcm_hardware_filter) |
@@ -271,17 +274,6 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params) | |||
271 | } | 274 | } |
272 | } | 275 | } |
273 | 276 | ||
274 | unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, | ||
275 | unsigned int channel, | ||
276 | struct snd_pcm_hw_params *hw_params) | ||
277 | { | ||
278 | if (params_rate(hw_params) <= 96000) | ||
279 | return OXYGEN_I2S_MCLK_256; | ||
280 | else | ||
281 | return OXYGEN_I2S_MCLK_128; | ||
282 | } | ||
283 | EXPORT_SYMBOL(oxygen_default_i2s_mclk); | ||
284 | |||
285 | static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) | 277 | static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) |
286 | { | 278 | { |
287 | if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) | 279 | if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) |
@@ -341,6 +333,26 @@ static int oxygen_hw_params(struct snd_pcm_substream *substream, | |||
341 | return 0; | 333 | return 0; |
342 | } | 334 | } |
343 | 335 | ||
336 | static u16 get_mclk(struct oxygen *chip, unsigned int channel, | ||
337 | struct snd_pcm_hw_params *params) | ||
338 | { | ||
339 | unsigned int mclks, shift; | ||
340 | |||
341 | if (channel == PCM_MULTICH) | ||
342 | mclks = chip->model.dac_mclks; | ||
343 | else | ||
344 | mclks = chip->model.adc_mclks; | ||
345 | |||
346 | if (params_rate(params) <= 48000) | ||
347 | shift = 0; | ||
348 | else if (params_rate(params) <= 96000) | ||
349 | shift = 2; | ||
350 | else | ||
351 | shift = 4; | ||
352 | |||
353 | return OXYGEN_I2S_MCLK(mclks >> shift); | ||
354 | } | ||
355 | |||
344 | static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, | 356 | static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, |
345 | struct snd_pcm_hw_params *hw_params) | 357 | struct snd_pcm_hw_params *hw_params) |
346 | { | 358 | { |
@@ -357,8 +369,8 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, | |||
357 | OXYGEN_REC_FORMAT_A_MASK); | 369 | OXYGEN_REC_FORMAT_A_MASK); |
358 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, | 370 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, |
359 | oxygen_rate(hw_params) | | 371 | oxygen_rate(hw_params) | |
360 | chip->model.get_i2s_mclk(chip, PCM_A, hw_params) | | ||
361 | chip->model.adc_i2s_format | | 372 | chip->model.adc_i2s_format | |
373 | get_mclk(chip, PCM_A, hw_params) | | ||
362 | oxygen_i2s_bits(hw_params), | 374 | oxygen_i2s_bits(hw_params), |
363 | OXYGEN_I2S_RATE_MASK | | 375 | OXYGEN_I2S_RATE_MASK | |
364 | OXYGEN_I2S_FORMAT_MASK | | 376 | OXYGEN_I2S_FORMAT_MASK | |
@@ -393,9 +405,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, | |||
393 | if (!is_ac97) | 405 | if (!is_ac97) |
394 | oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, | 406 | oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, |
395 | oxygen_rate(hw_params) | | 407 | oxygen_rate(hw_params) | |
396 | chip->model.get_i2s_mclk(chip, PCM_B, | ||
397 | hw_params) | | ||
398 | chip->model.adc_i2s_format | | 408 | chip->model.adc_i2s_format | |
409 | get_mclk(chip, PCM_B, hw_params) | | ||
399 | oxygen_i2s_bits(hw_params), | 410 | oxygen_i2s_bits(hw_params), |
400 | OXYGEN_I2S_RATE_MASK | | 411 | OXYGEN_I2S_RATE_MASK | |
401 | OXYGEN_I2S_FORMAT_MASK | | 412 | OXYGEN_I2S_FORMAT_MASK | |
@@ -476,8 +487,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, | |||
476 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, | 487 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, |
477 | oxygen_rate(hw_params) | | 488 | oxygen_rate(hw_params) | |
478 | chip->model.dac_i2s_format | | 489 | chip->model.dac_i2s_format | |
479 | chip->model.get_i2s_mclk(chip, PCM_MULTICH, | 490 | get_mclk(chip, PCM_MULTICH, hw_params) | |
480 | hw_params) | | ||
481 | oxygen_i2s_bits(hw_params), | 491 | oxygen_i2s_bits(hw_params), |
482 | OXYGEN_I2S_RATE_MASK | | 492 | OXYGEN_I2S_RATE_MASK | |
483 | OXYGEN_I2S_FORMAT_MASK | | 493 | OXYGEN_I2S_FORMAT_MASK | |
@@ -530,7 +540,10 @@ static int oxygen_prepare(struct snd_pcm_substream *substream) | |||
530 | oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | 540 | oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); |
531 | oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | 541 | oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); |
532 | 542 | ||
533 | chip->interrupt_mask |= channel_mask; | 543 | if (substream->runtime->no_period_wakeup) |
544 | chip->interrupt_mask &= ~channel_mask; | ||
545 | else | ||
546 | chip->interrupt_mask |= channel_mask; | ||
534 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | 547 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); |
535 | spin_unlock_irq(&chip->reg_lock); | 548 | spin_unlock_irq(&chip->reg_lock); |
536 | return 0; | 549 | return 0; |
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h index 72de159d4567..63dc7a0ab555 100644 --- a/sound/pci/oxygen/oxygen_regs.h +++ b/sound/pci/oxygen/oxygen_regs.h | |||
@@ -139,9 +139,11 @@ | |||
139 | #define OXYGEN_I2S_FORMAT_I2S 0x0000 | 139 | #define OXYGEN_I2S_FORMAT_I2S 0x0000 |
140 | #define OXYGEN_I2S_FORMAT_LJUST 0x0008 | 140 | #define OXYGEN_I2S_FORMAT_LJUST 0x0008 |
141 | #define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */ | 141 | #define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */ |
142 | #define OXYGEN_I2S_MCLK_128 0x0000 | 142 | #define OXYGEN_I2S_MCLK_SHIFT 4 |
143 | #define OXYGEN_I2S_MCLK_256 0x0010 | 143 | #define MCLK_128 0 |
144 | #define OXYGEN_I2S_MCLK_512 0x0020 | 144 | #define MCLK_256 1 |
145 | #define MCLK_512 2 | ||
146 | #define OXYGEN_I2S_MCLK(f) (((f) & 3) << OXYGEN_I2S_MCLK_SHIFT) | ||
145 | #define OXYGEN_I2S_BITS_MASK 0x00c0 | 147 | #define OXYGEN_I2S_BITS_MASK 0x00c0 |
146 | #define OXYGEN_I2S_BITS_16 0x0000 | 148 | #define OXYGEN_I2S_BITS_16 0x0000 |
147 | #define OXYGEN_I2S_BITS_20 0x0040 | 149 | #define OXYGEN_I2S_BITS_20 0x0040 |
@@ -238,11 +240,11 @@ | |||
238 | #define OXYGEN_SPI_DATA_LENGTH_MASK 0x02 | 240 | #define OXYGEN_SPI_DATA_LENGTH_MASK 0x02 |
239 | #define OXYGEN_SPI_DATA_LENGTH_2 0x00 | 241 | #define OXYGEN_SPI_DATA_LENGTH_2 0x00 |
240 | #define OXYGEN_SPI_DATA_LENGTH_3 0x02 | 242 | #define OXYGEN_SPI_DATA_LENGTH_3 0x02 |
241 | #define OXYGEN_SPI_CLOCK_MASK 0xc0 | 243 | #define OXYGEN_SPI_CLOCK_MASK 0x0c |
242 | #define OXYGEN_SPI_CLOCK_160 0x00 /* ns */ | 244 | #define OXYGEN_SPI_CLOCK_160 0x00 /* ns */ |
243 | #define OXYGEN_SPI_CLOCK_320 0x40 | 245 | #define OXYGEN_SPI_CLOCK_320 0x04 |
244 | #define OXYGEN_SPI_CLOCK_640 0x80 | 246 | #define OXYGEN_SPI_CLOCK_640 0x08 |
245 | #define OXYGEN_SPI_CLOCK_1280 0xc0 | 247 | #define OXYGEN_SPI_CLOCK_1280 0x0c |
246 | #define OXYGEN_SPI_CODEC_MASK 0x70 /* 0..5 */ | 248 | #define OXYGEN_SPI_CODEC_MASK 0x70 /* 0..5 */ |
247 | #define OXYGEN_SPI_CODEC_SHIFT 4 | 249 | #define OXYGEN_SPI_CODEC_SHIFT 4 |
248 | #define OXYGEN_SPI_CEN_MASK 0x80 | 250 | #define OXYGEN_SPI_CEN_MASK 0x80 |
@@ -436,13 +438,15 @@ | |||
436 | /* OXYGEN_CHANNEL_* */ | 438 | /* OXYGEN_CHANNEL_* */ |
437 | 439 | ||
438 | #define OXYGEN_CODEC_VERSION 0xe4 | 440 | #define OXYGEN_CODEC_VERSION 0xe4 |
439 | #define OXYGEN_XCID_MASK 0x07 | 441 | #define OXYGEN_CODEC_ID_MASK 0x07 |
440 | 442 | ||
441 | #define OXYGEN_REVISION 0xe6 | 443 | #define OXYGEN_REVISION 0xe6 |
442 | #define OXYGEN_REVISION_XPKGID_MASK 0x0007 | 444 | #define OXYGEN_PACKAGE_ID_MASK 0x0007 |
445 | #define OXYGEN_PACKAGE_ID_8786 0x0004 | ||
446 | #define OXYGEN_PACKAGE_ID_8787 0x0006 | ||
447 | #define OXYGEN_PACKAGE_ID_8788 0x0007 | ||
443 | #define OXYGEN_REVISION_MASK 0xfff8 | 448 | #define OXYGEN_REVISION_MASK 0xfff8 |
444 | #define OXYGEN_REVISION_2 0x0008 /* bit flag */ | 449 | #define OXYGEN_REVISION_2 0x0008 |
445 | #define OXYGEN_REVISION_8787 0x0014 /* 8 bits */ | ||
446 | 450 | ||
447 | #define OXYGEN_OFFSIN_48K 0xe8 | 451 | #define OXYGEN_OFFSIN_48K 0xe8 |
448 | #define OXYGEN_OFFSBASE_48K 0xe9 | 452 | #define OXYGEN_OFFSBASE_48K 0xe9 |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 06c863e86e3d..469010a8b849 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -25,9 +25,9 @@ | |||
25 | #include "xonar.h" | 25 | #include "xonar.h" |
26 | 26 | ||
27 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 27 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
28 | MODULE_DESCRIPTION("Asus AVx00 driver"); | 28 | MODULE_DESCRIPTION("Asus Virtuoso driver"); |
29 | MODULE_LICENSE("GPL v2"); | 29 | MODULE_LICENSE("GPL v2"); |
30 | MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); | 30 | MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}"); |
31 | 31 | ||
32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
@@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { | |||
49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, | 49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, |
50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, | 50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, |
51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, | 51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, |
52 | { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, | ||
52 | { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, | 53 | { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, |
53 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
54 | { } | 55 | { } |
diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h index b35343b0a9a5..0434c207e811 100644 --- a/sound/pci/oxygen/xonar.h +++ b/sound/pci/oxygen/xonar.h | |||
@@ -24,6 +24,8 @@ void xonar_init_ext_power(struct oxygen *chip); | |||
24 | void xonar_init_cs53x1(struct oxygen *chip); | 24 | void xonar_init_cs53x1(struct oxygen *chip); |
25 | void xonar_set_cs53x1_params(struct oxygen *chip, | 25 | void xonar_set_cs53x1_params(struct oxygen *chip, |
26 | struct snd_pcm_hw_params *params); | 26 | struct snd_pcm_hw_params *params); |
27 | |||
28 | #define XONAR_GPIO_BIT_INVERT (1 << 16) | ||
27 | int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, | 29 | int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, |
28 | struct snd_ctl_elem_value *value); | 30 | struct snd_ctl_elem_value *value); |
29 | int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, | 31 | int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, |
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 7c4986b27f2b..252719101c42 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c | |||
@@ -22,29 +22,28 @@ | |||
22 | * | 22 | * |
23 | * CMI8788: | 23 | * CMI8788: |
24 | * | 24 | * |
25 | * I²C <-> CS4398 (front) | 25 | * I²C <-> CS4398 (addr 1001111) (front) |
26 | * <-> CS4362A (surround, center/LFE, back) | 26 | * <-> CS4362A (addr 0011000) (surround, center/LFE, back) |
27 | * | 27 | * |
28 | * GPI 0 <- external power present (DX only) | 28 | * GPI 0 <- external power present (DX only) |
29 | * | 29 | * |
30 | * GPIO 0 -> enable output to speakers | 30 | * GPIO 0 -> enable output to speakers |
31 | * GPIO 1 -> enable front panel I/O | 31 | * GPIO 1 -> route output to front panel |
32 | * GPIO 2 -> M0 of CS5361 | 32 | * GPIO 2 -> M0 of CS5361 |
33 | * GPIO 3 -> M1 of CS5361 | 33 | * GPIO 3 -> M1 of CS5361 |
34 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | 34 | * GPIO 6 -> ? |
35 | * GPIO 7 -> ? | ||
36 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
35 | * | 37 | * |
36 | * CS4398: | 38 | * CM9780: |
37 | * | ||
38 | * AD0 <- 1 | ||
39 | * AD1 <- 1 | ||
40 | * | ||
41 | * CS4362A: | ||
42 | * | 39 | * |
43 | * AD0 <- 0 | 40 | * LINE_OUT -> input of ADC |
44 | * | 41 | * |
45 | * CM9780: | 42 | * AUX_IN <- aux |
43 | * MIC_IN <- mic | ||
44 | * FMIC_IN <- front mic | ||
46 | * | 45 | * |
47 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input | 46 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input |
48 | */ | 47 | */ |
49 | 48 | ||
50 | #include <linux/pci.h> | 49 | #include <linux/pci.h> |
@@ -63,6 +62,7 @@ | |||
63 | #define GPI_EXT_POWER 0x01 | 62 | #define GPI_EXT_POWER 0x01 |
64 | #define GPIO_D1_OUTPUT_ENABLE 0x0001 | 63 | #define GPIO_D1_OUTPUT_ENABLE 0x0001 |
65 | #define GPIO_D1_FRONT_PANEL 0x0002 | 64 | #define GPIO_D1_FRONT_PANEL 0x0002 |
65 | #define GPIO_D1_MAGIC 0x00c0 | ||
66 | #define GPIO_D1_INPUT_ROUTE 0x0100 | 66 | #define GPIO_D1_INPUT_ROUTE 0x0100 |
67 | 67 | ||
68 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ | 68 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ |
@@ -169,12 +169,12 @@ static void xonar_d1_init(struct oxygen *chip) | |||
169 | cs43xx_registers_init(chip); | 169 | cs43xx_registers_init(chip); |
170 | 170 | ||
171 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | 171 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
172 | GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); | 172 | GPIO_D1_FRONT_PANEL | |
173 | GPIO_D1_MAGIC | | ||
174 | GPIO_D1_INPUT_ROUTE); | ||
173 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | 175 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, |
174 | GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); | 176 | GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); |
175 | 177 | ||
176 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | ||
177 | |||
178 | xonar_init_cs53x1(chip); | 178 | xonar_init_cs53x1(chip); |
179 | xonar_enable_output(chip); | 179 | xonar_enable_output(chip); |
180 | 180 | ||
@@ -284,7 +284,7 @@ static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed) | |||
284 | 284 | ||
285 | static const struct snd_kcontrol_new front_panel_switch = { | 285 | static const struct snd_kcontrol_new front_panel_switch = { |
286 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 286 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
287 | .name = "Front Panel Switch", | 287 | .name = "Front Panel Playback Switch", |
288 | .info = snd_ctl_boolean_mono_info, | 288 | .info = snd_ctl_boolean_mono_info, |
289 | .get = xonar_gpio_bit_switch_get, | 289 | .get = xonar_gpio_bit_switch_get, |
290 | .put = xonar_gpio_bit_switch_put, | 290 | .put = xonar_gpio_bit_switch_put, |
@@ -298,13 +298,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, | |||
298 | "Fast Roll-off", "Slow Roll-off" | 298 | "Fast Roll-off", "Slow Roll-off" |
299 | }; | 299 | }; |
300 | 300 | ||
301 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 301 | return snd_ctl_enum_info(info, 1, 2, names); |
302 | info->count = 1; | ||
303 | info->value.enumerated.items = 2; | ||
304 | if (info->value.enumerated.item >= 2) | ||
305 | info->value.enumerated.item = 1; | ||
306 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
307 | return 0; | ||
308 | } | 302 | } |
309 | 303 | ||
310 | static int rolloff_get(struct snd_kcontrol *ctl, | 304 | static int rolloff_get(struct snd_kcontrol *ctl, |
@@ -367,13 +361,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, | |||
367 | 361 | ||
368 | static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); | 362 | static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); |
369 | 363 | ||
370 | static int xonar_d1_control_filter(struct snd_kcontrol_new *template) | ||
371 | { | ||
372 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
373 | return 1; /* no CD input */ | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int xonar_d1_mixer_init(struct oxygen *chip) | 364 | static int xonar_d1_mixer_init(struct oxygen *chip) |
378 | { | 365 | { |
379 | int err; | 366 | int err; |
@@ -387,31 +374,58 @@ static int xonar_d1_mixer_init(struct oxygen *chip) | |||
387 | return 0; | 374 | return 0; |
388 | } | 375 | } |
389 | 376 | ||
377 | static void dump_cs4362a_registers(struct xonar_cs43xx *data, | ||
378 | struct snd_info_buffer *buffer) | ||
379 | { | ||
380 | unsigned int i; | ||
381 | |||
382 | snd_iprintf(buffer, "\nCS4362A:"); | ||
383 | for (i = 1; i <= 14; ++i) | ||
384 | snd_iprintf(buffer, " %02x", data->cs4362a_regs[i]); | ||
385 | snd_iprintf(buffer, "\n"); | ||
386 | } | ||
387 | |||
388 | static void dump_d1_registers(struct oxygen *chip, | ||
389 | struct snd_info_buffer *buffer) | ||
390 | { | ||
391 | struct xonar_cs43xx *data = chip->model_data; | ||
392 | unsigned int i; | ||
393 | |||
394 | snd_iprintf(buffer, "\nCS4398: 7?"); | ||
395 | for (i = 2; i < 8; ++i) | ||
396 | snd_iprintf(buffer, " %02x", data->cs4398_regs[i]); | ||
397 | snd_iprintf(buffer, "\n"); | ||
398 | dump_cs4362a_registers(data, buffer); | ||
399 | } | ||
400 | |||
390 | static const struct oxygen_model model_xonar_d1 = { | 401 | static const struct oxygen_model model_xonar_d1 = { |
391 | .longname = "Asus Virtuoso 100", | 402 | .longname = "Asus Virtuoso 100", |
392 | .chip = "AV200", | 403 | .chip = "AV200", |
393 | .init = xonar_d1_init, | 404 | .init = xonar_d1_init, |
394 | .control_filter = xonar_d1_control_filter, | ||
395 | .mixer_init = xonar_d1_mixer_init, | 405 | .mixer_init = xonar_d1_mixer_init, |
396 | .cleanup = xonar_d1_cleanup, | 406 | .cleanup = xonar_d1_cleanup, |
397 | .suspend = xonar_d1_suspend, | 407 | .suspend = xonar_d1_suspend, |
398 | .resume = xonar_d1_resume, | 408 | .resume = xonar_d1_resume, |
399 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
400 | .set_dac_params = set_cs43xx_params, | 409 | .set_dac_params = set_cs43xx_params, |
401 | .set_adc_params = xonar_set_cs53x1_params, | 410 | .set_adc_params = xonar_set_cs53x1_params, |
402 | .update_dac_volume = update_cs43xx_volume, | 411 | .update_dac_volume = update_cs43xx_volume, |
403 | .update_dac_mute = update_cs43xx_mute, | 412 | .update_dac_mute = update_cs43xx_mute, |
404 | .update_center_lfe_mix = update_cs43xx_center_lfe_mix, | 413 | .update_center_lfe_mix = update_cs43xx_center_lfe_mix, |
405 | .ac97_switch = xonar_d1_line_mic_ac97_switch, | 414 | .ac97_switch = xonar_d1_line_mic_ac97_switch, |
415 | .dump_registers = dump_d1_registers, | ||
406 | .dac_tlv = cs4362a_db_scale, | 416 | .dac_tlv = cs4362a_db_scale, |
407 | .model_data_size = sizeof(struct xonar_cs43xx), | 417 | .model_data_size = sizeof(struct xonar_cs43xx), |
408 | .device_config = PLAYBACK_0_TO_I2S | | 418 | .device_config = PLAYBACK_0_TO_I2S | |
409 | PLAYBACK_1_TO_SPDIF | | 419 | PLAYBACK_1_TO_SPDIF | |
410 | CAPTURE_0_FROM_I2S_2, | 420 | CAPTURE_0_FROM_I2S_2 | |
411 | .dac_channels = 8, | 421 | AC97_FMIC_SWITCH, |
422 | .dac_channels_pcm = 8, | ||
423 | .dac_channels_mixer = 8, | ||
412 | .dac_volume_min = 127 - 60, | 424 | .dac_volume_min = 127 - 60, |
413 | .dac_volume_max = 127, | 425 | .dac_volume_max = 127, |
414 | .function_flags = OXYGEN_FUNCTION_2WIRE, | 426 | .function_flags = OXYGEN_FUNCTION_2WIRE, |
427 | .dac_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
428 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
415 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 429 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
416 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 430 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
417 | }; | 431 | }; |
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c new file mode 100644 index 000000000000..bc6eb58be380 --- /dev/null +++ b/sound/pci/oxygen/xonar_dg.c | |||
@@ -0,0 +1,608 @@ | |||
1 | /* | ||
2 | * card driver for the Xonar DG | ||
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, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * Xonar DG | ||
21 | * -------- | ||
22 | * | ||
23 | * CMI8788: | ||
24 | * | ||
25 | * SPI 0 -> CS4245 | ||
26 | * | ||
27 | * I²S 1 -> CS4245 | ||
28 | * I²S 2 -> CS4361 (center/LFE) | ||
29 | * I²S 3 -> CS4361 (surround) | ||
30 | * I²S 4 -> CS4361 (front) | ||
31 | * | ||
32 | * GPIO 3 <- ? | ||
33 | * GPIO 4 <- headphone detect | ||
34 | * GPIO 5 -> route input jack to line-in (0) or mic-in (1) | ||
35 | * GPIO 6 -> route input jack to line-in (0) or mic-in (1) | ||
36 | * GPIO 7 -> enable rear headphone amp | ||
37 | * GPIO 8 -> enable output to speakers | ||
38 | * | ||
39 | * CS4245: | ||
40 | * | ||
41 | * input 1 <- aux | ||
42 | * input 2 <- front mic | ||
43 | * input 4 <- line/mic | ||
44 | * DAC out -> headphones | ||
45 | * aux out -> front panel headphones | ||
46 | */ | ||
47 | |||
48 | #include <linux/pci.h> | ||
49 | #include <linux/delay.h> | ||
50 | #include <sound/control.h> | ||
51 | #include <sound/core.h> | ||
52 | #include <sound/info.h> | ||
53 | #include <sound/pcm.h> | ||
54 | #include <sound/tlv.h> | ||
55 | #include "oxygen.h" | ||
56 | #include "xonar_dg.h" | ||
57 | #include "cs4245.h" | ||
58 | |||
59 | #define GPIO_MAGIC 0x0008 | ||
60 | #define GPIO_HP_DETECT 0x0010 | ||
61 | #define GPIO_INPUT_ROUTE 0x0060 | ||
62 | #define GPIO_HP_REAR 0x0080 | ||
63 | #define GPIO_OUTPUT_ENABLE 0x0100 | ||
64 | |||
65 | struct dg { | ||
66 | unsigned int output_sel; | ||
67 | s8 input_vol[4][2]; | ||
68 | unsigned int input_sel; | ||
69 | u8 hp_vol_att; | ||
70 | u8 cs4245_regs[0x11]; | ||
71 | }; | ||
72 | |||
73 | static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) | ||
74 | { | ||
75 | struct dg *data = chip->model_data; | ||
76 | |||
77 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
78 | OXYGEN_SPI_DATA_LENGTH_3 | | ||
79 | OXYGEN_SPI_CLOCK_1280 | | ||
80 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | ||
81 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
82 | CS4245_SPI_ADDRESS | | ||
83 | CS4245_SPI_WRITE | | ||
84 | (reg << 8) | value); | ||
85 | data->cs4245_regs[reg] = value; | ||
86 | } | ||
87 | |||
88 | static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) | ||
89 | { | ||
90 | struct dg *data = chip->model_data; | ||
91 | |||
92 | if (value != data->cs4245_regs[reg]) | ||
93 | cs4245_write(chip, reg, value); | ||
94 | } | ||
95 | |||
96 | static void cs4245_registers_init(struct oxygen *chip) | ||
97 | { | ||
98 | struct dg *data = chip->model_data; | ||
99 | |||
100 | cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN); | ||
101 | cs4245_write(chip, CS4245_DAC_CTRL_1, | ||
102 | data->cs4245_regs[CS4245_DAC_CTRL_1]); | ||
103 | cs4245_write(chip, CS4245_ADC_CTRL, | ||
104 | data->cs4245_regs[CS4245_ADC_CTRL]); | ||
105 | cs4245_write(chip, CS4245_SIGNAL_SEL, | ||
106 | data->cs4245_regs[CS4245_SIGNAL_SEL]); | ||
107 | cs4245_write(chip, CS4245_PGA_B_CTRL, | ||
108 | data->cs4245_regs[CS4245_PGA_B_CTRL]); | ||
109 | cs4245_write(chip, CS4245_PGA_A_CTRL, | ||
110 | data->cs4245_regs[CS4245_PGA_A_CTRL]); | ||
111 | cs4245_write(chip, CS4245_ANALOG_IN, | ||
112 | data->cs4245_regs[CS4245_ANALOG_IN]); | ||
113 | cs4245_write(chip, CS4245_DAC_A_CTRL, | ||
114 | data->cs4245_regs[CS4245_DAC_A_CTRL]); | ||
115 | cs4245_write(chip, CS4245_DAC_B_CTRL, | ||
116 | data->cs4245_regs[CS4245_DAC_B_CTRL]); | ||
117 | cs4245_write(chip, CS4245_DAC_CTRL_2, | ||
118 | CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC); | ||
119 | cs4245_write(chip, CS4245_INT_MASK, 0); | ||
120 | cs4245_write(chip, CS4245_POWER_CTRL, 0); | ||
121 | } | ||
122 | |||
123 | static void cs4245_init(struct oxygen *chip) | ||
124 | { | ||
125 | struct dg *data = chip->model_data; | ||
126 | |||
127 | data->cs4245_regs[CS4245_DAC_CTRL_1] = | ||
128 | CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST; | ||
129 | data->cs4245_regs[CS4245_ADC_CTRL] = | ||
130 | CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST; | ||
131 | data->cs4245_regs[CS4245_SIGNAL_SEL] = | ||
132 | CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH; | ||
133 | data->cs4245_regs[CS4245_PGA_B_CTRL] = 0; | ||
134 | data->cs4245_regs[CS4245_PGA_A_CTRL] = 0; | ||
135 | data->cs4245_regs[CS4245_ANALOG_IN] = | ||
136 | CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4; | ||
137 | data->cs4245_regs[CS4245_DAC_A_CTRL] = 0; | ||
138 | data->cs4245_regs[CS4245_DAC_B_CTRL] = 0; | ||
139 | cs4245_registers_init(chip); | ||
140 | snd_component_add(chip->card, "CS4245"); | ||
141 | } | ||
142 | |||
143 | static void dg_output_enable(struct oxygen *chip) | ||
144 | { | ||
145 | msleep(2500); | ||
146 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
147 | } | ||
148 | |||
149 | static void dg_init(struct oxygen *chip) | ||
150 | { | ||
151 | struct dg *data = chip->model_data; | ||
152 | |||
153 | data->output_sel = 0; | ||
154 | data->input_sel = 3; | ||
155 | data->hp_vol_att = 2 * 16; | ||
156 | |||
157 | cs4245_init(chip); | ||
158 | |||
159 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
160 | GPIO_MAGIC | GPIO_HP_DETECT); | ||
161 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
162 | GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE); | ||
163 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | ||
164 | GPIO_INPUT_ROUTE | GPIO_HP_REAR); | ||
165 | dg_output_enable(chip); | ||
166 | } | ||
167 | |||
168 | static void dg_cleanup(struct oxygen *chip) | ||
169 | { | ||
170 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
171 | } | ||
172 | |||
173 | static void dg_suspend(struct oxygen *chip) | ||
174 | { | ||
175 | dg_cleanup(chip); | ||
176 | } | ||
177 | |||
178 | static void dg_resume(struct oxygen *chip) | ||
179 | { | ||
180 | cs4245_registers_init(chip); | ||
181 | dg_output_enable(chip); | ||
182 | } | ||
183 | |||
184 | static void set_cs4245_dac_params(struct oxygen *chip, | ||
185 | struct snd_pcm_hw_params *params) | ||
186 | { | ||
187 | struct dg *data = chip->model_data; | ||
188 | u8 value; | ||
189 | |||
190 | value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK; | ||
191 | if (params_rate(params) <= 50000) | ||
192 | value |= CS4245_DAC_FM_SINGLE; | ||
193 | else if (params_rate(params) <= 100000) | ||
194 | value |= CS4245_DAC_FM_DOUBLE; | ||
195 | else | ||
196 | value |= CS4245_DAC_FM_QUAD; | ||
197 | cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value); | ||
198 | } | ||
199 | |||
200 | static void set_cs4245_adc_params(struct oxygen *chip, | ||
201 | struct snd_pcm_hw_params *params) | ||
202 | { | ||
203 | struct dg *data = chip->model_data; | ||
204 | u8 value; | ||
205 | |||
206 | value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; | ||
207 | if (params_rate(params) <= 50000) | ||
208 | value |= CS4245_ADC_FM_SINGLE; | ||
209 | else if (params_rate(params) <= 100000) | ||
210 | value |= CS4245_ADC_FM_DOUBLE; | ||
211 | else | ||
212 | value |= CS4245_ADC_FM_QUAD; | ||
213 | cs4245_write_cached(chip, CS4245_ADC_CTRL, value); | ||
214 | } | ||
215 | |||
216 | static inline unsigned int shift_bits(unsigned int value, | ||
217 | unsigned int shift_from, | ||
218 | unsigned int shift_to, | ||
219 | unsigned int mask) | ||
220 | { | ||
221 | if (shift_from < shift_to) | ||
222 | return (value << (shift_to - shift_from)) & mask; | ||
223 | else | ||
224 | return (value >> (shift_from - shift_to)) & mask; | ||
225 | } | ||
226 | |||
227 | static unsigned int adjust_dg_dac_routing(struct oxygen *chip, | ||
228 | unsigned int play_routing) | ||
229 | { | ||
230 | return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) | | ||
231 | shift_bits(play_routing, | ||
232 | OXYGEN_PLAY_DAC2_SOURCE_SHIFT, | ||
233 | OXYGEN_PLAY_DAC1_SOURCE_SHIFT, | ||
234 | OXYGEN_PLAY_DAC1_SOURCE_MASK) | | ||
235 | shift_bits(play_routing, | ||
236 | OXYGEN_PLAY_DAC1_SOURCE_SHIFT, | ||
237 | OXYGEN_PLAY_DAC2_SOURCE_SHIFT, | ||
238 | OXYGEN_PLAY_DAC2_SOURCE_MASK) | | ||
239 | shift_bits(play_routing, | ||
240 | OXYGEN_PLAY_DAC0_SOURCE_SHIFT, | ||
241 | OXYGEN_PLAY_DAC3_SOURCE_SHIFT, | ||
242 | OXYGEN_PLAY_DAC3_SOURCE_MASK); | ||
243 | } | ||
244 | |||
245 | static int output_switch_info(struct snd_kcontrol *ctl, | ||
246 | struct snd_ctl_elem_info *info) | ||
247 | { | ||
248 | static const char *const names[3] = { | ||
249 | "Speakers", "Headphones", "FP Headphones" | ||
250 | }; | ||
251 | |||
252 | return snd_ctl_enum_info(info, 1, 3, names); | ||
253 | } | ||
254 | |||
255 | static int output_switch_get(struct snd_kcontrol *ctl, | ||
256 | struct snd_ctl_elem_value *value) | ||
257 | { | ||
258 | struct oxygen *chip = ctl->private_data; | ||
259 | struct dg *data = chip->model_data; | ||
260 | |||
261 | mutex_lock(&chip->mutex); | ||
262 | value->value.enumerated.item[0] = data->output_sel; | ||
263 | mutex_unlock(&chip->mutex); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int output_switch_put(struct snd_kcontrol *ctl, | ||
268 | struct snd_ctl_elem_value *value) | ||
269 | { | ||
270 | struct oxygen *chip = ctl->private_data; | ||
271 | struct dg *data = chip->model_data; | ||
272 | u8 reg; | ||
273 | int changed; | ||
274 | |||
275 | if (value->value.enumerated.item[0] > 2) | ||
276 | return -EINVAL; | ||
277 | |||
278 | mutex_lock(&chip->mutex); | ||
279 | changed = value->value.enumerated.item[0] != data->output_sel; | ||
280 | if (changed) { | ||
281 | data->output_sel = value->value.enumerated.item[0]; | ||
282 | |||
283 | reg = data->cs4245_regs[CS4245_SIGNAL_SEL] & | ||
284 | ~CS4245_A_OUT_SEL_MASK; | ||
285 | reg |= data->output_sel == 2 ? | ||
286 | CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; | ||
287 | cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); | ||
288 | |||
289 | cs4245_write_cached(chip, CS4245_DAC_A_CTRL, | ||
290 | data->output_sel ? data->hp_vol_att : 0); | ||
291 | cs4245_write_cached(chip, CS4245_DAC_B_CTRL, | ||
292 | data->output_sel ? data->hp_vol_att : 0); | ||
293 | |||
294 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
295 | data->output_sel == 1 ? GPIO_HP_REAR : 0, | ||
296 | GPIO_HP_REAR); | ||
297 | } | ||
298 | mutex_unlock(&chip->mutex); | ||
299 | return changed; | ||
300 | } | ||
301 | |||
302 | static int hp_volume_offset_info(struct snd_kcontrol *ctl, | ||
303 | struct snd_ctl_elem_info *info) | ||
304 | { | ||
305 | static const char *const names[3] = { | ||
306 | "< 64 ohms", "64-150 ohms", "150-300 ohms" | ||
307 | }; | ||
308 | |||
309 | return snd_ctl_enum_info(info, 1, 3, names); | ||
310 | } | ||
311 | |||
312 | static int hp_volume_offset_get(struct snd_kcontrol *ctl, | ||
313 | struct snd_ctl_elem_value *value) | ||
314 | { | ||
315 | struct oxygen *chip = ctl->private_data; | ||
316 | struct dg *data = chip->model_data; | ||
317 | |||
318 | mutex_lock(&chip->mutex); | ||
319 | if (data->hp_vol_att > 2 * 7) | ||
320 | value->value.enumerated.item[0] = 0; | ||
321 | else if (data->hp_vol_att > 0) | ||
322 | value->value.enumerated.item[0] = 1; | ||
323 | else | ||
324 | value->value.enumerated.item[0] = 2; | ||
325 | mutex_unlock(&chip->mutex); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int hp_volume_offset_put(struct snd_kcontrol *ctl, | ||
330 | struct snd_ctl_elem_value *value) | ||
331 | { | ||
332 | static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; | ||
333 | struct oxygen *chip = ctl->private_data; | ||
334 | struct dg *data = chip->model_data; | ||
335 | s8 att; | ||
336 | int changed; | ||
337 | |||
338 | if (value->value.enumerated.item[0] > 2) | ||
339 | return -EINVAL; | ||
340 | att = atts[value->value.enumerated.item[0]]; | ||
341 | mutex_lock(&chip->mutex); | ||
342 | changed = att != data->hp_vol_att; | ||
343 | if (changed) { | ||
344 | data->hp_vol_att = att; | ||
345 | if (data->output_sel) { | ||
346 | cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); | ||
347 | cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); | ||
348 | } | ||
349 | } | ||
350 | mutex_unlock(&chip->mutex); | ||
351 | return changed; | ||
352 | } | ||
353 | |||
354 | static int input_vol_info(struct snd_kcontrol *ctl, | ||
355 | struct snd_ctl_elem_info *info) | ||
356 | { | ||
357 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
358 | info->count = 2; | ||
359 | info->value.integer.min = 2 * -12; | ||
360 | info->value.integer.max = 2 * 12; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int input_vol_get(struct snd_kcontrol *ctl, | ||
365 | struct snd_ctl_elem_value *value) | ||
366 | { | ||
367 | struct oxygen *chip = ctl->private_data; | ||
368 | struct dg *data = chip->model_data; | ||
369 | unsigned int idx = ctl->private_value; | ||
370 | |||
371 | mutex_lock(&chip->mutex); | ||
372 | value->value.integer.value[0] = data->input_vol[idx][0]; | ||
373 | value->value.integer.value[1] = data->input_vol[idx][1]; | ||
374 | mutex_unlock(&chip->mutex); | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int input_vol_put(struct snd_kcontrol *ctl, | ||
379 | struct snd_ctl_elem_value *value) | ||
380 | { | ||
381 | struct oxygen *chip = ctl->private_data; | ||
382 | struct dg *data = chip->model_data; | ||
383 | unsigned int idx = ctl->private_value; | ||
384 | int changed = 0; | ||
385 | |||
386 | if (value->value.integer.value[0] < 2 * -12 || | ||
387 | value->value.integer.value[0] > 2 * 12 || | ||
388 | value->value.integer.value[1] < 2 * -12 || | ||
389 | value->value.integer.value[1] > 2 * 12) | ||
390 | return -EINVAL; | ||
391 | mutex_lock(&chip->mutex); | ||
392 | changed = data->input_vol[idx][0] != value->value.integer.value[0] || | ||
393 | data->input_vol[idx][1] != value->value.integer.value[1]; | ||
394 | if (changed) { | ||
395 | data->input_vol[idx][0] = value->value.integer.value[0]; | ||
396 | data->input_vol[idx][1] = value->value.integer.value[1]; | ||
397 | if (idx == data->input_sel) { | ||
398 | cs4245_write_cached(chip, CS4245_PGA_A_CTRL, | ||
399 | data->input_vol[idx][0]); | ||
400 | cs4245_write_cached(chip, CS4245_PGA_B_CTRL, | ||
401 | data->input_vol[idx][1]); | ||
402 | } | ||
403 | } | ||
404 | mutex_unlock(&chip->mutex); | ||
405 | return changed; | ||
406 | } | ||
407 | |||
408 | static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); | ||
409 | |||
410 | static int input_sel_info(struct snd_kcontrol *ctl, | ||
411 | struct snd_ctl_elem_info *info) | ||
412 | { | ||
413 | static const char *const names[4] = { | ||
414 | "Mic", "Aux", "Front Mic", "Line" | ||
415 | }; | ||
416 | |||
417 | return snd_ctl_enum_info(info, 1, 4, names); | ||
418 | } | ||
419 | |||
420 | static int input_sel_get(struct snd_kcontrol *ctl, | ||
421 | struct snd_ctl_elem_value *value) | ||
422 | { | ||
423 | struct oxygen *chip = ctl->private_data; | ||
424 | struct dg *data = chip->model_data; | ||
425 | |||
426 | mutex_lock(&chip->mutex); | ||
427 | value->value.enumerated.item[0] = data->input_sel; | ||
428 | mutex_unlock(&chip->mutex); | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int input_sel_put(struct snd_kcontrol *ctl, | ||
433 | struct snd_ctl_elem_value *value) | ||
434 | { | ||
435 | static const u8 sel_values[4] = { | ||
436 | CS4245_SEL_MIC, | ||
437 | CS4245_SEL_INPUT_1, | ||
438 | CS4245_SEL_INPUT_2, | ||
439 | CS4245_SEL_INPUT_4 | ||
440 | }; | ||
441 | struct oxygen *chip = ctl->private_data; | ||
442 | struct dg *data = chip->model_data; | ||
443 | int changed; | ||
444 | |||
445 | if (value->value.enumerated.item[0] > 3) | ||
446 | return -EINVAL; | ||
447 | |||
448 | mutex_lock(&chip->mutex); | ||
449 | changed = value->value.enumerated.item[0] != data->input_sel; | ||
450 | if (changed) { | ||
451 | data->input_sel = value->value.enumerated.item[0]; | ||
452 | |||
453 | cs4245_write(chip, CS4245_ANALOG_IN, | ||
454 | (data->cs4245_regs[CS4245_ANALOG_IN] & | ||
455 | ~CS4245_SEL_MASK) | | ||
456 | sel_values[data->input_sel]); | ||
457 | |||
458 | cs4245_write_cached(chip, CS4245_PGA_A_CTRL, | ||
459 | data->input_vol[data->input_sel][0]); | ||
460 | cs4245_write_cached(chip, CS4245_PGA_B_CTRL, | ||
461 | data->input_vol[data->input_sel][1]); | ||
462 | |||
463 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
464 | data->input_sel ? 0 : GPIO_INPUT_ROUTE, | ||
465 | GPIO_INPUT_ROUTE); | ||
466 | } | ||
467 | mutex_unlock(&chip->mutex); | ||
468 | return changed; | ||
469 | } | ||
470 | |||
471 | static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
472 | { | ||
473 | static const char *const names[2] = { "Active", "Frozen" }; | ||
474 | |||
475 | return snd_ctl_enum_info(info, 1, 2, names); | ||
476 | } | ||
477 | |||
478 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
479 | { | ||
480 | struct oxygen *chip = ctl->private_data; | ||
481 | struct dg *data = chip->model_data; | ||
482 | |||
483 | value->value.enumerated.item[0] = | ||
484 | !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
489 | { | ||
490 | struct oxygen *chip = ctl->private_data; | ||
491 | struct dg *data = chip->model_data; | ||
492 | u8 reg; | ||
493 | int changed; | ||
494 | |||
495 | mutex_lock(&chip->mutex); | ||
496 | reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; | ||
497 | if (value->value.enumerated.item[0]) | ||
498 | reg |= CS4245_HPF_FREEZE; | ||
499 | changed = reg != data->cs4245_regs[CS4245_ADC_CTRL]; | ||
500 | if (changed) | ||
501 | cs4245_write(chip, CS4245_ADC_CTRL, reg); | ||
502 | mutex_unlock(&chip->mutex); | ||
503 | return changed; | ||
504 | } | ||
505 | |||
506 | #define INPUT_VOLUME(xname, index) { \ | ||
507 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
508 | .name = xname, \ | ||
509 | .info = input_vol_info, \ | ||
510 | .get = input_vol_get, \ | ||
511 | .put = input_vol_put, \ | ||
512 | .tlv = { .p = cs4245_pga_db_scale }, \ | ||
513 | .private_value = index, \ | ||
514 | } | ||
515 | static const struct snd_kcontrol_new dg_controls[] = { | ||
516 | { | ||
517 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
518 | .name = "Analog Output Playback Enum", | ||
519 | .info = output_switch_info, | ||
520 | .get = output_switch_get, | ||
521 | .put = output_switch_put, | ||
522 | }, | ||
523 | { | ||
524 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
525 | .name = "Headphones Impedance Playback Enum", | ||
526 | .info = hp_volume_offset_info, | ||
527 | .get = hp_volume_offset_get, | ||
528 | .put = hp_volume_offset_put, | ||
529 | }, | ||
530 | INPUT_VOLUME("Mic Capture Volume", 0), | ||
531 | INPUT_VOLUME("Aux Capture Volume", 1), | ||
532 | INPUT_VOLUME("Front Mic Capture Volume", 2), | ||
533 | INPUT_VOLUME("Line Capture Volume", 3), | ||
534 | { | ||
535 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
536 | .name = "Capture Source", | ||
537 | .info = input_sel_info, | ||
538 | .get = input_sel_get, | ||
539 | .put = input_sel_put, | ||
540 | }, | ||
541 | { | ||
542 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
543 | .name = "ADC High-pass Filter Capture Enum", | ||
544 | .info = hpf_info, | ||
545 | .get = hpf_get, | ||
546 | .put = hpf_put, | ||
547 | }, | ||
548 | }; | ||
549 | |||
550 | static int dg_control_filter(struct snd_kcontrol_new *template) | ||
551 | { | ||
552 | if (!strncmp(template->name, "Master Playback ", 16)) | ||
553 | return 1; | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int dg_mixer_init(struct oxygen *chip) | ||
558 | { | ||
559 | unsigned int i; | ||
560 | int err; | ||
561 | |||
562 | for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { | ||
563 | err = snd_ctl_add(chip->card, | ||
564 | snd_ctl_new1(&dg_controls[i], chip)); | ||
565 | if (err < 0) | ||
566 | return err; | ||
567 | } | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static void dump_cs4245_registers(struct oxygen *chip, | ||
572 | struct snd_info_buffer *buffer) | ||
573 | { | ||
574 | struct dg *data = chip->model_data; | ||
575 | unsigned int i; | ||
576 | |||
577 | snd_iprintf(buffer, "\nCS4245:"); | ||
578 | for (i = 1; i <= 0x10; ++i) | ||
579 | snd_iprintf(buffer, " %02x", data->cs4245_regs[i]); | ||
580 | snd_iprintf(buffer, "\n"); | ||
581 | } | ||
582 | |||
583 | struct oxygen_model model_xonar_dg = { | ||
584 | .shortname = "Xonar DG", | ||
585 | .longname = "C-Media Oxygen HD Audio", | ||
586 | .chip = "CMI8786", | ||
587 | .init = dg_init, | ||
588 | .control_filter = dg_control_filter, | ||
589 | .mixer_init = dg_mixer_init, | ||
590 | .cleanup = dg_cleanup, | ||
591 | .suspend = dg_suspend, | ||
592 | .resume = dg_resume, | ||
593 | .set_dac_params = set_cs4245_dac_params, | ||
594 | .set_adc_params = set_cs4245_adc_params, | ||
595 | .adjust_dac_routing = adjust_dg_dac_routing, | ||
596 | .dump_registers = dump_cs4245_registers, | ||
597 | .model_data_size = sizeof(struct dg), | ||
598 | .device_config = PLAYBACK_0_TO_I2S | | ||
599 | PLAYBACK_1_TO_SPDIF | | ||
600 | CAPTURE_0_FROM_I2S_2, | ||
601 | .dac_channels_pcm = 6, | ||
602 | .dac_channels_mixer = 0, | ||
603 | .function_flags = OXYGEN_FUNCTION_SPI, | ||
604 | .dac_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
605 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
606 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
607 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
608 | }; | ||
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h new file mode 100644 index 000000000000..5688d78609a9 --- /dev/null +++ b/sound/pci/oxygen/xonar_dg.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef XONAR_DG_H_INCLUDED | ||
2 | #define XONAR_DG_H_INCLUDED | ||
3 | |||
4 | #include "oxygen.h" | ||
5 | |||
6 | extern struct oxygen_model model_xonar_dg; | ||
7 | |||
8 | #endif | ||
diff --git a/sound/pci/oxygen/xonar_hdmi.c b/sound/pci/oxygen/xonar_hdmi.c index b12db1f1cea9..136dac6a3964 100644 --- a/sound/pci/oxygen/xonar_hdmi.c +++ b/sound/pci/oxygen/xonar_hdmi.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * helper functions for HDMI models (Xonar HDAV1.3) | 2 | * helper functions for HDMI models (Xonar HDAV1.3/HDAV1.3 Slim) |
3 | * | 3 | * |
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
5 | * | 5 | * |
diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c index b3ff71316653..0ebe7f5916f9 100644 --- a/sound/pci/oxygen/xonar_lib.c +++ b/sound/pci/oxygen/xonar_lib.c | |||
@@ -104,9 +104,10 @@ int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, | |||
104 | { | 104 | { |
105 | struct oxygen *chip = ctl->private_data; | 105 | struct oxygen *chip = ctl->private_data; |
106 | u16 bit = ctl->private_value; | 106 | u16 bit = ctl->private_value; |
107 | bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; | ||
107 | 108 | ||
108 | value->value.integer.value[0] = | 109 | value->value.integer.value[0] = |
109 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit); | 110 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert; |
110 | return 0; | 111 | return 0; |
111 | } | 112 | } |
112 | 113 | ||
@@ -115,12 +116,13 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, | |||
115 | { | 116 | { |
116 | struct oxygen *chip = ctl->private_data; | 117 | struct oxygen *chip = ctl->private_data; |
117 | u16 bit = ctl->private_value; | 118 | u16 bit = ctl->private_value; |
119 | bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; | ||
118 | u16 old_bits, new_bits; | 120 | u16 old_bits, new_bits; |
119 | int changed; | 121 | int changed; |
120 | 122 | ||
121 | spin_lock_irq(&chip->reg_lock); | 123 | spin_lock_irq(&chip->reg_lock); |
122 | old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | 124 | old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); |
123 | if (value->value.integer.value[0]) | 125 | if (!!value->value.integer.value[0] ^ invert) |
124 | new_bits = old_bits | bit; | 126 | new_bits = old_bits | bit; |
125 | else | 127 | else |
126 | new_bits = old_bits & ~bit; | 128 | new_bits = old_bits & ~bit; |
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index ba18fb546b4f..54cad38ec30a 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
@@ -22,20 +22,26 @@ | |||
22 | * | 22 | * |
23 | * CMI8788: | 23 | * CMI8788: |
24 | * | 24 | * |
25 | * SPI 0 -> 1st PCM1796 (front) | 25 | * SPI 0 -> 1st PCM1796 (front) |
26 | * SPI 1 -> 2nd PCM1796 (surround) | 26 | * SPI 1 -> 2nd PCM1796 (surround) |
27 | * SPI 2 -> 3rd PCM1796 (center/LFE) | 27 | * SPI 2 -> 3rd PCM1796 (center/LFE) |
28 | * SPI 4 -> 4th PCM1796 (back) | 28 | * SPI 4 -> 4th PCM1796 (back) |
29 | * | 29 | * |
30 | * GPIO 2 -> M0 of CS5381 | 30 | * GPIO 2 -> M0 of CS5381 |
31 | * GPIO 3 -> M1 of CS5381 | 31 | * GPIO 3 -> M1 of CS5381 |
32 | * GPIO 5 <- external power present (D2X only) | 32 | * GPIO 5 <- external power present (D2X only) |
33 | * GPIO 7 -> ALT | 33 | * GPIO 7 -> ALT |
34 | * GPIO 8 -> enable output to speakers | 34 | * GPIO 8 -> enable output to speakers |
35 | * | 35 | * |
36 | * CM9780: | 36 | * CM9780: |
37 | * | 37 | * |
38 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | 38 | * LINE_OUT -> input of ADC |
39 | * | ||
40 | * AUX_IN <- aux | ||
41 | * VIDEO_IN <- CD | ||
42 | * FMIC_IN <- mic | ||
43 | * | ||
44 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
39 | */ | 45 | */ |
40 | 46 | ||
41 | /* | 47 | /* |
@@ -44,52 +50,53 @@ | |||
44 | * | 50 | * |
45 | * CMI8788: | 51 | * CMI8788: |
46 | * | 52 | * |
47 | * I²C <-> PCM1796 (front) | 53 | * I²C <-> PCM1796 (addr 1001100) (front) |
48 | * | 54 | * |
49 | * GPI 0 <- external power present | 55 | * GPI 0 <- external power present |
50 | * | 56 | * |
51 | * GPIO 0 -> enable output to speakers | 57 | * GPIO 0 -> enable HDMI (0) or speaker (1) output |
52 | * GPIO 2 -> M0 of CS5381 | 58 | * GPIO 2 -> M0 of CS5381 |
53 | * GPIO 3 -> M1 of CS5381 | 59 | * GPIO 3 -> M1 of CS5381 |
54 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | 60 | * GPIO 4 <- daughterboard detection |
61 | * GPIO 5 <- daughterboard detection | ||
62 | * GPIO 6 -> ? | ||
63 | * GPIO 7 -> ? | ||
64 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
55 | * | 65 | * |
56 | * TXD -> HDMI controller | 66 | * UART <-> HDMI controller |
57 | * RXD <- HDMI controller | ||
58 | * | ||
59 | * PCM1796 front: AD1,0 <- 0,0 | ||
60 | * | 67 | * |
61 | * CM9780: | 68 | * CM9780: |
62 | * | 69 | * |
63 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | 70 | * LINE_OUT -> input of ADC |
71 | * | ||
72 | * AUX_IN <- aux | ||
73 | * CD_IN <- CD | ||
74 | * MIC_IN <- mic | ||
75 | * | ||
76 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
64 | * | 77 | * |
65 | * no daughterboard | 78 | * no daughterboard |
66 | * ---------------- | 79 | * ---------------- |
67 | * | 80 | * |
68 | * GPIO 4 <- 1 | 81 | * GPIO 4 <- 1 |
69 | * | 82 | * |
70 | * H6 daughterboard | 83 | * H6 daughterboard |
71 | * ---------------- | 84 | * ---------------- |
72 | * | 85 | * |
73 | * GPIO 4 <- 0 | 86 | * GPIO 4 <- 0 |
74 | * GPIO 5 <- 0 | 87 | * GPIO 5 <- 0 |
75 | * | ||
76 | * I²C <-> PCM1796 (surround) | ||
77 | * <-> PCM1796 (center/LFE) | ||
78 | * <-> PCM1796 (back) | ||
79 | * | 88 | * |
80 | * PCM1796 surround: AD1,0 <- 0,1 | 89 | * I²C <-> PCM1796 (addr 1001101) (surround) |
81 | * PCM1796 center/LFE: AD1,0 <- 1,0 | 90 | * <-> PCM1796 (addr 1001110) (center/LFE) |
82 | * PCM1796 back: AD1,0 <- 1,1 | 91 | * <-> PCM1796 (addr 1001111) (back) |
83 | * | 92 | * |
84 | * unknown daughterboard | 93 | * unknown daughterboard |
85 | * --------------------- | 94 | * --------------------- |
86 | * | 95 | * |
87 | * GPIO 4 <- 0 | 96 | * GPIO 4 <- 0 |
88 | * GPIO 5 <- 1 | 97 | * GPIO 5 <- 1 |
89 | * | ||
90 | * I²C <-> CS4362A (surround, center/LFE, back) | ||
91 | * | 98 | * |
92 | * CS4362A: AD0 <- 0 | 99 | * I²C <-> CS4362A (addr 0011000) (surround, center/LFE, back) |
93 | */ | 100 | */ |
94 | 101 | ||
95 | /* | 102 | /* |
@@ -98,32 +105,35 @@ | |||
98 | * | 105 | * |
99 | * CMI8788: | 106 | * CMI8788: |
100 | * | 107 | * |
101 | * I²C <-> PCM1792A | 108 | * I²C <-> PCM1792A (addr 1001100) |
102 | * <-> CS2000 (ST only) | 109 | * <-> CS2000 (addr 1001110) (ST only) |
103 | * | 110 | * |
104 | * ADC1 MCLK -> REF_CLK of CS2000 (ST only) | 111 | * ADC1 MCLK -> REF_CLK of CS2000 (ST only) |
105 | * | 112 | * |
106 | * GPI 0 <- external power present (STX only) | 113 | * GPI 0 <- external power present (STX only) |
107 | * | 114 | * |
108 | * GPIO 0 -> enable output to speakers | 115 | * GPIO 0 -> enable output to speakers |
109 | * GPIO 1 -> route HP to front panel (0) or rear jack (1) | 116 | * GPIO 1 -> route HP to front panel (0) or rear jack (1) |
110 | * GPIO 2 -> M0 of CS5381 | 117 | * GPIO 2 -> M0 of CS5381 |
111 | * GPIO 3 -> M1 of CS5381 | 118 | * GPIO 3 -> M1 of CS5381 |
112 | * GPIO 7 -> route output to speaker jacks (0) or HP (1) | 119 | * GPIO 4 <- daughterboard detection |
113 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | 120 | * GPIO 5 <- daughterboard detection |
121 | * GPIO 6 -> ? | ||
122 | * GPIO 7 -> route output to speaker jacks (0) or HP (1) | ||
123 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
114 | * | 124 | * |
115 | * PCM1792A: | 125 | * PCM1792A: |
116 | * | 126 | * |
117 | * AD1,0 <- 0,0 | 127 | * SCK <- CLK_OUT of CS2000 (ST only) |
118 | * SCK <- CLK_OUT of CS2000 (ST only) | ||
119 | * | 128 | * |
120 | * CS2000: | 129 | * CM9780: |
121 | * | 130 | * |
122 | * AD0 <- 0 | 131 | * LINE_OUT -> input of ADC |
123 | * | 132 | * |
124 | * CM9780: | 133 | * AUX_IN <- aux |
134 | * MIC_IN <- mic | ||
125 | * | 135 | * |
126 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | 136 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input |
127 | * | 137 | * |
128 | * H6 daughterboard | 138 | * H6 daughterboard |
129 | * ---------------- | 139 | * ---------------- |
@@ -132,12 +142,49 @@ | |||
132 | * GPIO 5 <- 0 | 142 | * GPIO 5 <- 0 |
133 | */ | 143 | */ |
134 | 144 | ||
145 | /* | ||
146 | * Xonar Xense | ||
147 | * ----------- | ||
148 | * | ||
149 | * CMI8788: | ||
150 | * | ||
151 | * I²C <-> PCM1796 (addr 1001100) (front) | ||
152 | * <-> CS4362A (addr 0011000) (surround, center/LFE, back) | ||
153 | * <-> CS2000 (addr 1001110) | ||
154 | * | ||
155 | * ADC1 MCLK -> REF_CLK of CS2000 | ||
156 | * | ||
157 | * GPI 0 <- external power present | ||
158 | * | ||
159 | * GPIO 0 -> enable output | ||
160 | * GPIO 1 -> route HP to front panel (0) or rear jack (1) | ||
161 | * GPIO 2 -> M0 of CS5381 | ||
162 | * GPIO 3 -> M1 of CS5381 | ||
163 | * GPIO 4 -> enable output | ||
164 | * GPIO 5 -> enable output | ||
165 | * GPIO 6 -> ? | ||
166 | * GPIO 7 -> route output to HP (0) or speaker (1) | ||
167 | * GPIO 8 -> route input jack to mic-in (0) or line-in (1) | ||
168 | * | ||
169 | * CM9780: | ||
170 | * | ||
171 | * LINE_OUT -> input of ADC | ||
172 | * | ||
173 | * AUX_IN <- aux | ||
174 | * VIDEO_IN <- ? | ||
175 | * FMIC_IN <- mic | ||
176 | * | ||
177 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
178 | * GPO 1 -> route mic-in from input jack (0) or front panel header (1) | ||
179 | */ | ||
180 | |||
135 | #include <linux/pci.h> | 181 | #include <linux/pci.h> |
136 | #include <linux/delay.h> | 182 | #include <linux/delay.h> |
137 | #include <linux/mutex.h> | 183 | #include <linux/mutex.h> |
138 | #include <sound/ac97_codec.h> | 184 | #include <sound/ac97_codec.h> |
139 | #include <sound/control.h> | 185 | #include <sound/control.h> |
140 | #include <sound/core.h> | 186 | #include <sound/core.h> |
187 | #include <sound/info.h> | ||
141 | #include <sound/pcm.h> | 188 | #include <sound/pcm.h> |
142 | #include <sound/pcm_params.h> | 189 | #include <sound/pcm_params.h> |
143 | #include <sound/tlv.h> | 190 | #include <sound/tlv.h> |
@@ -155,12 +202,14 @@ | |||
155 | #define GPIO_INPUT_ROUTE 0x0100 | 202 | #define GPIO_INPUT_ROUTE 0x0100 |
156 | 203 | ||
157 | #define GPIO_HDAV_OUTPUT_ENABLE 0x0001 | 204 | #define GPIO_HDAV_OUTPUT_ENABLE 0x0001 |
205 | #define GPIO_HDAV_MAGIC 0x00c0 | ||
158 | 206 | ||
159 | #define GPIO_DB_MASK 0x0030 | 207 | #define GPIO_DB_MASK 0x0030 |
160 | #define GPIO_DB_H6 0x0000 | 208 | #define GPIO_DB_H6 0x0000 |
161 | 209 | ||
162 | #define GPIO_ST_OUTPUT_ENABLE 0x0001 | 210 | #define GPIO_ST_OUTPUT_ENABLE 0x0001 |
163 | #define GPIO_ST_HP_REAR 0x0002 | 211 | #define GPIO_ST_HP_REAR 0x0002 |
212 | #define GPIO_ST_MAGIC 0x0040 | ||
164 | #define GPIO_ST_HP 0x0080 | 213 | #define GPIO_ST_HP 0x0080 |
165 | 214 | ||
166 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ | 215 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ |
@@ -174,11 +223,12 @@ struct xonar_pcm179x { | |||
174 | unsigned int dacs; | 223 | unsigned int dacs; |
175 | u8 pcm1796_regs[4][5]; | 224 | u8 pcm1796_regs[4][5]; |
176 | unsigned int current_rate; | 225 | unsigned int current_rate; |
177 | bool os_128; | 226 | bool h6; |
178 | bool hp_active; | 227 | bool hp_active; |
179 | s8 hp_gain_offset; | 228 | s8 hp_gain_offset; |
180 | bool has_cs2000; | 229 | bool has_cs2000; |
181 | u8 cs2000_fun_cfg_1; | 230 | u8 cs2000_regs[0x1f]; |
231 | bool broken_i2c; | ||
182 | }; | 232 | }; |
183 | 233 | ||
184 | struct xonar_hdav { | 234 | struct xonar_hdav { |
@@ -237,16 +287,14 @@ static void cs2000_write(struct oxygen *chip, u8 reg, u8 value) | |||
237 | struct xonar_pcm179x *data = chip->model_data; | 287 | struct xonar_pcm179x *data = chip->model_data; |
238 | 288 | ||
239 | oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); | 289 | oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); |
240 | if (reg == CS2000_FUN_CFG_1) | 290 | data->cs2000_regs[reg] = value; |
241 | data->cs2000_fun_cfg_1 = value; | ||
242 | } | 291 | } |
243 | 292 | ||
244 | static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value) | 293 | static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value) |
245 | { | 294 | { |
246 | struct xonar_pcm179x *data = chip->model_data; | 295 | struct xonar_pcm179x *data = chip->model_data; |
247 | 296 | ||
248 | if (reg != CS2000_FUN_CFG_1 || | 297 | if (value != data->cs2000_regs[reg]) |
249 | value != data->cs2000_fun_cfg_1) | ||
250 | cs2000_write(chip, reg, value); | 298 | cs2000_write(chip, reg, value); |
251 | } | 299 | } |
252 | 300 | ||
@@ -256,6 +304,7 @@ static void pcm1796_registers_init(struct oxygen *chip) | |||
256 | unsigned int i; | 304 | unsigned int i; |
257 | s8 gain_offset; | 305 | s8 gain_offset; |
258 | 306 | ||
307 | msleep(1); | ||
259 | gain_offset = data->hp_active ? data->hp_gain_offset : 0; | 308 | gain_offset = data->hp_active ? data->hp_gain_offset : 0; |
260 | for (i = 0; i < data->dacs; ++i) { | 309 | for (i = 0; i < data->dacs; ++i) { |
261 | /* set ATLD before ATL/ATR */ | 310 | /* set ATLD before ATL/ATR */ |
@@ -270,6 +319,7 @@ static void pcm1796_registers_init(struct oxygen *chip) | |||
270 | pcm1796_write(chip, i, 20, | 319 | pcm1796_write(chip, i, 20, |
271 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); | 320 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); |
272 | pcm1796_write(chip, i, 21, 0); | 321 | pcm1796_write(chip, i, 21, 0); |
322 | gain_offset = 0; | ||
273 | } | 323 | } |
274 | } | 324 | } |
275 | 325 | ||
@@ -278,10 +328,11 @@ static void pcm1796_init(struct oxygen *chip) | |||
278 | struct xonar_pcm179x *data = chip->model_data; | 328 | struct xonar_pcm179x *data = chip->model_data; |
279 | 329 | ||
280 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | | 330 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | |
281 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 331 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD; |
282 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = | 332 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = |
283 | PCM1796_FLT_SHARP | PCM1796_ATS_1; | 333 | PCM1796_FLT_SHARP | PCM1796_ATS_1; |
284 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; | 334 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = |
335 | data->h6 ? PCM1796_OS_64 : PCM1796_OS_128; | ||
285 | pcm1796_registers_init(chip); | 336 | pcm1796_registers_init(chip); |
286 | data->current_rate = 48000; | 337 | data->current_rate = 48000; |
287 | } | 338 | } |
@@ -327,18 +378,20 @@ static void xonar_hdav_init(struct oxygen *chip) | |||
327 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 378 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
328 | OXYGEN_2WIRE_LENGTH_8 | | 379 | OXYGEN_2WIRE_LENGTH_8 | |
329 | OXYGEN_2WIRE_INTERRUPT_MASK | | 380 | OXYGEN_2WIRE_INTERRUPT_MASK | |
330 | OXYGEN_2WIRE_SPEED_FAST); | 381 | OXYGEN_2WIRE_SPEED_STANDARD); |
331 | 382 | ||
332 | data->pcm179x.generic.anti_pop_delay = 100; | 383 | data->pcm179x.generic.anti_pop_delay = 100; |
333 | data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE; | 384 | data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE; |
334 | data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA; | 385 | data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA; |
335 | data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 386 | data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
336 | data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER; | 387 | data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER; |
337 | data->pcm179x.dacs = chip->model.private_data ? 4 : 1; | 388 | data->pcm179x.dacs = chip->model.dac_channels_mixer / 2; |
389 | data->pcm179x.h6 = chip->model.dac_channels_mixer > 2; | ||
338 | 390 | ||
339 | pcm1796_init(chip); | 391 | pcm1796_init(chip); |
340 | 392 | ||
341 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE); | 393 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
394 | GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE); | ||
342 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE); | 395 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE); |
343 | 396 | ||
344 | xonar_init_cs53x1(chip); | 397 | xonar_init_cs53x1(chip); |
@@ -355,22 +408,22 @@ static void xonar_st_init_i2c(struct oxygen *chip) | |||
355 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 408 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
356 | OXYGEN_2WIRE_LENGTH_8 | | 409 | OXYGEN_2WIRE_LENGTH_8 | |
357 | OXYGEN_2WIRE_INTERRUPT_MASK | | 410 | OXYGEN_2WIRE_INTERRUPT_MASK | |
358 | OXYGEN_2WIRE_SPEED_FAST); | 411 | OXYGEN_2WIRE_SPEED_STANDARD); |
359 | } | 412 | } |
360 | 413 | ||
361 | static void xonar_st_init_common(struct oxygen *chip) | 414 | static void xonar_st_init_common(struct oxygen *chip) |
362 | { | 415 | { |
363 | struct xonar_pcm179x *data = chip->model_data; | 416 | struct xonar_pcm179x *data = chip->model_data; |
364 | 417 | ||
365 | data->generic.anti_pop_delay = 100; | ||
366 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; | 418 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; |
367 | data->dacs = chip->model.private_data ? 4 : 1; | 419 | data->dacs = chip->model.dac_channels_mixer / 2; |
368 | data->hp_gain_offset = 2*-18; | 420 | data->hp_gain_offset = 2*-18; |
369 | 421 | ||
370 | pcm1796_init(chip); | 422 | pcm1796_init(chip); |
371 | 423 | ||
372 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | 424 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
373 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); | 425 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | |
426 | GPIO_ST_MAGIC | GPIO_ST_HP); | ||
374 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | 427 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, |
375 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); | 428 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); |
376 | 429 | ||
@@ -399,22 +452,30 @@ static void cs2000_registers_init(struct oxygen *chip) | |||
399 | cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10); | 452 | cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10); |
400 | cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00); | 453 | cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00); |
401 | cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00); | 454 | cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00); |
402 | cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); | 455 | cs2000_write(chip, CS2000_FUN_CFG_1, |
456 | data->cs2000_regs[CS2000_FUN_CFG_1]); | ||
403 | cs2000_write(chip, CS2000_FUN_CFG_2, 0); | 457 | cs2000_write(chip, CS2000_FUN_CFG_2, 0); |
404 | cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2); | 458 | cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2); |
459 | msleep(3); /* PLL lock delay */ | ||
405 | } | 460 | } |
406 | 461 | ||
407 | static void xonar_st_init(struct oxygen *chip) | 462 | static void xonar_st_init(struct oxygen *chip) |
408 | { | 463 | { |
409 | struct xonar_pcm179x *data = chip->model_data; | 464 | struct xonar_pcm179x *data = chip->model_data; |
410 | 465 | ||
466 | data->generic.anti_pop_delay = 100; | ||
467 | data->h6 = chip->model.dac_channels_mixer > 2; | ||
411 | data->has_cs2000 = 1; | 468 | data->has_cs2000 = 1; |
412 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; | 469 | data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1; |
470 | data->broken_i2c = true; | ||
413 | 471 | ||
414 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | 472 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, |
415 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S | | 473 | OXYGEN_RATE_48000 | |
416 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | 474 | OXYGEN_I2S_FORMAT_I2S | |
417 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | 475 | OXYGEN_I2S_MCLK(data->h6 ? MCLK_256 : MCLK_512) | |
476 | OXYGEN_I2S_BITS_16 | | ||
477 | OXYGEN_I2S_MASTER | | ||
478 | OXYGEN_I2S_BCLK_64); | ||
418 | 479 | ||
419 | xonar_st_init_i2c(chip); | 480 | xonar_st_init_i2c(chip); |
420 | cs2000_registers_init(chip); | 481 | cs2000_registers_init(chip); |
@@ -428,6 +489,7 @@ static void xonar_stx_init(struct oxygen *chip) | |||
428 | struct xonar_pcm179x *data = chip->model_data; | 489 | struct xonar_pcm179x *data = chip->model_data; |
429 | 490 | ||
430 | xonar_st_init_i2c(chip); | 491 | xonar_st_init_i2c(chip); |
492 | data->generic.anti_pop_delay = 800; | ||
431 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; | 493 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; |
432 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 494 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
433 | data->generic.ext_power_bit = GPI_EXT_POWER; | 495 | data->generic.ext_power_bit = GPI_EXT_POWER; |
@@ -494,44 +556,16 @@ static void xonar_st_resume(struct oxygen *chip) | |||
494 | xonar_stx_resume(chip); | 556 | xonar_stx_resume(chip); |
495 | } | 557 | } |
496 | 558 | ||
497 | static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate) | ||
498 | { | ||
499 | struct xonar_pcm179x *data = chip->model_data; | ||
500 | |||
501 | if (rate <= 32000) | ||
502 | return OXYGEN_I2S_MCLK_512; | ||
503 | else if (rate <= 48000 && data->os_128) | ||
504 | return OXYGEN_I2S_MCLK_512; | ||
505 | else if (rate <= 96000) | ||
506 | return OXYGEN_I2S_MCLK_256; | ||
507 | else | ||
508 | return OXYGEN_I2S_MCLK_128; | ||
509 | } | ||
510 | |||
511 | static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip, | ||
512 | unsigned int channel, | ||
513 | struct snd_pcm_hw_params *params) | ||
514 | { | ||
515 | if (channel == PCM_MULTICH) | ||
516 | return mclk_from_rate(chip, params_rate(params)); | ||
517 | else | ||
518 | return oxygen_default_i2s_mclk(chip, channel, params); | ||
519 | } | ||
520 | |||
521 | static void update_pcm1796_oversampling(struct oxygen *chip) | 559 | static void update_pcm1796_oversampling(struct oxygen *chip) |
522 | { | 560 | { |
523 | struct xonar_pcm179x *data = chip->model_data; | 561 | struct xonar_pcm179x *data = chip->model_data; |
524 | unsigned int i; | 562 | unsigned int i; |
525 | u8 reg; | 563 | u8 reg; |
526 | 564 | ||
527 | if (data->current_rate <= 32000) | 565 | if (data->current_rate <= 48000 && !data->h6) |
528 | reg = PCM1796_OS_128; | 566 | reg = PCM1796_OS_128; |
529 | else if (data->current_rate <= 48000 && data->os_128) | ||
530 | reg = PCM1796_OS_128; | ||
531 | else if (data->current_rate <= 96000 || data->os_128) | ||
532 | reg = PCM1796_OS_64; | ||
533 | else | 567 | else |
534 | reg = PCM1796_OS_32; | 568 | reg = PCM1796_OS_64; |
535 | for (i = 0; i < data->dacs; ++i) | 569 | for (i = 0; i < data->dacs; ++i) |
536 | pcm1796_write_cached(chip, i, 20, reg); | 570 | pcm1796_write_cached(chip, i, 20, reg); |
537 | } | 571 | } |
@@ -541,6 +575,7 @@ static void set_pcm1796_params(struct oxygen *chip, | |||
541 | { | 575 | { |
542 | struct xonar_pcm179x *data = chip->model_data; | 576 | struct xonar_pcm179x *data = chip->model_data; |
543 | 577 | ||
578 | msleep(1); | ||
544 | data->current_rate = params_rate(params); | 579 | data->current_rate = params_rate(params); |
545 | update_pcm1796_oversampling(chip); | 580 | update_pcm1796_oversampling(chip); |
546 | } | 581 | } |
@@ -557,6 +592,7 @@ static void update_pcm1796_volume(struct oxygen *chip) | |||
557 | + gain_offset); | 592 | + gain_offset); |
558 | pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1] | 593 | pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1] |
559 | + gain_offset); | 594 | + gain_offset); |
595 | gain_offset = 0; | ||
560 | } | 596 | } |
561 | } | 597 | } |
562 | 598 | ||
@@ -566,7 +602,7 @@ static void update_pcm1796_mute(struct oxygen *chip) | |||
566 | unsigned int i; | 602 | unsigned int i; |
567 | u8 value; | 603 | u8 value; |
568 | 604 | ||
569 | value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 605 | value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD; |
570 | if (chip->dac_mute) | 606 | if (chip->dac_mute) |
571 | value |= PCM1796_MUTE; | 607 | value |= PCM1796_MUTE; |
572 | for (i = 0; i < data->dacs; ++i) | 608 | for (i = 0; i < data->dacs; ++i) |
@@ -579,45 +615,35 @@ static void update_cs2000_rate(struct oxygen *chip, unsigned int rate) | |||
579 | u8 rate_mclk, reg; | 615 | u8 rate_mclk, reg; |
580 | 616 | ||
581 | switch (rate) { | 617 | switch (rate) { |
582 | /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */ | ||
583 | case 32000: | 618 | case 32000: |
584 | rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; | ||
585 | break; | ||
586 | case 44100: | ||
587 | if (data->os_128) | ||
588 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
589 | else | ||
590 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128; | ||
591 | break; | ||
592 | default: /* 48000 */ | ||
593 | if (data->os_128) | ||
594 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
595 | else | ||
596 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128; | ||
597 | break; | ||
598 | case 64000: | 619 | case 64000: |
599 | rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; | 620 | rate_mclk = OXYGEN_RATE_32000; |
600 | break; | 621 | break; |
622 | case 44100: | ||
601 | case 88200: | 623 | case 88200: |
602 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
603 | break; | ||
604 | case 96000: | ||
605 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
606 | break; | ||
607 | case 176400: | 624 | case 176400: |
608 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | 625 | rate_mclk = OXYGEN_RATE_44100; |
609 | break; | 626 | break; |
627 | default: | ||
628 | case 48000: | ||
629 | case 96000: | ||
610 | case 192000: | 630 | case 192000: |
611 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | 631 | rate_mclk = OXYGEN_RATE_48000; |
612 | break; | 632 | break; |
613 | } | 633 | } |
614 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, | 634 | |
615 | OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); | 635 | if (rate <= 96000 && (rate > 48000 || data->h6)) { |
616 | if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) | 636 | rate_mclk |= OXYGEN_I2S_MCLK(MCLK_256); |
617 | reg = CS2000_REF_CLK_DIV_1; | 637 | reg = CS2000_REF_CLK_DIV_1; |
618 | else | 638 | } else { |
639 | rate_mclk |= OXYGEN_I2S_MCLK(MCLK_512); | ||
619 | reg = CS2000_REF_CLK_DIV_2; | 640 | reg = CS2000_REF_CLK_DIV_2; |
641 | } | ||
642 | |||
643 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, | ||
644 | OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); | ||
620 | cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg); | 645 | cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg); |
646 | msleep(3); /* PLL lock delay */ | ||
621 | } | 647 | } |
622 | 648 | ||
623 | static void set_st_params(struct oxygen *chip, | 649 | static void set_st_params(struct oxygen *chip, |
@@ -652,13 +678,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, | |||
652 | "Sharp Roll-off", "Slow Roll-off" | 678 | "Sharp Roll-off", "Slow Roll-off" |
653 | }; | 679 | }; |
654 | 680 | ||
655 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 681 | return snd_ctl_enum_info(info, 1, 2, names); |
656 | info->count = 1; | ||
657 | info->value.enumerated.items = 2; | ||
658 | if (info->value.enumerated.item >= 2) | ||
659 | info->value.enumerated.item = 1; | ||
660 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
661 | return 0; | ||
662 | } | 682 | } |
663 | 683 | ||
664 | static int rolloff_get(struct snd_kcontrol *ctl, | 684 | static int rolloff_get(struct snd_kcontrol *ctl, |
@@ -706,57 +726,13 @@ static const struct snd_kcontrol_new rolloff_control = { | |||
706 | .put = rolloff_put, | 726 | .put = rolloff_put, |
707 | }; | 727 | }; |
708 | 728 | ||
709 | static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | 729 | static const struct snd_kcontrol_new hdav_hdmi_control = { |
710 | { | ||
711 | static const char *const names[2] = { "64x", "128x" }; | ||
712 | |||
713 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
714 | info->count = 1; | ||
715 | info->value.enumerated.items = 2; | ||
716 | if (info->value.enumerated.item >= 2) | ||
717 | info->value.enumerated.item = 1; | ||
718 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static int os_128_get(struct snd_kcontrol *ctl, | ||
723 | struct snd_ctl_elem_value *value) | ||
724 | { | ||
725 | struct oxygen *chip = ctl->private_data; | ||
726 | struct xonar_pcm179x *data = chip->model_data; | ||
727 | |||
728 | value->value.enumerated.item[0] = data->os_128; | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int os_128_put(struct snd_kcontrol *ctl, | ||
733 | struct snd_ctl_elem_value *value) | ||
734 | { | ||
735 | struct oxygen *chip = ctl->private_data; | ||
736 | struct xonar_pcm179x *data = chip->model_data; | ||
737 | int changed; | ||
738 | |||
739 | mutex_lock(&chip->mutex); | ||
740 | changed = value->value.enumerated.item[0] != data->os_128; | ||
741 | if (changed) { | ||
742 | data->os_128 = value->value.enumerated.item[0]; | ||
743 | if (data->has_cs2000) | ||
744 | update_cs2000_rate(chip, data->current_rate); | ||
745 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, | ||
746 | mclk_from_rate(chip, data->current_rate), | ||
747 | OXYGEN_I2S_MCLK_MASK); | ||
748 | update_pcm1796_oversampling(chip); | ||
749 | } | ||
750 | mutex_unlock(&chip->mutex); | ||
751 | return changed; | ||
752 | } | ||
753 | |||
754 | static const struct snd_kcontrol_new os_128_control = { | ||
755 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 730 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
756 | .name = "DAC Oversampling Playback Enum", | 731 | .name = "HDMI Playback Switch", |
757 | .info = os_128_info, | 732 | .info = snd_ctl_boolean_mono_info, |
758 | .get = os_128_get, | 733 | .get = xonar_gpio_bit_switch_get, |
759 | .put = os_128_put, | 734 | .put = xonar_gpio_bit_switch_put, |
735 | .private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT, | ||
760 | }; | 736 | }; |
761 | 737 | ||
762 | static int st_output_switch_info(struct snd_kcontrol *ctl, | 738 | static int st_output_switch_info(struct snd_kcontrol *ctl, |
@@ -766,13 +742,7 @@ static int st_output_switch_info(struct snd_kcontrol *ctl, | |||
766 | "Speakers", "Headphones", "FP Headphones" | 742 | "Speakers", "Headphones", "FP Headphones" |
767 | }; | 743 | }; |
768 | 744 | ||
769 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 745 | return snd_ctl_enum_info(info, 1, 3, names); |
770 | info->count = 1; | ||
771 | info->value.enumerated.items = 3; | ||
772 | if (info->value.enumerated.item >= 3) | ||
773 | info->value.enumerated.item = 2; | ||
774 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
775 | return 0; | ||
776 | } | 746 | } |
777 | 747 | ||
778 | static int st_output_switch_get(struct snd_kcontrol *ctl, | 748 | static int st_output_switch_get(struct snd_kcontrol *ctl, |
@@ -827,13 +797,7 @@ static int st_hp_volume_offset_info(struct snd_kcontrol *ctl, | |||
827 | "< 64 ohms", "64-300 ohms", "300-600 ohms" | 797 | "< 64 ohms", "64-300 ohms", "300-600 ohms" |
828 | }; | 798 | }; |
829 | 799 | ||
830 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 800 | return snd_ctl_enum_info(info, 1, 3, names); |
831 | info->count = 1; | ||
832 | info->value.enumerated.items = 3; | ||
833 | if (info->value.enumerated.item > 2) | ||
834 | info->value.enumerated.item = 2; | ||
835 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
836 | return 0; | ||
837 | } | 801 | } |
838 | 802 | ||
839 | static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, | 803 | static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, |
@@ -915,23 +879,25 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template) | |||
915 | return 0; | 879 | return 0; |
916 | } | 880 | } |
917 | 881 | ||
918 | static int xonar_st_control_filter(struct snd_kcontrol_new *template) | 882 | static int xonar_st_h6_control_filter(struct snd_kcontrol_new *template) |
919 | { | 883 | { |
920 | if (!strncmp(template->name, "CD Capture ", 11)) | 884 | if (!strncmp(template->name, "Master Playback ", 16)) |
921 | return 1; /* no CD input */ | 885 | /* no volume/mute, as I²C to the third DAC does not work */ |
886 | return 1; | ||
922 | return 0; | 887 | return 0; |
923 | } | 888 | } |
924 | 889 | ||
925 | static int add_pcm1796_controls(struct oxygen *chip) | 890 | static int add_pcm1796_controls(struct oxygen *chip) |
926 | { | 891 | { |
892 | struct xonar_pcm179x *data = chip->model_data; | ||
927 | int err; | 893 | int err; |
928 | 894 | ||
929 | err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | 895 | if (!data->broken_i2c) { |
930 | if (err < 0) | 896 | err = snd_ctl_add(chip->card, |
931 | return err; | 897 | snd_ctl_new1(&rolloff_control, chip)); |
932 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | 898 | if (err < 0) |
933 | if (err < 0) | 899 | return err; |
934 | return err; | 900 | } |
935 | return 0; | 901 | return 0; |
936 | } | 902 | } |
937 | 903 | ||
@@ -950,7 +916,15 @@ static int xonar_d2_mixer_init(struct oxygen *chip) | |||
950 | 916 | ||
951 | static int xonar_hdav_mixer_init(struct oxygen *chip) | 917 | static int xonar_hdav_mixer_init(struct oxygen *chip) |
952 | { | 918 | { |
953 | return add_pcm1796_controls(chip); | 919 | int err; |
920 | |||
921 | err = snd_ctl_add(chip->card, snd_ctl_new1(&hdav_hdmi_control, chip)); | ||
922 | if (err < 0) | ||
923 | return err; | ||
924 | err = add_pcm1796_controls(chip); | ||
925 | if (err < 0) | ||
926 | return err; | ||
927 | return 0; | ||
954 | } | 928 | } |
955 | 929 | ||
956 | static int xonar_st_mixer_init(struct oxygen *chip) | 930 | static int xonar_st_mixer_init(struct oxygen *chip) |
@@ -970,6 +944,45 @@ static int xonar_st_mixer_init(struct oxygen *chip) | |||
970 | return 0; | 944 | return 0; |
971 | } | 945 | } |
972 | 946 | ||
947 | static void dump_pcm1796_registers(struct oxygen *chip, | ||
948 | struct snd_info_buffer *buffer) | ||
949 | { | ||
950 | struct xonar_pcm179x *data = chip->model_data; | ||
951 | unsigned int dac, i; | ||
952 | |||
953 | for (dac = 0; dac < data->dacs; ++dac) { | ||
954 | snd_iprintf(buffer, "\nPCM1796 %u:", dac + 1); | ||
955 | for (i = 0; i < 5; ++i) | ||
956 | snd_iprintf(buffer, " %02x", | ||
957 | data->pcm1796_regs[dac][i]); | ||
958 | } | ||
959 | snd_iprintf(buffer, "\n"); | ||
960 | } | ||
961 | |||
962 | static void dump_cs2000_registers(struct oxygen *chip, | ||
963 | struct snd_info_buffer *buffer) | ||
964 | { | ||
965 | struct xonar_pcm179x *data = chip->model_data; | ||
966 | unsigned int i; | ||
967 | |||
968 | if (data->has_cs2000) { | ||
969 | snd_iprintf(buffer, "\nCS2000:\n00: "); | ||
970 | for (i = 1; i < 0x10; ++i) | ||
971 | snd_iprintf(buffer, " %02x", data->cs2000_regs[i]); | ||
972 | snd_iprintf(buffer, "\n10:"); | ||
973 | for (i = 0x10; i < 0x1f; ++i) | ||
974 | snd_iprintf(buffer, " %02x", data->cs2000_regs[i]); | ||
975 | snd_iprintf(buffer, "\n"); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | static void dump_st_registers(struct oxygen *chip, | ||
980 | struct snd_info_buffer *buffer) | ||
981 | { | ||
982 | dump_pcm1796_registers(chip, buffer); | ||
983 | dump_cs2000_registers(chip, buffer); | ||
984 | } | ||
985 | |||
973 | static const struct oxygen_model model_xonar_d2 = { | 986 | static const struct oxygen_model model_xonar_d2 = { |
974 | .longname = "Asus Virtuoso 200", | 987 | .longname = "Asus Virtuoso 200", |
975 | .chip = "AV200", | 988 | .chip = "AV200", |
@@ -979,11 +992,11 @@ static const struct oxygen_model model_xonar_d2 = { | |||
979 | .cleanup = xonar_d2_cleanup, | 992 | .cleanup = xonar_d2_cleanup, |
980 | .suspend = xonar_d2_suspend, | 993 | .suspend = xonar_d2_suspend, |
981 | .resume = xonar_d2_resume, | 994 | .resume = xonar_d2_resume, |
982 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
983 | .set_dac_params = set_pcm1796_params, | 995 | .set_dac_params = set_pcm1796_params, |
984 | .set_adc_params = xonar_set_cs53x1_params, | 996 | .set_adc_params = xonar_set_cs53x1_params, |
985 | .update_dac_volume = update_pcm1796_volume, | 997 | .update_dac_volume = update_pcm1796_volume, |
986 | .update_dac_mute = update_pcm1796_mute, | 998 | .update_dac_mute = update_pcm1796_mute, |
999 | .dump_registers = dump_pcm1796_registers, | ||
987 | .dac_tlv = pcm1796_db_scale, | 1000 | .dac_tlv = pcm1796_db_scale, |
988 | .model_data_size = sizeof(struct xonar_pcm179x), | 1001 | .model_data_size = sizeof(struct xonar_pcm179x), |
989 | .device_config = PLAYBACK_0_TO_I2S | | 1002 | .device_config = PLAYBACK_0_TO_I2S | |
@@ -991,14 +1004,18 @@ static const struct oxygen_model model_xonar_d2 = { | |||
991 | CAPTURE_0_FROM_I2S_2 | | 1004 | CAPTURE_0_FROM_I2S_2 | |
992 | CAPTURE_1_FROM_SPDIF | | 1005 | CAPTURE_1_FROM_SPDIF | |
993 | MIDI_OUTPUT | | 1006 | MIDI_OUTPUT | |
994 | MIDI_INPUT, | 1007 | MIDI_INPUT | |
995 | .dac_channels = 8, | 1008 | AC97_CD_INPUT, |
1009 | .dac_channels_pcm = 8, | ||
1010 | .dac_channels_mixer = 8, | ||
996 | .dac_volume_min = 255 - 2*60, | 1011 | .dac_volume_min = 255 - 2*60, |
997 | .dac_volume_max = 255, | 1012 | .dac_volume_max = 255, |
998 | .misc_flags = OXYGEN_MISC_MIDI, | 1013 | .misc_flags = OXYGEN_MISC_MIDI, |
999 | .function_flags = OXYGEN_FUNCTION_SPI | | 1014 | .function_flags = OXYGEN_FUNCTION_SPI | |
1000 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | 1015 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, |
1001 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1016 | .dac_mclks = OXYGEN_MCLKS(512, 128, 128), |
1017 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
1018 | .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, | ||
1002 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1019 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1003 | }; | 1020 | }; |
1004 | 1021 | ||
@@ -1011,25 +1028,28 @@ static const struct oxygen_model model_xonar_hdav = { | |||
1011 | .suspend = xonar_hdav_suspend, | 1028 | .suspend = xonar_hdav_suspend, |
1012 | .resume = xonar_hdav_resume, | 1029 | .resume = xonar_hdav_resume, |
1013 | .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, | 1030 | .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, |
1014 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
1015 | .set_dac_params = set_hdav_params, | 1031 | .set_dac_params = set_hdav_params, |
1016 | .set_adc_params = xonar_set_cs53x1_params, | 1032 | .set_adc_params = xonar_set_cs53x1_params, |
1017 | .update_dac_volume = update_pcm1796_volume, | 1033 | .update_dac_volume = update_pcm1796_volume, |
1018 | .update_dac_mute = update_pcm1796_mute, | 1034 | .update_dac_mute = update_pcm1796_mute, |
1019 | .uart_input = xonar_hdmi_uart_input, | 1035 | .uart_input = xonar_hdmi_uart_input, |
1020 | .ac97_switch = xonar_line_mic_ac97_switch, | 1036 | .ac97_switch = xonar_line_mic_ac97_switch, |
1037 | .dump_registers = dump_pcm1796_registers, | ||
1021 | .dac_tlv = pcm1796_db_scale, | 1038 | .dac_tlv = pcm1796_db_scale, |
1022 | .model_data_size = sizeof(struct xonar_hdav), | 1039 | .model_data_size = sizeof(struct xonar_hdav), |
1023 | .device_config = PLAYBACK_0_TO_I2S | | 1040 | .device_config = PLAYBACK_0_TO_I2S | |
1024 | PLAYBACK_1_TO_SPDIF | | 1041 | PLAYBACK_1_TO_SPDIF | |
1025 | CAPTURE_0_FROM_I2S_2 | | 1042 | CAPTURE_0_FROM_I2S_2 | |
1026 | CAPTURE_1_FROM_SPDIF, | 1043 | CAPTURE_1_FROM_SPDIF, |
1027 | .dac_channels = 8, | 1044 | .dac_channels_pcm = 8, |
1045 | .dac_channels_mixer = 2, | ||
1028 | .dac_volume_min = 255 - 2*60, | 1046 | .dac_volume_min = 255 - 2*60, |
1029 | .dac_volume_max = 255, | 1047 | .dac_volume_max = 255, |
1030 | .misc_flags = OXYGEN_MISC_MIDI, | 1048 | .misc_flags = OXYGEN_MISC_MIDI, |
1031 | .function_flags = OXYGEN_FUNCTION_2WIRE, | 1049 | .function_flags = OXYGEN_FUNCTION_2WIRE, |
1032 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1050 | .dac_mclks = OXYGEN_MCLKS(512, 128, 128), |
1051 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
1052 | .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, | ||
1033 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1053 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1034 | }; | 1054 | }; |
1035 | 1055 | ||
@@ -1037,27 +1057,30 @@ static const struct oxygen_model model_xonar_st = { | |||
1037 | .longname = "Asus Virtuoso 100", | 1057 | .longname = "Asus Virtuoso 100", |
1038 | .chip = "AV200", | 1058 | .chip = "AV200", |
1039 | .init = xonar_st_init, | 1059 | .init = xonar_st_init, |
1040 | .control_filter = xonar_st_control_filter, | ||
1041 | .mixer_init = xonar_st_mixer_init, | 1060 | .mixer_init = xonar_st_mixer_init, |
1042 | .cleanup = xonar_st_cleanup, | 1061 | .cleanup = xonar_st_cleanup, |
1043 | .suspend = xonar_st_suspend, | 1062 | .suspend = xonar_st_suspend, |
1044 | .resume = xonar_st_resume, | 1063 | .resume = xonar_st_resume, |
1045 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
1046 | .set_dac_params = set_st_params, | 1064 | .set_dac_params = set_st_params, |
1047 | .set_adc_params = xonar_set_cs53x1_params, | 1065 | .set_adc_params = xonar_set_cs53x1_params, |
1048 | .update_dac_volume = update_pcm1796_volume, | 1066 | .update_dac_volume = update_pcm1796_volume, |
1049 | .update_dac_mute = update_pcm1796_mute, | 1067 | .update_dac_mute = update_pcm1796_mute, |
1050 | .ac97_switch = xonar_line_mic_ac97_switch, | 1068 | .ac97_switch = xonar_line_mic_ac97_switch, |
1069 | .dump_registers = dump_st_registers, | ||
1051 | .dac_tlv = pcm1796_db_scale, | 1070 | .dac_tlv = pcm1796_db_scale, |
1052 | .model_data_size = sizeof(struct xonar_pcm179x), | 1071 | .model_data_size = sizeof(struct xonar_pcm179x), |
1053 | .device_config = PLAYBACK_0_TO_I2S | | 1072 | .device_config = PLAYBACK_0_TO_I2S | |
1054 | PLAYBACK_1_TO_SPDIF | | 1073 | PLAYBACK_1_TO_SPDIF | |
1055 | CAPTURE_0_FROM_I2S_2, | 1074 | CAPTURE_0_FROM_I2S_2 | |
1056 | .dac_channels = 2, | 1075 | AC97_FMIC_SWITCH, |
1076 | .dac_channels_pcm = 2, | ||
1077 | .dac_channels_mixer = 2, | ||
1057 | .dac_volume_min = 255 - 2*60, | 1078 | .dac_volume_min = 255 - 2*60, |
1058 | .dac_volume_max = 255, | 1079 | .dac_volume_max = 255, |
1059 | .function_flags = OXYGEN_FUNCTION_2WIRE, | 1080 | .function_flags = OXYGEN_FUNCTION_2WIRE, |
1060 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1081 | .dac_mclks = OXYGEN_MCLKS(512, 128, 128), |
1082 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
1083 | .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, | ||
1061 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1084 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1062 | }; | 1085 | }; |
1063 | 1086 | ||
@@ -1083,7 +1106,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | |||
1083 | break; | 1106 | break; |
1084 | case GPIO_DB_H6: | 1107 | case GPIO_DB_H6: |
1085 | chip->model.shortname = "Xonar HDAV1.3+H6"; | 1108 | chip->model.shortname = "Xonar HDAV1.3+H6"; |
1086 | chip->model.private_data = 1; | 1109 | chip->model.dac_channels_mixer = 8; |
1110 | chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); | ||
1087 | break; | 1111 | break; |
1088 | } | 1112 | } |
1089 | break; | 1113 | break; |
@@ -1096,8 +1120,10 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | |||
1096 | break; | 1120 | break; |
1097 | case GPIO_DB_H6: | 1121 | case GPIO_DB_H6: |
1098 | chip->model.shortname = "Xonar ST+H6"; | 1122 | chip->model.shortname = "Xonar ST+H6"; |
1099 | chip->model.dac_channels = 8; | 1123 | chip->model.control_filter = xonar_st_h6_control_filter; |
1100 | chip->model.private_data = 1; | 1124 | chip->model.dac_channels_pcm = 8; |
1125 | chip->model.dac_channels_mixer = 8; | ||
1126 | chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); | ||
1101 | break; | 1127 | break; |
1102 | } | 1128 | } |
1103 | break; | 1129 | break; |
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index b82c1cfa96f5..42d1ab136217 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * card driver for models with WM8776/WM8766 DACs (Xonar DS) | 2 | * card driver for models with WM8776/WM8766 DACs (Xonar DS/HDAV1.3 Slim) |
3 | * | 3 | * |
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
5 | * | 5 | * |
@@ -22,19 +22,49 @@ | |||
22 | * | 22 | * |
23 | * CMI8788: | 23 | * CMI8788: |
24 | * | 24 | * |
25 | * SPI 0 -> WM8766 (surround, center/LFE, back) | 25 | * SPI 0 -> WM8766 (surround, center/LFE, back) |
26 | * SPI 1 -> WM8776 (front, input) | 26 | * SPI 1 -> WM8776 (front, input) |
27 | * | 27 | * |
28 | * GPIO 4 <- headphone detect | 28 | * GPIO 4 <- headphone detect, 0 = plugged |
29 | * GPIO 6 -> route input jack to input 1/2 (1/0) | 29 | * GPIO 6 -> route input jack to mic-in (0) or line-in (1) |
30 | * GPIO 7 -> enable output to speakers | 30 | * GPIO 7 -> enable output to front L/R speaker channels |
31 | * GPIO 8 -> enable output to speakers | 31 | * GPIO 8 -> enable output to other speaker channels and front panel headphone |
32 | * | ||
33 | * WM8776: | ||
34 | * | ||
35 | * input 1 <- line | ||
36 | * input 2 <- mic | ||
37 | * input 3 <- front mic | ||
38 | * input 4 <- aux | ||
39 | */ | ||
40 | |||
41 | /* | ||
42 | * Xonar HDAV1.3 Slim | ||
43 | * ------------------ | ||
44 | * | ||
45 | * CMI8788: | ||
46 | * | ||
47 | * I²C <-> WM8776 (addr 0011010) | ||
48 | * | ||
49 | * GPIO 0 -> disable HDMI output | ||
50 | * GPIO 1 -> enable HP output | ||
51 | * GPIO 6 -> firmware EEPROM I²C clock | ||
52 | * GPIO 7 <-> firmware EEPROM I²C data | ||
53 | * | ||
54 | * UART <-> HDMI controller | ||
55 | * | ||
56 | * WM8776: | ||
57 | * | ||
58 | * input 1 <- mic | ||
59 | * input 2 <- aux | ||
32 | */ | 60 | */ |
33 | 61 | ||
34 | #include <linux/pci.h> | 62 | #include <linux/pci.h> |
35 | #include <linux/delay.h> | 63 | #include <linux/delay.h> |
36 | #include <sound/control.h> | 64 | #include <sound/control.h> |
37 | #include <sound/core.h> | 65 | #include <sound/core.h> |
66 | #include <sound/info.h> | ||
67 | #include <sound/jack.h> | ||
38 | #include <sound/pcm.h> | 68 | #include <sound/pcm.h> |
39 | #include <sound/pcm_params.h> | 69 | #include <sound/pcm_params.h> |
40 | #include <sound/tlv.h> | 70 | #include <sound/tlv.h> |
@@ -44,7 +74,15 @@ | |||
44 | 74 | ||
45 | #define GPIO_DS_HP_DETECT 0x0010 | 75 | #define GPIO_DS_HP_DETECT 0x0010 |
46 | #define GPIO_DS_INPUT_ROUTE 0x0040 | 76 | #define GPIO_DS_INPUT_ROUTE 0x0040 |
47 | #define GPIO_DS_OUTPUT_ENABLE 0x0180 | 77 | #define GPIO_DS_OUTPUT_FRONTLR 0x0080 |
78 | #define GPIO_DS_OUTPUT_ENABLE 0x0100 | ||
79 | |||
80 | #define GPIO_SLIM_HDMI_DISABLE 0x0001 | ||
81 | #define GPIO_SLIM_OUTPUT_ENABLE 0x0002 | ||
82 | #define GPIO_SLIM_FIRMWARE_CLK 0x0040 | ||
83 | #define GPIO_SLIM_FIRMWARE_DATA 0x0080 | ||
84 | |||
85 | #define I2C_DEVICE_WM8776 0x34 /* 001101, 0, /W=0 */ | ||
48 | 86 | ||
49 | #define LC_CONTROL_LIMITER 0x40000000 | 87 | #define LC_CONTROL_LIMITER 0x40000000 |
50 | #define LC_CONTROL_ALC 0x20000000 | 88 | #define LC_CONTROL_ALC 0x20000000 |
@@ -56,19 +94,38 @@ struct xonar_wm87x6 { | |||
56 | struct snd_kcontrol *line_adcmux_control; | 94 | struct snd_kcontrol *line_adcmux_control; |
57 | struct snd_kcontrol *mic_adcmux_control; | 95 | struct snd_kcontrol *mic_adcmux_control; |
58 | struct snd_kcontrol *lc_controls[13]; | 96 | struct snd_kcontrol *lc_controls[13]; |
97 | struct snd_jack *hp_jack; | ||
98 | struct xonar_hdmi hdmi; | ||
59 | }; | 99 | }; |
60 | 100 | ||
61 | static void wm8776_write(struct oxygen *chip, | 101 | static void wm8776_write_spi(struct oxygen *chip, |
62 | unsigned int reg, unsigned int value) | 102 | unsigned int reg, unsigned int value) |
63 | { | 103 | { |
64 | struct xonar_wm87x6 *data = chip->model_data; | ||
65 | |||
66 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | 104 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | |
67 | OXYGEN_SPI_DATA_LENGTH_2 | | 105 | OXYGEN_SPI_DATA_LENGTH_2 | |
68 | OXYGEN_SPI_CLOCK_160 | | 106 | OXYGEN_SPI_CLOCK_160 | |
69 | (1 << OXYGEN_SPI_CODEC_SHIFT) | | 107 | (1 << OXYGEN_SPI_CODEC_SHIFT) | |
70 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 108 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
71 | (reg << 9) | value); | 109 | (reg << 9) | value); |
110 | } | ||
111 | |||
112 | static void wm8776_write_i2c(struct oxygen *chip, | ||
113 | unsigned int reg, unsigned int value) | ||
114 | { | ||
115 | oxygen_write_i2c(chip, I2C_DEVICE_WM8776, | ||
116 | (reg << 1) | (value >> 8), value); | ||
117 | } | ||
118 | |||
119 | static void wm8776_write(struct oxygen *chip, | ||
120 | unsigned int reg, unsigned int value) | ||
121 | { | ||
122 | struct xonar_wm87x6 *data = chip->model_data; | ||
123 | |||
124 | if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) == | ||
125 | OXYGEN_FUNCTION_SPI) | ||
126 | wm8776_write_spi(chip, reg, value); | ||
127 | else | ||
128 | wm8776_write_i2c(chip, reg, value); | ||
72 | if (reg < ARRAY_SIZE(data->wm8776_regs)) { | 129 | if (reg < ARRAY_SIZE(data->wm8776_regs)) { |
73 | if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) | 130 | if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) |
74 | value &= ~WM8776_UPDATE; | 131 | value &= ~WM8776_UPDATE; |
@@ -97,8 +154,12 @@ static void wm8766_write(struct oxygen *chip, | |||
97 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | 154 | (0 << OXYGEN_SPI_CODEC_SHIFT) | |
98 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 155 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
99 | (reg << 9) | value); | 156 | (reg << 9) | value); |
100 | if (reg < ARRAY_SIZE(data->wm8766_regs)) | 157 | if (reg < ARRAY_SIZE(data->wm8766_regs)) { |
158 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
159 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
160 | value &= ~WM8766_UPDATE; | ||
101 | data->wm8766_regs[reg] = value; | 161 | data->wm8766_regs[reg] = value; |
162 | } | ||
102 | } | 163 | } |
103 | 164 | ||
104 | static void wm8766_write_cached(struct oxygen *chip, | 165 | static void wm8766_write_cached(struct oxygen *chip, |
@@ -107,12 +168,8 @@ static void wm8766_write_cached(struct oxygen *chip, | |||
107 | struct xonar_wm87x6 *data = chip->model_data; | 168 | struct xonar_wm87x6 *data = chip->model_data; |
108 | 169 | ||
109 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || | 170 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || |
110 | value != data->wm8766_regs[reg]) { | 171 | value != data->wm8766_regs[reg]) |
111 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
112 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
113 | value &= ~WM8766_UPDATE; | ||
114 | wm8766_write(chip, reg, value); | 172 | wm8766_write(chip, reg, value); |
115 | } | ||
116 | } | 173 | } |
117 | 174 | ||
118 | static void wm8776_registers_init(struct oxygen *chip) | 175 | static void wm8776_registers_init(struct oxygen *chip) |
@@ -141,7 +198,10 @@ static void wm8776_registers_init(struct oxygen *chip) | |||
141 | 198 | ||
142 | static void wm8766_registers_init(struct oxygen *chip) | 199 | static void wm8766_registers_init(struct oxygen *chip) |
143 | { | 200 | { |
201 | struct xonar_wm87x6 *data = chip->model_data; | ||
202 | |||
144 | wm8766_write(chip, WM8766_RESET, 0); | 203 | wm8766_write(chip, WM8766_RESET, 0); |
204 | wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]); | ||
145 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); | 205 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); |
146 | wm8766_write(chip, WM8766_DAC_CTRL2, | 206 | wm8766_write(chip, WM8766_DAC_CTRL2, |
147 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | 207 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); |
@@ -170,6 +230,40 @@ static void wm8776_init(struct oxygen *chip) | |||
170 | wm8776_registers_init(chip); | 230 | wm8776_registers_init(chip); |
171 | } | 231 | } |
172 | 232 | ||
233 | static void wm8766_init(struct oxygen *chip) | ||
234 | { | ||
235 | struct xonar_wm87x6 *data = chip->model_data; | ||
236 | |||
237 | data->wm8766_regs[WM8766_DAC_CTRL] = | ||
238 | WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; | ||
239 | wm8766_registers_init(chip); | ||
240 | } | ||
241 | |||
242 | static void xonar_ds_handle_hp_jack(struct oxygen *chip) | ||
243 | { | ||
244 | struct xonar_wm87x6 *data = chip->model_data; | ||
245 | bool hp_plugged; | ||
246 | unsigned int reg; | ||
247 | |||
248 | mutex_lock(&chip->mutex); | ||
249 | |||
250 | hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
251 | GPIO_DS_HP_DETECT); | ||
252 | |||
253 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
254 | hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR, | ||
255 | GPIO_DS_OUTPUT_FRONTLR); | ||
256 | |||
257 | reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL; | ||
258 | if (hp_plugged) | ||
259 | reg |= WM8766_MUTEALL; | ||
260 | wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); | ||
261 | |||
262 | snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0); | ||
263 | |||
264 | mutex_unlock(&chip->mutex); | ||
265 | } | ||
266 | |||
173 | static void xonar_ds_init(struct oxygen *chip) | 267 | static void xonar_ds_init(struct oxygen *chip) |
174 | { | 268 | { |
175 | struct xonar_wm87x6 *data = chip->model_data; | 269 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -178,36 +272,85 @@ static void xonar_ds_init(struct oxygen *chip) | |||
178 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; | 272 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; |
179 | 273 | ||
180 | wm8776_init(chip); | 274 | wm8776_init(chip); |
181 | wm8766_registers_init(chip); | 275 | wm8766_init(chip); |
182 | 276 | ||
183 | oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, | 277 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
184 | GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); | 278 | GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR); |
279 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
280 | GPIO_DS_HP_DETECT); | ||
185 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); | 281 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); |
186 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); | 282 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); |
187 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | 283 | chip->interrupt_mask |= OXYGEN_INT_GPIO; |
188 | 284 | ||
189 | xonar_enable_output(chip); | 285 | xonar_enable_output(chip); |
190 | 286 | ||
287 | snd_jack_new(chip->card, "Headphone", | ||
288 | SND_JACK_HEADPHONE, &data->hp_jack); | ||
289 | xonar_ds_handle_hp_jack(chip); | ||
290 | |||
191 | snd_component_add(chip->card, "WM8776"); | 291 | snd_component_add(chip->card, "WM8776"); |
192 | snd_component_add(chip->card, "WM8766"); | 292 | snd_component_add(chip->card, "WM8766"); |
193 | } | 293 | } |
194 | 294 | ||
295 | static void xonar_hdav_slim_init(struct oxygen *chip) | ||
296 | { | ||
297 | struct xonar_wm87x6 *data = chip->model_data; | ||
298 | |||
299 | data->generic.anti_pop_delay = 300; | ||
300 | data->generic.output_enable_bit = GPIO_SLIM_OUTPUT_ENABLE; | ||
301 | |||
302 | wm8776_init(chip); | ||
303 | |||
304 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
305 | GPIO_SLIM_HDMI_DISABLE | | ||
306 | GPIO_SLIM_FIRMWARE_CLK | | ||
307 | GPIO_SLIM_FIRMWARE_DATA); | ||
308 | |||
309 | xonar_hdmi_init(chip, &data->hdmi); | ||
310 | xonar_enable_output(chip); | ||
311 | |||
312 | snd_component_add(chip->card, "WM8776"); | ||
313 | } | ||
314 | |||
195 | static void xonar_ds_cleanup(struct oxygen *chip) | 315 | static void xonar_ds_cleanup(struct oxygen *chip) |
196 | { | 316 | { |
197 | xonar_disable_output(chip); | 317 | xonar_disable_output(chip); |
198 | wm8776_write(chip, WM8776_RESET, 0); | 318 | wm8776_write(chip, WM8776_RESET, 0); |
199 | } | 319 | } |
200 | 320 | ||
321 | static void xonar_hdav_slim_cleanup(struct oxygen *chip) | ||
322 | { | ||
323 | xonar_hdmi_cleanup(chip); | ||
324 | xonar_disable_output(chip); | ||
325 | wm8776_write(chip, WM8776_RESET, 0); | ||
326 | msleep(2); | ||
327 | } | ||
328 | |||
201 | static void xonar_ds_suspend(struct oxygen *chip) | 329 | static void xonar_ds_suspend(struct oxygen *chip) |
202 | { | 330 | { |
203 | xonar_ds_cleanup(chip); | 331 | xonar_ds_cleanup(chip); |
204 | } | 332 | } |
205 | 333 | ||
334 | static void xonar_hdav_slim_suspend(struct oxygen *chip) | ||
335 | { | ||
336 | xonar_hdav_slim_cleanup(chip); | ||
337 | } | ||
338 | |||
206 | static void xonar_ds_resume(struct oxygen *chip) | 339 | static void xonar_ds_resume(struct oxygen *chip) |
207 | { | 340 | { |
208 | wm8776_registers_init(chip); | 341 | wm8776_registers_init(chip); |
209 | wm8766_registers_init(chip); | 342 | wm8766_registers_init(chip); |
210 | xonar_enable_output(chip); | 343 | xonar_enable_output(chip); |
344 | xonar_ds_handle_hp_jack(chip); | ||
345 | } | ||
346 | |||
347 | static void xonar_hdav_slim_resume(struct oxygen *chip) | ||
348 | { | ||
349 | struct xonar_wm87x6 *data = chip->model_data; | ||
350 | |||
351 | wm8776_registers_init(chip); | ||
352 | xonar_hdmi_resume(chip, &data->hdmi); | ||
353 | xonar_enable_output(chip); | ||
211 | } | 354 | } |
212 | 355 | ||
213 | static void wm8776_adc_hardware_filter(unsigned int channel, | 356 | static void wm8776_adc_hardware_filter(unsigned int channel, |
@@ -224,6 +367,13 @@ static void wm8776_adc_hardware_filter(unsigned int channel, | |||
224 | } | 367 | } |
225 | } | 368 | } |
226 | 369 | ||
370 | static void xonar_hdav_slim_hardware_filter(unsigned int channel, | ||
371 | struct snd_pcm_hardware *hardware) | ||
372 | { | ||
373 | wm8776_adc_hardware_filter(channel, hardware); | ||
374 | xonar_hdmi_pcm_hardware_filter(channel, hardware); | ||
375 | } | ||
376 | |||
227 | static void set_wm87x6_dac_params(struct oxygen *chip, | 377 | static void set_wm87x6_dac_params(struct oxygen *chip, |
228 | struct snd_pcm_hw_params *params) | 378 | struct snd_pcm_hw_params *params) |
229 | { | 379 | { |
@@ -240,6 +390,14 @@ static void set_wm8776_adc_params(struct oxygen *chip, | |||
240 | wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); | 390 | wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); |
241 | } | 391 | } |
242 | 392 | ||
393 | static void set_hdav_slim_dac_params(struct oxygen *chip, | ||
394 | struct snd_pcm_hw_params *params) | ||
395 | { | ||
396 | struct xonar_wm87x6 *data = chip->model_data; | ||
397 | |||
398 | xonar_set_hdmi_params(chip, &data->hdmi, params); | ||
399 | } | ||
400 | |||
243 | static void update_wm8776_volume(struct oxygen *chip) | 401 | static void update_wm8776_volume(struct oxygen *chip) |
244 | { | 402 | { |
245 | struct xonar_wm87x6 *data = chip->model_data; | 403 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -323,12 +481,27 @@ static void update_wm87x6_mute(struct oxygen *chip) | |||
323 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | 481 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); |
324 | } | 482 | } |
325 | 483 | ||
326 | static void xonar_ds_gpio_changed(struct oxygen *chip) | 484 | static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed) |
327 | { | 485 | { |
328 | u16 bits; | 486 | struct xonar_wm87x6 *data = chip->model_data; |
487 | unsigned int reg; | ||
488 | |||
489 | /* | ||
490 | * The WM8766 can mix left and right channels, but this setting | ||
491 | * applies to all three stereo pairs. | ||
492 | */ | ||
493 | reg = data->wm8766_regs[WM8766_DAC_CTRL] & | ||
494 | ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK); | ||
495 | if (mixed) | ||
496 | reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX; | ||
497 | else | ||
498 | reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; | ||
499 | wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); | ||
500 | } | ||
329 | 501 | ||
330 | bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | 502 | static void xonar_ds_gpio_changed(struct oxygen *chip) |
331 | snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); | 503 | { |
504 | xonar_ds_handle_hp_jack(chip); | ||
332 | } | 505 | } |
333 | 506 | ||
334 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, | 507 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, |
@@ -404,11 +577,6 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, | |||
404 | const char *const *names; | 577 | const char *const *names; |
405 | 578 | ||
406 | max = (ctl->private_value >> 12) & 0xf; | 579 | max = (ctl->private_value >> 12) & 0xf; |
407 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
408 | info->count = 1; | ||
409 | info->value.enumerated.items = max + 1; | ||
410 | if (info->value.enumerated.item > max) | ||
411 | info->value.enumerated.item = max; | ||
412 | switch ((ctl->private_value >> 24) & 0x1f) { | 580 | switch ((ctl->private_value >> 24) & 0x1f) { |
413 | case WM8776_ALCCTRL2: | 581 | case WM8776_ALCCTRL2: |
414 | names = hld; | 582 | names = hld; |
@@ -432,8 +600,7 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, | |||
432 | default: | 600 | default: |
433 | return -ENXIO; | 601 | return -ENXIO; |
434 | } | 602 | } |
435 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | 603 | return snd_ctl_enum_info(info, 1, max + 1, names); |
436 | return 0; | ||
437 | } | 604 | } |
438 | 605 | ||
439 | static int wm8776_field_volume_info(struct snd_kcontrol *ctl, | 606 | static int wm8776_field_volume_info(struct snd_kcontrol *ctl, |
@@ -690,13 +857,8 @@ static int wm8776_level_control_info(struct snd_kcontrol *ctl, | |||
690 | static const char *const names[3] = { | 857 | static const char *const names[3] = { |
691 | "None", "Peak Limiter", "Automatic Level Control" | 858 | "None", "Peak Limiter", "Automatic Level Control" |
692 | }; | 859 | }; |
693 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 860 | |
694 | info->count = 1; | 861 | return snd_ctl_enum_info(info, 1, 3, names); |
695 | info->value.enumerated.items = 3; | ||
696 | if (info->value.enumerated.item >= 3) | ||
697 | info->value.enumerated.item = 2; | ||
698 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
699 | return 0; | ||
700 | } | 862 | } |
701 | 863 | ||
702 | static int wm8776_level_control_get(struct snd_kcontrol *ctl, | 864 | static int wm8776_level_control_get(struct snd_kcontrol *ctl, |
@@ -782,13 +944,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | |||
782 | "None", "High-pass Filter" | 944 | "None", "High-pass Filter" |
783 | }; | 945 | }; |
784 | 946 | ||
785 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 947 | return snd_ctl_enum_info(info, 1, 2, names); |
786 | info->count = 1; | ||
787 | info->value.enumerated.items = 2; | ||
788 | if (info->value.enumerated.item >= 2) | ||
789 | info->value.enumerated.item = 1; | ||
790 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
791 | return 0; | ||
792 | } | 948 | } |
793 | 949 | ||
794 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 950 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) |
@@ -896,7 +1052,57 @@ static const struct snd_kcontrol_new ds_controls[] = { | |||
896 | .put = wm8776_input_mux_put, | 1052 | .put = wm8776_input_mux_put, |
897 | .private_value = 1 << 1, | 1053 | .private_value = 1 << 1, |
898 | }, | 1054 | }, |
899 | WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), | 1055 | WM8776_BIT_SWITCH("Front Mic Capture Switch", |
1056 | WM8776_ADCMUX, 1 << 2, 0, 0), | ||
1057 | WM8776_BIT_SWITCH("Aux Capture Switch", | ||
1058 | WM8776_ADCMUX, 1 << 3, 0, 0), | ||
1059 | { | ||
1060 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1061 | .name = "ADC Filter Capture Enum", | ||
1062 | .info = hpf_info, | ||
1063 | .get = hpf_get, | ||
1064 | .put = hpf_put, | ||
1065 | }, | ||
1066 | { | ||
1067 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1068 | .name = "Level Control Capture Enum", | ||
1069 | .info = wm8776_level_control_info, | ||
1070 | .get = wm8776_level_control_get, | ||
1071 | .put = wm8776_level_control_put, | ||
1072 | .private_value = 0, | ||
1073 | }, | ||
1074 | }; | ||
1075 | static const struct snd_kcontrol_new hdav_slim_controls[] = { | ||
1076 | { | ||
1077 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1078 | .name = "HDMI Playback Switch", | ||
1079 | .info = snd_ctl_boolean_mono_info, | ||
1080 | .get = xonar_gpio_bit_switch_get, | ||
1081 | .put = xonar_gpio_bit_switch_put, | ||
1082 | .private_value = GPIO_SLIM_HDMI_DISABLE | XONAR_GPIO_BIT_INVERT, | ||
1083 | }, | ||
1084 | { | ||
1085 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1086 | .name = "Headphone Playback Volume", | ||
1087 | .info = wm8776_hp_vol_info, | ||
1088 | .get = wm8776_hp_vol_get, | ||
1089 | .put = wm8776_hp_vol_put, | ||
1090 | .tlv = { .p = wm8776_hp_db_scale }, | ||
1091 | }, | ||
1092 | WM8776_BIT_SWITCH("Headphone Playback Switch", | ||
1093 | WM8776_PWRDOWN, WM8776_HPPD, 1, 0), | ||
1094 | { | ||
1095 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1096 | .name = "Input Capture Volume", | ||
1097 | .info = wm8776_input_vol_info, | ||
1098 | .get = wm8776_input_vol_get, | ||
1099 | .put = wm8776_input_vol_put, | ||
1100 | .tlv = { .p = wm8776_adc_db_scale }, | ||
1101 | }, | ||
1102 | WM8776_BIT_SWITCH("Mic Capture Switch", | ||
1103 | WM8776_ADCMUX, 1 << 0, 0, 0), | ||
1104 | WM8776_BIT_SWITCH("Aux Capture Switch", | ||
1105 | WM8776_ADCMUX, 1 << 1, 0, 0), | ||
900 | { | 1106 | { |
901 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1107 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
902 | .name = "ADC Filter Capture Enum", | 1108 | .name = "ADC Filter Capture Enum", |
@@ -956,10 +1162,23 @@ static const struct snd_kcontrol_new lc_controls[] = { | |||
956 | LC_CONTROL_ALC, wm8776_ngth_db_scale), | 1162 | LC_CONTROL_ALC, wm8776_ngth_db_scale), |
957 | }; | 1163 | }; |
958 | 1164 | ||
959 | static int xonar_ds_control_filter(struct snd_kcontrol_new *template) | 1165 | static int add_lc_controls(struct oxygen *chip) |
960 | { | 1166 | { |
961 | if (!strncmp(template->name, "CD Capture ", 11)) | 1167 | struct xonar_wm87x6 *data = chip->model_data; |
962 | return 1; /* no CD input */ | 1168 | unsigned int i; |
1169 | struct snd_kcontrol *ctl; | ||
1170 | int err; | ||
1171 | |||
1172 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | ||
1173 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | ||
1174 | ctl = snd_ctl_new1(&lc_controls[i], chip); | ||
1175 | if (!ctl) | ||
1176 | return -ENOMEM; | ||
1177 | err = snd_ctl_add(chip->card, ctl); | ||
1178 | if (err < 0) | ||
1179 | return err; | ||
1180 | data->lc_controls[i] = ctl; | ||
1181 | } | ||
963 | return 0; | 1182 | return 0; |
964 | } | 1183 | } |
965 | 1184 | ||
@@ -984,45 +1203,117 @@ static int xonar_ds_mixer_init(struct oxygen *chip) | |||
984 | } | 1203 | } |
985 | if (!data->line_adcmux_control || !data->mic_adcmux_control) | 1204 | if (!data->line_adcmux_control || !data->mic_adcmux_control) |
986 | return -ENXIO; | 1205 | return -ENXIO; |
987 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | 1206 | |
988 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | 1207 | return add_lc_controls(chip); |
989 | ctl = snd_ctl_new1(&lc_controls[i], chip); | 1208 | } |
1209 | |||
1210 | static int xonar_hdav_slim_mixer_init(struct oxygen *chip) | ||
1211 | { | ||
1212 | unsigned int i; | ||
1213 | struct snd_kcontrol *ctl; | ||
1214 | int err; | ||
1215 | |||
1216 | for (i = 0; i < ARRAY_SIZE(hdav_slim_controls); ++i) { | ||
1217 | ctl = snd_ctl_new1(&hdav_slim_controls[i], chip); | ||
990 | if (!ctl) | 1218 | if (!ctl) |
991 | return -ENOMEM; | 1219 | return -ENOMEM; |
992 | err = snd_ctl_add(chip->card, ctl); | 1220 | err = snd_ctl_add(chip->card, ctl); |
993 | if (err < 0) | 1221 | if (err < 0) |
994 | return err; | 1222 | return err; |
995 | data->lc_controls[i] = ctl; | ||
996 | } | 1223 | } |
997 | return 0; | 1224 | |
1225 | return add_lc_controls(chip); | ||
1226 | } | ||
1227 | |||
1228 | static void dump_wm8776_registers(struct oxygen *chip, | ||
1229 | struct snd_info_buffer *buffer) | ||
1230 | { | ||
1231 | struct xonar_wm87x6 *data = chip->model_data; | ||
1232 | unsigned int i; | ||
1233 | |||
1234 | snd_iprintf(buffer, "\nWM8776:\n00:"); | ||
1235 | for (i = 0; i < 0x10; ++i) | ||
1236 | snd_iprintf(buffer, " %03x", data->wm8776_regs[i]); | ||
1237 | snd_iprintf(buffer, "\n10:"); | ||
1238 | for (i = 0x10; i < 0x17; ++i) | ||
1239 | snd_iprintf(buffer, " %03x", data->wm8776_regs[i]); | ||
1240 | snd_iprintf(buffer, "\n"); | ||
1241 | } | ||
1242 | |||
1243 | static void dump_wm87x6_registers(struct oxygen *chip, | ||
1244 | struct snd_info_buffer *buffer) | ||
1245 | { | ||
1246 | struct xonar_wm87x6 *data = chip->model_data; | ||
1247 | unsigned int i; | ||
1248 | |||
1249 | dump_wm8776_registers(chip, buffer); | ||
1250 | snd_iprintf(buffer, "\nWM8766:\n00:"); | ||
1251 | for (i = 0; i < 0x10; ++i) | ||
1252 | snd_iprintf(buffer, " %03x", data->wm8766_regs[i]); | ||
1253 | snd_iprintf(buffer, "\n"); | ||
998 | } | 1254 | } |
999 | 1255 | ||
1000 | static const struct oxygen_model model_xonar_ds = { | 1256 | static const struct oxygen_model model_xonar_ds = { |
1001 | .shortname = "Xonar DS", | 1257 | .shortname = "Xonar DS", |
1002 | .longname = "Asus Virtuoso 200", | 1258 | .longname = "Asus Virtuoso 66", |
1003 | .chip = "AV200", | 1259 | .chip = "AV200", |
1004 | .init = xonar_ds_init, | 1260 | .init = xonar_ds_init, |
1005 | .control_filter = xonar_ds_control_filter, | ||
1006 | .mixer_init = xonar_ds_mixer_init, | 1261 | .mixer_init = xonar_ds_mixer_init, |
1007 | .cleanup = xonar_ds_cleanup, | 1262 | .cleanup = xonar_ds_cleanup, |
1008 | .suspend = xonar_ds_suspend, | 1263 | .suspend = xonar_ds_suspend, |
1009 | .resume = xonar_ds_resume, | 1264 | .resume = xonar_ds_resume, |
1010 | .pcm_hardware_filter = wm8776_adc_hardware_filter, | 1265 | .pcm_hardware_filter = wm8776_adc_hardware_filter, |
1011 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
1012 | .set_dac_params = set_wm87x6_dac_params, | 1266 | .set_dac_params = set_wm87x6_dac_params, |
1013 | .set_adc_params = set_wm8776_adc_params, | 1267 | .set_adc_params = set_wm8776_adc_params, |
1014 | .update_dac_volume = update_wm87x6_volume, | 1268 | .update_dac_volume = update_wm87x6_volume, |
1015 | .update_dac_mute = update_wm87x6_mute, | 1269 | .update_dac_mute = update_wm87x6_mute, |
1270 | .update_center_lfe_mix = update_wm8766_center_lfe_mix, | ||
1016 | .gpio_changed = xonar_ds_gpio_changed, | 1271 | .gpio_changed = xonar_ds_gpio_changed, |
1272 | .dump_registers = dump_wm87x6_registers, | ||
1017 | .dac_tlv = wm87x6_dac_db_scale, | 1273 | .dac_tlv = wm87x6_dac_db_scale, |
1018 | .model_data_size = sizeof(struct xonar_wm87x6), | 1274 | .model_data_size = sizeof(struct xonar_wm87x6), |
1019 | .device_config = PLAYBACK_0_TO_I2S | | 1275 | .device_config = PLAYBACK_0_TO_I2S | |
1020 | PLAYBACK_1_TO_SPDIF | | 1276 | PLAYBACK_1_TO_SPDIF | |
1021 | CAPTURE_0_FROM_I2S_1, | 1277 | CAPTURE_0_FROM_I2S_1, |
1022 | .dac_channels = 8, | 1278 | .dac_channels_pcm = 8, |
1279 | .dac_channels_mixer = 8, | ||
1023 | .dac_volume_min = 255 - 2*60, | 1280 | .dac_volume_min = 255 - 2*60, |
1024 | .dac_volume_max = 255, | 1281 | .dac_volume_max = 255, |
1025 | .function_flags = OXYGEN_FUNCTION_SPI, | 1282 | .function_flags = OXYGEN_FUNCTION_SPI, |
1283 | .dac_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1284 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1285 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1286 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1287 | }; | ||
1288 | |||
1289 | static const struct oxygen_model model_xonar_hdav_slim = { | ||
1290 | .shortname = "Xonar HDAV1.3 Slim", | ||
1291 | .longname = "Asus Virtuoso 200", | ||
1292 | .chip = "AV200", | ||
1293 | .init = xonar_hdav_slim_init, | ||
1294 | .mixer_init = xonar_hdav_slim_mixer_init, | ||
1295 | .cleanup = xonar_hdav_slim_cleanup, | ||
1296 | .suspend = xonar_hdav_slim_suspend, | ||
1297 | .resume = xonar_hdav_slim_resume, | ||
1298 | .pcm_hardware_filter = xonar_hdav_slim_hardware_filter, | ||
1299 | .set_dac_params = set_hdav_slim_dac_params, | ||
1300 | .set_adc_params = set_wm8776_adc_params, | ||
1301 | .update_dac_volume = update_wm8776_volume, | ||
1302 | .update_dac_mute = update_wm8776_mute, | ||
1303 | .uart_input = xonar_hdmi_uart_input, | ||
1304 | .dump_registers = dump_wm8776_registers, | ||
1305 | .dac_tlv = wm87x6_dac_db_scale, | ||
1306 | .model_data_size = sizeof(struct xonar_wm87x6), | ||
1307 | .device_config = PLAYBACK_0_TO_I2S | | ||
1308 | PLAYBACK_1_TO_SPDIF | | ||
1309 | CAPTURE_0_FROM_I2S_1, | ||
1310 | .dac_channels_pcm = 8, | ||
1311 | .dac_channels_mixer = 2, | ||
1312 | .dac_volume_min = 255 - 2*60, | ||
1313 | .dac_volume_max = 255, | ||
1314 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
1315 | .dac_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1316 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1026 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1317 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1027 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1318 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1028 | }; | 1319 | }; |
@@ -1034,6 +1325,9 @@ int __devinit get_xonar_wm87x6_model(struct oxygen *chip, | |||
1034 | case 0x838e: | 1325 | case 0x838e: |
1035 | chip->model = model_xonar_ds; | 1326 | chip->model = model_xonar_ds; |
1036 | break; | 1327 | break; |
1328 | case 0x835e: | ||
1329 | chip->model = model_xonar_hdav_slim; | ||
1330 | break; | ||
1037 | default: | 1331 | default: |
1038 | return -EINVAL; | 1332 | return -EINVAL; |
1039 | } | 1333 | } |