18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Digigram VX soundcards 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Common mixer part 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <sound/core.h> 118c2ecf20Sopenharmony_ci#include <sound/control.h> 128c2ecf20Sopenharmony_ci#include <sound/tlv.h> 138c2ecf20Sopenharmony_ci#include <sound/vx_core.h> 148c2ecf20Sopenharmony_ci#include "vx_cmd.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * write a codec data (24bit) 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_cistatic void vx_write_codec_reg(struct vx_core *chip, int codec, unsigned int data) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci if (snd_BUG_ON(!chip->ops->write_codec)) 238c2ecf20Sopenharmony_ci return; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci if (chip->chip_status & VX_STAT_IS_STALE) 268c2ecf20Sopenharmony_ci return; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci mutex_lock(&chip->lock); 298c2ecf20Sopenharmony_ci chip->ops->write_codec(chip, codec, data); 308c2ecf20Sopenharmony_ci mutex_unlock(&chip->lock); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * Data type used to access the Codec 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ciunion vx_codec_data { 378c2ecf20Sopenharmony_ci u32 l; 388c2ecf20Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN 398c2ecf20Sopenharmony_ci struct w { 408c2ecf20Sopenharmony_ci u16 h; 418c2ecf20Sopenharmony_ci u16 l; 428c2ecf20Sopenharmony_ci } w; 438c2ecf20Sopenharmony_ci struct b { 448c2ecf20Sopenharmony_ci u8 hh; 458c2ecf20Sopenharmony_ci u8 mh; 468c2ecf20Sopenharmony_ci u8 ml; 478c2ecf20Sopenharmony_ci u8 ll; 488c2ecf20Sopenharmony_ci } b; 498c2ecf20Sopenharmony_ci#else /* LITTLE_ENDIAN */ 508c2ecf20Sopenharmony_ci struct w { 518c2ecf20Sopenharmony_ci u16 l; 528c2ecf20Sopenharmony_ci u16 h; 538c2ecf20Sopenharmony_ci } w; 548c2ecf20Sopenharmony_ci struct b { 558c2ecf20Sopenharmony_ci u8 ll; 568c2ecf20Sopenharmony_ci u8 ml; 578c2ecf20Sopenharmony_ci u8 mh; 588c2ecf20Sopenharmony_ci u8 hh; 598c2ecf20Sopenharmony_ci } b; 608c2ecf20Sopenharmony_ci#endif 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define SET_CDC_DATA_SEL(di,s) ((di).b.mh = (u8) (s)) 648c2ecf20Sopenharmony_ci#define SET_CDC_DATA_REG(di,r) ((di).b.ml = (u8) (r)) 658c2ecf20Sopenharmony_ci#define SET_CDC_DATA_VAL(di,d) ((di).b.ll = (u8) (d)) 668c2ecf20Sopenharmony_ci#define SET_CDC_DATA_INIT(di) ((di).l = 0L, SET_CDC_DATA_SEL(di,XX_CODEC_SELECTOR)) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * set up codec register and write the value 708c2ecf20Sopenharmony_ci * @codec: the codec id, 0 or 1 718c2ecf20Sopenharmony_ci * @reg: register index 728c2ecf20Sopenharmony_ci * @val: data value 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_cistatic void vx_set_codec_reg(struct vx_core *chip, int codec, int reg, int val) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci union vx_codec_data data; 778c2ecf20Sopenharmony_ci /* DAC control register */ 788c2ecf20Sopenharmony_ci SET_CDC_DATA_INIT(data); 798c2ecf20Sopenharmony_ci SET_CDC_DATA_REG(data, reg); 808c2ecf20Sopenharmony_ci SET_CDC_DATA_VAL(data, val); 818c2ecf20Sopenharmony_ci vx_write_codec_reg(chip, codec, data.l); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * vx_set_analog_output_level - set the output attenuation level 878c2ecf20Sopenharmony_ci * @codec: the output codec, 0 or 1. (1 for VXP440 only) 888c2ecf20Sopenharmony_ci * @left: left output level, 0 = mute 898c2ecf20Sopenharmony_ci * @right: right output level 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_cistatic void vx_set_analog_output_level(struct vx_core *chip, int codec, int left, int right) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci left = chip->hw->output_level_max - left; 948c2ecf20Sopenharmony_ci right = chip->hw->output_level_max - right; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (chip->ops->akm_write) { 978c2ecf20Sopenharmony_ci chip->ops->akm_write(chip, XX_CODEC_LEVEL_LEFT_REGISTER, left); 988c2ecf20Sopenharmony_ci chip->ops->akm_write(chip, XX_CODEC_LEVEL_RIGHT_REGISTER, right); 998c2ecf20Sopenharmony_ci } else { 1008c2ecf20Sopenharmony_ci /* convert to attenuation level: 0 = 0dB (max), 0xe3 = -113.5 dB (min) */ 1018c2ecf20Sopenharmony_ci vx_set_codec_reg(chip, codec, XX_CODEC_LEVEL_LEFT_REGISTER, left); 1028c2ecf20Sopenharmony_ci vx_set_codec_reg(chip, codec, XX_CODEC_LEVEL_RIGHT_REGISTER, right); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* 1088c2ecf20Sopenharmony_ci * vx_toggle_dac_mute - mute/unmute DAC 1098c2ecf20Sopenharmony_ci * @mute: 0 = unmute, 1 = mute 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define DAC_ATTEN_MIN 0x08 1138c2ecf20Sopenharmony_ci#define DAC_ATTEN_MAX 0x38 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid vx_toggle_dac_mute(struct vx_core *chip, int mute) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci unsigned int i; 1188c2ecf20Sopenharmony_ci for (i = 0; i < chip->hw->num_codecs; i++) { 1198c2ecf20Sopenharmony_ci if (chip->ops->akm_write) 1208c2ecf20Sopenharmony_ci chip->ops->akm_write(chip, XX_CODEC_DAC_CONTROL_REGISTER, mute); /* XXX */ 1218c2ecf20Sopenharmony_ci else 1228c2ecf20Sopenharmony_ci vx_set_codec_reg(chip, i, XX_CODEC_DAC_CONTROL_REGISTER, 1238c2ecf20Sopenharmony_ci mute ? DAC_ATTEN_MAX : DAC_ATTEN_MIN); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * vx_reset_codec - reset and initialize the codecs 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_civoid vx_reset_codec(struct vx_core *chip, int cold_reset) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci unsigned int i; 1338c2ecf20Sopenharmony_ci int port = chip->type >= VX_TYPE_VXPOCKET ? 0x75 : 0x65; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci chip->ops->reset_codec(chip); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* AKM codecs should be initialized in reset_codec callback */ 1388c2ecf20Sopenharmony_ci if (! chip->ops->akm_write) { 1398c2ecf20Sopenharmony_ci /* initialize old codecs */ 1408c2ecf20Sopenharmony_ci for (i = 0; i < chip->hw->num_codecs; i++) { 1418c2ecf20Sopenharmony_ci /* DAC control register (change level when zero crossing + mute) */ 1428c2ecf20Sopenharmony_ci vx_set_codec_reg(chip, i, XX_CODEC_DAC_CONTROL_REGISTER, DAC_ATTEN_MAX); 1438c2ecf20Sopenharmony_ci /* ADC control register */ 1448c2ecf20Sopenharmony_ci vx_set_codec_reg(chip, i, XX_CODEC_ADC_CONTROL_REGISTER, 0x00); 1458c2ecf20Sopenharmony_ci /* Port mode register */ 1468c2ecf20Sopenharmony_ci vx_set_codec_reg(chip, i, XX_CODEC_PORT_MODE_REGISTER, port); 1478c2ecf20Sopenharmony_ci /* Clock control register */ 1488c2ecf20Sopenharmony_ci vx_set_codec_reg(chip, i, XX_CODEC_CLOCK_CONTROL_REGISTER, 0x00); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* mute analog output */ 1538c2ecf20Sopenharmony_ci for (i = 0; i < chip->hw->num_codecs; i++) { 1548c2ecf20Sopenharmony_ci chip->output_level[i][0] = 0; 1558c2ecf20Sopenharmony_ci chip->output_level[i][1] = 0; 1568c2ecf20Sopenharmony_ci vx_set_analog_output_level(chip, i, 0, 0); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* 1618c2ecf20Sopenharmony_ci * change the audio input source 1628c2ecf20Sopenharmony_ci * @src: the target source (VX_AUDIO_SRC_XXX) 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_cistatic void vx_change_audio_source(struct vx_core *chip, int src) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci if (chip->chip_status & VX_STAT_IS_STALE) 1678c2ecf20Sopenharmony_ci return; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci mutex_lock(&chip->lock); 1708c2ecf20Sopenharmony_ci chip->ops->change_audio_source(chip, src); 1718c2ecf20Sopenharmony_ci mutex_unlock(&chip->lock); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* 1768c2ecf20Sopenharmony_ci * change the audio source if necessary and possible 1778c2ecf20Sopenharmony_ci * returns 1 if the source is actually changed. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ciint vx_sync_audio_source(struct vx_core *chip) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (chip->audio_source_target == chip->audio_source || 1828c2ecf20Sopenharmony_ci chip->pcm_running) 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci vx_change_audio_source(chip, chip->audio_source_target); 1858c2ecf20Sopenharmony_ci chip->audio_source = chip->audio_source_target; 1868c2ecf20Sopenharmony_ci return 1; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * audio level, mute, monitoring 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_cistruct vx_audio_level { 1948c2ecf20Sopenharmony_ci unsigned int has_level: 1; 1958c2ecf20Sopenharmony_ci unsigned int has_monitor_level: 1; 1968c2ecf20Sopenharmony_ci unsigned int has_mute: 1; 1978c2ecf20Sopenharmony_ci unsigned int has_monitor_mute: 1; 1988c2ecf20Sopenharmony_ci unsigned int mute; 1998c2ecf20Sopenharmony_ci unsigned int monitor_mute; 2008c2ecf20Sopenharmony_ci short level; 2018c2ecf20Sopenharmony_ci short monitor_level; 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int vx_adjust_audio_level(struct vx_core *chip, int audio, int capture, 2058c2ecf20Sopenharmony_ci struct vx_audio_level *info) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct vx_rmh rmh; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (chip->chip_status & VX_STAT_IS_STALE) 2108c2ecf20Sopenharmony_ci return -EBUSY; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci vx_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); 2138c2ecf20Sopenharmony_ci if (capture) 2148c2ecf20Sopenharmony_ci rmh.Cmd[0] |= COMMAND_RECORD_MASK; 2158c2ecf20Sopenharmony_ci /* Add Audio IO mask */ 2168c2ecf20Sopenharmony_ci rmh.Cmd[1] = 1 << audio; 2178c2ecf20Sopenharmony_ci rmh.Cmd[2] = 0; 2188c2ecf20Sopenharmony_ci if (info->has_level) { 2198c2ecf20Sopenharmony_ci rmh.Cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; 2208c2ecf20Sopenharmony_ci rmh.Cmd[2] |= info->level; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci if (info->has_monitor_level) { 2238c2ecf20Sopenharmony_ci rmh.Cmd[0] |= VALID_AUDIO_IO_MONITORING_LEVEL; 2248c2ecf20Sopenharmony_ci rmh.Cmd[2] |= ((unsigned int)info->monitor_level << 10); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci if (info->has_mute) { 2278c2ecf20Sopenharmony_ci rmh.Cmd[0] |= VALID_AUDIO_IO_MUTE_LEVEL; 2288c2ecf20Sopenharmony_ci if (info->mute) 2298c2ecf20Sopenharmony_ci rmh.Cmd[2] |= AUDIO_IO_HAS_MUTE_LEVEL; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci if (info->has_monitor_mute) { 2328c2ecf20Sopenharmony_ci /* validate flag for M2 at least to unmute it */ 2338c2ecf20Sopenharmony_ci rmh.Cmd[0] |= VALID_AUDIO_IO_MUTE_MONITORING_1 | VALID_AUDIO_IO_MUTE_MONITORING_2; 2348c2ecf20Sopenharmony_ci if (info->monitor_mute) 2358c2ecf20Sopenharmony_ci rmh.Cmd[2] |= AUDIO_IO_HAS_MUTE_MONITORING_1; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return vx_send_msg(chip, &rmh); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#if 0 // not used 2438c2ecf20Sopenharmony_cistatic int vx_read_audio_level(struct vx_core *chip, int audio, int capture, 2448c2ecf20Sopenharmony_ci struct vx_audio_level *info) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci int err; 2478c2ecf20Sopenharmony_ci struct vx_rmh rmh; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 2508c2ecf20Sopenharmony_ci vx_init_rmh(&rmh, CMD_GET_AUDIO_LEVELS); 2518c2ecf20Sopenharmony_ci if (capture) 2528c2ecf20Sopenharmony_ci rmh.Cmd[0] |= COMMAND_RECORD_MASK; 2538c2ecf20Sopenharmony_ci /* Add Audio IO mask */ 2548c2ecf20Sopenharmony_ci rmh.Cmd[1] = 1 << audio; 2558c2ecf20Sopenharmony_ci err = vx_send_msg(chip, &rmh); 2568c2ecf20Sopenharmony_ci if (err < 0) 2578c2ecf20Sopenharmony_ci return err; 2588c2ecf20Sopenharmony_ci info.level = rmh.Stat[0] & MASK_DSP_WORD_LEVEL; 2598c2ecf20Sopenharmony_ci info.monitor_level = (rmh.Stat[0] >> 10) & MASK_DSP_WORD_LEVEL; 2608c2ecf20Sopenharmony_ci info.mute = (rmh.Stat[i] & AUDIO_IO_HAS_MUTE_LEVEL) ? 1 : 0; 2618c2ecf20Sopenharmony_ci info.monitor_mute = (rmh.Stat[i] & AUDIO_IO_HAS_MUTE_MONITORING_1) ? 1 : 0; 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci#endif // not used 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* 2678c2ecf20Sopenharmony_ci * set the monitoring level and mute state of the given audio 2688c2ecf20Sopenharmony_ci * no more static, because must be called from vx_pcm to demute monitoring 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ciint vx_set_monitor_level(struct vx_core *chip, int audio, int level, int active) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct vx_audio_level info; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 2758c2ecf20Sopenharmony_ci info.has_monitor_level = 1; 2768c2ecf20Sopenharmony_ci info.monitor_level = level; 2778c2ecf20Sopenharmony_ci info.has_monitor_mute = 1; 2788c2ecf20Sopenharmony_ci info.monitor_mute = !active; 2798c2ecf20Sopenharmony_ci chip->audio_monitor[audio] = level; 2808c2ecf20Sopenharmony_ci chip->audio_monitor_active[audio] = active; 2818c2ecf20Sopenharmony_ci return vx_adjust_audio_level(chip, audio, 0, &info); /* playback only */ 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* 2868c2ecf20Sopenharmony_ci * set the mute status of the given audio 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_cistatic int vx_set_audio_switch(struct vx_core *chip, int audio, int active) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct vx_audio_level info; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 2938c2ecf20Sopenharmony_ci info.has_mute = 1; 2948c2ecf20Sopenharmony_ci info.mute = !active; 2958c2ecf20Sopenharmony_ci chip->audio_active[audio] = active; 2968c2ecf20Sopenharmony_ci return vx_adjust_audio_level(chip, audio, 0, &info); /* playback only */ 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* 3008c2ecf20Sopenharmony_ci * set the mute status of the given audio 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic int vx_set_audio_gain(struct vx_core *chip, int audio, int capture, int level) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct vx_audio_level info; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 3078c2ecf20Sopenharmony_ci info.has_level = 1; 3088c2ecf20Sopenharmony_ci info.level = level; 3098c2ecf20Sopenharmony_ci chip->audio_gain[capture][audio] = level; 3108c2ecf20Sopenharmony_ci return vx_adjust_audio_level(chip, audio, capture, &info); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* 3148c2ecf20Sopenharmony_ci * reset all audio levels 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_cistatic void vx_reset_audio_levels(struct vx_core *chip) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci unsigned int i, c; 3198c2ecf20Sopenharmony_ci struct vx_audio_level info; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci memset(chip->audio_gain, 0, sizeof(chip->audio_gain)); 3228c2ecf20Sopenharmony_ci memset(chip->audio_active, 0, sizeof(chip->audio_active)); 3238c2ecf20Sopenharmony_ci memset(chip->audio_monitor, 0, sizeof(chip->audio_monitor)); 3248c2ecf20Sopenharmony_ci memset(chip->audio_monitor_active, 0, sizeof(chip->audio_monitor_active)); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci for (c = 0; c < 2; c++) { 3278c2ecf20Sopenharmony_ci for (i = 0; i < chip->hw->num_ins * 2; i++) { 3288c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 3298c2ecf20Sopenharmony_ci if (c == 0) { 3308c2ecf20Sopenharmony_ci info.has_monitor_level = 1; 3318c2ecf20Sopenharmony_ci info.has_mute = 1; 3328c2ecf20Sopenharmony_ci info.has_monitor_mute = 1; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci info.has_level = 1; 3358c2ecf20Sopenharmony_ci info.level = CVAL_0DB; /* default: 0dB */ 3368c2ecf20Sopenharmony_ci vx_adjust_audio_level(chip, i, c, &info); 3378c2ecf20Sopenharmony_ci chip->audio_gain[c][i] = CVAL_0DB; 3388c2ecf20Sopenharmony_ci chip->audio_monitor[i] = CVAL_0DB; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* 3458c2ecf20Sopenharmony_ci * VU, peak meter record 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci#define VU_METER_CHANNELS 2 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistruct vx_vu_meter { 3518c2ecf20Sopenharmony_ci int saturated; 3528c2ecf20Sopenharmony_ci int vu_level; 3538c2ecf20Sopenharmony_ci int peak_level; 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/* 3578c2ecf20Sopenharmony_ci * get the VU and peak meter values 3588c2ecf20Sopenharmony_ci * @audio: the audio index 3598c2ecf20Sopenharmony_ci * @capture: 0 = playback, 1 = capture operation 3608c2ecf20Sopenharmony_ci * @info: the array of vx_vu_meter records (size = 2). 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_cistatic int vx_get_audio_vu_meter(struct vx_core *chip, int audio, int capture, struct vx_vu_meter *info) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct vx_rmh rmh; 3658c2ecf20Sopenharmony_ci int i, err; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (chip->chip_status & VX_STAT_IS_STALE) 3688c2ecf20Sopenharmony_ci return -EBUSY; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci vx_init_rmh(&rmh, CMD_AUDIO_VU_PIC_METER); 3718c2ecf20Sopenharmony_ci rmh.LgStat += 2 * VU_METER_CHANNELS; 3728c2ecf20Sopenharmony_ci if (capture) 3738c2ecf20Sopenharmony_ci rmh.Cmd[0] |= COMMAND_RECORD_MASK; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Add Audio IO mask */ 3768c2ecf20Sopenharmony_ci rmh.Cmd[1] = 0; 3778c2ecf20Sopenharmony_ci for (i = 0; i < VU_METER_CHANNELS; i++) 3788c2ecf20Sopenharmony_ci rmh.Cmd[1] |= 1 << (audio + i); 3798c2ecf20Sopenharmony_ci err = vx_send_msg(chip, &rmh); 3808c2ecf20Sopenharmony_ci if (err < 0) 3818c2ecf20Sopenharmony_ci return err; 3828c2ecf20Sopenharmony_ci /* Read response */ 3838c2ecf20Sopenharmony_ci for (i = 0; i < 2 * VU_METER_CHANNELS; i +=2) { 3848c2ecf20Sopenharmony_ci info->saturated = (rmh.Stat[0] & (1 << (audio + i))) ? 1 : 0; 3858c2ecf20Sopenharmony_ci info->vu_level = rmh.Stat[i + 1]; 3868c2ecf20Sopenharmony_ci info->peak_level = rmh.Stat[i + 2]; 3878c2ecf20Sopenharmony_ci info++; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci/* 3948c2ecf20Sopenharmony_ci * control API entries 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/* 3988c2ecf20Sopenharmony_ci * output level control 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_cistatic int vx_output_level_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 4038c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4048c2ecf20Sopenharmony_ci uinfo->count = 2; 4058c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 4068c2ecf20Sopenharmony_ci uinfo->value.integer.max = chip->hw->output_level_max; 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int vx_output_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 4138c2ecf20Sopenharmony_ci int codec = kcontrol->id.index; 4148c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 4158c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->output_level[codec][0]; 4168c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->output_level[codec][1]; 4178c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 4248c2ecf20Sopenharmony_ci int codec = kcontrol->id.index; 4258c2ecf20Sopenharmony_ci unsigned int val[2], vmax; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci vmax = chip->hw->output_level_max; 4288c2ecf20Sopenharmony_ci val[0] = ucontrol->value.integer.value[0]; 4298c2ecf20Sopenharmony_ci val[1] = ucontrol->value.integer.value[1]; 4308c2ecf20Sopenharmony_ci if (val[0] > vmax || val[1] > vmax) 4318c2ecf20Sopenharmony_ci return -EINVAL; 4328c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 4338c2ecf20Sopenharmony_ci if (val[0] != chip->output_level[codec][0] || 4348c2ecf20Sopenharmony_ci val[1] != chip->output_level[codec][1]) { 4358c2ecf20Sopenharmony_ci vx_set_analog_output_level(chip, codec, val[0], val[1]); 4368c2ecf20Sopenharmony_ci chip->output_level[codec][0] = val[0]; 4378c2ecf20Sopenharmony_ci chip->output_level[codec][1] = val[1]; 4388c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 4398c2ecf20Sopenharmony_ci return 1; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_output_level = { 4468c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4478c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 4488c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 4498c2ecf20Sopenharmony_ci .name = "Master Playback Volume", 4508c2ecf20Sopenharmony_ci .info = vx_output_level_info, 4518c2ecf20Sopenharmony_ci .get = vx_output_level_get, 4528c2ecf20Sopenharmony_ci .put = vx_output_level_put, 4538c2ecf20Sopenharmony_ci /* tlv will be filled later */ 4548c2ecf20Sopenharmony_ci}; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci/* 4578c2ecf20Sopenharmony_ci * audio source select 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_cistatic int vx_audio_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci static const char * const texts_mic[3] = { 4628c2ecf20Sopenharmony_ci "Digital", "Line", "Mic" 4638c2ecf20Sopenharmony_ci }; 4648c2ecf20Sopenharmony_ci static const char * const texts_vx2[2] = { 4658c2ecf20Sopenharmony_ci "Digital", "Analog" 4668c2ecf20Sopenharmony_ci }; 4678c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (chip->type >= VX_TYPE_VXPOCKET) 4708c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 3, texts_mic); 4718c2ecf20Sopenharmony_ci else 4728c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts_vx2); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int vx_audio_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 4788c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = chip->audio_source_target; 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (chip->type >= VX_TYPE_VXPOCKET) { 4878c2ecf20Sopenharmony_ci if (ucontrol->value.enumerated.item[0] > 2) 4888c2ecf20Sopenharmony_ci return -EINVAL; 4898c2ecf20Sopenharmony_ci } else { 4908c2ecf20Sopenharmony_ci if (ucontrol->value.enumerated.item[0] > 1) 4918c2ecf20Sopenharmony_ci return -EINVAL; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 4948c2ecf20Sopenharmony_ci if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) { 4958c2ecf20Sopenharmony_ci chip->audio_source_target = ucontrol->value.enumerated.item[0]; 4968c2ecf20Sopenharmony_ci vx_sync_audio_source(chip); 4978c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 4988c2ecf20Sopenharmony_ci return 1; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_audio_src = { 5058c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5068c2ecf20Sopenharmony_ci .name = "Capture Source", 5078c2ecf20Sopenharmony_ci .info = vx_audio_src_info, 5088c2ecf20Sopenharmony_ci .get = vx_audio_src_get, 5098c2ecf20Sopenharmony_ci .put = vx_audio_src_put, 5108c2ecf20Sopenharmony_ci}; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/* 5138c2ecf20Sopenharmony_ci * clock mode selection 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_cistatic int vx_clock_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci static const char * const texts[3] = { 5188c2ecf20Sopenharmony_ci "Auto", "Internal", "External" 5198c2ecf20Sopenharmony_ci }; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 3, texts); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int vx_clock_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 5278c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = chip->clock_mode; 5288c2ecf20Sopenharmony_ci return 0; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (ucontrol->value.enumerated.item[0] > 2) 5368c2ecf20Sopenharmony_ci return -EINVAL; 5378c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 5388c2ecf20Sopenharmony_ci if (chip->clock_mode != ucontrol->value.enumerated.item[0]) { 5398c2ecf20Sopenharmony_ci chip->clock_mode = ucontrol->value.enumerated.item[0]; 5408c2ecf20Sopenharmony_ci vx_set_clock(chip, chip->freq); 5418c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 5428c2ecf20Sopenharmony_ci return 1; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 5458c2ecf20Sopenharmony_ci return 0; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_clock_mode = { 5498c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5508c2ecf20Sopenharmony_ci .name = "Clock Mode", 5518c2ecf20Sopenharmony_ci .info = vx_clock_mode_info, 5528c2ecf20Sopenharmony_ci .get = vx_clock_mode_get, 5538c2ecf20Sopenharmony_ci .put = vx_clock_mode_put, 5548c2ecf20Sopenharmony_ci}; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/* 5578c2ecf20Sopenharmony_ci * Audio Gain 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_cistatic int vx_audio_gain_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 5628c2ecf20Sopenharmony_ci uinfo->count = 2; 5638c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 5648c2ecf20Sopenharmony_ci uinfo->value.integer.max = CVAL_MAX; 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int vx_audio_gain_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 5718c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 5728c2ecf20Sopenharmony_ci int capture = (kcontrol->private_value >> 8) & 1; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 5758c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->audio_gain[capture][audio]; 5768c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->audio_gain[capture][audio+1]; 5778c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int vx_audio_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 5848c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 5858c2ecf20Sopenharmony_ci int capture = (kcontrol->private_value >> 8) & 1; 5868c2ecf20Sopenharmony_ci unsigned int val[2]; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci val[0] = ucontrol->value.integer.value[0]; 5898c2ecf20Sopenharmony_ci val[1] = ucontrol->value.integer.value[1]; 5908c2ecf20Sopenharmony_ci if (val[0] > CVAL_MAX || val[1] > CVAL_MAX) 5918c2ecf20Sopenharmony_ci return -EINVAL; 5928c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 5938c2ecf20Sopenharmony_ci if (val[0] != chip->audio_gain[capture][audio] || 5948c2ecf20Sopenharmony_ci val[1] != chip->audio_gain[capture][audio+1]) { 5958c2ecf20Sopenharmony_ci vx_set_audio_gain(chip, audio, capture, val[0]); 5968c2ecf20Sopenharmony_ci vx_set_audio_gain(chip, audio+1, capture, val[1]); 5978c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 5988c2ecf20Sopenharmony_ci return 1; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic int vx_audio_monitor_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 6078c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 6108c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->audio_monitor[audio]; 6118c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->audio_monitor[audio+1]; 6128c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic int vx_audio_monitor_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 6198c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 6208c2ecf20Sopenharmony_ci unsigned int val[2]; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci val[0] = ucontrol->value.integer.value[0]; 6238c2ecf20Sopenharmony_ci val[1] = ucontrol->value.integer.value[1]; 6248c2ecf20Sopenharmony_ci if (val[0] > CVAL_MAX || val[1] > CVAL_MAX) 6258c2ecf20Sopenharmony_ci return -EINVAL; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 6288c2ecf20Sopenharmony_ci if (val[0] != chip->audio_monitor[audio] || 6298c2ecf20Sopenharmony_ci val[1] != chip->audio_monitor[audio+1]) { 6308c2ecf20Sopenharmony_ci vx_set_monitor_level(chip, audio, val[0], 6318c2ecf20Sopenharmony_ci chip->audio_monitor_active[audio]); 6328c2ecf20Sopenharmony_ci vx_set_monitor_level(chip, audio+1, val[1], 6338c2ecf20Sopenharmony_ci chip->audio_monitor_active[audio+1]); 6348c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6358c2ecf20Sopenharmony_ci return 1; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6388c2ecf20Sopenharmony_ci return 0; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci#define vx_audio_sw_info snd_ctl_boolean_stereo_info 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int vx_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 6468c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 6498c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->audio_active[audio]; 6508c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->audio_active[audio+1]; 6518c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic int vx_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 6588c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 6618c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0] != chip->audio_active[audio] || 6628c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) { 6638c2ecf20Sopenharmony_ci vx_set_audio_switch(chip, audio, 6648c2ecf20Sopenharmony_ci !!ucontrol->value.integer.value[0]); 6658c2ecf20Sopenharmony_ci vx_set_audio_switch(chip, audio+1, 6668c2ecf20Sopenharmony_ci !!ucontrol->value.integer.value[1]); 6678c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6688c2ecf20Sopenharmony_ci return 1; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6718c2ecf20Sopenharmony_ci return 0; 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic int vx_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 6778c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 6808c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->audio_monitor_active[audio]; 6818c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->audio_monitor_active[audio+1]; 6828c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 6898c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 6928c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] || 6938c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) { 6948c2ecf20Sopenharmony_ci vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], 6958c2ecf20Sopenharmony_ci !!ucontrol->value.integer.value[0]); 6968c2ecf20Sopenharmony_ci vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], 6978c2ecf20Sopenharmony_ci !!ucontrol->value.integer.value[1]); 6988c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 6998c2ecf20Sopenharmony_ci return 1; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_audio_gain = { 7088c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7098c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 7108c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 7118c2ecf20Sopenharmony_ci /* name will be filled later */ 7128c2ecf20Sopenharmony_ci .info = vx_audio_gain_info, 7138c2ecf20Sopenharmony_ci .get = vx_audio_gain_get, 7148c2ecf20Sopenharmony_ci .put = vx_audio_gain_put, 7158c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_audio_gain }, 7168c2ecf20Sopenharmony_ci}; 7178c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_output_switch = { 7188c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7198c2ecf20Sopenharmony_ci .name = "PCM Playback Switch", 7208c2ecf20Sopenharmony_ci .info = vx_audio_sw_info, 7218c2ecf20Sopenharmony_ci .get = vx_audio_sw_get, 7228c2ecf20Sopenharmony_ci .put = vx_audio_sw_put 7238c2ecf20Sopenharmony_ci}; 7248c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_monitor_gain = { 7258c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7268c2ecf20Sopenharmony_ci .name = "Monitoring Volume", 7278c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 7288c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 7298c2ecf20Sopenharmony_ci .info = vx_audio_gain_info, /* shared */ 7308c2ecf20Sopenharmony_ci .get = vx_audio_monitor_get, 7318c2ecf20Sopenharmony_ci .put = vx_audio_monitor_put, 7328c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_audio_gain }, 7338c2ecf20Sopenharmony_ci}; 7348c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_monitor_switch = { 7358c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7368c2ecf20Sopenharmony_ci .name = "Monitoring Switch", 7378c2ecf20Sopenharmony_ci .info = vx_audio_sw_info, /* shared */ 7388c2ecf20Sopenharmony_ci .get = vx_monitor_sw_get, 7398c2ecf20Sopenharmony_ci .put = vx_monitor_sw_put 7408c2ecf20Sopenharmony_ci}; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/* 7448c2ecf20Sopenharmony_ci * IEC958 status bits 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_cistatic int vx_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 7498c2ecf20Sopenharmony_ci uinfo->count = 1; 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic int vx_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 7588c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = (chip->uer_bits >> 0) & 0xff; 7598c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = (chip->uer_bits >> 8) & 0xff; 7608c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[2] = (chip->uer_bits >> 16) & 0xff; 7618c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = (chip->uer_bits >> 24) & 0xff; 7628c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int vx_iec958_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = 0xff; 7698c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = 0xff; 7708c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[2] = 0xff; 7718c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = 0xff; 7728c2ecf20Sopenharmony_ci return 0; 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic int vx_iec958_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 7788c2ecf20Sopenharmony_ci unsigned int val; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci val = (ucontrol->value.iec958.status[0] << 0) | 7818c2ecf20Sopenharmony_ci (ucontrol->value.iec958.status[1] << 8) | 7828c2ecf20Sopenharmony_ci (ucontrol->value.iec958.status[2] << 16) | 7838c2ecf20Sopenharmony_ci (ucontrol->value.iec958.status[3] << 24); 7848c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_mutex); 7858c2ecf20Sopenharmony_ci if (chip->uer_bits != val) { 7868c2ecf20Sopenharmony_ci chip->uer_bits = val; 7878c2ecf20Sopenharmony_ci vx_set_iec958_status(chip, val); 7888c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 7898c2ecf20Sopenharmony_ci return 1; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_mutex); 7928c2ecf20Sopenharmony_ci return 0; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_iec958_mask = { 7968c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 7978c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 7988c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 7998c2ecf20Sopenharmony_ci .info = vx_iec958_info, /* shared */ 8008c2ecf20Sopenharmony_ci .get = vx_iec958_mask_get, 8018c2ecf20Sopenharmony_ci}; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_iec958 = { 8048c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8058c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 8068c2ecf20Sopenharmony_ci .info = vx_iec958_info, 8078c2ecf20Sopenharmony_ci .get = vx_iec958_get, 8088c2ecf20Sopenharmony_ci .put = vx_iec958_put 8098c2ecf20Sopenharmony_ci}; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci/* 8138c2ecf20Sopenharmony_ci * VU meter 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci#define METER_MAX 0xff 8178c2ecf20Sopenharmony_ci#define METER_SHIFT 16 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic int vx_vu_meter_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 8228c2ecf20Sopenharmony_ci uinfo->count = 2; 8238c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 8248c2ecf20Sopenharmony_ci uinfo->value.integer.max = METER_MAX; 8258c2ecf20Sopenharmony_ci return 0; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic int vx_vu_meter_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 8318c2ecf20Sopenharmony_ci struct vx_vu_meter meter[2]; 8328c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 8338c2ecf20Sopenharmony_ci int capture = (kcontrol->private_value >> 8) & 1; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci vx_get_audio_vu_meter(chip, audio, capture, meter); 8368c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = meter[0].vu_level >> METER_SHIFT; 8378c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = meter[1].vu_level >> METER_SHIFT; 8388c2ecf20Sopenharmony_ci return 0; 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic int vx_peak_meter_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 8448c2ecf20Sopenharmony_ci struct vx_vu_meter meter[2]; 8458c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 8468c2ecf20Sopenharmony_ci int capture = (kcontrol->private_value >> 8) & 1; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci vx_get_audio_vu_meter(chip, audio, capture, meter); 8498c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = meter[0].peak_level >> METER_SHIFT; 8508c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = meter[1].peak_level >> METER_SHIFT; 8518c2ecf20Sopenharmony_ci return 0; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci#define vx_saturation_info snd_ctl_boolean_stereo_info 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic int vx_saturation_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci struct vx_core *chip = snd_kcontrol_chip(kcontrol); 8598c2ecf20Sopenharmony_ci struct vx_vu_meter meter[2]; 8608c2ecf20Sopenharmony_ci int audio = kcontrol->private_value & 0xff; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci vx_get_audio_vu_meter(chip, audio, 1, meter); /* capture only */ 8638c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = meter[0].saturated; 8648c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = meter[1].saturated; 8658c2ecf20Sopenharmony_ci return 0; 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_vu_meter = { 8698c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8708c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8718c2ecf20Sopenharmony_ci /* name will be filled later */ 8728c2ecf20Sopenharmony_ci .info = vx_vu_meter_info, 8738c2ecf20Sopenharmony_ci .get = vx_vu_meter_get, 8748c2ecf20Sopenharmony_ci}; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_peak_meter = { 8778c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8788c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8798c2ecf20Sopenharmony_ci /* name will be filled later */ 8808c2ecf20Sopenharmony_ci .info = vx_vu_meter_info, /* shared */ 8818c2ecf20Sopenharmony_ci .get = vx_peak_meter_get, 8828c2ecf20Sopenharmony_ci}; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vx_control_saturation = { 8858c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8868c2ecf20Sopenharmony_ci .name = "Input Saturation", 8878c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8888c2ecf20Sopenharmony_ci .info = vx_saturation_info, 8898c2ecf20Sopenharmony_ci .get = vx_saturation_get, 8908c2ecf20Sopenharmony_ci}; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci/* 8958c2ecf20Sopenharmony_ci * 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ciint snd_vx_mixer_new(struct vx_core *chip) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci unsigned int i, c; 9018c2ecf20Sopenharmony_ci int err; 9028c2ecf20Sopenharmony_ci struct snd_kcontrol_new temp; 9038c2ecf20Sopenharmony_ci struct snd_card *card = chip->card; 9048c2ecf20Sopenharmony_ci char name[32]; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci strcpy(card->mixername, card->driver); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* output level controls */ 9098c2ecf20Sopenharmony_ci for (i = 0; i < chip->hw->num_outs; i++) { 9108c2ecf20Sopenharmony_ci temp = vx_control_output_level; 9118c2ecf20Sopenharmony_ci temp.index = i; 9128c2ecf20Sopenharmony_ci temp.tlv.p = chip->hw->output_level_db_scale; 9138c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9148c2ecf20Sopenharmony_ci return err; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* PCM volumes, switches, monitoring */ 9188c2ecf20Sopenharmony_ci for (i = 0; i < chip->hw->num_outs; i++) { 9198c2ecf20Sopenharmony_ci int val = i * 2; 9208c2ecf20Sopenharmony_ci temp = vx_control_audio_gain; 9218c2ecf20Sopenharmony_ci temp.index = i; 9228c2ecf20Sopenharmony_ci temp.name = "PCM Playback Volume"; 9238c2ecf20Sopenharmony_ci temp.private_value = val; 9248c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9258c2ecf20Sopenharmony_ci return err; 9268c2ecf20Sopenharmony_ci temp = vx_control_output_switch; 9278c2ecf20Sopenharmony_ci temp.index = i; 9288c2ecf20Sopenharmony_ci temp.private_value = val; 9298c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9308c2ecf20Sopenharmony_ci return err; 9318c2ecf20Sopenharmony_ci temp = vx_control_monitor_gain; 9328c2ecf20Sopenharmony_ci temp.index = i; 9338c2ecf20Sopenharmony_ci temp.private_value = val; 9348c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9358c2ecf20Sopenharmony_ci return err; 9368c2ecf20Sopenharmony_ci temp = vx_control_monitor_switch; 9378c2ecf20Sopenharmony_ci temp.index = i; 9388c2ecf20Sopenharmony_ci temp.private_value = val; 9398c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9408c2ecf20Sopenharmony_ci return err; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci for (i = 0; i < chip->hw->num_outs; i++) { 9438c2ecf20Sopenharmony_ci temp = vx_control_audio_gain; 9448c2ecf20Sopenharmony_ci temp.index = i; 9458c2ecf20Sopenharmony_ci temp.name = "PCM Capture Volume"; 9468c2ecf20Sopenharmony_ci temp.private_value = (i * 2) | (1 << 8); 9478c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9488c2ecf20Sopenharmony_ci return err; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* Audio source */ 9528c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0) 9538c2ecf20Sopenharmony_ci return err; 9548c2ecf20Sopenharmony_ci /* clock mode */ 9558c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip))) < 0) 9568c2ecf20Sopenharmony_ci return err; 9578c2ecf20Sopenharmony_ci /* IEC958 controls */ 9588c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0) 9598c2ecf20Sopenharmony_ci return err; 9608c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0) 9618c2ecf20Sopenharmony_ci return err; 9628c2ecf20Sopenharmony_ci /* VU, peak, saturation meters */ 9638c2ecf20Sopenharmony_ci for (c = 0; c < 2; c++) { 9648c2ecf20Sopenharmony_ci static const char * const dir[2] = { "Output", "Input" }; 9658c2ecf20Sopenharmony_ci for (i = 0; i < chip->hw->num_ins; i++) { 9668c2ecf20Sopenharmony_ci int val = (i * 2) | (c << 8); 9678c2ecf20Sopenharmony_ci if (c == 1) { 9688c2ecf20Sopenharmony_ci temp = vx_control_saturation; 9698c2ecf20Sopenharmony_ci temp.index = i; 9708c2ecf20Sopenharmony_ci temp.private_value = val; 9718c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9728c2ecf20Sopenharmony_ci return err; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci sprintf(name, "%s VU Meter", dir[c]); 9758c2ecf20Sopenharmony_ci temp = vx_control_vu_meter; 9768c2ecf20Sopenharmony_ci temp.index = i; 9778c2ecf20Sopenharmony_ci temp.name = name; 9788c2ecf20Sopenharmony_ci temp.private_value = val; 9798c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9808c2ecf20Sopenharmony_ci return err; 9818c2ecf20Sopenharmony_ci sprintf(name, "%s Peak Meter", dir[c]); 9828c2ecf20Sopenharmony_ci temp = vx_control_peak_meter; 9838c2ecf20Sopenharmony_ci temp.index = i; 9848c2ecf20Sopenharmony_ci temp.name = name; 9858c2ecf20Sopenharmony_ci temp.private_value = val; 9868c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) 9878c2ecf20Sopenharmony_ci return err; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci vx_reset_audio_levels(chip); 9918c2ecf20Sopenharmony_ci return 0; 9928c2ecf20Sopenharmony_ci} 993