18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci#define __NO_VERSION__ 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * Driver for Digigram pcxhr compatible soundcards 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * mixer callbacks 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (c) 2004 by Digigram <alsa@digigram.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/time.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/mutex.h> 158c2ecf20Sopenharmony_ci#include <sound/core.h> 168c2ecf20Sopenharmony_ci#include "pcxhr.h" 178c2ecf20Sopenharmony_ci#include "pcxhr_hwdep.h" 188c2ecf20Sopenharmony_ci#include "pcxhr_core.h" 198c2ecf20Sopenharmony_ci#include <sound/control.h> 208c2ecf20Sopenharmony_ci#include <sound/tlv.h> 218c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 228c2ecf20Sopenharmony_ci#include "pcxhr_mixer.h" 238c2ecf20Sopenharmony_ci#include "pcxhr_mix22.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define PCXHR_LINE_CAPTURE_LEVEL_MIN 0 /* -112.0 dB */ 268c2ecf20Sopenharmony_ci#define PCXHR_LINE_CAPTURE_LEVEL_MAX 255 /* +15.5 dB */ 278c2ecf20Sopenharmony_ci#define PCXHR_LINE_CAPTURE_ZERO_LEVEL 224 /* 0.0 dB ( 0 dBu -> 0 dBFS ) */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define PCXHR_LINE_PLAYBACK_LEVEL_MIN 0 /* -104.0 dB */ 308c2ecf20Sopenharmony_ci#define PCXHR_LINE_PLAYBACK_LEVEL_MAX 128 /* +24.0 dB */ 318c2ecf20Sopenharmony_ci#define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104 /* 0.0 dB ( 0 dBFS -> 0 dBu ) */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550); 348c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600); 378c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, 408c2ecf20Sopenharmony_ci int is_capture, int channel) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci int err, vol; 438c2ecf20Sopenharmony_ci struct pcxhr_rmh rmh; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); 468c2ecf20Sopenharmony_ci if (is_capture) { 478c2ecf20Sopenharmony_ci rmh.cmd[0] |= IO_NUM_REG_IN_ANA_LEVEL; 488c2ecf20Sopenharmony_ci rmh.cmd[2] = chip->analog_capture_volume[channel]; 498c2ecf20Sopenharmony_ci } else { 508c2ecf20Sopenharmony_ci rmh.cmd[0] |= IO_NUM_REG_OUT_ANA_LEVEL; 518c2ecf20Sopenharmony_ci if (chip->analog_playback_active[channel]) 528c2ecf20Sopenharmony_ci vol = chip->analog_playback_volume[channel]; 538c2ecf20Sopenharmony_ci else 548c2ecf20Sopenharmony_ci vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN; 558c2ecf20Sopenharmony_ci /* playback analog levels are inversed */ 568c2ecf20Sopenharmony_ci rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ 598c2ecf20Sopenharmony_ci rmh.cmd_len = 3; 608c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 618c2ecf20Sopenharmony_ci if (err < 0) { 628c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 638c2ecf20Sopenharmony_ci "error update_analog_audio_level card(%d)" 648c2ecf20Sopenharmony_ci " is_capture(%d) err(%x)\n", 658c2ecf20Sopenharmony_ci chip->chip_idx, is_capture, err); 668c2ecf20Sopenharmony_ci return -EINVAL; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* 728c2ecf20Sopenharmony_ci * analog level control 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_cistatic int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, 758c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 808c2ecf20Sopenharmony_ci uinfo->count = 2; 818c2ecf20Sopenharmony_ci if (kcontrol->private_value == 0) { /* playback */ 828c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) { 838c2ecf20Sopenharmony_ci uinfo->value.integer.min = 848c2ecf20Sopenharmony_ci HR222_LINE_PLAYBACK_LEVEL_MIN; /* -25 dB */ 858c2ecf20Sopenharmony_ci uinfo->value.integer.max = 868c2ecf20Sopenharmony_ci HR222_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ 878c2ecf20Sopenharmony_ci } else { 888c2ecf20Sopenharmony_ci uinfo->value.integer.min = 898c2ecf20Sopenharmony_ci PCXHR_LINE_PLAYBACK_LEVEL_MIN; /*-104 dB */ 908c2ecf20Sopenharmony_ci uinfo->value.integer.max = 918c2ecf20Sopenharmony_ci PCXHR_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } else { /* capture */ 948c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) { 958c2ecf20Sopenharmony_ci uinfo->value.integer.min = 968c2ecf20Sopenharmony_ci HR222_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ 978c2ecf20Sopenharmony_ci uinfo->value.integer.max = 988c2ecf20Sopenharmony_ci HR222_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ 998c2ecf20Sopenharmony_ci } else { 1008c2ecf20Sopenharmony_ci uinfo->value.integer.min = 1018c2ecf20Sopenharmony_ci PCXHR_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ 1028c2ecf20Sopenharmony_ci uinfo->value.integer.max = 1038c2ecf20Sopenharmony_ci PCXHR_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, 1108c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 1138c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 1148c2ecf20Sopenharmony_ci if (kcontrol->private_value == 0) { /* playback */ 1158c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; 1168c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; 1178c2ecf20Sopenharmony_ci } else { /* capture */ 1188c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; 1198c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, 1268c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 1298c2ecf20Sopenharmony_ci int changed = 0; 1308c2ecf20Sopenharmony_ci int is_capture, i; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 1338c2ecf20Sopenharmony_ci is_capture = (kcontrol->private_value != 0); 1348c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 1358c2ecf20Sopenharmony_ci int new_volume = ucontrol->value.integer.value[i]; 1368c2ecf20Sopenharmony_ci int *stored_volume = is_capture ? 1378c2ecf20Sopenharmony_ci &chip->analog_capture_volume[i] : 1388c2ecf20Sopenharmony_ci &chip->analog_playback_volume[i]; 1398c2ecf20Sopenharmony_ci if (is_capture) { 1408c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) { 1418c2ecf20Sopenharmony_ci if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN || 1428c2ecf20Sopenharmony_ci new_volume > HR222_LINE_CAPTURE_LEVEL_MAX) 1438c2ecf20Sopenharmony_ci continue; 1448c2ecf20Sopenharmony_ci } else { 1458c2ecf20Sopenharmony_ci if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN || 1468c2ecf20Sopenharmony_ci new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX) 1478c2ecf20Sopenharmony_ci continue; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci } else { 1508c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) { 1518c2ecf20Sopenharmony_ci if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN || 1528c2ecf20Sopenharmony_ci new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX) 1538c2ecf20Sopenharmony_ci continue; 1548c2ecf20Sopenharmony_ci } else { 1558c2ecf20Sopenharmony_ci if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN || 1568c2ecf20Sopenharmony_ci new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX) 1578c2ecf20Sopenharmony_ci continue; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci if (*stored_volume != new_volume) { 1618c2ecf20Sopenharmony_ci *stored_volume = new_volume; 1628c2ecf20Sopenharmony_ci changed = 1; 1638c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 1648c2ecf20Sopenharmony_ci hr222_update_analog_audio_level(chip, 1658c2ecf20Sopenharmony_ci is_capture, i); 1668c2ecf20Sopenharmony_ci else 1678c2ecf20Sopenharmony_ci pcxhr_update_analog_audio_level(chip, 1688c2ecf20Sopenharmony_ci is_capture, i); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 1728c2ecf20Sopenharmony_ci return changed; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_analog_level = { 1768c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1778c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 1788c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 1798c2ecf20Sopenharmony_ci /* name will be filled later */ 1808c2ecf20Sopenharmony_ci .info = pcxhr_analog_vol_info, 1818c2ecf20Sopenharmony_ci .get = pcxhr_analog_vol_get, 1828c2ecf20Sopenharmony_ci .put = pcxhr_analog_vol_put, 1838c2ecf20Sopenharmony_ci /* tlv will be filled later */ 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* shared */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define pcxhr_sw_info snd_ctl_boolean_stereo_info 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, 1918c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 1968c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; 1978c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; 1988c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, 2038c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 2068c2ecf20Sopenharmony_ci int i, changed = 0; 2078c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 2088c2ecf20Sopenharmony_ci for(i = 0; i < 2; i++) { 2098c2ecf20Sopenharmony_ci if (chip->analog_playback_active[i] != 2108c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i]) { 2118c2ecf20Sopenharmony_ci chip->analog_playback_active[i] = 2128c2ecf20Sopenharmony_ci !!ucontrol->value.integer.value[i]; 2138c2ecf20Sopenharmony_ci changed = 1; 2148c2ecf20Sopenharmony_ci /* update playback levels */ 2158c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 2168c2ecf20Sopenharmony_ci hr222_update_analog_audio_level(chip, 0, i); 2178c2ecf20Sopenharmony_ci else 2188c2ecf20Sopenharmony_ci pcxhr_update_analog_audio_level(chip, 0, i); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 2228c2ecf20Sopenharmony_ci return changed; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_output_switch = { 2268c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2278c2ecf20Sopenharmony_ci .name = "Master Playback Switch", 2288c2ecf20Sopenharmony_ci .info = pcxhr_sw_info, /* shared */ 2298c2ecf20Sopenharmony_ci .get = pcxhr_audio_sw_get, 2308c2ecf20Sopenharmony_ci .put = pcxhr_audio_sw_put 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#define PCXHR_DIGITAL_LEVEL_MIN 0x000 /* -110 dB */ 2358c2ecf20Sopenharmony_ci#define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ 2368c2ecf20Sopenharmony_ci#define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_digital, -10975, 25, 1800); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define MORE_THAN_ONE_STREAM_LEVEL 0x000001 2418c2ecf20Sopenharmony_ci#define VALID_STREAM_PAN_LEVEL_MASK 0x800000 2428c2ecf20Sopenharmony_ci#define VALID_STREAM_LEVEL_MASK 0x400000 2438c2ecf20Sopenharmony_ci#define VALID_STREAM_LEVEL_1_MASK 0x200000 2448c2ecf20Sopenharmony_ci#define VALID_STREAM_LEVEL_2_MASK 0x100000 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci int err; 2498c2ecf20Sopenharmony_ci struct pcxhr_rmh rmh; 2508c2ecf20Sopenharmony_ci struct pcxhr_pipe *pipe = &chip->playback_pipe; 2518c2ecf20Sopenharmony_ci int left, right; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (chip->digital_playback_active[idx][0]) 2548c2ecf20Sopenharmony_ci left = chip->digital_playback_volume[idx][0]; 2558c2ecf20Sopenharmony_ci else 2568c2ecf20Sopenharmony_ci left = PCXHR_DIGITAL_LEVEL_MIN; 2578c2ecf20Sopenharmony_ci if (chip->digital_playback_active[idx][1]) 2588c2ecf20Sopenharmony_ci right = chip->digital_playback_volume[idx][1]; 2598c2ecf20Sopenharmony_ci else 2608c2ecf20Sopenharmony_ci right = PCXHR_DIGITAL_LEVEL_MIN; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci pcxhr_init_rmh(&rmh, CMD_STREAM_OUT_LEVEL_ADJUST); 2638c2ecf20Sopenharmony_ci /* add pipe and stream mask */ 2648c2ecf20Sopenharmony_ci pcxhr_set_pipe_cmd_params(&rmh, 0, pipe->first_audio, 0, 1<<idx); 2658c2ecf20Sopenharmony_ci /* volume left->left / right->right panoramic level */ 2668c2ecf20Sopenharmony_ci rmh.cmd[0] |= MORE_THAN_ONE_STREAM_LEVEL; 2678c2ecf20Sopenharmony_ci rmh.cmd[2] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_1_MASK; 2688c2ecf20Sopenharmony_ci rmh.cmd[2] |= (left << 10); 2698c2ecf20Sopenharmony_ci rmh.cmd[3] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_2_MASK; 2708c2ecf20Sopenharmony_ci rmh.cmd[3] |= right; 2718c2ecf20Sopenharmony_ci rmh.cmd_len = 4; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 2748c2ecf20Sopenharmony_ci if (err < 0) { 2758c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "error update_playback_stream_level " 2768c2ecf20Sopenharmony_ci "card(%d) err(%x)\n", chip->chip_idx, err); 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci#define AUDIO_IO_HAS_MUTE_LEVEL 0x400000 2838c2ecf20Sopenharmony_ci#define AUDIO_IO_HAS_MUTE_MONITOR_1 0x200000 2848c2ecf20Sopenharmony_ci#define VALID_AUDIO_IO_DIGITAL_LEVEL 0x000001 2858c2ecf20Sopenharmony_ci#define VALID_AUDIO_IO_MONITOR_LEVEL 0x000002 2868c2ecf20Sopenharmony_ci#define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 2878c2ecf20Sopenharmony_ci#define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, 2908c2ecf20Sopenharmony_ci int capture, int channel) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci int err; 2938c2ecf20Sopenharmony_ci struct pcxhr_rmh rmh; 2948c2ecf20Sopenharmony_ci struct pcxhr_pipe *pipe; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (capture) 2978c2ecf20Sopenharmony_ci pipe = &chip->capture_pipe[0]; 2988c2ecf20Sopenharmony_ci else 2998c2ecf20Sopenharmony_ci pipe = &chip->playback_pipe; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); 3028c2ecf20Sopenharmony_ci /* add channel mask */ 3038c2ecf20Sopenharmony_ci pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 3048c2ecf20Sopenharmony_ci 1 << (channel + pipe->first_audio)); 3058c2ecf20Sopenharmony_ci /* TODO : if mask (3 << pipe->first_audio) is used, left and right 3068c2ecf20Sopenharmony_ci * channel will be programmed to the same params */ 3078c2ecf20Sopenharmony_ci if (capture) { 3088c2ecf20Sopenharmony_ci rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; 3098c2ecf20Sopenharmony_ci /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled 3108c2ecf20Sopenharmony_ci * (capture pipe level) */ 3118c2ecf20Sopenharmony_ci rmh.cmd[2] = chip->digital_capture_volume[channel]; 3128c2ecf20Sopenharmony_ci } else { 3138c2ecf20Sopenharmony_ci rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | 3148c2ecf20Sopenharmony_ci VALID_AUDIO_IO_MUTE_MONITOR_1; 3158c2ecf20Sopenharmony_ci /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL 3168c2ecf20Sopenharmony_ci * not yet handled (playback pipe level) 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci rmh.cmd[2] = chip->monitoring_volume[channel] << 10; 3198c2ecf20Sopenharmony_ci if (chip->monitoring_active[channel] == 0) 3208c2ecf20Sopenharmony_ci rmh.cmd[2] |= AUDIO_IO_HAS_MUTE_MONITOR_1; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci rmh.cmd_len = 3; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 3258c2ecf20Sopenharmony_ci if (err < 0) { 3268c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 3278c2ecf20Sopenharmony_ci "error update_audio_level(%d) err=%x\n", 3288c2ecf20Sopenharmony_ci chip->chip_idx, err); 3298c2ecf20Sopenharmony_ci return -EINVAL; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/* shared */ 3368c2ecf20Sopenharmony_cistatic int pcxhr_digital_vol_info(struct snd_kcontrol *kcontrol, 3378c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3408c2ecf20Sopenharmony_ci uinfo->count = 2; 3418c2ecf20Sopenharmony_ci uinfo->value.integer.min = PCXHR_DIGITAL_LEVEL_MIN; /* -109.5 dB */ 3428c2ecf20Sopenharmony_ci uinfo->value.integer.max = PCXHR_DIGITAL_LEVEL_MAX; /* 18.0 dB */ 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, 3488c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 3518c2ecf20Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ 3528c2ecf20Sopenharmony_ci int *stored_volume; 3538c2ecf20Sopenharmony_ci int is_capture = kcontrol->private_value; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 3568c2ecf20Sopenharmony_ci if (is_capture) /* digital capture */ 3578c2ecf20Sopenharmony_ci stored_volume = chip->digital_capture_volume; 3588c2ecf20Sopenharmony_ci else /* digital playback */ 3598c2ecf20Sopenharmony_ci stored_volume = chip->digital_playback_volume[idx]; 3608c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = stored_volume[0]; 3618c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = stored_volume[1]; 3628c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, 3678c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 3708c2ecf20Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ 3718c2ecf20Sopenharmony_ci int changed = 0; 3728c2ecf20Sopenharmony_ci int is_capture = kcontrol->private_value; 3738c2ecf20Sopenharmony_ci int *stored_volume; 3748c2ecf20Sopenharmony_ci int i; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 3778c2ecf20Sopenharmony_ci if (is_capture) /* digital capture */ 3788c2ecf20Sopenharmony_ci stored_volume = chip->digital_capture_volume; 3798c2ecf20Sopenharmony_ci else /* digital playback */ 3808c2ecf20Sopenharmony_ci stored_volume = chip->digital_playback_volume[idx]; 3818c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 3828c2ecf20Sopenharmony_ci int vol = ucontrol->value.integer.value[i]; 3838c2ecf20Sopenharmony_ci if (vol < PCXHR_DIGITAL_LEVEL_MIN || 3848c2ecf20Sopenharmony_ci vol > PCXHR_DIGITAL_LEVEL_MAX) 3858c2ecf20Sopenharmony_ci continue; 3868c2ecf20Sopenharmony_ci if (stored_volume[i] != vol) { 3878c2ecf20Sopenharmony_ci stored_volume[i] = vol; 3888c2ecf20Sopenharmony_ci changed = 1; 3898c2ecf20Sopenharmony_ci if (is_capture) /* update capture volume */ 3908c2ecf20Sopenharmony_ci pcxhr_update_audio_pipe_level(chip, 1, i); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci if (!is_capture && changed) /* update playback volume */ 3948c2ecf20Sopenharmony_ci pcxhr_update_playback_stream_level(chip, idx); 3958c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 3968c2ecf20Sopenharmony_ci return changed; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_pcxhr_pcm_vol = 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4028c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 4038c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 4048c2ecf20Sopenharmony_ci /* name will be filled later */ 4058c2ecf20Sopenharmony_ci /* count will be filled later */ 4068c2ecf20Sopenharmony_ci .info = pcxhr_digital_vol_info, /* shared */ 4078c2ecf20Sopenharmony_ci .get = pcxhr_pcm_vol_get, 4088c2ecf20Sopenharmony_ci .put = pcxhr_pcm_vol_put, 4098c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_digital }, 4108c2ecf20Sopenharmony_ci}; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, 4148c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 4178c2ecf20Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 4208c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; 4218c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; 4228c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, 4278c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 4308c2ecf20Sopenharmony_ci int changed = 0; 4318c2ecf20Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ 4328c2ecf20Sopenharmony_ci int i, j; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 4358c2ecf20Sopenharmony_ci j = idx; 4368c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 4378c2ecf20Sopenharmony_ci if (chip->digital_playback_active[j][i] != 4388c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i]) { 4398c2ecf20Sopenharmony_ci chip->digital_playback_active[j][i] = 4408c2ecf20Sopenharmony_ci !!ucontrol->value.integer.value[i]; 4418c2ecf20Sopenharmony_ci changed = 1; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci if (changed) 4458c2ecf20Sopenharmony_ci pcxhr_update_playback_stream_level(chip, idx); 4468c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 4478c2ecf20Sopenharmony_ci return changed; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_pcm_switch = { 4518c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4528c2ecf20Sopenharmony_ci .name = "PCM Playback Switch", 4538c2ecf20Sopenharmony_ci .count = PCXHR_PLAYBACK_STREAMS, 4548c2ecf20Sopenharmony_ci .info = pcxhr_sw_info, /* shared */ 4558c2ecf20Sopenharmony_ci .get = pcxhr_pcm_sw_get, 4568c2ecf20Sopenharmony_ci .put = pcxhr_pcm_sw_put 4578c2ecf20Sopenharmony_ci}; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci/* 4618c2ecf20Sopenharmony_ci * monitoring level control 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int pcxhr_monitor_vol_get(struct snd_kcontrol *kcontrol, 4658c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 4688c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 4698c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; 4708c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; 4718c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, 4768c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 4798c2ecf20Sopenharmony_ci int changed = 0; 4808c2ecf20Sopenharmony_ci int i; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 4838c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 4848c2ecf20Sopenharmony_ci if (chip->monitoring_volume[i] != 4858c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i]) { 4868c2ecf20Sopenharmony_ci chip->monitoring_volume[i] = 4878c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i]; 4888c2ecf20Sopenharmony_ci if (chip->monitoring_active[i]) 4898c2ecf20Sopenharmony_ci /* update monitoring volume and mute */ 4908c2ecf20Sopenharmony_ci /* do only when monitoring is unmuted */ 4918c2ecf20Sopenharmony_ci pcxhr_update_audio_pipe_level(chip, 0, i); 4928c2ecf20Sopenharmony_ci changed = 1; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 4968c2ecf20Sopenharmony_ci return changed; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_monitor_vol = { 5008c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5018c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 5028c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 5038c2ecf20Sopenharmony_ci .name = "Monitoring Playback Volume", 5048c2ecf20Sopenharmony_ci .info = pcxhr_digital_vol_info, /* shared */ 5058c2ecf20Sopenharmony_ci .get = pcxhr_monitor_vol_get, 5068c2ecf20Sopenharmony_ci .put = pcxhr_monitor_vol_put, 5078c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_digital }, 5088c2ecf20Sopenharmony_ci}; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci/* 5118c2ecf20Sopenharmony_ci * monitoring switch control 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic int pcxhr_monitor_sw_get(struct snd_kcontrol *kcontrol, 5158c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 5188c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 5198c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->monitoring_active[0]; 5208c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = chip->monitoring_active[1]; 5218c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, 5268c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 5298c2ecf20Sopenharmony_ci int changed = 0; 5308c2ecf20Sopenharmony_ci int i; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 5338c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 5348c2ecf20Sopenharmony_ci if (chip->monitoring_active[i] != 5358c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i]) { 5368c2ecf20Sopenharmony_ci chip->monitoring_active[i] = 5378c2ecf20Sopenharmony_ci !!ucontrol->value.integer.value[i]; 5388c2ecf20Sopenharmony_ci changed |= (1<<i); /* mask 0x01 and 0x02 */ 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci if (changed & 0x01) 5428c2ecf20Sopenharmony_ci /* update left monitoring volume and mute */ 5438c2ecf20Sopenharmony_ci pcxhr_update_audio_pipe_level(chip, 0, 0); 5448c2ecf20Sopenharmony_ci if (changed & 0x02) 5458c2ecf20Sopenharmony_ci /* update right monitoring volume and mute */ 5468c2ecf20Sopenharmony_ci pcxhr_update_audio_pipe_level(chip, 0, 1); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 5498c2ecf20Sopenharmony_ci return (changed != 0); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_monitor_sw = { 5538c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5548c2ecf20Sopenharmony_ci .name = "Monitoring Playback Switch", 5558c2ecf20Sopenharmony_ci .info = pcxhr_sw_info, /* shared */ 5568c2ecf20Sopenharmony_ci .get = pcxhr_monitor_sw_get, 5578c2ecf20Sopenharmony_ci .put = pcxhr_monitor_sw_put 5588c2ecf20Sopenharmony_ci}; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci/* 5638c2ecf20Sopenharmony_ci * audio source select 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_ci#define PCXHR_SOURCE_AUDIO01_UER 0x000100 5668c2ecf20Sopenharmony_ci#define PCXHR_SOURCE_AUDIO01_SYNC 0x000200 5678c2ecf20Sopenharmony_ci#define PCXHR_SOURCE_AUDIO23_UER 0x000400 5688c2ecf20Sopenharmony_ci#define PCXHR_SOURCE_AUDIO45_UER 0x001000 5698c2ecf20Sopenharmony_ci#define PCXHR_SOURCE_AUDIO67_UER 0x040000 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int pcxhr_set_audio_source(struct snd_pcxhr* chip) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct pcxhr_rmh rmh; 5748c2ecf20Sopenharmony_ci unsigned int mask, reg; 5758c2ecf20Sopenharmony_ci unsigned int codec; 5768c2ecf20Sopenharmony_ci int err, changed; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci switch (chip->chip_idx) { 5798c2ecf20Sopenharmony_ci case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; 5808c2ecf20Sopenharmony_ci case 1 : mask = PCXHR_SOURCE_AUDIO23_UER; codec = CS8420_23_CS; break; 5818c2ecf20Sopenharmony_ci case 2 : mask = PCXHR_SOURCE_AUDIO45_UER; codec = CS8420_45_CS; break; 5828c2ecf20Sopenharmony_ci case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; 5838c2ecf20Sopenharmony_ci default: return -EINVAL; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci if (chip->audio_capture_source != 0) { 5868c2ecf20Sopenharmony_ci reg = mask; /* audio source from digital plug */ 5878c2ecf20Sopenharmony_ci } else { 5888c2ecf20Sopenharmony_ci reg = 0; /* audio source from analog plug */ 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci /* set the input source */ 5918c2ecf20Sopenharmony_ci pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); 5928c2ecf20Sopenharmony_ci /* resync them (otherwise channel inversion possible) */ 5938c2ecf20Sopenharmony_ci if (changed) { 5948c2ecf20Sopenharmony_ci pcxhr_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS); 5958c2ecf20Sopenharmony_ci rmh.cmd[0] |= (1 << chip->chip_idx); 5968c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 5978c2ecf20Sopenharmony_ci if (err) 5988c2ecf20Sopenharmony_ci return err; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci if (chip->mgr->board_aes_in_192k) { 6018c2ecf20Sopenharmony_ci int i; 6028c2ecf20Sopenharmony_ci unsigned int src_config = 0xC0; 6038c2ecf20Sopenharmony_ci /* update all src configs with one call */ 6048c2ecf20Sopenharmony_ci for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) { 6058c2ecf20Sopenharmony_ci if (chip->mgr->chip[i]->audio_capture_source == 2) 6068c2ecf20Sopenharmony_ci src_config |= (1 << (3 - i)); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci /* set codec SRC on off */ 6098c2ecf20Sopenharmony_ci pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); 6108c2ecf20Sopenharmony_ci rmh.cmd_len = 2; 6118c2ecf20Sopenharmony_ci rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC; 6128c2ecf20Sopenharmony_ci rmh.cmd[1] = src_config; 6138c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 6148c2ecf20Sopenharmony_ci } else { 6158c2ecf20Sopenharmony_ci int use_src = 0; 6168c2ecf20Sopenharmony_ci if (chip->audio_capture_source == 2) 6178c2ecf20Sopenharmony_ci use_src = 1; 6188c2ecf20Sopenharmony_ci /* set codec SRC on off */ 6198c2ecf20Sopenharmony_ci pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); 6208c2ecf20Sopenharmony_ci rmh.cmd_len = 3; 6218c2ecf20Sopenharmony_ci rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; 6228c2ecf20Sopenharmony_ci rmh.cmd[1] = codec; 6238c2ecf20Sopenharmony_ci rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | 6248c2ecf20Sopenharmony_ci (use_src ? 0x41 : 0x54)); 6258c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 6268c2ecf20Sopenharmony_ci if (err) 6278c2ecf20Sopenharmony_ci return err; 6288c2ecf20Sopenharmony_ci rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | 6298c2ecf20Sopenharmony_ci (use_src ? 0x41 : 0x49)); 6308c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci return err; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, 6368c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci static const char *texts[5] = { 6398c2ecf20Sopenharmony_ci "Line", "Digital", "Digi+SRC", "Mic", "Line+Mic" 6408c2ecf20Sopenharmony_ci }; 6418c2ecf20Sopenharmony_ci int i; 6428c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci i = 2; /* no SRC, no Mic available */ 6458c2ecf20Sopenharmony_ci if (chip->mgr->board_has_aes1) { 6468c2ecf20Sopenharmony_ci i = 3; /* SRC available */ 6478c2ecf20Sopenharmony_ci if (chip->mgr->board_has_mic) 6488c2ecf20Sopenharmony_ci i = 5; /* Mic and MicroMix available */ 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, i, texts); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic int pcxhr_audio_src_get(struct snd_kcontrol *kcontrol, 6548c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 6578c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = chip->audio_capture_source; 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, 6628c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 6658c2ecf20Sopenharmony_ci int ret = 0; 6668c2ecf20Sopenharmony_ci int i = 2; /* no SRC, no Mic available */ 6678c2ecf20Sopenharmony_ci if (chip->mgr->board_has_aes1) { 6688c2ecf20Sopenharmony_ci i = 3; /* SRC available */ 6698c2ecf20Sopenharmony_ci if (chip->mgr->board_has_mic) 6708c2ecf20Sopenharmony_ci i = 5; /* Mic and MicroMix available */ 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci if (ucontrol->value.enumerated.item[0] >= i) 6738c2ecf20Sopenharmony_ci return -EINVAL; 6748c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 6758c2ecf20Sopenharmony_ci if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { 6768c2ecf20Sopenharmony_ci chip->audio_capture_source = ucontrol->value.enumerated.item[0]; 6778c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 6788c2ecf20Sopenharmony_ci hr222_set_audio_source(chip); 6798c2ecf20Sopenharmony_ci else 6808c2ecf20Sopenharmony_ci pcxhr_set_audio_source(chip); 6818c2ecf20Sopenharmony_ci ret = 1; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 6848c2ecf20Sopenharmony_ci return ret; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_audio_src = { 6888c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 6898c2ecf20Sopenharmony_ci .name = "Capture Source", 6908c2ecf20Sopenharmony_ci .info = pcxhr_audio_src_info, 6918c2ecf20Sopenharmony_ci .get = pcxhr_audio_src_get, 6928c2ecf20Sopenharmony_ci .put = pcxhr_audio_src_put, 6938c2ecf20Sopenharmony_ci}; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/* 6978c2ecf20Sopenharmony_ci * clock type selection 6988c2ecf20Sopenharmony_ci * enum pcxhr_clock_type { 6998c2ecf20Sopenharmony_ci * PCXHR_CLOCK_TYPE_INTERNAL = 0, 7008c2ecf20Sopenharmony_ci * PCXHR_CLOCK_TYPE_WORD_CLOCK, 7018c2ecf20Sopenharmony_ci * PCXHR_CLOCK_TYPE_AES_SYNC, 7028c2ecf20Sopenharmony_ci * PCXHR_CLOCK_TYPE_AES_1, 7038c2ecf20Sopenharmony_ci * PCXHR_CLOCK_TYPE_AES_2, 7048c2ecf20Sopenharmony_ci * PCXHR_CLOCK_TYPE_AES_3, 7058c2ecf20Sopenharmony_ci * PCXHR_CLOCK_TYPE_AES_4, 7068c2ecf20Sopenharmony_ci * PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, 7078c2ecf20Sopenharmony_ci * HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, 7088c2ecf20Sopenharmony_ci * HR22_CLOCK_TYPE_AES_SYNC, 7098c2ecf20Sopenharmony_ci * HR22_CLOCK_TYPE_AES_1, 7108c2ecf20Sopenharmony_ci * HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, 7118c2ecf20Sopenharmony_ci * }; 7128c2ecf20Sopenharmony_ci */ 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, 7158c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci static const char *textsPCXHR[7] = { 7188c2ecf20Sopenharmony_ci "Internal", "WordClock", "AES Sync", 7198c2ecf20Sopenharmony_ci "AES 1", "AES 2", "AES 3", "AES 4" 7208c2ecf20Sopenharmony_ci }; 7218c2ecf20Sopenharmony_ci static const char *textsHR22[3] = { 7228c2ecf20Sopenharmony_ci "Internal", "AES Sync", "AES 1" 7238c2ecf20Sopenharmony_ci }; 7248c2ecf20Sopenharmony_ci const char **texts; 7258c2ecf20Sopenharmony_ci struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); 7268c2ecf20Sopenharmony_ci int clock_items = 2; /* at least Internal and AES Sync clock */ 7278c2ecf20Sopenharmony_ci if (mgr->board_has_aes1) { 7288c2ecf20Sopenharmony_ci clock_items += mgr->capture_chips; /* add AES x */ 7298c2ecf20Sopenharmony_ci if (!mgr->is_hr_stereo) 7308c2ecf20Sopenharmony_ci clock_items += 1; /* add word clock */ 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci if (mgr->is_hr_stereo) { 7338c2ecf20Sopenharmony_ci texts = textsHR22; 7348c2ecf20Sopenharmony_ci snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1)); 7358c2ecf20Sopenharmony_ci } else { 7368c2ecf20Sopenharmony_ci texts = textsPCXHR; 7378c2ecf20Sopenharmony_ci snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1)); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, clock_items, texts); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int pcxhr_clock_type_get(struct snd_kcontrol *kcontrol, 7438c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); 7468c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = mgr->use_clock_type; 7478c2ecf20Sopenharmony_ci return 0; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, 7518c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); 7548c2ecf20Sopenharmony_ci int rate, ret = 0; 7558c2ecf20Sopenharmony_ci unsigned int clock_items = 2; /* at least Internal and AES Sync clock */ 7568c2ecf20Sopenharmony_ci if (mgr->board_has_aes1) { 7578c2ecf20Sopenharmony_ci clock_items += mgr->capture_chips; /* add AES x */ 7588c2ecf20Sopenharmony_ci if (!mgr->is_hr_stereo) 7598c2ecf20Sopenharmony_ci clock_items += 1; /* add word clock */ 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci if (ucontrol->value.enumerated.item[0] >= clock_items) 7628c2ecf20Sopenharmony_ci return -EINVAL; 7638c2ecf20Sopenharmony_ci mutex_lock(&mgr->mixer_mutex); 7648c2ecf20Sopenharmony_ci if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { 7658c2ecf20Sopenharmony_ci mutex_lock(&mgr->setup_mutex); 7668c2ecf20Sopenharmony_ci mgr->use_clock_type = ucontrol->value.enumerated.item[0]; 7678c2ecf20Sopenharmony_ci rate = 0; 7688c2ecf20Sopenharmony_ci if (mgr->use_clock_type != PCXHR_CLOCK_TYPE_INTERNAL) { 7698c2ecf20Sopenharmony_ci pcxhr_get_external_clock(mgr, mgr->use_clock_type, 7708c2ecf20Sopenharmony_ci &rate); 7718c2ecf20Sopenharmony_ci } else { 7728c2ecf20Sopenharmony_ci rate = mgr->sample_rate; 7738c2ecf20Sopenharmony_ci if (!rate) 7748c2ecf20Sopenharmony_ci rate = 48000; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci if (rate) { 7778c2ecf20Sopenharmony_ci pcxhr_set_clock(mgr, rate); 7788c2ecf20Sopenharmony_ci if (mgr->sample_rate) 7798c2ecf20Sopenharmony_ci mgr->sample_rate = rate; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci mutex_unlock(&mgr->setup_mutex); 7828c2ecf20Sopenharmony_ci ret = 1; /* return 1 even if the set was not done. ok ? */ 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci mutex_unlock(&mgr->mixer_mutex); 7858c2ecf20Sopenharmony_ci return ret; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_clock_type = { 7898c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7908c2ecf20Sopenharmony_ci .name = "Clock Mode", 7918c2ecf20Sopenharmony_ci .info = pcxhr_clock_type_info, 7928c2ecf20Sopenharmony_ci .get = pcxhr_clock_type_get, 7938c2ecf20Sopenharmony_ci .put = pcxhr_clock_type_put, 7948c2ecf20Sopenharmony_ci}; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci/* 7978c2ecf20Sopenharmony_ci * clock rate control 7988c2ecf20Sopenharmony_ci * specific control that scans the sample rates on the external plugs 7998c2ecf20Sopenharmony_ci */ 8008c2ecf20Sopenharmony_cistatic int pcxhr_clock_rate_info(struct snd_kcontrol *kcontrol, 8018c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); 8048c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 8058c2ecf20Sopenharmony_ci uinfo->count = 3 + mgr->capture_chips; 8068c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; /* clock not present */ 8078c2ecf20Sopenharmony_ci uinfo->value.integer.max = 192000; /* max sample rate 192 kHz */ 8088c2ecf20Sopenharmony_ci return 0; 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, 8128c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); 8158c2ecf20Sopenharmony_ci int i, err, rate; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci mutex_lock(&mgr->mixer_mutex); 8188c2ecf20Sopenharmony_ci for(i = 0; i < 3 + mgr->capture_chips; i++) { 8198c2ecf20Sopenharmony_ci if (i == PCXHR_CLOCK_TYPE_INTERNAL) 8208c2ecf20Sopenharmony_ci rate = mgr->sample_rate_real; 8218c2ecf20Sopenharmony_ci else { 8228c2ecf20Sopenharmony_ci err = pcxhr_get_external_clock(mgr, i, &rate); 8238c2ecf20Sopenharmony_ci if (err) 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = rate; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci mutex_unlock(&mgr->mixer_mutex); 8298c2ecf20Sopenharmony_ci return 0; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_clock_rate = { 8338c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 8348c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 8358c2ecf20Sopenharmony_ci .name = "Clock Rates", 8368c2ecf20Sopenharmony_ci .info = pcxhr_clock_rate_info, 8378c2ecf20Sopenharmony_ci .get = pcxhr_clock_rate_get, 8388c2ecf20Sopenharmony_ci}; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/* 8418c2ecf20Sopenharmony_ci * IEC958 status bits 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_cistatic int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, 8448c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 8478c2ecf20Sopenharmony_ci uinfo->count = 1; 8488c2ecf20Sopenharmony_ci return 0; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, 8528c2ecf20Sopenharmony_ci int aes_idx, unsigned char *aes_bits) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci int i, err; 8558c2ecf20Sopenharmony_ci unsigned char temp; 8568c2ecf20Sopenharmony_ci struct pcxhr_rmh rmh; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); 8598c2ecf20Sopenharmony_ci rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; 8608c2ecf20Sopenharmony_ci switch (chip->chip_idx) { 8618c2ecf20Sopenharmony_ci /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */ 8628c2ecf20Sopenharmony_ci case 0: rmh.cmd[1] = CS8420_01_CS; break; 8638c2ecf20Sopenharmony_ci case 1: rmh.cmd[1] = CS8420_23_CS; break; 8648c2ecf20Sopenharmony_ci case 2: rmh.cmd[1] = CS8420_45_CS; break; 8658c2ecf20Sopenharmony_ci case 3: rmh.cmd[1] = CS8420_67_CS; break; 8668c2ecf20Sopenharmony_ci default: return -EINVAL; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci if (chip->mgr->board_aes_in_192k) { 8698c2ecf20Sopenharmony_ci switch (aes_idx) { 8708c2ecf20Sopenharmony_ci case 0: rmh.cmd[2] = CS8416_CSB0; break; 8718c2ecf20Sopenharmony_ci case 1: rmh.cmd[2] = CS8416_CSB1; break; 8728c2ecf20Sopenharmony_ci case 2: rmh.cmd[2] = CS8416_CSB2; break; 8738c2ecf20Sopenharmony_ci case 3: rmh.cmd[2] = CS8416_CSB3; break; 8748c2ecf20Sopenharmony_ci case 4: rmh.cmd[2] = CS8416_CSB4; break; 8758c2ecf20Sopenharmony_ci default: return -EINVAL; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci } else { 8788c2ecf20Sopenharmony_ci switch (aes_idx) { 8798c2ecf20Sopenharmony_ci /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */ 8808c2ecf20Sopenharmony_ci case 0: rmh.cmd[2] = CS8420_CSB0; break; 8818c2ecf20Sopenharmony_ci case 1: rmh.cmd[2] = CS8420_CSB1; break; 8828c2ecf20Sopenharmony_ci case 2: rmh.cmd[2] = CS8420_CSB2; break; 8838c2ecf20Sopenharmony_ci case 3: rmh.cmd[2] = CS8420_CSB3; break; 8848c2ecf20Sopenharmony_ci case 4: rmh.cmd[2] = CS8420_CSB4; break; 8858c2ecf20Sopenharmony_ci default: return -EINVAL; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci /* size and code the chip id for the fpga */ 8898c2ecf20Sopenharmony_ci rmh.cmd[1] &= 0x0fffff; 8908c2ecf20Sopenharmony_ci /* chip signature + map for spi read */ 8918c2ecf20Sopenharmony_ci rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; 8928c2ecf20Sopenharmony_ci rmh.cmd_len = 3; 8938c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 8948c2ecf20Sopenharmony_ci if (err) 8958c2ecf20Sopenharmony_ci return err; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (chip->mgr->board_aes_in_192k) { 8988c2ecf20Sopenharmony_ci temp = (unsigned char)rmh.stat[1]; 8998c2ecf20Sopenharmony_ci } else { 9008c2ecf20Sopenharmony_ci temp = 0; 9018c2ecf20Sopenharmony_ci /* reversed bit order (not with CS8416_01_CS) */ 9028c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 9038c2ecf20Sopenharmony_ci temp <<= 1; 9048c2ecf20Sopenharmony_ci if (rmh.stat[1] & (1 << i)) 9058c2ecf20Sopenharmony_ci temp |= 1; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n", 9098c2ecf20Sopenharmony_ci chip->chip_idx, aes_idx, temp); 9108c2ecf20Sopenharmony_ci *aes_bits = temp; 9118c2ecf20Sopenharmony_ci return 0; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, 9158c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 9188c2ecf20Sopenharmony_ci unsigned char aes_bits; 9198c2ecf20Sopenharmony_ci int i, err; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 9228c2ecf20Sopenharmony_ci for(i = 0; i < 5; i++) { 9238c2ecf20Sopenharmony_ci if (kcontrol->private_value == 0) /* playback */ 9248c2ecf20Sopenharmony_ci aes_bits = chip->aes_bits[i]; 9258c2ecf20Sopenharmony_ci else { /* capture */ 9268c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 9278c2ecf20Sopenharmony_ci err = hr222_iec958_capture_byte(chip, i, 9288c2ecf20Sopenharmony_ci &aes_bits); 9298c2ecf20Sopenharmony_ci else 9308c2ecf20Sopenharmony_ci err = pcxhr_iec958_capture_byte(chip, i, 9318c2ecf20Sopenharmony_ci &aes_bits); 9328c2ecf20Sopenharmony_ci if (err) 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[i] = aes_bits; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 9388c2ecf20Sopenharmony_ci return 0; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol, 9428c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci int i; 9458c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) 9468c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[i] = 0xff; 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, 9518c2ecf20Sopenharmony_ci int aes_idx, unsigned char aes_bits) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci int i, err, cmd; 9548c2ecf20Sopenharmony_ci unsigned char new_bits = aes_bits; 9558c2ecf20Sopenharmony_ci unsigned char old_bits = chip->aes_bits[aes_idx]; 9568c2ecf20Sopenharmony_ci struct pcxhr_rmh rmh; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 9598c2ecf20Sopenharmony_ci if ((old_bits & 0x01) != (new_bits & 0x01)) { 9608c2ecf20Sopenharmony_ci cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ 9618c2ecf20Sopenharmony_ci if (chip->chip_idx > 3) 9628c2ecf20Sopenharmony_ci /* new bit used if chip_idx>3 (PCX1222HR) */ 9638c2ecf20Sopenharmony_ci cmd |= 1 << 22; 9648c2ecf20Sopenharmony_ci cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ 9658c2ecf20Sopenharmony_ci cmd |= (new_bits & 0x01) << 23; /* add bit value */ 9668c2ecf20Sopenharmony_ci pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); 9678c2ecf20Sopenharmony_ci rmh.cmd[0] |= IO_NUM_REG_CUER; 9688c2ecf20Sopenharmony_ci rmh.cmd[1] = cmd; 9698c2ecf20Sopenharmony_ci rmh.cmd_len = 2; 9708c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 9718c2ecf20Sopenharmony_ci "write iec958 AES %d byte %d bit %d (cmd %x)\n", 9728c2ecf20Sopenharmony_ci chip->chip_idx, aes_idx, i, cmd); 9738c2ecf20Sopenharmony_ci err = pcxhr_send_msg(chip->mgr, &rmh); 9748c2ecf20Sopenharmony_ci if (err) 9758c2ecf20Sopenharmony_ci return err; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci old_bits >>= 1; 9788c2ecf20Sopenharmony_ci new_bits >>= 1; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci chip->aes_bits[aes_idx] = aes_bits; 9818c2ecf20Sopenharmony_ci return 0; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, 9858c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 9888c2ecf20Sopenharmony_ci int i, changed = 0; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* playback */ 9918c2ecf20Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 9928c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 9938c2ecf20Sopenharmony_ci if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { 9948c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 9958c2ecf20Sopenharmony_ci hr222_iec958_update_byte(chip, i, 9968c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[i]); 9978c2ecf20Sopenharmony_ci else 9988c2ecf20Sopenharmony_ci pcxhr_iec958_update_byte(chip, i, 9998c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[i]); 10008c2ecf20Sopenharmony_ci changed = 1; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 10048c2ecf20Sopenharmony_ci return changed; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_playback_iec958_mask = { 10088c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 10098c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10108c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 10118c2ecf20Sopenharmony_ci .info = pcxhr_iec958_info, 10128c2ecf20Sopenharmony_ci .get = pcxhr_iec958_mask_get 10138c2ecf20Sopenharmony_ci}; 10148c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_playback_iec958 = { 10158c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10168c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 10178c2ecf20Sopenharmony_ci .info = pcxhr_iec958_info, 10188c2ecf20Sopenharmony_ci .get = pcxhr_iec958_get, 10198c2ecf20Sopenharmony_ci .put = pcxhr_iec958_put, 10208c2ecf20Sopenharmony_ci .private_value = 0 /* playback */ 10218c2ecf20Sopenharmony_ci}; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_capture_iec958_mask = { 10248c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 10258c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10268c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), 10278c2ecf20Sopenharmony_ci .info = pcxhr_iec958_info, 10288c2ecf20Sopenharmony_ci .get = pcxhr_iec958_mask_get 10298c2ecf20Sopenharmony_ci}; 10308c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcxhr_control_capture_iec958 = { 10318c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 10328c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10338c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), 10348c2ecf20Sopenharmony_ci .info = pcxhr_iec958_info, 10358c2ecf20Sopenharmony_ci .get = pcxhr_iec958_get, 10368c2ecf20Sopenharmony_ci .private_value = 1 /* capture */ 10378c2ecf20Sopenharmony_ci}; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic void pcxhr_init_audio_levels(struct snd_pcxhr *chip) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci int i; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 10448c2ecf20Sopenharmony_ci if (chip->nb_streams_play) { 10458c2ecf20Sopenharmony_ci int j; 10468c2ecf20Sopenharmony_ci /* at boot time the digital volumes are unmuted 0dB */ 10478c2ecf20Sopenharmony_ci for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { 10488c2ecf20Sopenharmony_ci chip->digital_playback_active[j][i] = 1; 10498c2ecf20Sopenharmony_ci chip->digital_playback_volume[j][i] = 10508c2ecf20Sopenharmony_ci PCXHR_DIGITAL_ZERO_LEVEL; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci /* after boot, only two bits are set on the uer 10538c2ecf20Sopenharmony_ci * interface 10548c2ecf20Sopenharmony_ci */ 10558c2ecf20Sopenharmony_ci chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL | 10568c2ecf20Sopenharmony_ci IEC958_AES0_PRO_FS_48000); 10578c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_DEBUG 10588c2ecf20Sopenharmony_ci /* analog volumes for playback 10598c2ecf20Sopenharmony_ci * (is LEVEL_MIN after boot) 10608c2ecf20Sopenharmony_ci */ 10618c2ecf20Sopenharmony_ci chip->analog_playback_active[i] = 1; 10628c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 10638c2ecf20Sopenharmony_ci chip->analog_playback_volume[i] = 10648c2ecf20Sopenharmony_ci HR222_LINE_PLAYBACK_ZERO_LEVEL; 10658c2ecf20Sopenharmony_ci else { 10668c2ecf20Sopenharmony_ci chip->analog_playback_volume[i] = 10678c2ecf20Sopenharmony_ci PCXHR_LINE_PLAYBACK_ZERO_LEVEL; 10688c2ecf20Sopenharmony_ci pcxhr_update_analog_audio_level(chip, 0, i); 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci#endif 10718c2ecf20Sopenharmony_ci /* stereo cards need to be initialised after boot */ 10728c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 10738c2ecf20Sopenharmony_ci hr222_update_analog_audio_level(chip, 0, i); 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci if (chip->nb_streams_capt) { 10768c2ecf20Sopenharmony_ci /* at boot time the digital volumes are unmuted 0dB */ 10778c2ecf20Sopenharmony_ci chip->digital_capture_volume[i] = 10788c2ecf20Sopenharmony_ci PCXHR_DIGITAL_ZERO_LEVEL; 10798c2ecf20Sopenharmony_ci chip->analog_capture_active = 1; 10808c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_DEBUG 10818c2ecf20Sopenharmony_ci /* analog volumes for playback 10828c2ecf20Sopenharmony_ci * (is LEVEL_MIN after boot) 10838c2ecf20Sopenharmony_ci */ 10848c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 10858c2ecf20Sopenharmony_ci chip->analog_capture_volume[i] = 10868c2ecf20Sopenharmony_ci HR222_LINE_CAPTURE_ZERO_LEVEL; 10878c2ecf20Sopenharmony_ci else { 10888c2ecf20Sopenharmony_ci chip->analog_capture_volume[i] = 10898c2ecf20Sopenharmony_ci PCXHR_LINE_CAPTURE_ZERO_LEVEL; 10908c2ecf20Sopenharmony_ci pcxhr_update_analog_audio_level(chip, 1, i); 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci#endif 10938c2ecf20Sopenharmony_ci /* stereo cards need to be initialised after boot */ 10948c2ecf20Sopenharmony_ci if (chip->mgr->is_hr_stereo) 10958c2ecf20Sopenharmony_ci hr222_update_analog_audio_level(chip, 1, i); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ciint pcxhr_create_mixer(struct pcxhr_mgr *mgr) 11048c2ecf20Sopenharmony_ci{ 11058c2ecf20Sopenharmony_ci struct snd_pcxhr *chip; 11068c2ecf20Sopenharmony_ci int err, i; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci mutex_init(&mgr->mixer_mutex); /* can be in another place */ 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci for (i = 0; i < mgr->num_cards; i++) { 11118c2ecf20Sopenharmony_ci struct snd_kcontrol_new temp; 11128c2ecf20Sopenharmony_ci chip = mgr->chip[i]; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (chip->nb_streams_play) { 11158c2ecf20Sopenharmony_ci /* analog output level control */ 11168c2ecf20Sopenharmony_ci temp = pcxhr_control_analog_level; 11178c2ecf20Sopenharmony_ci temp.name = "Master Playback Volume"; 11188c2ecf20Sopenharmony_ci temp.private_value = 0; /* playback */ 11198c2ecf20Sopenharmony_ci if (mgr->is_hr_stereo) 11208c2ecf20Sopenharmony_ci temp.tlv.p = db_scale_a_hr222_playback; 11218c2ecf20Sopenharmony_ci else 11228c2ecf20Sopenharmony_ci temp.tlv.p = db_scale_analog_playback; 11238c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11248c2ecf20Sopenharmony_ci snd_ctl_new1(&temp, chip)); 11258c2ecf20Sopenharmony_ci if (err < 0) 11268c2ecf20Sopenharmony_ci return err; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* output mute controls */ 11298c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11308c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_output_switch, 11318c2ecf20Sopenharmony_ci chip)); 11328c2ecf20Sopenharmony_ci if (err < 0) 11338c2ecf20Sopenharmony_ci return err; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci temp = snd_pcxhr_pcm_vol; 11368c2ecf20Sopenharmony_ci temp.name = "PCM Playback Volume"; 11378c2ecf20Sopenharmony_ci temp.count = PCXHR_PLAYBACK_STREAMS; 11388c2ecf20Sopenharmony_ci temp.private_value = 0; /* playback */ 11398c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11408c2ecf20Sopenharmony_ci snd_ctl_new1(&temp, chip)); 11418c2ecf20Sopenharmony_ci if (err < 0) 11428c2ecf20Sopenharmony_ci return err; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11458c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_pcm_switch, chip)); 11468c2ecf20Sopenharmony_ci if (err < 0) 11478c2ecf20Sopenharmony_ci return err; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* IEC958 controls */ 11508c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11518c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_playback_iec958_mask, 11528c2ecf20Sopenharmony_ci chip)); 11538c2ecf20Sopenharmony_ci if (err < 0) 11548c2ecf20Sopenharmony_ci return err; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11578c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_playback_iec958, 11588c2ecf20Sopenharmony_ci chip)); 11598c2ecf20Sopenharmony_ci if (err < 0) 11608c2ecf20Sopenharmony_ci return err; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci if (chip->nb_streams_capt) { 11638c2ecf20Sopenharmony_ci /* analog input level control */ 11648c2ecf20Sopenharmony_ci temp = pcxhr_control_analog_level; 11658c2ecf20Sopenharmony_ci temp.name = "Line Capture Volume"; 11668c2ecf20Sopenharmony_ci temp.private_value = 1; /* capture */ 11678c2ecf20Sopenharmony_ci if (mgr->is_hr_stereo) 11688c2ecf20Sopenharmony_ci temp.tlv.p = db_scale_a_hr222_capture; 11698c2ecf20Sopenharmony_ci else 11708c2ecf20Sopenharmony_ci temp.tlv.p = db_scale_analog_capture; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11738c2ecf20Sopenharmony_ci snd_ctl_new1(&temp, chip)); 11748c2ecf20Sopenharmony_ci if (err < 0) 11758c2ecf20Sopenharmony_ci return err; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci temp = snd_pcxhr_pcm_vol; 11788c2ecf20Sopenharmony_ci temp.name = "PCM Capture Volume"; 11798c2ecf20Sopenharmony_ci temp.count = 1; 11808c2ecf20Sopenharmony_ci temp.private_value = 1; /* capture */ 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11838c2ecf20Sopenharmony_ci snd_ctl_new1(&temp, chip)); 11848c2ecf20Sopenharmony_ci if (err < 0) 11858c2ecf20Sopenharmony_ci return err; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* Audio source */ 11888c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11898c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_audio_src, chip)); 11908c2ecf20Sopenharmony_ci if (err < 0) 11918c2ecf20Sopenharmony_ci return err; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci /* IEC958 controls */ 11948c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 11958c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_capture_iec958_mask, 11968c2ecf20Sopenharmony_ci chip)); 11978c2ecf20Sopenharmony_ci if (err < 0) 11988c2ecf20Sopenharmony_ci return err; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 12018c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_capture_iec958, 12028c2ecf20Sopenharmony_ci chip)); 12038c2ecf20Sopenharmony_ci if (err < 0) 12048c2ecf20Sopenharmony_ci return err; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (mgr->is_hr_stereo) { 12078c2ecf20Sopenharmony_ci err = hr222_add_mic_controls(chip); 12088c2ecf20Sopenharmony_ci if (err < 0) 12098c2ecf20Sopenharmony_ci return err; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci /* monitoring only if playback and capture device available */ 12138c2ecf20Sopenharmony_ci if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { 12148c2ecf20Sopenharmony_ci /* monitoring */ 12158c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 12168c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_monitor_vol, chip)); 12178c2ecf20Sopenharmony_ci if (err < 0) 12188c2ecf20Sopenharmony_ci return err; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 12218c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_monitor_sw, chip)); 12228c2ecf20Sopenharmony_ci if (err < 0) 12238c2ecf20Sopenharmony_ci return err; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (i == 0) { 12278c2ecf20Sopenharmony_ci /* clock mode only one control per pcxhr */ 12288c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 12298c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_clock_type, mgr)); 12308c2ecf20Sopenharmony_ci if (err < 0) 12318c2ecf20Sopenharmony_ci return err; 12328c2ecf20Sopenharmony_ci /* non standard control used to scan 12338c2ecf20Sopenharmony_ci * the external clock presence/frequencies 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_ci err = snd_ctl_add(chip->card, 12368c2ecf20Sopenharmony_ci snd_ctl_new1(&pcxhr_control_clock_rate, mgr)); 12378c2ecf20Sopenharmony_ci if (err < 0) 12388c2ecf20Sopenharmony_ci return err; 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* init values for the mixer data */ 12428c2ecf20Sopenharmony_ci pcxhr_init_audio_levels(chip); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return 0; 12468c2ecf20Sopenharmony_ci} 1247