cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

burgundy.c (24235B)


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