Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- 33 participants
- 50748 discussions
I installed Ubuntu Feisty on a D900t laptop : it contains a ALC880 audio
chipset
eric@gondor:~$ lspci |grep Audio
00:1b.0 Audio device: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6
Family) High Definition Audio Controller (rev 03)
When modprobing the modules I get :
eric@gondor:~$ sudo modprobe -v snd-hda-intel model=3stack-digout
insmod /lib/modules/2.6.20-15-generic/kernel/sound/pci/hda/snd-hda-codec.ko
insmod /lib/modules/2.6.20-15-generic/kernel/sound/pci/hda/snd-hda-intel.ko model=3stack-digout
while /var/log/messages says :
May 14 14:42:45 gondor kernel: [ 3699.070904] hda_intel:
azx_get_response timeout, switching to polling mode...
Feisty dist. is provided with alsa-1.0.13. I get no sound, here are the
results of aplay :
eric@gondor:~$ aplay
ALSA lib pcm_direct.c:867:(snd_pcm_direct_initialize_slave)
snd_pcm_hw_params_any failed
ALSA lib pcm_dmix.c:876:(snd_pcm_dmix_open) unable to initialize slave
aplay: main:550: Erreur d'ouverture audio: Argument invalide
eric@gondor:~$
Here are some other infos :
eric@gondor:~$ tail -2 /proc/asound/oss/sndstat
0: Realtek ALC880
1: SAA7134 Mixer
amixer shows this :
eric@gondor:~$ amixer
Simple mixer control 'Headphone',0
Capabilities: pswitch
Playback channels: Front Left - Front Right
Mono:
Front Left: Playback [on]
Front Right: Playback [on]
Simple mixer control 'PCM',0
Capabilities: pvolume
Playback channels: Front Left - Front Right
Limits: Playback 0 - 255
Mono:
Front Left: Playback 228 [89%]
Front Right: Playback 228 [89%]
Simple mixer control 'Front',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 60 [47%] [-2144.00dB] [on]
Front Right: Playback 60 [47%] [-2144.00dB] [on]
Simple mixer control 'Front Mic',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 55 [43%] [-2304.00dB] [on]
Front Right: Playback 55 [43%] [-2304.00dB] [on]
Simple mixer control 'Surround',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 64 [50%] [-2016.00dB] [on]
Front Right: Playback 64 [50%] [-2016.00dB] [on]
Simple mixer control 'Center',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback 0 - 127
Mono: Playback 56 [44%] [-2272.00dB] [on]
Simple mixer control 'LFE',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback 0 - 127
Mono: Playback 58 [46%] [-2208.00dB] [on]
Simple mixer control 'Line',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 60 [47%] [-2144.00dB] [on]
Front Right: Playback 60 [47%] [-2144.00dB] [on]
Simple mixer control 'CD',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 58 [46%] [-2208.00dB] [on]
Front Right: Playback 58 [46%] [-2208.00dB] [on]
Simple mixer control 'Mic',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 57 [45%] [-2240.00dB] [on]
Front Right: Playback 57 [45%] [-2240.00dB] [on]
Simple mixer control 'IEC958',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [off]
Simple mixer control 'PC Speaker',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 53 [42%] [-2368.00dB] [on]
Front Right: Playback 53 [42%] [-2368.00dB] [on]
Simple mixer control 'Capture',0
Capabilities: cvolume cswitch
Capture channels: Front Left - Front Right
Limits: Capture 0 - 127
Front Left: Capture 31 [24%] [-3072.00dB] [on]
Front Right: Capture 31 [24%] [-3072.00dB] [on]
Simple mixer control 'Capture',1
Capabilities: cvolume cswitch
Capture channels: Front Left - Front Right
Limits: Capture 0 - 127
Front Left: Capture 27 [21%] [-3200.00dB] [on]
Front Right: Capture 27 [21%] [-3200.00dB] [on]
Simple mixer control 'Capture',2
Capabilities: cvolume cswitch
Capture channels: Front Left - Front Right
Limits: Capture 0 - 127
Front Left: Capture 24 [19%] [-3296.00dB] [on]
Front Right: Capture 24 [19%] [-3296.00dB] [on]
Simple mixer control 'Caller ID',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [on]
Simple mixer control 'Channel Mode',0
Capabilities: enum
Items: '2ch' '6ch'
Item0: '6ch'
Simple mixer control 'Input Source',0
Capabilities: enum
Items: 'Mic' 'Front Mic' 'Line' 'CD'
Item0: 'Mic'
Simple mixer control 'Input Source',1
Capabilities: enum
Items: 'Mic' 'Front Mic' 'Line' 'CD'
Item0: 'Mic'
Simple mixer control 'Input Source',2
Capabilities: enum
Items: 'Mic' 'Front Mic' 'Line' 'CD'
Item0: 'Mic'
Simple mixer control 'Off-hook',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [on]
aplay -l seems to work :
eric@gondor:~$ aplay -l
**** Liste des PLAYBACK périphériques ****
carte 0: Intel [HDA Intel], périphérique 0 : ALC880 Analog [ALC880
Analog]
Sous-périphériques: 1/1
Sous-périphérique: #0: subdevice #0
carte 0: Intel [HDA Intel], périphérique 1 : ALC880 Digital [ALC880
Digital]
Sous-périphériques: 1/1
Sous-périphérique: #0: subdevice #0
carte 0: Intel [HDA Intel], périphérique 6 : Si3054 Modem [Si3054
Modem]
Sous-périphériques: 1/1
Sous-périphérique: #0: subdevice #0
eric@gondor:~$ cat /proc/asound/cards
0 [Intel ]: HDA-Intel - HDA Intel
HDA Intel at 0xb0000000 irq 17
1 [SAA7134 ]: SAA7134 - SAA7134
saa7133[0] at 0xb3006000 irq 22
if I try to do a cat /proc/asound/card0/codec#0 it hangs
while /var/log/messages gives a lot of
May 14 14:44:52 gondor kernel: [ 3825.457412] hda_codec: invalid
dep_range_val 0:7fff
May 14 14:44:52 gondor kernel: [ 3825.457696] hda_codec: invalid
dep_range_val 0:7fff
........................
eric@gondor:~$ sudo lspci -nv
00:00.0 0600: 8086:2580 (rev 04)
Subsystem: 1558:0900
Flags: bus master, fast devsel, latency 0
Capabilities: [e0] Vendor Specific Information
00:01.0 0604: 8086:2581 (rev 04) (prog-if 00 [Normal decode])
Flags: bus master, fast devsel, latency 0
Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
Memory behind bridge: b1000000-b2ffffff
Prefetchable memory behind bridge: c0000000-cfffffff
Capabilities: [88] Subsystem: 8086:2582
Capabilities: [80] Power Management version 2
Capabilities: [90] Message Signalled Interrupts: Mask- 64bit-
Queue=0/0 Enable-
Capabilities: [a0] Express Root Port (Slot+) IRQ 0
00:1b.0 0403: 8086:2668 (rev 03)
Subsystem: 1558:0900
Flags: bus master, fast devsel, latency 0, IRQ 20
Memory at b0000000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [50] Power Management version 2
Capabilities: [60] Message Signalled Interrupts: Mask- 64bit+
Queue=0/0 Enable-
Capabilities: [70] Express Unknown type IRQ 0
00:1d.0 0c03: 8086:2658 (rev 03) (prog-if 00 [UHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 18
I/O ports at 1800 [size=32]
00:1d.1 0c03: 8086:2659 (rev 03) (prog-if 00 [UHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 19
I/O ports at 3000 [size=32]
00:1d.2 0c03: 8086:265a (rev 03) (prog-if 00 [UHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 17
I/O ports at 3020 [size=32]
00:1d.3 0c03: 8086:265b (rev 03) (prog-if 00 [UHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 20
I/O ports at 3040 [size=32]
00:1d.7 0c03: 8086:265c (rev 03) (prog-if 20 [EHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 18
Memory at b0004000 (32-bit, non-prefetchable) [size=1K]
Capabilities: [50] Power Management version 2
Capabilities: [58] Debug port
00:1e.0 0604: 8086:244e (rev d3) (prog-if 01 [Subtractive decode])
Flags: bus master, fast devsel, latency 0
Bus: primary=00, secondary=0a, subordinate=0e, sec-latency=32
I/O behind bridge: 00004000-00004fff
Memory behind bridge: b3000000-b30fffff
Prefetchable memory behind bridge:
0000000050000000-0000000055ffffff
Capabilities: [50] Subsystem: 1558:0900
00:1f.0 0601: 8086:2640 (rev 03)
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0
00:1f.1 0101: 8086:266f (rev 03) (prog-if 8a [Master SecP PriP])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 17
I/O ports at 01f0 [size=8]
I/O ports at 03f4 [size=1]
I/O ports at 0170 [size=8]
I/O ports at 0374 [size=1]
I/O ports at 3080 [size=16]
00:1f.3 0c05: 8086:266a (rev 03)
Subsystem: 1558:0900
Flags: medium devsel, IRQ 10
I/O ports at 3060 [size=32]
01:00.0 0300: 10de:00c8 (rev a2) (prog-if 00 [VGA])
Subsystem: 1558:0900
Flags: bus master, fast devsel, latency 0, IRQ 11
Memory at b2000000 (32-bit, non-prefetchable) [size=16M]
Memory at c0000000 (64-bit, prefetchable) [size=256M]
Memory at b1000000 (64-bit, non-prefetchable) [size=16M]
Capabilities: [60] Power Management version 2
Capabilities: [68] Message Signalled Interrupts: Mask- 64bit+
Queue=0/0 Enable-
Capabilities: [78] Express Endpoint IRQ 0
0a:00.0 0607: 104c:ac50 (rev 02)
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 168, IRQ 17
Memory at b3007000 (32-bit, non-prefetchable) [size=4K]
Bus: primary=0a, secondary=0b, subordinate=0e, sec-latency=176
Memory window 0: 50000000-53fff000 (prefetchable)
Memory window 1: 58000000-5bfff000
I/O window 0: 00004800-000048ff
I/O window 1: 00004c00-00004cff
16-bit legacy interface ports at 0001
0a:01.0 0c00: 104c:8023 (prog-if 10 [OHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 64, IRQ 21
Memory at b3004000 (32-bit, non-prefetchable) [size=2K]
Memory at b3000000 (32-bit, non-prefetchable) [size=16K]
Capabilities: [44] Power Management version 2
0a:02.0 0104: 105a:3373 (rev 02)
Subsystem: 1558:0900
Flags: bus master, 66MHz, medium devsel, latency 96, IRQ 19
I/O ports at 4480 [size=64]
I/O ports at 44c0 [size=16]
I/O ports at 4400 [size=128]
Memory at b3005000 (32-bit, non-prefetchable) [size=4K]
Memory at b3020000 (32-bit, non-prefetchable) [size=128K]
Capabilities: [60] Power Management version 2
0a:03.0 0200: 10ec:8169 (rev 10)
Subsystem: 1558:0900
Flags: bus master, 66MHz, medium devsel, latency 64, IRQ 22
I/O ports at 4000 [size=256]
Memory at b3004800 (32-bit, non-prefetchable) [size=256]
[virtual] Expansion ROM at 54000000 [disabled] [size=128K]
Capabilities: [dc] Power Management version 2
0a:04.0 0480: 1131:7133 (rev f0)
Subsystem: 1461:f31e
Flags: bus master, medium devsel, latency 64, IRQ 23
Memory at b3006000 (32-bit, non-prefetchable) [size=2K]
Capabilities: [40] Power Management version 2
0a:05.0 0280: 1814:0201 (rev 01)
Subsystem: 1462:6833
Flags: bus master, slow devsel, latency 64, IRQ 20
Memory at b3008000 (32-bit, non-prefetchable) [size=8K]
Capabilities: [40] Power Management version 2
asoundconf output :
eric@gondor:~$ asoundconf list
Names of available sound cards:
Intel
SAA7134
I tried a lot of workarounds but none worked : boot options (irqpoll,
pci=noacpi), single_cmd=1, position_fix=1, several models of hda-intel
driver, I tried 1.0.13 and 1.0.14rc4 driver, with debug on...
I must add that I already had this problem with previous distributions
of Ubuntu. It worked with an old one (Breezy) then in Dapper and Edgy,
it did worked ONLY when I self-compiled the driver with debug option
enabled I never understood why. And now with Feisty/alsa 1.0.13/ubuntu
kernel 2.6.20, or an ubuntu kernel with self-compiled alsa 1.0.14rc4, it
does not work. I cannot have one sound :-(.
Please help me ....
Eric
3
2
Hello again,
I am running alsa on a custom AT91SAM9260 arm based SOC board together
with a a simple external PCM1725 codec. When using alsa-lib and the
at91 soc driver (pcm+i2s) I can playback PCM samples using both aplay
and test/pcm. Using softvol I can also reduce the volume of the
playback.
The problem I have is that the playback volume (with softvol=100%) is
not very loud. The volume is the same even without the softvol
plugin. The PCM codec has no hw volume control. According to our hw
team the sound level should be much higher.
Is there a default PCM attenuation (volume reduction) built into alsa
lib? If so, how can it be adjusted?
Thanks,
Michel
1
0
14 May '07
ALSA support for the SEGA Dreamcast Yamaha AICA sound device (pcm)
This patch adds ALSA sound support for pcm playback on two channels on
the SEGA Dreamcast built-in sound device (the Yamaha AICA)
Add driver for the AICA sound device built into the SEGA Dreamcast
Hook it all up with the build system.
Signed-off-by: Adrian McMenamin <adrian(a)mcmen.demon.co.uk>
2
1
Hello,
here goes attempt #3 for the SH7760 ASoC patch.
Changes v2 -> v3
- added a generic demo board for AC97
Changes v1 -> v2
- incorporate Paul Mundt's suggestions
- work around an oops when aplay is used in mmap mode ('aplay -M')
by changing the allocation type to SNDRV_DMA_TYPE_CONTINUOUS
As soon as I get Linux working on the EDOSK7780 board, I'll complete
SH7780 support as well.
Thanks,
Manuel Lauss
---
ALSA ASoC support for SH7760
- SH7760 DMA engine (dmabrg)
- AC97 driver for HAC unit(s) found on SH7760/SH7780
- I2S driver for SSI unit(s) found on SH7760/SH7780
- generic SH7760-AC97 "demoboard"
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 3 +-
sound/soc/sh/Kconfig | 39 +++++
sound/soc/sh/Makefile | 14 ++
sound/soc/sh/dma-sh7760.c | 354 +++++++++++++++++++++++++++++++++++++++
sound/soc/sh/hac.c | 322 +++++++++++++++++++++++++++++++++++
sound/soc/sh/sh7760-ac97.c | 92 ++++++++++
sound/soc/sh/ssi.c | 400 ++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 1224 insertions(+), 1 deletions(-)
Signed-off-by: Manuel Lauss <mano(a)roarinelk.homelinux.net>
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index dccaa4b..3e3df26 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -26,6 +26,7 @@ menu "SoC Platforms"
depends on SND_SOC
source "sound/soc/at91/Kconfig"
source "sound/soc/pxa/Kconfig"
+source "sound/soc/sh/Kconfig"
endmenu
# Supported codecs
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 98e6f49..e1c9a70 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,5 @@
snd-soc-core-objs := soc-core.o soc-dapm.o
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
-obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/
+obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ sh/
+
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
new file mode 100644
index 0000000..a332e51
--- /dev/null
+++ b/sound/soc/sh/Kconfig
@@ -0,0 +1,39 @@
+menu "SoC Audio support for SuperH"
+
+config SND_SOC_PCM_SH7760
+ tristate "SoC Audio support for Renesas SH7760"
+ depends on CPU_SUBTYPE_SH7760 && SND_SOC
+ select SH_DMABRG
+ help
+ Enable this option for SH7760 AC97/I2S audio support.
+
+
+##
+## Audio unit modules
+##
+
+config SND_SOC_SH4_HAC
+ select AC97_BUS
+ select SND_SOC_AC97_BUS
+ select SND_AC97_CODEC
+ tristate
+
+config SND_SOC_SH4_SSI
+ tristate
+
+
+
+##
+## Boards
+##
+
+config SND_SH7760_AC97
+ tristate "SH7760 AC97 sound support"
+ depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760
+ select SND_SOC_SH4_HAC
+ select SND_SOC_AC97_CODEC
+ help
+ This option enables generic sound support for the first
+ AC97 unit of the SH7760.
+
+endmenu
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
new file mode 100644
index 0000000..a8e8ab8
--- /dev/null
+++ b/sound/soc/sh/Makefile
@@ -0,0 +1,14 @@
+## DMA engines
+snd-soc-dma-sh7760-objs := dma-sh7760.o
+obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o
+
+## audio units found on some SH-4
+snd-soc-hac-objs := hac.o
+snd-soc-ssi-objs := ssi.o
+obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o
+obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o
+
+## boards
+snd-soc-sh7760-ac97-objs := sh7760-ac97.o
+
+obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
new file mode 100644
index 0000000..cdee374
--- /dev/null
+++ b/sound/soc/sh/dma-sh7760.c
@@ -0,0 +1,354 @@
+/*
+ * SH7760 ("camelot") DMABRG audio DMA unit support
+ *
+ * Copyright (C) 2007 Manuel Lauss <mano(a)roarinelk.homelinux.net>
+ * licensed under the terms outlined in the file COPYING at the root
+ * of the linux kernel sources.
+ *
+ * The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
+ * trigger an interrupt when one half of the programmed transfer size
+ * has been xmitted.
+ *
+ * FIXME: little-endian only for now
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/dmabrg.h>
+
+
+/* registers and bits */
+#define BRGATXSAR 0x00
+#define BRGARXDAR 0x04
+#define BRGATXTCR 0x08
+#define BRGARXTCR 0x0C
+#define BRGACR 0x10
+#define BRGATXTCNT 0x14
+#define BRGARXTCNT 0x18
+
+#define ACR_RAR (1 << 18)
+#define ACR_RDS (1 << 17)
+#define ACR_RDE (1 << 16)
+#define ACR_TAR (1 << 2)
+#define ACR_TDS (1 << 1)
+#define ACR_TDE (1 << 0)
+
+/* receiver/transmitter data alignment */
+#define ACR_RAM_NONE (0 << 24)
+#define ACR_RAM_4BYTE (1 << 24)
+#define ACR_RAM_2WORD (2 << 24)
+#define ACR_TAM_NONE (0 << 8)
+#define ACR_TAM_4BYTE (1 << 8)
+#define ACR_TAM_2WORD (2 << 8)
+
+
+struct camelot_pcm {
+ unsigned long mmio; /* DMABRG audio channel control reg MMIO */
+ unsigned int txid; /* ID of first DMABRG IRQ for this unit */
+
+ struct snd_pcm_substream *tx_ss;
+ unsigned long tx_period_size;
+ unsigned int tx_period;
+
+ struct snd_pcm_substream *rx_ss;
+ unsigned long rx_period_size;
+ unsigned int rx_period;
+
+} cam_pcm_data[2] = {
+ {
+ .mmio = 0xFE3C0040,
+ .txid = DMABRGIRQ_A0TXF,
+ },
+ {
+ .mmio = 0xFE3C0060,
+ .txid = DMABRGIRQ_A1TXF,
+ },
+};
+
+#define BRGREG(x) (*(unsigned long *)(cam->mmio + (x)))
+
+/*
+ * set a minimum of 16kb per period, to avoid interrupt-"storm" and
+ * resulting skipping. In general, the bigger the minimum size, the
+ * better for overall system performance. (The SH7760 is a puny CPU
+ * with a slow SDRAM interface and poor internal bus bandwidth,
+ * *especially* when the LCDC is active). The minimum for the DMAC
+ * is 8 bytes; 16kbytes are enough to get skip-free playback of a
+ * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain
+ * reasonable responsiveness in MPlayer.
+ */
+#define DMABRG_PERIOD_MIN 16 * 1024
+#define DMABRG_PERIOD_MAX 0x03fffffc
+#define DMABRG_PREALLOC_BUFFER 32 * 1024
+#define DMABRG_PREALLOC_BUFFER_MAX 32 * 1024
+
+/* support everything the SSI supports */
+#define DMABRG_RATES \
+ SNDRV_PCM_RATE_8000_192000
+
+#define DMABRG_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
+
+static struct snd_pcm_hardware camelot_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = DMABRG_FMTS,
+ .rates = DMABRG_RATES,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 2,
+ .channels_max = 8, /* max of the SSI */
+ .buffer_bytes_max = DMABRG_PERIOD_MAX,
+ .period_bytes_min = DMABRG_PERIOD_MIN,
+ .period_bytes_max = DMABRG_PERIOD_MAX / 2,
+ .periods_min = 2,
+ .periods_max = 2,
+ .fifo_size = 128,
+};
+
+static void camelot_txdma(void *data)
+{
+ struct camelot_pcm *cam = data;
+ cam->tx_period ^= 1;
+ snd_pcm_period_elapsed(cam->tx_ss);
+}
+
+static void camelot_rxdma(void *data)
+{
+ struct camelot_pcm *cam = data;
+ cam->rx_period ^= 1;
+ snd_pcm_period_elapsed(cam->rx_ss);
+}
+
+static int camelot_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+ int ret, dmairq;
+
+ snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
+
+ /* DMABRG buffer half/full events */
+ dmairq = (recv) ? cam->txid + 2 : cam->txid;
+ if (recv) {
+ cam->rx_ss = substream;
+ ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
+ if (unlikely(ret)) {
+ pr_debug("audio unit %d irqs already taken!\n",
+ rtd->dai->cpu_dai->id);
+ return -EBUSY;
+ }
+ (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
+ } else {
+ cam->tx_ss = substream;
+ ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
+ if (unlikely(ret)) {
+ pr_debug("audio unit %d irqs already taken!\n",
+ rtd->dai->cpu_dai->id);
+ return -EBUSY;
+ }
+ (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
+ }
+ return 0;
+}
+
+static int camelot_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+ int dmairq;
+
+ dmairq = (recv) ? cam->txid + 2 : cam->txid;
+
+ if (recv)
+ cam->rx_ss = NULL;
+ else
+ cam->tx_ss = NULL;
+
+ dmabrg_free_irq(dmairq + 1);
+ dmabrg_free_irq(dmairq);
+
+ return 0;
+}
+
+static int camelot_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+ int ret;
+
+ ret = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (ret < 0)
+ return ret;
+
+ if (recv) {
+ cam->rx_period_size = params_period_bytes(hw_params);
+ cam->rx_period = 0;
+ } else {
+ cam->tx_period_size = params_period_bytes(hw_params);
+ cam->tx_period = 0;
+ }
+ return 0;
+}
+
+static int camelot_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int camelot_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+
+ pr_debug("PCM data: addr 0x%08ulx len %d\n",
+ (u32)runtime->dma_addr, runtime->dma_bytes);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
+ BRGREG(BRGATXTCR) = runtime->dma_bytes;
+ } else {
+ BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
+ BRGREG(BRGARXTCR) = runtime->dma_bytes;
+ }
+
+ return 0;
+}
+
+static inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
+{
+ unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+ /* start DMABRG engine: XFER start, auto-addr-reload */
+ BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
+}
+
+static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
+{
+ unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+ /* forcibly terminate data transmission */
+ BRGREG(BRGACR) = acr | ACR_TDS;
+}
+
+static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
+{
+ unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+ /* start DMABRG engine: recv start, auto-reload */
+ BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
+}
+
+static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
+{
+ unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+ /* forcibly terminate data receiver */
+ BRGREG(BRGACR) = acr | ACR_RDS;
+}
+
+static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ if (recv)
+ dmabrg_rec_dma_start(cam);
+ else
+ dmabrg_play_dma_start(cam);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (recv)
+ dmabrg_rec_dma_stop(cam);
+ else
+ dmabrg_play_dma_stop(cam);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+ unsigned long pos;
+
+ /* cannot use the DMABRG pointer register: under load, by the
+ * time ALSA comes around to read the register, it is already
+ * far ahead (or worse, already done with the fragment) of the
+ * position at the time the IRQ was triggered, which results in
+ * fast-playback sound in my test application (ScummVM)
+ */
+ if (recv)
+ pos = cam->rx_period ? cam->rx_period_size : 0;
+ else
+ pos = cam->tx_period ? cam->tx_period_size : 0;
+
+ return bytes_to_frames(runtime, pos);
+}
+
+static struct snd_pcm_ops camelot_pcm_ops = {
+ .open = camelot_pcm_open,
+ .close = camelot_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = camelot_hw_params,
+ .hw_free = camelot_hw_free,
+ .prepare = camelot_prepare,
+ .trigger = camelot_trigger,
+ .pointer = camelot_pos,
+};
+
+static void camelot_pcm_free(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int camelot_pcm_new(struct snd_card *card,
+ struct snd_soc_codec_dai *dai,
+ struct snd_pcm *pcm)
+{
+ /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
+ * in MMAP mode (i.e. aplay -M)
+ */
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX);
+
+ return 0;
+}
+
+struct snd_soc_platform sh7760_soc_platform = {
+ .name = "sh7760-pcm",
+ .pcm_ops = &camelot_pcm_ops,
+ .pcm_new = camelot_pcm_new,
+ .pcm_free = camelot_pcm_free,
+};
+EXPORT_SYMBOL_GPL(sh7760_soc_platform);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
+MODULE_AUTHOR("Manuel Lauss <mano(a)roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
new file mode 100644
index 0000000..8e3f039
--- /dev/null
+++ b/sound/soc/sh/hac.c
@@ -0,0 +1,322 @@
+/*
+ * Hitachi Audio Controller (AC97) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano(a)roarinelk.homelinux.net>
+ * licensed under the terms outlined in the file COPYING at the root
+ * of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable HAC output pins!
+ */
+
+/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
+ * the FIRST can be used since ASoC does not pass any information to the
+ * ac97_read/write() functions regarding WHICH unit to use. You'll have
+ * to edit the code a bit to use the other AC97 unit. --mlau
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+/* regs and bits */
+#define HACCR 0x08
+#define HACCSAR 0x20
+#define HACCSDR 0x24
+#define HACPCML 0x28
+#define HACPCMR 0x2C
+#define HACTIER 0x50
+#define HACTSR 0x54
+#define HACRIER 0x58
+#define HACRSR 0x5C
+#define HACACR 0x60
+
+#define CR_CR (1 << 15) /* "codec-ready" indicator */
+#define CR_CDRT (1 << 11) /* cold reset */
+#define CR_WMRT (1 << 10) /* warm reset */
+#define CR_B9 (1 << 9) /* the mysterious "bit 9" */
+#define CR_ST (1 << 5) /* AC97 link start bit */
+
+#define CSAR_RD (1 << 19) /* AC97 data read bit */
+#define CSAR_WR (0)
+
+#define TSR_CMDAMT (1 << 31)
+#define TSR_CMDDMT (1 << 30)
+
+#define RSR_STARY (1 << 22)
+#define RSR_STDRY (1 << 21)
+
+#define ACR_DMARX16 (1 << 30)
+#define ACR_DMATX16 (1 << 29)
+#define ACR_TX12ATOM (1 << 26)
+#define ACR_DMARX20 ((1 << 24) | (1 << 22))
+#define ACR_DMATX20 ((1 << 23) | (1 << 21))
+
+#define CSDR_SHIFT 4
+#define CSDR_MASK (0xffff << CSDR_SHIFT)
+#define CSAR_SHIFT 12
+#define CSAR_MASK (0x7f << CSAR_SHIFT)
+
+#define AC97_WRITE_RETRY 1
+#define AC97_READ_RETRY 5
+
+/* manual-suggested AC97 codec access timeouts (us) */
+#define TMO_E1 500 /* 21 < E1 < 1000 */
+#define TMO_E2 13 /* 13 < E2 */
+#define TMO_E3 21 /* 21 < E3 */
+#define TMO_E4 500 /* 21 < E4 < 1000 */
+
+struct hac_priv {
+ unsigned long mmio; /* HAC base address */
+} hac_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+ {
+ .mmio = 0xFE240000,
+ },
+ {
+ .mmio = 0xFE250000,
+ },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ {
+ .mmio = 0xFFE40000,
+ },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+#define HACREG(reg) (*(unsigned long *)(hac->mmio + (reg)))
+
+/*
+ * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
+ */
+static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
+ unsigned short *v)
+{
+ unsigned int to1, to2, i;
+ unsigned short adr;
+
+ for (i = 0; i < AC97_READ_RETRY; ++i) {
+ *v = 0;
+ /* wait for HAC to receive something from the codec */
+ for (to1 = TMO_E4;
+ to1 && !(HACREG(HACRSR) & RSR_STARY);
+ --to1)
+ udelay(1);
+ for (to2 = TMO_E4;
+ to2 && !(HACREG(HACRSR) & RSR_STDRY);
+ --to2)
+ udelay(1);
+
+ if (!to1 && !to2)
+ return 0; /* codec comm is down */
+
+ adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
+ *v = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
+
+ HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+
+ if (r == adr)
+ break;
+
+ /* manual says: wait at least 21 usec before retrying */
+ udelay(21);
+ }
+ HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+ return (i < AC97_READ_RETRY);
+}
+
+static unsigned short hac_read_codec_aux(struct hac_priv *hac,
+ unsigned short reg)
+{
+ unsigned short val;
+ unsigned int i, to;
+
+ for (i = 0; i < AC97_READ_RETRY; i++) {
+ /* send_read_request */
+ local_irq_disable();
+ HACREG(HACTSR) &= ~(TSR_CMDAMT);
+ HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
+ local_irq_enable();
+
+ for (to = TMO_E3;
+ to && !(HACREG(HACTSR) & TSR_CMDAMT);
+ --to)
+ udelay(1);
+
+ HACREG(HACTSR) &= ~TSR_CMDAMT;
+ val = 0;
+ if (hac_get_codec_data(hac, reg, &val) != 0)
+ break;
+ }
+
+ if (i == AC97_READ_RETRY)
+ return ~0;
+
+ return val;
+}
+
+static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ int unit_id = 0 /* ac97->private_data */;
+ struct hac_priv *hac = &hac_cpu_data[unit_id];
+ unsigned int i, to;
+ /* write_codec_aux */
+ for (i = 0; i < AC97_WRITE_RETRY; i++) {
+ /* send_write_request */
+ local_irq_disable();
+ HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
+ HACREG(HACCSDR) = (val << CSDR_SHIFT);
+ HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
+ local_irq_enable();
+
+ /* poll-wait for CMDAMT and CMDDMT */
+ for (to = TMO_E1;
+ to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
+ --to)
+ udelay(1);
+
+ HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
+ if (to)
+ break;
+ /* timeout, try again */
+ }
+}
+
+static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ int unit_id = 0 /* ac97->private_data */;
+ struct hac_priv *hac = &hac_cpu_data[unit_id];
+ return hac_read_codec_aux(hac, reg);
+}
+
+static void hac_ac97_warmrst(struct snd_ac97 *ac97)
+{
+ int unit_id = 0 /* ac97->private_data */;
+ struct hac_priv *hac = &hac_cpu_data[unit_id];
+ unsigned int tmo;
+
+ HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
+ msleep(10);
+ HACREG(HACCR) = CR_ST | CR_B9;
+ for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
+ udelay(1);
+
+ if (!tmo)
+ printk(KERN_INFO "hac: reset: AC97 link down!\n");
+ /* settings this bit lets us have a conversation with codec */
+ HACREG(HACACR) |= ACR_TX12ATOM;
+}
+
+static void hac_ac97_coldrst(struct snd_ac97 *ac97)
+{
+ int unit_id = 0 /* ac97->private_data */;
+ struct hac_priv *hac;
+ hac = &hac_cpu_data[unit_id];
+
+ HACREG(HACCR) = 0;
+ HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
+ msleep(10);
+ hac_ac97_warmrst(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = hac_ac97_read,
+ .write = hac_ac97_write,
+ .reset = hac_ac97_coldrst,
+ .warm_reset = hac_ac97_warmrst,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int hac_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+ int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+ switch (params->msbits) {
+ case 16:
+ HACREG(HACACR) |= d ? ACR_DMARX16 : ACR_DMATX16;
+ HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
+ break;
+ case 20:
+ HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
+ HACREG(HACACR) |= d ? ACR_DMARX20 : ACR_DMATX20;
+ break;
+ default:
+ pr_debug("hac: invalid depth %d bit\n", params->msbits);
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+#define AC97_RATES \
+ SNDRV_PCM_RATE_8000_192000
+
+#define AC97_FMTS \
+ SNDRV_PCM_FMTBIT_S16_LE
+
+struct snd_soc_cpu_dai sh4_hac_dai[] = {
+{
+ .name = "HAC0",
+ .id = 0,
+ .type = SND_SOC_DAI_AC97,
+ .playback = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = {
+ .hw_params = hac_hw_params,
+ },
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+ .name = "HAC1",
+ .id = 1,
+ .type = SND_SOC_DAI_AC97,
+ .playback = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = {
+ .hw_params = hac_hw_params,
+ },
+
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_hac_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano(a)roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
new file mode 100644
index 0000000..5563f14
--- /dev/null
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -0,0 +1,92 @@
+/*
+ * Generic AC97 sound support for SH7760
+ *
+ * (c) 2007 Manuel Lauss
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+
+#include "../codecs/ac97.h"
+
+#define IPSEL 0xFE400034
+
+/* platform specific structs can be declared here */
+extern struct snd_soc_cpu_dai sh4_hac_dai[2];
+extern struct snd_soc_platform sh7760_soc_platform;
+
+static int machine_init(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_sync_endpoints(codec);
+ return 0;
+}
+
+static struct snd_soc_dai_link sh7760_ac97_dai = {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &sh4_hac_dai[0], /* HAC0 */
+ .codec_dai = &ac97_dai,
+ .init = machine_init,
+ .ops = NULL,
+};
+
+static struct snd_soc_machine sh7760_ac97_soc_machine = {
+ .name = "SH7760 AC97",
+ .dai_link = &sh7760_ac97_dai,
+ .num_links = 1,
+};
+
+static struct snd_soc_device sh7760_ac97_snd_devdata = {
+ .machine = &sh7760_ac97_soc_machine,
+ .platform = &sh7760_soc_platform,
+ .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *sh7760_ac97_snd_device;
+
+static int __init sh7760_ac97_init(void)
+{
+ int ret;
+ unsigned short ipsel;
+
+ /* enable both AC97 controllers in pinmux reg */
+ ipsel = ctrl_inw(IPSEL);
+ ctrl_outw(ipsel | (3 << 10), IPSEL);
+
+ ret = -ENOMEM;
+ sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!sh7760_ac97_snd_device)
+ goto out;
+
+ platform_set_drvdata(sh7760_ac97_snd_device,
+ &sh7760_ac97_snd_devdata);
+ sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+ ret = platform_device_add(sh7760_ac97_snd_device);
+
+ if (ret)
+ platform_device_put(sh7760_ac97_snd_device);
+
+out:
+ return ret;
+}
+
+static void __exit sh7760_ac97_exit(void)
+{
+ platform_device_unregister(sh7760_ac97_snd_device);
+}
+
+module_init(sh7760_ac97_init);
+module_exit(sh7760_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
+MODULE_AUTHOR("Manuel Lauss <mano(a)roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
new file mode 100644
index 0000000..b72bc31
--- /dev/null
+++ b/sound/soc/sh/ssi.c
@@ -0,0 +1,400 @@
+/*
+ * Serial Sound Interface (I2S) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano(a)roarinelk.homelinux.net>
+ *
+ * licensed under the terms outlined in the file COPYING at the root
+ * of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable SSI output pins!
+ */
+
+/*
+ * LIMITATIONS:
+ * The SSI unit has only one physical data line, so full duplex is
+ * impossible. This can be remedied on the SH7760 by using the
+ * other SSI unit for recording; however the SH7780 has only 1 SSI
+ * unit, and its pins are shared with the AC97 unit, among others.
+ *
+ * FEATURES:
+ * The SSI features "compressed mode": in this mode it continuously
+ * streams PCM data over the I2S lines and uses LRCK as a handshake
+ * signal. Can be used to send compressed data (AC3/DTS) to a DSP.
+ * The number of bits sent over the wire in a frame can be adjusted
+ * and can be independent from the actual sample bit depth. This is
+ * useful to support TDM mode codecs like the AD1939 which have a
+ * fixed TDM slot size, regardless of sample resolution.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/io.h>
+
+#define SSICR 0x00
+#define SSISR 0x04
+
+#define CR_DMAEN (1 << 28)
+#define CR_CHNL_SHIFT 22
+#define CR_CHNL_MASK (3 << CR_CHNL_SHIFT)
+#define CR_DWL_SHIFT 19
+#define CR_DWL_MASK (7 << CR_DWL_SHIFT)
+#define CR_SWL_SHIFT 16
+#define CR_SWL_MASK (7 << CR_SWL_SHIFT)
+#define CR_SCK_MASTER (1 << 15) /* bitclock master bit */
+#define CR_SWS_MASTER (1 << 14) /* wordselect master bit */
+#define CR_SCKP (1 << 13) /* I2Sclock polarity */
+#define CR_SWSP (1 << 12) /* LRCK polarity */
+#define CR_SPDP (1 << 11)
+#define CR_SDTA (1 << 10) /* i2s alignment (msb/lsb) */
+#define CR_PDTA (1 << 9) /* fifo data alignment */
+#define CR_DEL (1 << 8) /* delay data by 1 i2sclk */
+#define CR_BREN (1 << 7) /* clock gating in burst mode */
+#define CR_CKDIV_SHIFT 4
+#define CR_CKDIV_MASK (7 << CR_CKDIV_SHIFT) /* bitclock divider */
+#define CR_MUTE (1 << 3) /* SSI mute */
+#define CR_CPEN (1 << 2) /* compressed mode */
+#define CR_TRMD (1 << 1) /* transmit/receive select */
+#define CR_EN (1 << 0) /* enable SSI */
+
+#define SSIREG(reg) (*(unsigned long *)(ssi->mmio + (reg)))
+
+struct ssi_priv {
+ unsigned long mmio;
+ unsigned long sysclk;
+ int inuse;
+} ssi_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+ {
+ .mmio = 0xFE680000,
+ },
+ {
+ .mmio = 0xFE690000,
+ },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ {
+ .mmio = 0xFFE70000,
+ },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+/*
+ * track usage of the SSI; it is simplex-only so prevent attempts of
+ * concurrent playback + capture. FIXME: any locking required?
+ */
+static int ssi_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ if (ssi->inuse) {
+ pr_debug("ssi: already in use!\n");
+ return -EBUSY;
+ } else
+ ssi->inuse = 1;
+ return 0;
+}
+
+static void ssi_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+ ssi->inuse = 0;
+}
+
+static int ssi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ SSIREG(SSICR) |= CR_DMAEN | CR_EN;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ssi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ unsigned long ssicr = SSIREG(SSICR);
+ unsigned int bits, channels, swl, recv, i;
+
+ channels = params_channels(params);
+ bits = params->msbits;
+ recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+
+ pr_debug("ssi_hw_params() enter\nssicr was %08lx\n", ssicr);
+ pr_debug("bits: %d channels: %d\n", bits, channels);
+
+ ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
+ CR_SWL_MASK);
+
+ /* direction (send/receive) */
+ if (!recv)
+ ssicr |= CR_TRMD; /* transmit */
+
+ /* channels */
+ if ((channels < 2) || (channels > 8) || (channels & 1)) {
+ pr_debug("ssi: invalid number of channels\n");
+ return -EINVAL;
+ }
+ ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
+
+ /* DATA WORD LENGTH (DWL): databits in audio sample */
+ i = 0;
+ switch (bits) {
+ case 32: ++i;
+ case 24: ++i;
+ case 22: ++i;
+ case 20: ++i;
+ case 18: ++i;
+ case 16: ++i;
+ ssicr |= i << CR_DWL_SHIFT;
+ case 8: break;
+ default:
+ pr_debug("ssi: invalid sample width\n");
+ return -EINVAL;
+ }
+
+ /*
+ * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S
+ * wires. This is usually bits_per_sample x channels/2; i.e. in
+ * Stereo mode the SWL equals DWL. SWL can be bigger than the
+ * product of (channels_per_slot x samplebits), e.g. for codecs
+ * like the AD1939 which only accept 32bit wide TDM slots. For
+ * "standard" I2S operation we set SWL = chans / 2 * DWL here.
+ * Waiting for ASoC to get TDM support ;-)
+ */
+ if ((bits > 16) && (bits <= 24)) {
+ bits = 24; /* these are padded by the SSI */
+ /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */
+ }
+ i = 0;
+ swl = (bits * channels) / 2;
+ switch (swl) {
+ case 256: ++i;
+ case 128: ++i;
+ case 64: ++i;
+ case 48: ++i;
+ case 32: ++i;
+ case 16: ++i;
+ ssicr |= i << CR_SWL_SHIFT;
+ case 8: break;
+ default:
+ pr_debug("ssi: invalid system word length computed\n");
+ return -EINVAL;
+ }
+
+ SSIREG(SSICR) = ssicr;
+
+ pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
+ return 0;
+}
+
+static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
+
+ ssi->sysclk = freq;
+
+ return 0;
+}
+
+/*
+ * This divider is used to generate the SSI_SCK (I2S bitclock) from the
+ * clock at the HAC_BIT_CLK ("oversampling clock") pin.
+ */
+static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div)
+{
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+ unsigned long ssicr;
+ int i;
+
+ i = 0;
+ ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
+ switch (div) {
+ case 16: ++i;
+ case 8: ++i;
+ case 4: ++i;
+ case 2: ++i;
+ SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
+ case 1: break;
+ default:
+ pr_debug("ssi: invalid sck divider %d\n", div);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt)
+{
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+ unsigned long ssicr = SSIREG(SSICR);
+
+ pr_debug("ssi_set_fmt()\nssicr was 0x%08lx\n", ssicr);
+
+ ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
+ CR_SWS_MASTER | CR_SCK_MASTER);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ssicr |= CR_DEL | CR_PDTA;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ssicr |= CR_DEL;
+ break;
+ default:
+ pr_debug("ssi: unsupported format\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+ case SND_SOC_DAIFMT_CONT:
+ break;
+ case SND_SOC_DAIFMT_GATED:
+ ssicr |= CR_BREN;
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ ssicr |= CR_SCKP; /* sample data at low clkedge */
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ ssicr |= CR_SCKP | CR_SWSP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ ssicr |= CR_SWSP; /* word select starts low */
+ break;
+ default:
+ pr_debug("ssi: invalid inversion\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ ssicr |= CR_SCK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ ssicr |= CR_SWS_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
+ break;
+ default:
+ pr_debug("ssi: invalid master/slave configuration\n");
+ return -EINVAL;
+ }
+
+ SSIREG(SSICR) = ssicr;
+ pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
+
+ return 0;
+}
+
+/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in
+ * Master mode, so really this is board specific; the SSI can do any
+ * rate with the right bitclk and divider settings.
+ */
+#define SSI_RATES \
+ SNDRV_PCM_RATE_8000_192000
+
+/* the SSI can do 8-32 bit samples, with 8 possible channels */
+#define SSI_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
+
+struct snd_soc_cpu_dai sh4_ssi_dai[] = {
+{
+ .name = "SSI0",
+ .id = 0,
+ .type = SND_SOC_DAI_I2S,
+ .playback = {
+ .rates = SSI_RATES,
+ .formats = SSI_FMTS,
+ .channels_min = 2,
+ .channels_max = 8,
+ },
+ .capture = {
+ .rates = SSI_RATES,
+ .formats = SSI_FMTS,
+ .channels_min = 2,
+ .channels_max = 8,
+ },
+ .ops = {
+ .startup = ssi_startup,
+ .shutdown = ssi_shutdown,
+ .trigger = ssi_trigger,
+ .hw_params = ssi_hw_params,
+ },
+ .dai_ops = {
+ .set_sysclk = ssi_set_sysclk,
+ .set_clkdiv = ssi_set_clkdiv,
+ .set_fmt = ssi_set_fmt,
+ },
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+ .name = "SSI1",
+ .id = 1,
+ .type = SND_SOC_DAI_I2S,
+ .playback = {
+ .rates = SSI_RATES,
+ .formats = SSI_FMTS,
+ .channels_min = 2,
+ .channels_max = 8,
+ },
+ .capture = {
+ .rates = SSI_RATES,
+ .formats = SSI_FMTS,
+ .channels_min = 2,
+ .channels_max = 8,
+ },
+ .ops = {
+ .startup = ssi_startup,
+ .shutdown = ssi_shutdown,
+ .trigger = ssi_trigger,
+ .hw_params = ssi_hw_params,
+ },
+ .dai_ops = {
+ .set_sysclk = ssi_set_sysclk,
+ .set_clkdiv = ssi_set_clkdiv,
+ .set_fmt = ssi_set_fmt,
+ },
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_ssi_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano(a)roarinelk.homelinux.net>");
3
4
Re: [alsa-devel] Can someone verify support for "AzTech Sound Galaxy Nova 16 Extra II-3D - using AZT-2316/R Chipset - FCC-ID:I38-MMSN846" ?
by ramkromberg@mail.com 14 May '07
by ramkromberg@mail.com 14 May '07
14 May '07
Since the only successful modprobe is done with the jumper on SOFTWARE
instead of EPPROM, I'll only tested the following:
Jumper: Software:
sudo modprobe snd-sb8 port=0x220 irq=5 dma8=1
without an error,
dmesg - gives no hint, verbose, mention...
cat /proc/asound/cards:
0 [Pro ]: SB Pro - Sound Blaster Pro
Sound Blaster Pro at 0x220, irq 5, dma 1
So I did the following:
cd /proc/asound/
cat *
cat: Pro: Is a directory
cat: card0: Is a directory
0 [Pro ]: SB Pro - Sound Blaster Pro
Sound Blaster Pro at 0x220, irq 5, dma 1
2: : timer
3: : sequencer
4: [ 0- 0]: raw midi
5: [ 0- 0]: hardware dependent
6: [ 0- 0]: digital audio playback
7: [ 0- 0]: digital audio capture
8: [ 0] : control
00-00: OPL3 FM
0 snd_sb8
cat: oss: Is a directory
00-00: SB8 DSP : DSP v3.1 : playback 1 : capture 1
cat: seq: Is a directory
G0: system timer : 4000.000us (10000000 ticks)
P0-0-0: PCM playback 0-0-0 : SLAVE
P0-0-1: PCM capture 0-0-1 : SLAVE
Advanced Linux Sound Architecture Driver Version 1.0.14rc1 (Tue Jan 09
09:56:17 2007 UTC).
Thanks for your help,
Ram Kromberg,
ramkromberg(a)mail.com
2
1
I installed Ubuntu Feisty on a D900t laptop : it contains a ALC880 audio
chipset
eric@gondor:~$ lspci |grep Audio
00:1b.0 Audio device: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6
Family) High Definition Audio Controller (rev 03)
When modprobing the modules I get :
eric@gondor:~$ sudo modprobe -v snd-hda-intel model=3stack-digout
insmod /lib/modules/2.6.20-15-generic/kernel/sound/pci/hda/snd-hda-codec.ko
insmod /lib/modules/2.6.20-15-generic/kernel/sound/pci/hda/snd-hda-intel.ko model=3stack-digout
while /var/log/messages says :
May 14 14:42:45 gondor kernel: [ 3699.070904] hda_intel:
azx_get_response timeout, switching to polling mode...
Feisty dist. is provided with alsa-1.0.13. I get no sound, here are the
results of aplay :
eric@gondor:~$ aplay
ALSA lib pcm_direct.c:867:(snd_pcm_direct_initialize_slave)
snd_pcm_hw_params_any failed
ALSA lib pcm_dmix.c:876:(snd_pcm_dmix_open) unable to initialize slave
aplay: main:550: Erreur d'ouverture audio: Argument invalide
eric@gondor:~$
Here are some other infos :
eric@gondor:~$ tail -2 /proc/asound/oss/sndstat
0: Realtek ALC880
1: SAA7134 Mixer
amixer shows this :
eric@gondor:~$ amixer
Simple mixer control 'Headphone',0
Capabilities: pswitch
Playback channels: Front Left - Front Right
Mono:
Front Left: Playback [on]
Front Right: Playback [on]
Simple mixer control 'PCM',0
Capabilities: pvolume
Playback channels: Front Left - Front Right
Limits: Playback 0 - 255
Mono:
Front Left: Playback 228 [89%]
Front Right: Playback 228 [89%]
Simple mixer control 'Front',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 60 [47%] [-2144.00dB] [on]
Front Right: Playback 60 [47%] [-2144.00dB] [on]
Simple mixer control 'Front Mic',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 55 [43%] [-2304.00dB] [on]
Front Right: Playback 55 [43%] [-2304.00dB] [on]
Simple mixer control 'Surround',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 64 [50%] [-2016.00dB] [on]
Front Right: Playback 64 [50%] [-2016.00dB] [on]
Simple mixer control 'Center',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback 0 - 127
Mono: Playback 56 [44%] [-2272.00dB] [on]
Simple mixer control 'LFE',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback 0 - 127
Mono: Playback 58 [46%] [-2208.00dB] [on]
Simple mixer control 'Line',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 60 [47%] [-2144.00dB] [on]
Front Right: Playback 60 [47%] [-2144.00dB] [on]
Simple mixer control 'CD',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 58 [46%] [-2208.00dB] [on]
Front Right: Playback 58 [46%] [-2208.00dB] [on]
Simple mixer control 'Mic',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 57 [45%] [-2240.00dB] [on]
Front Right: Playback 57 [45%] [-2240.00dB] [on]
Simple mixer control 'IEC958',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [off]
Simple mixer control 'PC Speaker',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 53 [42%] [-2368.00dB] [on]
Front Right: Playback 53 [42%] [-2368.00dB] [on]
Simple mixer control 'Capture',0
Capabilities: cvolume cswitch
Capture channels: Front Left - Front Right
Limits: Capture 0 - 127
Front Left: Capture 31 [24%] [-3072.00dB] [on]
Front Right: Capture 31 [24%] [-3072.00dB] [on]
Simple mixer control 'Capture',1
Capabilities: cvolume cswitch
Capture channels: Front Left - Front Right
Limits: Capture 0 - 127
Front Left: Capture 27 [21%] [-3200.00dB] [on]
Front Right: Capture 27 [21%] [-3200.00dB] [on]
Simple mixer control 'Capture',2
Capabilities: cvolume cswitch
Capture channels: Front Left - Front Right
Limits: Capture 0 - 127
Front Left: Capture 24 [19%] [-3296.00dB] [on]
Front Right: Capture 24 [19%] [-3296.00dB] [on]
Simple mixer control 'Caller ID',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [on]
Simple mixer control 'Channel Mode',0
Capabilities: enum
Items: '2ch' '6ch'
Item0: '6ch'
Simple mixer control 'Input Source',0
Capabilities: enum
Items: 'Mic' 'Front Mic' 'Line' 'CD'
Item0: 'Mic'
Simple mixer control 'Input Source',1
Capabilities: enum
Items: 'Mic' 'Front Mic' 'Line' 'CD'
Item0: 'Mic'
Simple mixer control 'Input Source',2
Capabilities: enum
Items: 'Mic' 'Front Mic' 'Line' 'CD'
Item0: 'Mic'
Simple mixer control 'Off-hook',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [on]
aplay -l seems to work :
eric@gondor:~$ aplay -l
**** Liste des PLAYBACK périphériques ****
carte 0: Intel [HDA Intel], périphérique 0 : ALC880 Analog [ALC880
Analog]
Sous-périphériques: 1/1
Sous-périphérique: #0: subdevice #0
carte 0: Intel [HDA Intel], périphérique 1 : ALC880 Digital [ALC880
Digital]
Sous-périphériques: 1/1
Sous-périphérique: #0: subdevice #0
carte 0: Intel [HDA Intel], périphérique 6 : Si3054 Modem [Si3054
Modem]
Sous-périphériques: 1/1
Sous-périphérique: #0: subdevice #0
eric@gondor:~$ cat /proc/asound/cards
0 [Intel ]: HDA-Intel - HDA Intel
HDA Intel at 0xb0000000 irq 17
1 [SAA7134 ]: SAA7134 - SAA7134
saa7133[0] at 0xb3006000 irq 22
if I try to do a cat /proc/asound/card0/codec#0 it hangs
while /var/log/messages gives a lot of
May 14 14:44:52 gondor kernel: [ 3825.457412] hda_codec: invalid
dep_range_val 0:7fff
May 14 14:44:52 gondor kernel: [ 3825.457696] hda_codec: invalid
dep_range_val 0:7fff
........................
eric@gondor:~$ sudo lspci -nv
00:00.0 0600: 8086:2580 (rev 04)
Subsystem: 1558:0900
Flags: bus master, fast devsel, latency 0
Capabilities: [e0] Vendor Specific Information
00:01.0 0604: 8086:2581 (rev 04) (prog-if 00 [Normal decode])
Flags: bus master, fast devsel, latency 0
Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
Memory behind bridge: b1000000-b2ffffff
Prefetchable memory behind bridge: c0000000-cfffffff
Capabilities: [88] Subsystem: 8086:2582
Capabilities: [80] Power Management version 2
Capabilities: [90] Message Signalled Interrupts: Mask- 64bit-
Queue=0/0 Enable-
Capabilities: [a0] Express Root Port (Slot+) IRQ 0
00:1b.0 0403: 8086:2668 (rev 03)
Subsystem: 1558:0900
Flags: bus master, fast devsel, latency 0, IRQ 20
Memory at b0000000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [50] Power Management version 2
Capabilities: [60] Message Signalled Interrupts: Mask- 64bit+
Queue=0/0 Enable-
Capabilities: [70] Express Unknown type IRQ 0
00:1d.0 0c03: 8086:2658 (rev 03) (prog-if 00 [UHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 18
I/O ports at 1800 [size=32]
00:1d.1 0c03: 8086:2659 (rev 03) (prog-if 00 [UHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 19
I/O ports at 3000 [size=32]
00:1d.2 0c03: 8086:265a (rev 03) (prog-if 00 [UHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 17
I/O ports at 3020 [size=32]
00:1d.3 0c03: 8086:265b (rev 03) (prog-if 00 [UHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 20
I/O ports at 3040 [size=32]
00:1d.7 0c03: 8086:265c (rev 03) (prog-if 20 [EHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 18
Memory at b0004000 (32-bit, non-prefetchable) [size=1K]
Capabilities: [50] Power Management version 2
Capabilities: [58] Debug port
00:1e.0 0604: 8086:244e (rev d3) (prog-if 01 [Subtractive decode])
Flags: bus master, fast devsel, latency 0
Bus: primary=00, secondary=0a, subordinate=0e, sec-latency=32
I/O behind bridge: 00004000-00004fff
Memory behind bridge: b3000000-b30fffff
Prefetchable memory behind bridge:
0000000050000000-0000000055ffffff
Capabilities: [50] Subsystem: 1558:0900
00:1f.0 0601: 8086:2640 (rev 03)
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0
00:1f.1 0101: 8086:266f (rev 03) (prog-if 8a [Master SecP PriP])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 0, IRQ 17
I/O ports at 01f0 [size=8]
I/O ports at 03f4 [size=1]
I/O ports at 0170 [size=8]
I/O ports at 0374 [size=1]
I/O ports at 3080 [size=16]
00:1f.3 0c05: 8086:266a (rev 03)
Subsystem: 1558:0900
Flags: medium devsel, IRQ 10
I/O ports at 3060 [size=32]
01:00.0 0300: 10de:00c8 (rev a2) (prog-if 00 [VGA])
Subsystem: 1558:0900
Flags: bus master, fast devsel, latency 0, IRQ 11
Memory at b2000000 (32-bit, non-prefetchable) [size=16M]
Memory at c0000000 (64-bit, prefetchable) [size=256M]
Memory at b1000000 (64-bit, non-prefetchable) [size=16M]
Capabilities: [60] Power Management version 2
Capabilities: [68] Message Signalled Interrupts: Mask- 64bit+
Queue=0/0 Enable-
Capabilities: [78] Express Endpoint IRQ 0
0a:00.0 0607: 104c:ac50 (rev 02)
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 168, IRQ 17
Memory at b3007000 (32-bit, non-prefetchable) [size=4K]
Bus: primary=0a, secondary=0b, subordinate=0e, sec-latency=176
Memory window 0: 50000000-53fff000 (prefetchable)
Memory window 1: 58000000-5bfff000
I/O window 0: 00004800-000048ff
I/O window 1: 00004c00-00004cff
16-bit legacy interface ports at 0001
0a:01.0 0c00: 104c:8023 (prog-if 10 [OHCI])
Subsystem: 1558:0900
Flags: bus master, medium devsel, latency 64, IRQ 21
Memory at b3004000 (32-bit, non-prefetchable) [size=2K]
Memory at b3000000 (32-bit, non-prefetchable) [size=16K]
Capabilities: [44] Power Management version 2
0a:02.0 0104: 105a:3373 (rev 02)
Subsystem: 1558:0900
Flags: bus master, 66MHz, medium devsel, latency 96, IRQ 19
I/O ports at 4480 [size=64]
I/O ports at 44c0 [size=16]
I/O ports at 4400 [size=128]
Memory at b3005000 (32-bit, non-prefetchable) [size=4K]
Memory at b3020000 (32-bit, non-prefetchable) [size=128K]
Capabilities: [60] Power Management version 2
0a:03.0 0200: 10ec:8169 (rev 10)
Subsystem: 1558:0900
Flags: bus master, 66MHz, medium devsel, latency 64, IRQ 22
I/O ports at 4000 [size=256]
Memory at b3004800 (32-bit, non-prefetchable) [size=256]
[virtual] Expansion ROM at 54000000 [disabled] [size=128K]
Capabilities: [dc] Power Management version 2
0a:04.0 0480: 1131:7133 (rev f0)
Subsystem: 1461:f31e
Flags: bus master, medium devsel, latency 64, IRQ 23
Memory at b3006000 (32-bit, non-prefetchable) [size=2K]
Capabilities: [40] Power Management version 2
0a:05.0 0280: 1814:0201 (rev 01)
Subsystem: 1462:6833
Flags: bus master, slow devsel, latency 64, IRQ 20
Memory at b3008000 (32-bit, non-prefetchable) [size=8K]
Capabilities: [40] Power Management version 2
asoundconf output :
eric@gondor:~$ asoundconf list
Names of available sound cards:
Intel
SAA7134
I tried a lot of workarounds but none worked : boot options (irqpoll,
pci=noacpi), single_cmd=1, position_fix=1, several models of hda-intel
driver, I tried 1.0.13 and 1.0.14rc4 driver, with debug on...
I must add that I already had this problem with previous distributions
of Ubuntu. It worked with an old one (Breezy) then in Dapper and Edgy,
it did worked ONLY when I self-compiled the driver with debug option
enabled I never understood why. And now with Feisty/alsa 1.0.13/ubuntu
kernel 2.6.20, or an ubuntu kernel with self-compiled alsa 1.0.14rc4, it
does not work. I cannot have one sound :-(.
Please help me ....
Eric
1
0
[alsa-devel] alsa-lib functions reporting conflicting information with two sound cards
by nick smethurst 14 May '07
by nick smethurst 14 May '07
14 May '07
Hey guys
I am rather confused that I am getting crossed information when
calling snd_names_list
and snd_pcm_info in order to gather information about pcm devices.
I have two sound cards in my development pc: RME Digi 96/8 PCI and an
onboard VIA 8237.
I'm trying to develop a piece of code that generates a list of objects
containing pcm device information, including information on virtual
devices.
My current idea is to use snd_names_list() to get a full list of
devices, and then get information about them by opening each device
and querying.
The bizzare thing is that snd_names_list() is returning comments that
do not agree with the associated device.
For example, given the following code:
#include <alsa/asoundlib.h>
int main()
{
snd_devname_t * list;
snd_config_update();
snd_names_list("pcm", &list);
while (list) {
if (!strcmp(list->name, "hw:0,0")) {
printf("hw:0,0 comment: %s\n", list->comment);
break;
}
list = list->next;
}
snd_names_list_free(list);
snd_pcm_t * pcm;
snd_pcm_info_t * pcm_info;
snd_pcm_info_malloc(&pcm_info);
snd_pcm_open(&pcm, "hw:0,0", SND_PCM_STREAM_PLAYBACK, 0);
snd_pcm_info(pcm, pcm_info);
printf("id: %s\n", snd_pcm_info_get_id(pcm_info));
snd_pcm_close(pcm);
snd_pcm_info_free(pcm_info);
return 0;
}
The result on my pc is:
hw:0,0 comment: Physical Device - VIA 8237 (Duplex)
id: Digi96 IEC958
So I'm apparently doing something very wrong here.
I would like to ask if there is an easier and more reliable way of
getting a list of pcm devices and querying them, and if not, what I am
doing wrong here?
Regards
Nicholas
6
16
14 May '07
Sorry for the lateness in the current merge window of this patch
series.
From: Graeme Gregory <gg(a)opensource.wolfsonmicro.com>
This patch adds AC97 support to the Samsung S3C2443 CPU.
Signed-off-by: Graeme Gregory <gg(a)opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lg(a)opensource.wolfsonmicro.com>
3
4
[alsa-devel] Undefined Symbols: snd-aoa-codec-tas.c:944 warning: implicit declaration of function 'of_get_property'
by Elimar Riesebieter 14 May '07
by Elimar Riesebieter 14 May '07
14 May '07
Hi all,
the aoa drivers in 1.0.14rc4 are not usable. Compiling the modules
there are much warnings "implicit declaration of function
'of_get_property'" Loading the module dmesg tells: snd_aoa: Unknown
symbol of_get_property. rc3 out of 2.6.21 works fine.
Any hints?
Thanks
Elimar
--
You cannot propel yourself forward by
patting yourself on the back.
3
4
I haven't touched this for a year, but after some small changes (to
run queues) I can compile this and it runs well. Anyone care to
comment on the prospects of getting it committed? I'll obviously be
happy to be named as the maintainer in that case...
diff -Naur ./linux-2.6.21-orig/sound/Kconfig ./linux-2.6.21/sound/Kconfig
--- ./linux-2.6.21-orig/sound/Kconfig 2007-04-26 04:08:32.000000000 +0100
+++ ./linux-2.6.21/sound/Kconfig 2007-05-07 21:20:54.000000000 +0100
@@ -64,6 +64,8 @@
source "sound/mips/Kconfig"
+source "sound/sh/Kconfig"
+
# the following will depend on the order of config.
# here assuming USB is defined before ALSA
source "sound/usb/Kconfig"
diff -Naur ./linux-2.6.21-orig/sound/Makefile ./linux-2.6.21/sound/Makefile
--- ./linux-2.6.21-orig/sound/Makefile 2007-04-26 04:08:32.000000000 +0100
+++ ./linux-2.6.21/sound/Makefile 2007-05-07 21:37:05.000000000 +0100
@@ -5,7 +5,7 @@
obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/
usb/ sparc/ parisc/ pcmcia/ mips/ soc/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/
synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out
diff -Naur ./linux-2.6.21-orig/sound/sh/aica.c ./linux-2.6.21/sound/sh/aica.c
--- ./linux-2.6.21-orig/sound/sh/aica.c 1970-01-01 01:00:00.000000000 +0100
+++ ./linux-2.6.21/sound/sh/aica.c 2007-05-12 15:27:54.000000000 +0100
@@ -0,0 +1,677 @@
+/*
+* This code is licenced under
+* the General Public Licence
+* version 2
+*
+* Copyright Adrian McMenamin 2005, 2006
+* <adrian(a)mcmen.demon.co.uk>
+* See also http://newgolddream.dyndns.info/cgi-bin/cvsweb
+*
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License
as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/dreamcast/sysasic.h>
+#include "aica.h"
+
+MODULE_AUTHOR("Adrian McMenamin <adrian(a)mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}");
+
+/* module parameters */
+#define CARD_NAME "AICA"
+static int index = -1;
+static char *id;
+static int enable = 1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param(enable, bool, 0644);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+/* Use workqueue */
+
+static struct spu_work_holder {
+ struct work_struct spu_dma_work;
+ void *sspointer;
+} spu_working;
+
+static struct workqueue_struct *aica_queue;
+
+/* Simple platform device */
+static struct platform_device *pd;
+static struct resource aica_memory_space[2] = {
+ {
+ .name = "AICA ARM CONTROL",
+ .start = ARM_RESET_REGISTER,
+ .flags = IORESOURCE_MEM,
+ .end = ARM_RESET_REGISTER + 3,
+ },
+ {
+ .name = "AICA Sound RAM",
+ .start = SPU_MEMORY_BASE,
+ .flags = IORESOURCE_MEM,
+ .end = SPU_MEMORY_BASE + 0x200000 - 1,
+ },
+};
+
+/* SPU specific functions */
+/* spu_write_wait - wait for G2-SH FIFO to clear */
+static inline void spu_write_wait(void)
+{
+ int time_count;
+ time_count = 0;
+ while (1) {
+ if (!(readl(G2_FIFO) & 0x11))
+ break;
+ /* To ensure hardware failure doesn't wedge kernel */
+ time_count++;
+ if (time_count > 0x10000)
+ break;
+ }
+}
+
+/* spu_memset - write to memory in SPU address space */
+static void spu_memset(uint32_t toi, uint32_t what, int length)
+{
+ int i;
+ snd_assert(length % 4 == 0, return);
+ spu_write_wait();
+ for (i = 0; i < length; i++) {
+ writel(what, toi + SPU_MEMORY_BASE);
+ toi++;
+ if (i && !(i % 8))
+ spu_write_wait();
+ }
+}
+
+/* spu_memload - write to SPU address space */
+static void spu_memload(uint32_t toi, void __iomem * from, int length)
+{
+ uint32_t __iomem *froml = from;
+ uint32_t __iomem *to = (uint32_t __iomem *) (SPU_MEMORY_BASE + toi);
+ int i, val;
+ if (length % 4)
+ length = (length / 4) + 1;
+ else
+ length = length / 4;
+ spu_write_wait();
+ for (i = 0; i < length; i++) {
+ val = *froml;
+ writel(val, to);
+ froml++;
+ to++;
+ if (i && !(i % 8))
+ spu_write_wait();
+ }
+}
+
+/* spu_disable - set spu registers to stop sound output */
+static void spu_disable(void)
+{
+ int i;
+ uint32_t regval;
+ spu_write_wait();
+ regval = readl(ARM_RESET_REGISTER);
+ regval |= 1;
+ spu_write_wait();
+ writel(regval, ARM_RESET_REGISTER);
+ for (i = 0; i < 64; i++) {
+ spu_write_wait();
+ regval = readl(SPU_REGISTER_BASE + (i * 0x80));
+ regval = (regval & ~0x4000) | 0x8000;
+ spu_write_wait();
+ writel(regval, SPU_REGISTER_BASE + (i * 0x80));
+ }
+}
+
+/* spu_enable - set spu registers to enable sound output */
+static void spu_enable(void)
+{
+ uint32_t regval = readl(ARM_RESET_REGISTER);
+ regval &= ~1;
+ spu_write_wait();
+ writel(regval, ARM_RESET_REGISTER);
+}
+
+/*
+ * Halt the sound processor, clear the memory,
+ * load some default ARM7 code, and then restart ARM7
+*/
+static void spu_reset(void)
+{
+ spu_disable();
+ spu_memset(0, 0, 0x200000 / 4);
+ /* Put ARM7 in endless loop */
+ ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+ spu_enable();
+}
+
+/* aica_chn_start - write to spu to start playback */
+static void aica_chn_start(void)
+{
+ spu_write_wait();
+ writel(AICA_CMD_KICK | AICA_CMD_START, (uint32_t *) AICA_CONTROL_POINT);
+}
+
+/* aica_chn_halt - write to spu to halt playback */
+static void aica_chn_halt(void)
+{
+ spu_write_wait();
+ writel(AICA_CMD_KICK | AICA_CMD_STOP, (uint32_t *) AICA_CONTROL_POINT);
+}
+
+/* ALSA code below */
+static struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
+ .info = (SNDRV_PCM_INFO_NONINTERLEAVED),
+ .formats =
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_IMA_ADPCM),
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = AICA_BUFFER_SIZE,
+ .period_bytes_min = AICA_PERIOD_SIZE,
+ .period_bytes_max = AICA_PERIOD_SIZE,
+ .periods_min = AICA_PERIOD_NUMBER,
+ .periods_max = AICA_PERIOD_NUMBER,
+};
+
+static int aica_dma_transfer(int channels, int buffer_size,
+ struct snd_pcm_substream *substream)
+{
+ int q, err, period_offset;
+ struct snd_card_aica *dreamcastcard;
+ struct snd_pcm_runtime *runtime;
+ err = 0;
+ dreamcastcard = substream->pcm->private_data;
+ period_offset = dreamcastcard->clicks;
+ period_offset %= (AICA_PERIOD_NUMBER / channels);
+ runtime = substream->runtime;
+ for (q = 0; q < channels; q++) {
+ err = dma_xfer(AICA_DMA_CHANNEL,
+ (unsigned long)(runtime->dma_area +
+ (AICA_BUFFER_SIZE * q) /
+ channels +
+ AICA_PERIOD_SIZE *
+ period_offset),
+ AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
+ AICA_PERIOD_SIZE * period_offset,
+ buffer_size / channels, AICA_DMA_MODE);
+ if (unlikely(err < 0))
+ break;
+ dma_wait_for_completion(AICA_DMA_CHANNEL);
+ }
+ return err;
+}
+
+static void startup_aica(struct snd_card_aica *dreamcastcard)
+{
+ spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+ (uint8_t *) dreamcastcard->channel,
+ sizeof(struct aica_channel));
+ aica_chn_start();
+}
+
+static void run_spu_dma(struct work_struct *work)
+{
+ int buffer_size;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+ struct snd_card_aica *dreamcastcard;
+ struct spu_work_holder *holder = container_of(work, struct
spu_work_holder, spu_dma_work);
+ substream = holder-> sspointer;
+ dreamcastcard = substream->pcm->private_data;
+ runtime = substream->runtime;
+ if (unlikely(dreamcastcard->dma_check == 0)) {
+ buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
+ if (runtime->channels > 1)
+ dreamcastcard->channel->flags |= 0x01;
+ aica_dma_transfer(runtime->channels, buffer_size, substream);
+ startup_aica(dreamcastcard);
+ dreamcastcard->clicks =
+ buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
+ return;
+ } else {
+ aica_dma_transfer(runtime->channels,
+ AICA_PERIOD_SIZE * runtime->channels,
+ substream);
+ snd_pcm_period_elapsed(dreamcastcard->substream);
+ dreamcastcard->clicks++;
+ dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
+ mod_timer(&dreamcastcard->timer, jiffies + 1);
+ }
+}
+
+static void aica_period_elapsed(unsigned long timer_var)
+{
+ /*timer fuction - so cannot sleep */
+ int play_period;
+ struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *substream;
+ struct snd_card_aica *dreamcastcard;
+ substream = (struct snd_pcm_substream *)timer_var;
+ runtime = substream->runtime;
+ dreamcastcard = substream->pcm->private_data;
+ /* Have we played out an additional period? */
+ play_period =
+ frames_to_bytes(runtime,
+ readl
+ (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
+ AICA_PERIOD_SIZE;
+ if (play_period == dreamcastcard->current_period) {
+ /* reschedule the timer */
+ dreamcastcard->timer.expires = jiffies + 1;
+ add_timer(&(dreamcastcard->timer));
+ return;
+ }
+ if (runtime->channels > 1)
+ dreamcastcard->current_period = play_period;
+ if (unlikely(dreamcastcard->dma_check == 0))
+ dreamcastcard->dma_check = 1;
+ queue_work(aica_queue, &(spu_working.spu_dma_work));
+}
+
+static void spu_begin_dma(struct snd_pcm_substream *substream)
+{
+ /* Must be atomic */
+ struct snd_card_aica *dreamcastcard;
+ struct snd_pcm_runtime *runtime;
+ runtime = substream->runtime;
+ dreamcastcard = substream->pcm->private_data;
+ /* Use queue to do the heavy lifting */
+ spu_working.sspointer = substream;
+ INIT_WORK(&(spu_working.spu_dma_work), run_spu_dma);
+ queue_work(aica_queue, &(spu_working.spu_dma_work));
+ /* Timer may already be running */
+ if (unlikely(dreamcastcard->timer.data)) {
+ mod_timer(&dreamcastcard->timer, jiffies + 4);
+ return;
+ }
+ init_timer(&(dreamcastcard->timer));
+ dreamcastcard->timer.data = (unsigned long)substream;
+ dreamcastcard->timer.function = aica_period_elapsed;
+ dreamcastcard->timer.expires = jiffies + 4;
+ add_timer(&(dreamcastcard->timer));
+}
+
+static int snd_aicapcm_pcm_open(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ struct aica_channel *channel;
+ struct snd_card_aica *dreamcastcard;
+ if (!enable)
+ return -ENOENT;
+ dreamcastcard = substream->pcm->private_data;
+ channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
+ if (!channel)
+ return -ENOMEM;
+ /* set defaults for channel */
+ channel->sfmt = SM_8BIT;
+ channel->cmd = AICA_CMD_START;
+ channel->vol = dreamcastcard->master_volume;
+ channel->pan = 0x80;
+ channel->pos = 0;
+ channel->flags = 0; /* default to mono */
+ dreamcastcard->channel = channel;
+ runtime = substream->runtime;
+ runtime->hw = snd_pcm_aica_playback_hw;
+ spu_enable();
+ dreamcastcard->clicks = 0;
+ dreamcastcard->current_period = 0;
+ dreamcastcard->dma_check = 0;
+ return 0;
+}
+
+static int snd_aicapcm_pcm_close(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+ del_timer(&dreamcastcard->timer);
+ kfree(dreamcastcard->channel);
+ spu_disable();
+ return 0;
+}
+
+static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream
+ *substream)
+{
+ /* Free the DMA buffer */
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_aicapcm_pcm_hw_params(struct snd_pcm_substream
+ *substream, struct snd_pcm_hw_params
+ *hw_params)
+{
+ /* Allocate a DMA buffer using ALSA built-ins */
+ return
+ snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+ if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
+ dreamcastcard->channel->sfmt = SM_16BIT;
+ dreamcastcard->channel->freq = substream->runtime->rate;
+ dreamcastcard->substream = substream;
+ return 0;
+}
+
+static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
+ *substream, int cmd)
+{
+ struct snd_card_aica *dreamcastcard;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ spu_begin_dma(substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ dreamcastcard = substream->pcm->private_data;
+ if (dreamcastcard->timer.data)
+ del_timer(&dreamcastcard->timer);
+ aica_chn_halt();
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
+ *substream)
+{
+ return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
+}
+
+static struct snd_pcm_ops snd_aicapcm_playback_ops = {
+ .open = snd_aicapcm_pcm_open,
+ .close = snd_aicapcm_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_aicapcm_pcm_hw_params,
+ .hw_free = snd_aicapcm_pcm_hw_free,
+ .prepare = snd_aicapcm_pcm_prepare,
+ .trigger = snd_aicapcm_pcm_trigger,
+ .pointer = snd_aicapcm_pcm_pointer,
+};
+
+/* TO DO: set up to handle more than one pcm instance */
+static int __init snd_aicapcmchip(struct snd_card_aica
+ *dreamcastcard, int pcm_index)
+{
+ struct snd_pcm *pcm;
+ int err;
+ /* AICA has no capture ability */
+ err =
+ snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0, &pcm);
+ if (unlikely(err < 0))
+ return err;
+ pcm->private_data = dreamcastcard;
+ strcpy(pcm->name, "AICA PCM");
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_aicapcm_playback_ops);
+ /* Allocate the DMA buffers */
+ err =
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data
+ (GFP_KERNEL),
+ AICA_BUFFER_SIZE,
+ AICA_BUFFER_SIZE);
+ return err;
+}
+
+/* Mixer controls */
+static int aica_pcmswitch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 1; /* TO DO: Fix me */
+ return 0;
+}
+
+static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ if (ucontrol->value.integer.value[0] == 1)
+ return 0; /* TO DO: Fix me */
+ else
+ aica_chn_halt();
+ return 0;
+}
+
+static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0xFF;
+ return 0;
+}
+
+static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard = kcontrol->private_data;
+ if (unlikely(!dreamcastcard->channel))
+ return -ETXTBSY; /* we've not yet been set up */
+ ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
+ return 0;
+}
+
+static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard = kcontrol->private_data;
+ if (unlikely(!dreamcastcard->channel))
+ return -ETXTBSY;
+ if (unlikely(dreamcastcard->channel->vol ==
+ ucontrol->value.integer.value[0]))
+ return 0;
+ dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
+ dreamcastcard->master_volume = ucontrol->value.integer.value[0];
+ spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+ (uint8_t *) dreamcastcard->channel,
+ sizeof(struct aica_channel));
+
+ return 1;
+}
+
+static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+ .index = 0,
+ .info = aica_pcmswitch_info,
+ .get = aica_pcmswitch_get,
+ .put = aica_pcmswitch_put
+};
+
+static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .index = 0,
+ .info = aica_pcmvolume_info,
+ .get = aica_pcmvolume_get,
+ .put = aica_pcmvolume_put
+};
+
+static int load_aica_firmware(void)
+{
+ int err;
+ const struct firmware *fw_entry;
+ err = 0;
+ spu_reset();
+ err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
+ if (unlikely(err))
+ return err;
+ /* write firware into memory */
+ spu_disable();
+ spu_memload(0, fw_entry->data, fw_entry->size);
+ spu_enable();
+ release_firmware(fw_entry);
+ return err;
+}
+
+static int __devinit add_aicamixer_controls(struct snd_card_aica
+ *dreamcastcard)
+{
+ int err;
+ err = snd_ctl_add
+ (dreamcastcard->card,
+ snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
+ if (unlikely(err < 0))
+ return err;
+ err = snd_ctl_add
+ (dreamcastcard->card,
+ snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
+ if (unlikely(err < 0))
+ return err;
+ return 0;
+}
+
+static int snd_aica_remove(struct platform_device *devptr)
+{
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard = platform_get_drvdata(devptr);
+ if (unlikely(!dreamcastcard))
+ return -ENODEV;
+ snd_card_free(dreamcastcard->card);
+ kfree(dreamcastcard);
+ platform_set_drvdata(devptr, NULL);
+ return 0;
+}
+
+static int __init snd_aica_probe(struct platform_device *devptr)
+{
+ int err;
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
+ if (unlikely(!dreamcastcard))
+ return -ENOMEM;
+ dreamcastcard->card =
+ snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0);
+ if (unlikely(!dreamcastcard->card)) {
+ kfree(dreamcastcard);
+ return -ENODEV;
+ }
+ strcpy(dreamcastcard->card->driver, "snd_aica");
+ strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
+ strcpy(dreamcastcard->card->longname,
+ "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
+ /* Load the PCM 'chip' */
+ err = snd_aicapcmchip(dreamcastcard, 0);
+ if (unlikely(err < 0))
+ goto freedreamcast;
+ snd_card_set_dev(dreamcastcard->card, &devptr->dev);
+ dreamcastcard->timer.data = 0;
+ dreamcastcard->channel = NULL;
+ /* Add basic controls */
+ err = add_aicamixer_controls(dreamcastcard);
+ if (unlikely(err < 0))
+ goto freedreamcast;
+ /* Register the card with ALSA subsystem */
+ err = snd_card_register(dreamcastcard->card);
+ if (unlikely(err < 0))
+ goto freedreamcast;
+ platform_set_drvdata(devptr, dreamcastcard);
+ aica_queue = create_workqueue("aica");
+ if (unlikely(!aica_queue))
+ goto freedreamcast;
+ snd_printk
+ ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
+ return 0;
+ freedreamcast:
+ snd_card_free(dreamcastcard->card);
+ kfree(dreamcastcard);
+ return err;
+}
+
+static struct platform_driver snd_aica_driver = {
+ .probe = snd_aica_probe,
+ .remove = snd_aica_remove,
+ .driver = {
+ .name = SND_AICA_DRIVER},
+};
+
+static int __init aica_init(void)
+{
+ int err;
+ err = platform_driver_register(&snd_aica_driver);
+ if (unlikely(err < 0))
+ return err;
+ pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
+ aica_memory_space, 2);
+ if (unlikely(IS_ERR(pd))) {
+ platform_driver_unregister(&snd_aica_driver);
+ return PTR_ERR(pd);
+ }
+ /* Load the firmware */
+ err = load_aica_firmware();
+ if (unlikely(err < 0))
+ return err;
+
+ return 0;
+}
+
+static void __exit aica_exit(void)
+{
+ /* Destroy the aica kernel thread */
+ destroy_workqueue(aica_queue);
+ platform_device_unregister(pd);
+ platform_driver_unregister(&snd_aica_driver);
+ /* Kill any sound still playing and reset ARM7 to safe state */
+ spu_reset();
+}
+
+module_init(aica_init);
+module_exit(aica_exit);
diff -Naur ./linux-2.6.21-orig/sound/sh/aica.h ./linux-2.6.21/sound/sh/aica.h
--- ./linux-2.6.21-orig/sound/sh/aica.h 1970-01-01 01:00:00.000000000 +0100
+++ ./linux-2.6.21/sound/sh/aica.h 2007-05-07 21:47:31.000000000 +0100
@@ -0,0 +1,80 @@
+/* aica.h
+ * Header file for ALSA driver for
+ * Sega Dreamcast Yamaha AICA sound
+ * Copyright Adrian McMenamin
+ * <adrian(a)mcmen.demon.co.uk>
+ * 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* SPU memory and register constants etc */
+#define G2_FIFO 0xa05f688c
+#define SPU_MEMORY_BASE 0xA0800000
+#define ARM_RESET_REGISTER 0xA0702C00
+#define SPU_REGISTER_BASE 0xA0700000
+
+/* AICA channels stuff */
+#define AICA_CONTROL_POINT 0xA0810000
+#define AICA_CONTROL_CHANNEL_SAMPLE_NUMBER 0xA0810008
+#define AICA_CHANNEL0_CONTROL_OFFSET 0x10004
+
+/* Command values */
+#define AICA_CMD_KICK 0x80000000
+#define AICA_CMD_NONE 0
+#define AICA_CMD_START 1
+#define AICA_CMD_STOP 2
+#define AICA_CMD_VOL 3
+
+/* Sound modes */
+#define SM_8BIT 1
+#define SM_16BIT 0
+#define SM_ADPCM 2
+
+/* Buffer and period size */
+#define AICA_BUFFER_SIZE 0x8000
+#define AICA_PERIOD_SIZE 0x800
+#define AICA_PERIOD_NUMBER 16
+
+#define AICA_CHANNEL0_OFFSET 0x11000
+#define AICA_CHANNEL1_OFFSET 0x21000
+#define CHANNEL_OFFSET 0x10000
+
+#define AICA_DMA_CHANNEL 0
+#define AICA_DMA_MODE 5
+
+#define SND_AICA_DRIVER "AICA"
+
+struct aica_channel {
+ uint32_t cmd; /* Command ID */
+ uint32_t pos; /* Sample position */
+ uint32_t length; /* Sample length */
+ uint32_t freq; /* Frequency */
+ uint32_t vol; /* Volume 0-255 */
+ uint32_t pan; /* Pan 0-255 */
+ uint32_t sfmt; /* Sound format */
+ uint32_t flags; /* Bit flags */
+};
+
+struct snd_card_aica {
+ struct snd_card *card;
+ struct aica_channel *channel;
+ struct snd_pcm_substream *substream;
+ int clicks;
+ int current_period;
+ struct timer_list timer;
+ int master_volume;
+ int dma_check;
+};
diff -Naur ./linux-2.6.21-orig/sound/sh/Kconfig ./linux-2.6.21/sound/sh/Kconfig
--- ./linux-2.6.21-orig/sound/sh/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ ./linux-2.6.21/sound/sh/Kconfig 2007-05-07 21:28:30.000000000 +0100
@@ -0,0 +1,14 @@
+# ALSA SH drivers
+
+menu "SUPERH devices"
+ depends on SND!=n && SUPERH
+
+config SND_AICA
+ tristate "Dreamcast Yamaha AICA sound"
+ depends on SH_DREAMCAST && SND
+ select SND_PCM
+ help
+ ALSA Sound driver for the SEGA Dreamcast console.
+
+endmenu
+
diff -Naur ./linux-2.6.21-orig/sound/sh/Makefile
./linux-2.6.21/sound/sh/Makefile
--- ./linux-2.6.21-orig/sound/sh/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ ./linux-2.6.21/sound/sh/Makefile 2007-05-07 21:34:10.000000000 +0100
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+#
+
+snd-aica-objs := aica.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_AICA) += snd-aica.o
Signed-off by: Adrian McMenamin
2
1