2 * Mixer controls for the Xonar DG/DGX
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * Copyright (c) Roman Volkov <v1ron@mail.ru>
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.
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.
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/>.
19 #include <linux/pci.h>
20 #include <linux/delay.h>
21 #include <sound/control.h>
22 #include <sound/core.h>
23 #include <sound/info.h>
24 #include <sound/pcm.h>
25 #include <sound/tlv.h>
30 static int output_switch_info(struct snd_kcontrol
*ctl
,
31 struct snd_ctl_elem_info
*info
)
33 static const char *const names
[3] = {
34 "Speakers", "Headphones", "FP Headphones"
37 return snd_ctl_enum_info(info
, 1, 3, names
);
40 static int output_switch_get(struct snd_kcontrol
*ctl
,
41 struct snd_ctl_elem_value
*value
)
43 struct oxygen
*chip
= ctl
->private_data
;
44 struct dg
*data
= chip
->model_data
;
46 mutex_lock(&chip
->mutex
);
47 value
->value
.enumerated
.item
[0] = data
->output_sel
;
48 mutex_unlock(&chip
->mutex
);
52 static int output_switch_put(struct snd_kcontrol
*ctl
,
53 struct snd_ctl_elem_value
*value
)
55 struct oxygen
*chip
= ctl
->private_data
;
56 struct dg
*data
= chip
->model_data
;
60 if (value
->value
.enumerated
.item
[0] > 2)
63 mutex_lock(&chip
->mutex
);
64 changed
= value
->value
.enumerated
.item
[0] != data
->output_sel
;
66 data
->output_sel
= value
->value
.enumerated
.item
[0];
68 reg
= data
->cs4245_shadow
[CS4245_SIGNAL_SEL
] &
69 ~CS4245_A_OUT_SEL_MASK
;
70 reg
|= data
->output_sel
== 2 ?
71 CS4245_A_OUT_SEL_DAC
: CS4245_A_OUT_SEL_HIZ
;
72 cs4245_write_cached(chip
, CS4245_SIGNAL_SEL
, reg
);
74 cs4245_write_cached(chip
, CS4245_DAC_A_CTRL
,
75 data
->output_sel
? data
->hp_vol_att
: 0);
76 cs4245_write_cached(chip
, CS4245_DAC_B_CTRL
,
77 data
->output_sel
? data
->hp_vol_att
: 0);
79 oxygen_write16_masked(chip
, OXYGEN_GPIO_DATA
,
80 data
->output_sel
== 1 ? GPIO_HP_REAR
: 0,
83 mutex_unlock(&chip
->mutex
);
87 static int hp_volume_offset_info(struct snd_kcontrol
*ctl
,
88 struct snd_ctl_elem_info
*info
)
90 static const char *const names
[3] = {
91 "< 64 ohms", "64-150 ohms", "150-300 ohms"
94 return snd_ctl_enum_info(info
, 1, 3, names
);
97 static int hp_volume_offset_get(struct snd_kcontrol
*ctl
,
98 struct snd_ctl_elem_value
*value
)
100 struct oxygen
*chip
= ctl
->private_data
;
101 struct dg
*data
= chip
->model_data
;
103 mutex_lock(&chip
->mutex
);
104 if (data
->hp_vol_att
> 2 * 7)
105 value
->value
.enumerated
.item
[0] = 0;
106 else if (data
->hp_vol_att
> 0)
107 value
->value
.enumerated
.item
[0] = 1;
109 value
->value
.enumerated
.item
[0] = 2;
110 mutex_unlock(&chip
->mutex
);
114 static int hp_volume_offset_put(struct snd_kcontrol
*ctl
,
115 struct snd_ctl_elem_value
*value
)
117 static const s8 atts
[3] = { 2 * 16, 2 * 7, 0 };
118 struct oxygen
*chip
= ctl
->private_data
;
119 struct dg
*data
= chip
->model_data
;
123 if (value
->value
.enumerated
.item
[0] > 2)
125 att
= atts
[value
->value
.enumerated
.item
[0]];
126 mutex_lock(&chip
->mutex
);
127 changed
= att
!= data
->hp_vol_att
;
129 data
->hp_vol_att
= att
;
130 if (data
->output_sel
) {
131 cs4245_write_cached(chip
, CS4245_DAC_A_CTRL
, att
);
132 cs4245_write_cached(chip
, CS4245_DAC_B_CTRL
, att
);
135 mutex_unlock(&chip
->mutex
);
139 static int input_vol_info(struct snd_kcontrol
*ctl
,
140 struct snd_ctl_elem_info
*info
)
142 info
->type
= SNDRV_CTL_ELEM_TYPE_INTEGER
;
144 info
->value
.integer
.min
= 2 * -12;
145 info
->value
.integer
.max
= 2 * 12;
149 static int input_vol_get(struct snd_kcontrol
*ctl
,
150 struct snd_ctl_elem_value
*value
)
152 struct oxygen
*chip
= ctl
->private_data
;
153 struct dg
*data
= chip
->model_data
;
154 unsigned int idx
= ctl
->private_value
;
156 mutex_lock(&chip
->mutex
);
157 value
->value
.integer
.value
[0] = data
->input_vol
[idx
][0];
158 value
->value
.integer
.value
[1] = data
->input_vol
[idx
][1];
159 mutex_unlock(&chip
->mutex
);
163 static int input_vol_put(struct snd_kcontrol
*ctl
,
164 struct snd_ctl_elem_value
*value
)
166 struct oxygen
*chip
= ctl
->private_data
;
167 struct dg
*data
= chip
->model_data
;
168 unsigned int idx
= ctl
->private_value
;
171 if (value
->value
.integer
.value
[0] < 2 * -12 ||
172 value
->value
.integer
.value
[0] > 2 * 12 ||
173 value
->value
.integer
.value
[1] < 2 * -12 ||
174 value
->value
.integer
.value
[1] > 2 * 12)
176 mutex_lock(&chip
->mutex
);
177 changed
= data
->input_vol
[idx
][0] != value
->value
.integer
.value
[0] ||
178 data
->input_vol
[idx
][1] != value
->value
.integer
.value
[1];
180 data
->input_vol
[idx
][0] = value
->value
.integer
.value
[0];
181 data
->input_vol
[idx
][1] = value
->value
.integer
.value
[1];
182 if (idx
== data
->input_sel
) {
183 cs4245_write_cached(chip
, CS4245_PGA_A_CTRL
,
184 data
->input_vol
[idx
][0]);
185 cs4245_write_cached(chip
, CS4245_PGA_B_CTRL
,
186 data
->input_vol
[idx
][1]);
189 mutex_unlock(&chip
->mutex
);
193 static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale
, -1200, 50, 0);
195 static int input_sel_info(struct snd_kcontrol
*ctl
,
196 struct snd_ctl_elem_info
*info
)
198 static const char *const names
[4] = {
199 "Mic", "Aux", "Front Mic", "Line"
202 return snd_ctl_enum_info(info
, 1, 4, names
);
205 static int input_sel_get(struct snd_kcontrol
*ctl
,
206 struct snd_ctl_elem_value
*value
)
208 struct oxygen
*chip
= ctl
->private_data
;
209 struct dg
*data
= chip
->model_data
;
211 mutex_lock(&chip
->mutex
);
212 value
->value
.enumerated
.item
[0] = data
->input_sel
;
213 mutex_unlock(&chip
->mutex
);
217 static int input_sel_put(struct snd_kcontrol
*ctl
,
218 struct snd_ctl_elem_value
*value
)
220 static const u8 sel_values
[4] = {
226 struct oxygen
*chip
= ctl
->private_data
;
227 struct dg
*data
= chip
->model_data
;
230 if (value
->value
.enumerated
.item
[0] > 3)
233 mutex_lock(&chip
->mutex
);
234 changed
= value
->value
.enumerated
.item
[0] != data
->input_sel
;
236 data
->input_sel
= value
->value
.enumerated
.item
[0];
238 cs4245_write(chip
, CS4245_ANALOG_IN
,
239 (data
->cs4245_shadow
[CS4245_ANALOG_IN
] &
241 sel_values
[data
->input_sel
]);
243 cs4245_write_cached(chip
, CS4245_PGA_A_CTRL
,
244 data
->input_vol
[data
->input_sel
][0]);
245 cs4245_write_cached(chip
, CS4245_PGA_B_CTRL
,
246 data
->input_vol
[data
->input_sel
][1]);
248 oxygen_write16_masked(chip
, OXYGEN_GPIO_DATA
,
249 data
->input_sel
? 0 : GPIO_INPUT_ROUTE
,
252 mutex_unlock(&chip
->mutex
);
256 static int hpf_info(struct snd_kcontrol
*ctl
, struct snd_ctl_elem_info
*info
)
258 static const char *const names
[2] = { "Active", "Frozen" };
260 return snd_ctl_enum_info(info
, 1, 2, names
);
263 static int hpf_get(struct snd_kcontrol
*ctl
, struct snd_ctl_elem_value
*value
)
265 struct oxygen
*chip
= ctl
->private_data
;
266 struct dg
*data
= chip
->model_data
;
268 value
->value
.enumerated
.item
[0] =
269 !!(data
->cs4245_shadow
[CS4245_ADC_CTRL
] & CS4245_HPF_FREEZE
);
273 static int hpf_put(struct snd_kcontrol
*ctl
, struct snd_ctl_elem_value
*value
)
275 struct oxygen
*chip
= ctl
->private_data
;
276 struct dg
*data
= chip
->model_data
;
280 mutex_lock(&chip
->mutex
);
281 reg
= data
->cs4245_shadow
[CS4245_ADC_CTRL
] & ~CS4245_HPF_FREEZE
;
282 if (value
->value
.enumerated
.item
[0])
283 reg
|= CS4245_HPF_FREEZE
;
284 changed
= reg
!= data
->cs4245_shadow
[CS4245_ADC_CTRL
];
286 cs4245_write(chip
, CS4245_ADC_CTRL
, reg
);
287 mutex_unlock(&chip
->mutex
);
291 #define INPUT_VOLUME(xname, index) { \
292 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
294 .info = input_vol_info, \
295 .get = input_vol_get, \
296 .put = input_vol_put, \
297 .tlv = { .p = cs4245_pga_db_scale }, \
298 .private_value = index, \
300 static const struct snd_kcontrol_new dg_controls
[] = {
302 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
303 .name
= "Analog Output Playback Enum",
304 .info
= output_switch_info
,
305 .get
= output_switch_get
,
306 .put
= output_switch_put
,
309 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
310 .name
= "Headphones Impedance Playback Enum",
311 .info
= hp_volume_offset_info
,
312 .get
= hp_volume_offset_get
,
313 .put
= hp_volume_offset_put
,
315 INPUT_VOLUME("Mic Capture Volume", 0),
316 INPUT_VOLUME("Aux Capture Volume", 1),
317 INPUT_VOLUME("Front Mic Capture Volume", 2),
318 INPUT_VOLUME("Line Capture Volume", 3),
320 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
321 .name
= "Capture Source",
322 .info
= input_sel_info
,
323 .get
= input_sel_get
,
324 .put
= input_sel_put
,
327 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
328 .name
= "ADC High-pass Filter Capture Enum",
335 static int dg_control_filter(struct snd_kcontrol_new
*template)
337 if (!strncmp(template->name
, "Master Playback ", 16))
342 static int dg_mixer_init(struct oxygen
*chip
)
347 for (i
= 0; i
< ARRAY_SIZE(dg_controls
); ++i
) {
348 err
= snd_ctl_add(chip
->card
,
349 snd_ctl_new1(&dg_controls
[i
], chip
));
356 struct oxygen_model model_xonar_dg
= {
357 .longname
= "C-Media Oxygen HD Audio",
360 .control_filter
= dg_control_filter
,
361 .mixer_init
= dg_mixer_init
,
362 .cleanup
= dg_cleanup
,
363 .suspend
= dg_suspend
,
365 .set_dac_params
= set_cs4245_dac_params
,
366 .set_adc_params
= set_cs4245_adc_params
,
367 .adjust_dac_routing
= adjust_dg_dac_routing
,
368 .dump_registers
= dump_cs4245_registers
,
369 .model_data_size
= sizeof(struct dg
),
370 .device_config
= PLAYBACK_0_TO_I2S
|
371 PLAYBACK_1_TO_SPDIF
|
372 CAPTURE_0_FROM_I2S_1
|
373 CAPTURE_1_FROM_SPDIF
,
374 .dac_channels_pcm
= 6,
375 .dac_channels_mixer
= 0,
376 .function_flags
= OXYGEN_FUNCTION_SPI
,
377 .dac_mclks
= OXYGEN_MCLKS(256, 128, 128),
378 .adc_mclks
= OXYGEN_MCLKS(256, 128, 128),
379 .dac_i2s_format
= OXYGEN_I2S_FORMAT_LJUST
,
380 .adc_i2s_format
= OXYGEN_I2S_FORMAT_LJUST
,