aboutsummaryrefslogtreecommitdiff
path: root/sound/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/ppc')
-rw-r--r--sound/ppc/Kconfig27
-rw-r--r--sound/ppc/awacs.c412
-rw-r--r--sound/ppc/awacs.h21
-rw-r--r--sound/ppc/beep.c8
-rw-r--r--sound/ppc/burgundy.c478
-rw-r--r--sound/ppc/burgundy.h31
-rw-r--r--sound/ppc/daca.c6
-rw-r--r--sound/ppc/keywest.c102
-rw-r--r--sound/ppc/pmac.c74
-rw-r--r--sound/ppc/powermac.c44
-rw-r--r--sound/ppc/snd_ps3.c703
-rw-r--r--sound/ppc/snd_ps3.h1
-rw-r--r--sound/ppc/snd_ps3_reg.h14
-rw-r--r--sound/ppc/tumbler.c70
14 files changed, 1282 insertions, 709 deletions
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig
index cacb0b13688..0519c60f5be 100644
--- a/sound/ppc/Kconfig
+++ b/sound/ppc/Kconfig
@@ -1,18 +1,19 @@
# ALSA PowerMac drivers
-menu "ALSA PowerMac devices"
- depends on SND!=n && PPC
-
-comment "ALSA PowerMac requires I2C"
- depends on SND && I2C=n
+menuconfig SND_PPC
+ bool "PowerPC sound devices"
+ depends on PPC
+ default y
+ help
+ Support for sound devices specific to PowerPC architectures.
-comment "ALSA PowerMac requires INPUT"
- depends on SND && INPUT=n
+if SND_PPC
config SND_POWERMAC
tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
- depends on SND && I2C && INPUT && PPC_PMAC
+ depends on I2C && INPUT && PPC_PMAC
select SND_PCM
+ select SND_VMASTER
help
Say Y here to include support for the integrated sound device.
@@ -32,14 +33,9 @@ config SND_POWERMAC_AUTO_DRC
Note that you can turn on/off DRC manually even without this
option.
-endmenu
-
-menu "ALSA PowerPC devices"
- depends on SND!=n && ( PPC64 || PPC32 )
-
config SND_PS3
tristate "PS3 Audio support"
- depends on SND && PS3_PS3AV
+ depends on PS3_PS3AV
select SND_PCM
default m
help
@@ -52,4 +48,5 @@ config SND_PS3_DEFAULT_START_DELAY
int "Startup delay time in ms"
depends on SND_PS3
default "2000"
-endmenu
+
+endif # SND_PPC
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 8441e780df0..5fbf5db2543 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -141,7 +141,7 @@ static int snd_pmac_awacs_info_volume(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 15;
return 0;
}
-
+
static int snd_pmac_awacs_get_volume(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -267,7 +267,8 @@ static int snd_pmac_awacs_put_switch(struct snd_kcontrol *kcontrol,
static void awacs_set_cuda(int reg, int val)
{
struct adb_request req;
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, reg, val);
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a,
+ reg, val);
while (! req.complete)
cuda_poll();
}
@@ -289,11 +290,11 @@ static void awacs_amp_set_tone(struct awacs_amp *amp, int bass, int treble)
/*
* vol = 0 - 31 (attenuation), 32 = mute bit, stereo
*/
-static int awacs_amp_set_vol(struct awacs_amp *amp, int index, int lvol, int rvol,
- int do_check)
+static int awacs_amp_set_vol(struct awacs_amp *amp, int index,
+ int lvol, int rvol, int do_check)
{
if (do_check && amp->amp_vol[index][0] == lvol &&
- amp->amp_vol[index][1] == rvol)
+ amp->amp_vol[index][1] == rvol)
return 0;
awacs_set_cuda(3 + index, lvol);
awacs_set_cuda(5 + index, rvol);
@@ -318,7 +319,8 @@ static void awacs_amp_set_master(struct awacs_amp *amp, int vol)
static void awacs_amp_free(struct snd_pmac *chip)
{
struct awacs_amp *amp = chip->mixer_data;
- snd_assert(amp, return);
+ if (!amp)
+ return;
kfree(amp);
chip->mixer_data = NULL;
chip->mixer_free = NULL;
@@ -337,15 +339,14 @@ static int snd_pmac_awacs_info_volume_amp(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 31;
return 0;
}
-
+
static int snd_pmac_awacs_get_volume_amp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
int index = kcontrol->private_value;
struct awacs_amp *amp = chip->mixer_data;
- snd_assert(amp, return -EINVAL);
- snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
ucontrol->value.integer.value[0] = 31 - (amp->amp_vol[index][0] & 31);
ucontrol->value.integer.value[1] = 31 - (amp->amp_vol[index][1] & 31);
return 0;
@@ -358,11 +359,11 @@ static int snd_pmac_awacs_put_volume_amp(struct snd_kcontrol *kcontrol,
int index = kcontrol->private_value;
int vol[2];
struct awacs_amp *amp = chip->mixer_data;
- snd_assert(amp, return -EINVAL);
- snd_assert(index >= 0 && index <= 1, return -EINVAL);
- vol[0] = (31 - (ucontrol->value.integer.value[0] & 31)) | (amp->amp_vol[index][0] & 32);
- vol[1] = (31 - (ucontrol->value.integer.value[1] & 31)) | (amp->amp_vol[index][1] & 32);
+ vol[0] = (31 - (ucontrol->value.integer.value[0] & 31))
+ | (amp->amp_vol[index][0] & 32);
+ vol[1] = (31 - (ucontrol->value.integer.value[1] & 31))
+ | (amp->amp_vol[index][1] & 32);
return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
}
@@ -372,10 +373,11 @@ static int snd_pmac_awacs_get_switch_amp(struct snd_kcontrol *kcontrol,
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
int index = kcontrol->private_value;
struct awacs_amp *amp = chip->mixer_data;
- snd_assert(amp, return -EINVAL);
- snd_assert(index >= 0 && index <= 1, return -EINVAL);
- ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32) ? 0 : 1;
- ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32) ? 0 : 1;
+
+ ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32)
+ ? 0 : 1;
+ ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32)
+ ? 0 : 1;
return 0;
}
@@ -386,11 +388,11 @@ static int snd_pmac_awacs_put_switch_amp(struct snd_kcontrol *kcontrol,
int index = kcontrol->private_value;
int vol[2];
struct awacs_amp *amp = chip->mixer_data;
- snd_assert(amp, return -EINVAL);
- snd_assert(index >= 0 && index <= 1, return -EINVAL);
- vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32) | (amp->amp_vol[index][0] & 31);
- vol[1] = (ucontrol->value.integer.value[1] ? 0 : 32) | (amp->amp_vol[index][1] & 31);
+ vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32)
+ | (amp->amp_vol[index][0] & 31);
+ vol[1] = (ucontrol->value.integer.value[1] ? 0 : 32)
+ | (amp->amp_vol[index][1] & 31);
return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
}
@@ -403,15 +405,14 @@ static int snd_pmac_awacs_info_tone_amp(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 14;
return 0;
}
-
+
static int snd_pmac_awacs_get_tone_amp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
int index = kcontrol->private_value;
struct awacs_amp *amp = chip->mixer_data;
- snd_assert(amp, return -EINVAL);
- snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
ucontrol->value.integer.value[0] = amp->amp_tone[index];
return 0;
}
@@ -423,8 +424,7 @@ static int snd_pmac_awacs_put_tone_amp(struct snd_kcontrol *kcontrol,
int index = kcontrol->private_value;
struct awacs_amp *amp = chip->mixer_data;
unsigned int val;
- snd_assert(amp, return -EINVAL);
- snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
val = ucontrol->value.integer.value[0];
if (val > 14)
return -EINVAL;
@@ -445,13 +445,13 @@ static int snd_pmac_awacs_info_master_amp(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 99;
return 0;
}
-
+
static int snd_pmac_awacs_get_master_amp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct awacs_amp *amp = chip->mixer_data;
- snd_assert(amp, return -EINVAL);
+
ucontrol->value.integer.value[0] = amp->amp_master;
return 0;
}
@@ -462,7 +462,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol,
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct awacs_amp *amp = chip->mixer_data;
unsigned int val;
- snd_assert(amp, return -EINVAL);
+
val = ucontrol->value.integer.value[0];
if (val > 99)
return -EINVAL;
@@ -477,9 +477,9 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol,
#define AMP_CH_SPK 0
#define AMP_CH_HD 1
-static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] = {
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PC Speaker Playback Volume",
+ .name = "Speaker Playback Volume",
.info = snd_pmac_awacs_info_volume_amp,
.get = snd_pmac_awacs_get_volume_amp,
.put = snd_pmac_awacs_put_volume_amp,
@@ -514,7 +514,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = {
},
};
-static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Headphone Playback Switch",
.info = snd_pmac_boolean_stereo_info,
@@ -523,9 +523,9 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = {
.private_value = AMP_CH_HD,
};
-static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PC Speaker Playback Switch",
+ .name = "Speaker Playback Switch",
.info = snd_pmac_boolean_stereo_info,
.get = snd_pmac_awacs_get_switch_amp,
.put = snd_pmac_awacs_put_switch_amp,
@@ -544,7 +544,7 @@ static int snd_pmac_screamer_mic_boost_info(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 2;
+ uinfo->value.integer.max = 3;
return 0;
}
@@ -552,16 +552,14 @@ static int snd_pmac_screamer_mic_boost_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
- int val;
+ int val = 0;
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
if (chip->awacs_reg[6] & MASK_MIC_BOOST)
- val = 2;
- else if (chip->awacs_reg[0] & MASK_GAINLINE)
- val = 1;
- else
- val = 0;
+ val |= 2;
+ if (chip->awacs_reg[0] & MASK_GAINLINE)
+ val |= 1;
spin_unlock_irqrestore(&chip->reg_lock, flags);
ucontrol->value.integer.value[0] = val;
return 0;
@@ -578,11 +576,10 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol,
spin_lock_irqsave(&chip->reg_lock, flags);
val0 = chip->awacs_reg[0] & ~MASK_GAINLINE;
val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST;
- if (ucontrol->value.integer.value[0] > 0) {
+ if (ucontrol->value.integer.value[0] & 1)
val0 |= MASK_GAINLINE;
- if (ucontrol->value.integer.value[0] > 1)
- val6 |= MASK_MIC_BOOST;
- }
+ if (ucontrol->value.integer.value[0] & 2)
+ val6 |= MASK_MIC_BOOST;
if (val0 != chip->awacs_reg[0]) {
snd_pmac_awacs_write_reg(chip, 0, val0);
changed = 1;
@@ -598,58 +595,131 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol,
/*
* lists of mixer elements
*/
-static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __initdata = {
- AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
+static struct snd_kcontrol_new snd_pmac_awacs_mixers[] = {
AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0),
- AWACS_VOLUME("Capture Volume", 0, 4, 0),
+ AWACS_VOLUME("Master Capture Volume", 0, 4, 0),
+/* AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] = {
+ AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
+ AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
+ AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
+ AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] = {
+ AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] = {
+ AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
+ AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] = {
+ AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
+ AWACS_VOLUME("Master Playback Volume", 5, 6, 1),
+ AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+ AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] = {
+ AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
+ AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+ AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] = {
+ AWACS_VOLUME("Headphone Playback Volume", 2, 6, 1),
+};
+
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] = {
+ AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
};
/* FIXME: is this correct order?
* screamer (powerbook G3 pismo) seems to have different bits...
*/
-static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] = {
AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0),
AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0),
};
-static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] = {
AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0),
};
-static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] = {
+ AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw =
AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);
-static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = {
- AWACS_SWITCH("Mic Boost", 0, SHIFT_GAINLINE, 0),
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac =
+AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1);
+
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 =
+AWACS_SWITCH("Headphone Playback Switch", 1, SHIFT_HDMUTE, 1);
+
+static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] = {
+ AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
};
-static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] = {
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic Boost",
+ .name = "Mic Boost Capture Volume",
.info = snd_pmac_screamer_mic_boost_info,
.get = snd_pmac_screamer_mic_boost_get,
.put = snd_pmac_screamer_mic_boost_put,
},
};
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __initdata = {
- AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1),
+static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] =
+{
+ AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] =
+{
+ AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
+ AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] =
+{
+ AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
+ AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] = {
+ AWACS_VOLUME("Speaker Playback Volume", 4, 6, 1),
};
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata =
-AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
+
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw =
+AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
+
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 =
+AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 1);
+
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 =
+AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 0);
/*
* add new mixer elements to the card
*/
-static int build_mixers(struct snd_pmac *chip, int nums, struct snd_kcontrol_new *mixers)
+static int build_mixers(struct snd_pmac *chip, int nums,
+ struct snd_kcontrol_new *mixers)
{
int i, err;
for (i = 0; i < nums; i++) {
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixers[i], chip))) < 0)
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&mixers[i], chip));
+ if (err < 0)
return err;
}
return 0;
@@ -681,8 +751,8 @@ static void snd_pmac_awacs_suspend(struct snd_pmac *chip)
static void snd_pmac_awacs_resume(struct snd_pmac *chip)
{
- if (machine_is_compatible("PowerBook3,1")
- || machine_is_compatible("PowerBook3,2")) {
+ if (of_machine_is_compatible("PowerBook3,1")
+ || of_machine_is_compatible("PowerBook3,2")) {
msleep(100);
snd_pmac_awacs_write_reg(chip, 1,
chip->awacs_reg[1] & ~MASK_PAROUT);
@@ -699,8 +769,10 @@ static void snd_pmac_awacs_resume(struct snd_pmac *chip)
#ifdef PMAC_AMP_AVAIL
if (chip->mixer_data) {
struct awacs_amp *amp = chip->mixer_data;
- awacs_amp_set_vol(amp, 0, amp->amp_vol[0][0], amp->amp_vol[0][1], 0);
- awacs_amp_set_vol(amp, 1, amp->amp_vol[1][0], amp->amp_vol[1][1], 0);
+ awacs_amp_set_vol(amp, 0,
+ amp->amp_vol[0][0], amp->amp_vol[0][1], 0);
+ awacs_amp_set_vol(amp, 1,
+ amp->amp_vol[1][0], amp->amp_vol[1][1], 0);
awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);
awacs_amp_set_master(amp, amp->amp_master);
}
@@ -708,6 +780,19 @@ static void snd_pmac_awacs_resume(struct snd_pmac *chip)
}
#endif /* CONFIG_PM */
+#define IS_PM7500 (of_machine_is_compatible("AAPL,7500") \
+ || of_machine_is_compatible("AAPL,8500") \
+ || of_machine_is_compatible("AAPL,9500"))
+#define IS_PM5500 (of_machine_is_compatible("AAPL,e411"))
+#define IS_BEIGE (of_machine_is_compatible("AAPL,Gossamer"))
+#define IS_IMAC1 (of_machine_is_compatible("PowerMac2,1"))
+#define IS_IMAC2 (of_machine_is_compatible("PowerMac2,2") \
+ || of_machine_is_compatible("PowerMac4,1"))
+#define IS_G4AGP (of_machine_is_compatible("PowerMac3,1"))
+#define IS_LOMBARD (of_machine_is_compatible("PowerBook1,1"))
+
+static int imac1, imac2;
+
#ifdef PMAC_SUPPORT_AUTOMUTE
/*
* auto-mute stuffs
@@ -750,9 +835,21 @@ static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify)
} else
#endif
{
- int reg = chip->awacs_reg[1] | (MASK_HDMUTE|MASK_SPKMUTE);
+ int reg = chip->awacs_reg[1]
+ | (MASK_HDMUTE | MASK_SPKMUTE);
+ if (imac1) {
+ reg &= ~MASK_SPKMUTE;
+ reg |= MASK_PAROUT1;
+ } else if (imac2) {
+ reg &= ~MASK_SPKMUTE;
+ reg &= ~MASK_PAROUT1;
+ }
if (snd_pmac_awacs_detect_headphone(chip))
reg &= ~MASK_HDMUTE;
+ else if (imac1)
+ reg &= ~MASK_PAROUT1;
+ else if (imac2)
+ reg |= MASK_PAROUT1;
else
reg &= ~MASK_SPKMUTE;
if (do_notify && reg == chip->awacs_reg[1])
@@ -775,11 +872,22 @@ static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify)
/*
* initialize chip
*/
-int __init
+int
snd_pmac_awacs_init(struct snd_pmac *chip)
{
+ int pm7500 = IS_PM7500;
+ int pm5500 = IS_PM5500;
+ int beige = IS_BEIGE;
+ int g4agp = IS_G4AGP;
+ int lombard = IS_LOMBARD;
+ int imac;
int err, vol;
+ struct snd_kcontrol *vmaster_sw, *vmaster_vol;
+ struct snd_kcontrol *master_vol, *speaker_vol;
+ imac1 = IS_IMAC1;
+ imac2 = IS_IMAC2;
+ imac = imac1 || imac2;
/* looks like MASK_GAINLINE triggers something, so we set here
* as start-up
*/
@@ -787,7 +895,7 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
chip->awacs_reg[1] = MASK_CMUTE | MASK_AMUTE;
/* FIXME: Only machines with external SRS module need MASK_PAROUT */
if (chip->has_iic || chip->device_id == 0x5 ||
- /*chip->_device_id == 0x8 || */
+ /* chip->_device_id == 0x8 || */
chip->device_id == 0xb)
chip->awacs_reg[1] |= MASK_PAROUT;
/* get default volume from nvram */
@@ -798,8 +906,10 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
chip->awacs_reg[2] = vol;
chip->awacs_reg[4] = vol;
if (chip->model == PMAC_SCREAMER) {
- chip->awacs_reg[5] = vol; /* FIXME: screamer has loopthru vol control */
- chip->awacs_reg[6] = MASK_MIC_BOOST; /* FIXME: maybe should be vol << 3 for PCMCIA speaker */
+ /* FIXME: screamer has loopthru vol control */
+ chip->awacs_reg[5] = vol;
+ /* FIXME: maybe should be vol << 3 for PCMCIA speaker */
+ chip->awacs_reg[6] = MASK_MIC_BOOST;
chip->awacs_reg[7] = 0;
}
@@ -815,7 +925,8 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
return -ENOMEM;
chip->mixer_data = amp;
chip->mixer_free = awacs_amp_free;
- awacs_amp_set_vol(amp, 0, 63, 63, 0); /* mute and zero vol */
+ /* mute and zero vol */
+ awacs_amp_set_vol(amp, 0, 63, 63, 0);
awacs_amp_set_vol(amp, 1, 63, 63, 0);
awacs_amp_set_tone(amp, 7, 7); /* 0 dB */
awacs_amp_set_master(amp, 79); /* 0 dB */
@@ -826,20 +937,25 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
/* set headphone-jack detection bit */
switch (chip->model) {
case PMAC_AWACS:
- chip->hp_stat_mask = 0x04;
+ chip->hp_stat_mask = pm7500 || pm5500 ? MASK_HDPCONN
+ : MASK_LOCONN;
break;
case PMAC_SCREAMER:
switch (chip->device_id) {
case 0x08:
- /* 1 = side jack, 2 = front jack */
- chip->hp_stat_mask = 0x03;
+ case 0x0B:
+ chip->hp_stat_mask = imac
+ ? MASK_LOCONN_IMAC |
+ MASK_HDPLCONN_IMAC |
+ MASK_HDPRCONN_IMAC
+ : MASK_HDPCONN;
break;
case 0x00:
case 0x05:
- chip->hp_stat_mask = 0x04;
+ chip->hp_stat_mask = MASK_LOCONN;
break;
default:
- chip->hp_stat_mask = 0x08;
+ chip->hp_stat_mask = MASK_HDPCONN;
break;
}
break;
@@ -854,19 +970,65 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
*/
strcpy(chip->card->mixername, "PowerMac AWACS");
- if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),
- snd_pmac_awacs_mixers)) < 0)
+ err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),
+ snd_pmac_awacs_mixers);
+ if (err < 0)
return err;
- if (chip->model == PMAC_SCREAMER)
+ if (beige || g4agp)
+ ;
+ else if (chip->model == PMAC_SCREAMER || pm5500)
err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2),
snd_pmac_screamer_mixers2);
- else
+ else if (!pm7500)
err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers2),
snd_pmac_awacs_mixers2);
if (err < 0)
return err;
- chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_master_sw, chip);
- if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
+ if (pm5500) {
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_awacs_mixers2_pmac5500),
+ snd_pmac_awacs_mixers2_pmac5500);
+ if (err < 0)
+ return err;
+ }
+ if (pm7500)
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500),
+ snd_pmac_awacs_mixers_pmac7500);
+ else if (pm5500)
+ err = snd_ctl_add(chip->card,
+ (master_vol = snd_ctl_new1(snd_pmac_awacs_mixers_pmac5500,
+ chip)));
+ else if (beige)
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_screamer_mixers_beige),
+ snd_pmac_screamer_mixers_beige);
+ else if (imac || lombard) {
+ err = snd_ctl_add(chip->card,
+ (master_vol = snd_ctl_new1(snd_pmac_screamer_mixers_lo,
+ chip)));
+ if (err < 0)
+ return err;
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_screamer_mixers_imac),
+ snd_pmac_screamer_mixers_imac);
+ } else if (g4agp)
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_screamer_mixers_g4agp),
+ snd_pmac_screamer_mixers_g4agp);
+ else
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_awacs_mixers_pmac),
+ snd_pmac_awacs_mixers_pmac);
+ if (err < 0)
+ return err;
+ chip->master_sw_ctl = snd_ctl_new1((pm7500 || imac || g4agp || lombard)
+ ? &snd_pmac_awacs_master_sw_imac
+ : pm5500
+ ? &snd_pmac_awacs_master_sw_pmac5500
+ : &snd_pmac_awacs_master_sw, chip);
+ err = snd_ctl_add(chip->card, chip->master_sw_ctl);
+ if (err < 0)
return err;
#ifdef PMAC_AMP_AVAIL
if (chip->mixer_data) {
@@ -876,38 +1038,89 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
* screamer registers.
* in this case, it seems the route C is not used.
*/
- if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol),
- snd_pmac_awacs_amp_vol)) < 0)
+ err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol),
+ snd_pmac_awacs_amp_vol);
+ if (err < 0)
return err;
/* overwrite */
- chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_hp_sw, chip);
- if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
+ chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_hp_sw,
+ chip);
+ err = snd_ctl_add(chip->card, chip->master_sw_ctl);
+ if (err < 0)
return err;
- chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_spk_sw, chip);
- if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
+ chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_spk_sw,
+ chip);
+ err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
+ if (err < 0)
return err;
} else
#endif /* PMAC_AMP_AVAIL */
{
/* route A = headphone, route C = speaker */
- if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_speaker_vol),
- snd_pmac_awacs_speaker_vol)) < 0)
+ err = snd_ctl_add(chip->card,
+ (speaker_vol = snd_ctl_new1(snd_pmac_awacs_speaker_vol,
+ chip)));
+ if (err < 0)
return err;
- chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_speaker_sw, chip);
- if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
+ chip->speaker_sw_ctl = snd_ctl_new1(imac1
+ ? &snd_pmac_awacs_speaker_sw_imac1
+ : imac2
+ ? &snd_pmac_awacs_speaker_sw_imac2
+ : &snd_pmac_awacs_speaker_sw, chip);
+ err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
+ if (err < 0)
return err;
}
- if (chip->model == PMAC_SCREAMER) {
- if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mic_boost),
- snd_pmac_screamer_mic_boost)) < 0)
+ if (pm5500 || imac || lombard) {
+ vmaster_sw = snd_ctl_make_virtual_master(
+ "Master Playback Switch", (unsigned int *) NULL);
+ err = snd_ctl_add_slave_uncached(vmaster_sw,
+ chip->master_sw_ctl);
+ if (err < 0)
return err;
- } else {
- if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost),
- snd_pmac_awacs_mic_boost)) < 0)
+ err = snd_ctl_add_slave_uncached(vmaster_sw,
+ chip->speaker_sw_ctl);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add(chip->card, vmaster_sw);
+ if (err < 0)
+ return err;
+ vmaster_vol = snd_ctl_make_virtual_master(
+ "Master Playback Volume", (unsigned int *) NULL);
+ err = snd_ctl_add_slave(vmaster_vol, master_vol);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add_slave(vmaster_vol, speaker_vol);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add(chip->card, vmaster_vol);
+ if (err < 0)
return err;
}
+ if (beige || g4agp)
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_screamer_mic_boost_beige),
+ snd_pmac_screamer_mic_boost_beige);
+ else if (imac)
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_screamer_mic_boost_imac),
+ snd_pmac_screamer_mic_boost_imac);
+ else if (chip->model == PMAC_SCREAMER)
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_screamer_mic_boost),
+ snd_pmac_screamer_mic_boost);
+ else if (pm7500)
+ err = build_mixers(chip,
+ ARRAY_SIZE(snd_pmac_awacs_mic_boost_pmac7500),
+ snd_pmac_awacs_mic_boost_pmac7500);
+ else
+ err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost),
+ snd_pmac_awacs_mic_boost);
+ if (err < 0)
+ return err;
+
/*
* set lowlevel callbacks
*/
@@ -917,7 +1130,8 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
chip->resume = snd_pmac_awacs_resume;
#endif
#ifdef PMAC_SUPPORT_AUTOMUTE
- if ((err = snd_pmac_add_automute(chip)) < 0)
+ err = snd_pmac_add_automute(chip);
+ if (err < 0)
return err;
chip->detect_headphone = snd_pmac_awacs_detect_headphone;
chip->update_automute = snd_pmac_awacs_update_automute;
diff --git a/sound/ppc/awacs.h b/sound/ppc/awacs.h
index 1b2cc44eda5..c33e6a531cf 100644
--- a/sound/ppc/awacs.h
+++ b/sound/ppc/awacs.h
@@ -116,6 +116,11 @@ struct awacs_regs {
#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 */
@@ -139,7 +144,7 @@ struct awacs_regs {
#define VOLLEFT(x) (((~(x)) << 6) & MASK_OUTVOLLEFT)
/* address 6 */
-#define MASK_MIC_BOOST (0x4) /* screamer mic boost */
+#define MASK_MIC_BOOST (0x4) /* screamer mic boost */
#define SHIFT_MIC_BOOST 2
/* Audio Codec Status Reg Bit Masks */
@@ -152,8 +157,15 @@ struct awacs_regs {
#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_INPPORT (0xf) /* Input Port */
-#define MASK_HDPCONN 8 /* headphone plugged in */
+#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 */
/* -------- ----- --- --- ----- */
@@ -163,7 +175,8 @@ struct awacs_regs {
/* DBDMA ChannelStatus Bit Masks */
/* ----- ------------- --- ----- */
#define MASK_CSERR (0x1 << 7) /* Error */
-#define MASK_EOI (0x1 << 6) /* End of Input -- only for Input Channel */
+#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 */
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
index baa2a723737..0040f048221 100644
--- a/sound/ppc/beep.c
+++ b/sound/ppc/beep.c
@@ -185,7 +185,8 @@ static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
- snd_assert(chip->beep, return -ENXIO);
+ if (snd_BUG_ON(!chip->beep))
+ return -ENXIO;
ucontrol->value.integer.value[0] = chip->beep->volume;
return 0;
}
@@ -195,7 +196,8 @@ static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
unsigned int oval, nval;
- snd_assert(chip->beep, return -ENXIO);
+ if (snd_BUG_ON(!chip->beep))
+ return -ENXIO;
oval = chip->beep->volume;
nval = ucontrol->value.integer.value[0];
if (nval > 100)
@@ -213,7 +215,7 @@ static struct snd_kcontrol_new snd_pmac_beep_mixer = {
};
/* Initialize beep stuff */
-int __init snd_pmac_attach_beep(struct snd_pmac *chip)
+int snd_pmac_attach_beep(struct snd_pmac *chip)
{
struct pmac_beep *beep;
struct input_dev *input_dev;
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c
index 1a545ac0de0..cb4f0a5e984 100644
--- a/sound/ppc/burgundy.c
+++ b/sound/ppc/burgundy.c
@@ -21,7 +21,6 @@
#include <asm/io.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/delay.h>
#include <sound/core.h>
#include "pmac.h"
@@ -35,7 +34,7 @@ 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)
+ if (timeout < 0)
printk(KERN_DEBUG "burgundy_busy_wait: timeout\n");
}
@@ -46,12 +45,12 @@ snd_pmac_burgundy_extend_wait(struct snd_pmac *chip)
timeout = 50;
while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
udelay(1);
- if (! timeout)
+ 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)
+ if (timeout < 0)
printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n");
}
@@ -102,7 +101,8 @@ snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr)
}
static void
-snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr, unsigned int val)
+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);
@@ -126,8 +126,11 @@ snd_pmac_burgundy_rcb(struct snd_pmac *chip, unsigned int addr)
return val;
}
+#define BASE2ADDR(base) ((base) << 12)
+#define ADDR2BASE(addr) ((addr) >> 12)
+
/*
- * Burgundy volume: 0 - 100, stereo
+ * Burgundy volume: 0 - 100, stereo, word reg
*/
static void
snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address,
@@ -168,13 +171,6 @@ snd_pmac_burgundy_read_volume(struct snd_pmac *chip, unsigned int address,
volume[1] = 0;
}
-
-/*
- */
-
-#define BASE2ADDR(base) ((base) << 12)
-#define ADDR2BASE(addr) ((addr) >> 12)
-
static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -191,8 +187,8 @@ static int snd_pmac_burgundy_get_volume(struct snd_kcontrol *kcontrol,
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);
+ snd_pmac_burgundy_read_volume(chip, addr,
+ ucontrol->value.integer.value, shift);
return 0;
}
@@ -204,24 +200,163 @@ static int snd_pmac_burgundy_put_volume(struct snd_kcontrol *kcontrol,
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_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(xname, xindex, addr, shift) \
+#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)) }
-/* lineout/speaker */
+/*
+ * 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_info_switch_out(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+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;
@@ -231,111 +366,207 @@ static int snd_pmac_burgundy_info_switch_out(struct snd_kcontrol *kcontrol,
return 0;
}
-static int snd_pmac_burgundy_get_switch_out(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+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);
- int lmask = kcontrol->private_value & 0xff;
- int rmask = (kcontrol->private_value >> 8) & 0xff;
+ 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_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
+ 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_out(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+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);
- int lmask = kcontrol->private_value & 0xff;
- int rmask = (kcontrol->private_value >> 8) & 0xff;
+ 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_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
- val = oval & ~(lmask | rmask);
+ 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_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, val);
+ snd_pmac_burgundy_wcw(chip, addr, val);
return val != oval;
}
-#define BURGUNDY_OUTPUT_SWITCH(xname, xindex, lmask, rmask, stereo) \
+#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_out,\
- .get = snd_pmac_burgundy_get_switch_out,\
- .put = snd_pmac_burgundy_put_switch_out,\
- .private_value = ((lmask) | ((rmask) << 8) | ((stereo) << 24)) }
-
-/* line/speaker output volume */
-static int snd_pmac_burgundy_info_volume_out(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+ .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_INTEGER;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = stereo + 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 15;
+ uinfo->value.integer.max = 1;
return 0;
}
-static int snd_pmac_burgundy_get_volume_out(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+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 & 0xff);
+ 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 oval;
-
- oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff;
- ucontrol->value.integer.value[0] = oval & 0xf;
+ int val = snd_pmac_burgundy_rcb(chip, addr);
+ ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
if (stereo)
- ucontrol->value.integer.value[1] = (oval >> 4) & 0xf;
+ ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
return 0;
}
-static int snd_pmac_burgundy_put_volume_out(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+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 & 0xff);
+ 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;
- unsigned int oval, val;
-
- oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff;
- val = ucontrol->value.integer.value[0] & 15;
- if (stereo)
- val |= (ucontrol->value.integer.value[1] & 15) << 4;
- else
- val |= val << 4;
- val = ~val & 0xff;
+ 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_OUTPUT_VOLUME(xname, xindex, addr, stereo) \
+#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_volume_out,\
- .get = snd_pmac_burgundy_get_volume_out,\
- .put = snd_pmac_burgundy_put_volume_out,\
- .private_value = (ADDR2BASE(addr) | ((stereo) << 24)) }
-
-static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = {
- BURGUNDY_VOLUME("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
- BURGUNDY_VOLUME("Line Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16),
- BURGUNDY_VOLUME("CD Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLCD, 16),
- BURGUNDY_VOLUME("Mic Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16),
- BURGUNDY_OUTPUT_VOLUME("PC Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENHP, 0),
- /*BURGUNDY_OUTPUT_VOLUME("PCM Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1),*/
- BURGUNDY_OUTPUT_VOLUME("Headphone Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1),
-};
-static struct snd_kcontrol_new snd_pmac_burgundy_master_sw __initdata =
-BURGUNDY_OUTPUT_SWITCH("Headphone Playback Switch", 0, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw __initdata =
-BURGUNDY_OUTPUT_SWITCH("PC Speaker Playback Switch", 0, BURGUNDY_OUTPUT_INTERN, 0, 0);
+ .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
@@ -350,16 +581,26 @@ static int snd_pmac_burgundy_detect_headphone(struct snd_pmac *chip)
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 &= ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT | BURGUNDY_OUTPUT_INTERN);
+ 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 |= BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT;
+ reg |= imac ? (BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
+ : (BURGUNDY_OUTPUT_LEFT
+ | BURGUNDY_OUTPUT_RIGHT);
else
- reg |= BURGUNDY_OUTPUT_INTERN;
+ 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);
+ 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);
@@ -376,8 +617,9 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti
/*
* initialize burgundy
*/
-int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
+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 */
@@ -386,7 +628,7 @@ int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
return 1;
}
- snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES,
+ 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);
@@ -396,7 +638,8 @@ int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21,
DEF_BURGUNDY_INPSEL21);
snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3,
- DEF_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,
@@ -422,27 +665,62 @@ int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC,
DEF_BURGUNDY_VOLMIC);
- if (chip->hp_stat_mask == 0)
+ if (chip->hp_stat_mask == 0) {
/* set headphone-jack detection bit */
- chip->hp_stat_mask = 0x04;
-
+ 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++) {
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip))) < 0)
+ 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(&snd_pmac_burgundy_master_sw, chip);
- if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
+ 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;
- chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_speaker_sw, chip);
- if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
+ 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
- if ((err = snd_pmac_add_automute(chip)) < 0)
+ err = snd_pmac_add_automute(chip);
+ if (err < 0)
return err;
chip->detect_headphone = snd_pmac_burgundy_detect_headphone;
diff --git a/sound/ppc/burgundy.h b/sound/ppc/burgundy.h
index ebb457a8342..7a7f9cf3d29 100644
--- a/sound/ppc/burgundy.h
+++ b/sound/ppc/burgundy.h
@@ -22,6 +22,7 @@
#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)
@@ -35,7 +36,10 @@
#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)
@@ -45,6 +49,10 @@
#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)
@@ -59,21 +67,22 @@
/* These are all default values for the burgundy */
#define DEF_BURGUNDY_INPSEL21 (0xAA)
-#define DEF_BURGUNDY_INPSEL3 (0x0A)
+#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 */
+/* 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 (0x0A)
+#define DEF_BURGUNDY_OUTPUTSELECTS (0x010F010F)
+#define DEF_BURGUNDY_OUTPUTENABLES (0x0100000A)
/* #define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) */ /* too loud */
#define DEF_BURGUNDY_MASTER_VOLUME (0xDDDDDDDD)
@@ -84,12 +93,22 @@
#define DEF_BURGUNDY_ATTENLINEOUT (0xCC)
#define DEF_BURGUNDY_ATTENHP (0xCC)
-/* OUTPUTENABLES bits */
+/* 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
-/* volume offset */
+/* 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 */
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c
index ca9452901a5..b86526223e4 100644
--- a/sound/ppc/daca.c
+++ b/sound/ppc/daca.c
@@ -82,7 +82,7 @@ static int daca_set_volume(struct pmac_daca *mix)
data[1] |= mix->deemphasis ? 0x40 : 0;
if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
2, data) < 0) {
- snd_printk("failed to set volume \n");
+ snd_printk(KERN_ERR "failed to set volume \n");
return -EINVAL;
}
return 0;
@@ -244,14 +244,12 @@ static void daca_cleanup(struct snd_pmac *chip)
}
/* exported */
-int __init snd_pmac_daca_init(struct snd_pmac *chip)
+int snd_pmac_daca_init(struct snd_pmac *chip)
{
int i, err;
struct pmac_daca *mix;
-#ifdef CONFIG_KMOD
request_module("i2c-powermac");
-#endif /* CONFIG_KMOD */
mix = kzalloc(sizeof(*mix), GFP_KERNEL);
if (! mix)
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index 6ff99ed7751..0d1c27e911b 100644
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <sound/core.h>
#include "pmac.h"
@@ -33,73 +32,80 @@
static struct pmac_keywest *keywest_ctx;
-static int keywest_attach_adapter(struct i2c_adapter *adapter);
-static int keywest_detach_client(struct i2c_client *client);
-
-struct i2c_driver keywest_driver = {
- .driver = {
- .name = "PMac Keywest Audio",
- },
- .attach_adapter = &keywest_attach_adapter,
- .detach_client = &keywest_detach_client,
-};
-
-
-#ifndef i2c_device_name
-#define i2c_device_name(x) ((x)->name)
-#endif
+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)
{
- int err;
- struct i2c_client *new_client;
+ struct i2c_board_info info;
if (! keywest_ctx)
return -EINVAL;
- if (strncmp(i2c_device_name(adapter), "mac-io", 6))
+ if (strncmp(adapter->name, "mac-io", 6))
return 0; /* ignored */
- new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (! new_client)
- return -ENOMEM;
-
- new_client->addr = keywest_ctx->addr;
- i2c_set_clientdata(new_client, keywest_ctx);
- new_client->adapter = adapter;
- new_client->driver = &keywest_driver;
- new_client->flags = 0;
-
- strcpy(i2c_device_name(new_client), keywest_ctx->name);
- keywest_ctx->client = new_client;
-
- /* Tell the i2c layer a new client has arrived */
- if (i2c_attach_client(new_client)) {
- snd_printk(KERN_ERR "tumbler: cannot attach i2c client\n");
- err = -ENODEV;
- goto __err;
+ 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;
-
- __err:
- kfree(new_client);
- keywest_ctx->client = NULL;
- return err;
}
-static int keywest_detach_client(struct i2c_client *client)
+static int keywest_remove(struct i2c_client *client)
{
if (! keywest_ctx)
return 0;
if (client == keywest_ctx->client)
keywest_ctx->client = NULL;
- i2c_detach_client(client);
- kfree(client);
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)
{
@@ -109,7 +115,7 @@ void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c)
}
}
-int __init snd_pmac_tumbler_post_init(void)
+int snd_pmac_tumbler_post_init(void)
{
int err;
@@ -124,7 +130,7 @@ int __init snd_pmac_tumbler_post_init(void)
}
/* exported */
-int __init snd_pmac_keywest_init(struct pmac_keywest *i2c)
+int snd_pmac_keywest_init(struct pmac_keywest *i2c)
{
int err;
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 613a565e04d..7a43c0c3831 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -28,6 +28,8 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <sound/core.h>
#include "pmac.h"
#include <sound/pcm_params.h>
@@ -214,7 +216,7 @@ static int snd_pmac_pcm_prepare(struct snd_pmac *chip, struct pmac_stream *rec,
int rate_index;
long offset;
struct pmac_stream *astr;
-
+
rec->dma_size = snd_pcm_lib_buffer_bytes(subs);
rec->period_size = snd_pcm_lib_period_bytes(subs);
rec->nperiods = rec->dma_size / rec->period_size;
@@ -299,7 +301,7 @@ static int snd_pmac_pcm_trigger(struct snd_pmac *chip, struct pmac_stream *rec,
case SNDRV_PCM_TRIGGER_SUSPEND:
spin_lock(&chip->reg_lock);
rec->running = 0;
- /*printk("stopped!!\n");*/
+ /*printk(KERN_DEBUG "stopped!!\n");*/
snd_pmac_dma_stop(rec);
for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
out_le16(&cp->command, DBDMA_STOP);
@@ -334,7 +336,7 @@ static snd_pcm_uframes_t snd_pmac_pcm_pointer(struct snd_pmac *chip,
}
#endif
count += rec->cur_period * rec->period_size;
- /*printk("pointer=%d\n", count);*/
+ /*printk(KERN_DEBUG "pointer=%d\n", count);*/
return bytes_to_frames(subs->runtime, count);
}
@@ -486,7 +488,7 @@ static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec)
if (! (stat & ACTIVE))
break;
- /*printk("update frag %d\n", rec->cur_period);*/
+ /*printk(KERN_DEBUG "update frag %d\n", rec->cur_period);*/
st_le16(&cp->xfer_status, 0);
st_le16(&cp->req_count, rec->period_size);
/*st_le16(&cp->res_count, 0);*/
@@ -643,7 +645,7 @@ static int snd_pmac_pcm_close(struct snd_pmac *chip, struct pmac_stream *rec,
/* reset constraints */
astr->cur_freqs = chip->freqs_ok;
astr->cur_formats = chip->formats_ok;
-
+
return 0;
}
@@ -702,7 +704,7 @@ static struct snd_pcm_ops snd_pmac_capture_ops = {
.pointer = snd_pmac_capture_pointer,
};
-int __init snd_pmac_pcm_new(struct snd_pmac *chip)
+int snd_pmac_pcm_new(struct snd_pmac *chip)
{
struct snd_pcm *pcm;
int err;
@@ -806,7 +808,7 @@ snd_pmac_ctrl_intr(int irq, void *devid)
struct snd_pmac *chip = devid;
int ctrl = in_le32(&chip->awacs->control);
- /*printk("pmac: control interrupt.. 0x%x\n", ctrl);*/
+ /*printk(KERN_DEBUG "pmac: control interrupt.. 0x%x\n", ctrl);*/
if (ctrl & MASK_PORTCHG) {
/* do something when headphone is plugged/unplugged? */
if (chip->update_automute)
@@ -881,8 +883,7 @@ static int snd_pmac_free(struct snd_pmac *chip)
for (i = 0; i < 3; i++) {
if (chip->requested & (1 << i))
release_mem_region(chip->rsrc[i].start,
- chip->rsrc[i].end -
- chip->rsrc[i].start + 1);
+ resource_size(&chip->rsrc[i]));
}
}
@@ -908,7 +909,7 @@ static int snd_pmac_dev_free(struct snd_device *device)
* check the machine support byteswap (little-endian)
*/
-static void __init detect_byte_swap(struct snd_pmac *chip)
+static void detect_byte_swap(struct snd_pmac *chip)
{
struct device_node *mio;
@@ -922,11 +923,11 @@ static void __init detect_byte_swap(struct snd_pmac *chip)
}
/* it seems the Pismo & iBook can't byte-swap in hardware. */
- if (machine_is_compatible("PowerBook3,1") ||
- machine_is_compatible("PowerBook2,1"))
+ if (of_machine_is_compatible("PowerBook3,1") ||
+ of_machine_is_compatible("PowerBook2,1"))
chip->can_byte_swap = 0 ;
- if (machine_is_compatible("PowerBook2,1"))
+ if (of_machine_is_compatible("PowerBook2,1"))
chip->can_duplex = 0;
}
@@ -934,7 +935,7 @@ static void __init detect_byte_swap(struct snd_pmac *chip)
/*
* detect a sound chip
*/
-static int __init snd_pmac_detect(struct snd_pmac *chip)
+static int snd_pmac_detect(struct snd_pmac *chip)
{
struct device_node *sound;
struct device_node *dn;
@@ -959,11 +960,11 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */
/* check machine type */
- if (machine_is_compatible("AAPL,3400/2400")
- || machine_is_compatible("AAPL,3500"))
+ if (of_machine_is_compatible("AAPL,3400/2400")
+ || of_machine_is_compatible("AAPL,3500"))
chip->is_pbook_3400 = 1;
- else if (machine_is_compatible("PowerBook1,1")
- || machine_is_compatible("AAPL,PowerBook1998"))
+ else if (of_machine_is_compatible("PowerBook1,1")
+ || of_machine_is_compatible("AAPL,PowerBook1998"))
chip->is_pbook_G3 = 1;
chip->node = of_find_node_by_name(NULL, "awacs");
sound = of_node_get(chip->node);
@@ -1033,7 +1034,12 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
}
if (of_device_is_compatible(sound, "tumbler")) {
chip->model = PMAC_TUMBLER;
- chip->can_capture = 0; /* no capture */
+ chip->can_capture = of_machine_is_compatible("PowerMac4,2")
+ || of_machine_is_compatible("PowerBook3,2")
+ || of_machine_is_compatible("PowerBook3,3")
+ || of_machine_is_compatible("PowerBook4,1")
+ || of_machine_is_compatible("PowerBook4,2")
+ || of_machine_is_compatible("PowerBook4,3");
chip->can_duplex = 0;
// chip->can_byte_swap = 0; /* FIXME: check this */
chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
@@ -1142,7 +1148,7 @@ static int pmac_hp_detect_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new auto_mute_controls[] __initdata = {
+static struct snd_kcontrol_new auto_mute_controls[] = {
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Auto Mute Switch",
.info = snd_pmac_boolean_mono_info,
@@ -1157,7 +1163,7 @@ static struct snd_kcontrol_new auto_mute_controls[] __initdata = {
},
};
-int __init snd_pmac_add_automute(struct snd_pmac *chip)
+int snd_pmac_add_automute(struct snd_pmac *chip)
{
int err;
chip->auto_mute = 1;
@@ -1174,7 +1180,7 @@ int __init snd_pmac_add_automute(struct snd_pmac *chip)
/*
* create and detect a pmac chip record
*/
-int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
+int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
{
struct snd_pmac *chip;
struct device_node *np;
@@ -1223,14 +1229,11 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
goto __error;
}
if (request_mem_region(chip->rsrc[i].start,
- chip->rsrc[i].end -
- chip->rsrc[i].start + 1,
+ resource_size(&chip->rsrc[i]),
rnames[i]) == NULL) {
printk(KERN_ERR "snd: can't request rsrc "
- " %d (%s: 0x%016llx:%016llx)\n",
- i, rnames[i],
- (unsigned long long)chip->rsrc[i].start,
- (unsigned long long)chip->rsrc[i].end);
+ " %d (%s: %pR)\n",
+ i, rnames[i], &chip->rsrc[i]);
err = -ENODEV;
goto __error;
}
@@ -1251,14 +1254,11 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
goto __error;
}
if (request_mem_region(chip->rsrc[i].start,
- chip->rsrc[i].end -
- chip->rsrc[i].start + 1,
+ resource_size(&chip->rsrc[i]),
rnames[i]) == NULL) {
printk(KERN_ERR "snd: can't request rsrc "
- " %d (%s: 0x%016llx:%016llx)\n",
- i, rnames[i],
- (unsigned long long)chip->rsrc[i].start,
- (unsigned long long)chip->rsrc[i].end);
+ " %d (%s: %pR)\n",
+ i, rnames[i], &chip->rsrc[i]);
err = -ENODEV;
goto __error;
}
@@ -1300,9 +1300,9 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
snd_pmac_sound_feature(chip, 1);
- /* reset */
- if (chip->model == PMAC_AWACS)
- out_le32(&chip->awacs->control, 0x11);
+ /* reset & enable interrupts */
+ if (chip->model <= PMAC_BURGUNDY)
+ out_le32(&chip->awacs->control, chip->control_mask);
/* Powerbooks have odd ways of enabling inputs such as
an expansion-bay CD or sound from an internal modem
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
index c936225771b..350a7c8f86d 100644
--- a/sound/ppc/powermac.c
+++ b/sound/ppc/powermac.c
@@ -21,7 +21,7 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
#include "pmac.h"
@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
-static int enable_beep = 1;
+static bool enable_beep = 1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for " CHIP_NAME " soundchip.");
@@ -51,16 +51,16 @@ static struct platform_device *device;
/*
*/
-static int __init snd_pmac_probe(struct platform_device *devptr)
+static int snd_pmac_probe(struct platform_device *devptr)
{
struct snd_card *card;
struct snd_pmac *chip;
char *name_ext;
int err;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ 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;
@@ -110,7 +110,7 @@ static int __init snd_pmac_probe(struct platform_device *devptr)
goto __error;
break;
default:
- snd_printk("unsupported hardware %d\n", chip->model);
+ snd_printk(KERN_ERR "unsupported hardware %d\n", chip->model);
err = -EINVAL;
goto __error;
}
@@ -122,8 +122,6 @@ static int __init snd_pmac_probe(struct platform_device *devptr)
if (enable_beep)
snd_pmac_attach_beep(chip);
- snd_card_set_dev(card, &devptr->dev);
-
if ((err = snd_card_register(card)) < 0)
goto __error;
@@ -136,40 +134,42 @@ __error:
}
-static int __devexit snd_pmac_remove(struct platform_device *devptr)
+static int snd_pmac_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
return 0;
}
-#ifdef CONFIG_PM
-static int snd_pmac_driver_suspend(struct platform_device *devptr, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int snd_pmac_driver_suspend(struct device *dev)
{
- struct snd_card *card = platform_get_drvdata(devptr);
+ struct snd_card *card = dev_get_drvdata(dev);
snd_pmac_suspend(card->private_data);
return 0;
}
-static int snd_pmac_driver_resume(struct platform_device *devptr)
+static int snd_pmac_driver_resume(struct device *dev)
{
- struct snd_card *card = platform_get_drvdata(devptr);
+ 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 = __devexit_p(snd_pmac_remove),
-#ifdef CONFIG_PM
- .suspend = snd_pmac_driver_suspend,
- .resume = snd_pmac_driver_resume,
-#endif
+ .remove = snd_pmac_remove,
.driver = {
- .name = SND_PMAC_DRIVER
+ .name = SND_PMAC_DRIVER,
+ .owner = THIS_MODULE,
+ .pm = SND_PMAC_PM_OPS,
},
};
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index d8d0b4b2395..58f292a87f9 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -18,80 +18,31 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/gfp.h>
#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include <sound/asound.h>
+#include <sound/control.h>
#include <sound/core.h>
#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/asound.h>
#include <sound/memalloc.h>
+#include <sound/pcm.h>
#include <sound/pcm_params.h>
-#include <sound/control.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <asm/firmware.h>
+
#include <asm/dma.h>
+#include <asm/firmware.h>
#include <asm/lv1call.h>
#include <asm/ps3.h>
#include <asm/ps3av.h>
-#include "snd_ps3_reg.h"
#include "snd_ps3.h"
+#include "snd_ps3_reg.h"
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PS3 sound driver");
-MODULE_AUTHOR("Sony Computer Entertainment Inc.");
-
-/* module entries */
-static int __init snd_ps3_init(void);
-static void __exit snd_ps3_exit(void);
-
-/* ALSA snd driver ops */
-static int snd_ps3_pcm_open(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_close(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
- int cmd);
-static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream
- *substream);
-static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params);
-static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream);
-
-
-/* ps3_system_bus_driver entries */
-static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev);
-static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev);
-
-/* address setup */
-static int snd_ps3_map_mmio(void);
-static void snd_ps3_unmap_mmio(void);
-static int snd_ps3_allocate_irq(void);
-static void snd_ps3_free_irq(void);
-static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start);
-
-/* interrupt handler */
-static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id);
-
-
-/* set sampling rate/format */
-static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream);
-/* take effect parameter change */
-static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card);
-/* initialize avsetting and take it effect */
-static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card);
-/* setup dma */
-static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
- enum snd_ps3_dma_filltype filltype);
-static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card);
-
-static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void *vaddr, int ch);
-
-
-module_init(snd_ps3_init);
-module_exit(snd_ps3_exit);
/*
* global
@@ -101,7 +52,7 @@ static struct snd_ps3_card_info the_card;
static int snd_ps3_start_delay = CONFIG_SND_PS3_DEFAULT_START_DELAY;
module_param_named(start_delay, snd_ps3_start_delay, uint, 0644);
-MODULE_PARM_DESC(start_delay, "time to insert silent data in milisec");
+MODULE_PARM_DESC(start_delay, "time to insert silent data in ms");
static int index = SNDRV_DEFAULT_IDX1;
static char *id = SNDRV_DEFAULT_STR1;
@@ -137,7 +88,7 @@ static inline void update_mask_reg(unsigned int reg, u32 mask, u32 or_val)
/*
* ALSA defs
*/
-const static struct snd_pcm_hardware snd_ps3_pcm_hw = {
+static const struct snd_pcm_hardware snd_ps3_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_NONINTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
@@ -165,25 +116,13 @@ const static struct snd_pcm_hardware snd_ps3_pcm_hw = {
.fifo_size = PS3_AUDIO_FIFO_SIZE
};
-static struct snd_pcm_ops snd_ps3_pcm_spdif_ops =
-{
- .open = snd_ps3_pcm_open,
- .close = snd_ps3_pcm_close,
- .prepare = snd_ps3_pcm_prepare,
- .ioctl = snd_pcm_lib_ioctl,
- .trigger = snd_ps3_pcm_trigger,
- .pointer = snd_ps3_pcm_pointer,
- .hw_params = snd_ps3_pcm_hw_params,
- .hw_free = snd_ps3_pcm_hw_free
-};
-
static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card,
int count, int force_stop)
{
int dma_ch, done, retries, stop_forced = 0;
uint32_t status;
- for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+ for (dma_ch = 0; dma_ch < 8; dma_ch++) {
retries = count;
do {
status = read_reg(PS3_AUDIO_KICK(dma_ch)) &
@@ -259,9 +198,7 @@ static void snd_ps3_kick_dma(struct snd_ps3_card_info *card)
/*
* convert virtual addr to ioif bus addr.
*/
-static dma_addr_t v_to_bus(struct snd_ps3_card_info *card,
- void * paddr,
- int ch)
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *card, void *paddr, int ch)
{
return card->dma_start_bus_addr[ch] +
(paddr - card->dma_start_vaddr[ch]);
@@ -321,7 +258,7 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
spin_lock_irqsave(&card->dma_lock, irqsave);
for (ch = 0; ch < 2; ch++) {
start_vaddr = card->dma_next_transfer_vaddr[0];
- for (stage = 0; stage < fill_stages; stage ++) {
+ for (stage = 0; stage < fill_stages; stage++) {
dma_ch = stage * 2 + ch;
if (silent)
dma_addr = card->null_buffer_start_dma_addr;
@@ -372,6 +309,71 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
}
/*
+ * Interrupt handler
+ */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
+{
+
+ uint32_t port_intr;
+ int underflow_occured = 0;
+ struct snd_ps3_card_info *card = dev_id;
+
+ if (!card->running) {
+ update_reg(PS3_AUDIO_AX_IS, 0);
+ update_reg(PS3_AUDIO_INTR_0, 0);
+ return IRQ_HANDLED;
+ }
+
+ port_intr = read_reg(PS3_AUDIO_AX_IS);
+ /*
+ *serial buffer empty detected (every 4 times),
+ *program next dma and kick it
+ */
+ if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
+ write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
+ if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+ write_reg(PS3_AUDIO_AX_IS, port_intr);
+ underflow_occured = 1;
+ }
+ if (card->silent) {
+ /* we are still in silent time */
+ snd_ps3_program_dma(card,
+ (underflow_occured) ?
+ SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
+ SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+ snd_ps3_kick_dma(card);
+ card->silent--;
+ } else {
+ snd_ps3_program_dma(card,
+ (underflow_occured) ?
+ SND_PS3_DMA_FILLTYPE_FIRSTFILL :
+ SND_PS3_DMA_FILLTYPE_RUNNING);
+ snd_ps3_kick_dma(card);
+ snd_pcm_period_elapsed(card->substream);
+ }
+ } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+ write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
+ /*
+ * serial out underflow, but buffer empty not detected.
+ * in this case, fill fifo with 0 to recover. After
+ * filling dummy data, serial automatically start to
+ * consume them and then will generate normal buffer
+ * empty interrupts.
+ * If both buffer underflow and buffer empty are occurred,
+ * it is better to do nomal data transfer than empty one
+ */
+ snd_ps3_program_dma(card,
+ SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+ snd_ps3_kick_dma(card);
+ snd_ps3_program_dma(card,
+ SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+ snd_ps3_kick_dma(card);
+ }
+ /* clear interrupt cause */
+ return IRQ_HANDLED;
+};
+
+/*
* audio mute on/off
* mute_on : 0 output enabled
* 1 mute
@@ -382,6 +384,142 @@ static int snd_ps3_mute(int mute_on)
}
/*
+ * av setting
+ * NOTE: calling this function may generate audio interrupt.
+ */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
+{
+ int ret, retries, i;
+ pr_debug("%s: start\n", __func__);
+
+ ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
+ card->avs.avs_audio_rate,
+ card->avs.avs_audio_width,
+ card->avs.avs_audio_format,
+ card->avs.avs_audio_source);
+ /*
+ * Reset the following unwanted settings:
+ */
+
+ /* disable all 3wire buffers */
+ update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+ ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
+ 0);
+ wmb(); /* ensure the hardware sees the change */
+ /* wait for actually stopped */
+ retries = 1000;
+ while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
+ (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
+ --retries) {
+ udelay(1);
+ }
+
+ /* reset buffer pointer */
+ for (i = 0; i < 4; i++) {
+ update_reg(PS3_AUDIO_AO_3WCTRL(i),
+ PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
+ udelay(10);
+ }
+ wmb(); /* ensure the hardware actually start resetting */
+
+ /* enable 3wire#0 buffer */
+ update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
+
+
+ /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
+ update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
+ ~PS3_AUDIO_AO_3WCTRL_ASODF,
+ PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
+ update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
+ ~PS3_AUDIO_AO_SPDCTRL_SPODF,
+ PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
+ /* ensure all the setting above is written back to register */
+ wmb();
+ /* avsetting driver altered AX_IE, caller must reset it if you want */
+ pr_debug("%s: end\n", __func__);
+ return ret;
+}
+
+/*
+ * set sampling rate according to the substream
+ */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+{
+ struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+ struct snd_ps3_avsetting_info avs;
+ int ret;
+
+ avs = card->avs;
+
+ pr_debug("%s: called freq=%d width=%d\n", __func__,
+ substream->runtime->rate,
+ snd_pcm_format_width(substream->runtime->format));
+
+ pr_debug("%s: before freq=%d width=%d\n", __func__,
+ card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+ /* sample rate */
+ switch (substream->runtime->rate) {
+ case 44100:
+ avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
+ break;
+ case 48000:
+ avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+ break;
+ case 88200:
+ avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
+ break;
+ case 96000:
+ avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
+ break;
+ default:
+ pr_info("%s: invalid rate %d\n", __func__,
+ substream->runtime->rate);
+ return 1;
+ }
+
+ /* width */
+ switch (snd_pcm_format_width(substream->runtime->format)) {
+ case 16:
+ avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+ break;
+ case 24:
+ avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
+ break;
+ default:
+ pr_info("%s: invalid width %d\n", __func__,
+ snd_pcm_format_width(substream->runtime->format));
+ return 1;
+ }
+
+ memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8);
+
+ if (memcmp(&card->avs, &avs, sizeof(avs))) {
+ pr_debug("%s: after freq=%d width=%d\n", __func__,
+ card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+ card->avs = avs;
+ snd_ps3_change_avsetting(card);
+ ret = 0;
+ } else
+ ret = 1;
+
+ /* check CS non-audio bit and mute accordingly */
+ if (avs.avs_cs_info[0] & 0x02)
+ ps3av_audio_mute_analog(1); /* mute if non-audio */
+ else
+ ps3av_audio_mute_analog(0);
+
+ return ret;
+}
+
+/*
* PCM operators
*/
static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
@@ -406,6 +544,13 @@ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
return 0;
};
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
+{
+ /* mute on */
+ snd_ps3_mute(1);
+ return 0;
+};
+
static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
@@ -417,6 +562,13 @@ static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
return 0;
};
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ int ret;
+ ret = snd_pcm_lib_free_pages(substream);
+ return ret;
+};
+
static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
unsigned int delay_ms)
{
@@ -428,7 +580,7 @@ static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
rate * delay_ms / 1000)
* substream->runtime->channels;
- pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n",
+ pr_debug("%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n",
__func__,
delay_ms,
rate,
@@ -477,7 +629,7 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
card->dma_start_bus_addr[SND_PS3_CH_R] =
runtime->dma_addr + (runtime->dma_bytes / 2);
- pr_debug("%s: vaddr=%p bus=%#lx\n", __func__,
+ pr_debug("%s: vaddr=%p bus=%#llx\n", __func__,
card->dma_start_vaddr[SND_PS3_CH_L],
card->dma_start_bus_addr[SND_PS3_CH_L]);
@@ -556,192 +708,82 @@ static snd_pcm_uframes_t snd_ps3_pcm_pointer(
return ret;
};
-static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- int ret;
- ret = snd_pcm_lib_free_pages(substream);
- return ret;
-};
-
-static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
+/*
+ * SPDIF status bits controls
+ */
+static int snd_ps3_spdif_mask_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
- /* mute on */
- snd_ps3_mute(1);
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
return 0;
-};
+}
-static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
+/* FIXME: ps3av_set_audio_mode() assumes only consumer mode */
+static int snd_ps3_spdif_cmask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- /*
- * avsetting driver seems to never change the followings
- * so, init them here once
- */
-
- /* no dma interrupt needed */
- write_reg(PS3_AUDIO_INTR_EN_0, 0);
-
- /* use every 4 buffer empty interrupt */
- update_mask_reg(PS3_AUDIO_AX_IC,
- PS3_AUDIO_AX_IC_AASOIMD_MASK,
- PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
-
- /* enable 3wire clocks */
- update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
- ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
- PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
- 0);
- update_reg(PS3_AUDIO_AO_3WMCTRL,
- PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
+ memset(ucontrol->value.iec958.status, 0xff, 8);
+ return 0;
}
-/*
- * av setting
- * NOTE: calling this function may generate audio interrupt.
- */
-static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
+static int snd_ps3_spdif_pmask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- int ret, retries, i;
- pr_debug("%s: start\n", __func__);
-
- ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
- card->avs.avs_audio_rate,
- card->avs.avs_audio_width,
- card->avs.avs_audio_format,
- card->avs.avs_audio_source);
- /*
- * Reset the following unwanted settings:
- */
-
- /* disable all 3wire buffers */
- update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
- ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
- PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
- PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
- PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
- 0);
- wmb(); /* ensure the hardware sees the change */
- /* wait for actually stopped */
- retries = 1000;
- while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
- (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
- PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
- PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
- PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
- --retries) {
- udelay(1);
- }
-
- /* reset buffer pointer */
- for (i = 0; i < 4; i++) {
- update_reg(PS3_AUDIO_AO_3WCTRL(i),
- PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
- udelay(10);
- }
- wmb(); /* ensure the hardware actually start resetting */
-
- /* enable 3wire#0 buffer */
- update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
-
-
- /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
- update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
- ~PS3_AUDIO_AO_3WCTRL_ASODF,
- PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
- update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
- ~PS3_AUDIO_AO_SPDCTRL_SPODF,
- PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
- /* ensure all the setting above is written back to register */
- wmb();
- /* avsetting driver altered AX_IE, caller must reset it if you want */
- pr_debug("%s: end\n", __func__);
- return ret;
+ return 0;
}
-static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
+static int snd_ps3_spdif_default_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- int ret;
- pr_debug("%s: start\n", __func__);
- card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
- card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
- card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
- card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
- card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
-
- ret = snd_ps3_change_avsetting(card);
-
- snd_ps3_audio_fixup(card);
-
- /* to start to generate SPDIF signal, fill data */
- snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
- snd_ps3_kick_dma(card);
- pr_debug("%s: end\n", __func__);
- return ret;
+ memcpy(ucontrol->value.iec958.status, ps3av_mode_cs_info, 8);
+ return 0;
}
-/*
- * set sampling rate according to the substream
- */
-static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+static int snd_ps3_spdif_default_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
- struct snd_ps3_avsetting_info avs;
-
- avs = card->avs;
-
- pr_debug("%s: called freq=%d width=%d\n", __func__,
- substream->runtime->rate,
- snd_pcm_format_width(substream->runtime->format));
-
- pr_debug("%s: before freq=%d width=%d\n", __func__,
- card->avs.avs_audio_rate, card->avs.avs_audio_width);
-
- /* sample rate */
- switch (substream->runtime->rate) {
- case 44100:
- avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
- break;
- case 48000:
- avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
- break;
- case 88200:
- avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
- break;
- case 96000:
- avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
- break;
- default:
- pr_info("%s: invalid rate %d\n", __func__,
- substream->runtime->rate);
- return 1;
- }
-
- /* width */
- switch (snd_pcm_format_width(substream->runtime->format)) {
- case 16:
- avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
- break;
- case 24:
- avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
- break;
- default:
- pr_info("%s: invalid width %d\n", __func__,
- snd_pcm_format_width(substream->runtime->format));
+ if (memcmp(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8)) {
+ memcpy(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8);
return 1;
}
-
- if ((card->avs.avs_audio_width != avs.avs_audio_width) ||
- (card->avs.avs_audio_rate != avs.avs_audio_rate)) {
- card->avs = avs;
- snd_ps3_change_avsetting(card);
-
- pr_debug("%s: after freq=%d width=%d\n", __func__,
- card->avs.avs_audio_rate, card->avs.avs_audio_width);
-
- return 0;
- } else
- return 1;
+ return 0;
}
+static struct snd_kcontrol_new spdif_ctls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
+ .info = snd_ps3_spdif_mask_info,
+ .get = snd_ps3_spdif_cmask_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
+ .info = snd_ps3_spdif_mask_info,
+ .get = snd_ps3_spdif_pmask_get,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = snd_ps3_spdif_mask_info,
+ .get = snd_ps3_spdif_default_get,
+ .put = snd_ps3_spdif_default_put,
+ },
+};
+
+static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = {
+ .open = snd_ps3_pcm_open,
+ .close = snd_ps3_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_ps3_pcm_hw_params,
+ .hw_free = snd_ps3_pcm_hw_free,
+ .prepare = snd_ps3_pcm_prepare,
+ .trigger = snd_ps3_pcm_trigger,
+ .pointer = snd_ps3_pcm_pointer,
+};
static int snd_ps3_map_mmio(void)
@@ -804,7 +846,7 @@ static int snd_ps3_allocate_irq(void)
return ret;
}
- ret = request_irq(the_card.irq_no, snd_ps3_interrupt, IRQF_DISABLED,
+ ret = request_irq(the_card.irq_no, snd_ps3_interrupt, 0,
SND_PS3_DRIVER_NAME, &the_card);
if (ret) {
pr_info("%s: request_irq failed (%d)\n", __func__, ret);
@@ -834,19 +876,67 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
(0x0fUL << 12) |
(PS3_AUDIO_IOID);
- ret = lv1_gpu_attribute(0x100, 0x007, val, 0, 0);
+ ret = lv1_gpu_attribute(0x100, 0x007, val);
if (ret)
pr_info("%s: gpu_attribute failed %d\n", __func__,
ret);
}
-static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
+static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
+{
+ /*
+ * avsetting driver seems to never change the followings
+ * so, init them here once
+ */
+
+ /* no dma interrupt needed */
+ write_reg(PS3_AUDIO_INTR_EN_0, 0);
+
+ /* use every 4 buffer empty interrupt */
+ update_mask_reg(PS3_AUDIO_AX_IC,
+ PS3_AUDIO_AX_IC_AASOIMD_MASK,
+ PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
+
+ /* enable 3wire clocks */
+ update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+ ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
+ PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
+ 0);
+ update_reg(PS3_AUDIO_AO_3WMCTRL,
+ PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
+}
+
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
{
int ret;
+ pr_debug("%s: start\n", __func__);
+ card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
+ card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+ card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+ card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
+ card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
+ memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8);
+
+ ret = snd_ps3_change_avsetting(card);
+
+ snd_ps3_audio_fixup(card);
+
+ /* to start to generate SPDIF signal, fill data */
+ snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+ snd_ps3_kick_dma(card);
+ pr_debug("%s: end\n", __func__);
+ return ret;
+}
+
+static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
+{
+ int i, ret;
u64 lpar_addr, lpar_size;
- BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1));
- BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND);
+ if (WARN_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)))
+ return -ENODEV;
+ if (WARN_ON(dev->match_id != PS3_MATCH_ID_SOUND))
+ return -ENODEV;
the_card.ps3_dev = dev;
@@ -894,15 +984,23 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
}
/* create card instance */
- the_card.card = snd_card_new(index, id, THIS_MODULE, 0);
- if (!the_card.card) {
- ret = -ENXIO;
+ ret = snd_card_new(&dev->core, index, id, THIS_MODULE,
+ 0, &the_card.card);
+ if (ret < 0)
goto clean_irq;
- }
strcpy(the_card.card->driver, "PS3");
strcpy(the_card.card->shortname, "PS3");
strcpy(the_card.card->longname, "PS3 sound");
+
+ /* create control elements */
+ for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) {
+ ret = snd_ctl_add(the_card.card,
+ snd_ctl_new1(&spdif_ctls[i], &the_card));
+ if (ret < 0)
+ goto clean_card;
+ }
+
/* create PCM devices instance */
/* NOTE:this driver works assuming pcm:substream = 1:1 */
ret = snd_pcm_new(the_card.card,
@@ -938,22 +1036,23 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
* its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2
* PAGE_SIZE is enogh
*/
- if (!(the_card.null_buffer_start_vaddr =
- dma_alloc_coherent(&the_card.ps3_dev->core,
- PAGE_SIZE,
- &the_card.null_buffer_start_dma_addr,
- GFP_KERNEL))) {
+ the_card.null_buffer_start_vaddr =
+ dma_alloc_coherent(&the_card.ps3_dev->core,
+ PAGE_SIZE,
+ &the_card.null_buffer_start_dma_addr,
+ GFP_KERNEL);
+ if (!the_card.null_buffer_start_vaddr) {
pr_info("%s: nullbuffer alloc failed\n", __func__);
+ ret = -ENOMEM;
goto clean_preallocate;
}
- pr_debug("%s: null vaddr=%p dma=%#lx\n", __func__,
+ pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__,
the_card.null_buffer_start_vaddr,
the_card.null_buffer_start_dma_addr);
/* set default sample rate/word width */
snd_ps3_init_avsetting(&the_card);
/* register the card */
- snd_card_set_dev(the_card.card, &dev->core);
ret = snd_card_register(the_card.card);
if (ret < 0)
goto clean_dma_map;
@@ -1033,71 +1132,6 @@ static struct ps3_system_bus_driver snd_ps3_bus_driver_info = {
/*
- * Interrupt handler
- */
-static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
-{
-
- uint32_t port_intr;
- int underflow_occured = 0;
- struct snd_ps3_card_info *card = dev_id;
-
- if (!card->running) {
- update_reg(PS3_AUDIO_AX_IS, 0);
- update_reg(PS3_AUDIO_INTR_0, 0);
- return IRQ_HANDLED;
- }
-
- port_intr = read_reg(PS3_AUDIO_AX_IS);
- /*
- *serial buffer empty detected (every 4 times),
- *program next dma and kick it
- */
- if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
- write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
- if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
- write_reg(PS3_AUDIO_AX_IS, port_intr);
- underflow_occured = 1;
- }
- if (card->silent) {
- /* we are still in silent time */
- snd_ps3_program_dma(card,
- (underflow_occured) ?
- SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
- SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
- snd_ps3_kick_dma(card);
- card->silent --;
- } else {
- snd_ps3_program_dma(card,
- (underflow_occured) ?
- SND_PS3_DMA_FILLTYPE_FIRSTFILL :
- SND_PS3_DMA_FILLTYPE_RUNNING);
- snd_ps3_kick_dma(card);
- snd_pcm_period_elapsed(card->substream);
- }
- } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
- write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
- /*
- * serial out underflow, but buffer empty not detected.
- * in this case, fill fifo with 0 to recover. After
- * filling dummy data, serial automatically start to
- * consume them and then will generate normal buffer
- * empty interrupts.
- * If both buffer underflow and buffer empty are occured,
- * it is better to do nomal data transfer than empty one
- */
- snd_ps3_program_dma(card,
- SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
- snd_ps3_kick_dma(card);
- snd_ps3_program_dma(card,
- SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
- snd_ps3_kick_dma(card);
- }
- /* clear interrupt cause */
- return IRQ_HANDLED;
-};
-
-/*
* module/subsystem initialize/terminate
*/
static int __init snd_ps3_init(void)
@@ -1115,10 +1149,15 @@ static int __init snd_ps3_init(void)
return ret;
}
+module_init(snd_ps3_init);
static void __exit snd_ps3_exit(void)
{
ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info);
}
+module_exit(snd_ps3_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 sound driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND);
diff --git a/sound/ppc/snd_ps3.h b/sound/ppc/snd_ps3.h
index 4b7e6fbbe50..326fb29e82d 100644
--- a/sound/ppc/snd_ps3.h
+++ b/sound/ppc/snd_ps3.h
@@ -51,6 +51,7 @@ struct snd_ps3_avsetting_info {
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
diff --git a/sound/ppc/snd_ps3_reg.h b/sound/ppc/snd_ps3_reg.h
index 03fdee4aaaf..2e630207956 100644
--- a/sound/ppc/snd_ps3_reg.h
+++ b/sound/ppc/snd_ps3_reg.h
@@ -125,7 +125,7 @@
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 prefered to wait
+ 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 */
@@ -316,13 +316,13 @@ DISABLED=Interrupt generation disabled.
/*
Audio Port Interrupt Status Register
-Indicates Interrupt status, which interrupt has occured, and can clear
+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 occured.
-1 - Interrupt has occured.
+0 - Interrupt hasn't occurred.
+1 - Interrupt has occurred.
31 24 23 16 15 8 7 0
@@ -473,7 +473,7 @@ Channel N is out of action by setting 0 to asoen.
/*
Sampling Rate
Specifies the divide ratio of the bit clock (clock output
-from bclko) used by the 3-wire Audio Output Clock, whcih
+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.
*/
@@ -756,7 +756,7 @@ 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 occured.
+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.
@@ -824,7 +824,7 @@ AUDIOFIFO = Audio WriteData FIFO,
/*
PS3_AUDIO_DMASIZE specifies the number of 128-byte blocks + 1 to transfer.
-So a value of 0 means 128-bytes will get transfered.
+So a value of 0 means 128-bytes will get transferred.
31 24 23 16 15 8 7 0
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 3f8d7164cef..b9ffc17a479 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -30,6 +30,8 @@
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/of_irq.h>
#include <sound/core.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -41,11 +43,13 @@
#undef DEBUG
#ifdef DEBUG
-#define DBG(fmt...) printk(fmt)
+#define DBG(fmt...) printk(KERN_DEBUG fmt)
#else
#define DBG(fmt...)
#endif
+#define IS_G4DA (of_machine_is_compatible("PowerMac3,4"))
+
/* i2c address for tumbler */
#define TAS_I2C_ADDR 0x34
@@ -240,9 +244,10 @@ static int tumbler_set_master_volume(struct pmac_tumbler *mix)
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_VOL, 6,
block) < 0) {
- snd_printk("failed to set volume \n");
+ snd_printk(KERN_ERR "failed to set volume \n");
return -EINVAL;
}
+ DBG("(I) succeeded to set volume (%u, %u)\n", left_vol, right_vol);
return 0;
}
@@ -263,7 +268,7 @@ static int tumbler_get_master_volume(struct snd_kcontrol *kcontrol,
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_tumbler *mix = chip->mixer_data;
- snd_assert(mix, return -ENODEV);
+
ucontrol->value.integer.value[0] = mix->master_vol[0];
ucontrol->value.integer.value[1] = mix->master_vol[1];
return 0;
@@ -277,7 +282,6 @@ static int tumbler_put_master_volume(struct snd_kcontrol *kcontrol,
unsigned int vol[2];
int change;
- snd_assert(mix, return -ENODEV);
vol[0] = ucontrol->value.integer.value[0];
vol[1] = ucontrol->value.integer.value[1];
if (vol[0] >= ARRAY_SIZE(master_volume_table) ||
@@ -299,7 +303,7 @@ static int tumbler_get_master_switch(struct snd_kcontrol *kcontrol,
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_tumbler *mix = chip->mixer_data;
- snd_assert(mix, return -ENODEV);
+
ucontrol->value.integer.value[0] = mix->master_switch[0];
ucontrol->value.integer.value[1] = mix->master_switch[1];
return 0;
@@ -312,7 +316,6 @@ static int tumbler_put_master_switch(struct snd_kcontrol *kcontrol,
struct pmac_tumbler *mix = chip->mixer_data;
int change;
- snd_assert(mix, return -ENODEV);
change = mix->master_switch[0] != ucontrol->value.integer.value[0] ||
mix->master_switch[1] != ucontrol->value.integer.value[1];
if (change) {
@@ -352,9 +355,10 @@ static int tumbler_set_drc(struct pmac_tumbler *mix)
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_DRC,
2, val) < 0) {
- snd_printk("failed to set DRC\n");
+ snd_printk(KERN_ERR "failed to set DRC\n");
return -EINVAL;
}
+ DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]);
return 0;
}
@@ -388,9 +392,10 @@ static int snapper_set_drc(struct pmac_tumbler *mix)
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_DRC,
6, val) < 0) {
- snd_printk("failed to set DRC\n");
+ snd_printk(KERN_ERR "failed to set DRC\n");
return -EINVAL;
}
+ DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]);
return 0;
}
@@ -508,7 +513,8 @@ static int tumbler_set_mono_volume(struct pmac_tumbler *mix,
block[i] = (vol >> ((info->bytes - i - 1) * 8)) & 0xff;
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, info->reg,
info->bytes, block) < 0) {
- snd_printk("failed to set mono volume %d\n", info->index);
+ snd_printk(KERN_ERR "failed to set mono volume %d\n",
+ info->index);
return -EINVAL;
}
return 0;
@@ -645,7 +651,7 @@ static int snapper_set_mix_vol1(struct pmac_tumbler *mix, int idx, int ch, int r
}
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, reg,
9, block) < 0) {
- snd_printk("failed to set mono volume %d\n", reg);
+ snd_printk(KERN_ERR "failed to set mono volume %d\n", reg);
return -EINVAL;
}
return 0;
@@ -780,7 +786,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix)
if (! mix->i2c.client)
return -ENODEV;
if (mix->capture_source)
- mix->acs = mix->acs |= 2;
+ mix->acs |= 2;
else
mix->acs &= ~2;
return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);
@@ -807,7 +813,6 @@ static int snapper_get_capture_source(struct snd_kcontrol *kcontrol,
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
struct pmac_tumbler *mix = chip->mixer_data;
- snd_assert(mix, return -ENODEV);
ucontrol->value.enumerated.item[0] = mix->capture_source;
return 0;
}
@@ -819,7 +824,6 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol,
struct pmac_tumbler *mix = chip->mixer_data;
int change;
- snd_assert(mix, return -ENODEV);
change = ucontrol->value.enumerated.item[0] != mix->capture_source;
if (change) {
mix->capture_source = !!ucontrol->value.enumerated.item[0];
@@ -841,7 +845,7 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol,
/*
*/
-static struct snd_kcontrol_new tumbler_mixers[] __initdata = {
+static struct snd_kcontrol_new tumbler_mixers[] = {
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Volume",
.info = tumbler_info_master_volume,
@@ -865,7 +869,7 @@ static struct snd_kcontrol_new tumbler_mixers[] __initdata = {
},
};
-static struct snd_kcontrol_new snapper_mixers[] __initdata = {
+static struct snd_kcontrol_new snapper_mixers[] = {
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Volume",
.info = tumbler_info_master_volume,
@@ -879,7 +883,8 @@ static struct snd_kcontrol_new snapper_mixers[] __initdata = {
.put = tumbler_put_master_switch
},
DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM),
- DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2),
+ /* Alternative PCM is assigned to Mic analog loopback on iBook G4 */
+ DEFINE_SNAPPER_MIX("Mic Playback Volume", 0, VOL_IDX_PCM2),
DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC),
DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),
DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),
@@ -897,7 +902,7 @@ static struct snd_kcontrol_new snapper_mixers[] __initdata = {
},
};
-static struct snd_kcontrol_new tumbler_hp_sw __initdata = {
+static struct snd_kcontrol_new tumbler_hp_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Headphone Playback Switch",
.info = snd_pmac_boolean_mono_info,
@@ -905,15 +910,15 @@ static struct snd_kcontrol_new tumbler_hp_sw __initdata = {
.put = tumbler_put_mute_switch,
.private_value = TUMBLER_MUTE_HP,
};
-static struct snd_kcontrol_new tumbler_speaker_sw __initdata = {
+static struct snd_kcontrol_new tumbler_speaker_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PC Speaker Playback Switch",
+ .name = "Speaker Playback Switch",
.info = snd_pmac_boolean_mono_info,
.get = tumbler_get_mute_switch,
.put = tumbler_put_mute_switch,
.private_value = TUMBLER_MUTE_AMP,
};
-static struct snd_kcontrol_new tumbler_lineout_sw __initdata = {
+static struct snd_kcontrol_new tumbler_lineout_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Line Out Playback Switch",
.info = snd_pmac_boolean_mono_info,
@@ -921,7 +926,7 @@ static struct snd_kcontrol_new tumbler_lineout_sw __initdata = {
.put = tumbler_put_mute_switch,
.private_value = TUMBLER_MUTE_LINE,
};
-static struct snd_kcontrol_new tumbler_drc_sw __initdata = {
+static struct snd_kcontrol_new tumbler_drc_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "DRC Switch",
.info = snd_pmac_boolean_mono_info,
@@ -978,7 +983,8 @@ static void device_change_handler(struct work_struct *work)
return;
mix = chip->mixer_data;
- snd_assert(mix, return);
+ if (snd_BUG_ON(!mix))
+ return;
headphone = tumbler_detect_headphone(chip);
lineout = tumbler_detect_lineout(chip);
@@ -995,7 +1001,7 @@ static void device_change_handler(struct work_struct *work)
chip->lineout_sw_ctl);
if (mix->anded_reset)
msleep(10);
- check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,
+ check_mute(chip, &mix->amp_mute, !IS_G4DA, mix->auto_mute_notify,
chip->speaker_sw_ctl);
} else {
/* unmute speaker, mute others */
@@ -1033,7 +1039,8 @@ static void tumbler_update_automute(struct snd_pmac *chip, int do_notify)
if (chip->auto_mute) {
struct pmac_tumbler *mix;
mix = chip->mixer_data;
- snd_assert(mix, return);
+ if (snd_BUG_ON(!mix))
+ return;
mix->auto_mute_notify = do_notify;
schedule_work(&device_change);
}
@@ -1134,7 +1141,8 @@ static long tumbler_find_device(const char *device, const char *platform,
gp->inactive_val = (*base) ? 0x4 : 0x5;
} else {
const u32 *prop = NULL;
- gp->active_state = 0;
+ gp->active_state = IS_G4DA
+ && !strncmp(device, "keywest-gpio1", 13);
gp->active_val = 0x4;
gp->inactive_val = 0x5;
/* Here are some crude hacks to extract the GPIO polarity and
@@ -1227,8 +1235,6 @@ static void tumbler_resume(struct snd_pmac *chip)
{
struct pmac_tumbler *mix = chip->mixer_data;
- snd_assert(mix, return);
-
mix->acs &= ~1;
mix->master_switch[0] = mix->save_master_switch[0];
mix->master_switch[1] = mix->save_master_switch[1];
@@ -1271,11 +1277,10 @@ static void tumbler_resume(struct snd_pmac *chip)
#endif
/* initialize tumbler */
-static int __init tumbler_init(struct snd_pmac *chip)
+static int tumbler_init(struct snd_pmac *chip)
{
int irq;
struct pmac_tumbler *mix = chip->mixer_data;
- snd_assert(mix, return -EINVAL);
if (tumbler_find_device("audio-hw-reset",
"platform-do-hw-reset",
@@ -1315,6 +1320,9 @@ static int __init tumbler_init(struct snd_pmac *chip)
if (irq <= NO_IRQ)
irq = tumbler_find_device("line-output-detect",
NULL, &mix->line_detect, 1);
+ if (IS_G4DA && irq <= NO_IRQ)
+ irq = tumbler_find_device("keywest-gpio16",
+ NULL, &mix->line_detect, 1);
mix->lineout_irq = irq;
tumbler_reset_audio(chip);
@@ -1342,7 +1350,7 @@ static void tumbler_cleanup(struct snd_pmac *chip)
}
/* exported */
-int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
+int snd_pmac_tumbler_init(struct snd_pmac *chip)
{
int i, err;
struct pmac_tumbler *mix;
@@ -1350,9 +1358,7 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
struct device_node *tas_node, *np;
char *chipname;
-#ifdef CONFIG_KMOD
request_module("i2c-powermac");
-#endif /* CONFIG_KMOD */
mix = kzalloc(sizeof(*mix), GFP_KERNEL);
if (! mix)