162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ALSA driver for ICEnsemble VT1724 (Envy24HT) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Lowlevel functions for Ego Sys Waveterminal 192M 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com> 862306a36Sopenharmony_ci * Some functions are taken from the Prodigy192 driver 962306a36Sopenharmony_ci * source 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <sound/core.h> 1862306a36Sopenharmony_ci#include <sound/tlv.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "ice1712.h" 2262306a36Sopenharmony_ci#include "envy24ht.h" 2362306a36Sopenharmony_ci#include "wtm.h" 2462306a36Sopenharmony_ci#include "stac946x.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct wtm_spec { 2762306a36Sopenharmony_ci /* rate change needs atomic mute/unmute of all dacs*/ 2862306a36Sopenharmony_ci struct mutex mute_mutex; 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic inline void stac9460_put(struct snd_ice1712 *ice, int reg, 3662306a36Sopenharmony_ci unsigned char val) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_cistatic inline void stac9460_2_put(struct snd_ice1712 *ice, int reg, 5062306a36Sopenharmony_ci unsigned char val) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * DAC mute control 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistatic void stac9460_dac_mute_all(struct snd_ice1712 *ice, unsigned char mute, 6562306a36Sopenharmony_ci unsigned short int *change_mask) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci unsigned char new, old; 6862306a36Sopenharmony_ci int id, idx, change; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /*stac9460 1*/ 7162306a36Sopenharmony_ci for (id = 0; id < 7; id++) { 7262306a36Sopenharmony_ci if (*change_mask & (0x01 << id)) { 7362306a36Sopenharmony_ci if (id == 0) 7462306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 7562306a36Sopenharmony_ci else 7662306a36Sopenharmony_ci idx = STAC946X_LF_VOLUME - 1 + id; 7762306a36Sopenharmony_ci old = stac9460_get(ice, idx); 7862306a36Sopenharmony_ci new = (~mute << 7 & 0x80) | (old & ~0x80); 7962306a36Sopenharmony_ci change = (new != old); 8062306a36Sopenharmony_ci if (change) { 8162306a36Sopenharmony_ci stac9460_put(ice, idx, new); 8262306a36Sopenharmony_ci *change_mask = *change_mask | (0x01 << id); 8362306a36Sopenharmony_ci } else { 8462306a36Sopenharmony_ci *change_mask = *change_mask & ~(0x01 << id); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /*stac9460 2*/ 9062306a36Sopenharmony_ci for (id = 0; id < 3; id++) { 9162306a36Sopenharmony_ci if (*change_mask & (0x01 << (id + 7))) { 9262306a36Sopenharmony_ci if (id == 0) 9362306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 9462306a36Sopenharmony_ci else 9562306a36Sopenharmony_ci idx = STAC946X_LF_VOLUME - 1 + id; 9662306a36Sopenharmony_ci old = stac9460_2_get(ice, idx); 9762306a36Sopenharmony_ci new = (~mute << 7 & 0x80) | (old & ~0x80); 9862306a36Sopenharmony_ci change = (new != old); 9962306a36Sopenharmony_ci if (change) { 10062306a36Sopenharmony_ci stac9460_2_put(ice, idx, new); 10162306a36Sopenharmony_ci *change_mask = *change_mask | (0x01 << id); 10262306a36Sopenharmony_ci } else { 10362306a36Sopenharmony_ci *change_mask = *change_mask & ~(0x01 << id); 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define stac9460_dac_mute_info snd_ctl_boolean_mono_info 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, 11462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 11762306a36Sopenharmony_ci struct wtm_spec *spec = ice->spec; 11862306a36Sopenharmony_ci unsigned char val; 11962306a36Sopenharmony_ci int idx, id; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci mutex_lock(&spec->mute_mutex); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (kcontrol->private_value) { 12462306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 12562306a36Sopenharmony_ci id = 0; 12662306a36Sopenharmony_ci } else { 12762306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 12862306a36Sopenharmony_ci idx = id + STAC946X_LF_VOLUME; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci if (id < 6) 13162306a36Sopenharmony_ci val = stac9460_get(ice, idx); 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci val = stac9460_2_get(ice, idx - 6); 13462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci mutex_unlock(&spec->mute_mutex); 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, 14162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 14462306a36Sopenharmony_ci unsigned char new, old; 14562306a36Sopenharmony_ci int id, idx; 14662306a36Sopenharmony_ci int change; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (kcontrol->private_value) { 14962306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 15062306a36Sopenharmony_ci old = stac9460_get(ice, idx); 15162306a36Sopenharmony_ci new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | 15262306a36Sopenharmony_ci (old & ~0x80); 15362306a36Sopenharmony_ci change = (new != old); 15462306a36Sopenharmony_ci if (change) { 15562306a36Sopenharmony_ci stac9460_put(ice, idx, new); 15662306a36Sopenharmony_ci stac9460_2_put(ice, idx, new); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 16062306a36Sopenharmony_ci idx = id + STAC946X_LF_VOLUME; 16162306a36Sopenharmony_ci if (id < 6) 16262306a36Sopenharmony_ci old = stac9460_get(ice, idx); 16362306a36Sopenharmony_ci else 16462306a36Sopenharmony_ci old = stac9460_2_get(ice, idx - 6); 16562306a36Sopenharmony_ci new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | 16662306a36Sopenharmony_ci (old & ~0x80); 16762306a36Sopenharmony_ci change = (new != old); 16862306a36Sopenharmony_ci if (change) { 16962306a36Sopenharmony_ci if (id < 6) 17062306a36Sopenharmony_ci stac9460_put(ice, idx, new); 17162306a36Sopenharmony_ci else 17262306a36Sopenharmony_ci stac9460_2_put(ice, idx - 6, new); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci return change; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* 17962306a36Sopenharmony_ci * DAC volume attenuation mixer control 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistatic int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, 18262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 18562306a36Sopenharmony_ci uinfo->count = 1; 18662306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute */ 18762306a36Sopenharmony_ci uinfo->value.integer.max = 0x7f; /* 0dB */ 18862306a36Sopenharmony_ci return 0; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, 19262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 19562306a36Sopenharmony_ci int idx, id; 19662306a36Sopenharmony_ci unsigned char vol; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (kcontrol->private_value) { 19962306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 20062306a36Sopenharmony_ci id = 0; 20162306a36Sopenharmony_ci } else { 20262306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 20362306a36Sopenharmony_ci idx = id + STAC946X_LF_VOLUME; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci if (id < 6) 20662306a36Sopenharmony_ci vol = stac9460_get(ice, idx) & 0x7f; 20762306a36Sopenharmony_ci else 20862306a36Sopenharmony_ci vol = stac9460_2_get(ice, idx - 6) & 0x7f; 20962306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 0x7f - vol; 21062306a36Sopenharmony_ci return 0; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, 21462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 21762306a36Sopenharmony_ci int idx, id; 21862306a36Sopenharmony_ci unsigned char tmp, ovol, nvol; 21962306a36Sopenharmony_ci int change; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (kcontrol->private_value) { 22262306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 22362306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[0] & 0x7f; 22462306a36Sopenharmony_ci tmp = stac9460_get(ice, idx); 22562306a36Sopenharmony_ci ovol = 0x7f - (tmp & 0x7f); 22662306a36Sopenharmony_ci change = (ovol != nvol); 22762306a36Sopenharmony_ci if (change) { 22862306a36Sopenharmony_ci stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 22962306a36Sopenharmony_ci stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } else { 23262306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 23362306a36Sopenharmony_ci idx = id + STAC946X_LF_VOLUME; 23462306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[0] & 0x7f; 23562306a36Sopenharmony_ci if (id < 6) 23662306a36Sopenharmony_ci tmp = stac9460_get(ice, idx); 23762306a36Sopenharmony_ci else 23862306a36Sopenharmony_ci tmp = stac9460_2_get(ice, idx - 6); 23962306a36Sopenharmony_ci ovol = 0x7f - (tmp & 0x7f); 24062306a36Sopenharmony_ci change = (ovol != nvol); 24162306a36Sopenharmony_ci if (change) { 24262306a36Sopenharmony_ci if (id < 6) 24362306a36Sopenharmony_ci stac9460_put(ice, idx, (0x7f - nvol) | 24462306a36Sopenharmony_ci (tmp & 0x80)); 24562306a36Sopenharmony_ci else 24662306a36Sopenharmony_ci stac9460_2_put(ice, idx-6, (0x7f - nvol) | 24762306a36Sopenharmony_ci (tmp & 0x80)); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci return change; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/* 25462306a36Sopenharmony_ci * ADC mute control 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci#define stac9460_adc_mute_info snd_ctl_boolean_stereo_info 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, 25962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 26262306a36Sopenharmony_ci unsigned char val; 26362306a36Sopenharmony_ci int i, id; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 26662306a36Sopenharmony_ci if (id == 0) { 26762306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 26862306a36Sopenharmony_ci val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); 26962306a36Sopenharmony_ci ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci } else { 27262306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 27362306a36Sopenharmony_ci val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i); 27462306a36Sopenharmony_ci ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, 28162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 28462306a36Sopenharmony_ci unsigned char new, old; 28562306a36Sopenharmony_ci int i, reg, id; 28662306a36Sopenharmony_ci int change; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 28962306a36Sopenharmony_ci if (id == 0) { 29062306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 29162306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 29262306a36Sopenharmony_ci old = stac9460_get(ice, reg); 29362306a36Sopenharmony_ci new = (~ucontrol->value.integer.value[i]<<7&0x80) | 29462306a36Sopenharmony_ci (old&~0x80); 29562306a36Sopenharmony_ci change = (new != old); 29662306a36Sopenharmony_ci if (change) 29762306a36Sopenharmony_ci stac9460_put(ice, reg, new); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci } else { 30062306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 30162306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 30262306a36Sopenharmony_ci old = stac9460_2_get(ice, reg); 30362306a36Sopenharmony_ci new = (~ucontrol->value.integer.value[i]<<7&0x80) | 30462306a36Sopenharmony_ci (old&~0x80); 30562306a36Sopenharmony_ci change = (new != old); 30662306a36Sopenharmony_ci if (change) 30762306a36Sopenharmony_ci stac9460_2_put(ice, reg, new); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci return change; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/* 31462306a36Sopenharmony_ci *ADC gain mixer control 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_cistatic int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, 31762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 32062306a36Sopenharmony_ci uinfo->count = 2; 32162306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* 0dB */ 32262306a36Sopenharmony_ci uinfo->value.integer.max = 0x0f; /* 22.5dB */ 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, 32762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 33062306a36Sopenharmony_ci int i, reg, id; 33162306a36Sopenharmony_ci unsigned char vol; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 33462306a36Sopenharmony_ci if (id == 0) { 33562306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 33662306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 33762306a36Sopenharmony_ci vol = stac9460_get(ice, reg) & 0x0f; 33862306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 0x0f - vol; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } else { 34162306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 34262306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 34362306a36Sopenharmony_ci vol = stac9460_2_get(ice, reg) & 0x0f; 34462306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 0x0f - vol; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, 35162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 35462306a36Sopenharmony_ci int i, reg, id; 35562306a36Sopenharmony_ci unsigned char ovol, nvol; 35662306a36Sopenharmony_ci int change; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 35962306a36Sopenharmony_ci if (id == 0) { 36062306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 36162306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 36262306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[i] & 0x0f; 36362306a36Sopenharmony_ci ovol = 0x0f - stac9460_get(ice, reg); 36462306a36Sopenharmony_ci change = ((ovol & 0x0f) != nvol); 36562306a36Sopenharmony_ci if (change) 36662306a36Sopenharmony_ci stac9460_put(ice, reg, (0x0f - nvol) | 36762306a36Sopenharmony_ci (ovol & ~0x0f)); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci } else { 37062306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 37162306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 37262306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[i] & 0x0f; 37362306a36Sopenharmony_ci ovol = 0x0f - stac9460_2_get(ice, reg); 37462306a36Sopenharmony_ci change = ((ovol & 0x0f) != nvol); 37562306a36Sopenharmony_ci if (change) 37662306a36Sopenharmony_ci stac9460_2_put(ice, reg, (0x0f - nvol) | 37762306a36Sopenharmony_ci (ovol & ~0x0f)); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci return change; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* 38462306a36Sopenharmony_ci * MIC / LINE switch fonction 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_cistatic int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, 38762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci static const char * const texts[2] = { "Line In", "Mic" }; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, 39662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 39962306a36Sopenharmony_ci unsigned char val; 40062306a36Sopenharmony_ci int id; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 40362306a36Sopenharmony_ci if (id == 0) 40462306a36Sopenharmony_ci val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 40562306a36Sopenharmony_ci else 40662306a36Sopenharmony_ci val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); 40762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1; 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, 41262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 41562306a36Sopenharmony_ci unsigned char new, old; 41662306a36Sopenharmony_ci int change, id; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 41962306a36Sopenharmony_ci if (id == 0) 42062306a36Sopenharmony_ci old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 42162306a36Sopenharmony_ci else 42262306a36Sopenharmony_ci old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); 42362306a36Sopenharmony_ci new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80); 42462306a36Sopenharmony_ci change = (new != old); 42562306a36Sopenharmony_ci if (change) { 42662306a36Sopenharmony_ci if (id == 0) 42762306a36Sopenharmony_ci stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); 42862306a36Sopenharmony_ci else 42962306a36Sopenharmony_ci stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci return change; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci/* 43662306a36Sopenharmony_ci * Handler for setting correct codec rate - called when rate change is detected 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_cistatic void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci unsigned char old, new; 44162306a36Sopenharmony_ci unsigned short int changed; 44262306a36Sopenharmony_ci struct wtm_spec *spec = ice->spec; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (rate == 0) /* no hint - S/PDIF input is master, simply return */ 44562306a36Sopenharmony_ci return; 44662306a36Sopenharmony_ci else if (rate <= 48000) 44762306a36Sopenharmony_ci new = 0x08; /* 256x, base rate mode */ 44862306a36Sopenharmony_ci else if (rate <= 96000) 44962306a36Sopenharmony_ci new = 0x11; /* 256x, mid rate mode */ 45062306a36Sopenharmony_ci else 45162306a36Sopenharmony_ci new = 0x12; /* 128x, high rate mode */ 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); 45462306a36Sopenharmony_ci if (old == new) 45562306a36Sopenharmony_ci return; 45662306a36Sopenharmony_ci /* change detected, setting master clock, muting first */ 45762306a36Sopenharmony_ci /* due to possible conflicts with mute controls - mutexing */ 45862306a36Sopenharmony_ci mutex_lock(&spec->mute_mutex); 45962306a36Sopenharmony_ci /* we have to remember current mute status for each DAC */ 46062306a36Sopenharmony_ci changed = 0xFFFF; 46162306a36Sopenharmony_ci stac9460_dac_mute_all(ice, 0, &changed); 46262306a36Sopenharmony_ci /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ 46362306a36Sopenharmony_ci stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); 46462306a36Sopenharmony_ci stac9460_2_put(ice, STAC946X_MASTER_CLOCKING, new); 46562306a36Sopenharmony_ci udelay(10); 46662306a36Sopenharmony_ci /* unmuting - only originally unmuted dacs - 46762306a36Sopenharmony_ci * i.e. those changed when muting */ 46862306a36Sopenharmony_ci stac9460_dac_mute_all(ice, 1, &changed); 46962306a36Sopenharmony_ci mutex_unlock(&spec->mute_mutex); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/*Limits value in dB for fader*/ 47462306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); 47562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/* 47862306a36Sopenharmony_ci * Control tabs 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cistatic const struct snd_kcontrol_new stac9640_controls[] = { 48162306a36Sopenharmony_ci { 48262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 48362306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 48462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 48562306a36Sopenharmony_ci .name = "Master Playback Switch", 48662306a36Sopenharmony_ci .info = stac9460_dac_mute_info, 48762306a36Sopenharmony_ci .get = stac9460_dac_mute_get, 48862306a36Sopenharmony_ci .put = stac9460_dac_mute_put, 48962306a36Sopenharmony_ci .private_value = 1, 49062306a36Sopenharmony_ci .tlv = { .p = db_scale_dac } 49162306a36Sopenharmony_ci }, 49262306a36Sopenharmony_ci { 49362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 49462306a36Sopenharmony_ci .name = "Master Playback Volume", 49562306a36Sopenharmony_ci .info = stac9460_dac_vol_info, 49662306a36Sopenharmony_ci .get = stac9460_dac_vol_get, 49762306a36Sopenharmony_ci .put = stac9460_dac_vol_put, 49862306a36Sopenharmony_ci .private_value = 1, 49962306a36Sopenharmony_ci }, 50062306a36Sopenharmony_ci { 50162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 50262306a36Sopenharmony_ci .name = "MIC/Line Input Enum", 50362306a36Sopenharmony_ci .count = 2, 50462306a36Sopenharmony_ci .info = stac9460_mic_sw_info, 50562306a36Sopenharmony_ci .get = stac9460_mic_sw_get, 50662306a36Sopenharmony_ci .put = stac9460_mic_sw_put, 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci }, 50962306a36Sopenharmony_ci { 51062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 51162306a36Sopenharmony_ci .name = "DAC Switch", 51262306a36Sopenharmony_ci .count = 8, 51362306a36Sopenharmony_ci .info = stac9460_dac_mute_info, 51462306a36Sopenharmony_ci .get = stac9460_dac_mute_get, 51562306a36Sopenharmony_ci .put = stac9460_dac_mute_put, 51662306a36Sopenharmony_ci }, 51762306a36Sopenharmony_ci { 51862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 51962306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 52062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci .name = "DAC Volume", 52362306a36Sopenharmony_ci .count = 8, 52462306a36Sopenharmony_ci .info = stac9460_dac_vol_info, 52562306a36Sopenharmony_ci .get = stac9460_dac_vol_get, 52662306a36Sopenharmony_ci .put = stac9460_dac_vol_put, 52762306a36Sopenharmony_ci .tlv = { .p = db_scale_dac } 52862306a36Sopenharmony_ci }, 52962306a36Sopenharmony_ci { 53062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 53162306a36Sopenharmony_ci .name = "ADC Switch", 53262306a36Sopenharmony_ci .count = 2, 53362306a36Sopenharmony_ci .info = stac9460_adc_mute_info, 53462306a36Sopenharmony_ci .get = stac9460_adc_mute_get, 53562306a36Sopenharmony_ci .put = stac9460_adc_mute_put, 53662306a36Sopenharmony_ci }, 53762306a36Sopenharmony_ci { 53862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 53962306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 54062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci .name = "ADC Volume", 54362306a36Sopenharmony_ci .count = 2, 54462306a36Sopenharmony_ci .info = stac9460_adc_vol_info, 54562306a36Sopenharmony_ci .get = stac9460_adc_vol_get, 54662306a36Sopenharmony_ci .put = stac9460_adc_vol_put, 54762306a36Sopenharmony_ci .tlv = { .p = db_scale_adc } 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci}; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/*INIT*/ 55462306a36Sopenharmony_cistatic int wtm_add_controls(struct snd_ice1712 *ice) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci unsigned int i; 55762306a36Sopenharmony_ci int err; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) { 56062306a36Sopenharmony_ci err = snd_ctl_add(ice->card, 56162306a36Sopenharmony_ci snd_ctl_new1(&stac9640_controls[i], ice)); 56262306a36Sopenharmony_ci if (err < 0) 56362306a36Sopenharmony_ci return err; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci return 0; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic int wtm_init(struct snd_ice1712 *ice) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci static const unsigned short stac_inits_wtm[] = { 57162306a36Sopenharmony_ci STAC946X_RESET, 0, 57262306a36Sopenharmony_ci STAC946X_MASTER_CLOCKING, 0x11, 57362306a36Sopenharmony_ci (unsigned short)-1 57462306a36Sopenharmony_ci }; 57562306a36Sopenharmony_ci const unsigned short *p; 57662306a36Sopenharmony_ci struct wtm_spec *spec; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /*WTM 192M*/ 57962306a36Sopenharmony_ci ice->num_total_dacs = 8; 58062306a36Sopenharmony_ci ice->num_total_adcs = 4; 58162306a36Sopenharmony_ci ice->force_rdma1 = 1; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /*init mutex for dac mute conflict*/ 58462306a36Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 58562306a36Sopenharmony_ci if (!spec) 58662306a36Sopenharmony_ci return -ENOMEM; 58762306a36Sopenharmony_ci ice->spec = spec; 58862306a36Sopenharmony_ci mutex_init(&spec->mute_mutex); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /*initialize codec*/ 59262306a36Sopenharmony_ci p = stac_inits_wtm; 59362306a36Sopenharmony_ci for (; *p != (unsigned short)-1; p += 2) { 59462306a36Sopenharmony_ci stac9460_put(ice, p[0], p[1]); 59562306a36Sopenharmony_ci stac9460_2_put(ice, p[0], p[1]); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci ice->gpio.set_pro_rate = stac9460_set_rate_val; 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic const unsigned char wtm_eeprom[] = { 60362306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x67, /*SYSCONF: clock 192KHz, mpu401, 60462306a36Sopenharmony_ci 4ADC, 8DAC */ 60562306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* ACLINK : I2S */ 60662306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xf8, /* I2S: vol; 96k, 24bit, 192k */ 60762306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc1, /*SPDIF: out-en, spidf ext out*/ 60862306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0x9f, 60962306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 61062306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x7f, 61162306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x9f, 61262306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0xff, 61362306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x7f, 61462306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x16, 61562306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x80, 61662306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 61762306a36Sopenharmony_ci}; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci/*entry point*/ 62162306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_wtm_cards[] = { 62262306a36Sopenharmony_ci { 62362306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_WTM, 62462306a36Sopenharmony_ci .name = "ESI Waveterminal 192M", 62562306a36Sopenharmony_ci .model = "WT192M", 62662306a36Sopenharmony_ci .chip_init = wtm_init, 62762306a36Sopenharmony_ci .build_controls = wtm_add_controls, 62862306a36Sopenharmony_ci .eeprom_size = sizeof(wtm_eeprom), 62962306a36Sopenharmony_ci .eeprom_data = wtm_eeprom, 63062306a36Sopenharmony_ci }, 63162306a36Sopenharmony_ci {} /*terminator*/ 63262306a36Sopenharmony_ci}; 633