linux/sound/pci/ice1712/wtm.c
<<
>>
Prefs
   1/*
   2 *      ALSA driver for ICEnsemble VT1724 (Envy24HT)
   3 *
   4 *      Lowlevel functions for Ego Sys Waveterminal 192M
   5 *
   6 *              Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com>
   7 *              Some functions are taken from the Prodigy192 driver
   8 *              source
   9 *
  10 *      This program is free software; you can redistribute it and/or modify
  11 *      it under the terms of the GNU General Public License as published by
  12 *      the Free Software Foundation; either version 2 of the License, or
  13 *      (at your option) any later version.
  14 *
  15 *      This program is distributed in the hope that it will be useful,
  16 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18 *      GNU General Public License for more details.
  19 *
  20 *      You should have received a copy of the GNU General Public License
  21 *      along with this program; if not, write to the Free Software
  22 *      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23 *
  24 */
  25
  26
  27
  28#include <linux/delay.h>
  29#include <linux/interrupt.h>
  30#include <linux/init.h>
  31#include <sound/core.h>
  32
  33#include "ice1712.h"
  34#include "envy24ht.h"
  35#include "wtm.h"
  36#include "stac946x.h"
  37
  38
  39/*
  40 *      2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
  41 */
  42static inline void stac9460_put(struct snd_ice1712 *ice, int reg,
  43                                                unsigned char val)
  44{
  45        snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val);
  46}
  47
  48static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg)
  49{
  50        return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg);
  51}
  52
  53/*
  54 *      2*ADC 2*DAC no2 ringbuffer r/w on i2c bus
  55 */
  56static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg,
  57                                                unsigned char val)
  58{
  59        snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val);
  60}
  61
  62static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
  63{
  64        return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg);
  65}
  66
  67
  68/*
  69 *      DAC mute control
  70 */
  71#define stac9460_dac_mute_info          snd_ctl_boolean_mono_info
  72
  73static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
  74                                struct snd_ctl_elem_value *ucontrol)
  75{
  76        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
  77        unsigned char val;
  78        int idx, id;
  79
  80        if (kcontrol->private_value) {
  81                idx = STAC946X_MASTER_VOLUME;
  82                id = 0;
  83        } else {
  84                id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
  85                idx = id + STAC946X_LF_VOLUME;
  86        }
  87        if (id < 6)
  88                val = stac9460_get(ice, idx);
  89        else
  90                val = stac9460_2_get(ice, idx - 6);
  91        ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
  92        return 0;
  93}
  94
  95static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
  96                                struct snd_ctl_elem_value *ucontrol)
  97{
  98        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
  99        unsigned char new, old;
 100        int id, idx;
 101        int change;
 102
 103        if (kcontrol->private_value) {
 104                idx = STAC946X_MASTER_VOLUME;
 105                old = stac9460_get(ice, idx);
 106                new = (~ucontrol->value.integer.value[0] << 7 & 0x80) |
 107                                                        (old & ~0x80);
 108                change = (new != old);
 109                if (change) {
 110                        stac9460_put(ice, idx, new);
 111                        stac9460_2_put(ice, idx, new);
 112                }
 113        } else {
 114                id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 115                idx = id + STAC946X_LF_VOLUME;
 116                if (id < 6)
 117                        old = stac9460_get(ice, idx);
 118                else
 119                        old = stac9460_2_get(ice, idx - 6);
 120                new = (~ucontrol->value.integer.value[0] << 7 & 0x80) |
 121                                                        (old & ~0x80);
 122                change = (new != old);
 123                if (change) {
 124                        if (id < 6)
 125                                stac9460_put(ice, idx, new);
 126                        else
 127                                stac9460_2_put(ice, idx - 6, new);
 128                }
 129        }
 130        return change;
 131}
 132
 133/*
 134 *      DAC volume attenuation mixer control
 135 */
 136static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
 137                                struct snd_ctl_elem_info *uinfo)
 138{
 139        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 140        uinfo->count = 1;
 141        uinfo->value.integer.min = 0;                   /* mute */
 142        uinfo->value.integer.max = 0x7f;                /* 0dB */
 143        return 0;
 144}
 145
 146static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
 147                                struct snd_ctl_elem_value *ucontrol)
 148{
 149        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 150        int idx, id;
 151        unsigned char vol;
 152
 153        if (kcontrol->private_value) {
 154                idx = STAC946X_MASTER_VOLUME;
 155                id = 0;
 156        } else {
 157                id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 158                idx = id + STAC946X_LF_VOLUME;
 159        }
 160        if (id < 6)
 161                vol = stac9460_get(ice, idx) & 0x7f;
 162        else
 163                vol = stac9460_2_get(ice, idx - 6) & 0x7f;
 164        ucontrol->value.integer.value[0] = 0x7f - vol;
 165        return 0;
 166}
 167
 168static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
 169                                struct snd_ctl_elem_value *ucontrol)
 170{
 171        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 172        int idx, id;
 173        unsigned char tmp, ovol, nvol;
 174        int change;
 175
 176        if (kcontrol->private_value) {
 177                idx = STAC946X_MASTER_VOLUME;
 178                nvol = ucontrol->value.integer.value[0] & 0x7f;
 179                tmp = stac9460_get(ice, idx);
 180                ovol = 0x7f - (tmp & 0x7f);
 181                change = (ovol != nvol);
 182                if (change) {
 183                        stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
 184                        stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
 185                }
 186        } else {
 187                id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 188                idx = id + STAC946X_LF_VOLUME;
 189                nvol = ucontrol->value.integer.value[0] & 0x7f;
 190                if (id < 6)
 191                        tmp = stac9460_get(ice, idx);
 192                else
 193                        tmp = stac9460_2_get(ice, idx - 6);
 194                ovol = 0x7f - (tmp & 0x7f);
 195                change = (ovol != nvol);
 196                if (change) {
 197                        if (id < 6)
 198                                stac9460_put(ice, idx, (0x7f - nvol) |
 199                                                        (tmp & 0x80));
 200                        else
 201                                stac9460_2_put(ice, idx-6, (0x7f - nvol) |
 202                                                        (tmp & 0x80));
 203                }
 204        }
 205        return change;
 206}
 207
 208/*
 209 * ADC mute control
 210 */
 211#define stac9460_adc_mute_info          snd_ctl_boolean_stereo_info
 212
 213static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
 214                                struct snd_ctl_elem_value *ucontrol)
 215{
 216        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 217        unsigned char val;
 218        int i, id;
 219
 220        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 221        if (id == 0) {
 222                for (i = 0; i < 2; ++i) {
 223                        val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
 224                        ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
 225                }
 226        } else {
 227                for (i = 0; i < 2; ++i) {
 228                        val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i);
 229                        ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
 230                }
 231        }
 232        return 0;
 233}
 234
 235static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
 236                                struct snd_ctl_elem_value *ucontrol)
 237{
 238        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 239        unsigned char new, old;
 240        int i, reg, id;
 241        int change;
 242
 243        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 244        if (id == 0) {
 245                for (i = 0; i < 2; ++i) {
 246                        reg = STAC946X_MIC_L_VOLUME + i;
 247                        old = stac9460_get(ice, reg);
 248                        new = (~ucontrol->value.integer.value[i]<<7&0x80) |
 249                                                                (old&~0x80);
 250                        change = (new != old);
 251                        if (change)
 252                                stac9460_put(ice, reg, new);
 253                }
 254        } else {
 255                for (i = 0; i < 2; ++i) {
 256                        reg = STAC946X_MIC_L_VOLUME + i;
 257                        old = stac9460_2_get(ice, reg);
 258                        new = (~ucontrol->value.integer.value[i]<<7&0x80) |
 259                                                                (old&~0x80);
 260                        change = (new != old);
 261                        if (change)
 262                                stac9460_2_put(ice, reg, new);
 263                }
 264        }
 265        return change;
 266}
 267
 268/*
 269 *ADC gain mixer control
 270 */
 271static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
 272                                struct snd_ctl_elem_info *uinfo)
 273{
 274        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 275        uinfo->count = 2;
 276        uinfo->value.integer.min = 0;           /* 0dB */
 277        uinfo->value.integer.max = 0x0f;        /* 22.5dB */
 278        return 0;
 279}
 280
 281static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
 282                                struct snd_ctl_elem_value *ucontrol)
 283{
 284        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 285        int i, reg, id;
 286        unsigned char vol;
 287
 288        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 289        if (id == 0) {
 290                for (i = 0; i < 2; ++i) {
 291                        reg = STAC946X_MIC_L_VOLUME + i;
 292                        vol = stac9460_get(ice, reg) & 0x0f;
 293                        ucontrol->value.integer.value[i] = 0x0f - vol;
 294                }
 295        } else {
 296                for (i = 0; i < 2; ++i) {
 297                        reg = STAC946X_MIC_L_VOLUME + i;
 298                        vol = stac9460_2_get(ice, reg) & 0x0f;
 299                        ucontrol->value.integer.value[i] = 0x0f - vol;
 300                }
 301        }
 302        return 0;
 303}
 304
 305static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
 306                                struct snd_ctl_elem_value *ucontrol)
 307{
 308        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 309        int i, reg, id;
 310        unsigned char ovol, nvol;
 311        int change;
 312
 313        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 314        if (id == 0) {
 315                for (i = 0; i < 2; ++i) {
 316                        reg = STAC946X_MIC_L_VOLUME + i;
 317                        nvol = ucontrol->value.integer.value[i] & 0x0f;
 318                        ovol = 0x0f - stac9460_get(ice, reg);
 319                        change = ((ovol & 0x0f) != nvol);
 320                        if (change)
 321                                stac9460_put(ice, reg, (0x0f - nvol) |
 322                                                        (ovol & ~0x0f));
 323                }
 324        } else {
 325                for (i = 0; i < 2; ++i) {
 326                        reg = STAC946X_MIC_L_VOLUME + i;
 327                        nvol = ucontrol->value.integer.value[i] & 0x0f;
 328                        ovol = 0x0f - stac9460_2_get(ice, reg);
 329                        change = ((ovol & 0x0f) != nvol);
 330                        if (change)
 331                                stac9460_2_put(ice, reg, (0x0f - nvol) |
 332                                                        (ovol & ~0x0f));
 333                }
 334        }
 335        return change;
 336}
 337
 338/*
 339 * MIC / LINE switch fonction
 340 */
 341
 342#define stac9460_mic_sw_info            snd_ctl_boolean_mono_info
 343
 344static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
 345                                struct snd_ctl_elem_value *ucontrol)
 346{
 347        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 348        unsigned char val;
 349        int id;
 350
 351        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 352        if (id == 0)
 353                val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
 354        else
 355                val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
 356        ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
 357        return 0;
 358}
 359
 360static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
 361                                struct snd_ctl_elem_value *ucontrol)
 362{
 363        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 364        unsigned char new, old;
 365        int change, id;
 366
 367        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 368        if (id == 0)
 369                old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
 370        else
 371                old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
 372        new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | (old & ~0x80);
 373        change = (new != old);
 374        if (change) {
 375                if (id == 0)
 376                        stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
 377                else
 378                        stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
 379        }
 380        return change;
 381}
 382
 383/*
 384 * Control tabs
 385 */
 386static struct snd_kcontrol_new stac9640_controls[] = {
 387        {
 388                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 389                .name = "Master Playback Switch",
 390                .info = stac9460_dac_mute_info,
 391                .get = stac9460_dac_mute_get,
 392                .put = stac9460_dac_mute_put,
 393                .private_value = 1
 394        },
 395        {
 396                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 397                .name = "Master Playback Volume",
 398                .info = stac9460_dac_vol_info,
 399                .get = stac9460_dac_vol_get,
 400                .put = stac9460_dac_vol_put,
 401                .private_value = 1,
 402        },
 403        {
 404                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 405                .name = "MIC/Line switch",
 406                .count = 2,
 407                .info = stac9460_mic_sw_info,
 408                .get = stac9460_mic_sw_get,
 409                .put = stac9460_mic_sw_put,
 410
 411        },
 412        {
 413                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 414                .name = "DAC Switch",
 415                .count = 8,
 416                .info = stac9460_dac_mute_info,
 417                .get = stac9460_dac_mute_get,
 418                .put = stac9460_dac_mute_put,
 419        },
 420        {
 421                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 422                .name = "DAC Volume",
 423                .count = 8,
 424                .info = stac9460_dac_vol_info,
 425                .get = stac9460_dac_vol_get,
 426                .put = stac9460_dac_vol_put,
 427        },
 428        {
 429                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 430                .name = "ADC Switch",
 431                .count = 2,
 432                .info = stac9460_adc_mute_info,
 433                .get = stac9460_adc_mute_get,
 434                .put = stac9460_adc_mute_put,
 435        },
 436        {
 437                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 438                .name = "ADC Volume",
 439                .count = 2,
 440                .info = stac9460_adc_vol_info,
 441                .get = stac9460_adc_vol_get,
 442                .put = stac9460_adc_vol_put,
 443
 444        }
 445};
 446
 447
 448
 449/*INIT*/
 450static int wtm_add_controls(struct snd_ice1712 *ice)
 451{
 452        unsigned int i;
 453        int err;
 454
 455        for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) {
 456                err = snd_ctl_add(ice->card,
 457                                snd_ctl_new1(&stac9640_controls[i], ice));
 458                if (err < 0)
 459                        return err;
 460        }
 461        return 0;
 462}
 463
 464static int wtm_init(struct snd_ice1712 *ice)
 465{
 466        static unsigned short stac_inits_prodigy[] = {
 467                STAC946X_RESET, 0,
 468                (unsigned short)-1
 469        };
 470        unsigned short *p;
 471
 472        /*WTM 192M*/
 473        ice->num_total_dacs = 8;
 474        ice->num_total_adcs = 4;
 475        ice->force_rdma1 = 1;
 476
 477        /*initialize codec*/
 478        p = stac_inits_prodigy;
 479        for (; *p != (unsigned short)-1; p += 2) {
 480                stac9460_put(ice, p[0], p[1]);
 481                stac9460_2_put(ice, p[0], p[1]);
 482        }
 483        return 0;
 484}
 485
 486
 487static unsigned char wtm_eeprom[] = {
 488        0x47,   /*SYSCONF: clock 192KHz, 4ADC, 8DAC */
 489        0x80,   /* ACLINK : I2S */
 490        0xf8,   /* I2S: vol; 96k, 24bit, 192k */
 491        0xc1    /*SPDIF: out-en, spidf ext out*/,
 492        0x9f,   /* GPIO_DIR */
 493        0xff,   /* GPIO_DIR1 */
 494        0x7f,   /* GPIO_DIR2 */
 495        0x9f,   /* GPIO_MASK */
 496        0xff,   /* GPIO_MASK1 */
 497        0x7f,   /* GPIO_MASK2 */
 498        0x16,   /* GPIO_STATE */
 499        0x80,   /* GPIO_STATE1 */
 500        0x00,   /* GPIO_STATE2 */
 501};
 502
 503
 504/*entry point*/
 505struct snd_ice1712_card_info snd_vt1724_wtm_cards[] = {
 506        {
 507                .subvendor = VT1724_SUBDEVICE_WTM,
 508                .name = "ESI Waveterminal 192M",
 509                .model = "WT192M",
 510                .chip_init = wtm_init,
 511                .build_controls = wtm_add_controls,
 512                .eeprom_size = sizeof(wtm_eeprom),
 513                .eeprom_data = wtm_eeprom,
 514        },
 515        {} /*terminator*/
 516};
 517