162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * C-Media CMI8788 driver - mixer code 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/mutex.h> 962306a36Sopenharmony_ci#include <sound/ac97_codec.h> 1062306a36Sopenharmony_ci#include <sound/asoundef.h> 1162306a36Sopenharmony_ci#include <sound/control.h> 1262306a36Sopenharmony_ci#include <sound/tlv.h> 1362306a36Sopenharmony_ci#include "oxygen.h" 1462306a36Sopenharmony_ci#include "cm9780.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic int dac_volume_info(struct snd_kcontrol *ctl, 1762306a36Sopenharmony_ci struct snd_ctl_elem_info *info) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2262306a36Sopenharmony_ci info->count = chip->model.dac_channels_mixer; 2362306a36Sopenharmony_ci info->value.integer.min = chip->model.dac_volume_min; 2462306a36Sopenharmony_ci info->value.integer.max = chip->model.dac_volume_max; 2562306a36Sopenharmony_ci return 0; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int dac_volume_get(struct snd_kcontrol *ctl, 2962306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 3262306a36Sopenharmony_ci unsigned int i; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci mutex_lock(&chip->mutex); 3562306a36Sopenharmony_ci for (i = 0; i < chip->model.dac_channels_mixer; ++i) 3662306a36Sopenharmony_ci value->value.integer.value[i] = chip->dac_volume[i]; 3762306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 3862306a36Sopenharmony_ci return 0; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int dac_volume_put(struct snd_kcontrol *ctl, 4262306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 4562306a36Sopenharmony_ci unsigned int i; 4662306a36Sopenharmony_ci int changed; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci changed = 0; 4962306a36Sopenharmony_ci mutex_lock(&chip->mutex); 5062306a36Sopenharmony_ci for (i = 0; i < chip->model.dac_channels_mixer; ++i) 5162306a36Sopenharmony_ci if (value->value.integer.value[i] != chip->dac_volume[i]) { 5262306a36Sopenharmony_ci chip->dac_volume[i] = value->value.integer.value[i]; 5362306a36Sopenharmony_ci changed = 1; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci if (changed) 5662306a36Sopenharmony_ci chip->model.update_dac_volume(chip); 5762306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 5862306a36Sopenharmony_ci return changed; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int dac_mute_get(struct snd_kcontrol *ctl, 6262306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci mutex_lock(&chip->mutex); 6762306a36Sopenharmony_ci value->value.integer.value[0] = !chip->dac_mute; 6862306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int dac_mute_put(struct snd_kcontrol *ctl, 7362306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 7662306a36Sopenharmony_ci int changed; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci mutex_lock(&chip->mutex); 7962306a36Sopenharmony_ci changed = (!value->value.integer.value[0]) != chip->dac_mute; 8062306a36Sopenharmony_ci if (changed) { 8162306a36Sopenharmony_ci chip->dac_mute = !value->value.integer.value[0]; 8262306a36Sopenharmony_ci chip->model.update_dac_mute(chip); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 8562306a36Sopenharmony_ci return changed; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic unsigned int upmix_item_count(struct oxygen *chip) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci if (chip->model.dac_channels_pcm < 8) 9162306a36Sopenharmony_ci return 2; 9262306a36Sopenharmony_ci else if (chip->model.update_center_lfe_mix) 9362306a36Sopenharmony_ci return 5; 9462306a36Sopenharmony_ci else 9562306a36Sopenharmony_ci return 3; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci static const char *const names[5] = { 10162306a36Sopenharmony_ci "Front", 10262306a36Sopenharmony_ci "Front+Surround", 10362306a36Sopenharmony_ci "Front+Surround+Back", 10462306a36Sopenharmony_ci "Front+Surround+Center/LFE", 10562306a36Sopenharmony_ci "Front+Surround+Center/LFE+Back", 10662306a36Sopenharmony_ci }; 10762306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 10862306a36Sopenharmony_ci unsigned int count = upmix_item_count(chip); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return snd_ctl_enum_info(info, 1, count, names); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci mutex_lock(&chip->mutex); 11862306a36Sopenharmony_ci value->value.enumerated.item[0] = chip->dac_routing; 11962306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_civoid oxygen_update_dac_routing(struct oxygen *chip) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */ 12662306a36Sopenharmony_ci static const unsigned int reg_values[5] = { 12762306a36Sopenharmony_ci /* stereo -> front */ 12862306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 12962306a36Sopenharmony_ci (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 13062306a36Sopenharmony_ci (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 13162306a36Sopenharmony_ci (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), 13262306a36Sopenharmony_ci /* stereo -> front+surround */ 13362306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 13462306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 13562306a36Sopenharmony_ci (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 13662306a36Sopenharmony_ci (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), 13762306a36Sopenharmony_ci /* stereo -> front+surround+back */ 13862306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 13962306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 14062306a36Sopenharmony_ci (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 14162306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), 14262306a36Sopenharmony_ci /* stereo -> front+surround+center/LFE */ 14362306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 14462306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 14562306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 14662306a36Sopenharmony_ci (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), 14762306a36Sopenharmony_ci /* stereo -> front+surround+center/LFE+back */ 14862306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 14962306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 15062306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 15162306a36Sopenharmony_ci (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), 15262306a36Sopenharmony_ci }; 15362306a36Sopenharmony_ci u8 channels; 15462306a36Sopenharmony_ci unsigned int reg_value; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci channels = oxygen_read8(chip, OXYGEN_PLAY_CHANNELS) & 15762306a36Sopenharmony_ci OXYGEN_PLAY_CHANNELS_MASK; 15862306a36Sopenharmony_ci if (channels == OXYGEN_PLAY_CHANNELS_2) 15962306a36Sopenharmony_ci reg_value = reg_values[chip->dac_routing]; 16062306a36Sopenharmony_ci else if (channels == OXYGEN_PLAY_CHANNELS_8) 16162306a36Sopenharmony_ci /* in 7.1 mode, "rear" channels go to the "back" jack */ 16262306a36Sopenharmony_ci reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 16362306a36Sopenharmony_ci (3 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 16462306a36Sopenharmony_ci (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 16562306a36Sopenharmony_ci (1 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); 16662306a36Sopenharmony_ci else 16762306a36Sopenharmony_ci reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 16862306a36Sopenharmony_ci (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 16962306a36Sopenharmony_ci (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 17062306a36Sopenharmony_ci (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); 17162306a36Sopenharmony_ci if (chip->model.adjust_dac_routing) 17262306a36Sopenharmony_ci reg_value = chip->model.adjust_dac_routing(chip, reg_value); 17362306a36Sopenharmony_ci oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, 17462306a36Sopenharmony_ci OXYGEN_PLAY_DAC0_SOURCE_MASK | 17562306a36Sopenharmony_ci OXYGEN_PLAY_DAC1_SOURCE_MASK | 17662306a36Sopenharmony_ci OXYGEN_PLAY_DAC2_SOURCE_MASK | 17762306a36Sopenharmony_ci OXYGEN_PLAY_DAC3_SOURCE_MASK); 17862306a36Sopenharmony_ci if (chip->model.update_center_lfe_mix) 17962306a36Sopenharmony_ci chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ciEXPORT_SYMBOL(oxygen_update_dac_routing); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 18662306a36Sopenharmony_ci unsigned int count = upmix_item_count(chip); 18762306a36Sopenharmony_ci int changed; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (value->value.enumerated.item[0] >= count) 19062306a36Sopenharmony_ci return -EINVAL; 19162306a36Sopenharmony_ci mutex_lock(&chip->mutex); 19262306a36Sopenharmony_ci changed = value->value.enumerated.item[0] != chip->dac_routing; 19362306a36Sopenharmony_ci if (changed) { 19462306a36Sopenharmony_ci chip->dac_routing = value->value.enumerated.item[0]; 19562306a36Sopenharmony_ci oxygen_update_dac_routing(chip); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 19862306a36Sopenharmony_ci return changed; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int spdif_switch_get(struct snd_kcontrol *ctl, 20262306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci mutex_lock(&chip->mutex); 20762306a36Sopenharmony_ci value->value.integer.value[0] = chip->spdif_playback_enable; 20862306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic unsigned int oxygen_spdif_rate(unsigned int oxygen_rate) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci switch (oxygen_rate) { 21562306a36Sopenharmony_ci case OXYGEN_RATE_32000: 21662306a36Sopenharmony_ci return IEC958_AES3_CON_FS_32000 << OXYGEN_SPDIF_CS_RATE_SHIFT; 21762306a36Sopenharmony_ci case OXYGEN_RATE_44100: 21862306a36Sopenharmony_ci return IEC958_AES3_CON_FS_44100 << OXYGEN_SPDIF_CS_RATE_SHIFT; 21962306a36Sopenharmony_ci default: /* OXYGEN_RATE_48000 */ 22062306a36Sopenharmony_ci return IEC958_AES3_CON_FS_48000 << OXYGEN_SPDIF_CS_RATE_SHIFT; 22162306a36Sopenharmony_ci case OXYGEN_RATE_64000: 22262306a36Sopenharmony_ci return 0xb << OXYGEN_SPDIF_CS_RATE_SHIFT; 22362306a36Sopenharmony_ci case OXYGEN_RATE_88200: 22462306a36Sopenharmony_ci return IEC958_AES3_CON_FS_88200 << OXYGEN_SPDIF_CS_RATE_SHIFT; 22562306a36Sopenharmony_ci case OXYGEN_RATE_96000: 22662306a36Sopenharmony_ci return IEC958_AES3_CON_FS_96000 << OXYGEN_SPDIF_CS_RATE_SHIFT; 22762306a36Sopenharmony_ci case OXYGEN_RATE_176400: 22862306a36Sopenharmony_ci return IEC958_AES3_CON_FS_176400 << OXYGEN_SPDIF_CS_RATE_SHIFT; 22962306a36Sopenharmony_ci case OXYGEN_RATE_192000: 23062306a36Sopenharmony_ci return IEC958_AES3_CON_FS_192000 << OXYGEN_SPDIF_CS_RATE_SHIFT; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_civoid oxygen_update_spdif_source(struct oxygen *chip) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci u32 old_control, new_control; 23762306a36Sopenharmony_ci u16 old_routing, new_routing; 23862306a36Sopenharmony_ci unsigned int oxygen_rate; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci old_control = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); 24162306a36Sopenharmony_ci old_routing = oxygen_read16(chip, OXYGEN_PLAY_ROUTING); 24262306a36Sopenharmony_ci if (chip->pcm_active & (1 << PCM_SPDIF)) { 24362306a36Sopenharmony_ci new_control = old_control | OXYGEN_SPDIF_OUT_ENABLE; 24462306a36Sopenharmony_ci new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK) 24562306a36Sopenharmony_ci | OXYGEN_PLAY_SPDIF_SPDIF; 24662306a36Sopenharmony_ci oxygen_rate = (old_control >> OXYGEN_SPDIF_OUT_RATE_SHIFT) 24762306a36Sopenharmony_ci & OXYGEN_I2S_RATE_MASK; 24862306a36Sopenharmony_ci /* S/PDIF rate was already set by the caller */ 24962306a36Sopenharmony_ci } else if ((chip->pcm_active & (1 << PCM_MULTICH)) && 25062306a36Sopenharmony_ci chip->spdif_playback_enable) { 25162306a36Sopenharmony_ci new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK) 25262306a36Sopenharmony_ci | OXYGEN_PLAY_SPDIF_MULTICH_01; 25362306a36Sopenharmony_ci oxygen_rate = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) 25462306a36Sopenharmony_ci & OXYGEN_I2S_RATE_MASK; 25562306a36Sopenharmony_ci new_control = (old_control & ~OXYGEN_SPDIF_OUT_RATE_MASK) | 25662306a36Sopenharmony_ci (oxygen_rate << OXYGEN_SPDIF_OUT_RATE_SHIFT) | 25762306a36Sopenharmony_ci OXYGEN_SPDIF_OUT_ENABLE; 25862306a36Sopenharmony_ci } else { 25962306a36Sopenharmony_ci new_control = old_control & ~OXYGEN_SPDIF_OUT_ENABLE; 26062306a36Sopenharmony_ci new_routing = old_routing; 26162306a36Sopenharmony_ci oxygen_rate = OXYGEN_RATE_44100; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci if (old_routing != new_routing) { 26462306a36Sopenharmony_ci oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, 26562306a36Sopenharmony_ci new_control & ~OXYGEN_SPDIF_OUT_ENABLE); 26662306a36Sopenharmony_ci oxygen_write16(chip, OXYGEN_PLAY_ROUTING, new_routing); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci if (new_control & OXYGEN_SPDIF_OUT_ENABLE) 26962306a36Sopenharmony_ci oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, 27062306a36Sopenharmony_ci oxygen_spdif_rate(oxygen_rate) | 27162306a36Sopenharmony_ci ((chip->pcm_active & (1 << PCM_SPDIF)) ? 27262306a36Sopenharmony_ci chip->spdif_pcm_bits : chip->spdif_bits)); 27362306a36Sopenharmony_ci oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, new_control); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int spdif_switch_put(struct snd_kcontrol *ctl, 27762306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 28062306a36Sopenharmony_ci int changed; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci mutex_lock(&chip->mutex); 28362306a36Sopenharmony_ci changed = value->value.integer.value[0] != chip->spdif_playback_enable; 28462306a36Sopenharmony_ci if (changed) { 28562306a36Sopenharmony_ci chip->spdif_playback_enable = !!value->value.integer.value[0]; 28662306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 28762306a36Sopenharmony_ci oxygen_update_spdif_source(chip); 28862306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 29162306a36Sopenharmony_ci return changed; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic int spdif_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci info->type = SNDRV_CTL_ELEM_TYPE_IEC958; 29762306a36Sopenharmony_ci info->count = 1; 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void oxygen_to_iec958(u32 bits, struct snd_ctl_elem_value *value) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci value->value.iec958.status[0] = 30462306a36Sopenharmony_ci bits & (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C | 30562306a36Sopenharmony_ci OXYGEN_SPDIF_PREEMPHASIS); 30662306a36Sopenharmony_ci value->value.iec958.status[1] = /* category and original */ 30762306a36Sopenharmony_ci bits >> OXYGEN_SPDIF_CATEGORY_SHIFT; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic u32 iec958_to_oxygen(struct snd_ctl_elem_value *value) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci u32 bits; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci bits = value->value.iec958.status[0] & 31562306a36Sopenharmony_ci (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C | 31662306a36Sopenharmony_ci OXYGEN_SPDIF_PREEMPHASIS); 31762306a36Sopenharmony_ci bits |= value->value.iec958.status[1] << OXYGEN_SPDIF_CATEGORY_SHIFT; 31862306a36Sopenharmony_ci if (bits & OXYGEN_SPDIF_NONAUDIO) 31962306a36Sopenharmony_ci bits |= OXYGEN_SPDIF_V; 32062306a36Sopenharmony_ci return bits; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic inline void write_spdif_bits(struct oxygen *chip, u32 bits) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci oxygen_write32_masked(chip, OXYGEN_SPDIF_OUTPUT_BITS, bits, 32662306a36Sopenharmony_ci OXYGEN_SPDIF_NONAUDIO | 32762306a36Sopenharmony_ci OXYGEN_SPDIF_C | 32862306a36Sopenharmony_ci OXYGEN_SPDIF_PREEMPHASIS | 32962306a36Sopenharmony_ci OXYGEN_SPDIF_CATEGORY_MASK | 33062306a36Sopenharmony_ci OXYGEN_SPDIF_ORIGINAL | 33162306a36Sopenharmony_ci OXYGEN_SPDIF_V); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int spdif_default_get(struct snd_kcontrol *ctl, 33562306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci mutex_lock(&chip->mutex); 34062306a36Sopenharmony_ci oxygen_to_iec958(chip->spdif_bits, value); 34162306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic int spdif_default_put(struct snd_kcontrol *ctl, 34662306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 34962306a36Sopenharmony_ci u32 new_bits; 35062306a36Sopenharmony_ci int changed; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci new_bits = iec958_to_oxygen(value); 35362306a36Sopenharmony_ci mutex_lock(&chip->mutex); 35462306a36Sopenharmony_ci changed = new_bits != chip->spdif_bits; 35562306a36Sopenharmony_ci if (changed) { 35662306a36Sopenharmony_ci chip->spdif_bits = new_bits; 35762306a36Sopenharmony_ci if (!(chip->pcm_active & (1 << PCM_SPDIF))) 35862306a36Sopenharmony_ci write_spdif_bits(chip, new_bits); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 36162306a36Sopenharmony_ci return changed; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int spdif_mask_get(struct snd_kcontrol *ctl, 36562306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci value->value.iec958.status[0] = IEC958_AES0_NONAUDIO | 36862306a36Sopenharmony_ci IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS; 36962306a36Sopenharmony_ci value->value.iec958.status[1] = 37062306a36Sopenharmony_ci IEC958_AES1_CON_CATEGORY | IEC958_AES1_CON_ORIGINAL; 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int spdif_pcm_get(struct snd_kcontrol *ctl, 37562306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci mutex_lock(&chip->mutex); 38062306a36Sopenharmony_ci oxygen_to_iec958(chip->spdif_pcm_bits, value); 38162306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int spdif_pcm_put(struct snd_kcontrol *ctl, 38662306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 38962306a36Sopenharmony_ci u32 new_bits; 39062306a36Sopenharmony_ci int changed; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci new_bits = iec958_to_oxygen(value); 39362306a36Sopenharmony_ci mutex_lock(&chip->mutex); 39462306a36Sopenharmony_ci changed = new_bits != chip->spdif_pcm_bits; 39562306a36Sopenharmony_ci if (changed) { 39662306a36Sopenharmony_ci chip->spdif_pcm_bits = new_bits; 39762306a36Sopenharmony_ci if (chip->pcm_active & (1 << PCM_SPDIF)) 39862306a36Sopenharmony_ci write_spdif_bits(chip, new_bits); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 40162306a36Sopenharmony_ci return changed; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int spdif_input_mask_get(struct snd_kcontrol *ctl, 40562306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci value->value.iec958.status[0] = 0xff; 40862306a36Sopenharmony_ci value->value.iec958.status[1] = 0xff; 40962306a36Sopenharmony_ci value->value.iec958.status[2] = 0xff; 41062306a36Sopenharmony_ci value->value.iec958.status[3] = 0xff; 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic int spdif_input_default_get(struct snd_kcontrol *ctl, 41562306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 41862306a36Sopenharmony_ci u32 bits; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci bits = oxygen_read32(chip, OXYGEN_SPDIF_INPUT_BITS); 42162306a36Sopenharmony_ci value->value.iec958.status[0] = bits; 42262306a36Sopenharmony_ci value->value.iec958.status[1] = bits >> 8; 42362306a36Sopenharmony_ci value->value.iec958.status[2] = bits >> 16; 42462306a36Sopenharmony_ci value->value.iec958.status[3] = bits >> 24; 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int spdif_bit_switch_get(struct snd_kcontrol *ctl, 42962306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 43262306a36Sopenharmony_ci u32 bit = ctl->private_value; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci value->value.integer.value[0] = 43562306a36Sopenharmony_ci !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) & bit); 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int spdif_bit_switch_put(struct snd_kcontrol *ctl, 44062306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 44362306a36Sopenharmony_ci u32 bit = ctl->private_value; 44462306a36Sopenharmony_ci u32 oldreg, newreg; 44562306a36Sopenharmony_ci int changed; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 44862306a36Sopenharmony_ci oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); 44962306a36Sopenharmony_ci if (value->value.integer.value[0]) 45062306a36Sopenharmony_ci newreg = oldreg | bit; 45162306a36Sopenharmony_ci else 45262306a36Sopenharmony_ci newreg = oldreg & ~bit; 45362306a36Sopenharmony_ci changed = newreg != oldreg; 45462306a36Sopenharmony_ci if (changed) 45562306a36Sopenharmony_ci oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); 45662306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 45762306a36Sopenharmony_ci return changed; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic int monitor_volume_info(struct snd_kcontrol *ctl, 46162306a36Sopenharmony_ci struct snd_ctl_elem_info *info) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 46462306a36Sopenharmony_ci info->count = 1; 46562306a36Sopenharmony_ci info->value.integer.min = 0; 46662306a36Sopenharmony_ci info->value.integer.max = 1; 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int monitor_get(struct snd_kcontrol *ctl, 47162306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 47462306a36Sopenharmony_ci u8 bit = ctl->private_value; 47562306a36Sopenharmony_ci int invert = ctl->private_value & (1 << 8); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci value->value.integer.value[0] = 47862306a36Sopenharmony_ci !!invert ^ !!(oxygen_read8(chip, OXYGEN_ADC_MONITOR) & bit); 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic int monitor_put(struct snd_kcontrol *ctl, 48362306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 48662306a36Sopenharmony_ci u8 bit = ctl->private_value; 48762306a36Sopenharmony_ci int invert = ctl->private_value & (1 << 8); 48862306a36Sopenharmony_ci u8 oldreg, newreg; 48962306a36Sopenharmony_ci int changed; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 49262306a36Sopenharmony_ci oldreg = oxygen_read8(chip, OXYGEN_ADC_MONITOR); 49362306a36Sopenharmony_ci if ((!!value->value.integer.value[0] ^ !!invert) != 0) 49462306a36Sopenharmony_ci newreg = oldreg | bit; 49562306a36Sopenharmony_ci else 49662306a36Sopenharmony_ci newreg = oldreg & ~bit; 49762306a36Sopenharmony_ci changed = newreg != oldreg; 49862306a36Sopenharmony_ci if (changed) 49962306a36Sopenharmony_ci oxygen_write8(chip, OXYGEN_ADC_MONITOR, newreg); 50062306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 50162306a36Sopenharmony_ci return changed; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int ac97_switch_get(struct snd_kcontrol *ctl, 50562306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 50862306a36Sopenharmony_ci unsigned int codec = (ctl->private_value >> 24) & 1; 50962306a36Sopenharmony_ci unsigned int index = ctl->private_value & 0xff; 51062306a36Sopenharmony_ci unsigned int bitnr = (ctl->private_value >> 8) & 0xff; 51162306a36Sopenharmony_ci int invert = ctl->private_value & (1 << 16); 51262306a36Sopenharmony_ci u16 reg; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci mutex_lock(&chip->mutex); 51562306a36Sopenharmony_ci reg = oxygen_read_ac97(chip, codec, index); 51662306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 51762306a36Sopenharmony_ci if (!(reg & (1 << bitnr)) ^ !invert) 51862306a36Sopenharmony_ci value->value.integer.value[0] = 1; 51962306a36Sopenharmony_ci else 52062306a36Sopenharmony_ci value->value.integer.value[0] = 0; 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic void mute_ac97_ctl(struct oxygen *chip, unsigned int control) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci unsigned int priv_idx; 52762306a36Sopenharmony_ci u16 value; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!chip->controls[control]) 53062306a36Sopenharmony_ci return; 53162306a36Sopenharmony_ci priv_idx = chip->controls[control]->private_value & 0xff; 53262306a36Sopenharmony_ci value = oxygen_read_ac97(chip, 0, priv_idx); 53362306a36Sopenharmony_ci if (!(value & 0x8000)) { 53462306a36Sopenharmony_ci oxygen_write_ac97(chip, 0, priv_idx, value | 0x8000); 53562306a36Sopenharmony_ci if (chip->model.ac97_switch) 53662306a36Sopenharmony_ci chip->model.ac97_switch(chip, priv_idx, 0x8000); 53762306a36Sopenharmony_ci snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 53862306a36Sopenharmony_ci &chip->controls[control]->id); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic int ac97_switch_put(struct snd_kcontrol *ctl, 54362306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 54662306a36Sopenharmony_ci unsigned int codec = (ctl->private_value >> 24) & 1; 54762306a36Sopenharmony_ci unsigned int index = ctl->private_value & 0xff; 54862306a36Sopenharmony_ci unsigned int bitnr = (ctl->private_value >> 8) & 0xff; 54962306a36Sopenharmony_ci int invert = ctl->private_value & (1 << 16); 55062306a36Sopenharmony_ci u16 oldreg, newreg; 55162306a36Sopenharmony_ci int change; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci mutex_lock(&chip->mutex); 55462306a36Sopenharmony_ci oldreg = oxygen_read_ac97(chip, codec, index); 55562306a36Sopenharmony_ci newreg = oldreg; 55662306a36Sopenharmony_ci if (!value->value.integer.value[0] ^ !invert) 55762306a36Sopenharmony_ci newreg |= 1 << bitnr; 55862306a36Sopenharmony_ci else 55962306a36Sopenharmony_ci newreg &= ~(1 << bitnr); 56062306a36Sopenharmony_ci change = newreg != oldreg; 56162306a36Sopenharmony_ci if (change) { 56262306a36Sopenharmony_ci oxygen_write_ac97(chip, codec, index, newreg); 56362306a36Sopenharmony_ci if (codec == 0 && chip->model.ac97_switch) 56462306a36Sopenharmony_ci chip->model.ac97_switch(chip, index, newreg & 0x8000); 56562306a36Sopenharmony_ci if (index == AC97_LINE) { 56662306a36Sopenharmony_ci oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, 56762306a36Sopenharmony_ci newreg & 0x8000 ? 56862306a36Sopenharmony_ci CM9780_GPO0 : 0, CM9780_GPO0); 56962306a36Sopenharmony_ci if (!(newreg & 0x8000)) { 57062306a36Sopenharmony_ci mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH); 57162306a36Sopenharmony_ci mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH); 57262306a36Sopenharmony_ci mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci } else if ((index == AC97_MIC || index == AC97_CD || 57562306a36Sopenharmony_ci index == AC97_VIDEO || index == AC97_AUX) && 57662306a36Sopenharmony_ci bitnr == 15 && !(newreg & 0x8000)) { 57762306a36Sopenharmony_ci mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH); 57862306a36Sopenharmony_ci oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, 57962306a36Sopenharmony_ci CM9780_GPO0, CM9780_GPO0); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 58362306a36Sopenharmony_ci return change; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic int ac97_volume_info(struct snd_kcontrol *ctl, 58762306a36Sopenharmony_ci struct snd_ctl_elem_info *info) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci int stereo = (ctl->private_value >> 16) & 1; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 59262306a36Sopenharmony_ci info->count = stereo ? 2 : 1; 59362306a36Sopenharmony_ci info->value.integer.min = 0; 59462306a36Sopenharmony_ci info->value.integer.max = 0x1f; 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int ac97_volume_get(struct snd_kcontrol *ctl, 59962306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 60262306a36Sopenharmony_ci unsigned int codec = (ctl->private_value >> 24) & 1; 60362306a36Sopenharmony_ci int stereo = (ctl->private_value >> 16) & 1; 60462306a36Sopenharmony_ci unsigned int index = ctl->private_value & 0xff; 60562306a36Sopenharmony_ci u16 reg; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci mutex_lock(&chip->mutex); 60862306a36Sopenharmony_ci reg = oxygen_read_ac97(chip, codec, index); 60962306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 61062306a36Sopenharmony_ci if (!stereo) { 61162306a36Sopenharmony_ci value->value.integer.value[0] = 31 - (reg & 0x1f); 61262306a36Sopenharmony_ci } else { 61362306a36Sopenharmony_ci value->value.integer.value[0] = 31 - ((reg >> 8) & 0x1f); 61462306a36Sopenharmony_ci value->value.integer.value[1] = 31 - (reg & 0x1f); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci return 0; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int ac97_volume_put(struct snd_kcontrol *ctl, 62062306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 62362306a36Sopenharmony_ci unsigned int codec = (ctl->private_value >> 24) & 1; 62462306a36Sopenharmony_ci int stereo = (ctl->private_value >> 16) & 1; 62562306a36Sopenharmony_ci unsigned int index = ctl->private_value & 0xff; 62662306a36Sopenharmony_ci u16 oldreg, newreg; 62762306a36Sopenharmony_ci int change; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci mutex_lock(&chip->mutex); 63062306a36Sopenharmony_ci oldreg = oxygen_read_ac97(chip, codec, index); 63162306a36Sopenharmony_ci if (!stereo) { 63262306a36Sopenharmony_ci newreg = oldreg & ~0x1f; 63362306a36Sopenharmony_ci newreg |= 31 - (value->value.integer.value[0] & 0x1f); 63462306a36Sopenharmony_ci } else { 63562306a36Sopenharmony_ci newreg = oldreg & ~0x1f1f; 63662306a36Sopenharmony_ci newreg |= (31 - (value->value.integer.value[0] & 0x1f)) << 8; 63762306a36Sopenharmony_ci newreg |= 31 - (value->value.integer.value[1] & 0x1f); 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci change = newreg != oldreg; 64062306a36Sopenharmony_ci if (change) 64162306a36Sopenharmony_ci oxygen_write_ac97(chip, codec, index, newreg); 64262306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 64362306a36Sopenharmony_ci return change; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int mic_fmic_source_info(struct snd_kcontrol *ctl, 64762306a36Sopenharmony_ci struct snd_ctl_elem_info *info) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci static const char *const names[] = { "Mic Jack", "Front Panel" }; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci return snd_ctl_enum_info(info, 1, 2, names); 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic int mic_fmic_source_get(struct snd_kcontrol *ctl, 65562306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci mutex_lock(&chip->mutex); 66062306a36Sopenharmony_ci value->value.enumerated.item[0] = 66162306a36Sopenharmony_ci !!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC); 66262306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 66362306a36Sopenharmony_ci return 0; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic int mic_fmic_source_put(struct snd_kcontrol *ctl, 66762306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 67062306a36Sopenharmony_ci u16 oldreg, newreg; 67162306a36Sopenharmony_ci int change; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci mutex_lock(&chip->mutex); 67462306a36Sopenharmony_ci oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK); 67562306a36Sopenharmony_ci if (value->value.enumerated.item[0]) 67662306a36Sopenharmony_ci newreg = oldreg | CM9780_FMIC2MIC; 67762306a36Sopenharmony_ci else 67862306a36Sopenharmony_ci newreg = oldreg & ~CM9780_FMIC2MIC; 67962306a36Sopenharmony_ci change = newreg != oldreg; 68062306a36Sopenharmony_ci if (change) 68162306a36Sopenharmony_ci oxygen_write_ac97(chip, 0, CM9780_JACK, newreg); 68262306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 68362306a36Sopenharmony_ci return change; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, 68762306a36Sopenharmony_ci struct snd_ctl_elem_info *info) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 69062306a36Sopenharmony_ci info->count = 2; 69162306a36Sopenharmony_ci info->value.integer.min = 0; 69262306a36Sopenharmony_ci info->value.integer.max = 7; 69362306a36Sopenharmony_ci return 0; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl, 69762306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 70062306a36Sopenharmony_ci u16 reg; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci mutex_lock(&chip->mutex); 70362306a36Sopenharmony_ci reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); 70462306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 70562306a36Sopenharmony_ci value->value.integer.value[0] = reg & 7; 70662306a36Sopenharmony_ci value->value.integer.value[1] = (reg >> 8) & 7; 70762306a36Sopenharmony_ci return 0; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, 71162306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 71462306a36Sopenharmony_ci u16 oldreg, newreg; 71562306a36Sopenharmony_ci int change; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci mutex_lock(&chip->mutex); 71862306a36Sopenharmony_ci oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); 71962306a36Sopenharmony_ci newreg = oldreg & ~0x0707; 72062306a36Sopenharmony_ci newreg = newreg | (value->value.integer.value[0] & 7); 72162306a36Sopenharmony_ci newreg = newreg | ((value->value.integer.value[1] & 7) << 8); 72262306a36Sopenharmony_ci change = newreg != oldreg; 72362306a36Sopenharmony_ci if (change) 72462306a36Sopenharmony_ci oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg); 72562306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 72662306a36Sopenharmony_ci return change; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci#define AC97_SWITCH(xname, codec, index, bitnr, invert) { \ 73062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 73162306a36Sopenharmony_ci .name = xname, \ 73262306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, \ 73362306a36Sopenharmony_ci .get = ac97_switch_get, \ 73462306a36Sopenharmony_ci .put = ac97_switch_put, \ 73562306a36Sopenharmony_ci .private_value = ((codec) << 24) | ((invert) << 16) | \ 73662306a36Sopenharmony_ci ((bitnr) << 8) | (index), \ 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci#define AC97_VOLUME(xname, codec, index, stereo) { \ 73962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 74062306a36Sopenharmony_ci .name = xname, \ 74162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 74262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 74362306a36Sopenharmony_ci .info = ac97_volume_info, \ 74462306a36Sopenharmony_ci .get = ac97_volume_get, \ 74562306a36Sopenharmony_ci .put = ac97_volume_put, \ 74662306a36Sopenharmony_ci .tlv = { .p = ac97_db_scale, }, \ 74762306a36Sopenharmony_ci .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0); 75162306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); 75262306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic const struct snd_kcontrol_new controls[] = { 75562306a36Sopenharmony_ci { 75662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 75762306a36Sopenharmony_ci .name = "Master Playback Volume", 75862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 75962306a36Sopenharmony_ci .info = dac_volume_info, 76062306a36Sopenharmony_ci .get = dac_volume_get, 76162306a36Sopenharmony_ci .put = dac_volume_put, 76262306a36Sopenharmony_ci }, 76362306a36Sopenharmony_ci { 76462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 76562306a36Sopenharmony_ci .name = "Master Playback Switch", 76662306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 76762306a36Sopenharmony_ci .get = dac_mute_get, 76862306a36Sopenharmony_ci .put = dac_mute_put, 76962306a36Sopenharmony_ci }, 77062306a36Sopenharmony_ci { 77162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 77262306a36Sopenharmony_ci .name = "Stereo Upmixing", 77362306a36Sopenharmony_ci .info = upmix_info, 77462306a36Sopenharmony_ci .get = upmix_get, 77562306a36Sopenharmony_ci .put = upmix_put, 77662306a36Sopenharmony_ci }, 77762306a36Sopenharmony_ci}; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic const struct snd_kcontrol_new spdif_output_controls[] = { 78062306a36Sopenharmony_ci { 78162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 78262306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), 78362306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 78462306a36Sopenharmony_ci .get = spdif_switch_get, 78562306a36Sopenharmony_ci .put = spdif_switch_put, 78662306a36Sopenharmony_ci }, 78762306a36Sopenharmony_ci { 78862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 78962306a36Sopenharmony_ci .device = 1, 79062306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 79162306a36Sopenharmony_ci .info = spdif_info, 79262306a36Sopenharmony_ci .get = spdif_default_get, 79362306a36Sopenharmony_ci .put = spdif_default_put, 79462306a36Sopenharmony_ci }, 79562306a36Sopenharmony_ci { 79662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 79762306a36Sopenharmony_ci .device = 1, 79862306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), 79962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 80062306a36Sopenharmony_ci .info = spdif_info, 80162306a36Sopenharmony_ci .get = spdif_mask_get, 80262306a36Sopenharmony_ci }, 80362306a36Sopenharmony_ci { 80462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 80562306a36Sopenharmony_ci .device = 1, 80662306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), 80762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 80862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_INACTIVE, 80962306a36Sopenharmony_ci .info = spdif_info, 81062306a36Sopenharmony_ci .get = spdif_pcm_get, 81162306a36Sopenharmony_ci .put = spdif_pcm_put, 81262306a36Sopenharmony_ci }, 81362306a36Sopenharmony_ci}; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic const struct snd_kcontrol_new spdif_input_controls[] = { 81662306a36Sopenharmony_ci { 81762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 81862306a36Sopenharmony_ci .device = 1, 81962306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), 82062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 82162306a36Sopenharmony_ci .info = spdif_info, 82262306a36Sopenharmony_ci .get = spdif_input_mask_get, 82362306a36Sopenharmony_ci }, 82462306a36Sopenharmony_ci { 82562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 82662306a36Sopenharmony_ci .device = 1, 82762306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 82862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 82962306a36Sopenharmony_ci .info = spdif_info, 83062306a36Sopenharmony_ci .get = spdif_input_default_get, 83162306a36Sopenharmony_ci }, 83262306a36Sopenharmony_ci { 83362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 83462306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH), 83562306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 83662306a36Sopenharmony_ci .get = spdif_bit_switch_get, 83762306a36Sopenharmony_ci .put = spdif_bit_switch_put, 83862306a36Sopenharmony_ci .private_value = OXYGEN_SPDIF_LOOPBACK, 83962306a36Sopenharmony_ci }, 84062306a36Sopenharmony_ci { 84162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 84262306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("Validity Check ",CAPTURE,SWITCH), 84362306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 84462306a36Sopenharmony_ci .get = spdif_bit_switch_get, 84562306a36Sopenharmony_ci .put = spdif_bit_switch_put, 84662306a36Sopenharmony_ci .private_value = OXYGEN_SPDIF_SPDVALID, 84762306a36Sopenharmony_ci }, 84862306a36Sopenharmony_ci}; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic const struct { 85162306a36Sopenharmony_ci unsigned int pcm_dev; 85262306a36Sopenharmony_ci struct snd_kcontrol_new controls[2]; 85362306a36Sopenharmony_ci} monitor_controls[] = { 85462306a36Sopenharmony_ci { 85562306a36Sopenharmony_ci .pcm_dev = CAPTURE_0_FROM_I2S_1, 85662306a36Sopenharmony_ci .controls = { 85762306a36Sopenharmony_ci { 85862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 85962306a36Sopenharmony_ci .name = "Analog Input Monitor Playback Switch", 86062306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 86162306a36Sopenharmony_ci .get = monitor_get, 86262306a36Sopenharmony_ci .put = monitor_put, 86362306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_A, 86462306a36Sopenharmony_ci }, 86562306a36Sopenharmony_ci { 86662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 86762306a36Sopenharmony_ci .name = "Analog Input Monitor Playback Volume", 86862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 86962306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 87062306a36Sopenharmony_ci .info = monitor_volume_info, 87162306a36Sopenharmony_ci .get = monitor_get, 87262306a36Sopenharmony_ci .put = monitor_put, 87362306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_A_HALF_VOL 87462306a36Sopenharmony_ci | (1 << 8), 87562306a36Sopenharmony_ci .tlv = { .p = monitor_db_scale, }, 87662306a36Sopenharmony_ci }, 87762306a36Sopenharmony_ci }, 87862306a36Sopenharmony_ci }, 87962306a36Sopenharmony_ci { 88062306a36Sopenharmony_ci .pcm_dev = CAPTURE_0_FROM_I2S_2, 88162306a36Sopenharmony_ci .controls = { 88262306a36Sopenharmony_ci { 88362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 88462306a36Sopenharmony_ci .name = "Analog Input Monitor Playback Switch", 88562306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 88662306a36Sopenharmony_ci .get = monitor_get, 88762306a36Sopenharmony_ci .put = monitor_put, 88862306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_B, 88962306a36Sopenharmony_ci }, 89062306a36Sopenharmony_ci { 89162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 89262306a36Sopenharmony_ci .name = "Analog Input Monitor Playback Volume", 89362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 89462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 89562306a36Sopenharmony_ci .info = monitor_volume_info, 89662306a36Sopenharmony_ci .get = monitor_get, 89762306a36Sopenharmony_ci .put = monitor_put, 89862306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL 89962306a36Sopenharmony_ci | (1 << 8), 90062306a36Sopenharmony_ci .tlv = { .p = monitor_db_scale, }, 90162306a36Sopenharmony_ci }, 90262306a36Sopenharmony_ci }, 90362306a36Sopenharmony_ci }, 90462306a36Sopenharmony_ci { 90562306a36Sopenharmony_ci .pcm_dev = CAPTURE_2_FROM_I2S_2, 90662306a36Sopenharmony_ci .controls = { 90762306a36Sopenharmony_ci { 90862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 90962306a36Sopenharmony_ci .name = "Analog Input Monitor Playback Switch", 91062306a36Sopenharmony_ci .index = 1, 91162306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 91262306a36Sopenharmony_ci .get = monitor_get, 91362306a36Sopenharmony_ci .put = monitor_put, 91462306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_B, 91562306a36Sopenharmony_ci }, 91662306a36Sopenharmony_ci { 91762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 91862306a36Sopenharmony_ci .name = "Analog Input Monitor Playback Volume", 91962306a36Sopenharmony_ci .index = 1, 92062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 92162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 92262306a36Sopenharmony_ci .info = monitor_volume_info, 92362306a36Sopenharmony_ci .get = monitor_get, 92462306a36Sopenharmony_ci .put = monitor_put, 92562306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL 92662306a36Sopenharmony_ci | (1 << 8), 92762306a36Sopenharmony_ci .tlv = { .p = monitor_db_scale, }, 92862306a36Sopenharmony_ci }, 92962306a36Sopenharmony_ci }, 93062306a36Sopenharmony_ci }, 93162306a36Sopenharmony_ci { 93262306a36Sopenharmony_ci .pcm_dev = CAPTURE_3_FROM_I2S_3, 93362306a36Sopenharmony_ci .controls = { 93462306a36Sopenharmony_ci { 93562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 93662306a36Sopenharmony_ci .name = "Analog Input Monitor Playback Switch", 93762306a36Sopenharmony_ci .index = 2, 93862306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 93962306a36Sopenharmony_ci .get = monitor_get, 94062306a36Sopenharmony_ci .put = monitor_put, 94162306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_C, 94262306a36Sopenharmony_ci }, 94362306a36Sopenharmony_ci { 94462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 94562306a36Sopenharmony_ci .name = "Analog Input Monitor Playback Volume", 94662306a36Sopenharmony_ci .index = 2, 94762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 94862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 94962306a36Sopenharmony_ci .info = monitor_volume_info, 95062306a36Sopenharmony_ci .get = monitor_get, 95162306a36Sopenharmony_ci .put = monitor_put, 95262306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL 95362306a36Sopenharmony_ci | (1 << 8), 95462306a36Sopenharmony_ci .tlv = { .p = monitor_db_scale, }, 95562306a36Sopenharmony_ci }, 95662306a36Sopenharmony_ci }, 95762306a36Sopenharmony_ci }, 95862306a36Sopenharmony_ci { 95962306a36Sopenharmony_ci .pcm_dev = CAPTURE_1_FROM_SPDIF, 96062306a36Sopenharmony_ci .controls = { 96162306a36Sopenharmony_ci { 96262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 96362306a36Sopenharmony_ci .name = "Digital Input Monitor Playback Switch", 96462306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 96562306a36Sopenharmony_ci .get = monitor_get, 96662306a36Sopenharmony_ci .put = monitor_put, 96762306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_C, 96862306a36Sopenharmony_ci }, 96962306a36Sopenharmony_ci { 97062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 97162306a36Sopenharmony_ci .name = "Digital Input Monitor Playback Volume", 97262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 97362306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 97462306a36Sopenharmony_ci .info = monitor_volume_info, 97562306a36Sopenharmony_ci .get = monitor_get, 97662306a36Sopenharmony_ci .put = monitor_put, 97762306a36Sopenharmony_ci .private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL 97862306a36Sopenharmony_ci | (1 << 8), 97962306a36Sopenharmony_ci .tlv = { .p = monitor_db_scale, }, 98062306a36Sopenharmony_ci }, 98162306a36Sopenharmony_ci }, 98262306a36Sopenharmony_ci }, 98362306a36Sopenharmony_ci}; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_cistatic const struct snd_kcontrol_new ac97_controls[] = { 98662306a36Sopenharmony_ci AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0), 98762306a36Sopenharmony_ci AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), 98862306a36Sopenharmony_ci AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), 98962306a36Sopenharmony_ci { 99062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 99162306a36Sopenharmony_ci .name = "Mic Source Capture Enum", 99262306a36Sopenharmony_ci .info = mic_fmic_source_info, 99362306a36Sopenharmony_ci .get = mic_fmic_source_get, 99462306a36Sopenharmony_ci .put = mic_fmic_source_put, 99562306a36Sopenharmony_ci }, 99662306a36Sopenharmony_ci AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), 99762306a36Sopenharmony_ci AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1), 99862306a36Sopenharmony_ci AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), 99962306a36Sopenharmony_ci AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX, 1), 100062306a36Sopenharmony_ci AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1), 100162306a36Sopenharmony_ci}; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic const struct snd_kcontrol_new ac97_fp_controls[] = { 100462306a36Sopenharmony_ci AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE, 1), 100562306a36Sopenharmony_ci AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1), 100662306a36Sopenharmony_ci { 100762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 100862306a36Sopenharmony_ci .name = "Front Panel Capture Volume", 100962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 101062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 101162306a36Sopenharmony_ci .info = ac97_fp_rec_volume_info, 101262306a36Sopenharmony_ci .get = ac97_fp_rec_volume_get, 101362306a36Sopenharmony_ci .put = ac97_fp_rec_volume_put, 101462306a36Sopenharmony_ci .tlv = { .p = ac97_rec_db_scale, }, 101562306a36Sopenharmony_ci }, 101662306a36Sopenharmony_ci AC97_SWITCH("Front Panel Capture Switch", 1, AC97_REC_GAIN, 15, 1), 101762306a36Sopenharmony_ci}; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic void oxygen_any_ctl_free(struct snd_kcontrol *ctl) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 102262306a36Sopenharmony_ci unsigned int i; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* I'm too lazy to write a function for each control :-) */ 102562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(chip->controls); ++i) 102662306a36Sopenharmony_ci chip->controls[i] = NULL; 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic int add_controls(struct oxygen *chip, 103062306a36Sopenharmony_ci const struct snd_kcontrol_new controls[], 103162306a36Sopenharmony_ci unsigned int count) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci static const char *const known_ctl_names[CONTROL_COUNT] = { 103462306a36Sopenharmony_ci [CONTROL_SPDIF_PCM] = 103562306a36Sopenharmony_ci SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), 103662306a36Sopenharmony_ci [CONTROL_SPDIF_INPUT_BITS] = 103762306a36Sopenharmony_ci SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 103862306a36Sopenharmony_ci [CONTROL_MIC_CAPTURE_SWITCH] = "Mic Capture Switch", 103962306a36Sopenharmony_ci [CONTROL_LINE_CAPTURE_SWITCH] = "Line Capture Switch", 104062306a36Sopenharmony_ci [CONTROL_CD_CAPTURE_SWITCH] = "CD Capture Switch", 104162306a36Sopenharmony_ci [CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch", 104262306a36Sopenharmony_ci }; 104362306a36Sopenharmony_ci unsigned int i; 104462306a36Sopenharmony_ci struct snd_kcontrol_new template; 104562306a36Sopenharmony_ci struct snd_kcontrol *ctl; 104662306a36Sopenharmony_ci int j, err; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 104962306a36Sopenharmony_ci template = controls[i]; 105062306a36Sopenharmony_ci if (chip->model.control_filter) { 105162306a36Sopenharmony_ci err = chip->model.control_filter(&template); 105262306a36Sopenharmony_ci if (err < 0) 105362306a36Sopenharmony_ci return err; 105462306a36Sopenharmony_ci if (err == 1) 105562306a36Sopenharmony_ci continue; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci if (!strcmp(template.name, "Stereo Upmixing") && 105862306a36Sopenharmony_ci chip->model.dac_channels_pcm == 2) 105962306a36Sopenharmony_ci continue; 106062306a36Sopenharmony_ci if (!strcmp(template.name, "Mic Source Capture Enum") && 106162306a36Sopenharmony_ci !(chip->model.device_config & AC97_FMIC_SWITCH)) 106262306a36Sopenharmony_ci continue; 106362306a36Sopenharmony_ci if (!strncmp(template.name, "CD Capture ", 11) && 106462306a36Sopenharmony_ci !(chip->model.device_config & AC97_CD_INPUT)) 106562306a36Sopenharmony_ci continue; 106662306a36Sopenharmony_ci if (!strcmp(template.name, "Master Playback Volume") && 106762306a36Sopenharmony_ci chip->model.dac_tlv) { 106862306a36Sopenharmony_ci template.tlv.p = chip->model.dac_tlv; 106962306a36Sopenharmony_ci template.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci ctl = snd_ctl_new1(&template, chip); 107262306a36Sopenharmony_ci if (!ctl) 107362306a36Sopenharmony_ci return -ENOMEM; 107462306a36Sopenharmony_ci err = snd_ctl_add(chip->card, ctl); 107562306a36Sopenharmony_ci if (err < 0) 107662306a36Sopenharmony_ci return err; 107762306a36Sopenharmony_ci j = match_string(known_ctl_names, CONTROL_COUNT, ctl->id.name); 107862306a36Sopenharmony_ci if (j >= 0) { 107962306a36Sopenharmony_ci chip->controls[j] = ctl; 108062306a36Sopenharmony_ci ctl->private_free = oxygen_any_ctl_free; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci return 0; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ciint oxygen_mixer_init(struct oxygen *chip) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci unsigned int i; 108962306a36Sopenharmony_ci int err; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci err = add_controls(chip, controls, ARRAY_SIZE(controls)); 109262306a36Sopenharmony_ci if (err < 0) 109362306a36Sopenharmony_ci return err; 109462306a36Sopenharmony_ci if (chip->model.device_config & PLAYBACK_1_TO_SPDIF) { 109562306a36Sopenharmony_ci err = add_controls(chip, spdif_output_controls, 109662306a36Sopenharmony_ci ARRAY_SIZE(spdif_output_controls)); 109762306a36Sopenharmony_ci if (err < 0) 109862306a36Sopenharmony_ci return err; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) { 110162306a36Sopenharmony_ci err = add_controls(chip, spdif_input_controls, 110262306a36Sopenharmony_ci ARRAY_SIZE(spdif_input_controls)); 110362306a36Sopenharmony_ci if (err < 0) 110462306a36Sopenharmony_ci return err; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(monitor_controls); ++i) { 110762306a36Sopenharmony_ci if (!(chip->model.device_config & monitor_controls[i].pcm_dev)) 110862306a36Sopenharmony_ci continue; 110962306a36Sopenharmony_ci err = add_controls(chip, monitor_controls[i].controls, 111062306a36Sopenharmony_ci ARRAY_SIZE(monitor_controls[i].controls)); 111162306a36Sopenharmony_ci if (err < 0) 111262306a36Sopenharmony_ci return err; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci if (chip->has_ac97_0) { 111562306a36Sopenharmony_ci err = add_controls(chip, ac97_controls, 111662306a36Sopenharmony_ci ARRAY_SIZE(ac97_controls)); 111762306a36Sopenharmony_ci if (err < 0) 111862306a36Sopenharmony_ci return err; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci if (chip->has_ac97_1) { 112162306a36Sopenharmony_ci err = add_controls(chip, ac97_fp_controls, 112262306a36Sopenharmony_ci ARRAY_SIZE(ac97_fp_controls)); 112362306a36Sopenharmony_ci if (err < 0) 112462306a36Sopenharmony_ci return err; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci return chip->model.mixer_init ? chip->model.mixer_init(chip) : 0; 112762306a36Sopenharmony_ci} 1128