18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA driver for ICEnsemble VT1724 (Envy24HT) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Lowlevel functions for Ego Sys Waveterminal 192M 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com> 88c2ecf20Sopenharmony_ci * Some functions are taken from the Prodigy192 driver 98c2ecf20Sopenharmony_ci * source 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <sound/core.h> 188c2ecf20Sopenharmony_ci#include <sound/tlv.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "ice1712.h" 228c2ecf20Sopenharmony_ci#include "envy24ht.h" 238c2ecf20Sopenharmony_ci#include "wtm.h" 248c2ecf20Sopenharmony_ci#include "stac946x.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct wtm_spec { 278c2ecf20Sopenharmony_ci /* rate change needs atomic mute/unmute of all dacs*/ 288c2ecf20Sopenharmony_ci struct mutex mute_mutex; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistatic inline void stac9460_put(struct snd_ice1712 *ice, int reg, 368c2ecf20Sopenharmony_ci unsigned char val) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_cistatic inline void stac9460_2_put(struct snd_ice1712 *ice, int reg, 508c2ecf20Sopenharmony_ci unsigned char val) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * DAC mute control 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic void stac9460_dac_mute_all(struct snd_ice1712 *ice, unsigned char mute, 658c2ecf20Sopenharmony_ci unsigned short int *change_mask) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci unsigned char new, old; 688c2ecf20Sopenharmony_ci int id, idx, change; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /*stac9460 1*/ 718c2ecf20Sopenharmony_ci for (id = 0; id < 7; id++) { 728c2ecf20Sopenharmony_ci if (*change_mask & (0x01 << id)) { 738c2ecf20Sopenharmony_ci if (id == 0) 748c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 758c2ecf20Sopenharmony_ci else 768c2ecf20Sopenharmony_ci idx = STAC946X_LF_VOLUME - 1 + id; 778c2ecf20Sopenharmony_ci old = stac9460_get(ice, idx); 788c2ecf20Sopenharmony_ci new = (~mute << 7 & 0x80) | (old & ~0x80); 798c2ecf20Sopenharmony_ci change = (new != old); 808c2ecf20Sopenharmony_ci if (change) { 818c2ecf20Sopenharmony_ci stac9460_put(ice, idx, new); 828c2ecf20Sopenharmony_ci *change_mask = *change_mask | (0x01 << id); 838c2ecf20Sopenharmony_ci } else { 848c2ecf20Sopenharmony_ci *change_mask = *change_mask & ~(0x01 << id); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /*stac9460 2*/ 908c2ecf20Sopenharmony_ci for (id = 0; id < 3; id++) { 918c2ecf20Sopenharmony_ci if (*change_mask & (0x01 << (id + 7))) { 928c2ecf20Sopenharmony_ci if (id == 0) 938c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 948c2ecf20Sopenharmony_ci else 958c2ecf20Sopenharmony_ci idx = STAC946X_LF_VOLUME - 1 + id; 968c2ecf20Sopenharmony_ci old = stac9460_2_get(ice, idx); 978c2ecf20Sopenharmony_ci new = (~mute << 7 & 0x80) | (old & ~0x80); 988c2ecf20Sopenharmony_ci change = (new != old); 998c2ecf20Sopenharmony_ci if (change) { 1008c2ecf20Sopenharmony_ci stac9460_2_put(ice, idx, new); 1018c2ecf20Sopenharmony_ci *change_mask = *change_mask | (0x01 << id); 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci *change_mask = *change_mask & ~(0x01 << id); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define stac9460_dac_mute_info snd_ctl_boolean_mono_info 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, 1148c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 1178c2ecf20Sopenharmony_ci struct wtm_spec *spec = ice->spec; 1188c2ecf20Sopenharmony_ci unsigned char val; 1198c2ecf20Sopenharmony_ci int idx, id; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci mutex_lock(&spec->mute_mutex); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (kcontrol->private_value) { 1248c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 1258c2ecf20Sopenharmony_ci id = 0; 1268c2ecf20Sopenharmony_ci } else { 1278c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1288c2ecf20Sopenharmony_ci idx = id + STAC946X_LF_VOLUME; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci if (id < 6) 1318c2ecf20Sopenharmony_ci val = stac9460_get(ice, idx); 1328c2ecf20Sopenharmony_ci else 1338c2ecf20Sopenharmony_ci val = stac9460_2_get(ice, idx - 6); 1348c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci mutex_unlock(&spec->mute_mutex); 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, 1418c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 1448c2ecf20Sopenharmony_ci unsigned char new, old; 1458c2ecf20Sopenharmony_ci int id, idx; 1468c2ecf20Sopenharmony_ci int change; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (kcontrol->private_value) { 1498c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 1508c2ecf20Sopenharmony_ci old = stac9460_get(ice, idx); 1518c2ecf20Sopenharmony_ci new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | 1528c2ecf20Sopenharmony_ci (old & ~0x80); 1538c2ecf20Sopenharmony_ci change = (new != old); 1548c2ecf20Sopenharmony_ci if (change) { 1558c2ecf20Sopenharmony_ci stac9460_put(ice, idx, new); 1568c2ecf20Sopenharmony_ci stac9460_2_put(ice, idx, new); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } else { 1598c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1608c2ecf20Sopenharmony_ci idx = id + STAC946X_LF_VOLUME; 1618c2ecf20Sopenharmony_ci if (id < 6) 1628c2ecf20Sopenharmony_ci old = stac9460_get(ice, idx); 1638c2ecf20Sopenharmony_ci else 1648c2ecf20Sopenharmony_ci old = stac9460_2_get(ice, idx - 6); 1658c2ecf20Sopenharmony_ci new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | 1668c2ecf20Sopenharmony_ci (old & ~0x80); 1678c2ecf20Sopenharmony_ci change = (new != old); 1688c2ecf20Sopenharmony_ci if (change) { 1698c2ecf20Sopenharmony_ci if (id < 6) 1708c2ecf20Sopenharmony_ci stac9460_put(ice, idx, new); 1718c2ecf20Sopenharmony_ci else 1728c2ecf20Sopenharmony_ci stac9460_2_put(ice, idx - 6, new); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci return change; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* 1798c2ecf20Sopenharmony_ci * DAC volume attenuation mixer control 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, 1828c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1858c2ecf20Sopenharmony_ci uinfo->count = 1; 1868c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; /* mute */ 1878c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0x7f; /* 0dB */ 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, 1928c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 1958c2ecf20Sopenharmony_ci int idx, id; 1968c2ecf20Sopenharmony_ci unsigned char vol; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (kcontrol->private_value) { 1998c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 2008c2ecf20Sopenharmony_ci id = 0; 2018c2ecf20Sopenharmony_ci } else { 2028c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2038c2ecf20Sopenharmony_ci idx = id + STAC946X_LF_VOLUME; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci if (id < 6) 2068c2ecf20Sopenharmony_ci vol = stac9460_get(ice, idx) & 0x7f; 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci vol = stac9460_2_get(ice, idx - 6) & 0x7f; 2098c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 0x7f - vol; 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, 2148c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2178c2ecf20Sopenharmony_ci int idx, id; 2188c2ecf20Sopenharmony_ci unsigned char tmp, ovol, nvol; 2198c2ecf20Sopenharmony_ci int change; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (kcontrol->private_value) { 2228c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 2238c2ecf20Sopenharmony_ci nvol = ucontrol->value.integer.value[0] & 0x7f; 2248c2ecf20Sopenharmony_ci tmp = stac9460_get(ice, idx); 2258c2ecf20Sopenharmony_ci ovol = 0x7f - (tmp & 0x7f); 2268c2ecf20Sopenharmony_ci change = (ovol != nvol); 2278c2ecf20Sopenharmony_ci if (change) { 2288c2ecf20Sopenharmony_ci stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 2298c2ecf20Sopenharmony_ci stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci } else { 2328c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2338c2ecf20Sopenharmony_ci idx = id + STAC946X_LF_VOLUME; 2348c2ecf20Sopenharmony_ci nvol = ucontrol->value.integer.value[0] & 0x7f; 2358c2ecf20Sopenharmony_ci if (id < 6) 2368c2ecf20Sopenharmony_ci tmp = stac9460_get(ice, idx); 2378c2ecf20Sopenharmony_ci else 2388c2ecf20Sopenharmony_ci tmp = stac9460_2_get(ice, idx - 6); 2398c2ecf20Sopenharmony_ci ovol = 0x7f - (tmp & 0x7f); 2408c2ecf20Sopenharmony_ci change = (ovol != nvol); 2418c2ecf20Sopenharmony_ci if (change) { 2428c2ecf20Sopenharmony_ci if (id < 6) 2438c2ecf20Sopenharmony_ci stac9460_put(ice, idx, (0x7f - nvol) | 2448c2ecf20Sopenharmony_ci (tmp & 0x80)); 2458c2ecf20Sopenharmony_ci else 2468c2ecf20Sopenharmony_ci stac9460_2_put(ice, idx-6, (0x7f - nvol) | 2478c2ecf20Sopenharmony_ci (tmp & 0x80)); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci return change; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* 2548c2ecf20Sopenharmony_ci * ADC mute control 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_ci#define stac9460_adc_mute_info snd_ctl_boolean_stereo_info 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, 2598c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2628c2ecf20Sopenharmony_ci unsigned char val; 2638c2ecf20Sopenharmony_ci int i, id; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2668c2ecf20Sopenharmony_ci if (id == 0) { 2678c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 2688c2ecf20Sopenharmony_ci val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); 2698c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci } else { 2728c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 2738c2ecf20Sopenharmony_ci val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i); 2748c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, 2818c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2848c2ecf20Sopenharmony_ci unsigned char new, old; 2858c2ecf20Sopenharmony_ci int i, reg, id; 2868c2ecf20Sopenharmony_ci int change; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2898c2ecf20Sopenharmony_ci if (id == 0) { 2908c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 2918c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 2928c2ecf20Sopenharmony_ci old = stac9460_get(ice, reg); 2938c2ecf20Sopenharmony_ci new = (~ucontrol->value.integer.value[i]<<7&0x80) | 2948c2ecf20Sopenharmony_ci (old&~0x80); 2958c2ecf20Sopenharmony_ci change = (new != old); 2968c2ecf20Sopenharmony_ci if (change) 2978c2ecf20Sopenharmony_ci stac9460_put(ice, reg, new); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci } else { 3008c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 3018c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 3028c2ecf20Sopenharmony_ci old = stac9460_2_get(ice, reg); 3038c2ecf20Sopenharmony_ci new = (~ucontrol->value.integer.value[i]<<7&0x80) | 3048c2ecf20Sopenharmony_ci (old&~0x80); 3058c2ecf20Sopenharmony_ci change = (new != old); 3068c2ecf20Sopenharmony_ci if (change) 3078c2ecf20Sopenharmony_ci stac9460_2_put(ice, reg, new); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci return change; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* 3148c2ecf20Sopenharmony_ci *ADC gain mixer control 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_cistatic int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, 3178c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3208c2ecf20Sopenharmony_ci uinfo->count = 2; 3218c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; /* 0dB */ 3228c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0x0f; /* 22.5dB */ 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, 3278c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 3308c2ecf20Sopenharmony_ci int i, reg, id; 3318c2ecf20Sopenharmony_ci unsigned char vol; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3348c2ecf20Sopenharmony_ci if (id == 0) { 3358c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 3368c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 3378c2ecf20Sopenharmony_ci vol = stac9460_get(ice, reg) & 0x0f; 3388c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = 0x0f - vol; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } else { 3418c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 3428c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 3438c2ecf20Sopenharmony_ci vol = stac9460_2_get(ice, reg) & 0x0f; 3448c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = 0x0f - vol; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, 3518c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 3548c2ecf20Sopenharmony_ci int i, reg, id; 3558c2ecf20Sopenharmony_ci unsigned char ovol, nvol; 3568c2ecf20Sopenharmony_ci int change; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3598c2ecf20Sopenharmony_ci if (id == 0) { 3608c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 3618c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 3628c2ecf20Sopenharmony_ci nvol = ucontrol->value.integer.value[i] & 0x0f; 3638c2ecf20Sopenharmony_ci ovol = 0x0f - stac9460_get(ice, reg); 3648c2ecf20Sopenharmony_ci change = ((ovol & 0x0f) != nvol); 3658c2ecf20Sopenharmony_ci if (change) 3668c2ecf20Sopenharmony_ci stac9460_put(ice, reg, (0x0f - nvol) | 3678c2ecf20Sopenharmony_ci (ovol & ~0x0f)); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci } else { 3708c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 3718c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 3728c2ecf20Sopenharmony_ci nvol = ucontrol->value.integer.value[i] & 0x0f; 3738c2ecf20Sopenharmony_ci ovol = 0x0f - stac9460_2_get(ice, reg); 3748c2ecf20Sopenharmony_ci change = ((ovol & 0x0f) != nvol); 3758c2ecf20Sopenharmony_ci if (change) 3768c2ecf20Sopenharmony_ci stac9460_2_put(ice, reg, (0x0f - nvol) | 3778c2ecf20Sopenharmony_ci (ovol & ~0x0f)); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci return change; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/* 3848c2ecf20Sopenharmony_ci * MIC / LINE switch fonction 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_cistatic int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, 3878c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci static const char * const texts[2] = { "Line In", "Mic" }; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, 3968c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 3998c2ecf20Sopenharmony_ci unsigned char val; 4008c2ecf20Sopenharmony_ci int id; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 4038c2ecf20Sopenharmony_ci if (id == 0) 4048c2ecf20Sopenharmony_ci val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 4058c2ecf20Sopenharmony_ci else 4068c2ecf20Sopenharmony_ci val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); 4078c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1; 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, 4128c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 4158c2ecf20Sopenharmony_ci unsigned char new, old; 4168c2ecf20Sopenharmony_ci int change, id; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 4198c2ecf20Sopenharmony_ci if (id == 0) 4208c2ecf20Sopenharmony_ci old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 4218c2ecf20Sopenharmony_ci else 4228c2ecf20Sopenharmony_ci old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); 4238c2ecf20Sopenharmony_ci new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80); 4248c2ecf20Sopenharmony_ci change = (new != old); 4258c2ecf20Sopenharmony_ci if (change) { 4268c2ecf20Sopenharmony_ci if (id == 0) 4278c2ecf20Sopenharmony_ci stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); 4288c2ecf20Sopenharmony_ci else 4298c2ecf20Sopenharmony_ci stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new); 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci return change; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* 4368c2ecf20Sopenharmony_ci * Handler for setting correct codec rate - called when rate change is detected 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_cistatic void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci unsigned char old, new; 4418c2ecf20Sopenharmony_ci unsigned short int changed; 4428c2ecf20Sopenharmony_ci struct wtm_spec *spec = ice->spec; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (rate == 0) /* no hint - S/PDIF input is master, simply return */ 4458c2ecf20Sopenharmony_ci return; 4468c2ecf20Sopenharmony_ci else if (rate <= 48000) 4478c2ecf20Sopenharmony_ci new = 0x08; /* 256x, base rate mode */ 4488c2ecf20Sopenharmony_ci else if (rate <= 96000) 4498c2ecf20Sopenharmony_ci new = 0x11; /* 256x, mid rate mode */ 4508c2ecf20Sopenharmony_ci else 4518c2ecf20Sopenharmony_ci new = 0x12; /* 128x, high rate mode */ 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); 4548c2ecf20Sopenharmony_ci if (old == new) 4558c2ecf20Sopenharmony_ci return; 4568c2ecf20Sopenharmony_ci /* change detected, setting master clock, muting first */ 4578c2ecf20Sopenharmony_ci /* due to possible conflicts with mute controls - mutexing */ 4588c2ecf20Sopenharmony_ci mutex_lock(&spec->mute_mutex); 4598c2ecf20Sopenharmony_ci /* we have to remember current mute status for each DAC */ 4608c2ecf20Sopenharmony_ci changed = 0xFFFF; 4618c2ecf20Sopenharmony_ci stac9460_dac_mute_all(ice, 0, &changed); 4628c2ecf20Sopenharmony_ci /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ 4638c2ecf20Sopenharmony_ci stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); 4648c2ecf20Sopenharmony_ci stac9460_2_put(ice, STAC946X_MASTER_CLOCKING, new); 4658c2ecf20Sopenharmony_ci udelay(10); 4668c2ecf20Sopenharmony_ci /* unmuting - only originally unmuted dacs - 4678c2ecf20Sopenharmony_ci * i.e. those changed when muting */ 4688c2ecf20Sopenharmony_ci stac9460_dac_mute_all(ice, 1, &changed); 4698c2ecf20Sopenharmony_ci mutex_unlock(&spec->mute_mutex); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/*Limits value in dB for fader*/ 4748c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); 4758c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci/* 4788c2ecf20Sopenharmony_ci * Control tabs 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new stac9640_controls[] = { 4818c2ecf20Sopenharmony_ci { 4828c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4838c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 4848c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 4858c2ecf20Sopenharmony_ci .name = "Master Playback Switch", 4868c2ecf20Sopenharmony_ci .info = stac9460_dac_mute_info, 4878c2ecf20Sopenharmony_ci .get = stac9460_dac_mute_get, 4888c2ecf20Sopenharmony_ci .put = stac9460_dac_mute_put, 4898c2ecf20Sopenharmony_ci .private_value = 1, 4908c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_dac } 4918c2ecf20Sopenharmony_ci }, 4928c2ecf20Sopenharmony_ci { 4938c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4948c2ecf20Sopenharmony_ci .name = "Master Playback Volume", 4958c2ecf20Sopenharmony_ci .info = stac9460_dac_vol_info, 4968c2ecf20Sopenharmony_ci .get = stac9460_dac_vol_get, 4978c2ecf20Sopenharmony_ci .put = stac9460_dac_vol_put, 4988c2ecf20Sopenharmony_ci .private_value = 1, 4998c2ecf20Sopenharmony_ci }, 5008c2ecf20Sopenharmony_ci { 5018c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5028c2ecf20Sopenharmony_ci .name = "MIC/Line Input Enum", 5038c2ecf20Sopenharmony_ci .count = 2, 5048c2ecf20Sopenharmony_ci .info = stac9460_mic_sw_info, 5058c2ecf20Sopenharmony_ci .get = stac9460_mic_sw_get, 5068c2ecf20Sopenharmony_ci .put = stac9460_mic_sw_put, 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci }, 5098c2ecf20Sopenharmony_ci { 5108c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5118c2ecf20Sopenharmony_ci .name = "DAC Switch", 5128c2ecf20Sopenharmony_ci .count = 8, 5138c2ecf20Sopenharmony_ci .info = stac9460_dac_mute_info, 5148c2ecf20Sopenharmony_ci .get = stac9460_dac_mute_get, 5158c2ecf20Sopenharmony_ci .put = stac9460_dac_mute_put, 5168c2ecf20Sopenharmony_ci }, 5178c2ecf20Sopenharmony_ci { 5188c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5198c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 5208c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci .name = "DAC Volume", 5238c2ecf20Sopenharmony_ci .count = 8, 5248c2ecf20Sopenharmony_ci .info = stac9460_dac_vol_info, 5258c2ecf20Sopenharmony_ci .get = stac9460_dac_vol_get, 5268c2ecf20Sopenharmony_ci .put = stac9460_dac_vol_put, 5278c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_dac } 5288c2ecf20Sopenharmony_ci }, 5298c2ecf20Sopenharmony_ci { 5308c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5318c2ecf20Sopenharmony_ci .name = "ADC Switch", 5328c2ecf20Sopenharmony_ci .count = 2, 5338c2ecf20Sopenharmony_ci .info = stac9460_adc_mute_info, 5348c2ecf20Sopenharmony_ci .get = stac9460_adc_mute_get, 5358c2ecf20Sopenharmony_ci .put = stac9460_adc_mute_put, 5368c2ecf20Sopenharmony_ci }, 5378c2ecf20Sopenharmony_ci { 5388c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5398c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 5408c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci .name = "ADC Volume", 5438c2ecf20Sopenharmony_ci .count = 2, 5448c2ecf20Sopenharmony_ci .info = stac9460_adc_vol_info, 5458c2ecf20Sopenharmony_ci .get = stac9460_adc_vol_get, 5468c2ecf20Sopenharmony_ci .put = stac9460_adc_vol_put, 5478c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_adc } 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci}; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci/*INIT*/ 5548c2ecf20Sopenharmony_cistatic int wtm_add_controls(struct snd_ice1712 *ice) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci unsigned int i; 5578c2ecf20Sopenharmony_ci int err; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) { 5608c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, 5618c2ecf20Sopenharmony_ci snd_ctl_new1(&stac9640_controls[i], ice)); 5628c2ecf20Sopenharmony_ci if (err < 0) 5638c2ecf20Sopenharmony_ci return err; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int wtm_init(struct snd_ice1712 *ice) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci static const unsigned short stac_inits_wtm[] = { 5718c2ecf20Sopenharmony_ci STAC946X_RESET, 0, 5728c2ecf20Sopenharmony_ci STAC946X_MASTER_CLOCKING, 0x11, 5738c2ecf20Sopenharmony_ci (unsigned short)-1 5748c2ecf20Sopenharmony_ci }; 5758c2ecf20Sopenharmony_ci const unsigned short *p; 5768c2ecf20Sopenharmony_ci struct wtm_spec *spec; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /*WTM 192M*/ 5798c2ecf20Sopenharmony_ci ice->num_total_dacs = 8; 5808c2ecf20Sopenharmony_ci ice->num_total_adcs = 4; 5818c2ecf20Sopenharmony_ci ice->force_rdma1 = 1; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /*init mutex for dac mute conflict*/ 5848c2ecf20Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 5858c2ecf20Sopenharmony_ci if (!spec) 5868c2ecf20Sopenharmony_ci return -ENOMEM; 5878c2ecf20Sopenharmony_ci ice->spec = spec; 5888c2ecf20Sopenharmony_ci mutex_init(&spec->mute_mutex); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /*initialize codec*/ 5928c2ecf20Sopenharmony_ci p = stac_inits_wtm; 5938c2ecf20Sopenharmony_ci for (; *p != (unsigned short)-1; p += 2) { 5948c2ecf20Sopenharmony_ci stac9460_put(ice, p[0], p[1]); 5958c2ecf20Sopenharmony_ci stac9460_2_put(ice, p[0], p[1]); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci ice->gpio.set_pro_rate = stac9460_set_rate_val; 5988c2ecf20Sopenharmony_ci return 0; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic const unsigned char wtm_eeprom[] = { 6038c2ecf20Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x67, /*SYSCONF: clock 192KHz, mpu401, 6048c2ecf20Sopenharmony_ci 4ADC, 8DAC */ 6058c2ecf20Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* ACLINK : I2S */ 6068c2ecf20Sopenharmony_ci [ICE_EEP2_I2S] = 0xf8, /* I2S: vol; 96k, 24bit, 192k */ 6078c2ecf20Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc1, /*SPDIF: out-en, spidf ext out*/ 6088c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0x9f, 6098c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 6108c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x7f, 6118c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x9f, 6128c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0xff, 6138c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x7f, 6148c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x16, 6158c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x80, 6168c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 6178c2ecf20Sopenharmony_ci}; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci/*entry point*/ 6218c2ecf20Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_wtm_cards[] = { 6228c2ecf20Sopenharmony_ci { 6238c2ecf20Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_WTM, 6248c2ecf20Sopenharmony_ci .name = "ESI Waveterminal 192M", 6258c2ecf20Sopenharmony_ci .model = "WT192M", 6268c2ecf20Sopenharmony_ci .chip_init = wtm_init, 6278c2ecf20Sopenharmony_ci .build_controls = wtm_add_controls, 6288c2ecf20Sopenharmony_ci .eeprom_size = sizeof(wtm_eeprom), 6298c2ecf20Sopenharmony_ci .eeprom_data = wtm_eeprom, 6308c2ecf20Sopenharmony_ci }, 6318c2ecf20Sopenharmony_ci {} /*terminator*/ 6328c2ecf20Sopenharmony_ci}; 633