Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

52
sound/ppc/Kconfig Normal file
View file

@ -0,0 +1,52 @@
# ALSA PowerMac drivers
menuconfig SND_PPC
bool "PowerPC sound devices"
depends on PPC
default y
help
Support for sound devices specific to PowerPC architectures.
if SND_PPC
config SND_POWERMAC
tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
depends on I2C && INPUT && PPC_PMAC
select SND_PCM
select SND_VMASTER
help
Say Y here to include support for the integrated sound device.
To compile this driver as a module, choose M here: the module
will be called snd-powermac.
config SND_POWERMAC_AUTO_DRC
bool "Toggle DRC automatically at headphone/line plug-in"
depends on SND_POWERMAC
default y
help
Say Y here to enable the automatic toggle of DRC (dynamic
range compression) on Tumbler/Snapper.
If this feature is enabled, DRC is turned off when the
headphone/line jack is plugged, and turned on when unplugged.
Note that you can turn on/off DRC manually even without this
option.
config SND_PS3
tristate "PS3 Audio support"
depends on PS3_PS3AV
select SND_PCM
default m
help
Say Y here to include support for audio on the PS3
To compile this driver as a module, choose M here: the module
will be called snd_ps3.
config SND_PS3_DEFAULT_START_DELAY
int "Startup delay time in ms"
depends on SND_PS3
default "2000"
endif # SND_PPC

10
sound/ppc/Makefile Normal file
View file

@ -0,0 +1,10 @@
#
# Makefile for ALSA
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
obj-$(CONFIG_SND_PS3) += snd_ps3.o

1146
sound/ppc/awacs.c Normal file

File diff suppressed because it is too large Load diff

205
sound/ppc/awacs.h Normal file
View file

@ -0,0 +1,205 @@
/*
* Driver for PowerMac AWACS onboard soundchips
* Copyright (c) 2001 by Takashi Iwai <tiwai@suse.de>
* based on dmasound.c.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __AWACS_H
#define __AWACS_H
/*******************************/
/* AWACs Audio Register Layout */
/*******************************/
struct awacs_regs {
unsigned control; /* Audio control register */
unsigned pad0[3];
unsigned codec_ctrl; /* Codec control register */
unsigned pad1[3];
unsigned codec_stat; /* Codec status register */
unsigned pad2[3];
unsigned clip_count; /* Clipping count register */
unsigned pad3[3];
unsigned byteswap; /* Data is little-endian if 1 */
};
/*******************/
/* Audio Bit Masks */
/*******************/
/* Audio Control Reg Bit Masks */
/* ----- ------- --- --- ----- */
#define MASK_ISFSEL (0xf) /* Input SubFrame Select */
#define MASK_OSFSEL (0xf << 4) /* Output SubFrame Select */
#define MASK_RATE (0x7 << 8) /* Sound Rate */
#define MASK_CNTLERR (0x1 << 11) /* Error */
#define MASK_PORTCHG (0x1 << 12) /* Port Change */
#define MASK_IEE (0x1 << 13) /* Enable Interrupt on Error */
#define MASK_IEPC (0x1 << 14) /* Enable Interrupt on Port Change */
#define MASK_SSFSEL (0x3 << 15) /* Status SubFrame Select */
/* Audio Codec Control Reg Bit Masks */
/* ----- ----- ------- --- --- ----- */
#define MASK_NEWECMD (0x1 << 24) /* Lock: don't write to reg when 1 */
#define MASK_EMODESEL (0x3 << 22) /* Send info out on which frame? */
#define MASK_EXMODEADDR (0x3ff << 12) /* Extended Mode Address -- 10 bits */
#define MASK_EXMODEDATA (0xfff) /* Extended Mode Data -- 12 bits */
/* Audio Codec Control Address Values / Masks */
/* ----- ----- ------- ------- ------ - ----- */
#define MASK_ADDR0 (0x0 << 12) /* Expanded Data Mode Address 0 */
#define MASK_ADDR_MUX MASK_ADDR0 /* Mux Control */
#define MASK_ADDR_GAIN MASK_ADDR0
#define MASK_ADDR1 (0x1 << 12) /* Expanded Data Mode Address 1 */
#define MASK_ADDR_MUTE MASK_ADDR1
#define MASK_ADDR_RATE MASK_ADDR1
#define MASK_ADDR2 (0x2 << 12) /* Expanded Data Mode Address 2 */
#define MASK_ADDR_VOLA MASK_ADDR2 /* Volume Control A -- Headphones */
#define MASK_ADDR_VOLHD MASK_ADDR2
#define MASK_ADDR4 (0x4 << 12) /* Expanded Data Mode Address 4 */
#define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */
#define MASK_ADDR_VOLSPK MASK_ADDR4
/* additional registers of screamer */
#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */
#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */
#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */
/* Address 0 Bit Masks & Macros */
/* ------- - --- ----- - ------ */
#define MASK_GAINRIGHT (0xf) /* Gain Right Mask */
#define MASK_GAINLEFT (0xf << 4) /* Gain Left Mask */
#define MASK_GAINLINE (0x1 << 8) /* Disable Mic preamp */
#define MASK_GAINMIC (0x0 << 8) /* Enable Mic preamp */
#define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */
#define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */
#define MASK_MUX_AUDIN (0x1 << 11) /* Select Audio In in MUX */
#define MASK_MUX_LINE MASK_MUX_AUDIN
#define SHIFT_GAINLINE 8
#define SHIFT_MUX_CD 9
#define SHIFT_MUX_MIC 10
#define SHIFT_MUX_LINE 11
#define GAINRIGHT(x) ((x) & MASK_GAINRIGHT)
#define GAINLEFT(x) (((x) << 4) & MASK_GAINLEFT)
/* Address 1 Bit Masks */
/* ------- - --- ----- */
#define MASK_ADDR1RES1 (0x3) /* Reserved */
#define MASK_RECALIBRATE (0x1 << 2) /* Recalibrate */
#define MASK_SAMPLERATE (0x7 << 3) /* Sample Rate: */
#define MASK_LOOPTHRU (0x1 << 6) /* Loopthrough Enable */
#define SHIFT_LOOPTHRU 6
#define MASK_CMUTE (0x1 << 7) /* Output C (Speaker) Mute when 1 */
#define MASK_SPKMUTE MASK_CMUTE
#define SHIFT_SPKMUTE 7
#define MASK_ADDR1RES2 (0x1 << 8) /* Reserved */
#define MASK_AMUTE (0x1 << 9) /* Output A (Headphone) Mute when 1 */
#define MASK_HDMUTE MASK_AMUTE
#define SHIFT_HDMUTE 9
#define MASK_PAROUT (0x3 << 10) /* Parallel Out (???) */
#define MASK_PAROUT0 (0x1 << 10) /* Parallel Out (???) */
#define MASK_PAROUT1 (0x1 << 11) /* Parallel Out (enable speaker) */
#define SHIFT_PAROUT 10
#define SHIFT_PAROUT0 10
#define SHIFT_PAROUT1 11
#define SAMPLERATE_48000 (0x0 << 3) /* 48 or 44.1 kHz */
#define SAMPLERATE_32000 (0x1 << 3) /* 32 or 29.4 kHz */
#define SAMPLERATE_24000 (0x2 << 3) /* 24 or 22.05 kHz */
#define SAMPLERATE_19200 (0x3 << 3) /* 19.2 or 17.64 kHz */
#define SAMPLERATE_16000 (0x4 << 3) /* 16 or 14.7 kHz */
#define SAMPLERATE_12000 (0x5 << 3) /* 12 or 11.025 kHz */
#define SAMPLERATE_9600 (0x6 << 3) /* 9.6 or 8.82 kHz */
#define SAMPLERATE_8000 (0x7 << 3) /* 8 or 7.35 kHz */
/* Address 2 & 4 Bit Masks & Macros */
/* ------- - - - --- ----- - ------ */
#define MASK_OUTVOLRIGHT (0xf) /* Output Right Volume */
#define MASK_ADDR2RES1 (0x2 << 4) /* Reserved */
#define MASK_ADDR4RES1 MASK_ADDR2RES1
#define MASK_OUTVOLLEFT (0xf << 6) /* Output Left Volume */
#define MASK_ADDR2RES2 (0x2 << 10) /* Reserved */
#define MASK_ADDR4RES2 MASK_ADDR2RES2
#define VOLRIGHT(x) (((~(x)) & MASK_OUTVOLRIGHT))
#define VOLLEFT(x) (((~(x)) << 6) & MASK_OUTVOLLEFT)
/* address 6 */
#define MASK_MIC_BOOST (0x4) /* screamer mic boost */
#define SHIFT_MIC_BOOST 2
/* Audio Codec Status Reg Bit Masks */
/* ----- ----- ------ --- --- ----- */
#define MASK_EXTEND (0x1 << 23) /* Extend */
#define MASK_VALID (0x1 << 22) /* Valid Data? */
#define MASK_OFLEFT (0x1 << 21) /* Overflow Left */
#define MASK_OFRIGHT (0x1 << 20) /* Overflow Right */
#define MASK_ERRCODE (0xf << 16) /* Error Code */
#define MASK_REVISION (0xf << 12) /* Revision Number */
#define MASK_MFGID (0xf << 8) /* Mfg. ID */
#define MASK_CODSTATRES (0xf << 4) /* bits 4 - 7 reserved */
#define MASK_INSENSE (0xf) /* port sense bits: */
#define MASK_HDPCONN 8 /* headphone plugged in */
#define MASK_LOCONN 4 /* line-out plugged in */
#define MASK_LICONN 2 /* line-in plugged in */
#define MASK_MICCONN 1 /* microphone plugged in */
#define MASK_LICONN_IMAC 8 /* line-in plugged in */
#define MASK_HDPRCONN_IMAC 4 /* headphone right plugged in */
#define MASK_HDPLCONN_IMAC 2 /* headphone left plugged in */
#define MASK_LOCONN_IMAC 1 /* line-out plugged in */
/* Clipping Count Reg Bit Masks */
/* -------- ----- --- --- ----- */
#define MASK_CLIPLEFT (0xff << 7) /* Clipping Count, Left Channel */
#define MASK_CLIPRIGHT (0xff) /* Clipping Count, Right Channel */
/* DBDMA ChannelStatus Bit Masks */
/* ----- ------------- --- ----- */
#define MASK_CSERR (0x1 << 7) /* Error */
#define MASK_EOI (0x1 << 6) /* End of Input --
only for Input Channel */
#define MASK_CSUNUSED (0x1f << 1) /* bits 1-5 not used */
#define MASK_WAIT (0x1) /* Wait */
/* Various Rates */
/* ------- ----- */
#define RATE_48000 (0x0 << 8) /* 48 kHz */
#define RATE_44100 (0x0 << 8) /* 44.1 kHz */
#define RATE_32000 (0x1 << 8) /* 32 kHz */
#define RATE_29400 (0x1 << 8) /* 29.4 kHz */
#define RATE_24000 (0x2 << 8) /* 24 kHz */
#define RATE_22050 (0x2 << 8) /* 22.05 kHz */
#define RATE_19200 (0x3 << 8) /* 19.2 kHz */
#define RATE_17640 (0x3 << 8) /* 17.64 kHz */
#define RATE_16000 (0x4 << 8) /* 16 kHz */
#define RATE_14700 (0x4 << 8) /* 14.7 kHz */
#define RATE_12000 (0x5 << 8) /* 12 kHz */
#define RATE_11025 (0x5 << 8) /* 11.025 kHz */
#define RATE_9600 (0x6 << 8) /* 9.6 kHz */
#define RATE_8820 (0x6 << 8) /* 8.82 kHz */
#define RATE_8000 (0x7 << 8) /* 8 kHz */
#define RATE_7350 (0x7 << 8) /* 7.35 kHz */
#define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */
#endif /* __AWACS_H */

285
sound/ppc/beep.c Normal file
View file

@ -0,0 +1,285 @@
/*
* Beep using pcm
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/control.h>
#include "pmac.h"
struct pmac_beep {
int running; /* boolean */
int volume; /* mixer volume: 0-100 */
int volume_play; /* currently playing volume */
int hz;
int nsamples;
short *buf; /* allocated wave buffer */
dma_addr_t addr; /* physical address of buffer */
struct input_dev *dev;
};
/*
* stop beep if running
*/
void snd_pmac_beep_stop(struct snd_pmac *chip)
{
struct pmac_beep *beep = chip->beep;
if (beep && beep->running) {
beep->running = 0;
snd_pmac_beep_dma_stop(chip);
}
}
/*
* Stuff for outputting a beep. The values range from -327 to +327
* so we can multiply by an amplitude in the range 0..100 to get a
* signed short value to put in the output buffer.
*/
static short beep_wform[256] = {
0, 40, 79, 117, 153, 187, 218, 245,
269, 288, 304, 316, 323, 327, 327, 324,
318, 310, 299, 288, 275, 262, 249, 236,
224, 213, 204, 196, 190, 186, 183, 182,
182, 183, 186, 189, 192, 196, 200, 203,
206, 208, 209, 209, 209, 207, 204, 201,
197, 193, 188, 183, 179, 174, 170, 166,
163, 161, 160, 159, 159, 160, 161, 162,
164, 166, 168, 169, 171, 171, 171, 170,
169, 167, 163, 159, 155, 150, 144, 139,
133, 128, 122, 117, 113, 110, 107, 105,
103, 103, 103, 103, 104, 104, 105, 105,
105, 103, 101, 97, 92, 86, 78, 68,
58, 45, 32, 18, 3, -11, -26, -41,
-55, -68, -79, -88, -95, -100, -102, -102,
-99, -93, -85, -75, -62, -48, -33, -16,
0, 16, 33, 48, 62, 75, 85, 93,
99, 102, 102, 100, 95, 88, 79, 68,
55, 41, 26, 11, -3, -18, -32, -45,
-58, -68, -78, -86, -92, -97, -101, -103,
-105, -105, -105, -104, -104, -103, -103, -103,
-103, -105, -107, -110, -113, -117, -122, -128,
-133, -139, -144, -150, -155, -159, -163, -167,
-169, -170, -171, -171, -171, -169, -168, -166,
-164, -162, -161, -160, -159, -159, -160, -161,
-163, -166, -170, -174, -179, -183, -188, -193,
-197, -201, -204, -207, -209, -209, -209, -208,
-206, -203, -200, -196, -192, -189, -186, -183,
-182, -182, -183, -186, -190, -196, -204, -213,
-224, -236, -249, -262, -275, -288, -299, -310,
-318, -324, -327, -327, -323, -316, -304, -288,
-269, -245, -218, -187, -153, -117, -79, -40,
};
#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
#define BEEP_BUFLEN 512
#define BEEP_VOLUME 15 /* 0 - 100 */
static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
unsigned int code, int hz)
{
struct snd_pmac *chip;
struct pmac_beep *beep;
unsigned long flags;
int beep_speed = 0;
int srate;
int period, ncycles, nsamples;
int i, j, f;
short *p;
if (type != EV_SND)
return -1;
switch (code) {
case SND_BELL: if (hz) hz = 1000;
case SND_TONE: break;
default: return -1;
}
chip = input_get_drvdata(dev);
if (! chip || (beep = chip->beep) == NULL)
return -1;
if (! hz) {
spin_lock_irqsave(&chip->reg_lock, flags);
if (beep->running)
snd_pmac_beep_stop(chip);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
srate = chip->freq_table[beep_speed];
if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
hz = 1000;
spin_lock_irqsave(&chip->reg_lock, flags);
if (chip->playback.running || chip->capture.running || beep->running) {
spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
beep->running = 1;
spin_unlock_irqrestore(&chip->reg_lock, flags);
if (hz == beep->hz && beep->volume == beep->volume_play) {
nsamples = beep->nsamples;
} else {
period = srate * 256 / hz; /* fixed point */
ncycles = BEEP_BUFLEN * 256 / period;
nsamples = (period * ncycles) >> 8;
f = ncycles * 65536 / nsamples;
j = 0;
p = beep->buf;
for (i = 0; i < nsamples; ++i, p += 2) {
p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
j = (j + f) & 0xffff;
}
beep->hz = hz;
beep->volume_play = beep->volume;
beep->nsamples = nsamples;
}
spin_lock_irqsave(&chip->reg_lock, flags);
snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
/*
* beep volume mixer
*/
static int snd_pmac_info_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 100;
return 0;
}
static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
if (snd_BUG_ON(!chip->beep))
return -ENXIO;
ucontrol->value.integer.value[0] = chip->beep->volume;
return 0;
}
static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int oval, nval;
if (snd_BUG_ON(!chip->beep))
return -ENXIO;
oval = chip->beep->volume;
nval = ucontrol->value.integer.value[0];
if (nval > 100)
return -EINVAL;
chip->beep->volume = nval;
return oval != chip->beep->volume;
}
static struct snd_kcontrol_new snd_pmac_beep_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Beep Playback Volume",
.info = snd_pmac_info_beep,
.get = snd_pmac_get_beep,
.put = snd_pmac_put_beep,
};
/* Initialize beep stuff */
int snd_pmac_attach_beep(struct snd_pmac *chip)
{
struct pmac_beep *beep;
struct input_dev *input_dev;
struct snd_kcontrol *beep_ctl;
void *dmabuf;
int err = -ENOMEM;
beep = kzalloc(sizeof(*beep), GFP_KERNEL);
if (! beep)
return -ENOMEM;
dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
&beep->addr, GFP_KERNEL);
input_dev = input_allocate_device();
if (! dmabuf || ! input_dev)
goto fail1;
/* FIXME: set more better values */
input_dev->name = "PowerMac Beep";
input_dev->phys = "powermac/beep";
input_dev->id.bustype = BUS_ADB;
input_dev->id.vendor = 0x001f;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->evbit[0] = BIT_MASK(EV_SND);
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
input_dev->event = snd_pmac_beep_event;
input_dev->dev.parent = &chip->pdev->dev;
input_set_drvdata(input_dev, chip);
beep->dev = input_dev;
beep->buf = dmabuf;
beep->volume = BEEP_VOLUME;
beep->running = 0;
beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip);
err = snd_ctl_add(chip->card, beep_ctl);
if (err < 0)
goto fail1;
chip->beep = beep;
err = input_register_device(beep->dev);
if (err)
goto fail2;
return 0;
fail2: snd_ctl_remove(chip->card, beep_ctl);
fail1: input_free_device(input_dev);
if (dmabuf)
dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
dmabuf, beep->addr);
kfree(beep);
return err;
}
void snd_pmac_detach_beep(struct snd_pmac *chip)
{
if (chip->beep) {
input_unregister_device(chip->beep->dev);
dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
chip->beep->buf, chip->beep->addr);
kfree(chip->beep);
chip->beep = NULL;
}
}

732
sound/ppc/burgundy.c Normal file
View file

@ -0,0 +1,732 @@
/*
* PMac Burgundy lowlevel functions
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
* code based on dmasound.c.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/io.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <sound/core.h>
#include "pmac.h"
#include "burgundy.h"
/* Waits for busy flag to clear */
static inline void
snd_pmac_burgundy_busy_wait(struct snd_pmac *chip)
{
int timeout = 50;
while ((in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) && timeout--)
udelay(1);
if (timeout < 0)
printk(KERN_DEBUG "burgundy_busy_wait: timeout\n");
}
static inline void
snd_pmac_burgundy_extend_wait(struct snd_pmac *chip)
{
int timeout;
timeout = 50;
while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
udelay(1);
if (timeout < 0)
printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n");
timeout = 50;
while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
udelay(1);
if (timeout < 0)
printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n");
}
static void
snd_pmac_burgundy_wcw(struct snd_pmac *chip, unsigned addr, unsigned val)
{
out_le32(&chip->awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
snd_pmac_burgundy_busy_wait(chip);
out_le32(&chip->awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
snd_pmac_burgundy_busy_wait(chip);
out_le32(&chip->awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
snd_pmac_burgundy_busy_wait(chip);
out_le32(&chip->awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
snd_pmac_burgundy_busy_wait(chip);
}
static unsigned
snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr)
{
unsigned val = 0;
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
snd_pmac_burgundy_busy_wait(chip);
snd_pmac_burgundy_extend_wait(chip);
val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
out_le32(&chip->awacs->codec_ctrl, addr + 0x100100);
snd_pmac_burgundy_busy_wait(chip);
snd_pmac_burgundy_extend_wait(chip);
val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<8;
out_le32(&chip->awacs->codec_ctrl, addr + 0x100200);
snd_pmac_burgundy_busy_wait(chip);
snd_pmac_burgundy_extend_wait(chip);
val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<16;
out_le32(&chip->awacs->codec_ctrl, addr + 0x100300);
snd_pmac_burgundy_busy_wait(chip);
snd_pmac_burgundy_extend_wait(chip);
val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<24;
spin_unlock_irqrestore(&chip->reg_lock, flags);
return val;
}
static void
snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr,
unsigned int val)
{
out_le32(&chip->awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
snd_pmac_burgundy_busy_wait(chip);
}
static unsigned
snd_pmac_burgundy_rcb(struct snd_pmac *chip, unsigned int addr)
{
unsigned val = 0;
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
snd_pmac_burgundy_busy_wait(chip);
snd_pmac_burgundy_extend_wait(chip);
val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
spin_unlock_irqrestore(&chip->reg_lock, flags);
return val;
}
#define BASE2ADDR(base) ((base) << 12)
#define ADDR2BASE(addr) ((addr) >> 12)
/*
* Burgundy volume: 0 - 100, stereo, word reg
*/
static void
snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address,
long *volume, int shift)
{
int hardvolume, lvolume, rvolume;
if (volume[0] < 0 || volume[0] > 100 ||
volume[1] < 0 || volume[1] > 100)
return; /* -EINVAL */
lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
hardvolume = lvolume + (rvolume << shift);
if (shift == 8)
hardvolume |= hardvolume << 16;
snd_pmac_burgundy_wcw(chip, address, hardvolume);
}
static void
snd_pmac_burgundy_read_volume(struct snd_pmac *chip, unsigned int address,
long *volume, int shift)
{
int wvolume;
wvolume = snd_pmac_burgundy_rcw(chip, address);
volume[0] = wvolume & 0xff;
if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
volume[0] -= BURGUNDY_VOLUME_OFFSET;
else
volume[0] = 0;
volume[1] = (wvolume >> shift) & 0xff;
if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
volume[1] -= BURGUNDY_VOLUME_OFFSET;
else
volume[1] = 0;
}
static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 100;
return 0;
}
static int snd_pmac_burgundy_get_volume(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
int shift = (kcontrol->private_value >> 8) & 0xff;
snd_pmac_burgundy_read_volume(chip, addr,
ucontrol->value.integer.value, shift);
return 0;
}
static int snd_pmac_burgundy_put_volume(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
int shift = (kcontrol->private_value >> 8) & 0xff;
long nvoices[2];
snd_pmac_burgundy_write_volume(chip, addr,
ucontrol->value.integer.value, shift);
snd_pmac_burgundy_read_volume(chip, addr, nvoices, shift);
return (nvoices[0] != ucontrol->value.integer.value[0] ||
nvoices[1] != ucontrol->value.integer.value[1]);
}
#define BURGUNDY_VOLUME_W(xname, xindex, addr, shift) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
.info = snd_pmac_burgundy_info_volume,\
.get = snd_pmac_burgundy_get_volume,\
.put = snd_pmac_burgundy_put_volume,\
.private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) }
/*
* Burgundy volume: 0 - 100, stereo, 2-byte reg
*/
static void
snd_pmac_burgundy_write_volume_2b(struct snd_pmac *chip, unsigned int address,
long *volume, int off)
{
int lvolume, rvolume;
off |= off << 2;
lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
snd_pmac_burgundy_wcb(chip, address + off, lvolume);
snd_pmac_burgundy_wcb(chip, address + off + 0x500, rvolume);
}
static void
snd_pmac_burgundy_read_volume_2b(struct snd_pmac *chip, unsigned int address,
long *volume, int off)
{
volume[0] = snd_pmac_burgundy_rcb(chip, address + off);
if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
volume[0] -= BURGUNDY_VOLUME_OFFSET;
else
volume[0] = 0;
volume[1] = snd_pmac_burgundy_rcb(chip, address + off + 0x100);
if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
volume[1] -= BURGUNDY_VOLUME_OFFSET;
else
volume[1] = 0;
}
static int snd_pmac_burgundy_info_volume_2b(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 100;
return 0;
}
static int snd_pmac_burgundy_get_volume_2b(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
int off = kcontrol->private_value & 0x300;
snd_pmac_burgundy_read_volume_2b(chip, addr,
ucontrol->value.integer.value, off);
return 0;
}
static int snd_pmac_burgundy_put_volume_2b(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
int off = kcontrol->private_value & 0x300;
long nvoices[2];
snd_pmac_burgundy_write_volume_2b(chip, addr,
ucontrol->value.integer.value, off);
snd_pmac_burgundy_read_volume_2b(chip, addr, nvoices, off);
return (nvoices[0] != ucontrol->value.integer.value[0] ||
nvoices[1] != ucontrol->value.integer.value[1]);
}
#define BURGUNDY_VOLUME_2B(xname, xindex, addr, off) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
.info = snd_pmac_burgundy_info_volume_2b,\
.get = snd_pmac_burgundy_get_volume_2b,\
.put = snd_pmac_burgundy_put_volume_2b,\
.private_value = ((ADDR2BASE(addr) & 0xff) | ((off) << 8)) }
/*
* Burgundy gain/attenuation: 0 - 15, mono/stereo, byte reg
*/
static int snd_pmac_burgundy_info_gain(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
int stereo = (kcontrol->private_value >> 24) & 1;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = stereo + 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 15;
return 0;
}
static int snd_pmac_burgundy_get_gain(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
int stereo = (kcontrol->private_value >> 24) & 1;
int atten = (kcontrol->private_value >> 25) & 1;
int oval;
oval = snd_pmac_burgundy_rcb(chip, addr);
if (atten)
oval = ~oval & 0xff;
ucontrol->value.integer.value[0] = oval & 0xf;
if (stereo)
ucontrol->value.integer.value[1] = (oval >> 4) & 0xf;
return 0;
}
static int snd_pmac_burgundy_put_gain(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
int stereo = (kcontrol->private_value >> 24) & 1;
int atten = (kcontrol->private_value >> 25) & 1;
int oval, val;
oval = snd_pmac_burgundy_rcb(chip, addr);
if (atten)
oval = ~oval & 0xff;
val = ucontrol->value.integer.value[0];
if (stereo)
val |= ucontrol->value.integer.value[1] << 4;
else
val |= ucontrol->value.integer.value[0] << 4;
if (atten)
val = ~val & 0xff;
snd_pmac_burgundy_wcb(chip, addr, val);
return val != oval;
}
#define BURGUNDY_VOLUME_B(xname, xindex, addr, stereo, atten) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
.info = snd_pmac_burgundy_info_gain,\
.get = snd_pmac_burgundy_get_gain,\
.put = snd_pmac_burgundy_put_gain,\
.private_value = (ADDR2BASE(addr) | ((stereo) << 24) | ((atten) << 25)) }
/*
* Burgundy switch: 0/1, mono/stereo, word reg
*/
static int snd_pmac_burgundy_info_switch_w(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
int stereo = (kcontrol->private_value >> 24) & 1;
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = stereo + 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int snd_pmac_burgundy_get_switch_w(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
int lmask = 1 << (kcontrol->private_value & 0xff);
int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
int stereo = (kcontrol->private_value >> 24) & 1;
int val = snd_pmac_burgundy_rcw(chip, addr);
ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
if (stereo)
ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
return 0;
}
static int snd_pmac_burgundy_put_switch_w(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
int lmask = 1 << (kcontrol->private_value & 0xff);
int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
int stereo = (kcontrol->private_value >> 24) & 1;
int val, oval;
oval = snd_pmac_burgundy_rcw(chip, addr);
val = oval & ~(lmask | (stereo ? rmask : 0));
if (ucontrol->value.integer.value[0])
val |= lmask;
if (stereo && ucontrol->value.integer.value[1])
val |= rmask;
snd_pmac_burgundy_wcw(chip, addr, val);
return val != oval;
}
#define BURGUNDY_SWITCH_W(xname, xindex, addr, lbit, rbit, stereo) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
.info = snd_pmac_burgundy_info_switch_w,\
.get = snd_pmac_burgundy_get_switch_w,\
.put = snd_pmac_burgundy_put_switch_w,\
.private_value = ((lbit) | ((rbit) << 8)\
| (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
/*
* Burgundy switch: 0/1, mono/stereo, byte reg, bit mask
*/
static int snd_pmac_burgundy_info_switch_b(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
int stereo = (kcontrol->private_value >> 24) & 1;
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = stereo + 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int snd_pmac_burgundy_get_switch_b(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
int lmask = kcontrol->private_value & 0xff;
int rmask = (kcontrol->private_value >> 8) & 0xff;
int stereo = (kcontrol->private_value >> 24) & 1;
int val = snd_pmac_burgundy_rcb(chip, addr);
ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
if (stereo)
ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
return 0;
}
static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
int lmask = kcontrol->private_value & 0xff;
int rmask = (kcontrol->private_value >> 8) & 0xff;
int stereo = (kcontrol->private_value >> 24) & 1;
int val, oval;
oval = snd_pmac_burgundy_rcb(chip, addr);
val = oval & ~(lmask | rmask);
if (ucontrol->value.integer.value[0])
val |= lmask;
if (stereo && ucontrol->value.integer.value[1])
val |= rmask;
snd_pmac_burgundy_wcb(chip, addr, val);
return val != oval;
}
#define BURGUNDY_SWITCH_B(xname, xindex, addr, lmask, rmask, stereo) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
.info = snd_pmac_burgundy_info_switch_b,\
.get = snd_pmac_burgundy_get_switch_b,\
.put = snd_pmac_burgundy_put_switch_b,\
.private_value = ((lmask) | ((rmask) << 8)\
| (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
/*
* Burgundy mixers
*/
static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] = {
BURGUNDY_VOLUME_W("Master Playback Volume", 0,
MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
BURGUNDY_VOLUME_W("CD Capture Volume", 0,
MASK_ADDR_BURGUNDY_VOLCD, 16),
BURGUNDY_VOLUME_2B("Input Capture Volume", 0,
MASK_ADDR_BURGUNDY_VOLMIX01, 2),
BURGUNDY_VOLUME_2B("Mixer Playback Volume", 0,
MASK_ADDR_BURGUNDY_VOLMIX23, 0),
BURGUNDY_VOLUME_B("CD Gain Capture Volume", 0,
MASK_ADDR_BURGUNDY_GAINCD, 1, 0),
BURGUNDY_SWITCH_W("Master Capture Switch", 0,
MASK_ADDR_BURGUNDY_OUTPUTENABLES, 24, 0, 0),
BURGUNDY_SWITCH_W("CD Capture Switch", 0,
MASK_ADDR_BURGUNDY_CAPTURESELECTS, 0, 16, 1),
BURGUNDY_SWITCH_W("CD Playback Switch", 0,
MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 0, 16, 1),
/* BURGUNDY_SWITCH_W("Loop Capture Switch", 0,
* MASK_ADDR_BURGUNDY_CAPTURESELECTS, 8, 24, 1),
* BURGUNDY_SWITCH_B("Mixer out Capture Switch", 0,
* MASK_ADDR_BURGUNDY_HOSTIFAD, 0x02, 0, 0),
* BURGUNDY_SWITCH_B("Mixer Capture Switch", 0,
* MASK_ADDR_BURGUNDY_HOSTIFAD, 0x01, 0, 0),
* BURGUNDY_SWITCH_B("PCM out Capture Switch", 0,
* MASK_ADDR_BURGUNDY_HOSTIFEH, 0x02, 0, 0),
*/ BURGUNDY_SWITCH_B("PCM Capture Switch", 0,
MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0)
};
static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] = {
BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
MASK_ADDR_BURGUNDY_VOLLINE, 16),
BURGUNDY_VOLUME_W("Mic Capture Volume", 0,
MASK_ADDR_BURGUNDY_VOLMIC, 16),
BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
MASK_ADDR_BURGUNDY_GAINLINE, 1, 0),
BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0,
MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
BURGUNDY_VOLUME_B("Speaker Playback Volume", 0,
MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1),
BURGUNDY_VOLUME_B("Headphone Playback Volume", 0,
MASK_ADDR_BURGUNDY_ATTENHP, 1, 1),
BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
MASK_ADDR_BURGUNDY_CAPTURESELECTS, 1, 17, 1),
BURGUNDY_SWITCH_W("Mic Capture Switch", 0,
MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 1, 17, 1),
BURGUNDY_SWITCH_W("Mic Playback Switch", 0,
MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0,
MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1)
};
static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] = {
BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
MASK_ADDR_BURGUNDY_VOLMIC, 16),
BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
BURGUNDY_VOLUME_B("Speaker Playback Volume", 0,
MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1),
BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
/* BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0,
* MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */
};
static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac =
BURGUNDY_SWITCH_B("Master Playback Switch", 0,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT,
BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1);
static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac =
BURGUNDY_SWITCH_B("Master Playback Switch", 0,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
BURGUNDY_OUTPUT_INTERN
| BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac =
BURGUNDY_SWITCH_B("Speaker Playback Switch", 0,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac =
BURGUNDY_SWITCH_B("Speaker Playback Switch", 0,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
BURGUNDY_OUTPUT_INTERN, 0, 0);
static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac =
BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1);
static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac =
BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac =
BURGUNDY_SWITCH_B("Headphone Playback Switch", 0,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1);
#ifdef PMAC_SUPPORT_AUTOMUTE
/*
* auto-mute stuffs
*/
static int snd_pmac_burgundy_detect_headphone(struct snd_pmac *chip)
{
return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0;
}
static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify)
{
if (chip->auto_mute) {
int imac = of_machine_is_compatible("iMac");
int reg, oreg;
reg = oreg = snd_pmac_burgundy_rcb(chip,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
reg &= imac ? ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
| BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
: ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
| BURGUNDY_OUTPUT_INTERN);
if (snd_pmac_burgundy_detect_headphone(chip))
reg |= imac ? (BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
: (BURGUNDY_OUTPUT_LEFT
| BURGUNDY_OUTPUT_RIGHT);
else
reg |= imac ? (BURGUNDY_OUTPUT_LEFT
| BURGUNDY_OUTPUT_RIGHT)
: (BURGUNDY_OUTPUT_INTERN);
if (do_notify && reg == oreg)
return;
snd_pmac_burgundy_wcb(chip,
MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg);
if (do_notify) {
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_sw_ctl->id);
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->speaker_sw_ctl->id);
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->hp_detect_ctl->id);
}
}
}
#endif /* PMAC_SUPPORT_AUTOMUTE */
/*
* initialize burgundy
*/
int snd_pmac_burgundy_init(struct snd_pmac *chip)
{
int imac = of_machine_is_compatible("iMac");
int i, err;
/* Checks to see the chip is alive and kicking */
if ((in_le32(&chip->awacs->codec_ctrl) & MASK_ERRCODE) == 0xf0000) {
printk(KERN_WARNING "pmac burgundy: disabled by MacOS :-(\n");
return 1;
}
snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES,
DEF_BURGUNDY_OUTPUTENABLES);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
DEF_BURGUNDY_MORE_OUTPUTENABLES);
snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
DEF_BURGUNDY_OUTPUTSELECTS);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21,
DEF_BURGUNDY_INPSEL21);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3,
imac ? DEF_BURGUNDY_INPSEL3_IMAC
: DEF_BURGUNDY_INPSEL3_PMAC);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD,
DEF_BURGUNDY_GAINCD);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE,
DEF_BURGUNDY_GAINLINE);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMIC,
DEF_BURGUNDY_GAINMIC);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMODEM,
DEF_BURGUNDY_GAINMODEM);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENSPEAKER,
DEF_BURGUNDY_ATTENSPEAKER);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENLINEOUT,
DEF_BURGUNDY_ATTENLINEOUT);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENHP,
DEF_BURGUNDY_ATTENHP);
snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_MASTER_VOLUME,
DEF_BURGUNDY_MASTER_VOLUME);
snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLCD,
DEF_BURGUNDY_VOLCD);
snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLLINE,
DEF_BURGUNDY_VOLLINE);
snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC,
DEF_BURGUNDY_VOLMIC);
if (chip->hp_stat_mask == 0) {
/* set headphone-jack detection bit */
if (imac)
chip->hp_stat_mask = BURGUNDY_HPDETECT_IMAC_UPPER
| BURGUNDY_HPDETECT_IMAC_LOWER
| BURGUNDY_HPDETECT_IMAC_SIDE;
else
chip->hp_stat_mask = BURGUNDY_HPDETECT_PMAC_BACK;
}
/*
* build burgundy mixers
*/
strcpy(chip->card->mixername, "PowerMac Burgundy");
for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) {
err = snd_ctl_add(chip->card,
snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip));
if (err < 0)
return err;
}
for (i = 0; i < (imac ? ARRAY_SIZE(snd_pmac_burgundy_mixers_imac)
: ARRAY_SIZE(snd_pmac_burgundy_mixers_pmac)); i++) {
err = snd_ctl_add(chip->card,
snd_ctl_new1(imac ? &snd_pmac_burgundy_mixers_imac[i]
: &snd_pmac_burgundy_mixers_pmac[i], chip));
if (err < 0)
return err;
}
chip->master_sw_ctl = snd_ctl_new1(imac
? &snd_pmac_burgundy_master_sw_imac
: &snd_pmac_burgundy_master_sw_pmac, chip);
err = snd_ctl_add(chip->card, chip->master_sw_ctl);
if (err < 0)
return err;
chip->master_sw_ctl = snd_ctl_new1(imac
? &snd_pmac_burgundy_line_sw_imac
: &snd_pmac_burgundy_line_sw_pmac, chip);
err = snd_ctl_add(chip->card, chip->master_sw_ctl);
if (err < 0)
return err;
if (imac) {
chip->master_sw_ctl = snd_ctl_new1(
&snd_pmac_burgundy_hp_sw_imac, chip);
err = snd_ctl_add(chip->card, chip->master_sw_ctl);
if (err < 0)
return err;
}
chip->speaker_sw_ctl = snd_ctl_new1(imac
? &snd_pmac_burgundy_speaker_sw_imac
: &snd_pmac_burgundy_speaker_sw_pmac, chip);
err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
if (err < 0)
return err;
#ifdef PMAC_SUPPORT_AUTOMUTE
err = snd_pmac_add_automute(chip);
if (err < 0)
return err;
chip->detect_headphone = snd_pmac_burgundy_detect_headphone;
chip->update_automute = snd_pmac_burgundy_update_automute;
snd_pmac_burgundy_update_automute(chip, 0); /* update the status only */
#endif
return 0;
}

114
sound/ppc/burgundy.h Normal file
View file

@ -0,0 +1,114 @@
/*
* Driver for PowerMac Burgundy onboard soundchips
* Copyright (c) 2001 by Takashi Iwai <tiwai@suse.de>
* based on dmasound.c.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __BURGUNDY_H
#define __BURGUNDY_H
#define MASK_ADDR_BURGUNDY_INPBOOST (0x10 << 12)
#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12)
#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12)
#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12)
#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12)
#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12)
#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12)
#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12)
#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12)
#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12)
#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12)
#define MASK_ADDR_BURGUNDY_CAPTURESELECTS (0x2A << 12)
#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12)
#define MASK_ADDR_BURGUNDY_VOLMIX01 (0x2D << 12)
#define MASK_ADDR_BURGUNDY_VOLMIX23 (0x2E << 12)
#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12)
#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12)
#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12)
#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12)
#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12)
#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12)
#define MASK_ADDR_BURGUNDY_ATTENMONO (0x65 << 12)
#define MASK_ADDR_BURGUNDY_HOSTIFAD (0x78 << 12)
#define MASK_ADDR_BURGUNDY_HOSTIFEH (0x79 << 12)
#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1)
#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2)
#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3)
#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1)
#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2)
#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3)
#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
/* These are all default values for the burgundy */
#define DEF_BURGUNDY_INPSEL21 (0xAA)
#define DEF_BURGUNDY_INPSEL3_IMAC (0x0A)
#define DEF_BURGUNDY_INPSEL3_PMAC (0x05)
#define DEF_BURGUNDY_GAINCD (0x33)
#define DEF_BURGUNDY_GAINLINE (0x44)
#define DEF_BURGUNDY_GAINMIC (0x44)
#define DEF_BURGUNDY_GAINMODEM (0x06)
/* Remember: lowest volume here is 0x9B (155) */
#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC)
#define DEF_BURGUNDY_VOLLINE (0x00000000)
#define DEF_BURGUNDY_VOLMIC (0x00000000)
#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC)
#define DEF_BURGUNDY_OUTPUTSELECTS (0x010F010F)
#define DEF_BURGUNDY_OUTPUTENABLES (0x0100000A)
/* #define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) */ /* too loud */
#define DEF_BURGUNDY_MASTER_VOLUME (0xDDDDDDDD)
#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E)
#define DEF_BURGUNDY_ATTENSPEAKER (0x44)
#define DEF_BURGUNDY_ATTENLINEOUT (0xCC)
#define DEF_BURGUNDY_ATTENHP (0xCC)
/* MORE_OUTPUTENABLES bits */
#define BURGUNDY_OUTPUT_LEFT 0x02
#define BURGUNDY_OUTPUT_RIGHT 0x04
#define BURGUNDY_LINEOUT_LEFT 0x08
#define BURGUNDY_LINEOUT_RIGHT 0x10
#define BURGUNDY_HP_LEFT 0x20
#define BURGUNDY_HP_RIGHT 0x40
#define BURGUNDY_OUTPUT_INTERN 0x80
/* Headphone detection bits */
#define BURGUNDY_HPDETECT_PMAC_BACK 0x04
#define BURGUNDY_HPDETECT_IMAC_SIDE 0x04
#define BURGUNDY_HPDETECT_IMAC_UPPER 0x08
#define BURGUNDY_HPDETECT_IMAC_LOWER 0x01
/* Volume offset */
#define BURGUNDY_VOLUME_OFFSET 155
#endif /* __BURGUNDY_H */

282
sound/ppc/daca.c Normal file
View file

@ -0,0 +1,282 @@
/*
* PMac DACA lowlevel functions
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <sound/core.h>
#include "pmac.h"
/* i2c address */
#define DACA_I2C_ADDR 0x4d
/* registers */
#define DACA_REG_SR 0x01
#define DACA_REG_AVOL 0x02
#define DACA_REG_GCFG 0x03
/* maximum volume value */
#define DACA_VOL_MAX 0x38
struct pmac_daca {
struct pmac_keywest i2c;
int left_vol, right_vol;
unsigned int deemphasis : 1;
unsigned int amp_on : 1;
};
/*
* initialize / detect DACA
*/
static int daca_init_client(struct pmac_keywest *i2c)
{
unsigned short wdata = 0x00;
/* SR: no swap, 1bit delay, 32-48kHz */
/* GCFG: power amp inverted, DAC on */
if (i2c_smbus_write_byte_data(i2c->client, DACA_REG_SR, 0x08) < 0 ||
i2c_smbus_write_byte_data(i2c->client, DACA_REG_GCFG, 0x05) < 0)
return -EINVAL;
return i2c_smbus_write_block_data(i2c->client, DACA_REG_AVOL,
2, (unsigned char*)&wdata);
}
/*
* update volume
*/
static int daca_set_volume(struct pmac_daca *mix)
{
unsigned char data[2];
if (! mix->i2c.client)
return -ENODEV;
if (mix->left_vol > DACA_VOL_MAX)
data[0] = DACA_VOL_MAX;
else
data[0] = mix->left_vol;
if (mix->right_vol > DACA_VOL_MAX)
data[1] = DACA_VOL_MAX;
else
data[1] = mix->right_vol;
data[1] |= mix->deemphasis ? 0x40 : 0;
if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
2, data) < 0) {
snd_printk(KERN_ERR "failed to set volume \n");
return -EINVAL;
}
return 0;
}
/* deemphasis switch */
#define daca_info_deemphasis snd_ctl_boolean_mono_info
static int daca_get_deemphasis(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_daca *mix;
if (! (mix = chip->mixer_data))
return -ENODEV;
ucontrol->value.integer.value[0] = mix->deemphasis ? 1 : 0;
return 0;
}
static int daca_put_deemphasis(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_daca *mix;
int change;
if (! (mix = chip->mixer_data))
return -ENODEV;
change = mix->deemphasis != ucontrol->value.integer.value[0];
if (change) {
mix->deemphasis = !!ucontrol->value.integer.value[0];
daca_set_volume(mix);
}
return change;
}
/* output volume */
static int daca_info_volume(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = DACA_VOL_MAX;
return 0;
}
static int daca_get_volume(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_daca *mix;
if (! (mix = chip->mixer_data))
return -ENODEV;
ucontrol->value.integer.value[0] = mix->left_vol;
ucontrol->value.integer.value[1] = mix->right_vol;
return 0;
}
static int daca_put_volume(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_daca *mix;
unsigned int vol[2];
int change;
if (! (mix = chip->mixer_data))
return -ENODEV;
vol[0] = ucontrol->value.integer.value[0];
vol[1] = ucontrol->value.integer.value[1];
if (vol[0] > DACA_VOL_MAX || vol[1] > DACA_VOL_MAX)
return -EINVAL;
change = mix->left_vol != vol[0] ||
mix->right_vol != vol[1];
if (change) {
mix->left_vol = vol[0];
mix->right_vol = vol[1];
daca_set_volume(mix);
}
return change;
}
/* amplifier switch */
#define daca_info_amp daca_info_deemphasis
static int daca_get_amp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_daca *mix;
if (! (mix = chip->mixer_data))
return -ENODEV;
ucontrol->value.integer.value[0] = mix->amp_on ? 1 : 0;
return 0;
}
static int daca_put_amp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_daca *mix;
int change;
if (! (mix = chip->mixer_data))
return -ENODEV;
change = mix->amp_on != ucontrol->value.integer.value[0];
if (change) {
mix->amp_on = !!ucontrol->value.integer.value[0];
i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
mix->amp_on ? 0x05 : 0x04);
}
return change;
}
static struct snd_kcontrol_new daca_mixers[] = {
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Deemphasis Switch",
.info = daca_info_deemphasis,
.get = daca_get_deemphasis,
.put = daca_put_deemphasis
},
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Volume",
.info = daca_info_volume,
.get = daca_get_volume,
.put = daca_put_volume
},
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Power Amplifier Switch",
.info = daca_info_amp,
.get = daca_get_amp,
.put = daca_put_amp
},
};
#ifdef CONFIG_PM
static void daca_resume(struct snd_pmac *chip)
{
struct pmac_daca *mix = chip->mixer_data;
i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_SR, 0x08);
i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
mix->amp_on ? 0x05 : 0x04);
daca_set_volume(mix);
}
#endif /* CONFIG_PM */
static void daca_cleanup(struct snd_pmac *chip)
{
struct pmac_daca *mix = chip->mixer_data;
if (! mix)
return;
snd_pmac_keywest_cleanup(&mix->i2c);
kfree(mix);
chip->mixer_data = NULL;
}
/* exported */
int snd_pmac_daca_init(struct snd_pmac *chip)
{
int i, err;
struct pmac_daca *mix;
request_module("i2c-powermac");
mix = kzalloc(sizeof(*mix), GFP_KERNEL);
if (! mix)
return -ENOMEM;
chip->mixer_data = mix;
chip->mixer_free = daca_cleanup;
mix->amp_on = 1; /* default on */
mix->i2c.addr = DACA_I2C_ADDR;
mix->i2c.init_client = daca_init_client;
mix->i2c.name = "DACA";
if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0)
return err;
/*
* build mixers
*/
strcpy(chip->card->mixername, "PowerMac DACA");
for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) {
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip))) < 0)
return err;
}
#ifdef CONFIG_PM
chip->resume = daca_resume;
#endif
return 0;
}

147
sound/ppc/keywest.c Normal file
View file

@ -0,0 +1,147 @@
/*
* common keywest i2c layer
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <sound/core.h>
#include "pmac.h"
/*
* we have to keep a static variable here since i2c attach_adapter
* callback cannot pass a private data.
*/
static struct pmac_keywest *keywest_ctx;
static int keywest_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
i2c_set_clientdata(client, keywest_ctx);
return 0;
}
/*
* This is kind of a hack, best would be to turn powermac to fixed i2c
* bus numbers and declare the sound device as part of platform
* initialization
*/
static int keywest_attach_adapter(struct i2c_adapter *adapter)
{
struct i2c_board_info info;
if (! keywest_ctx)
return -EINVAL;
if (strncmp(adapter->name, "mac-io", 6))
return 0; /* ignored */
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "keywest", I2C_NAME_SIZE);
info.addr = keywest_ctx->addr;
keywest_ctx->client = i2c_new_device(adapter, &info);
if (!keywest_ctx->client)
return -ENODEV;
/*
* We know the driver is already loaded, so the device should be
* already bound. If not it means binding failed, and then there
* is no point in keeping the device instantiated.
*/
if (!keywest_ctx->client->dev.driver) {
i2c_unregister_device(keywest_ctx->client);
keywest_ctx->client = NULL;
return -ENODEV;
}
/*
* Let i2c-core delete that device on driver removal.
* This is safe because i2c-core holds the core_lock mutex for us.
*/
list_add_tail(&keywest_ctx->client->detected,
&to_i2c_driver(keywest_ctx->client->dev.driver)->clients);
return 0;
}
static int keywest_remove(struct i2c_client *client)
{
if (! keywest_ctx)
return 0;
if (client == keywest_ctx->client)
keywest_ctx->client = NULL;
return 0;
}
static const struct i2c_device_id keywest_i2c_id[] = {
{ "keywest", 0 },
{ }
};
static struct i2c_driver keywest_driver = {
.driver = {
.name = "PMac Keywest Audio",
},
.attach_adapter = keywest_attach_adapter,
.probe = keywest_probe,
.remove = keywest_remove,
.id_table = keywest_i2c_id,
};
/* exported */
void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c)
{
if (keywest_ctx && keywest_ctx == i2c) {
i2c_del_driver(&keywest_driver);
keywest_ctx = NULL;
}
}
int snd_pmac_tumbler_post_init(void)
{
int err;
if (!keywest_ctx || !keywest_ctx->client)
return -ENXIO;
if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) {
snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err);
return err;
}
return 0;
}
/* exported */
int snd_pmac_keywest_init(struct pmac_keywest *i2c)
{
int err;
if (keywest_ctx)
return -EBUSY;
keywest_ctx = i2c;
if ((err = i2c_add_driver(&keywest_driver))) {
snd_printk(KERN_ERR "cannot register keywest i2c driver\n");
return err;
}
return 0;
}

1412
sound/ppc/pmac.c Normal file

File diff suppressed because it is too large Load diff

210
sound/ppc/pmac.h Normal file
View file

@ -0,0 +1,210 @@
/*
* Driver for PowerMac onboard soundchips
* Copyright (c) 2001 by Takashi Iwai <tiwai@suse.de>
* based on dmasound.c.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __PMAC_H
#define __PMAC_H
#include <sound/control.h>
#include <sound/pcm.h>
#include "awacs.h"
#include <linux/adb.h>
#ifdef CONFIG_ADB_CUDA
#include <linux/cuda.h>
#endif
#ifdef CONFIG_ADB_PMU
#include <linux/pmu.h>
#endif
#include <linux/nvram.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
#include <asm/dbdma.h>
#include <asm/prom.h>
#include <asm/machdep.h>
/* maximum number of fragments */
#define PMAC_MAX_FRAGS 32
#define PMAC_SUPPORT_AUTOMUTE
/*
* DBDMA space
*/
struct pmac_dbdma {
dma_addr_t dma_base;
dma_addr_t addr;
struct dbdma_cmd __iomem *cmds;
void *space;
int size;
};
/*
* playback/capture stream
*/
struct pmac_stream {
int running; /* boolean */
int stream; /* PLAYBACK/CAPTURE */
int dma_size; /* in bytes */
int period_size; /* in bytes */
int buffer_size; /* in kbytes */
int nperiods, cur_period;
struct pmac_dbdma cmd;
volatile struct dbdma_regs __iomem *dma;
struct snd_pcm_substream *substream;
unsigned int cur_freqs; /* currently available frequencies */
unsigned int cur_formats; /* currently available formats */
};
/*
*/
enum snd_pmac_model {
PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER,
PMAC_SNAPPER
};
struct snd_pmac {
struct snd_card *card;
/* h/w info */
struct device_node *node;
struct pci_dev *pdev;
unsigned int revision;
unsigned int manufacturer;
unsigned int subframe;
unsigned int device_id;
enum snd_pmac_model model;
unsigned int has_iic : 1;
unsigned int is_pbook_3400 : 1;
unsigned int is_pbook_G3 : 1;
unsigned int is_k2 : 1;
unsigned int can_byte_swap : 1;
unsigned int can_duplex : 1;
unsigned int can_capture : 1;
unsigned int auto_mute : 1;
unsigned int initialized : 1;
unsigned int feature_is_set : 1;
unsigned int requested;
struct resource rsrc[3];
int num_freqs;
int *freq_table;
unsigned int freqs_ok; /* bit flags */
unsigned int formats_ok; /* pcm hwinfo */
int active;
int rate_index;
int format; /* current format */
spinlock_t reg_lock;
volatile struct awacs_regs __iomem *awacs;
int awacs_reg[8]; /* register cache */
unsigned int hp_stat_mask;
unsigned char __iomem *latch_base;
unsigned char __iomem *macio_base;
struct pmac_stream playback;
struct pmac_stream capture;
struct pmac_dbdma extra_dma;
int irq, tx_irq, rx_irq;
struct snd_pcm *pcm;
struct pmac_beep *beep;
unsigned int control_mask; /* control mask */
/* mixer stuffs */
void *mixer_data;
void (*mixer_free)(struct snd_pmac *);
struct snd_kcontrol *master_sw_ctl;
struct snd_kcontrol *speaker_sw_ctl;
struct snd_kcontrol *drc_sw_ctl; /* only used for tumbler -ReneR */
struct snd_kcontrol *hp_detect_ctl;
struct snd_kcontrol *lineout_sw_ctl;
/* lowlevel callbacks */
void (*set_format)(struct snd_pmac *chip);
void (*update_automute)(struct snd_pmac *chip, int do_notify);
int (*detect_headphone)(struct snd_pmac *chip);
#ifdef CONFIG_PM
void (*suspend)(struct snd_pmac *chip);
void (*resume)(struct snd_pmac *chip);
#endif
};
/* exported functions */
int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return);
int snd_pmac_pcm_new(struct snd_pmac *chip);
int snd_pmac_attach_beep(struct snd_pmac *chip);
void snd_pmac_detach_beep(struct snd_pmac *chip);
void snd_pmac_beep_stop(struct snd_pmac *chip);
unsigned int snd_pmac_rate_index(struct snd_pmac *chip, struct pmac_stream *rec, unsigned int rate);
void snd_pmac_beep_dma_start(struct snd_pmac *chip, int bytes, unsigned long addr, int speed);
void snd_pmac_beep_dma_stop(struct snd_pmac *chip);
#ifdef CONFIG_PM
void snd_pmac_suspend(struct snd_pmac *chip);
void snd_pmac_resume(struct snd_pmac *chip);
#endif
/* initialize mixer */
int snd_pmac_awacs_init(struct snd_pmac *chip);
int snd_pmac_burgundy_init(struct snd_pmac *chip);
int snd_pmac_daca_init(struct snd_pmac *chip);
int snd_pmac_tumbler_init(struct snd_pmac *chip);
int snd_pmac_tumbler_post_init(void);
/* i2c functions */
struct pmac_keywest {
int addr;
struct i2c_client *client;
int id;
int (*init_client)(struct pmac_keywest *i2c);
char *name;
};
int snd_pmac_keywest_init(struct pmac_keywest *i2c);
void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c);
/* misc */
#define snd_pmac_boolean_stereo_info snd_ctl_boolean_stereo_info
#define snd_pmac_boolean_mono_info snd_ctl_boolean_mono_info
int snd_pmac_add_automute(struct snd_pmac *chip);
#endif /* __PMAC_H */

195
sound/ppc/powermac.c Normal file
View file

@ -0,0 +1,195 @@
/*
* Driver for PowerMac AWACS
* Copyright (c) 2001 by Takashi Iwai <tiwai@suse.de>
* based on dmasound.c.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
#include "pmac.h"
#include "awacs.h"
#include "burgundy.h"
#define CHIP_NAME "PMac"
MODULE_DESCRIPTION("PowerMac");
MODULE_SUPPORTED_DEVICE("{{Apple,PowerMac}}");
MODULE_LICENSE("GPL");
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
static bool enable_beep = 1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for " CHIP_NAME " soundchip.");
module_param(id, charp, 0444);
MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip.");
module_param(enable_beep, bool, 0444);
MODULE_PARM_DESC(enable_beep, "Enable beep using PCM.");
static struct platform_device *device;
/*
*/
static int snd_pmac_probe(struct platform_device *devptr)
{
struct snd_card *card;
struct snd_pmac *chip;
char *name_ext;
int err;
err = snd_card_new(&devptr->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
if ((err = snd_pmac_new(card, &chip)) < 0)
goto __error;
card->private_data = chip;
switch (chip->model) {
case PMAC_BURGUNDY:
strcpy(card->driver, "PMac Burgundy");
strcpy(card->shortname, "PowerMac Burgundy");
sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
card->shortname, chip->device_id, chip->subframe);
if ((err = snd_pmac_burgundy_init(chip)) < 0)
goto __error;
break;
case PMAC_DACA:
strcpy(card->driver, "PMac DACA");
strcpy(card->shortname, "PowerMac DACA");
sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
card->shortname, chip->device_id, chip->subframe);
if ((err = snd_pmac_daca_init(chip)) < 0)
goto __error;
break;
case PMAC_TUMBLER:
case PMAC_SNAPPER:
name_ext = chip->model == PMAC_TUMBLER ? "Tumbler" : "Snapper";
sprintf(card->driver, "PMac %s", name_ext);
sprintf(card->shortname, "PowerMac %s", name_ext);
sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
card->shortname, chip->device_id, chip->subframe);
if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0)
goto __error;
break;
case PMAC_AWACS:
case PMAC_SCREAMER:
name_ext = chip->model == PMAC_SCREAMER ? "Screamer" : "AWACS";
sprintf(card->driver, "PMac %s", name_ext);
sprintf(card->shortname, "PowerMac %s", name_ext);
if (chip->is_pbook_3400)
name_ext = " [PB3400]";
else if (chip->is_pbook_G3)
name_ext = " [PBG3]";
else
name_ext = "";
sprintf(card->longname, "%s%s Rev %d",
card->shortname, name_ext, chip->revision);
if ((err = snd_pmac_awacs_init(chip)) < 0)
goto __error;
break;
default:
snd_printk(KERN_ERR "unsupported hardware %d\n", chip->model);
err = -EINVAL;
goto __error;
}
if ((err = snd_pmac_pcm_new(chip)) < 0)
goto __error;
chip->initialized = 1;
if (enable_beep)
snd_pmac_attach_beep(chip);
if ((err = snd_card_register(card)) < 0)
goto __error;
platform_set_drvdata(devptr, card);
return 0;
__error:
snd_card_free(card);
return err;
}
static int snd_pmac_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int snd_pmac_driver_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
snd_pmac_suspend(card->private_data);
return 0;
}
static int snd_pmac_driver_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
snd_pmac_resume(card->private_data);
return 0;
}
static SIMPLE_DEV_PM_OPS(snd_pmac_pm, snd_pmac_driver_suspend, snd_pmac_driver_resume);
#define SND_PMAC_PM_OPS &snd_pmac_pm
#else
#define SND_PMAC_PM_OPS NULL
#endif
#define SND_PMAC_DRIVER "snd_powermac"
static struct platform_driver snd_pmac_driver = {
.probe = snd_pmac_probe,
.remove = snd_pmac_remove,
.driver = {
.name = SND_PMAC_DRIVER,
.owner = THIS_MODULE,
.pm = SND_PMAC_PM_OPS,
},
};
static int __init alsa_card_pmac_init(void)
{
int err;
if ((err = platform_driver_register(&snd_pmac_driver)) < 0)
return err;
device = platform_device_register_simple(SND_PMAC_DRIVER, -1, NULL, 0);
return 0;
}
static void __exit alsa_card_pmac_exit(void)
{
if (!IS_ERR(device))
platform_device_unregister(device);
platform_driver_unregister(&snd_pmac_driver);
}
module_init(alsa_card_pmac_init)
module_exit(alsa_card_pmac_exit)

1163
sound/ppc/snd_ps3.c Normal file

File diff suppressed because it is too large Load diff

136
sound/ppc/snd_ps3.h Normal file
View file

@ -0,0 +1,136 @@
/*
* Audio support for PS3
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* All rights reserved.
* Copyright 2006, 2007 Sony Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 of the Licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined(_SND_PS3_H_)
#define _SND_PS3_H_
#include <linux/irqreturn.h>
#define SND_PS3_DRIVER_NAME "snd_ps3"
enum snd_ps3_out_channel {
SND_PS3_OUT_SPDIF_0,
SND_PS3_OUT_SPDIF_1,
SND_PS3_OUT_SERIAL_0,
SND_PS3_OUT_DEVS
};
enum snd_ps3_dma_filltype {
SND_PS3_DMA_FILLTYPE_FIRSTFILL,
SND_PS3_DMA_FILLTYPE_RUNNING,
SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL,
SND_PS3_DMA_FILLTYPE_SILENT_RUNNING
};
enum snd_ps3_ch {
SND_PS3_CH_L = 0,
SND_PS3_CH_R = 1,
SND_PS3_CH_MAX = 2
};
struct snd_ps3_avsetting_info {
uint32_t avs_audio_ch; /* fixed */
uint32_t avs_audio_rate;
uint32_t avs_audio_width;
uint32_t avs_audio_format; /* fixed */
uint32_t avs_audio_source; /* fixed */
unsigned char avs_cs_info[8];
};
/*
* PS3 audio 'card' instance
* there should be only ONE hardware.
*/
struct snd_ps3_card_info {
struct ps3_system_bus_device *ps3_dev;
struct snd_card *card;
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
/* hvc info */
u64 audio_lpar_addr;
u64 audio_lpar_size;
/* registers */
void __iomem *mapped_mmio_vaddr;
/* irq */
u64 audio_irq_outlet;
unsigned int irq_no;
/* remember avsetting */
struct snd_ps3_avsetting_info avs;
/* dma buffer management */
spinlock_t dma_lock;
/* dma_lock start */
void * dma_start_vaddr[2]; /* 0 for L, 1 for R */
dma_addr_t dma_start_bus_addr[2];
size_t dma_buffer_size;
void * dma_last_transfer_vaddr[2];
void * dma_next_transfer_vaddr[2];
int silent;
/* dma_lock end */
int running;
/* null buffer */
void *null_buffer_start_vaddr;
dma_addr_t null_buffer_start_dma_addr;
/* start delay */
unsigned int start_delay;
};
/* PS3 audio DMAC block size in bytes */
#define PS3_AUDIO_DMAC_BLOCK_SIZE (128)
/* one stage (stereo) of audio FIFO in bytes */
#define PS3_AUDIO_FIFO_STAGE_SIZE (256)
/* how many stages the fifo have */
#define PS3_AUDIO_FIFO_STAGE_COUNT (8)
/* fifo size 128 bytes * 8 stages * stereo (2ch) */
#define PS3_AUDIO_FIFO_SIZE \
(PS3_AUDIO_FIFO_STAGE_SIZE * PS3_AUDIO_FIFO_STAGE_COUNT)
/* PS3 audio DMAC max block count in one dma shot = 128 (0x80) blocks*/
#define PS3_AUDIO_DMAC_MAX_BLOCKS (PS3_AUDIO_DMASIZE_BLOCKS_MASK + 1)
#define PS3_AUDIO_NORMAL_DMA_START_CH (0)
#define PS3_AUDIO_NORMAL_DMA_COUNT (8)
#define PS3_AUDIO_NULL_DMA_START_CH \
(PS3_AUDIO_NORMAL_DMA_START_CH + PS3_AUDIO_NORMAL_DMA_COUNT)
#define PS3_AUDIO_NULL_DMA_COUNT (2)
#define SND_PS3_MAX_VOL (0x0F)
#define SND_PS3_MIN_VOL (0x00)
#define SND_PS3_MIN_ATT SND_PS3_MIN_VOL
#define SND_PS3_MAX_ATT SND_PS3_MAX_VOL
#define SND_PS3_PCM_PREALLOC_SIZE \
(PS3_AUDIO_DMAC_BLOCK_SIZE * PS3_AUDIO_DMAC_MAX_BLOCKS * 4)
#define SND_PS3_DMA_REGION_SIZE \
(SND_PS3_PCM_PREALLOC_SIZE + PAGE_SIZE)
#define PS3_AUDIO_IOID (1UL)
#endif /* _SND_PS3_H_ */

891
sound/ppc/snd_ps3_reg.h Normal file
View file

@ -0,0 +1,891 @@
/*
* Audio support for PS3
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* Copyright 2006, 2007 Sony Corporation
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* interrupt / configure registers
*/
#define PS3_AUDIO_INTR_0 (0x00000100)
#define PS3_AUDIO_INTR_EN_0 (0x00000140)
#define PS3_AUDIO_CONFIG (0x00000200)
/*
* DMAC registers
* n:0..9
*/
#define PS3_AUDIO_DMAC_REGBASE(x) (0x0000210 + 0x20 * (x))
#define PS3_AUDIO_KICK(n) (PS3_AUDIO_DMAC_REGBASE(n) + 0x00)
#define PS3_AUDIO_SOURCE(n) (PS3_AUDIO_DMAC_REGBASE(n) + 0x04)
#define PS3_AUDIO_DEST(n) (PS3_AUDIO_DMAC_REGBASE(n) + 0x08)
#define PS3_AUDIO_DMASIZE(n) (PS3_AUDIO_DMAC_REGBASE(n) + 0x0C)
/*
* mute control
*/
#define PS3_AUDIO_AX_MCTRL (0x00004000)
#define PS3_AUDIO_AX_ISBP (0x00004004)
#define PS3_AUDIO_AX_AOBP (0x00004008)
#define PS3_AUDIO_AX_IC (0x00004010)
#define PS3_AUDIO_AX_IE (0x00004014)
#define PS3_AUDIO_AX_IS (0x00004018)
/*
* three wire serial
* n:0..3
*/
#define PS3_AUDIO_AO_MCTRL (0x00006000)
#define PS3_AUDIO_AO_3WMCTRL (0x00006004)
#define PS3_AUDIO_AO_3WCTRL(n) (0x00006200 + 0x200 * (n))
/*
* S/PDIF
* n:0..1
* x:0..11
* y:0..5
*/
#define PS3_AUDIO_AO_SPD_REGBASE(n) (0x00007200 + 0x200 * (n))
#define PS3_AUDIO_AO_SPDCTRL(n) \
(PS3_AUDIO_AO_SPD_REGBASE(n) + 0x00)
#define PS3_AUDIO_AO_SPDUB(n, x) \
(PS3_AUDIO_AO_SPD_REGBASE(n) + 0x04 + 0x04 * (x))
#define PS3_AUDIO_AO_SPDCS(n, y) \
(PS3_AUDIO_AO_SPD_REGBASE(n) + 0x34 + 0x04 * (y))
/*
PS3_AUDIO_INTR_0 register tells an interrupt handler which audio
DMA channel triggered the interrupt. The interrupt status for a channel
can be cleared by writing a '1' to the corresponding bit. A new interrupt
cannot be generated until the previous interrupt has been cleared.
Note that the status reported by PS3_AUDIO_INTR_0 is independent of the
value of PS3_AUDIO_INTR_EN_0.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
#define PS3_AUDIO_INTR_0_CHAN(n) (1 << ((n) * 2))
#define PS3_AUDIO_INTR_0_CHAN9 PS3_AUDIO_INTR_0_CHAN(9)
#define PS3_AUDIO_INTR_0_CHAN8 PS3_AUDIO_INTR_0_CHAN(8)
#define PS3_AUDIO_INTR_0_CHAN7 PS3_AUDIO_INTR_0_CHAN(7)
#define PS3_AUDIO_INTR_0_CHAN6 PS3_AUDIO_INTR_0_CHAN(6)
#define PS3_AUDIO_INTR_0_CHAN5 PS3_AUDIO_INTR_0_CHAN(5)
#define PS3_AUDIO_INTR_0_CHAN4 PS3_AUDIO_INTR_0_CHAN(4)
#define PS3_AUDIO_INTR_0_CHAN3 PS3_AUDIO_INTR_0_CHAN(3)
#define PS3_AUDIO_INTR_0_CHAN2 PS3_AUDIO_INTR_0_CHAN(2)
#define PS3_AUDIO_INTR_0_CHAN1 PS3_AUDIO_INTR_0_CHAN(1)
#define PS3_AUDIO_INTR_0_CHAN0 PS3_AUDIO_INTR_0_CHAN(0)
/*
The PS3_AUDIO_INTR_EN_0 register specifies which DMA channels can generate
an interrupt to the PU. Each bit of PS3_AUDIO_INTR_EN_0 is ANDed with the
corresponding bit in PS3_AUDIO_INTR_0. The resulting bits are OR'd together
to generate the Audio interrupt.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_EN_0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
Bit assignments are same as PS3_AUDIO_INTR_0
*/
/*
PS3_AUDIO_CONFIG
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 C|0 0 0 0 0 0 0 0| CONFIG
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/* The CLEAR field cancels all pending transfers, and stops any running DMA
transfers. Any interrupts associated with the canceled transfers
will occur as if the transfer had finished.
Since this bit is designed to recover from DMA related issues
which are caused by unpredictable situations, it is preferred to wait
for normal DMA transfer end without using this bit.
*/
#define PS3_AUDIO_CONFIG_CLEAR (1 << 8) /* RWIVF */
/*
PS3_AUDIO_AX_MCTRL: Audio Port Mute Control Register
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|A|A|0 0 0 0 0 0 0|S|S|A|A|A|A| AX_MCTRL
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/* 3 Wire Audio Serial Output Channel Mutes (0..3) */
#define PS3_AUDIO_AX_MCTRL_ASOMT(n) (1 << (3 - (n))) /* RWIVF */
#define PS3_AUDIO_AX_MCTRL_ASO3MT (1 << 0) /* RWIVF */
#define PS3_AUDIO_AX_MCTRL_ASO2MT (1 << 1) /* RWIVF */
#define PS3_AUDIO_AX_MCTRL_ASO1MT (1 << 2) /* RWIVF */
#define PS3_AUDIO_AX_MCTRL_ASO0MT (1 << 3) /* RWIVF */
/* S/PDIF mutes (0,1)*/
#define PS3_AUDIO_AX_MCTRL_SPOMT(n) (1 << (5 - (n))) /* RWIVF */
#define PS3_AUDIO_AX_MCTRL_SPO1MT (1 << 4) /* RWIVF */
#define PS3_AUDIO_AX_MCTRL_SPO0MT (1 << 5) /* RWIVF */
/* All 3 Wire Serial Outputs Mute */
#define PS3_AUDIO_AX_MCTRL_AASOMT (1 << 13) /* RWIVF */
/* All S/PDIF Mute */
#define PS3_AUDIO_AX_MCTRL_ASPOMT (1 << 14) /* RWIVF */
/* All Audio Outputs Mute */
#define PS3_AUDIO_AX_MCTRL_AAOMT (1 << 15) /* RWIVF */
/*
S/PDIF Outputs Buffer Read/Write Pointer Register
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B|0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B| AX_ISBP
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
S/PDIF Output Channel Read Buffer Numbers
Buffer number is value of field.
Indicates current read access buffer ID from Audio Data
Transfer controller of S/PDIF Output
*/
#define PS3_AUDIO_AX_ISBP_SPOBRN_MASK(n) (0x7 << 4 * (1 - (n))) /* R-IUF */
#define PS3_AUDIO_AX_ISBP_SPO1BRN_MASK (0x7 << 0) /* R-IUF */
#define PS3_AUDIO_AX_ISBP_SPO0BRN_MASK (0x7 << 4) /* R-IUF */
/*
S/PDIF Output Channel Buffer Write Numbers
Indicates current write access buffer ID from bus master.
*/
#define PS3_AUDIO_AX_ISBP_SPOBWN_MASK(n) (0x7 << 4 * (5 - (n))) /* R-IUF */
#define PS3_AUDIO_AX_ISBP_SPO1BWN_MASK (0x7 << 16) /* R-IUF */
#define PS3_AUDIO_AX_ISBP_SPO0BWN_MASK (0x7 << 20) /* R-IUF */
/*
3 Wire Audio Serial Outputs Buffer Read/Write
Pointer Register
Buffer number is value of field
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B|0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B| AX_AOBP
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
3 Wire Audio Serial Output Channel Buffer Read Numbers
Indicates current read access buffer Id from Audio Data Transfer
Controller of 3 Wire Audio Serial Output Channels
*/
#define PS3_AUDIO_AX_AOBP_ASOBRN_MASK(n) (0x7 << 4 * (3 - (n))) /* R-IUF */
#define PS3_AUDIO_AX_AOBP_ASO3BRN_MASK (0x7 << 0) /* R-IUF */
#define PS3_AUDIO_AX_AOBP_ASO2BRN_MASK (0x7 << 4) /* R-IUF */
#define PS3_AUDIO_AX_AOBP_ASO1BRN_MASK (0x7 << 8) /* R-IUF */
#define PS3_AUDIO_AX_AOBP_ASO0BRN_MASK (0x7 << 12) /* R-IUF */
/*
3 Wire Audio Serial Output Channel Buffer Write Numbers
Indicates current write access buffer ID from bus master.
*/
#define PS3_AUDIO_AX_AOBP_ASOBWN_MASK(n) (0x7 << 4 * (7 - (n))) /* R-IUF */
#define PS3_AUDIO_AX_AOBP_ASO3BWN_MASK (0x7 << 16) /* R-IUF */
#define PS3_AUDIO_AX_AOBP_ASO2BWN_MASK (0x7 << 20) /* R-IUF */
#define PS3_AUDIO_AX_AOBP_ASO1BWN_MASK (0x7 << 24) /* R-IUF */
#define PS3_AUDIO_AX_AOBP_ASO0BWN_MASK (0x7 << 28) /* R-IUF */
/*
Audio Port Interrupt Condition Register
For the fields in this register, the following values apply:
0 = Interrupt is generated every interrupt event.
1 = Interrupt is generated every 2 interrupt events.
2 = Interrupt is generated every 4 interrupt events.
3 = Reserved
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0|0 0|SPO|0 0|SPO|0 0|AAS|0 0 0 0 0 0 0 0 0 0 0 0| AX_IC
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
All 3-Wire Audio Serial Outputs Interrupt Mode
Configures the Interrupt and Signal Notification
condition of all 3-wire Audio Serial Outputs.
*/
#define PS3_AUDIO_AX_IC_AASOIMD_MASK (0x3 << 12) /* RWIVF */
#define PS3_AUDIO_AX_IC_AASOIMD_EVERY1 (0x0 << 12) /* RWI-V */
#define PS3_AUDIO_AX_IC_AASOIMD_EVERY2 (0x1 << 12) /* RW--V */
#define PS3_AUDIO_AX_IC_AASOIMD_EVERY4 (0x2 << 12) /* RW--V */
/*
S/PDIF Output Channel Interrupt Modes
Configures the Interrupt and signal Notification
conditions of S/PDIF output channels.
*/
#define PS3_AUDIO_AX_IC_SPO1IMD_MASK (0x3 << 16) /* RWIVF */
#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY1 (0x0 << 16) /* RWI-V */
#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY2 (0x1 << 16) /* RW--V */
#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY4 (0x2 << 16) /* RW--V */
#define PS3_AUDIO_AX_IC_SPO0IMD_MASK (0x3 << 20) /* RWIVF */
#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY1 (0x0 << 20) /* RWI-V */
#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY2 (0x1 << 20) /* RW--V */
#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY4 (0x2 << 20) /* RW--V */
/*
Audio Port interrupt Enable Register
Configures whether to enable or disable each Interrupt Generation.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IE
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
3 Wire Audio Serial Output Channel Buffer Underflow
Interrupt Enables
Select enable/disable of Buffer Underflow Interrupts for
3-Wire Audio Serial Output Channels
DISABLED=Interrupt generation disabled.
*/
#define PS3_AUDIO_AX_IE_ASOBUIE(n) (1 << (3 - (n))) /* RWIVF */
#define PS3_AUDIO_AX_IE_ASO3BUIE (1 << 0) /* RWIVF */
#define PS3_AUDIO_AX_IE_ASO2BUIE (1 << 1) /* RWIVF */
#define PS3_AUDIO_AX_IE_ASO1BUIE (1 << 2) /* RWIVF */
#define PS3_AUDIO_AX_IE_ASO0BUIE (1 << 3) /* RWIVF */
/* S/PDIF Output Channel Buffer Underflow Interrupt Enables */
#define PS3_AUDIO_AX_IE_SPOBUIE(n) (1 << (7 - (n))) /* RWIVF */
#define PS3_AUDIO_AX_IE_SPO1BUIE (1 << 6) /* RWIVF */
#define PS3_AUDIO_AX_IE_SPO0BUIE (1 << 7) /* RWIVF */
/* S/PDIF Output Channel One Block Transfer Completion Interrupt Enables */
#define PS3_AUDIO_AX_IE_SPOBTCIE(n) (1 << (11 - (n))) /* RWIVF */
#define PS3_AUDIO_AX_IE_SPO1BTCIE (1 << 10) /* RWIVF */
#define PS3_AUDIO_AX_IE_SPO0BTCIE (1 << 11) /* RWIVF */
/* 3-Wire Audio Serial Output Channel Buffer Empty Interrupt Enables */
#define PS3_AUDIO_AX_IE_ASOBEIE(n) (1 << (19 - (n))) /* RWIVF */
#define PS3_AUDIO_AX_IE_ASO3BEIE (1 << 16) /* RWIVF */
#define PS3_AUDIO_AX_IE_ASO2BEIE (1 << 17) /* RWIVF */
#define PS3_AUDIO_AX_IE_ASO1BEIE (1 << 18) /* RWIVF */
#define PS3_AUDIO_AX_IE_ASO0BEIE (1 << 19) /* RWIVF */
/* S/PDIF Output Channel Buffer Empty Interrupt Enables */
#define PS3_AUDIO_AX_IE_SPOBEIE(n) (1 << (23 - (n))) /* RWIVF */
#define PS3_AUDIO_AX_IE_SPO1BEIE (1 << 22) /* RWIVF */
#define PS3_AUDIO_AX_IE_SPO0BEIE (1 << 23) /* RWIVF */
/*
Audio Port Interrupt Status Register
Indicates Interrupt status, which interrupt has occurred, and can clear
each interrupt in this register.
Writing 1b to a field containing 1b clears field and de-asserts interrupt.
Writing 0b to a field has no effect.
Field vaules are the following:
0 - Interrupt hasn't occurred.
1 - Interrupt has occurred.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IS
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
Bit assignment are same as AX_IE
*/
/*
Audio Output Master Control Register
Configures Master Clock and other master Audio Output Settings
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0|SCKSE|0|SCKSE| MR0 | MR1 |MCL|MCL|0 0 0 0|0 0 0 0 0 0 0 0| AO_MCTRL
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
MCLK Output Control
Controls mclko[1] output.
0 - Disable output (fixed at High)
1 - Output clock produced by clock selected
with scksel1 by mr1
2 - Reserved
3 - Reserved
*/
#define PS3_AUDIO_AO_MCTRL_MCLKC1_MASK (0x3 << 12) /* RWIVF */
#define PS3_AUDIO_AO_MCTRL_MCLKC1_DISABLED (0x0 << 12) /* RWI-V */
#define PS3_AUDIO_AO_MCTRL_MCLKC1_ENABLED (0x1 << 12) /* RW--V */
#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD2 (0x2 << 12) /* RW--V */
#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD3 (0x3 << 12) /* RW--V */
/*
MCLK Output Control
Controls mclko[0] output.
0 - Disable output (fixed at High)
1 - Output clock produced by clock selected
with SCKSEL0 by MR0
2 - Reserved
3 - Reserved
*/
#define PS3_AUDIO_AO_MCTRL_MCLKC0_MASK (0x3 << 14) /* RWIVF */
#define PS3_AUDIO_AO_MCTRL_MCLKC0_DISABLED (0x0 << 14) /* RWI-V */
#define PS3_AUDIO_AO_MCTRL_MCLKC0_ENABLED (0x1 << 14) /* RW--V */
#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD2 (0x2 << 14) /* RW--V */
#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD3 (0x3 << 14) /* RW--V */
/*
Master Clock Rate 1
Sets the divide ration of Master Clock1 (clock output from
mclko[1] for the input clock selected by scksel1.
*/
#define PS3_AUDIO_AO_MCTRL_MR1_MASK (0xf << 16)
#define PS3_AUDIO_AO_MCTRL_MR1_DEFAULT (0x0 << 16) /* RWI-V */
/*
Master Clock Rate 0
Sets the divide ratio of Master Clock0 (clock output from
mclko[0] for the input clock selected by scksel0).
*/
#define PS3_AUDIO_AO_MCTRL_MR0_MASK (0xf << 20) /* RWIVF */
#define PS3_AUDIO_AO_MCTRL_MR0_DEFAULT (0x0 << 20) /* RWI-V */
/*
System Clock Select 0/1
Selects the system clock to be used as Master Clock 0/1
Input the system clock that is appropriate for the sampling
rate.
*/
#define PS3_AUDIO_AO_MCTRL_SCKSEL1_MASK (0x7 << 24) /* RWIVF */
#define PS3_AUDIO_AO_MCTRL_SCKSEL1_DEFAULT (0x2 << 24) /* RWI-V */
#define PS3_AUDIO_AO_MCTRL_SCKSEL0_MASK (0x7 << 28) /* RWIVF */
#define PS3_AUDIO_AO_MCTRL_SCKSEL0_DEFAULT (0x2 << 28) /* RWI-V */
/*
3-Wire Audio Output Master Control Register
Configures clock, 3-Wire Audio Serial Output Enable, and
other 3-Wire Audio Serial Output Master Settings
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|A|A|A|A|0 0 0|A| ASOSR |0 0 0 0|A|A|A|A|A|A|0|1|0 0 0 0 0 0 0 0| AO_3WMCTRL
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
LRCKO Polarity
0 - Reserved
1 - default
*/
#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK (1 << 8) /* RWIVF */
#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT (1 << 8) /* RW--V */
/* LRCK Output Disable */
#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD (1 << 10) /* RWIVF */
#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_ENABLED (0 << 10) /* RW--V */
#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED (1 << 10) /* RWI-V */
/* Bit Clock Output Disable */
#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD (1 << 11) /* RWIVF */
#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_ENABLED (0 << 11) /* RW--V */
#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED (1 << 11) /* RWI-V */
/*
3-Wire Audio Serial Output Channel 0-3 Operational
Status. Each bit becomes 1 after each 3-Wire Audio
Serial Output Channel N is in action by setting 1 to
asoen.
Each bit becomes 0 after each 3-Wire Audio Serial Output
Channel N is out of action by setting 0 to asoen.
*/
#define PS3_AUDIO_AO_3WMCTRL_ASORUN(n) (1 << (15 - (n))) /* R-IVF */
#define PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(n) (0 << (15 - (n))) /* R-I-V */
#define PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(n) (1 << (15 - (n))) /* R---V */
#define PS3_AUDIO_AO_3WMCTRL_ASORUN0 \
PS3_AUDIO_AO_3WMCTRL_ASORUN(0)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_STOPPED \
PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(0)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_RUNNING \
PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(0)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN1 \
PS3_AUDIO_AO_3WMCTRL_ASORUN(1)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_STOPPED \
PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(1)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_RUNNING \
PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(1)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN2 \
PS3_AUDIO_AO_3WMCTRL_ASORUN(2)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_STOPPED \
PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(2)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_RUNNING \
PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(2)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN3 \
PS3_AUDIO_AO_3WMCTRL_ASORUN(3)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_STOPPED \
PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(3)
#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_RUNNING \
PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(3)
/*
Sampling Rate
Specifies the divide ratio of the bit clock (clock output
from bclko) used by the 3-wire Audio Output Clock, which
is applied to the master clock selected by mcksel.
Data output is synchronized with this clock.
*/
#define PS3_AUDIO_AO_3WMCTRL_ASOSR_MASK (0xf << 20) /* RWIVF */
#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV2 (0x1 << 20) /* RWI-V */
#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV4 (0x2 << 20) /* RW--V */
#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV8 (0x4 << 20) /* RW--V */
#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV12 (0x6 << 20) /* RW--V */
/*
Master Clock Select
0 - Master Clock 0
1 - Master Clock 1
*/
#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL (1 << 24) /* RWIVF */
#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK0 (0 << 24) /* RWI-V */
#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK1 (1 << 24) /* RW--V */
/*
Enables and disables 4ch 3-Wire Audio Serial Output
operation. Each Bit from 0 to 3 corresponds to an
output channel, which means that each output channel
can be enabled or disabled individually. When
multiple channels are enabled at the same time, output
operations are performed in synchronization.
Bit 0 - Output Channel 0 (SDOUT[0])
Bit 1 - Output Channel 1 (SDOUT[1])
Bit 2 - Output Channel 2 (SDOUT[2])
Bit 3 - Output Channel 3 (SDOUT[3])
*/
#define PS3_AUDIO_AO_3WMCTRL_ASOEN(n) (1 << (31 - (n))) /* RWIVF */
#define PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(n) (0 << (31 - (n))) /* RWI-V */
#define PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(n) (1 << (31 - (n))) /* RW--V */
#define PS3_AUDIO_AO_3WMCTRL_ASOEN0 \
PS3_AUDIO_AO_3WMCTRL_ASOEN(0) /* RWIVF */
#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_DISABLED \
PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(0) /* RWI-V */
#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_ENABLED \
PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(0) /* RW--V */
#define PS3_AUDIO_A1_3WMCTRL_ASOEN0 \
PS3_AUDIO_AO_3WMCTRL_ASOEN(1) /* RWIVF */
#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_DISABLED \
PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(1) /* RWI-V */
#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_ENABLED \
PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(1) /* RW--V */
#define PS3_AUDIO_A2_3WMCTRL_ASOEN0 \
PS3_AUDIO_AO_3WMCTRL_ASOEN(2) /* RWIVF */
#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_DISABLED \
PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(2) /* RWI-V */
#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_ENABLED \
PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(2) /* RW--V */
#define PS3_AUDIO_A3_3WMCTRL_ASOEN0 \
PS3_AUDIO_AO_3WMCTRL_ASOEN(3) /* RWIVF */
#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_DISABLED \
PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(3) /* RWI-V */
#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_ENABLED \
PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(3) /* RW--V */
/*
3-Wire Audio Serial output Channel 0-3 Control Register
Configures settings for 3-Wire Serial Audio Output Channel 0-3
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|0 0 0 0|A|0|ASO|0 0 0|0|0|0|0|0| AO_3WCTRL
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
Data Bit Mode
Specifies the number of data bits
0 - 16 bits
1 - reserved
2 - 20 bits
3 - 24 bits
*/
#define PS3_AUDIO_AO_3WCTRL_ASODB_MASK (0x3 << 8) /* RWIVF */
#define PS3_AUDIO_AO_3WCTRL_ASODB_16BIT (0x0 << 8) /* RWI-V */
#define PS3_AUDIO_AO_3WCTRL_ASODB_RESVD (0x1 << 8) /* RWI-V */
#define PS3_AUDIO_AO_3WCTRL_ASODB_20BIT (0x2 << 8) /* RW--V */
#define PS3_AUDIO_AO_3WCTRL_ASODB_24BIT (0x3 << 8) /* RW--V */
/*
Data Format Mode
Specifies the data format where (LSB side or MSB) the data(in 20 bit
or 24 bit resolution mode) is put in a 32 bit field.
0 - Data put on LSB side
1 - Data put on MSB side
*/
#define PS3_AUDIO_AO_3WCTRL_ASODF (1 << 11) /* RWIVF */
#define PS3_AUDIO_AO_3WCTRL_ASODF_LSB (0 << 11) /* RWI-V */
#define PS3_AUDIO_AO_3WCTRL_ASODF_MSB (1 << 11) /* RW--V */
/*
Buffer Reset
Performs buffer reset. Writing 1 to this bit initializes the
corresponding 3-Wire Audio Output buffers(both L and R).
*/
#define PS3_AUDIO_AO_3WCTRL_ASOBRST (1 << 16) /* CWIVF */
#define PS3_AUDIO_AO_3WCTRL_ASOBRST_IDLE (0 << 16) /* -WI-V */
#define PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET (1 << 16) /* -W--T */
/*
S/PDIF Audio Output Channel 0/1 Control Register
Configures settings for S/PDIF Audio Output Channel 0/1.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|S|0 0 0|S|0 0|S| SPOSR |0 0|SPO|0 0 0 0|S|0|SPO|0 0 0 0 0 0 0|S| AO_SPDCTRL
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
Buffer reset. Writing 1 to this bit initializes the
corresponding S/PDIF output buffer pointer.
*/
#define PS3_AUDIO_AO_SPDCTRL_SPOBRST (1 << 0) /* CWIVF */
#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_IDLE (0 << 0) /* -WI-V */
#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_RESET (1 << 0) /* -W--T */
/*
Data Bit Mode
Specifies number of data bits
0 - 16 bits
1 - Reserved
2 - 20 bits
3 - 24 bits
*/
#define PS3_AUDIO_AO_SPDCTRL_SPODB_MASK (0x3 << 8) /* RWIVF */
#define PS3_AUDIO_AO_SPDCTRL_SPODB_16BIT (0x0 << 8) /* RWI-V */
#define PS3_AUDIO_AO_SPDCTRL_SPODB_RESVD (0x1 << 8) /* RW--V */
#define PS3_AUDIO_AO_SPDCTRL_SPODB_20BIT (0x2 << 8) /* RW--V */
#define PS3_AUDIO_AO_SPDCTRL_SPODB_24BIT (0x3 << 8) /* RW--V */
/*
Data format Mode
Specifies the data format, where (LSB side or MSB)
the data(in 20 or 24 bit resolution) is put in the
32 bit field.
0 - LSB Side
1 - MSB Side
*/
#define PS3_AUDIO_AO_SPDCTRL_SPODF (1 << 11) /* RWIVF */
#define PS3_AUDIO_AO_SPDCTRL_SPODF_LSB (0 << 11) /* RWI-V */
#define PS3_AUDIO_AO_SPDCTRL_SPODF_MSB (1 << 11) /* RW--V */
/*
Source Select
Specifies the source of the S/PDIF output. When 0, output
operation is controlled by 3wen[0] of AO_3WMCTRL register.
The SR must have the same setting as the a0_3wmctrl reg.
0 - 3-Wire Audio OUT Ch0 Buffer
1 - S/PDIF buffer
*/
#define PS3_AUDIO_AO_SPDCTRL_SPOSS_MASK (0x3 << 16) /* RWIVF */
#define PS3_AUDIO_AO_SPDCTRL_SPOSS_3WEN (0x0 << 16) /* RWI-V */
#define PS3_AUDIO_AO_SPDCTRL_SPOSS_SPDIF (0x1 << 16) /* RW--V */
/*
Sampling Rate
Specifies the divide ratio of the bit clock (clock output
from bclko) used by the S/PDIF Output Clock, which
is applied to the master clock selected by mcksel.
*/
#define PS3_AUDIO_AO_SPDCTRL_SPOSR (0xf << 20) /* RWIVF */
#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV2 (0x1 << 20) /* RWI-V */
#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV4 (0x2 << 20) /* RW--V */
#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV8 (0x4 << 20) /* RW--V */
#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV12 (0x6 << 20) /* RW--V */
/*
Master Clock Select
0 - Master Clock 0
1 - Master Clock 1
*/
#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL (1 << 24) /* RWIVF */
#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK0 (0 << 24) /* RWI-V */
#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK1 (1 << 24) /* RW--V */
/*
S/PDIF Output Channel Operational Status
This bit becomes 1 after S/PDIF Output Channel is in
action by setting 1 to spoen. This bit becomes 0
after S/PDIF Output Channel is out of action by setting
0 to spoen.
*/
#define PS3_AUDIO_AO_SPDCTRL_SPORUN (1 << 27) /* R-IVF */
#define PS3_AUDIO_AO_SPDCTRL_SPORUN_STOPPED (0 << 27) /* R-I-V */
#define PS3_AUDIO_AO_SPDCTRL_SPORUN_RUNNING (1 << 27) /* R---V */
/*
S/PDIF Audio Output Channel Output Enable
Enables and disables output operation. This bit is used
only when sposs = 1
*/
#define PS3_AUDIO_AO_SPDCTRL_SPOEN (1 << 31) /* RWIVF */
#define PS3_AUDIO_AO_SPDCTRL_SPOEN_DISABLED (0 << 31) /* RWI-V */
#define PS3_AUDIO_AO_SPDCTRL_SPOEN_ENABLED (1 << 31) /* RW--V */
/*
S/PDIF Audio Output Channel Channel Status
Setting Registers.
Configures channel status bit settings for each block
(192 bits).
Output is performed from the MSB(AO_SPDCS0 register bit 31).
The same value is added for subframes within the same frame.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
| SPOCS | AO_SPDCS
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
S/PDIF Audio Output Channel User Bit Setting
Configures user bit settings for each block (384 bits).
Output is performed from the MSB(ao_spdub0 register bit 31).
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
| SPOUB | AO_SPDUB
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*****************************************************************************
*
* DMAC register
*
*****************************************************************************/
/*
The PS3_AUDIO_KICK register is used to initiate a DMA transfer and monitor
its status
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0|STATU|0 0 0| EVENT |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|R| KICK
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
The REQUEST field is written to ACTIVE to initiate a DMA request when EVENT
occurs.
It will return to the DONE state when the request is completed.
The registers for a DMA channel should only be written if REQUEST is IDLE.
*/
#define PS3_AUDIO_KICK_REQUEST (1 << 0) /* RWIVF */
#define PS3_AUDIO_KICK_REQUEST_IDLE (0 << 0) /* RWI-V */
#define PS3_AUDIO_KICK_REQUEST_ACTIVE (1 << 0) /* -W--T */
/*
*The EVENT field is used to set the event in which
*the DMA request becomes active.
*/
#define PS3_AUDIO_KICK_EVENT_MASK (0x1f << 16) /* RWIVF */
#define PS3_AUDIO_KICK_EVENT_ALWAYS (0x00 << 16) /* RWI-V */
#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY (0x01 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_UNDERFLOW (0x02 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_EMPTY (0x03 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_UNDERFLOW (0x04 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_EMPTY (0x05 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_UNDERFLOW (0x06 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_EMPTY (0x07 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_UNDERFLOW (0x08 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SPDIF0_BLOCKTRANSFERCOMPLETE \
(0x09 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SPDIF0_UNDERFLOW (0x0A << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SPDIF0_EMPTY (0x0B << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SPDIF1_BLOCKTRANSFERCOMPLETE \
(0x0C << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SPDIF1_UNDERFLOW (0x0D << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_SPDIF1_EMPTY (0x0E << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA(n) \
((0x13 + (n)) << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA0 (0x13 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA1 (0x14 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA2 (0x15 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA3 (0x16 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA4 (0x17 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA5 (0x18 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA6 (0x19 << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA7 (0x1A << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA8 (0x1B << 16) /* RW--V */
#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA9 (0x1C << 16) /* RW--V */
/*
The STATUS field can be used to monitor the progress of a DMA request.
DONE indicates the previous request has completed.
EVENT indicates that the DMA engine is waiting for the EVENT to occur.
PENDING indicates that the DMA engine has not started processing this
request, but the EVENT has occurred.
DMA indicates that the data transfer is in progress.
NOTIFY indicates that the notifier signalling end of transfer is being written.
CLEAR indicated that the previous transfer was cleared.
ERROR indicates the previous transfer requested an unsupported
source/destination combination.
*/
#define PS3_AUDIO_KICK_STATUS_MASK (0x7 << 24) /* R-IVF */
#define PS3_AUDIO_KICK_STATUS_DONE (0x0 << 24) /* R-I-V */
#define PS3_AUDIO_KICK_STATUS_EVENT (0x1 << 24) /* R---V */
#define PS3_AUDIO_KICK_STATUS_PENDING (0x2 << 24) /* R---V */
#define PS3_AUDIO_KICK_STATUS_DMA (0x3 << 24) /* R---V */
#define PS3_AUDIO_KICK_STATUS_NOTIFY (0x4 << 24) /* R---V */
#define PS3_AUDIO_KICK_STATUS_CLEAR (0x5 << 24) /* R---V */
#define PS3_AUDIO_KICK_STATUS_ERROR (0x6 << 24) /* R---V */
/*
The PS3_AUDIO_SOURCE register specifies the source address for transfers.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
| START |0 0 0 0 0|TAR| SOURCE
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
to a 128 byte boundary. The low seven bits are assumed to be 0.
*/
#define PS3_AUDIO_SOURCE_START_MASK (0x01FFFFFF << 7) /* RWIUF */
/*
The TARGET field specifies the memory space containing the source address.
*/
#define PS3_AUDIO_SOURCE_TARGET_MASK (3 << 0) /* RWIVF */
#define PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY (2 << 0) /* RW--V */
/*
The PS3_AUDIO_DEST register specifies the destination address for transfers.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
| START |0 0 0 0 0|TAR| DEST
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
/*
The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
to a 128 byte boundary. The low seven bits are assumed to be 0.
*/
#define PS3_AUDIO_DEST_START_MASK (0x01FFFFFF << 7) /* RWIUF */
/*
The TARGET field specifies the memory space containing the destination address
AUDIOFIFO = Audio WriteData FIFO,
*/
#define PS3_AUDIO_DEST_TARGET_MASK (3 << 0) /* RWIVF */
#define PS3_AUDIO_DEST_TARGET_AUDIOFIFO (1 << 0) /* RW--V */
/*
PS3_AUDIO_DMASIZE specifies the number of 128-byte blocks + 1 to transfer.
So a value of 0 means 128-bytes will get transferred.
31 24 23 16 15 8 7 0
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| BLOCKS | DMASIZE
+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
*/
#define PS3_AUDIO_DMASIZE_BLOCKS_MASK (0x7f << 0) /* RWIUF */
/*
* source/destination address for internal fifos
*/
#define PS3_AUDIO_AO_3W_LDATA(n) (0x1000 + (0x100 * (n)))
#define PS3_AUDIO_AO_3W_RDATA(n) (0x1080 + (0x100 * (n)))
#define PS3_AUDIO_AO_SPD_DATA(n) (0x2000 + (0x400 * (n)))
/*
* field attiribute
*
* Read
* ' ' = Other Information
* '-' = Field is part of a write-only register
* 'C' = Value read is always the same, constant value line follows (C)
* 'R' = Value is read
*
* Write
* ' ' = Other Information
* '-' = Must not be written (D), value ignored when written (R,A,F)
* 'W' = Can be written
*
* Internal State
* ' ' = Other Information
* '-' = No internal state
* 'X' = Internal state, initial value is unknown
* 'I' = Internal state, initial value is known and follows (I)
*
* Declaration/Size
* ' ' = Other Information
* '-' = Does Not Apply
* 'V' = Type is void
* 'U' = Type is unsigned integer
* 'S' = Type is signed integer
* 'F' = Type is IEEE floating point
* '1' = Byte size (008)
* '2' = Short size (016)
* '3' = Three byte size (024)
* '4' = Word size (032)
* '8' = Double size (064)
*
* Define Indicator
* ' ' = Other Information
* 'D' = Device
* 'M' = Memory
* 'R' = Register
* 'A' = Array of Registers
* 'F' = Field
* 'V' = Value
* 'T' = Task
*/

1496
sound/ppc/tumbler.c Normal file

File diff suppressed because it is too large Load diff

250
sound/ppc/tumbler_volume.h Normal file
View file

@ -0,0 +1,250 @@
/* volume tables, taken from TAS3001c data manual */
/* volume gain values */
/* 0 = -70 dB, 175 = 18.0 dB in 0.5 dB step */
static unsigned int master_volume_table[] = {
0x00000015, 0x00000016, 0x00000017,
0x00000019, 0x0000001a, 0x0000001c,
0x0000001d, 0x0000001f, 0x00000021,
0x00000023, 0x00000025, 0x00000027,
0x00000029, 0x0000002c, 0x0000002e,
0x00000031, 0x00000034, 0x00000037,
0x0000003a, 0x0000003e, 0x00000042,
0x00000045, 0x0000004a, 0x0000004e,
0x00000053, 0x00000057, 0x0000005d,
0x00000062, 0x00000068, 0x0000006e,
0x00000075, 0x0000007b, 0x00000083,
0x0000008b, 0x00000093, 0x0000009b,
0x000000a5, 0x000000ae, 0x000000b9,
0x000000c4, 0x000000cf, 0x000000dc,
0x000000e9, 0x000000f6, 0x00000105,
0x00000114, 0x00000125, 0x00000136,
0x00000148, 0x0000015c, 0x00000171,
0x00000186, 0x0000019e, 0x000001b6,
0x000001d0, 0x000001eb, 0x00000209,
0x00000227, 0x00000248, 0x0000026b,
0x0000028f, 0x000002b6, 0x000002df,
0x0000030b, 0x00000339, 0x0000036a,
0x0000039e, 0x000003d5, 0x0000040f,
0x0000044c, 0x0000048d, 0x000004d2,
0x0000051c, 0x00000569, 0x000005bb,
0x00000612, 0x0000066e, 0x000006d0,
0x00000737, 0x000007a5, 0x00000818,
0x00000893, 0x00000915, 0x0000099f,
0x00000a31, 0x00000acc, 0x00000b6f,
0x00000c1d, 0x00000cd5, 0x00000d97,
0x00000e65, 0x00000f40, 0x00001027,
0x0000111c, 0x00001220, 0x00001333,
0x00001456, 0x0000158a, 0x000016d1,
0x0000182b, 0x0000199a, 0x00001b1e,
0x00001cb9, 0x00001e6d, 0x0000203a,
0x00002223, 0x00002429, 0x0000264e,
0x00002893, 0x00002afa, 0x00002d86,
0x00003039, 0x00003314, 0x0000361b,
0x00003950, 0x00003cb5, 0x0000404e,
0x0000441d, 0x00004827, 0x00004c6d,
0x000050f4, 0x000055c0, 0x00005ad5,
0x00006037, 0x000065ea, 0x00006bf4,
0x0000725a, 0x00007920, 0x0000804e,
0x000087e8, 0x00008ff6, 0x0000987d,
0x0000a186, 0x0000ab19, 0x0000b53c,
0x0000bff9, 0x0000cb59, 0x0000d766,
0x0000e429, 0x0000f1ae, 0x00010000,
0x00010f2b, 0x00011f3d, 0x00013042,
0x00014249, 0x00015562, 0x0001699c,
0x00017f09, 0x000195bc, 0x0001adc6,
0x0001c73d, 0x0001e237, 0x0001feca,
0x00021d0e, 0x00023d1d, 0x00025f12,
0x0002830b, 0x0002a925, 0x0002d182,
0x0002fc42, 0x0003298b, 0x00035983,
0x00038c53, 0x0003c225, 0x0003fb28,
0x0004378b, 0x00047783, 0x0004bb44,
0x0005030a, 0x00054f10, 0x00059f98,
0x0005f4e5, 0x00064f40, 0x0006aef6,
0x00071457, 0x00077fbb, 0x0007f17b,
};
/* treble table for TAS3001c */
/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
static unsigned int treble_volume_table[] = {
0x96, 0x95, 0x94,
0x93, 0x92, 0x91,
0x90, 0x8f, 0x8e,
0x8d, 0x8c, 0x8b,
0x8a, 0x89, 0x88,
0x87, 0x86, 0x85,
0x84, 0x83, 0x82,
0x81, 0x80, 0x7f,
0x7e, 0x7d, 0x7c,
0x7b, 0x7a, 0x79,
0x78, 0x77, 0x76,
0x75, 0x74, 0x73,
0x72, 0x71, 0x70,
0x6e, 0x6d, 0x6c,
0x6b, 0x69, 0x68,
0x66, 0x65, 0x63,
0x62, 0x60, 0x5e,
0x5c, 0x5a, 0x57,
0x55, 0x52, 0x4f,
0x4c, 0x49, 0x45,
0x42, 0x3e, 0x3a,
0x36, 0x32, 0x2d,
0x28, 0x22, 0x1c,
0x16, 0x10, 0x09,
0x01,
};
/* bass table for TAS3001c */
/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
static unsigned int bass_volume_table[] = {
0x86, 0x82, 0x7f,
0x7d, 0x7a, 0x78,
0x76, 0x74, 0x72,
0x70, 0x6e, 0x6d,
0x6b, 0x69, 0x66,
0x64, 0x61, 0x5f,
0x5d, 0x5c, 0x5a,
0x59, 0x58, 0x56,
0x55, 0x54, 0x53,
0x51, 0x4f, 0x4d,
0x4b, 0x49, 0x46,
0x44, 0x42, 0x40,
0x3e, 0x3c, 0x3b,
0x39, 0x38, 0x36,
0x35, 0x33, 0x31,
0x30, 0x2e, 0x2c,
0x2b, 0x29, 0x28,
0x26, 0x25, 0x23,
0x21, 0x1f, 0x1c,
0x19, 0x18, 0x17,
0x16, 0x14, 0x13,
0x12, 0x10, 0x0f,
0x0d, 0x0b, 0x0a,
0x08, 0x06, 0x03,
0x01,
};
/* mixer (pcm) volume table */
/* 0 = -70 dB, 175 = 18.0 dB in 0.5 dB step */
static unsigned int mixer_volume_table[] = {
0x00014b, 0x00015f, 0x000174,
0x00018a, 0x0001a1, 0x0001ba,
0x0001d4, 0x0001f0, 0x00020d,
0x00022c, 0x00024d, 0x000270,
0x000295, 0x0002bc, 0x0002e6,
0x000312, 0x000340, 0x000372,
0x0003a6, 0x0003dd, 0x000418,
0x000456, 0x000498, 0x0004de,
0x000528, 0x000576, 0x0005c9,
0x000620, 0x00067d, 0x0006e0,
0x000748, 0x0007b7, 0x00082c,
0x0008a8, 0x00092b, 0x0009b6,
0x000a49, 0x000ae5, 0x000b8b,
0x000c3a, 0x000cf3, 0x000db8,
0x000e88, 0x000f64, 0x00104e,
0x001145, 0x00124b, 0x001361,
0x001487, 0x0015be, 0x001708,
0x001865, 0x0019d8, 0x001b60,
0x001cff, 0x001eb7, 0x002089,
0x002276, 0x002481, 0x0026ab,
0x0028f5, 0x002b63, 0x002df5,
0x0030ae, 0x003390, 0x00369e,
0x0039db, 0x003d49, 0x0040ea,
0x0044c3, 0x0048d6, 0x004d27,
0x0051b9, 0x005691, 0x005bb2,
0x006121, 0x0066e3, 0x006cfb,
0x007370, 0x007a48, 0x008186,
0x008933, 0x009154, 0x0099f1,
0x00a310, 0x00acba, 0x00b6f6,
0x00c1cd, 0x00cd49, 0x00d973,
0x00e655, 0x00f3fb, 0x010270,
0x0111c0, 0x0121f9, 0x013328,
0x01455b, 0x0158a2, 0x016d0e,
0x0182af, 0x019999, 0x01b1de,
0x01cb94, 0x01e6cf, 0x0203a7,
0x022235, 0x024293, 0x0264db,
0x02892c, 0x02afa3, 0x02d862,
0x03038a, 0x033142, 0x0361af,
0x0394fa, 0x03cb50, 0x0404de,
0x0441d5, 0x048268, 0x04c6d0,
0x050f44, 0x055c04, 0x05ad50,
0x06036e, 0x065ea5, 0x06bf44,
0x07259d, 0x079207, 0x0804dc,
0x087e80, 0x08ff59, 0x0987d5,
0x0a1866, 0x0ab189, 0x0b53be,
0x0bff91, 0x0cb591, 0x0d765a,
0x0e4290, 0x0f1adf, 0x100000,
0x10f2b4, 0x11f3c9, 0x13041a,
0x14248e, 0x15561a, 0x1699c0,
0x17f094, 0x195bb8, 0x1adc61,
0x1c73d5, 0x1e236d, 0x1fec98,
0x21d0d9, 0x23d1cd, 0x25f125,
0x2830af, 0x2a9254, 0x2d1818,
0x2fc420, 0x3298b0, 0x35982f,
0x38c528, 0x3c224c, 0x3fb278,
0x437880, 0x477828, 0x4bb446,
0x5030a1, 0x54f106, 0x59f980,
0x5f4e52, 0x64f403, 0x6aef5d,
0x714575, 0x77fbaa, 0x7f17af,
};
/* treble table for TAS3004 */
/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
static unsigned int snapper_treble_volume_table[] = {
0x96, 0x95, 0x94,
0x93, 0x92, 0x91,
0x90, 0x8f, 0x8e,
0x8d, 0x8c, 0x8b,
0x8a, 0x89, 0x88,
0x87, 0x86, 0x85,
0x84, 0x83, 0x82,
0x81, 0x80, 0x7f,
0x7e, 0x7d, 0x7c,
0x7b, 0x7a, 0x79,
0x78, 0x77, 0x76,
0x75, 0x74, 0x73,
0x72, 0x71, 0x70,
0x6f, 0x6d, 0x6c,
0x6b, 0x69, 0x68,
0x67, 0x65, 0x63,
0x62, 0x60, 0x5d,
0x5b, 0x59, 0x56,
0x53, 0x51, 0x4d,
0x4a, 0x47, 0x43,
0x3f, 0x3b, 0x36,
0x31, 0x2c, 0x26,
0x20, 0x1a, 0x13,
0x08, 0x04, 0x01,
0x01,
};
/* bass table for TAS3004 */
/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
static unsigned int snapper_bass_volume_table[] = {
0x96, 0x95, 0x94,
0x93, 0x92, 0x91,
0x90, 0x8f, 0x8e,
0x8d, 0x8c, 0x8b,
0x8a, 0x89, 0x88,
0x87, 0x86, 0x85,
0x84, 0x83, 0x82,
0x81, 0x80, 0x7f,
0x7e, 0x7d, 0x7c,
0x7b, 0x7a, 0x79,
0x78, 0x77, 0x76,
0x75, 0x74, 0x73,
0x72, 0x71, 0x6f,
0x6e, 0x6d, 0x6b,
0x6a, 0x69, 0x67,
0x66, 0x65, 0x63,
0x62, 0x61, 0x5f,
0x5d, 0x5b, 0x58,
0x55, 0x52, 0x4f,
0x4c, 0x49, 0x46,
0x43, 0x3f, 0x3b,
0x37, 0x33, 0x2e,
0x29, 0x24, 0x1e,
0x18, 0x11, 0x0a,
0x01,
};