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