aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/oxygen
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2011-01-10 10:23:57 -0500
committerTakashi Iwai <tiwai@suse.de>2011-01-10 10:46:49 -0500
commitb532d6b8d3aa163e1dc143bc729e9ee92f75baf5 (patch)
treeec0676e5a327ca94a1edffca60ca53675ba45f04 /sound/pci/oxygen
parent66410bfdf14f7c2ad3b2d4a8adeab41d368b6f05 (diff)
ALSA: virtuoso: add Xonar HDAV1.3 Slim support
Add experimental support for the Asus Xonar HDAV1.3 Slim sound card. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r--sound/pci/oxygen/xonar_hdmi.c2
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c3
-rw-r--r--sound/pci/oxygen/xonar_wm87x6.c213
3 files changed, 204 insertions, 14 deletions
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_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index 003c4800400b..bf4fd4bb1359 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -1152,9 +1152,6 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
1152 chip->model.resume = xonar_stx_resume; 1152 chip->model.resume = xonar_stx_resume;
1153 chip->model.set_dac_params = set_pcm1796_params; 1153 chip->model.set_dac_params = set_pcm1796_params;
1154 break; 1154 break;
1155 case 0x835e:
1156 snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
1157 return -ENODEV;
1158 default: 1155 default:
1159 return -EINVAL; 1156 return -EINVAL;
1160 } 1157 }
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index 4f9657084603..ad48356c54e4 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 *
@@ -77,6 +77,13 @@
77#define GPIO_DS_OUTPUT_FRONTLR 0x0080 77#define GPIO_DS_OUTPUT_FRONTLR 0x0080
78#define GPIO_DS_OUTPUT_ENABLE 0x0100 78#define GPIO_DS_OUTPUT_ENABLE 0x0100
79 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 */
86
80#define LC_CONTROL_LIMITER 0x40000000 87#define LC_CONTROL_LIMITER 0x40000000
81#define LC_CONTROL_ALC 0x20000000 88#define LC_CONTROL_ALC 0x20000000
82 89
@@ -88,19 +95,37 @@ struct xonar_wm87x6 {
88 struct snd_kcontrol *mic_adcmux_control; 95 struct snd_kcontrol *mic_adcmux_control;
89 struct snd_kcontrol *lc_controls[13]; 96 struct snd_kcontrol *lc_controls[13];
90 struct snd_jack *hp_jack; 97 struct snd_jack *hp_jack;
98 struct xonar_hdmi hdmi;
91}; 99};
92 100
93static void wm8776_write(struct oxygen *chip, 101static void wm8776_write_spi(struct oxygen *chip,
94 unsigned int reg, unsigned int value) 102 unsigned int reg, unsigned int value)
95{ 103{
96 struct xonar_wm87x6 *data = chip->model_data;
97
98 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 104 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
99 OXYGEN_SPI_DATA_LENGTH_2 | 105 OXYGEN_SPI_DATA_LENGTH_2 |
100 OXYGEN_SPI_CLOCK_160 | 106 OXYGEN_SPI_CLOCK_160 |
101 (1 << OXYGEN_SPI_CODEC_SHIFT) | 107 (1 << OXYGEN_SPI_CODEC_SHIFT) |
102 OXYGEN_SPI_CEN_LATCH_CLOCK_LO, 108 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
103 (reg << 9) | value); 109 (reg << 9) | value);
110}
111
112static 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
119static 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);
104 if (reg < ARRAY_SIZE(data->wm8776_regs)) { 129 if (reg < ARRAY_SIZE(data->wm8776_regs)) {
105 if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) 130 if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER)
106 value &= ~WM8776_UPDATE; 131 value &= ~WM8776_UPDATE;
@@ -267,17 +292,50 @@ static void xonar_ds_init(struct oxygen *chip)
267 snd_component_add(chip->card, "WM8766"); 292 snd_component_add(chip->card, "WM8766");
268} 293}
269 294
295static 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
270static void xonar_ds_cleanup(struct oxygen *chip) 315static void xonar_ds_cleanup(struct oxygen *chip)
271{ 316{
272 xonar_disable_output(chip); 317 xonar_disable_output(chip);
273 wm8776_write(chip, WM8776_RESET, 0); 318 wm8776_write(chip, WM8776_RESET, 0);
274} 319}
275 320
321static 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
276static void xonar_ds_suspend(struct oxygen *chip) 329static void xonar_ds_suspend(struct oxygen *chip)
277{ 330{
278 xonar_ds_cleanup(chip); 331 xonar_ds_cleanup(chip);
279} 332}
280 333
334static void xonar_hdav_slim_suspend(struct oxygen *chip)
335{
336 xonar_hdav_slim_cleanup(chip);
337}
338
281static void xonar_ds_resume(struct oxygen *chip) 339static void xonar_ds_resume(struct oxygen *chip)
282{ 340{
283 wm8776_registers_init(chip); 341 wm8776_registers_init(chip);
@@ -286,6 +344,15 @@ static void xonar_ds_resume(struct oxygen *chip)
286 xonar_ds_handle_hp_jack(chip); 344 xonar_ds_handle_hp_jack(chip);
287} 345}
288 346
347static 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);
354}
355
289static void wm8776_adc_hardware_filter(unsigned int channel, 356static void wm8776_adc_hardware_filter(unsigned int channel,
290 struct snd_pcm_hardware *hardware) 357 struct snd_pcm_hardware *hardware)
291{ 358{
@@ -300,6 +367,13 @@ static void wm8776_adc_hardware_filter(unsigned int channel,
300 } 367 }
301} 368}
302 369
370static 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
303static void set_wm87x6_dac_params(struct oxygen *chip, 377static void set_wm87x6_dac_params(struct oxygen *chip,
304 struct snd_pcm_hw_params *params) 378 struct snd_pcm_hw_params *params)
305{ 379{
@@ -316,6 +390,14 @@ static void set_wm8776_adc_params(struct oxygen *chip,
316 wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); 390 wm8776_write_cached(chip, WM8776_MSTRCTRL, reg);
317} 391}
318 392
393static 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
319static void update_wm8776_volume(struct oxygen *chip) 401static void update_wm8776_volume(struct oxygen *chip)
320{ 402{
321 struct xonar_wm87x6 *data = chip->model_data; 403 struct xonar_wm87x6 *data = chip->model_data;
@@ -1007,6 +1089,53 @@ static const struct snd_kcontrol_new ds_controls[] = {
1007 .private_value = 0, 1089 .private_value = 0,
1008 }, 1090 },
1009}; 1091};
1092static const struct snd_kcontrol_new hdav_slim_controls[] = {
1093 {
1094 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1095 .name = "HDMI Playback Switch",
1096 .info = snd_ctl_boolean_mono_info,
1097 .get = xonar_gpio_bit_switch_get,
1098 .put = xonar_gpio_bit_switch_put,
1099 .private_value = GPIO_SLIM_HDMI_DISABLE | XONAR_GPIO_BIT_INVERT,
1100 },
1101 {
1102 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1103 .name = "Headphone Playback Volume",
1104 .info = wm8776_hp_vol_info,
1105 .get = wm8776_hp_vol_get,
1106 .put = wm8776_hp_vol_put,
1107 .tlv = { .p = wm8776_hp_db_scale },
1108 },
1109 WM8776_BIT_SWITCH("Headphone Playback Switch",
1110 WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
1111 {
1112 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1113 .name = "Input Capture Volume",
1114 .info = wm8776_input_vol_info,
1115 .get = wm8776_input_vol_get,
1116 .put = wm8776_input_vol_put,
1117 .tlv = { .p = wm8776_adc_db_scale },
1118 },
1119 WM8776_BIT_SWITCH("Mic Capture Switch",
1120 WM8776_ADCMUX, 1 << 0, 0, 0),
1121 WM8776_BIT_SWITCH("Aux Capture Switch",
1122 WM8776_ADCMUX, 1 << 1, 0, 0),
1123 {
1124 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1125 .name = "ADC Filter Capture Enum",
1126 .info = hpf_info,
1127 .get = hpf_get,
1128 .put = hpf_put,
1129 },
1130 {
1131 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1132 .name = "Level Control Capture Enum",
1133 .info = wm8776_level_control_info,
1134 .get = wm8776_level_control_get,
1135 .put = wm8776_level_control_put,
1136 .private_value = 0,
1137 },
1138};
1010static const struct snd_kcontrol_new lc_controls[] = { 1139static const struct snd_kcontrol_new lc_controls[] = {
1011 WM8776_FIELD_CTL_VOLUME("Limiter Threshold", 1140 WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
1012 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, 1141 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
@@ -1050,6 +1179,26 @@ static const struct snd_kcontrol_new lc_controls[] = {
1050 LC_CONTROL_ALC, wm8776_ngth_db_scale), 1179 LC_CONTROL_ALC, wm8776_ngth_db_scale),
1051}; 1180};
1052 1181
1182static int add_lc_controls(struct oxygen *chip)
1183{
1184 struct xonar_wm87x6 *data = chip->model_data;
1185 unsigned int i;
1186 struct snd_kcontrol *ctl;
1187 int err;
1188
1189 BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
1190 for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
1191 ctl = snd_ctl_new1(&lc_controls[i], chip);
1192 if (!ctl)
1193 return -ENOMEM;
1194 err = snd_ctl_add(chip->card, ctl);
1195 if (err < 0)
1196 return err;
1197 data->lc_controls[i] = ctl;
1198 }
1199 return 0;
1200}
1201
1053static int xonar_ds_mixer_init(struct oxygen *chip) 1202static int xonar_ds_mixer_init(struct oxygen *chip)
1054{ 1203{
1055 struct xonar_wm87x6 *data = chip->model_data; 1204 struct xonar_wm87x6 *data = chip->model_data;
@@ -1071,17 +1220,26 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
1071 } 1220 }
1072 if (!data->line_adcmux_control || !data->mic_adcmux_control) 1221 if (!data->line_adcmux_control || !data->mic_adcmux_control)
1073 return -ENXIO; 1222 return -ENXIO;
1074 BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); 1223
1075 for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { 1224 return add_lc_controls(chip);
1076 ctl = snd_ctl_new1(&lc_controls[i], chip); 1225}
1226
1227static int xonar_hdav_slim_mixer_init(struct oxygen *chip)
1228{
1229 unsigned int i;
1230 struct snd_kcontrol *ctl;
1231 int err;
1232
1233 for (i = 0; i < ARRAY_SIZE(hdav_slim_controls); ++i) {
1234 ctl = snd_ctl_new1(&hdav_slim_controls[i], chip);
1077 if (!ctl) 1235 if (!ctl)
1078 return -ENOMEM; 1236 return -ENOMEM;
1079 err = snd_ctl_add(chip->card, ctl); 1237 err = snd_ctl_add(chip->card, ctl);
1080 if (err < 0) 1238 if (err < 0)
1081 return err; 1239 return err;
1082 data->lc_controls[i] = ctl;
1083 } 1240 }
1084 return 0; 1241
1242 return add_lc_controls(chip);
1085} 1243}
1086 1244
1087static void dump_wm8776_registers(struct oxygen *chip, 1245static void dump_wm8776_registers(struct oxygen *chip,
@@ -1145,6 +1303,38 @@ static const struct oxygen_model model_xonar_ds = {
1145 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 1303 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1146}; 1304};
1147 1305
1306static const struct oxygen_model model_xonar_hdav_slim = {
1307 .shortname = "Xonar HDAV1.3 Slim",
1308 .longname = "Asus Virtuoso 200",
1309 .chip = "AV200",
1310 .init = xonar_hdav_slim_init,
1311 .mixer_init = xonar_hdav_slim_mixer_init,
1312 .cleanup = xonar_hdav_slim_cleanup,
1313 .suspend = xonar_hdav_slim_suspend,
1314 .resume = xonar_hdav_slim_resume,
1315 .pcm_hardware_filter = xonar_hdav_slim_hardware_filter,
1316 .set_dac_params = set_hdav_slim_dac_params,
1317 .set_adc_params = set_wm8776_adc_params,
1318 .update_dac_volume = update_wm8776_volume,
1319 .update_dac_mute = update_wm8776_mute,
1320 .uart_input = xonar_hdmi_uart_input,
1321 .dump_registers = dump_wm8776_registers,
1322 .dac_tlv = wm87x6_dac_db_scale,
1323 .model_data_size = sizeof(struct xonar_wm87x6),
1324 .device_config = PLAYBACK_0_TO_I2S |
1325 PLAYBACK_1_TO_SPDIF |
1326 CAPTURE_0_FROM_I2S_1,
1327 .dac_channels_pcm = 8,
1328 .dac_channels_mixer = 2,
1329 .dac_volume_min = 255 - 2*60,
1330 .dac_volume_max = 255,
1331 .function_flags = OXYGEN_FUNCTION_2WIRE,
1332 .dac_mclks = OXYGEN_MCLKS(256, 256, 128),
1333 .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
1334 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1335 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1336};
1337
1148int __devinit get_xonar_wm87x6_model(struct oxygen *chip, 1338int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
1149 const struct pci_device_id *id) 1339 const struct pci_device_id *id)
1150{ 1340{
@@ -1152,6 +1342,9 @@ int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
1152 case 0x838e: 1342 case 0x838e:
1153 chip->model = model_xonar_ds; 1343 chip->model = model_xonar_ds;
1154 break; 1344 break;
1345 case 0x835e:
1346 chip->model = model_xonar_hdav_slim;
1347 break;
1155 default: 1348 default:
1156 return -EINVAL; 1349 return -EINVAL;
1157 } 1350 }