1f6cdab5fSClement Guedez /* 2f6cdab5fSClement Guedez * ALSA driver for ICEnsemble VT1724 (Envy24HT) 3f6cdab5fSClement Guedez * 4f6cdab5fSClement Guedez * Lowlevel functions for Ego Sys Waveterminal 192M 5f6cdab5fSClement Guedez * 6f6cdab5fSClement Guedez * Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com> 7f6cdab5fSClement Guedez * Some functions are taken from the Prodigy192 driver 8f6cdab5fSClement Guedez * source 9f6cdab5fSClement Guedez * 10f6cdab5fSClement Guedez * This program is free software; you can redistribute it and/or modify 11f6cdab5fSClement Guedez * it under the terms of the GNU General Public License as published by 12f6cdab5fSClement Guedez * the Free Software Foundation; either version 2 of the License, or 13f6cdab5fSClement Guedez * (at your option) any later version. 14f6cdab5fSClement Guedez * 15f6cdab5fSClement Guedez * This program is distributed in the hope that it will be useful, 16f6cdab5fSClement Guedez * but WITHOUT ANY WARRANTY; without even the implied warranty of 17f6cdab5fSClement Guedez * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18f6cdab5fSClement Guedez * GNU General Public License for more details. 19f6cdab5fSClement Guedez * 20f6cdab5fSClement Guedez * You should have received a copy of the GNU General Public License 21f6cdab5fSClement Guedez * along with this program; if not, write to the Free Software 22f6cdab5fSClement Guedez * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23f6cdab5fSClement Guedez * 24f6cdab5fSClement Guedez */ 25f6cdab5fSClement Guedez 26f6cdab5fSClement Guedez 27f6cdab5fSClement Guedez 28f6cdab5fSClement Guedez #include <linux/delay.h> 29f6cdab5fSClement Guedez #include <linux/interrupt.h> 30f6cdab5fSClement Guedez #include <linux/init.h> 31f6cdab5fSClement Guedez #include <sound/core.h> 3216ddbe73SClément Guedez #include <sound/tlv.h> 33*1aa9a4eaSClément Guedez #include <linux/slab.h> 34f6cdab5fSClement Guedez 35f6cdab5fSClement Guedez #include "ice1712.h" 36f6cdab5fSClement Guedez #include "envy24ht.h" 37f6cdab5fSClement Guedez #include "wtm.h" 38f6cdab5fSClement Guedez #include "stac946x.h" 39f6cdab5fSClement Guedez 40*1aa9a4eaSClément Guedez struct wtm_spec { 41*1aa9a4eaSClément Guedez /* rate change needs atomic mute/unmute of all dacs*/ 42*1aa9a4eaSClément Guedez struct mutex mute_mutex; 43*1aa9a4eaSClément Guedez }; 44*1aa9a4eaSClément Guedez 45f6cdab5fSClement Guedez 46f6cdab5fSClement Guedez /* 47f6cdab5fSClement Guedez * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus 48f6cdab5fSClement Guedez */ 49f6cdab5fSClement Guedez static inline void stac9460_put(struct snd_ice1712 *ice, int reg, 50f6cdab5fSClement Guedez unsigned char val) 51f6cdab5fSClement Guedez { 52f6cdab5fSClement Guedez snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val); 53f6cdab5fSClement Guedez } 54f6cdab5fSClement Guedez 55f6cdab5fSClement Guedez static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) 56f6cdab5fSClement Guedez { 57f6cdab5fSClement Guedez return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg); 58f6cdab5fSClement Guedez } 59f6cdab5fSClement Guedez 60f6cdab5fSClement Guedez /* 61f6cdab5fSClement Guedez * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus 62f6cdab5fSClement Guedez */ 63f6cdab5fSClement Guedez static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg, 64f6cdab5fSClement Guedez unsigned char val) 65f6cdab5fSClement Guedez { 66f6cdab5fSClement Guedez snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val); 67f6cdab5fSClement Guedez } 68f6cdab5fSClement Guedez 69f6cdab5fSClement Guedez static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) 70f6cdab5fSClement Guedez { 71f6cdab5fSClement Guedez return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg); 72f6cdab5fSClement Guedez } 73f6cdab5fSClement Guedez 74f6cdab5fSClement Guedez 75f6cdab5fSClement Guedez /* 76f6cdab5fSClement Guedez * DAC mute control 77f6cdab5fSClement Guedez */ 78*1aa9a4eaSClément Guedez static void stac9460_dac_mute_all(struct snd_ice1712 *ice, unsigned char mute, 79*1aa9a4eaSClément Guedez unsigned short int *change_mask) 80*1aa9a4eaSClément Guedez { 81*1aa9a4eaSClément Guedez unsigned char new, old; 82*1aa9a4eaSClément Guedez int id, idx, change; 83*1aa9a4eaSClément Guedez 84*1aa9a4eaSClément Guedez /*stac9460 1*/ 85*1aa9a4eaSClément Guedez for (id = 0; id < 7; id++) { 86*1aa9a4eaSClément Guedez if (*change_mask & (0x01 << id)) { 87*1aa9a4eaSClément Guedez if (id == 0) 88*1aa9a4eaSClément Guedez idx = STAC946X_MASTER_VOLUME; 89*1aa9a4eaSClément Guedez else 90*1aa9a4eaSClément Guedez idx = STAC946X_LF_VOLUME - 1 + id; 91*1aa9a4eaSClément Guedez old = stac9460_get(ice, idx); 92*1aa9a4eaSClément Guedez new = (~mute << 7 & 0x80) | (old & ~0x80); 93*1aa9a4eaSClément Guedez change = (new != old); 94*1aa9a4eaSClément Guedez if (change) { 95*1aa9a4eaSClément Guedez stac9460_put(ice, idx, new); 96*1aa9a4eaSClément Guedez *change_mask = *change_mask | (0x01 << id); 97*1aa9a4eaSClément Guedez } else { 98*1aa9a4eaSClément Guedez *change_mask = *change_mask & ~(0x01 << id); 99*1aa9a4eaSClément Guedez } 100*1aa9a4eaSClément Guedez } 101*1aa9a4eaSClément Guedez } 102*1aa9a4eaSClément Guedez 103*1aa9a4eaSClément Guedez /*stac9460 2*/ 104*1aa9a4eaSClément Guedez for (id = 0; id < 3; id++) { 105*1aa9a4eaSClément Guedez if (*change_mask & (0x01 << (id + 7))) { 106*1aa9a4eaSClément Guedez if (id == 0) 107*1aa9a4eaSClément Guedez idx = STAC946X_MASTER_VOLUME; 108*1aa9a4eaSClément Guedez else 109*1aa9a4eaSClément Guedez idx = STAC946X_LF_VOLUME - 1 + id; 110*1aa9a4eaSClément Guedez old = stac9460_2_get(ice, idx); 111*1aa9a4eaSClément Guedez new = (~mute << 7 & 0x80) | (old & ~0x80); 112*1aa9a4eaSClément Guedez change = (new != old); 113*1aa9a4eaSClément Guedez if (change) { 114*1aa9a4eaSClément Guedez stac9460_2_put(ice, idx, new); 115*1aa9a4eaSClément Guedez *change_mask = *change_mask | (0x01 << id); 116*1aa9a4eaSClément Guedez } else { 117*1aa9a4eaSClément Guedez *change_mask = *change_mask & ~(0x01 << id); 118*1aa9a4eaSClément Guedez } 119*1aa9a4eaSClément Guedez } 120*1aa9a4eaSClément Guedez } 121*1aa9a4eaSClément Guedez } 122*1aa9a4eaSClément Guedez 123*1aa9a4eaSClément Guedez 124*1aa9a4eaSClément Guedez 125a5ce8890STakashi Iwai #define stac9460_dac_mute_info snd_ctl_boolean_mono_info 126f6cdab5fSClement Guedez 127f6cdab5fSClement Guedez static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, 128f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 129f6cdab5fSClement Guedez { 130f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 131*1aa9a4eaSClément Guedez struct wtm_spec *spec = ice->spec; 132f6cdab5fSClement Guedez unsigned char val; 133f6cdab5fSClement Guedez int idx, id; 134f6cdab5fSClement Guedez 135*1aa9a4eaSClément Guedez mutex_lock(&spec->mute_mutex); 136*1aa9a4eaSClément Guedez 137f6cdab5fSClement Guedez if (kcontrol->private_value) { 138f6cdab5fSClement Guedez idx = STAC946X_MASTER_VOLUME; 139f6cdab5fSClement Guedez id = 0; 140f6cdab5fSClement Guedez } else { 141f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 142f6cdab5fSClement Guedez idx = id + STAC946X_LF_VOLUME; 143f6cdab5fSClement Guedez } 144f6cdab5fSClement Guedez if (id < 6) 145f6cdab5fSClement Guedez val = stac9460_get(ice, idx); 146f6cdab5fSClement Guedez else 147f6cdab5fSClement Guedez val = stac9460_2_get(ice, idx - 6); 148f6cdab5fSClement Guedez ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; 149*1aa9a4eaSClément Guedez 150*1aa9a4eaSClément Guedez mutex_unlock(&spec->mute_mutex); 151f6cdab5fSClement Guedez return 0; 152f6cdab5fSClement Guedez } 153f6cdab5fSClement Guedez 154f6cdab5fSClement Guedez static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, 155f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 156f6cdab5fSClement Guedez { 157f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 158f6cdab5fSClement Guedez unsigned char new, old; 159f6cdab5fSClement Guedez int id, idx; 160f6cdab5fSClement Guedez int change; 161f6cdab5fSClement Guedez 162f6cdab5fSClement Guedez if (kcontrol->private_value) { 163f6cdab5fSClement Guedez idx = STAC946X_MASTER_VOLUME; 164f6cdab5fSClement Guedez old = stac9460_get(ice, idx); 165f6cdab5fSClement Guedez new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | 166f6cdab5fSClement Guedez (old & ~0x80); 167f6cdab5fSClement Guedez change = (new != old); 168f6cdab5fSClement Guedez if (change) { 169f6cdab5fSClement Guedez stac9460_put(ice, idx, new); 170f6cdab5fSClement Guedez stac9460_2_put(ice, idx, new); 171f6cdab5fSClement Guedez } 172f6cdab5fSClement Guedez } else { 173f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 174f6cdab5fSClement Guedez idx = id + STAC946X_LF_VOLUME; 175f6cdab5fSClement Guedez if (id < 6) 176f6cdab5fSClement Guedez old = stac9460_get(ice, idx); 177f6cdab5fSClement Guedez else 178f6cdab5fSClement Guedez old = stac9460_2_get(ice, idx - 6); 179f6cdab5fSClement Guedez new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | 180f6cdab5fSClement Guedez (old & ~0x80); 181f6cdab5fSClement Guedez change = (new != old); 182f6cdab5fSClement Guedez if (change) { 183f6cdab5fSClement Guedez if (id < 6) 184f6cdab5fSClement Guedez stac9460_put(ice, idx, new); 185f6cdab5fSClement Guedez else 186f6cdab5fSClement Guedez stac9460_2_put(ice, idx - 6, new); 187f6cdab5fSClement Guedez } 188f6cdab5fSClement Guedez } 189f6cdab5fSClement Guedez return change; 190f6cdab5fSClement Guedez } 191f6cdab5fSClement Guedez 192f6cdab5fSClement Guedez /* 193f6cdab5fSClement Guedez * DAC volume attenuation mixer control 194f6cdab5fSClement Guedez */ 195f6cdab5fSClement Guedez static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, 196f6cdab5fSClement Guedez struct snd_ctl_elem_info *uinfo) 197f6cdab5fSClement Guedez { 198f6cdab5fSClement Guedez uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 199f6cdab5fSClement Guedez uinfo->count = 1; 200f6cdab5fSClement Guedez uinfo->value.integer.min = 0; /* mute */ 201f6cdab5fSClement Guedez uinfo->value.integer.max = 0x7f; /* 0dB */ 202f6cdab5fSClement Guedez return 0; 203f6cdab5fSClement Guedez } 204f6cdab5fSClement Guedez 205f6cdab5fSClement Guedez static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, 206f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 207f6cdab5fSClement Guedez { 208f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 209f6cdab5fSClement Guedez int idx, id; 210f6cdab5fSClement Guedez unsigned char vol; 211f6cdab5fSClement Guedez 212f6cdab5fSClement Guedez if (kcontrol->private_value) { 213f6cdab5fSClement Guedez idx = STAC946X_MASTER_VOLUME; 214f6cdab5fSClement Guedez id = 0; 215f6cdab5fSClement Guedez } else { 216f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 217f6cdab5fSClement Guedez idx = id + STAC946X_LF_VOLUME; 218f6cdab5fSClement Guedez } 219f6cdab5fSClement Guedez if (id < 6) 220f6cdab5fSClement Guedez vol = stac9460_get(ice, idx) & 0x7f; 221f6cdab5fSClement Guedez else 222f6cdab5fSClement Guedez vol = stac9460_2_get(ice, idx - 6) & 0x7f; 223f6cdab5fSClement Guedez ucontrol->value.integer.value[0] = 0x7f - vol; 224f6cdab5fSClement Guedez return 0; 225f6cdab5fSClement Guedez } 226f6cdab5fSClement Guedez 227f6cdab5fSClement Guedez static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, 228f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 229f6cdab5fSClement Guedez { 230f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 231f6cdab5fSClement Guedez int idx, id; 232f6cdab5fSClement Guedez unsigned char tmp, ovol, nvol; 233f6cdab5fSClement Guedez int change; 234f6cdab5fSClement Guedez 235f6cdab5fSClement Guedez if (kcontrol->private_value) { 236f6cdab5fSClement Guedez idx = STAC946X_MASTER_VOLUME; 2379cd17cd2STakashi Iwai nvol = ucontrol->value.integer.value[0] & 0x7f; 238f6cdab5fSClement Guedez tmp = stac9460_get(ice, idx); 239f6cdab5fSClement Guedez ovol = 0x7f - (tmp & 0x7f); 240f6cdab5fSClement Guedez change = (ovol != nvol); 241f6cdab5fSClement Guedez if (change) { 242f6cdab5fSClement Guedez stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 243f6cdab5fSClement Guedez stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 244f6cdab5fSClement Guedez } 245f6cdab5fSClement Guedez } else { 246f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 247f6cdab5fSClement Guedez idx = id + STAC946X_LF_VOLUME; 2489cd17cd2STakashi Iwai nvol = ucontrol->value.integer.value[0] & 0x7f; 249f6cdab5fSClement Guedez if (id < 6) 250f6cdab5fSClement Guedez tmp = stac9460_get(ice, idx); 251f6cdab5fSClement Guedez else 252f6cdab5fSClement Guedez tmp = stac9460_2_get(ice, idx - 6); 253f6cdab5fSClement Guedez ovol = 0x7f - (tmp & 0x7f); 254f6cdab5fSClement Guedez change = (ovol != nvol); 255f6cdab5fSClement Guedez if (change) { 256f6cdab5fSClement Guedez if (id < 6) 257f6cdab5fSClement Guedez stac9460_put(ice, idx, (0x7f - nvol) | 258f6cdab5fSClement Guedez (tmp & 0x80)); 259f6cdab5fSClement Guedez else 260f6cdab5fSClement Guedez stac9460_2_put(ice, idx-6, (0x7f - nvol) | 261f6cdab5fSClement Guedez (tmp & 0x80)); 262f6cdab5fSClement Guedez } 263f6cdab5fSClement Guedez } 264f6cdab5fSClement Guedez return change; 265f6cdab5fSClement Guedez } 266f6cdab5fSClement Guedez 267f6cdab5fSClement Guedez /* 268f6cdab5fSClement Guedez * ADC mute control 269f6cdab5fSClement Guedez */ 270a5ce8890STakashi Iwai #define stac9460_adc_mute_info snd_ctl_boolean_stereo_info 271f6cdab5fSClement Guedez 272f6cdab5fSClement Guedez static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, 273f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 274f6cdab5fSClement Guedez { 275f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 276f6cdab5fSClement Guedez unsigned char val; 277f6cdab5fSClement Guedez int i, id; 278f6cdab5fSClement Guedez 279f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 280f6cdab5fSClement Guedez if (id == 0) { 281f6cdab5fSClement Guedez for (i = 0; i < 2; ++i) { 282f6cdab5fSClement Guedez val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); 283f6cdab5fSClement Guedez ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 284f6cdab5fSClement Guedez } 285f6cdab5fSClement Guedez } else { 286f6cdab5fSClement Guedez for (i = 0; i < 2; ++i) { 287f6cdab5fSClement Guedez val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i); 288f6cdab5fSClement Guedez ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 289f6cdab5fSClement Guedez } 290f6cdab5fSClement Guedez } 291f6cdab5fSClement Guedez return 0; 292f6cdab5fSClement Guedez } 293f6cdab5fSClement Guedez 294f6cdab5fSClement Guedez static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, 295f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 296f6cdab5fSClement Guedez { 297f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 298f6cdab5fSClement Guedez unsigned char new, old; 299f6cdab5fSClement Guedez int i, reg, id; 300f6cdab5fSClement Guedez int change; 301f6cdab5fSClement Guedez 302f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 303f6cdab5fSClement Guedez if (id == 0) { 304f6cdab5fSClement Guedez for (i = 0; i < 2; ++i) { 305f6cdab5fSClement Guedez reg = STAC946X_MIC_L_VOLUME + i; 306f6cdab5fSClement Guedez old = stac9460_get(ice, reg); 307f6cdab5fSClement Guedez new = (~ucontrol->value.integer.value[i]<<7&0x80) | 308f6cdab5fSClement Guedez (old&~0x80); 309f6cdab5fSClement Guedez change = (new != old); 310f6cdab5fSClement Guedez if (change) 311f6cdab5fSClement Guedez stac9460_put(ice, reg, new); 312f6cdab5fSClement Guedez } 313f6cdab5fSClement Guedez } else { 314f6cdab5fSClement Guedez for (i = 0; i < 2; ++i) { 315f6cdab5fSClement Guedez reg = STAC946X_MIC_L_VOLUME + i; 316f6cdab5fSClement Guedez old = stac9460_2_get(ice, reg); 317f6cdab5fSClement Guedez new = (~ucontrol->value.integer.value[i]<<7&0x80) | 318f6cdab5fSClement Guedez (old&~0x80); 319f6cdab5fSClement Guedez change = (new != old); 320f6cdab5fSClement Guedez if (change) 321f6cdab5fSClement Guedez stac9460_2_put(ice, reg, new); 322f6cdab5fSClement Guedez } 323f6cdab5fSClement Guedez } 324f6cdab5fSClement Guedez return change; 325f6cdab5fSClement Guedez } 326f6cdab5fSClement Guedez 327f6cdab5fSClement Guedez /* 328f6cdab5fSClement Guedez *ADC gain mixer control 329f6cdab5fSClement Guedez */ 330f6cdab5fSClement Guedez static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, 331f6cdab5fSClement Guedez struct snd_ctl_elem_info *uinfo) 332f6cdab5fSClement Guedez { 333f6cdab5fSClement Guedez uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 334f6cdab5fSClement Guedez uinfo->count = 2; 335f6cdab5fSClement Guedez uinfo->value.integer.min = 0; /* 0dB */ 336f6cdab5fSClement Guedez uinfo->value.integer.max = 0x0f; /* 22.5dB */ 337f6cdab5fSClement Guedez return 0; 338f6cdab5fSClement Guedez } 339f6cdab5fSClement Guedez 340f6cdab5fSClement Guedez static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, 341f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 342f6cdab5fSClement Guedez { 343f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 344f6cdab5fSClement Guedez int i, reg, id; 345f6cdab5fSClement Guedez unsigned char vol; 346f6cdab5fSClement Guedez 347f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 348f6cdab5fSClement Guedez if (id == 0) { 349f6cdab5fSClement Guedez for (i = 0; i < 2; ++i) { 350f6cdab5fSClement Guedez reg = STAC946X_MIC_L_VOLUME + i; 351f6cdab5fSClement Guedez vol = stac9460_get(ice, reg) & 0x0f; 352f6cdab5fSClement Guedez ucontrol->value.integer.value[i] = 0x0f - vol; 353f6cdab5fSClement Guedez } 354f6cdab5fSClement Guedez } else { 355f6cdab5fSClement Guedez for (i = 0; i < 2; ++i) { 356f6cdab5fSClement Guedez reg = STAC946X_MIC_L_VOLUME + i; 357f6cdab5fSClement Guedez vol = stac9460_2_get(ice, reg) & 0x0f; 358f6cdab5fSClement Guedez ucontrol->value.integer.value[i] = 0x0f - vol; 359f6cdab5fSClement Guedez } 360f6cdab5fSClement Guedez } 361f6cdab5fSClement Guedez return 0; 362f6cdab5fSClement Guedez } 363f6cdab5fSClement Guedez 364f6cdab5fSClement Guedez static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, 365f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 366f6cdab5fSClement Guedez { 367f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 368f6cdab5fSClement Guedez int i, reg, id; 369f6cdab5fSClement Guedez unsigned char ovol, nvol; 370f6cdab5fSClement Guedez int change; 371f6cdab5fSClement Guedez 372f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 373f6cdab5fSClement Guedez if (id == 0) { 374f6cdab5fSClement Guedez for (i = 0; i < 2; ++i) { 375f6cdab5fSClement Guedez reg = STAC946X_MIC_L_VOLUME + i; 3769cd17cd2STakashi Iwai nvol = ucontrol->value.integer.value[i] & 0x0f; 377f6cdab5fSClement Guedez ovol = 0x0f - stac9460_get(ice, reg); 378f6cdab5fSClement Guedez change = ((ovol & 0x0f) != nvol); 379f6cdab5fSClement Guedez if (change) 380f6cdab5fSClement Guedez stac9460_put(ice, reg, (0x0f - nvol) | 381f6cdab5fSClement Guedez (ovol & ~0x0f)); 382f6cdab5fSClement Guedez } 383f6cdab5fSClement Guedez } else { 384f6cdab5fSClement Guedez for (i = 0; i < 2; ++i) { 385f6cdab5fSClement Guedez reg = STAC946X_MIC_L_VOLUME + i; 3869cd17cd2STakashi Iwai nvol = ucontrol->value.integer.value[i] & 0x0f; 387f6cdab5fSClement Guedez ovol = 0x0f - stac9460_2_get(ice, reg); 388f6cdab5fSClement Guedez change = ((ovol & 0x0f) != nvol); 389f6cdab5fSClement Guedez if (change) 390f6cdab5fSClement Guedez stac9460_2_put(ice, reg, (0x0f - nvol) | 391f6cdab5fSClement Guedez (ovol & ~0x0f)); 392f6cdab5fSClement Guedez } 393f6cdab5fSClement Guedez } 394f6cdab5fSClement Guedez return change; 395f6cdab5fSClement Guedez } 396f6cdab5fSClement Guedez 397f6cdab5fSClement Guedez /* 398f6cdab5fSClement Guedez * MIC / LINE switch fonction 399f6cdab5fSClement Guedez */ 400ae8a9a11SClément Guedez static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, 401ae8a9a11SClément Guedez struct snd_ctl_elem_info *uinfo) 402ae8a9a11SClément Guedez { 403ae8a9a11SClément Guedez static const char * const texts[2] = { "Line In", "Mic" }; 404f6cdab5fSClement Guedez 405ae8a9a11SClément Guedez return snd_ctl_enum_info(uinfo, 1, 2, texts); 406ae8a9a11SClément Guedez } 407ae8a9a11SClément Guedez 408f6cdab5fSClement Guedez 409f6cdab5fSClement Guedez static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, 410f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 411f6cdab5fSClement Guedez { 412f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 413f6cdab5fSClement Guedez unsigned char val; 414f6cdab5fSClement Guedez int id; 415f6cdab5fSClement Guedez 416f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 417f6cdab5fSClement Guedez if (id == 0) 418f6cdab5fSClement Guedez val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 419f6cdab5fSClement Guedez else 420f6cdab5fSClement Guedez val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); 421ae8a9a11SClément Guedez ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1; 422f6cdab5fSClement Guedez return 0; 423f6cdab5fSClement Guedez } 424f6cdab5fSClement Guedez 425f6cdab5fSClement Guedez static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, 426f6cdab5fSClement Guedez struct snd_ctl_elem_value *ucontrol) 427f6cdab5fSClement Guedez { 428f6cdab5fSClement Guedez struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 429f6cdab5fSClement Guedez unsigned char new, old; 430f6cdab5fSClement Guedez int change, id; 431f6cdab5fSClement Guedez 432f6cdab5fSClement Guedez id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 433f6cdab5fSClement Guedez if (id == 0) 434f6cdab5fSClement Guedez old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 435f6cdab5fSClement Guedez else 436f6cdab5fSClement Guedez old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); 437ae8a9a11SClément Guedez new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80); 438f6cdab5fSClement Guedez change = (new != old); 439f6cdab5fSClement Guedez if (change) { 440f6cdab5fSClement Guedez if (id == 0) 441f6cdab5fSClement Guedez stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); 442f6cdab5fSClement Guedez else 443f6cdab5fSClement Guedez stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new); 444f6cdab5fSClement Guedez } 445f6cdab5fSClement Guedez return change; 446f6cdab5fSClement Guedez } 447f6cdab5fSClement Guedez 44816ddbe73SClément Guedez 449*1aa9a4eaSClément Guedez /* 450*1aa9a4eaSClément Guedez * Handler for setting correct codec rate - called when rate change is detected 451*1aa9a4eaSClément Guedez */ 452*1aa9a4eaSClément Guedez static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) 453*1aa9a4eaSClément Guedez { 454*1aa9a4eaSClément Guedez unsigned char old, new; 455*1aa9a4eaSClément Guedez unsigned short int changed; 456*1aa9a4eaSClément Guedez struct wtm_spec *spec = ice->spec; 457*1aa9a4eaSClément Guedez 458*1aa9a4eaSClément Guedez if (rate == 0) /* no hint - S/PDIF input is master, simply return */ 459*1aa9a4eaSClément Guedez return; 460*1aa9a4eaSClément Guedez else if (rate <= 48000) 461*1aa9a4eaSClément Guedez new = 0x08; /* 256x, base rate mode */ 462*1aa9a4eaSClément Guedez else if (rate <= 96000) 463*1aa9a4eaSClément Guedez new = 0x11; /* 256x, mid rate mode */ 464*1aa9a4eaSClément Guedez else 465*1aa9a4eaSClément Guedez new = 0x12; /* 128x, high rate mode */ 466*1aa9a4eaSClément Guedez 467*1aa9a4eaSClément Guedez old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); 468*1aa9a4eaSClément Guedez if (old == new) 469*1aa9a4eaSClément Guedez return; 470*1aa9a4eaSClément Guedez /* change detected, setting master clock, muting first */ 471*1aa9a4eaSClément Guedez /* due to possible conflicts with mute controls - mutexing */ 472*1aa9a4eaSClément Guedez mutex_lock(&spec->mute_mutex); 473*1aa9a4eaSClément Guedez /* we have to remember current mute status for each DAC */ 474*1aa9a4eaSClément Guedez changed = 0xFFFF; 475*1aa9a4eaSClément Guedez stac9460_dac_mute_all(ice, 0, &changed); 476*1aa9a4eaSClément Guedez /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ 477*1aa9a4eaSClément Guedez stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); 478*1aa9a4eaSClément Guedez stac9460_2_put(ice, STAC946X_MASTER_CLOCKING, new); 479*1aa9a4eaSClément Guedez udelay(10); 480*1aa9a4eaSClément Guedez /* unmuting - only originally unmuted dacs - 481*1aa9a4eaSClément Guedez * i.e. those changed when muting */ 482*1aa9a4eaSClément Guedez stac9460_dac_mute_all(ice, 1, &changed); 483*1aa9a4eaSClément Guedez mutex_unlock(&spec->mute_mutex); 484*1aa9a4eaSClément Guedez } 485*1aa9a4eaSClément Guedez 486*1aa9a4eaSClément Guedez 48716ddbe73SClément Guedez /*Limits value in dB for fader*/ 48816ddbe73SClément Guedez static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); 48916ddbe73SClément Guedez static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); 49016ddbe73SClément Guedez 491f6cdab5fSClement Guedez /* 492f6cdab5fSClement Guedez * Control tabs 493f6cdab5fSClement Guedez */ 494e23e7a14SBill Pemberton static struct snd_kcontrol_new stac9640_controls[] = { 495f6cdab5fSClement Guedez { 496f6cdab5fSClement Guedez .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 49716ddbe73SClément Guedez .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 49816ddbe73SClément Guedez SNDRV_CTL_ELEM_ACCESS_TLV_READ), 499f6cdab5fSClement Guedez .name = "Master Playback Switch", 500f6cdab5fSClement Guedez .info = stac9460_dac_mute_info, 501f6cdab5fSClement Guedez .get = stac9460_dac_mute_get, 502f6cdab5fSClement Guedez .put = stac9460_dac_mute_put, 50316ddbe73SClément Guedez .private_value = 1, 50416ddbe73SClément Guedez .tlv = { .p = db_scale_dac } 505f6cdab5fSClement Guedez }, 506f6cdab5fSClement Guedez { 507f6cdab5fSClement Guedez .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 508f6cdab5fSClement Guedez .name = "Master Playback Volume", 509f6cdab5fSClement Guedez .info = stac9460_dac_vol_info, 510f6cdab5fSClement Guedez .get = stac9460_dac_vol_get, 511f6cdab5fSClement Guedez .put = stac9460_dac_vol_put, 512f6cdab5fSClement Guedez .private_value = 1, 513f6cdab5fSClement Guedez }, 514f6cdab5fSClement Guedez { 515f6cdab5fSClement Guedez .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 516ae8a9a11SClément Guedez .name = "MIC/Line Input Enum", 517f6cdab5fSClement Guedez .count = 2, 518f6cdab5fSClement Guedez .info = stac9460_mic_sw_info, 519f6cdab5fSClement Guedez .get = stac9460_mic_sw_get, 520f6cdab5fSClement Guedez .put = stac9460_mic_sw_put, 521f6cdab5fSClement Guedez 522f6cdab5fSClement Guedez }, 523f6cdab5fSClement Guedez { 524f6cdab5fSClement Guedez .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 525f6cdab5fSClement Guedez .name = "DAC Switch", 526f6cdab5fSClement Guedez .count = 8, 527f6cdab5fSClement Guedez .info = stac9460_dac_mute_info, 528f6cdab5fSClement Guedez .get = stac9460_dac_mute_get, 529f6cdab5fSClement Guedez .put = stac9460_dac_mute_put, 530f6cdab5fSClement Guedez }, 531f6cdab5fSClement Guedez { 532f6cdab5fSClement Guedez .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 53316ddbe73SClément Guedez .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 53416ddbe73SClément Guedez SNDRV_CTL_ELEM_ACCESS_TLV_READ), 53516ddbe73SClément Guedez 536f6cdab5fSClement Guedez .name = "DAC Volume", 537f6cdab5fSClement Guedez .count = 8, 538f6cdab5fSClement Guedez .info = stac9460_dac_vol_info, 539f6cdab5fSClement Guedez .get = stac9460_dac_vol_get, 540f6cdab5fSClement Guedez .put = stac9460_dac_vol_put, 54116ddbe73SClément Guedez .tlv = { .p = db_scale_dac } 542f6cdab5fSClement Guedez }, 543f6cdab5fSClement Guedez { 544f6cdab5fSClement Guedez .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 545f6cdab5fSClement Guedez .name = "ADC Switch", 546f6cdab5fSClement Guedez .count = 2, 547f6cdab5fSClement Guedez .info = stac9460_adc_mute_info, 548f6cdab5fSClement Guedez .get = stac9460_adc_mute_get, 549f6cdab5fSClement Guedez .put = stac9460_adc_mute_put, 550f6cdab5fSClement Guedez }, 551f6cdab5fSClement Guedez { 552f6cdab5fSClement Guedez .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 55316ddbe73SClément Guedez .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 55416ddbe73SClément Guedez SNDRV_CTL_ELEM_ACCESS_TLV_READ), 55516ddbe73SClément Guedez 556f6cdab5fSClement Guedez .name = "ADC Volume", 557f6cdab5fSClement Guedez .count = 2, 558f6cdab5fSClement Guedez .info = stac9460_adc_vol_info, 559f6cdab5fSClement Guedez .get = stac9460_adc_vol_get, 560f6cdab5fSClement Guedez .put = stac9460_adc_vol_put, 56116ddbe73SClément Guedez .tlv = { .p = db_scale_adc } 562f6cdab5fSClement Guedez } 563f6cdab5fSClement Guedez }; 564f6cdab5fSClement Guedez 565f6cdab5fSClement Guedez 566f6cdab5fSClement Guedez 567f6cdab5fSClement Guedez /*INIT*/ 568e23e7a14SBill Pemberton static int wtm_add_controls(struct snd_ice1712 *ice) 569f6cdab5fSClement Guedez { 570f6cdab5fSClement Guedez unsigned int i; 571f6cdab5fSClement Guedez int err; 572f6cdab5fSClement Guedez 573f6cdab5fSClement Guedez for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) { 574f6cdab5fSClement Guedez err = snd_ctl_add(ice->card, 575f6cdab5fSClement Guedez snd_ctl_new1(&stac9640_controls[i], ice)); 576f6cdab5fSClement Guedez if (err < 0) 577f6cdab5fSClement Guedez return err; 578f6cdab5fSClement Guedez } 579f6cdab5fSClement Guedez return 0; 580f6cdab5fSClement Guedez } 581f6cdab5fSClement Guedez 582e23e7a14SBill Pemberton static int wtm_init(struct snd_ice1712 *ice) 583f6cdab5fSClement Guedez { 584b56df151SClément Guedez static unsigned short stac_inits_wtm[] = { 585f6cdab5fSClement Guedez STAC946X_RESET, 0, 586*1aa9a4eaSClément Guedez STAC946X_MASTER_CLOCKING, 0x11, 587f6cdab5fSClement Guedez (unsigned short)-1 588f6cdab5fSClement Guedez }; 589f6cdab5fSClement Guedez unsigned short *p; 590*1aa9a4eaSClément Guedez struct wtm_spec *spec; 591f6cdab5fSClement Guedez 592f6cdab5fSClement Guedez /*WTM 192M*/ 593f6cdab5fSClement Guedez ice->num_total_dacs = 8; 594f6cdab5fSClement Guedez ice->num_total_adcs = 4; 595f6cdab5fSClement Guedez ice->force_rdma1 = 1; 596f6cdab5fSClement Guedez 597*1aa9a4eaSClément Guedez /*init mutex for dac mute conflict*/ 598*1aa9a4eaSClément Guedez spec = kzalloc(sizeof(*spec), GFP_KERNEL); 599*1aa9a4eaSClément Guedez if (!spec) 600*1aa9a4eaSClément Guedez return -ENOMEM; 601*1aa9a4eaSClément Guedez ice->spec = spec; 602*1aa9a4eaSClément Guedez mutex_init(&spec->mute_mutex); 603*1aa9a4eaSClément Guedez 604*1aa9a4eaSClément Guedez 605f6cdab5fSClement Guedez /*initialize codec*/ 606b56df151SClément Guedez p = stac_inits_wtm; 607f6cdab5fSClement Guedez for (; *p != (unsigned short)-1; p += 2) { 608f6cdab5fSClement Guedez stac9460_put(ice, p[0], p[1]); 609f6cdab5fSClement Guedez stac9460_2_put(ice, p[0], p[1]); 610f6cdab5fSClement Guedez } 611*1aa9a4eaSClément Guedez ice->gpio.set_pro_rate = stac9460_set_rate_val; 612f6cdab5fSClement Guedez return 0; 613f6cdab5fSClement Guedez } 614f6cdab5fSClement Guedez 615f6cdab5fSClement Guedez 616e23e7a14SBill Pemberton static unsigned char wtm_eeprom[] = { 617f8a8b3a8SClément Guedez [ICE_EEP2_SYSCONF] = 0x67, /*SYSCONF: clock 192KHz, mpu401, 618f8a8b3a8SClément Guedez 4ADC, 8DAC */ 6197127744aSClément Guedez [ICE_EEP2_ACLINK] = 0x80, /* ACLINK : I2S */ 6207127744aSClément Guedez [ICE_EEP2_I2S] = 0xf8, /* I2S: vol; 96k, 24bit, 192k */ 6217127744aSClément Guedez [ICE_EEP2_SPDIF] = 0xc1, /*SPDIF: out-en, spidf ext out*/ 6227127744aSClément Guedez [ICE_EEP2_GPIO_DIR] = 0x9f, 6237127744aSClément Guedez [ICE_EEP2_GPIO_DIR1] = 0xff, 6247127744aSClément Guedez [ICE_EEP2_GPIO_DIR2] = 0x7f, 6257127744aSClément Guedez [ICE_EEP2_GPIO_MASK] = 0x9f, 6267127744aSClément Guedez [ICE_EEP2_GPIO_MASK1] = 0xff, 6277127744aSClément Guedez [ICE_EEP2_GPIO_MASK2] = 0x7f, 6287127744aSClément Guedez [ICE_EEP2_GPIO_STATE] = 0x16, 6297127744aSClément Guedez [ICE_EEP2_GPIO_STATE1] = 0x80, 6307127744aSClément Guedez [ICE_EEP2_GPIO_STATE2] = 0x00, 631f6cdab5fSClement Guedez }; 632f6cdab5fSClement Guedez 633f6cdab5fSClement Guedez 634f6cdab5fSClement Guedez /*entry point*/ 635e23e7a14SBill Pemberton struct snd_ice1712_card_info snd_vt1724_wtm_cards[] = { 636f6cdab5fSClement Guedez { 637f6cdab5fSClement Guedez .subvendor = VT1724_SUBDEVICE_WTM, 638f6cdab5fSClement Guedez .name = "ESI Waveterminal 192M", 639f6cdab5fSClement Guedez .model = "WT192M", 640f6cdab5fSClement Guedez .chip_init = wtm_init, 641f6cdab5fSClement Guedez .build_controls = wtm_add_controls, 642f6cdab5fSClement Guedez .eeprom_size = sizeof(wtm_eeprom), 643f6cdab5fSClement Guedez .eeprom_data = wtm_eeprom, 644f6cdab5fSClement Guedez }, 645f6cdab5fSClement Guedez {} /*terminator*/ 646f6cdab5fSClement Guedez }; 647