Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Mixer controls for the Xonar DG/DGX
0004  *
0005  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
0006  * Copyright (c) Roman Volkov <v1ron@mail.ru>
0007  */
0008 
0009 #include <linux/pci.h>
0010 #include <linux/delay.h>
0011 #include <sound/control.h>
0012 #include <sound/core.h>
0013 #include <sound/info.h>
0014 #include <sound/pcm.h>
0015 #include <sound/tlv.h>
0016 #include "oxygen.h"
0017 #include "xonar_dg.h"
0018 #include "cs4245.h"
0019 
0020 /* analog output select */
0021 
0022 static int output_select_apply(struct oxygen *chip)
0023 {
0024     struct dg *data = chip->model_data;
0025 
0026     data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK;
0027     if (data->output_sel == PLAYBACK_DST_HP) {
0028         /* mute FP (aux output) amplifier, switch rear jack to CS4245 */
0029         oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
0030     } else if (data->output_sel == PLAYBACK_DST_HP_FP) {
0031         /*
0032          * Unmute FP amplifier, switch rear jack to CS4361;
0033          * I2S channels 2,3,4 should be inactive.
0034          */
0035         oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
0036         data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC;
0037     } else {
0038         /*
0039          * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp.,
0040          * and change playback routing.
0041          */
0042         oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
0043     }
0044     return cs4245_write_spi(chip, CS4245_SIGNAL_SEL);
0045 }
0046 
0047 static int output_select_info(struct snd_kcontrol *ctl,
0048                   struct snd_ctl_elem_info *info)
0049 {
0050     static const char *const names[3] = {
0051         "Stereo Headphones",
0052         "Stereo Headphones FP",
0053         "Multichannel",
0054     };
0055 
0056     return snd_ctl_enum_info(info, 1, 3, names);
0057 }
0058 
0059 static int output_select_get(struct snd_kcontrol *ctl,
0060                  struct snd_ctl_elem_value *value)
0061 {
0062     struct oxygen *chip = ctl->private_data;
0063     struct dg *data = chip->model_data;
0064 
0065     mutex_lock(&chip->mutex);
0066     value->value.enumerated.item[0] = data->output_sel;
0067     mutex_unlock(&chip->mutex);
0068     return 0;
0069 }
0070 
0071 static int output_select_put(struct snd_kcontrol *ctl,
0072                  struct snd_ctl_elem_value *value)
0073 {
0074     struct oxygen *chip = ctl->private_data;
0075     struct dg *data = chip->model_data;
0076     unsigned int new = value->value.enumerated.item[0];
0077     int changed = 0;
0078     int ret;
0079 
0080     mutex_lock(&chip->mutex);
0081     if (data->output_sel != new) {
0082         data->output_sel = new;
0083         ret = output_select_apply(chip);
0084         changed = ret >= 0 ? 1 : ret;
0085         oxygen_update_dac_routing(chip);
0086     }
0087     mutex_unlock(&chip->mutex);
0088 
0089     return changed;
0090 }
0091 
0092 /* CS4245 Headphone Channels A&B Volume Control */
0093 
0094 static int hp_stereo_volume_info(struct snd_kcontrol *ctl,
0095                 struct snd_ctl_elem_info *info)
0096 {
0097     info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0098     info->count = 2;
0099     info->value.integer.min = 0;
0100     info->value.integer.max = 255;
0101     return 0;
0102 }
0103 
0104 static int hp_stereo_volume_get(struct snd_kcontrol *ctl,
0105                 struct snd_ctl_elem_value *val)
0106 {
0107     struct oxygen *chip = ctl->private_data;
0108     struct dg *data = chip->model_data;
0109     unsigned int tmp;
0110 
0111     mutex_lock(&chip->mutex);
0112     tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255;
0113     val->value.integer.value[0] = tmp;
0114     tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255;
0115     val->value.integer.value[1] = tmp;
0116     mutex_unlock(&chip->mutex);
0117     return 0;
0118 }
0119 
0120 static int hp_stereo_volume_put(struct snd_kcontrol *ctl,
0121                 struct snd_ctl_elem_value *val)
0122 {
0123     struct oxygen *chip = ctl->private_data;
0124     struct dg *data = chip->model_data;
0125     int ret;
0126     int changed = 0;
0127     long new1 = val->value.integer.value[0];
0128     long new2 = val->value.integer.value[1];
0129 
0130     if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0))
0131         return -EINVAL;
0132 
0133     mutex_lock(&chip->mutex);
0134     if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) ||
0135         (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) {
0136         data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1;
0137         data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2;
0138         ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL);
0139         if (ret >= 0)
0140             ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL);
0141         changed = ret >= 0 ? 1 : ret;
0142     }
0143     mutex_unlock(&chip->mutex);
0144 
0145     return changed;
0146 }
0147 
0148 /* Headphone Mute */
0149 
0150 static int hp_mute_get(struct snd_kcontrol *ctl,
0151             struct snd_ctl_elem_value *val)
0152 {
0153     struct oxygen *chip = ctl->private_data;
0154     struct dg *data = chip->model_data;
0155 
0156     mutex_lock(&chip->mutex);
0157     val->value.integer.value[0] =
0158         !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC);
0159     mutex_unlock(&chip->mutex);
0160     return 0;
0161 }
0162 
0163 static int hp_mute_put(struct snd_kcontrol *ctl,
0164             struct snd_ctl_elem_value *val)
0165 {
0166     struct oxygen *chip = ctl->private_data;
0167     struct dg *data = chip->model_data;
0168     int ret;
0169     int changed;
0170 
0171     if (val->value.integer.value[0] > 1)
0172         return -EINVAL;
0173     mutex_lock(&chip->mutex);
0174     data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC;
0175     data->cs4245_shadow[CS4245_DAC_CTRL_1] |=
0176         (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC;
0177     ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
0178     changed = ret >= 0 ? 1 : ret;
0179     mutex_unlock(&chip->mutex);
0180     return changed;
0181 }
0182 
0183 /* capture volume for all sources */
0184 
0185 static int input_volume_apply(struct oxygen *chip, char left, char right)
0186 {
0187     struct dg *data = chip->model_data;
0188     int ret;
0189 
0190     data->cs4245_shadow[CS4245_PGA_A_CTRL] = left;
0191     data->cs4245_shadow[CS4245_PGA_B_CTRL] = right;
0192     ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL);
0193     if (ret < 0)
0194         return ret;
0195     return cs4245_write_spi(chip, CS4245_PGA_B_CTRL);
0196 }
0197 
0198 static int input_vol_info(struct snd_kcontrol *ctl,
0199               struct snd_ctl_elem_info *info)
0200 {
0201     info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0202     info->count = 2;
0203     info->value.integer.min = 2 * -12;
0204     info->value.integer.max = 2 * 12;
0205     return 0;
0206 }
0207 
0208 static int input_vol_get(struct snd_kcontrol *ctl,
0209              struct snd_ctl_elem_value *value)
0210 {
0211     struct oxygen *chip = ctl->private_data;
0212     struct dg *data = chip->model_data;
0213     unsigned int idx = ctl->private_value;
0214 
0215     mutex_lock(&chip->mutex);
0216     value->value.integer.value[0] = data->input_vol[idx][0];
0217     value->value.integer.value[1] = data->input_vol[idx][1];
0218     mutex_unlock(&chip->mutex);
0219     return 0;
0220 }
0221 
0222 static int input_vol_put(struct snd_kcontrol *ctl,
0223              struct snd_ctl_elem_value *value)
0224 {
0225     struct oxygen *chip = ctl->private_data;
0226     struct dg *data = chip->model_data;
0227     unsigned int idx = ctl->private_value;
0228     int changed = 0;
0229     int ret = 0;
0230 
0231     if (value->value.integer.value[0] < 2 * -12 ||
0232         value->value.integer.value[0] > 2 * 12 ||
0233         value->value.integer.value[1] < 2 * -12 ||
0234         value->value.integer.value[1] > 2 * 12)
0235         return -EINVAL;
0236     mutex_lock(&chip->mutex);
0237     changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
0238           data->input_vol[idx][1] != value->value.integer.value[1];
0239     if (changed) {
0240         data->input_vol[idx][0] = value->value.integer.value[0];
0241         data->input_vol[idx][1] = value->value.integer.value[1];
0242         if (idx == data->input_sel) {
0243             ret = input_volume_apply(chip,
0244                 data->input_vol[idx][0],
0245                 data->input_vol[idx][1]);
0246         }
0247         changed = ret >= 0 ? 1 : ret;
0248     }
0249     mutex_unlock(&chip->mutex);
0250     return changed;
0251 }
0252 
0253 /* Capture Source */
0254 
0255 static int input_source_apply(struct oxygen *chip)
0256 {
0257     struct dg *data = chip->model_data;
0258 
0259     data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK;
0260     if (data->input_sel == CAPTURE_SRC_FP_MIC)
0261         data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2;
0262     else if (data->input_sel == CAPTURE_SRC_LINE)
0263         data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4;
0264     else if (data->input_sel != CAPTURE_SRC_MIC)
0265         data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1;
0266     return cs4245_write_spi(chip, CS4245_ANALOG_IN);
0267 }
0268 
0269 static int input_sel_info(struct snd_kcontrol *ctl,
0270               struct snd_ctl_elem_info *info)
0271 {
0272     static const char *const names[4] = {
0273         "Mic", "Front Mic", "Line", "Aux"
0274     };
0275 
0276     return snd_ctl_enum_info(info, 1, 4, names);
0277 }
0278 
0279 static int input_sel_get(struct snd_kcontrol *ctl,
0280              struct snd_ctl_elem_value *value)
0281 {
0282     struct oxygen *chip = ctl->private_data;
0283     struct dg *data = chip->model_data;
0284 
0285     mutex_lock(&chip->mutex);
0286     value->value.enumerated.item[0] = data->input_sel;
0287     mutex_unlock(&chip->mutex);
0288     return 0;
0289 }
0290 
0291 static int input_sel_put(struct snd_kcontrol *ctl,
0292              struct snd_ctl_elem_value *value)
0293 {
0294     struct oxygen *chip = ctl->private_data;
0295     struct dg *data = chip->model_data;
0296     int changed;
0297     int ret;
0298 
0299     if (value->value.enumerated.item[0] > 3)
0300         return -EINVAL;
0301 
0302     mutex_lock(&chip->mutex);
0303     changed = value->value.enumerated.item[0] != data->input_sel;
0304     if (changed) {
0305         data->input_sel = value->value.enumerated.item[0];
0306 
0307         ret = input_source_apply(chip);
0308         if (ret >= 0)
0309             ret = input_volume_apply(chip,
0310                 data->input_vol[data->input_sel][0],
0311                 data->input_vol[data->input_sel][1]);
0312         changed = ret >= 0 ? 1 : ret;
0313     }
0314     mutex_unlock(&chip->mutex);
0315     return changed;
0316 }
0317 
0318 /* ADC high-pass filter */
0319 
0320 static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
0321 {
0322     static const char *const names[2] = { "Active", "Frozen" };
0323 
0324     return snd_ctl_enum_info(info, 1, 2, names);
0325 }
0326 
0327 static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
0328 {
0329     struct oxygen *chip = ctl->private_data;
0330     struct dg *data = chip->model_data;
0331 
0332     value->value.enumerated.item[0] =
0333         !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
0334     return 0;
0335 }
0336 
0337 static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
0338 {
0339     struct oxygen *chip = ctl->private_data;
0340     struct dg *data = chip->model_data;
0341     u8 reg;
0342     int changed;
0343 
0344     mutex_lock(&chip->mutex);
0345     reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
0346     if (value->value.enumerated.item[0])
0347         reg |= CS4245_HPF_FREEZE;
0348     changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL];
0349     if (changed) {
0350         data->cs4245_shadow[CS4245_ADC_CTRL] = reg;
0351         cs4245_write_spi(chip, CS4245_ADC_CTRL);
0352     }
0353     mutex_unlock(&chip->mutex);
0354     return changed;
0355 }
0356 
0357 #define INPUT_VOLUME(xname, index) { \
0358     .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
0359     .name = xname, \
0360     .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
0361           SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
0362     .info = input_vol_info, \
0363     .get = input_vol_get, \
0364     .put = input_vol_put, \
0365     .tlv = { .p = pga_db_scale }, \
0366     .private_value = index, \
0367 }
0368 static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0);
0369 static const DECLARE_TLV_DB_MINMAX(pga_db_scale, -1200, 1200);
0370 static const struct snd_kcontrol_new dg_controls[] = {
0371     {
0372         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0373         .name = "Analog Output Playback Enum",
0374         .info = output_select_info,
0375         .get = output_select_get,
0376         .put = output_select_put,
0377     },
0378     {
0379         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0380         .name = "Headphone Playback Volume",
0381         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
0382               SNDRV_CTL_ELEM_ACCESS_TLV_READ,
0383         .info = hp_stereo_volume_info,
0384         .get = hp_stereo_volume_get,
0385         .put = hp_stereo_volume_put,
0386         .tlv = { .p = hp_db_scale, },
0387     },
0388     {
0389         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0390         .name = "Headphone Playback Switch",
0391         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0392         .info = snd_ctl_boolean_mono_info,
0393         .get = hp_mute_get,
0394         .put = hp_mute_put,
0395     },
0396     INPUT_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC),
0397     INPUT_VOLUME("Front Mic Capture Volume", CAPTURE_SRC_FP_MIC),
0398     INPUT_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE),
0399     INPUT_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX),
0400     {
0401         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0402         .name = "Capture Source",
0403         .info = input_sel_info,
0404         .get = input_sel_get,
0405         .put = input_sel_put,
0406     },
0407     {
0408         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0409         .name = "ADC High-pass Filter Capture Enum",
0410         .info = hpf_info,
0411         .get = hpf_get,
0412         .put = hpf_put,
0413     },
0414 };
0415 
0416 static int dg_control_filter(struct snd_kcontrol_new *template)
0417 {
0418     if (!strncmp(template->name, "Master Playback ", 16))
0419         return 1;
0420     return 0;
0421 }
0422 
0423 static int dg_mixer_init(struct oxygen *chip)
0424 {
0425     unsigned int i;
0426     int err;
0427 
0428     output_select_apply(chip);
0429     input_source_apply(chip);
0430     oxygen_update_dac_routing(chip);
0431 
0432     for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
0433         err = snd_ctl_add(chip->card,
0434                   snd_ctl_new1(&dg_controls[i], chip));
0435         if (err < 0)
0436             return err;
0437     }
0438 
0439     return 0;
0440 }
0441 
0442 const struct oxygen_model model_xonar_dg = {
0443     .longname = "C-Media Oxygen HD Audio",
0444     .chip = "CMI8786",
0445     .init = dg_init,
0446     .control_filter = dg_control_filter,
0447     .mixer_init = dg_mixer_init,
0448     .cleanup = dg_cleanup,
0449     .suspend = dg_suspend,
0450     .resume = dg_resume,
0451     .set_dac_params = set_cs4245_dac_params,
0452     .set_adc_params = set_cs4245_adc_params,
0453     .adjust_dac_routing = adjust_dg_dac_routing,
0454     .dump_registers = dump_cs4245_registers,
0455     .model_data_size = sizeof(struct dg),
0456     .device_config = PLAYBACK_0_TO_I2S |
0457              PLAYBACK_1_TO_SPDIF |
0458              CAPTURE_0_FROM_I2S_1 |
0459              CAPTURE_1_FROM_SPDIF,
0460     .dac_channels_pcm = 6,
0461     .dac_channels_mixer = 0,
0462     .function_flags = OXYGEN_FUNCTION_SPI,
0463     .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
0464     .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
0465     .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
0466     .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
0467 };