Hi,

As has been discovered long ago [1] but eventually forgotten, Nokia 770 has
AIC23 audio hardware [2] which can be used not only from DSP side, but
from ARM as well. Moreover, OS2006 kernel sources even contain an ARM driver
for it, but this driver is disabled (that's understandable as the driver is
not in a very good shape and has quite a number of bugs).

Recently I have been trying to make it running and seems like we have a very
good chance to have it working nicely. It is also interesting, that the
linux-omap guys seem to be developing a new driver [3] for AIC23 which may
eventually become a better alternative.

Kernel patch is attached. It enables AIC32 driver, adds a hack to
power on/off code so that audio codec is permanently powered on (power 
on/off code is not reliable and needs to be reworked). Also it fixes a 
problem with audio stuttering on video playback in mplayer (the driver
had broken position reporting which is critical for proper audio/video
synchronization).

Here is some usage instruction (beware that standard disclaimer applies: 
you can use this patch at your own risk, this code is quite untested. If it
somehow manages to fry your device, you have been warned and I'm not
responsible for any breakages):

1. Disable esd daemon and DSP stuff in order to move it out of the way
(temporarily rename '/usr/bin/esd' and '/usr/sbin/dsp_dld' to something else)
2. Apply the attached patch to OS2006 kernel, compile and flash it to the
device
3. Compile and install alsa userspace library, I used alsa-lib-1.0.11.tar.bz2
4. Put attached 'asound.conf' into '/etc' directory on the device, it enables
dmix plugin for audio mixing and resampling
5. Compile and try some applications which use ALSA, I tested 'aplay' 
and 'mplayer'

The driver is semi-usable now, but a lot still needs to be done:
* proper power management to avoid excessive battery drain
* audio volume control
* switch between speaker/headphone
* audio quality is a bit crappy now, this needs to be fixed
* maybe some more fixes for bugs that are yet to be discovered...

DMA code is quite suspicious (especially the way it does channels linking) and
might be responsible for audio quality issues. Also sofware mixing/resampling
code in dmix plugin can benefit from ARM optimizations.


Now regarding why we may want it. Once if we get a good, low latency, fully
functional and reliable ALSA sound driver running on ARM, it gives maemo 
community a nice possibility to scrap all the proprietary DSP binaries. This
provides us with a new and shiny 252MHz C55x DSP core ready to be used by
something else :)

Free linux DSP toolchain from TI [4] supports generation of both DSP kernel
and DSP tasks for OMAP1 based devices which is sufficient for DSP development.
The toolchain license was supposed to permit open source development (with
noncommercial restriction), though the license text itself is a bit
questionable [5].

With DSP avalable for use and having no need to spend efforts on ensuring
compatibility and peaceful coexistence with proprietary binary codecs (free
and proprietary code does not mix well), it should be possible to turn 
Nokia 770 into quite a powerful media player.


1. http://lists.maemo.org/pipermail/maemo-developers/2006-June/022231.html
2. http://focus.ti.com/docs/prod/folders/print/tlv320aic23b.html
3. http://thread.gmane.org/gmane.linux.ports.arm.omap/11700/focus=11709
4. 
https://www-a.ti.com/downloads/sds_support/targetcontent/LinuxDspTools/index.html
5. http://www.gossamer-threads.com/lists/maemo/developers/30611

-- 
Best regards,
Siarhei Siamashka
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index 3862a77..90f113a 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -33,6 +33,8 @@
 #include <asm/arch/aic23.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/lcd_mipid.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/omap-alsa.h>
 
 extern void nokia770_ts_init(void);
 extern void nokia770_mmc_init(void);
@@ -67,6 +69,42 @@ static int nokia770_keymap[] = {
 	0
 };
 
+#define DEFAULT_BITPERSAMPLE 16
+
+static struct omap_mcbsp_reg_cfg mcbsp_regs = {
+    .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+    .spcr1 = RINTM(3) | RRST,
+    .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+        RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0),
+    .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+    .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+        XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG,
+    .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+    .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
+    .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
+    /*.pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,*/ /* mcbsp: master */
+    .pcr0 = CLKXP | CLKRP,  /* mcbsp: slave */
+};
+
+static struct omap_alsa_codec_config alsa_config = {
+    .name           = "Nokia770 AIC23",
+    .mcbsp_regs_alsa    = &mcbsp_regs,
+    .codec_configure_dev    = NULL, /* aic23_configure, */
+    .codec_set_samplerate   = NULL, /* aic23_set_samplerate, */
+    .codec_clock_setup  = NULL, /* aic23_clock_setup, */
+    .codec_clock_on     = NULL, /* aic23_clock_on, */
+    .codec_clock_off    = NULL, /* aic23_clock_off, */
+    .get_default_samplerate = NULL, /* aic23_get_default_samplerate, */
+};
+
+static struct platform_device nokia770_mcbsp1_device = {
+    .name   = "omap_alsa_mcbsp",
+    .id = 1,
+    .dev = {
+        .platform_data  = &alsa_config,
+    },
+};
+
 static struct resource nokia770_kp_resources[] = {
 	[0] = {
 		.start	= INT_KEYBOARD,
@@ -93,6 +131,7 @@ static struct platform_device nokia770_kp_device = {
 };
 
 static struct platform_device *nokia770_devices[] __initdata = {
+        &nokia770_mcbsp1_device,
         &nokia770_kp_device,
 };
 
@@ -275,6 +314,7 @@ static void __init nokia770_init(void)
 	nokia770_ts_init();
 	nokia770_mmc_init();
 	nokia770_audio_init();
+	nokia770_audio_pwr_up_request(0); /* Do codec power up (temporary hack to avoid bugs) */
 }
 
 static void __init nokia770_map_io(void)
diff --git a/sound/arm/omap/omap-alsa-aic23.c b/sound/arm/omap/omap-alsa-aic23.c
index 18b7395..0860b93 100644
--- a/sound/arm/omap/omap-alsa-aic23.c
+++ b/sound/arm/omap/omap-alsa-aic23.c
@@ -79,7 +79,7 @@ static snd_pcm_hardware_t aic23_snd_omap_alsa_playback = {
 	.rate_max = 96000,
 	.channels_min = 2,
 	.channels_max = 2,
-	.buffer_bytes_max = 128 * 1024,
+	.buffer_bytes_max = 64 * 1024,
 	.period_bytes_min = 32,
 	.period_bytes_max = 8 * 1024,
 	.periods_min = 16,
@@ -100,7 +100,7 @@ static snd_pcm_hardware_t aic23_snd_omap_alsa_capture = {
 	.rate_max = 96000,
 	.channels_min = 2,
 	.channels_max = 2,
-	.buffer_bytes_max = 128 * 1024,
+	.buffer_bytes_max = 64 * 1024,
 	.period_bytes_min = 32,
 	.period_bytes_max = 8 * 1024,
 	.periods_min = 16,
@@ -245,6 +245,7 @@ int aic23_clock_on(void)
  */
 int aic23_clock_off(void)
 {
+#if 0 /* This clock on/off stuff is buggy, disable it until it gets fixed */
 	if  (clk_get_usecount(aic23_mclk) > 0) { 
 		if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
 			printk(KERN_WARNING
@@ -259,6 +260,7 @@ int aic23_clock_off(void)
 	audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
 			  DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
 			  ADC_OFF | MIC_OFF | LINE_OFF);	
+#endif
 	return 0;
 }
 
diff --git a/sound/arm/omap/omap-alsa.c b/sound/arm/omap/omap-alsa.c
index 328003b..c580f59 100644
--- a/sound/arm/omap/omap-alsa.c
+++ b/sound/arm/omap/omap-alsa.c
@@ -147,14 +147,17 @@ static u_int audio_get_dma_pos(struct audio_stream *s)
 
 	/* For the current period let's see where we are */
 	count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+	if (count == 0) /* Errata workaround, see omap-linux git tree */
+		count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
 
 	spin_unlock_irqrestore(&s->dma_lock, flags);
 
-	/* Now, the position related to the end of that period */
-	offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
-
-	if (offset >= runtime->buffer_size)
-		offset = 0;
+	/* As 'omap_get_dma_src_addr_counter' returns lower 16-bit of current
+	   DMA position in the source buffer, we need to do this trick. 
+	   It should work fine as long as DMA buffer is not larger than 64K */
+	count = (count - (dma_addr_t)runtime->dma_area) & 0xFFFF;
+	offset = bytes_to_frames(runtime, count);
+	if (offset >= runtime->buffer_size) offset = 0;
 
 	return offset;
 }
pcm.dmixer {
    type dmix
    ipc_key 321456
    ipc_key_add_uid true
    slave {
        pcm "hw:0"
    }
}
pcm.!default {
    type plug
    slave.pcm "dmixer"
}
_______________________________________________
maemo-developers mailing list
maemo-developers@maemo.org
https://lists.maemo.org/mailman/listinfo/maemo-developers

Reply via email to