File Index
Files and directories
Sign in
FILE

burgundy.c

File preview with syntax highlighting.

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