linux/sound/pci/ca0106/ca0106_mixer.c
<<
>>
Prefs
   1/*
   2 *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
   3 *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
   4 *  Version: 0.0.18
   5 *
   6 *  FEATURES currently supported:
   7 *    See ca0106_main.c for features.
   8 * 
   9 *  Changelog:
  10 *    Support interrupts per period.
  11 *    Removed noise from Center/LFE channel when in Analog mode.
  12 *    Rename and remove mixer controls.
  13 *  0.0.6
  14 *    Use separate card based DMA buffer for periods table list.
  15 *  0.0.7
  16 *    Change remove and rename ctrls into lists.
  17 *  0.0.8
  18 *    Try to fix capture sources.
  19 *  0.0.9
  20 *    Fix AC3 output.
  21 *    Enable S32_LE format support.
  22 *  0.0.10
  23 *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
  24 *  0.0.11
  25 *    Add Model name recognition.
  26 *  0.0.12
  27 *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
  28 *    Remove redundent "voice" handling.
  29 *  0.0.13
  30 *    Single trigger call for multi channels.
  31 *  0.0.14
  32 *    Set limits based on what the sound card hardware can do.
  33 *    playback periods_min=2, periods_max=8
  34 *    capture hw constraints require period_size = n * 64 bytes.
  35 *    playback hw constraints require period_size = n * 64 bytes.
  36 *  0.0.15
  37 *    Separated ca0106.c into separate functional .c files.
  38 *  0.0.16
  39 *    Modified Copyright message.
  40 *  0.0.17
  41 *    Implement Mic and Line in Capture.
  42 *  0.0.18
  43 *    Add support for mute control on SB Live 24bit (cards w/ SPI DAC)
  44 *
  45 *  This code was initally based on code from ALSA's emu10k1x.c which is:
  46 *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
  47 *
  48 *   This program is free software; you can redistribute it and/or modify
  49 *   it under the terms of the GNU General Public License as published by
  50 *   the Free Software Foundation; either version 2 of the License, or
  51 *   (at your option) any later version.
  52 *
  53 *   This program is distributed in the hope that it will be useful,
  54 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  55 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  56 *   GNU General Public License for more details.
  57 *
  58 *   You should have received a copy of the GNU General Public License
  59 *   along with this program; if not, write to the Free Software
  60 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  61 *
  62 */
  63#include <sound/driver.h>
  64#include <linux/delay.h>
  65#include <linux/init.h>
  66#include <linux/interrupt.h>
  67#include <linux/slab.h>
  68#include <linux/moduleparam.h>
  69#include <sound/core.h>
  70#include <sound/initval.h>
  71#include <sound/pcm.h>
  72#include <sound/ac97_codec.h>
  73#include <sound/info.h>
  74#include <sound/tlv.h>
  75#include <asm/io.h>
  76
  77#include "ca0106.h"
  78
  79static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
  80static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
  81
  82#define snd_ca0106_shared_spdif_info    snd_ctl_boolean_mono_info
  83
  84static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol,
  85                                        struct snd_ctl_elem_value *ucontrol)
  86{
  87        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
  88
  89        ucontrol->value.integer.value[0] = emu->spdif_enable;
  90        return 0;
  91}
  92
  93static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
  94                                        struct snd_ctl_elem_value *ucontrol)
  95{
  96        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
  97        unsigned int val;
  98        int change = 0;
  99        u32 mask;
 100
 101        val = !!ucontrol->value.integer.value[0];
 102        change = (emu->spdif_enable != val);
 103        if (change) {
 104                emu->spdif_enable = val;
 105                if (val) {
 106                        /* Digital */
 107                        snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
 108                        snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
 109                        snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
 110                                snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000);
 111                        mask = inl(emu->port + GPIO) & ~0x101;
 112                        outl(mask, emu->port + GPIO);
 113
 114                } else {
 115                        /* Analog */
 116                        snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
 117                        snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
 118                        snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
 119                                snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000);
 120                        mask = inl(emu->port + GPIO) | 0x101;
 121                        outl(mask, emu->port + GPIO);
 122                }
 123        }
 124        return change;
 125}
 126
 127static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol,
 128                                          struct snd_ctl_elem_info *uinfo)
 129{
 130        static char *texts[6] = {
 131                "IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out"
 132        };
 133
 134        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 135        uinfo->count = 1;
 136        uinfo->value.enumerated.items = 6;
 137        if (uinfo->value.enumerated.item > 5)
 138                uinfo->value.enumerated.item = 5;
 139        strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
 140        return 0;
 141}
 142
 143static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol,
 144                                        struct snd_ctl_elem_value *ucontrol)
 145{
 146        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 147
 148        ucontrol->value.enumerated.item[0] = emu->capture_source;
 149        return 0;
 150}
 151
 152static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
 153                                        struct snd_ctl_elem_value *ucontrol)
 154{
 155        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 156        unsigned int val;
 157        int change = 0;
 158        u32 mask;
 159        u32 source;
 160
 161        val = ucontrol->value.enumerated.item[0] ;
 162        if (val >= 6)
 163                return -EINVAL;
 164        change = (emu->capture_source != val);
 165        if (change) {
 166                emu->capture_source = val;
 167                source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
 168                mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
 169                snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
 170        }
 171        return change;
 172}
 173
 174static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
 175                                          struct snd_ctl_elem_info *uinfo)
 176{
 177        static char *texts[6] = {
 178                "Phone", "Mic", "Line in", "Aux"
 179        };
 180
 181        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 182        uinfo->count = 1;
 183        uinfo->value.enumerated.items = 4;
 184        if (uinfo->value.enumerated.item > 3)
 185                uinfo->value.enumerated.item = 3;
 186        strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
 187        return 0;
 188}
 189
 190static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
 191                                        struct snd_ctl_elem_value *ucontrol)
 192{
 193        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 194
 195        ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
 196        return 0;
 197}
 198
 199static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
 200                                        struct snd_ctl_elem_value *ucontrol)
 201{
 202        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 203        unsigned int source_id;
 204        unsigned int ngain, ogain;
 205        int change = 0;
 206        u32 source;
 207        /* If the capture source has changed,
 208         * update the capture volume from the cached value
 209         * for the particular source.
 210         */
 211        source_id = ucontrol->value.enumerated.item[0] ;
 212        if (source_id >= 4)
 213                return -EINVAL;
 214        change = (emu->i2c_capture_source != source_id);
 215        if (change) {
 216                snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
 217                ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
 218                ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
 219                if (ngain != ogain)
 220                        snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
 221                ngain = emu->i2c_capture_volume[source_id][1]; /* Left */
 222                ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */
 223                if (ngain != ogain)
 224                        snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
 225                source = 1 << source_id;
 226                snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
 227                emu->i2c_capture_source = source_id;
 228        }
 229        return change;
 230}
 231
 232static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
 233                                               struct snd_ctl_elem_info *uinfo)
 234{
 235        static char *texts[2] = { "Side out", "Line in" };
 236
 237        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 238        uinfo->count = 1;
 239        uinfo->value.enumerated.items = 2;
 240        if (uinfo->value.enumerated.item > 1)
 241                uinfo->value.enumerated.item = 1;
 242        strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
 243        return 0;
 244}
 245
 246static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
 247                                               struct snd_ctl_elem_info *uinfo)
 248{
 249        static char *texts[2] = { "Line in", "Mic in" };
 250
 251        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 252        uinfo->count = 1;
 253        uinfo->value.enumerated.items = 2;
 254        if (uinfo->value.enumerated.item > 1)
 255                uinfo->value.enumerated.item = 1;
 256        strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
 257        return 0;
 258}
 259
 260static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol,
 261                                        struct snd_ctl_elem_value *ucontrol)
 262{
 263        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 264
 265        ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in;
 266        return 0;
 267}
 268
 269static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
 270                                        struct snd_ctl_elem_value *ucontrol)
 271{
 272        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 273        unsigned int val;
 274        int change = 0;
 275        u32 tmp;
 276
 277        val = ucontrol->value.enumerated.item[0] ;
 278        if (val > 1)
 279                return -EINVAL;
 280        change = (emu->capture_mic_line_in != val);
 281        if (change) {
 282                emu->capture_mic_line_in = val;
 283                if (val) {
 284                        //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
 285                        tmp = inl(emu->port+GPIO) & ~0x400;
 286                        tmp = tmp | 0x400;
 287                        outl(tmp, emu->port+GPIO);
 288                        //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
 289                } else {
 290                        //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
 291                        tmp = inl(emu->port+GPIO) & ~0x400;
 292                        outl(tmp, emu->port+GPIO);
 293                        //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
 294                }
 295        }
 296        return change;
 297}
 298
 299static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata =
 300{
 301        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
 302        .name =         "Shared Mic/Line in Capture Switch",
 303        .info =         snd_ca0106_capture_mic_line_in_info,
 304        .get =          snd_ca0106_capture_mic_line_in_get,
 305        .put =          snd_ca0106_capture_mic_line_in_put
 306};
 307
 308static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata =
 309{
 310        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
 311        .name =         "Shared Line in/Side out Capture Switch",
 312        .info =         snd_ca0106_capture_line_in_side_out_info,
 313        .get =          snd_ca0106_capture_mic_line_in_get,
 314        .put =          snd_ca0106_capture_mic_line_in_put
 315};
 316
 317
 318static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
 319                                 struct snd_ctl_elem_info *uinfo)
 320{
 321        uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
 322        uinfo->count = 1;
 323        return 0;
 324}
 325
 326static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol,
 327                                 struct snd_ctl_elem_value *ucontrol)
 328{
 329        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 330        unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 331
 332        ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
 333        ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
 334        ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
 335        ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
 336        return 0;
 337}
 338
 339static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol,
 340                                      struct snd_ctl_elem_value *ucontrol)
 341{
 342        ucontrol->value.iec958.status[0] = 0xff;
 343        ucontrol->value.iec958.status[1] = 0xff;
 344        ucontrol->value.iec958.status[2] = 0xff;
 345        ucontrol->value.iec958.status[3] = 0xff;
 346        return 0;
 347}
 348
 349static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol,
 350                                 struct snd_ctl_elem_value *ucontrol)
 351{
 352        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 353        unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 354        int change;
 355        unsigned int val;
 356
 357        val = (ucontrol->value.iec958.status[0] << 0) |
 358              (ucontrol->value.iec958.status[1] << 8) |
 359              (ucontrol->value.iec958.status[2] << 16) |
 360              (ucontrol->value.iec958.status[3] << 24);
 361        change = val != emu->spdif_bits[idx];
 362        if (change) {
 363                snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val);
 364                emu->spdif_bits[idx] = val;
 365        }
 366        return change;
 367}
 368
 369static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
 370                                  struct snd_ctl_elem_info *uinfo)
 371{
 372        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 373        uinfo->count = 2;
 374        uinfo->value.integer.min = 0;
 375        uinfo->value.integer.max = 255;
 376        return 0;
 377}
 378
 379static int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol,
 380                                 struct snd_ctl_elem_value *ucontrol)
 381{
 382        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 383        unsigned int value;
 384        int channel_id, reg;
 385
 386        channel_id = (kcontrol->private_value >> 8) & 0xff;
 387        reg = kcontrol->private_value & 0xff;
 388
 389        value = snd_ca0106_ptr_read(emu, reg, channel_id);
 390        ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
 391        ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
 392        return 0;
 393}
 394
 395static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
 396                                 struct snd_ctl_elem_value *ucontrol)
 397{
 398        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 399        unsigned int oval, nval;
 400        int channel_id, reg;
 401
 402        channel_id = (kcontrol->private_value >> 8) & 0xff;
 403        reg = kcontrol->private_value & 0xff;
 404
 405        oval = snd_ca0106_ptr_read(emu, reg, channel_id);
 406        nval = ((0xff - ucontrol->value.integer.value[0]) << 24) |
 407                ((0xff - ucontrol->value.integer.value[1]) << 16);
 408        nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) |
 409                ((0xff - ucontrol->value.integer.value[1]) );
 410        if (oval == nval)
 411                return 0;
 412        snd_ca0106_ptr_write(emu, reg, channel_id, nval);
 413        return 1;
 414}
 415
 416static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
 417                                  struct snd_ctl_elem_info *uinfo)
 418{
 419        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 420        uinfo->count = 2;
 421        uinfo->value.integer.min = 0;
 422        uinfo->value.integer.max = 255;
 423        return 0;
 424}
 425
 426static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
 427                                 struct snd_ctl_elem_value *ucontrol)
 428{
 429        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 430        int source_id;
 431
 432        source_id = kcontrol->private_value;
 433
 434        ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
 435        ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
 436        return 0;
 437}
 438
 439static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
 440                                 struct snd_ctl_elem_value *ucontrol)
 441{
 442        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 443        unsigned int ogain;
 444        unsigned int ngain;
 445        int source_id;
 446        int change = 0;
 447
 448        source_id = kcontrol->private_value;
 449        ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
 450        ngain = ucontrol->value.integer.value[0];
 451        if (ngain > 0xff)
 452                return -EINVAL;
 453        if (ogain != ngain) {
 454                if (emu->i2c_capture_source == source_id)
 455                        snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
 456                emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
 457                change = 1;
 458        }
 459        ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
 460        ngain = ucontrol->value.integer.value[1];
 461        if (ngain > 0xff)
 462                return -EINVAL;
 463        if (ogain != ngain) {
 464                if (emu->i2c_capture_source == source_id)
 465                        snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
 466                emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
 467                change = 1;
 468        }
 469
 470        return change;
 471}
 472
 473#define spi_mute_info   snd_ctl_boolean_mono_info
 474
 475static int spi_mute_get(struct snd_kcontrol *kcontrol,
 476                        struct snd_ctl_elem_value *ucontrol)
 477{
 478        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 479        unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
 480        unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
 481
 482        ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit);
 483        return 0;
 484}
 485
 486static int spi_mute_put(struct snd_kcontrol *kcontrol,
 487                        struct snd_ctl_elem_value *ucontrol)
 488{
 489        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 490        unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
 491        unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
 492        int ret;
 493
 494        ret = emu->spi_dac_reg[reg] & bit;
 495        if (ucontrol->value.integer.value[0]) {
 496                if (!ret)       /* bit already cleared, do nothing */
 497                        return 0;
 498                emu->spi_dac_reg[reg] &= ~bit;
 499        } else {
 500                if (ret)        /* bit already set, do nothing */
 501                        return 0;
 502                emu->spi_dac_reg[reg] |= bit;
 503        }
 504
 505        ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]);
 506        return ret ? -EINVAL : 1;
 507}
 508
 509#define CA_VOLUME(xname,chid,reg) \
 510{                                                               \
 511        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
 512        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |             \
 513                  SNDRV_CTL_ELEM_ACCESS_TLV_READ,               \
 514        .info =  snd_ca0106_volume_info,                        \
 515        .get =   snd_ca0106_volume_get,                         \
 516        .put =   snd_ca0106_volume_put,                         \
 517        .tlv = { .p = snd_ca0106_db_scale1 },                   \
 518        .private_value = ((chid) << 8) | (reg)                  \
 519}
 520
 521static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
 522        CA_VOLUME("Analog Front Playback Volume",
 523                  CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
 524        CA_VOLUME("Analog Rear Playback Volume",
 525                  CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2),
 526        CA_VOLUME("Analog Center/LFE Playback Volume",
 527                  CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2),
 528        CA_VOLUME("Analog Side Playback Volume",
 529                  CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2),
 530
 531        CA_VOLUME("IEC958 Front Playback Volume",
 532                  CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1),
 533        CA_VOLUME("IEC958 Rear Playback Volume",
 534                  CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1),
 535        CA_VOLUME("IEC958 Center/LFE Playback Volume",
 536                  CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1),
 537        CA_VOLUME("IEC958 Unknown Playback Volume",
 538                  CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1),
 539
 540        CA_VOLUME("CAPTURE feedback Playback Volume",
 541                  1, CAPTURE_CONTROL),
 542
 543        {
 544                .access =       SNDRV_CTL_ELEM_ACCESS_READ,
 545                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
 546                .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
 547                .count =        4,
 548                .info =         snd_ca0106_spdif_info,
 549                .get =          snd_ca0106_spdif_get_mask
 550        },
 551        {
 552                .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
 553                .name =         "IEC958 Playback Switch",
 554                .info =         snd_ca0106_shared_spdif_info,
 555                .get =          snd_ca0106_shared_spdif_get,
 556                .put =          snd_ca0106_shared_spdif_put
 557        },
 558        {
 559                .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
 560                .name =         "Digital Source Capture Enum",
 561                .info =         snd_ca0106_capture_source_info,
 562                .get =          snd_ca0106_capture_source_get,
 563                .put =          snd_ca0106_capture_source_put
 564        },
 565        {
 566                .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
 567                .name =         "Analog Source Capture Enum",
 568                .info =         snd_ca0106_i2c_capture_source_info,
 569                .get =          snd_ca0106_i2c_capture_source_get,
 570                .put =          snd_ca0106_i2c_capture_source_put
 571        },
 572        {
 573                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
 574                .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
 575                .count =        4,
 576                .info =         snd_ca0106_spdif_info,
 577                .get =          snd_ca0106_spdif_get,
 578                .put =          snd_ca0106_spdif_put
 579        },
 580};
 581
 582#define I2C_VOLUME(xname,chid) \
 583{                                                               \
 584        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
 585        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |             \
 586                  SNDRV_CTL_ELEM_ACCESS_TLV_READ,               \
 587        .info =  snd_ca0106_i2c_volume_info,                    \
 588        .get =   snd_ca0106_i2c_volume_get,                     \
 589        .put =   snd_ca0106_i2c_volume_put,                     \
 590        .tlv = { .p = snd_ca0106_db_scale2 },                   \
 591        .private_value = chid                                   \
 592}
 593
 594static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = {
 595        I2C_VOLUME("Phone Capture Volume", 0),
 596        I2C_VOLUME("Mic Capture Volume", 1),
 597        I2C_VOLUME("Line in Capture Volume", 2),
 598        I2C_VOLUME("Aux Capture Volume", 3),
 599};
 600
 601#define SPI_SWITCH(xname,reg,bit) \
 602{                                                               \
 603        .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,    \
 604        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,              \
 605        .info   = spi_mute_info,                                \
 606        .get    = spi_mute_get,                                 \
 607        .put    = spi_mute_put,                                 \
 608        .private_value = (reg<<SPI_REG_SHIFT) | (bit)           \
 609}
 610
 611static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
 612__devinitdata = {
 613        SPI_SWITCH("Analog Front Playback Switch",
 614                   SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
 615        SPI_SWITCH("Analog Rear Playback Switch",
 616                   SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
 617        SPI_SWITCH("Analog Center/LFE Playback Switch",
 618                   SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
 619        SPI_SWITCH("Analog Side Playback Switch",
 620                   SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
 621};
 622
 623static int __devinit remove_ctl(struct snd_card *card, const char *name)
 624{
 625        struct snd_ctl_elem_id id;
 626        memset(&id, 0, sizeof(id));
 627        strcpy(id.name, name);
 628        id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 629        return snd_ctl_remove_id(card, &id);
 630}
 631
 632static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char *name)
 633{
 634        struct snd_ctl_elem_id sid;
 635        memset(&sid, 0, sizeof(sid));
 636        /* FIXME: strcpy is bad. */
 637        strcpy(sid.name, name);
 638        sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 639        return snd_ctl_find_id(card, &sid);
 640}
 641
 642static int __devinit rename_ctl(struct snd_card *card, const char *src, const char *dst)
 643{
 644        struct snd_kcontrol *kctl = ctl_find(card, src);
 645        if (kctl) {
 646                strcpy(kctl->id.name, dst);
 647                return 0;
 648        }
 649        return -ENOENT;
 650}
 651
 652#define ADD_CTLS(emu, ctls)                                             \
 653        do {                                                            \
 654                int i, err;                                             \
 655                for (i = 0; i < ARRAY_SIZE(ctls); i++) {                \
 656                        err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu)); \
 657                        if (err < 0)                                    \
 658                                return err;                             \
 659                }                                                       \
 660        } while (0)
 661
 662int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
 663{
 664        int err;
 665        struct snd_card *card = emu->card;
 666        char **c;
 667        static char *ca0106_remove_ctls[] = {
 668                "Master Mono Playback Switch",
 669                "Master Mono Playback Volume",
 670                "3D Control - Switch",
 671                "3D Control Sigmatel - Depth",
 672                "PCM Playback Switch",
 673                "PCM Playback Volume",
 674                "CD Playback Switch",
 675                "CD Playback Volume",
 676                "Phone Playback Switch",
 677                "Phone Playback Volume",
 678                "Video Playback Switch",
 679                "Video Playback Volume",
 680                "PC Speaker Playback Switch",
 681                "PC Speaker Playback Volume",
 682                "Mono Output Select",
 683                "Capture Source",
 684                "Capture Switch",
 685                "Capture Volume",
 686                "External Amplifier",
 687                "Sigmatel 4-Speaker Stereo Playback Switch",
 688                "Sigmatel Surround Phase Inversion Playback ",
 689                NULL
 690        };
 691        static char *ca0106_rename_ctls[] = {
 692                "Master Playback Switch", "Capture Switch",
 693                "Master Playback Volume", "Capture Volume",
 694                "Line Playback Switch", "AC97 Line Capture Switch",
 695                "Line Playback Volume", "AC97 Line Capture Volume",
 696                "Aux Playback Switch", "AC97 Aux Capture Switch",
 697                "Aux Playback Volume", "AC97 Aux Capture Volume",
 698                "Mic Playback Switch", "AC97 Mic Capture Switch",
 699                "Mic Playback Volume", "AC97 Mic Capture Volume",
 700                "Mic Select", "AC97 Mic Select",
 701                "Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)",
 702                NULL
 703        };
 704#if 1
 705        for (c = ca0106_remove_ctls; *c; c++)
 706                remove_ctl(card, *c);
 707        for (c = ca0106_rename_ctls; *c; c += 2)
 708                rename_ctl(card, c[0], c[1]);
 709#endif
 710
 711        ADD_CTLS(emu, snd_ca0106_volume_ctls);
 712        if (emu->details->i2c_adc == 1) {
 713                ADD_CTLS(emu, snd_ca0106_volume_i2c_adc_ctls);
 714                if (emu->details->gpio_type == 1)
 715                        err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
 716                else  /* gpio_type == 2 */
 717                        err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu));
 718                if (err < 0)
 719                        return err;
 720        }
 721        if (emu->details->spi_dac == 1)
 722                ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
 723        return 0;
 724}
 725
 726