aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/oxygen/xonar_wm87x6.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/oxygen/xonar_wm87x6.c')
-rw-r--r--sound/pci/oxygen/xonar_wm87x6.c121
1 files changed, 93 insertions, 28 deletions
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index b82c1cfa96f5..200f7601276f 100644
--- a/sound/pci/oxygen/xonar_wm87x6.c
+++ b/sound/pci/oxygen/xonar_wm87x6.c
@@ -25,16 +25,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 * WM8766:
34 *
35 * input 1 <- line
36 * input 2 <- mic
37 * input 3 <- front mic
38 * input 4 <- aux
32 */ 39 */
33 40
34#include <linux/pci.h> 41#include <linux/pci.h>
35#include <linux/delay.h> 42#include <linux/delay.h>
36#include <sound/control.h> 43#include <sound/control.h>
37#include <sound/core.h> 44#include <sound/core.h>
45#include <sound/jack.h>
38#include <sound/pcm.h> 46#include <sound/pcm.h>
39#include <sound/pcm_params.h> 47#include <sound/pcm_params.h>
40#include <sound/tlv.h> 48#include <sound/tlv.h>
@@ -44,7 +52,8 @@
44 52
45#define GPIO_DS_HP_DETECT 0x0010 53#define GPIO_DS_HP_DETECT 0x0010
46#define GPIO_DS_INPUT_ROUTE 0x0040 54#define GPIO_DS_INPUT_ROUTE 0x0040
47#define GPIO_DS_OUTPUT_ENABLE 0x0180 55#define GPIO_DS_OUTPUT_FRONTLR 0x0080
56#define GPIO_DS_OUTPUT_ENABLE 0x0100
48 57
49#define LC_CONTROL_LIMITER 0x40000000 58#define LC_CONTROL_LIMITER 0x40000000
50#define LC_CONTROL_ALC 0x20000000 59#define LC_CONTROL_ALC 0x20000000
@@ -56,6 +65,7 @@ struct xonar_wm87x6 {
56 struct snd_kcontrol *line_adcmux_control; 65 struct snd_kcontrol *line_adcmux_control;
57 struct snd_kcontrol *mic_adcmux_control; 66 struct snd_kcontrol *mic_adcmux_control;
58 struct snd_kcontrol *lc_controls[13]; 67 struct snd_kcontrol *lc_controls[13];
68 struct snd_jack *hp_jack;
59}; 69};
60 70
61static void wm8776_write(struct oxygen *chip, 71static void wm8776_write(struct oxygen *chip,
@@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip,
97 (0 << OXYGEN_SPI_CODEC_SHIFT) | 107 (0 << OXYGEN_SPI_CODEC_SHIFT) |
98 OXYGEN_SPI_CEN_LATCH_CLOCK_LO, 108 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
99 (reg << 9) | value); 109 (reg << 9) | value);
100 if (reg < ARRAY_SIZE(data->wm8766_regs)) 110 if (reg < ARRAY_SIZE(data->wm8766_regs)) {
111 if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
112 (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
113 value &= ~WM8766_UPDATE;
101 data->wm8766_regs[reg] = value; 114 data->wm8766_regs[reg] = value;
115 }
102} 116}
103 117
104static void wm8766_write_cached(struct oxygen *chip, 118static void wm8766_write_cached(struct oxygen *chip,
@@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip,
107 struct xonar_wm87x6 *data = chip->model_data; 121 struct xonar_wm87x6 *data = chip->model_data;
108 122
109 if (reg >= ARRAY_SIZE(data->wm8766_regs) || 123 if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
110 value != data->wm8766_regs[reg]) { 124 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); 125 wm8766_write(chip, reg, value);
115 }
116} 126}
117 127
118static void wm8776_registers_init(struct oxygen *chip) 128static void wm8776_registers_init(struct oxygen *chip)
@@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip)
141 151
142static void wm8766_registers_init(struct oxygen *chip) 152static void wm8766_registers_init(struct oxygen *chip)
143{ 153{
154 struct xonar_wm87x6 *data = chip->model_data;
155
144 wm8766_write(chip, WM8766_RESET, 0); 156 wm8766_write(chip, WM8766_RESET, 0);
157 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); 158 wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
146 wm8766_write(chip, WM8766_DAC_CTRL2, 159 wm8766_write(chip, WM8766_DAC_CTRL2,
147 WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); 160 WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
@@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip)
170 wm8776_registers_init(chip); 183 wm8776_registers_init(chip);
171} 184}
172 185
186static void wm8766_init(struct oxygen *chip)
187{
188 struct xonar_wm87x6 *data = chip->model_data;
189
190 data->wm8766_regs[WM8766_DAC_CTRL] =
191 WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
192 wm8766_registers_init(chip);
193}
194
195static void xonar_ds_handle_hp_jack(struct oxygen *chip)
196{
197 struct xonar_wm87x6 *data = chip->model_data;
198 bool hp_plugged;
199 unsigned int reg;
200
201 mutex_lock(&chip->mutex);
202
203 hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
204 GPIO_DS_HP_DETECT);
205
206 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
207 hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
208 GPIO_DS_OUTPUT_FRONTLR);
209
210 reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
211 if (hp_plugged)
212 reg |= WM8766_MUTEALL;
213 wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
214
215 snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
216
217 mutex_unlock(&chip->mutex);
218}
219
173static void xonar_ds_init(struct oxygen *chip) 220static void xonar_ds_init(struct oxygen *chip)
174{ 221{
175 struct xonar_wm87x6 *data = chip->model_data; 222 struct xonar_wm87x6 *data = chip->model_data;
@@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip)
178 data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; 225 data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
179 226
180 wm8776_init(chip); 227 wm8776_init(chip);
181 wm8766_registers_init(chip); 228 wm8766_init(chip);
182 229
183 oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, 230 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
184 GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); 231 GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
232 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
233 GPIO_DS_HP_DETECT);
185 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); 234 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
186 oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); 235 oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
187 chip->interrupt_mask |= OXYGEN_INT_GPIO; 236 chip->interrupt_mask |= OXYGEN_INT_GPIO;
188 237
189 xonar_enable_output(chip); 238 xonar_enable_output(chip);
190 239
240 snd_jack_new(chip->card, "Headphone",
241 SND_JACK_HEADPHONE, &data->hp_jack);
242 xonar_ds_handle_hp_jack(chip);
243
191 snd_component_add(chip->card, "WM8776"); 244 snd_component_add(chip->card, "WM8776");
192 snd_component_add(chip->card, "WM8766"); 245 snd_component_add(chip->card, "WM8766");
193} 246}
@@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip)
208 wm8776_registers_init(chip); 261 wm8776_registers_init(chip);
209 wm8766_registers_init(chip); 262 wm8766_registers_init(chip);
210 xonar_enable_output(chip); 263 xonar_enable_output(chip);
264 xonar_ds_handle_hp_jack(chip);
211} 265}
212 266
213static void wm8776_adc_hardware_filter(unsigned int channel, 267static void wm8776_adc_hardware_filter(unsigned int channel,
@@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip)
323 (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); 377 (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
324} 378}
325 379
326static void xonar_ds_gpio_changed(struct oxygen *chip) 380static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
327{ 381{
328 u16 bits; 382 struct xonar_wm87x6 *data = chip->model_data;
383 unsigned int reg;
329 384
330 bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); 385 /*
331 snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); 386 * The WM8766 can mix left and right channels, but this setting
387 * applies to all three stereo pairs.
388 */
389 reg = data->wm8766_regs[WM8766_DAC_CTRL] &
390 ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
391 if (mixed)
392 reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
393 else
394 reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
395 wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
396}
397
398static void xonar_ds_gpio_changed(struct oxygen *chip)
399{
400 xonar_ds_handle_hp_jack(chip);
332} 401}
333 402
334static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, 403static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
@@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = {
896 .put = wm8776_input_mux_put, 965 .put = wm8776_input_mux_put,
897 .private_value = 1 << 1, 966 .private_value = 1 << 1,
898 }, 967 },
899 WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), 968 WM8776_BIT_SWITCH("Front Mic Capture Switch",
969 WM8776_ADCMUX, 1 << 2, 0, 0),
970 WM8776_BIT_SWITCH("Aux Capture Switch",
971 WM8776_ADCMUX, 1 << 3, 0, 0),
900 { 972 {
901 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 973 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
902 .name = "ADC Filter Capture Enum", 974 .name = "ADC Filter Capture Enum",
@@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = {
956 LC_CONTROL_ALC, wm8776_ngth_db_scale), 1028 LC_CONTROL_ALC, wm8776_ngth_db_scale),
957}; 1029};
958 1030
959static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
960{
961 if (!strncmp(template->name, "CD Capture ", 11))
962 return 1; /* no CD input */
963 return 0;
964}
965
966static int xonar_ds_mixer_init(struct oxygen *chip) 1031static int xonar_ds_mixer_init(struct oxygen *chip)
967{ 1032{
968 struct xonar_wm87x6 *data = chip->model_data; 1033 struct xonar_wm87x6 *data = chip->model_data;
@@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
999 1064
1000static const struct oxygen_model model_xonar_ds = { 1065static const struct oxygen_model model_xonar_ds = {
1001 .shortname = "Xonar DS", 1066 .shortname = "Xonar DS",
1002 .longname = "Asus Virtuoso 200", 1067 .longname = "Asus Virtuoso 66",
1003 .chip = "AV200", 1068 .chip = "AV200",
1004 .init = xonar_ds_init, 1069 .init = xonar_ds_init,
1005 .control_filter = xonar_ds_control_filter,
1006 .mixer_init = xonar_ds_mixer_init, 1070 .mixer_init = xonar_ds_mixer_init,
1007 .cleanup = xonar_ds_cleanup, 1071 .cleanup = xonar_ds_cleanup,
1008 .suspend = xonar_ds_suspend, 1072 .suspend = xonar_ds_suspend,
@@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = {
1013 .set_adc_params = set_wm8776_adc_params, 1077 .set_adc_params = set_wm8776_adc_params,
1014 .update_dac_volume = update_wm87x6_volume, 1078 .update_dac_volume = update_wm87x6_volume,
1015 .update_dac_mute = update_wm87x6_mute, 1079 .update_dac_mute = update_wm87x6_mute,
1080 .update_center_lfe_mix = update_wm8766_center_lfe_mix,
1016 .gpio_changed = xonar_ds_gpio_changed, 1081 .gpio_changed = xonar_ds_gpio_changed,
1017 .dac_tlv = wm87x6_dac_db_scale, 1082 .dac_tlv = wm87x6_dac_db_scale,
1018 .model_data_size = sizeof(struct xonar_wm87x6), 1083 .model_data_size = sizeof(struct xonar_wm87x6),