linux/sound/ppc/burgundy.c
<<
>>
Prefs
   1/*
   2 * PMac Burgundy lowlevel functions
   3 *
   4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
   5 * code based on dmasound.c.
   6 *
   7 *   This program is free software; you can redistribute it and/or modify
   8 *   it under the terms of the GNU General Public License as published by
   9 *   the Free Software Foundation; either version 2 of the License, or
  10 *   (at your option) any later version.
  11 *
  12 *   This program is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *   GNU General Public License for more details.
  16 *
  17 *   You should have received a copy of the GNU General Public License
  18 *   along with this program; if not, write to the Free Software
  19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  20 */
  21
  22#include <asm/io.h>
  23#include <linux/init.h>
  24#include <linux/slab.h>
  25#include <linux/delay.h>
  26#include <sound/core.h>
  27#include "pmac.h"
  28#include "burgundy.h"
  29
  30
  31/* Waits for busy flag to clear */
  32static inline void
  33snd_pmac_burgundy_busy_wait(struct snd_pmac *chip)
  34{
  35        int timeout = 50;
  36        while ((in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) && timeout--)
  37                udelay(1);
  38        if (timeout < 0)
  39                printk(KERN_DEBUG "burgundy_busy_wait: timeout\n");
  40}
  41
  42static inline void
  43snd_pmac_burgundy_extend_wait(struct snd_pmac *chip)
  44{
  45        int timeout;
  46        timeout = 50;
  47        while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
  48                udelay(1);
  49        if (timeout < 0)
  50                printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n");
  51        timeout = 50;
  52        while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
  53                udelay(1);
  54        if (timeout < 0)
  55                printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n");
  56}
  57
  58static void
  59snd_pmac_burgundy_wcw(struct snd_pmac *chip, unsigned addr, unsigned val)
  60{
  61        out_le32(&chip->awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
  62        snd_pmac_burgundy_busy_wait(chip);
  63        out_le32(&chip->awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
  64        snd_pmac_burgundy_busy_wait(chip);
  65        out_le32(&chip->awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
  66        snd_pmac_burgundy_busy_wait(chip);
  67        out_le32(&chip->awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
  68        snd_pmac_burgundy_busy_wait(chip);
  69}
  70
  71static unsigned
  72snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr)
  73{
  74        unsigned val = 0;
  75        unsigned long flags;
  76
  77        spin_lock_irqsave(&chip->reg_lock, flags);
  78
  79        out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
  80        snd_pmac_burgundy_busy_wait(chip);
  81        snd_pmac_burgundy_extend_wait(chip);
  82        val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
  83
  84        out_le32(&chip->awacs->codec_ctrl, addr + 0x100100);
  85        snd_pmac_burgundy_busy_wait(chip);
  86        snd_pmac_burgundy_extend_wait(chip);
  87        val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<8;
  88
  89        out_le32(&chip->awacs->codec_ctrl, addr + 0x100200);
  90        snd_pmac_burgundy_busy_wait(chip);
  91        snd_pmac_burgundy_extend_wait(chip);
  92        val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<16;
  93
  94        out_le32(&chip->awacs->codec_ctrl, addr + 0x100300);
  95        snd_pmac_burgundy_busy_wait(chip);
  96        snd_pmac_burgundy_extend_wait(chip);
  97        val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<24;
  98
  99        spin_unlock_irqrestore(&chip->reg_lock, flags);
 100
 101        return val;
 102}
 103
 104static void
 105snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr,
 106                      unsigned int val)
 107{
 108        out_le32(&chip->awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
 109        snd_pmac_burgundy_busy_wait(chip);
 110}
 111
 112static unsigned
 113snd_pmac_burgundy_rcb(struct snd_pmac *chip, unsigned int addr)
 114{
 115        unsigned val = 0;
 116        unsigned long flags;
 117
 118        spin_lock_irqsave(&chip->reg_lock, flags);
 119
 120        out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
 121        snd_pmac_burgundy_busy_wait(chip);
 122        snd_pmac_burgundy_extend_wait(chip);
 123        val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
 124
 125        spin_unlock_irqrestore(&chip->reg_lock, flags);
 126
 127        return val;
 128}
 129
 130#define BASE2ADDR(base) ((base) << 12)
 131#define ADDR2BASE(addr) ((addr) >> 12)
 132
 133/*
 134 * Burgundy volume: 0 - 100, stereo, word reg
 135 */
 136static void
 137snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address,
 138                               long *volume, int shift)
 139{
 140        int hardvolume, lvolume, rvolume;
 141
 142        if (volume[0] < 0 || volume[0] > 100 ||
 143            volume[1] < 0 || volume[1] > 100)
 144                return; /* -EINVAL */
 145        lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
 146        rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
 147
 148        hardvolume = lvolume + (rvolume << shift);
 149        if (shift == 8)
 150                hardvolume |= hardvolume << 16;
 151
 152        snd_pmac_burgundy_wcw(chip, address, hardvolume);
 153}
 154
 155static void
 156snd_pmac_burgundy_read_volume(struct snd_pmac *chip, unsigned int address,
 157                              long *volume, int shift)
 158{
 159        int wvolume;
 160
 161        wvolume = snd_pmac_burgundy_rcw(chip, address);
 162
 163        volume[0] = wvolume & 0xff;
 164        if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
 165                volume[0] -= BURGUNDY_VOLUME_OFFSET;
 166        else
 167                volume[0] = 0;
 168        volume[1] = (wvolume >> shift) & 0xff;
 169        if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
 170                volume[1] -= BURGUNDY_VOLUME_OFFSET;
 171        else
 172                volume[1] = 0;
 173}
 174
 175static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol,
 176                                         struct snd_ctl_elem_info *uinfo)
 177{
 178        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 179        uinfo->count = 2;
 180        uinfo->value.integer.min = 0;
 181        uinfo->value.integer.max = 100;
 182        return 0;
 183}
 184
 185static int snd_pmac_burgundy_get_volume(struct snd_kcontrol *kcontrol,
 186                                        struct snd_ctl_elem_value *ucontrol)
 187{
 188        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 189        unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 190        int shift = (kcontrol->private_value >> 8) & 0xff;
 191        snd_pmac_burgundy_read_volume(chip, addr,
 192                                      ucontrol->value.integer.value, shift);
 193        return 0;
 194}
 195
 196static int snd_pmac_burgundy_put_volume(struct snd_kcontrol *kcontrol,
 197                                        struct snd_ctl_elem_value *ucontrol)
 198{
 199        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 200        unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 201        int shift = (kcontrol->private_value >> 8) & 0xff;
 202        long nvoices[2];
 203
 204        snd_pmac_burgundy_write_volume(chip, addr,
 205                                       ucontrol->value.integer.value, shift);
 206        snd_pmac_burgundy_read_volume(chip, addr, nvoices, shift);
 207        return (nvoices[0] != ucontrol->value.integer.value[0] ||
 208                nvoices[1] != ucontrol->value.integer.value[1]);
 209}
 210
 211#define BURGUNDY_VOLUME_W(xname, xindex, addr, shift) \
 212{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
 213  .info = snd_pmac_burgundy_info_volume,\
 214  .get = snd_pmac_burgundy_get_volume,\
 215  .put = snd_pmac_burgundy_put_volume,\
 216  .private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) }
 217
 218/*
 219 * Burgundy volume: 0 - 100, stereo, 2-byte reg
 220 */
 221static void
 222snd_pmac_burgundy_write_volume_2b(struct snd_pmac *chip, unsigned int address,
 223                                  long *volume, int off)
 224{
 225        int lvolume, rvolume;
 226
 227        off |= off << 2;
 228        lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
 229        rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
 230
 231        snd_pmac_burgundy_wcb(chip, address + off, lvolume);
 232        snd_pmac_burgundy_wcb(chip, address + off + 0x500, rvolume);
 233}
 234
 235static void
 236snd_pmac_burgundy_read_volume_2b(struct snd_pmac *chip, unsigned int address,
 237                                 long *volume, int off)
 238{
 239        volume[0] = snd_pmac_burgundy_rcb(chip, address + off);
 240        if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
 241                volume[0] -= BURGUNDY_VOLUME_OFFSET;
 242        else
 243                volume[0] = 0;
 244        volume[1] = snd_pmac_burgundy_rcb(chip, address + off + 0x100);
 245        if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
 246                volume[1] -= BURGUNDY_VOLUME_OFFSET;
 247        else
 248                volume[1] = 0;
 249}
 250
 251static int snd_pmac_burgundy_info_volume_2b(struct snd_kcontrol *kcontrol,
 252                                            struct snd_ctl_elem_info *uinfo)
 253{
 254        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 255        uinfo->count = 2;
 256        uinfo->value.integer.min = 0;
 257        uinfo->value.integer.max = 100;
 258        return 0;
 259}
 260
 261static int snd_pmac_burgundy_get_volume_2b(struct snd_kcontrol *kcontrol,
 262                                           struct snd_ctl_elem_value *ucontrol)
 263{
 264        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 265        unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 266        int off = kcontrol->private_value & 0x300;
 267        snd_pmac_burgundy_read_volume_2b(chip, addr,
 268                        ucontrol->value.integer.value, off);
 269        return 0;
 270}
 271
 272static int snd_pmac_burgundy_put_volume_2b(struct snd_kcontrol *kcontrol,
 273                                           struct snd_ctl_elem_value *ucontrol)
 274{
 275        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 276        unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 277        int off = kcontrol->private_value & 0x300;
 278        long nvoices[2];
 279
 280        snd_pmac_burgundy_write_volume_2b(chip, addr,
 281                        ucontrol->value.integer.value, off);
 282        snd_pmac_burgundy_read_volume_2b(chip, addr, nvoices, off);
 283        return (nvoices[0] != ucontrol->value.integer.value[0] ||
 284                nvoices[1] != ucontrol->value.integer.value[1]);
 285}
 286
 287#define BURGUNDY_VOLUME_2B(xname, xindex, addr, off) \
 288{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
 289  .info = snd_pmac_burgundy_info_volume_2b,\
 290  .get = snd_pmac_burgundy_get_volume_2b,\
 291  .put = snd_pmac_burgundy_put_volume_2b,\
 292  .private_value = ((ADDR2BASE(addr) & 0xff) | ((off) << 8)) }
 293
 294/*
 295 * Burgundy gain/attenuation: 0 - 15, mono/stereo, byte reg
 296 */
 297static int snd_pmac_burgundy_info_gain(struct snd_kcontrol *kcontrol,
 298                                       struct snd_ctl_elem_info *uinfo)
 299{
 300        int stereo = (kcontrol->private_value >> 24) & 1;
 301        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 302        uinfo->count = stereo + 1;
 303        uinfo->value.integer.min = 0;
 304        uinfo->value.integer.max = 15;
 305        return 0;
 306}
 307
 308static int snd_pmac_burgundy_get_gain(struct snd_kcontrol *kcontrol,
 309                                      struct snd_ctl_elem_value *ucontrol)
 310{
 311        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 312        unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 313        int stereo = (kcontrol->private_value >> 24) & 1;
 314        int atten = (kcontrol->private_value >> 25) & 1;
 315        int oval;
 316
 317        oval = snd_pmac_burgundy_rcb(chip, addr);
 318        if (atten)
 319                oval = ~oval & 0xff;
 320        ucontrol->value.integer.value[0] = oval & 0xf;
 321        if (stereo)
 322                ucontrol->value.integer.value[1] = (oval >> 4) & 0xf;
 323        return 0;
 324}
 325
 326static int snd_pmac_burgundy_put_gain(struct snd_kcontrol *kcontrol,
 327                                      struct snd_ctl_elem_value *ucontrol)
 328{
 329        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 330        unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 331        int stereo = (kcontrol->private_value >> 24) & 1;
 332        int atten = (kcontrol->private_value >> 25) & 1;
 333        int oval, val;
 334
 335        oval = snd_pmac_burgundy_rcb(chip, addr);
 336        if (atten)
 337                oval = ~oval & 0xff;
 338        val = ucontrol->value.integer.value[0];
 339        if (stereo)
 340                val |= ucontrol->value.integer.value[1] << 4;
 341        else
 342                val |= ucontrol->value.integer.value[0] << 4;
 343        if (atten)
 344                val = ~val & 0xff;
 345        snd_pmac_burgundy_wcb(chip, addr, val);
 346        return val != oval;
 347}
 348
 349#define BURGUNDY_VOLUME_B(xname, xindex, addr, stereo, atten) \
 350{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
 351  .info = snd_pmac_burgundy_info_gain,\
 352  .get = snd_pmac_burgundy_get_gain,\
 353  .put = snd_pmac_burgundy_put_gain,\
 354  .private_value = (ADDR2BASE(addr) | ((stereo) << 24) | ((atten) << 25)) }
 355
 356/*
 357 * Burgundy switch: 0/1, mono/stereo, word reg
 358 */
 359static int snd_pmac_burgundy_info_switch_w(struct snd_kcontrol *kcontrol,
 360                                           struct snd_ctl_elem_info *uinfo)
 361{
 362        int stereo = (kcontrol->private_value >> 24) & 1;
 363        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 364        uinfo->count = stereo + 1;
 365        uinfo->value.integer.min = 0;
 366        uinfo->value.integer.max = 1;
 367        return 0;
 368}
 369
 370static int snd_pmac_burgundy_get_switch_w(struct snd_kcontrol *kcontrol,
 371                                          struct snd_ctl_elem_value *ucontrol)
 372{
 373        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 374        unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
 375        int lmask = 1 << (kcontrol->private_value & 0xff);
 376        int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
 377        int stereo = (kcontrol->private_value >> 24) & 1;
 378        int val = snd_pmac_burgundy_rcw(chip, addr);
 379        ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
 380        if (stereo)
 381                ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
 382        return 0;
 383}
 384
 385static int snd_pmac_burgundy_put_switch_w(struct snd_kcontrol *kcontrol,
 386                                          struct snd_ctl_elem_value *ucontrol)
 387{
 388        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 389        unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
 390        int lmask = 1 << (kcontrol->private_value & 0xff);
 391        int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
 392        int stereo = (kcontrol->private_value >> 24) & 1;
 393        int val, oval;
 394        oval = snd_pmac_burgundy_rcw(chip, addr);
 395        val = oval & ~(lmask | (stereo ? rmask : 0));
 396        if (ucontrol->value.integer.value[0])
 397                val |= lmask;
 398        if (stereo && ucontrol->value.integer.value[1])
 399                val |= rmask;
 400        snd_pmac_burgundy_wcw(chip, addr, val);
 401        return val != oval;
 402}
 403
 404#define BURGUNDY_SWITCH_W(xname, xindex, addr, lbit, rbit, stereo) \
 405{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
 406  .info = snd_pmac_burgundy_info_switch_w,\
 407  .get = snd_pmac_burgundy_get_switch_w,\
 408  .put = snd_pmac_burgundy_put_switch_w,\
 409  .private_value = ((lbit) | ((rbit) << 8)\
 410                | (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
 411
 412/*
 413 * Burgundy switch: 0/1, mono/stereo, byte reg, bit mask
 414 */
 415static int snd_pmac_burgundy_info_switch_b(struct snd_kcontrol *kcontrol,
 416                                           struct snd_ctl_elem_info *uinfo)
 417{
 418        int stereo = (kcontrol->private_value >> 24) & 1;
 419        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 420        uinfo->count = stereo + 1;
 421        uinfo->value.integer.min = 0;
 422        uinfo->value.integer.max = 1;
 423        return 0;
 424}
 425
 426static int snd_pmac_burgundy_get_switch_b(struct snd_kcontrol *kcontrol,
 427                                          struct snd_ctl_elem_value *ucontrol)
 428{
 429        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 430        unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
 431        int lmask = kcontrol->private_value & 0xff;
 432        int rmask = (kcontrol->private_value >> 8) & 0xff;
 433        int stereo = (kcontrol->private_value >> 24) & 1;
 434        int val = snd_pmac_burgundy_rcb(chip, addr);
 435        ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
 436        if (stereo)
 437                ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
 438        return 0;
 439}
 440
 441static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol,
 442                                          struct snd_ctl_elem_value *ucontrol)
 443{
 444        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 445        unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
 446        int lmask = kcontrol->private_value & 0xff;
 447        int rmask = (kcontrol->private_value >> 8) & 0xff;
 448        int stereo = (kcontrol->private_value >> 24) & 1;
 449        int val, oval;
 450        oval = snd_pmac_burgundy_rcb(chip, addr);
 451        val = oval & ~(lmask | rmask);
 452        if (ucontrol->value.integer.value[0])
 453                val |= lmask;
 454        if (stereo && ucontrol->value.integer.value[1])
 455                val |= rmask;
 456        snd_pmac_burgundy_wcb(chip, addr, val);
 457        return val != oval;
 458}
 459
 460#define BURGUNDY_SWITCH_B(xname, xindex, addr, lmask, rmask, stereo) \
 461{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
 462  .info = snd_pmac_burgundy_info_switch_b,\
 463  .get = snd_pmac_burgundy_get_switch_b,\
 464  .put = snd_pmac_burgundy_put_switch_b,\
 465  .private_value = ((lmask) | ((rmask) << 8)\
 466                | (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
 467
 468/*
 469 * Burgundy mixers
 470 */
 471static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __devinitdata = {
 472        BURGUNDY_VOLUME_W("Master Playback Volume", 0,
 473                        MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
 474        BURGUNDY_VOLUME_W("CD Capture Volume", 0,
 475                        MASK_ADDR_BURGUNDY_VOLCD, 16),
 476        BURGUNDY_VOLUME_2B("Input Capture Volume", 0,
 477                        MASK_ADDR_BURGUNDY_VOLMIX01, 2),
 478        BURGUNDY_VOLUME_2B("Mixer Playback Volume", 0,
 479                        MASK_ADDR_BURGUNDY_VOLMIX23, 0),
 480        BURGUNDY_VOLUME_B("CD Gain Capture Volume", 0,
 481                        MASK_ADDR_BURGUNDY_GAINCD, 1, 0),
 482        BURGUNDY_SWITCH_W("Master Capture Switch", 0,
 483                        MASK_ADDR_BURGUNDY_OUTPUTENABLES, 24, 0, 0),
 484        BURGUNDY_SWITCH_W("CD Capture Switch", 0,
 485                        MASK_ADDR_BURGUNDY_CAPTURESELECTS, 0, 16, 1),
 486        BURGUNDY_SWITCH_W("CD Playback Switch", 0,
 487                        MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 0, 16, 1),
 488/*      BURGUNDY_SWITCH_W("Loop Capture Switch", 0,
 489 *              MASK_ADDR_BURGUNDY_CAPTURESELECTS, 8, 24, 1),
 490 *      BURGUNDY_SWITCH_B("Mixer out Capture Switch", 0,
 491 *              MASK_ADDR_BURGUNDY_HOSTIFAD, 0x02, 0, 0),
 492 *      BURGUNDY_SWITCH_B("Mixer Capture Switch", 0,
 493 *              MASK_ADDR_BURGUNDY_HOSTIFAD, 0x01, 0, 0),
 494 *      BURGUNDY_SWITCH_B("PCM out Capture Switch", 0,
 495 *              MASK_ADDR_BURGUNDY_HOSTIFEH, 0x02, 0, 0),
 496 */     BURGUNDY_SWITCH_B("PCM Capture Switch", 0,
 497                        MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0)
 498};
 499static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = {
 500        BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
 501                        MASK_ADDR_BURGUNDY_VOLLINE, 16),
 502        BURGUNDY_VOLUME_W("Mic Capture Volume", 0,
 503                        MASK_ADDR_BURGUNDY_VOLMIC, 16),
 504        BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
 505                        MASK_ADDR_BURGUNDY_GAINLINE, 1, 0),
 506        BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0,
 507                        MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
 508        BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
 509                        MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
 510        BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
 511                        MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1),
 512        BURGUNDY_VOLUME_B("Headphone Playback Volume", 0,
 513                        MASK_ADDR_BURGUNDY_ATTENHP, 1, 1),
 514        BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
 515                        MASK_ADDR_BURGUNDY_CAPTURESELECTS, 1, 17, 1),
 516        BURGUNDY_SWITCH_W("Mic Capture Switch", 0,
 517                        MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
 518        BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
 519                        MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 1, 17, 1),
 520        BURGUNDY_SWITCH_W("Mic Playback Switch", 0,
 521                        MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
 522        BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0,
 523                        MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1)
 524};
 525static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = {
 526        BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
 527                        MASK_ADDR_BURGUNDY_VOLMIC, 16),
 528        BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
 529                        MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
 530        BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
 531                        MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1),
 532        BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
 533                        MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
 534        BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
 535                        MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
 536        BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
 537                        MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
 538/*      BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0,
 539 *              MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */
 540};
 541static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __devinitdata =
 542BURGUNDY_SWITCH_B("Master Playback Switch", 0,
 543        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 544        BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT,
 545        BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1);
 546static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __devinitdata =
 547BURGUNDY_SWITCH_B("Master Playback Switch", 0,
 548        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 549        BURGUNDY_OUTPUT_INTERN
 550        | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
 551static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata =
 552BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
 553        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 554        BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
 555static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata =
 556BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
 557        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 558        BURGUNDY_OUTPUT_INTERN, 0, 0);
 559static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata =
 560BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
 561        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 562        BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1);
 563static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __devinitdata =
 564BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
 565        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 566        BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
 567static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __devinitdata =
 568BURGUNDY_SWITCH_B("Headphone Playback Switch", 0,
 569        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 570        BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1);
 571
 572
 573#ifdef PMAC_SUPPORT_AUTOMUTE
 574/*
 575 * auto-mute stuffs
 576 */
 577static int snd_pmac_burgundy_detect_headphone(struct snd_pmac *chip)
 578{
 579        return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0;
 580}
 581
 582static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify)
 583{
 584        if (chip->auto_mute) {
 585                int imac = machine_is_compatible("iMac");
 586                int reg, oreg;
 587                reg = oreg = snd_pmac_burgundy_rcb(chip,
 588                                MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
 589                reg &= imac ? ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
 590                                | BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
 591                        : ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
 592                                | BURGUNDY_OUTPUT_INTERN);
 593                if (snd_pmac_burgundy_detect_headphone(chip))
 594                        reg |= imac ? (BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
 595                                : (BURGUNDY_OUTPUT_LEFT
 596                                        | BURGUNDY_OUTPUT_RIGHT);
 597                else
 598                        reg |= imac ? (BURGUNDY_OUTPUT_LEFT
 599                                        | BURGUNDY_OUTPUT_RIGHT)
 600                                : (BURGUNDY_OUTPUT_INTERN);
 601                if (do_notify && reg == oreg)
 602                        return;
 603                snd_pmac_burgundy_wcb(chip,
 604                                MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg);
 605                if (do_notify) {
 606                        snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 607                                       &chip->master_sw_ctl->id);
 608                        snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 609                                       &chip->speaker_sw_ctl->id);
 610                        snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 611                                       &chip->hp_detect_ctl->id);
 612                }
 613        }
 614}
 615#endif /* PMAC_SUPPORT_AUTOMUTE */
 616
 617
 618/*
 619 * initialize burgundy
 620 */
 621int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip)
 622{
 623        int imac = machine_is_compatible("iMac");
 624        int i, err;
 625
 626        /* Checks to see the chip is alive and kicking */
 627        if ((in_le32(&chip->awacs->codec_ctrl) & MASK_ERRCODE) == 0xf0000) {
 628                printk(KERN_WARNING "pmac burgundy: disabled by MacOS :-(\n");
 629                return 1;
 630        }
 631
 632        snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES,
 633                           DEF_BURGUNDY_OUTPUTENABLES);
 634        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 635                           DEF_BURGUNDY_MORE_OUTPUTENABLES);
 636        snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
 637                           DEF_BURGUNDY_OUTPUTSELECTS);
 638
 639        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21,
 640                           DEF_BURGUNDY_INPSEL21);
 641        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3,
 642                           imac ? DEF_BURGUNDY_INPSEL3_IMAC
 643                           : DEF_BURGUNDY_INPSEL3_PMAC);
 644        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD,
 645                           DEF_BURGUNDY_GAINCD);
 646        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE,
 647                           DEF_BURGUNDY_GAINLINE);
 648        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMIC,
 649                           DEF_BURGUNDY_GAINMIC);
 650        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMODEM,
 651                           DEF_BURGUNDY_GAINMODEM);
 652
 653        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENSPEAKER,
 654                           DEF_BURGUNDY_ATTENSPEAKER);
 655        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENLINEOUT,
 656                           DEF_BURGUNDY_ATTENLINEOUT);
 657        snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENHP,
 658                           DEF_BURGUNDY_ATTENHP);
 659
 660        snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_MASTER_VOLUME,
 661                           DEF_BURGUNDY_MASTER_VOLUME);
 662        snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLCD,
 663                           DEF_BURGUNDY_VOLCD);
 664        snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLLINE,
 665                           DEF_BURGUNDY_VOLLINE);
 666        snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC,
 667                           DEF_BURGUNDY_VOLMIC);
 668
 669        if (chip->hp_stat_mask == 0) {
 670                /* set headphone-jack detection bit */
 671                if (imac)
 672                        chip->hp_stat_mask = BURGUNDY_HPDETECT_IMAC_UPPER
 673                                | BURGUNDY_HPDETECT_IMAC_LOWER
 674                                | BURGUNDY_HPDETECT_IMAC_SIDE;
 675                else
 676                        chip->hp_stat_mask = BURGUNDY_HPDETECT_PMAC_BACK;
 677        }
 678        /*
 679         * build burgundy mixers
 680         */
 681        strcpy(chip->card->mixername, "PowerMac Burgundy");
 682
 683        for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) {
 684                err = snd_ctl_add(chip->card,
 685                    snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip));
 686                if (err < 0)
 687                        return err;
 688        }
 689        for (i = 0; i < (imac ? ARRAY_SIZE(snd_pmac_burgundy_mixers_imac)
 690                        : ARRAY_SIZE(snd_pmac_burgundy_mixers_pmac)); i++) {
 691                err = snd_ctl_add(chip->card,
 692                    snd_ctl_new1(imac ? &snd_pmac_burgundy_mixers_imac[i]
 693                    : &snd_pmac_burgundy_mixers_pmac[i], chip));
 694                if (err < 0)
 695                        return err;
 696        }
 697        chip->master_sw_ctl = snd_ctl_new1(imac
 698                        ? &snd_pmac_burgundy_master_sw_imac
 699                        : &snd_pmac_burgundy_master_sw_pmac, chip);
 700        err = snd_ctl_add(chip->card, chip->master_sw_ctl);
 701        if (err < 0)
 702                return err;
 703        chip->master_sw_ctl = snd_ctl_new1(imac
 704                        ? &snd_pmac_burgundy_line_sw_imac
 705                        : &snd_pmac_burgundy_line_sw_pmac, chip);
 706        err = snd_ctl_add(chip->card, chip->master_sw_ctl);
 707        if (err < 0)
 708                return err;
 709        if (imac) {
 710                chip->master_sw_ctl = snd_ctl_new1(
 711                                &snd_pmac_burgundy_hp_sw_imac, chip);
 712                err = snd_ctl_add(chip->card, chip->master_sw_ctl);
 713                if (err < 0)
 714                        return err;
 715        }
 716        chip->speaker_sw_ctl = snd_ctl_new1(imac
 717                        ? &snd_pmac_burgundy_speaker_sw_imac
 718                        : &snd_pmac_burgundy_speaker_sw_pmac, chip);
 719        err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
 720        if (err < 0)
 721                return err;
 722#ifdef PMAC_SUPPORT_AUTOMUTE
 723        err = snd_pmac_add_automute(chip);
 724        if (err < 0)
 725                return err;
 726
 727        chip->detect_headphone = snd_pmac_burgundy_detect_headphone;
 728        chip->update_automute = snd_pmac_burgundy_update_automute;
 729        snd_pmac_burgundy_update_automute(chip, 0); /* update the status only */
 730#endif
 731
 732        return 0;
 733}
 734