* omap alsa tsc2101 driver
@ 2006-02-05 21:24 lamikr
2006-02-06 19:13 ` Daniel Petrini
0 siblings, 1 reply; 13+ messages in thread
From: lamikr @ 2006-02-05 21:24 UTC (permalink / raw)
To: linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 7058 bytes --]
Hi
I have not seen anyone working with the tsc2101 Alsa driver, so attached
are the tsc2101 alsa driver sources I have been working for a while. The
patch should apply to the omap-driver head. Unfortunately it is still
non-functional at least with my omap 1510 based iPAQ h6340.
I can hear small start of the song but then nothing happens. I have
tried to debug the code and I can see that the the driver is able to get
one callback to sound_dma_irq_handler with DSCR_END_BLOCK set, but after
it does not continue with a next period of code.
Here is some info from the driver
- all code is located in /sound/arm/omap as I have wanted to mix it to
existing aic23 code until this one works
- based on to aic23 Alsa and tsc2101 OSS drivers. DMA code and driver
base taken from the aic, but hardware initialization taken from the
tsc2101 oss driver. (dma has only small changes like 16 bit mono to
capture params instead of 32 bit ones supported in the aic23)
- mixer code for DGC, headset and handset
- debug is mostly printed by using DPRINTK() function and can be enabled
by uncommenting "#define DEBUG 1" from the omap-alsa.h
- This is platform driver, so you need to register it to your board-code
in arch/arm/mach-omap1/board-* in a following way:
static struct platform_device h6300_mcbsp1_device = {
.name = "omap_tsc2101_mcbsp",
.id = 1,
};
static struct platform_device *h6300_devices[] __initdata = {
...
&h6300_mcbsp1_device,
};
I have only tested this with omap1510 based iPAQ h6300, so I would
appreciate if somebody else could test this with other
devices having tsc2101 chipset to find out whether this is just my hw
specific problem. (Fixes would ofcource also be nice :-)
For testing the driver I have plugged headset and listened the result of
following commands
- aplay song.wav (44100 hz 16 bit little endion format)
- "speaker-test -r 8000", "-r 44100", etc...
I have also tryed to change the audio_get_dma_pos() method to be like in
the sa11xx-uda1341.c driver. With implementation
based on to that, the speaker-test is able to produce somekind of
periodic "wuff <silence> wuff <silence> wuff..." sound.
(that method version is commented out in the omap-alsa-tsc2101.c)
In addition to sources, attached is the log from one play attempt.
Mika
root@h6300:~# aplay free_breakbeat.wav
Playing WAVE 'free_breakbeat.wav' : Signed 16 bit Little Endian, Rate
44100 Hz, Stereo
aplay: pcm_write:1146: write error: Input/output error
root@h6300:~# dmesg
XXX Alsa debug f:omap_alsa_tsc2101_init, l:1157
XXX Alsa debug f:snd_omap_alsa_tsc2101_probe, l:1077
XXX Alsa debug f:snd_card_omap_alsa_tsc2101_pcm, l:845
XXX Alsa debug f:omap_alsa_tsc2101_audio_init, l:350
XXX Alsa debug f:audio_dma_request, l:385
[omap_request_alsa_sound_dma]: start
[omap_request_alsa_sound_dma]: end(0)
XXX Alsa debug f:audio_dma_request, l:385
[omap_request_alsa_sound_dma]: start
[omap_request_alsa_sound_dma]: end(0)
[snd_omap_init_mixer]: start
[setRecordSource]: start
[setRecordSource]: end(0)
[snd_omap_init_mixer]: end(0)
OMAP_ALSA_TSC2101 audio support initialized
<omap_alsa_tsc2101_clock_on>: clock use count = 0
<omap_alsa_tsc2101_clock_on>: old clock rate = 12000000
omap_alsa_tsc2101_clock_on(), no need to change clock rate, rate already
12000000 Hz.
<omap_alsa_tsc2101_clock_on>: MCLK = 12000000 [12000000], usecount = 1,
clk_enable retval = 0
<snd_card_omap_alsa_tsc2101_open>: runtime->hw =
snd_omap_alsa_tsc2101_playback
<snd_omap_alsa_tsc2101_hw_params>: snd_omap_alsa_tsc2101_hw_params(),
size = 131072
XXX Alsa debug f:snd_omap_alsa_tsc2101_prepare, l:686
XXX Alsa debug f:omap_alsa_tsc2101_set_samplerate, l:248
<omap_alsa_tsc2101_set_samplerate>: selected 44.1khz PLL
<snd_omap_alsa_tsc2101_trigger>: cmd = 1
<audio_process_dma>: started, offset = 0, dma_size = 8192, s->period =
0, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1042022400
[omap_start_alsa_sound_dma]: start
<omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
-1042022400, dma_size = 8192
[audio_set_dma_params_play]: start
[audio_set_dma_params_play]: end(0)
[audio_start_dma_chain]: start
XXX Alsa debug f:audio_ifc_stop, l:229
XXX Alsa debug f:audio_ifc_start, l:222
[audio_start_dma_chain]: end(0)
[omap_start_alsa_sound_dma]: end(0)
<audio_process_dma>: done, offset = 0, dma_size = 8192, s->period = 0,
s->periods = 1, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1042022400
<audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
= 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
dma_ptr = -1042023937
<audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
<audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
<sound_dma_irq_handler>: started, lch = 0, status = 0x20, dma_status =
32, data = c0b0608c
<sound_dma_irq_handler>: status = DCSR_END_BLOCK, calling
audio_dma_callback()
<audio_dma_callback>: s->active, calling snd_pcm_period_elapsed
<audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
= 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
dma_ptr = -1042023937
<audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
<audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
<audio_process_dma>: started, offset = 8192, dma_size = 8192, s->period
= 1, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1042014208
[omap_start_alsa_sound_dma]: start
<omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
-1042014208, dma_size = 8192
[audio_set_dma_params_play]: start
[audio_set_dma_params_play]: end(0)
[audio_start_dma_chain]: start
[audio_start_dma_chain]: end(0)
[omap_start_alsa_sound_dma]: end(0)
<audio_process_dma>: done, offset = 8192, dma_size = 8192, s->period =
1, s->periods = 1, s->dma_q_head = 0, s->offset = 8192, rt->buffer_size
= 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr
= 0, dma_ptr = -1042014208
<sound_dma_irq_handler>: done
ALSA
/home/lamikr/own/h6300/git/linux-omap-h6300-2.6/sound/core/pcm_lib.c:2231:
playback write error (DMA or IRQ trouble?)
<snd_omap_alsa_tsc2101_trigger>: cmd = 0
XXX Alsa debug f:audio_stop_dma, l:488
[omap_alsa_audio_stop_dma]: start
[omap_alsa_audio_stop_dma]: end(0)
[omap_clear_alsa_sound_dma]: start
[omap_clear_alsa_sound_dma]: end(0)
XXX Alsa debug f:snd_card_omap_alsa_tsc2101_close, l:785
<omap_alsa_tsc2101_clock_off>: clock use count = 1
<omap_alsa_tsc2101_clock_off>: clock rate = 12000000
<omap_alsa_tsc2101_clock_off>: clock disabled
<omap_alsa_tsc2101_clock_off>: audio codec off
[-- Attachment #2: omap_alsa_tsc2101.patch --]
[-- Type: text/x-patch, Size: 85019 bytes --]
diff -Naur linux-omap-2.6/sound/arm/Kconfig linux-omap-h6300-2.6/sound/arm/Kconfig
--- linux-omap-2.6/sound/arm/Kconfig 2006-02-04 16:20:13.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/Kconfig 2006-02-04 22:17:41.000000000 +0200
@@ -45,4 +45,14 @@
To compile this driver as a module, choose M here: the module
will be called snd-omap-aic23.
+config SND_OMAP_ALSA_TSC2101
+ tristate "TSC2101 driver for OMAP boards which has TSC2101 chip."
+ depends ARCH_OMAP1
+ select SND_PCM
+ help
+ Say Y here if you have a OMAP platform board (iPAQ H63xx for example)
+ and want to use its TSC2101 audio chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-alsa-tsc2101.
endmenu
diff -Naur linux-omap-2.6/sound/arm/Makefile linux-omap-h6300-2.6/sound/arm/Makefile
--- linux-omap-2.6/sound/arm/Makefile 2006-02-04 16:20:13.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/Makefile 2006-02-04 22:13:16.000000000 +0200
@@ -16,3 +16,5 @@
obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-aic23.o
snd-omap-aic23-objs := omap-aic23.o omap-alsa-dma.o omap-alsa-mixer.o
+
+obj-$(CONFIG_SND) += omap/
diff -Naur linux-omap-2.6/sound/arm/omap/Makefile linux-omap-h6300-2.6/sound/arm/omap/Makefile
--- linux-omap-2.6/sound/arm/omap/Makefile 1970-01-01 02:00:00.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/omap/Makefile 2006-02-04 22:06:37.000000000 +0200
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+#
+
+snd-omap-alsa-tsc2101-objs := omap-alsa-tsc2101.o omap-alsa-tsc2101-dma.o omap-alsa-tsc2101-mixer.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_OMAP_ALSA_TSC2101) += snd-omap-alsa-tsc2101.o
diff -Naur linux-omap-2.6/sound/arm/omap/omap-alsa.h linux-omap-h6300-2.6/sound/arm/omap/omap-alsa.h
--- linux-omap-2.6/sound/arm/omap/omap-alsa.h 1970-01-01 02:00:00.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/omap/omap-alsa.h 2006-02-05 21:33:41.000000000 +0200
@@ -0,0 +1,88 @@
+/*
+ * sound/arm/omap/omap-alsa.h
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ * Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Based on omap-aic23.h and tsc2101 OSS drivers.
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-02-04 Mika Laitio - Alsa driver startup for omap boards.
+ * Still a work in progress as at least with h6300 the DMA is somehow
+ * not working. (Producess only a start of the sound)
+ */
+
+#ifndef OMAPALSA_H_
+#define OMAPALSA_H_
+
+#include <sound/driver.h>
+#include <asm/arch/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+//#define DEBUG 1
+#undef DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+#define DPRINTK(ARGS...) /* nop */
+#define ADEBUG() /* nop */
+#define FN_IN /* nop */
+#define FN_OUT(n) /* nop */
+#endif
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+/*
+ * Buffer management for alsa and dma
+ */
+struct audio_stream {
+ char *id; /* identification string */
+ int stream_id; /* numeric identification */
+ int dma_dev; /* dma number of that device */
+ int *lch; /* Chain of channels this stream is linked to */
+ char started; /* to store if the chain was started or not */
+ int dma_q_head; /* DMA Channel Q Head */
+ int dma_q_tail; /* DMA Channel Q Tail */
+ char dma_q_count; /* DMA Channel Q Count */
+ int active:1; /* we are using this stream for transfer now */
+ int period; /* current transfer period */
+ int periods; /* current count of periods registerd in the DMA engine */
+ spinlock_t dma_lock; /* for locking in DMA operations */
+ snd_pcm_substream_t *stream; /* the pcm stream */
+ unsigned linked:1; /* dma channels linked */
+ int offset; /* store start position of the last period in the alsa buffer */
+ int (*hw_start)(void); /* interface to start HW interface, e.g. McBSP */
+ int (*hw_stop)(void); /* interface to stop HW interface, e.g. McBSP */
+};
+
+#endif /*OMAPALSA_H_*/
diff -Naur linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101.c linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101.c
--- linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101.c 2006-02-05 21:37:29.000000000 +0200
@@ -0,0 +1,1170 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101.c
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ * Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Based on omap-aic23.c, sa11xx-uda1341.c and omap tsc2101 OSS drivers.
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Written by Nishanth Menon and Sriram Kannan
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-02-04 Mika Laitio - Alsa driver startup for omap boards.
+ * Still a work in progress as at least with h6300 the DMA is somehow
+ * not working. (Producess only a start of the sound)
+ */
+
+#include <linux/config.h>
+#include <sound/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/clock.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/memalloc.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+
+#include "omap-alsa-tsc2101.h"
+#include "omap-alsa-tsc2101-dma.h"
+#include "omap-alsa-tsc2101-mixer.h"
+
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_MACH_OMAP_H6300)
+#include <../drivers/ssi/omap-uwire.h>
+#include <asm/arch/dsp_common.h>
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#else
+#error "Unsupported configuration"
+#endif
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+
+/* Define to set the tsc2101 as the master w.r.t McBSP */
+#define TSC2101_MASTER
+#define CODEC_CLOCK 12000000
+
+MODULE_AUTHOR("Mika Laitio");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP TSC2101 Alsa driver");
+MODULE_SUPPORTED_DEVICE("{{TSC2101,OMAP TSC2101}}");
+MODULE_ALIAS("omap tsc2101 mcbsp.1");
+
+static char *id = NULL;
+MODULE_PARM_DESC(id, "OMAP OSK ALSA Driver for TSC2101 chip.");
+
+static struct snd_card_omap_alsa_tsc2101 *omap_tsc2101 = NULL;
+static struct clk *tsc2101_mclk = 0;
+
+struct sample_rate_reg_info {
+ u16 sample_rate;
+ u8 divisor;
+ u8 fs_44kHz;
+};
+
+/*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+ 7350, 8000, 8018, 8727,
+ 8820, 9600, 11025, 12000,
+ 14700, 16000, 22050, 24000,
+ 29400, 32000, 44100, 48000
+};
+
+static const struct sample_rate_reg_info
+ reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+ // Div 6
+ {7350, 7, 1},
+ {8000, 7, 0},
+ // Div 5.5
+ {8018, 6, 1},
+ {8727, 6, 0},
+ // Div 5
+ {8820, 5, 1},
+ {9600, 5, 0},
+ // Div 4
+ {11025, 4, 1},
+ {12000, 4, 0},
+ // Div 3
+ {14700, 3, 1},
+ {16000, 3, 0},
+ // Div 2
+ {22050, 2, 1},
+ {24000, 2, 0},
+ // Div 1.5
+ {29400, 1, 1},
+ {32000, 1, 0},
+ // Div 1
+ {44100, 0, 1},
+ {48000, 0, 0},
+};
+
+/*
+ * mcbsp configuration structure
+ */
+static struct omap_mcbsp_reg_cfg initial_config_mcbsp = {
+#ifdef CONFIG_MACH_OMAP_H6300
+ .spcr2 = 0x0005,
+ .spcr1 = 0x0005,
+ .rcr2 = 0x8041,
+ .rcr1 = 0x8041,
+ .xcr2 = 0x00a1,
+ .xcr1 = 0x00a1,
+ .srgr2 = 0xb000,
+ .srgr1 = 0xb000,
+ .pcr0 = 0x0081,
+#else
+ .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+ .spcr1 = RINTM(3) | RRST,
+ .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+ RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
+ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+ .srgr1 = FWID(15),
+ .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
+
+ /* platform specific initialization */
+# if defined(CONFIG_MACH_OMAP_H2)
+ .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
+# elif defined(CONFIG_MACH_OMAP_H3)
+
+# ifndef TSC2101_MASTER
+ .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
+# else
+ .pcr0 = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
+# endif /* !TSC2101_MASTER */
+# endif /* CONFIG_MACH_OMAP_H2 */
+#endif /* CONFIG_MACH_H6300 */
+};
+
+static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+/*********************************************************************************
+ *
+ * Simplified write for tsc Audio
+ *
+ *********************************************************************************/
+static __inline__ void audio_tsc2101_write(u8 address, u16 data)
+{
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, address, data);
+}
+
+/*********************************************************************************
+ *
+ * Simplified read for tsc Audio
+ *
+ *********************************************************************************/
+static __inline__ u16 audio_tsc2101_read(u8 address)
+{
+ return (omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, address));
+}
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+ ADEBUG();
+ omap_mcbsp_start(AUDIO_MCBSP);
+ return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+ ADEBUG();
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ return 0;
+}
+
+/*
+ * Codec/mcbsp init and configuration section
+ * codec dependent code.
+ */
+
+/*
+ * Sample rate changing
+ */
+static int omap_alsa_tsc2101_set_samplerate(struct snd_card_omap_alsa_tsc2101 *omap_tsc2101, long rate)
+{
+ u8 count = 0;
+ u16 data = 0;
+ int clkgdv = 0;
+
+ ADEBUG();
+ if (rate >= 48000)
+ rate = 48000;
+ else if (rate >= 44100)
+ rate = 44100;
+ else if (rate >= 32000)
+ rate = 32000;
+ else if (rate >= 29400)
+ rate = 29400;
+ else if (rate >= 24000)
+ rate = 24000;
+ else if (rate >= 22050)
+ rate = 22050;
+ else if (rate >= 16000)
+ rate = 16000;
+ else if (rate >= 14700)
+ rate = 14700;
+ else if (rate >= 12000)
+ rate = 12000;
+ else if (rate >= 11025)
+ rate = 11025;
+ else if (rate >= 9600)
+ rate = 9600;
+ else if (rate >= 8820)
+ rate = 8820;
+ else if (rate >= 8727)
+ rate = 8727;
+ else if (rate >= 8018)
+ rate = 8018;
+ else if (rate >= 8000)
+ rate = 8000;
+ else
+ rate = 7350;
+
+ /* wait for any frame to complete */
+ udelay(125);
+
+ /* Search for the right sample rate */
+ while ((reg_info[count].sample_rate != rate) &&
+ (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+ count++;
+ }
+ if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+ printk(KERN_ERR "Invalid Sample Rate %d requested\n", (int)rate);
+ return -EPERM;
+ }
+ /* Set AC1 */
+ data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
+ /*Clear prev settings */
+ data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+ data |= AC1_DACFS(reg_info[count].divisor) |
+ AC1_ADCFS(reg_info[count].divisor);
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
+
+ /* Set the AC3 */
+ data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
+ /*Clear prev settings */
+ data &= ~(AC3_REFFS | AC3_SLVMS);
+ data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC2101_MASTER
+ data |= AC3_SLVMS;
+#endif /* #ifdef TSC2101_MASTER */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
+
+ /* program the PLLs */
+ if (reg_info[count].fs_44kHz) {
+ /* 44.1 khz - 12 MHz Mclk */
+ DPRINTK("selected 44.1khz PLL\n");
+ audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */
+ audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */
+ } else {
+ /* 48 khz - 12 Mhz Mclk */
+ DPRINTK("selected 48khz PLL\n");
+ audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */
+ audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */
+ }
+
+ omap_tsc2101->samplerate = rate;
+
+ /* Set the sample rate */
+#ifndef TSC2101_MASTER
+ clkgdv = DEFAULT_MCBSP_CLOCK / (rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+ if (clkgdv) {
+ initial_config_mcbsp.srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ }
+ else {
+ return (1);
+ }
+
+ /* Stereo Mode */
+ initial_config_mcbsp.srgr2 = (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+ initial_config_mcbsp.srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ initial_config_mcbsp.srgr2 = ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif /* end of #ifdef TSC2101_MASTER */
+ omap_mcbsp_config(AUDIO_MCBSP, &initial_config_mcbsp);
+ return 0;
+}
+
+static void omap_alsa_tsc2101_audio_init(struct snd_card_omap_alsa_tsc2101 *omap_tsc2101)
+{
+ ADEBUG();
+ /* Setup DMA stuff */
+ omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa TSC2101 out";
+ omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id = SNDRV_PCM_STREAM_PLAYBACK;
+ omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev = OMAP_DMA_MCBSP1_TX;
+ omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start = audio_ifc_start;
+ omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop = audio_ifc_stop;
+
+ omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa TSC2101 in";
+ omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].stream_id = SNDRV_PCM_STREAM_CAPTURE;
+ omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev = OMAP_DMA_MCBSP1_RX;
+ omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].hw_start = audio_ifc_start;
+ omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop = audio_ifc_stop;
+
+ /* configuring the McBSP */
+ omap_mcbsp_request(AUDIO_MCBSP);
+
+ /* if configured, then stop mcbsp */
+ omap_mcbsp_stop(AUDIO_MCBSP);
+
+ omap_mcbsp_config(AUDIO_MCBSP, &initial_config_mcbsp);
+ omap_mcbsp_start(AUDIO_MCBSP);
+}
+
+/*
+ * DMA functions
+ * Depends on omap-alsa-tsc2101-dma.c functions and (omap) dma.c
+ *
+ */
+
+static int audio_dma_request(struct audio_stream *s,
+ void (*callback) (void *))
+{
+ int err;
+
+ ADEBUG();
+ err = omap_request_alsa_sound_dma(s->dma_dev,
+ s->id,
+ s,
+ &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
+ return err;
+}
+
+static int audio_dma_free(struct audio_stream *s)
+{
+ int err = 0;
+
+ ADEBUG();
+ err = omap_free_alsa_sound_dma(s, &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "Unable to free audio dma channels!\n");
+ return err;
+}
+
+/*
+ * This function should calculate the current position of the dma in the
+ * buffer. It will help alsa middle layer to continue update the buffer.
+ * Its correctness is crucial for good functioning.
+ */
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ unsigned int offset;
+ unsigned long flags;
+ dma_addr_t count;
+ long offsetFrame;
+ long countFrame;
+ long dmaAddr;
+
+ // this must be called w/ interrupts locked as requested in dma.c
+ spin_lock_irqsave(&s->dma_lock, flags);
+ // For the current period let's see where we are
+ count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+ dmaAddr = runtime->dma_addr;
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+ // Now, the position related to the end of that period
+ //dma_size = frames_to_bytes(runtime, runtime->period_size);
+ //offsetFrame = dma_size * s->period;
+ offsetFrame = bytes_to_frames(runtime, s->offset);
+ countFrame = bytes_to_frames(runtime, count);
+ offset = offsetFrame - countFrame;
+ DPRINTK("count = %d, s->dma_q_head = %d, s->offset = %d, s->period = %d, s->periods = %d, rt->buffer_size = %ld, rt->period_size = %ld, rt->frame_bits = %d, runtime->dma_addr = %ld, offset = %d, dma_ptr = %d\n",
+ count,
+ s->dma_q_head,
+ s->offset,
+ s->period,
+ s->periods,
+ runtime->buffer_size,
+ runtime->period_size,
+ runtime->frame_bits,
+ dmaAddr,
+ offset,
+ (dma_addr_t)runtime->dma_area + offset);
+ DPRINTK("offsetFrame= %ld, countFrame = %ld\n", offsetFrame, countFrame);
+ if ((offset >= runtime->buffer_size) ||
+ (offset < 0))
+ {
+ offset = 0;
+ DPRINTK("warning, resetted offset to 0, old offset val = %d\n", offset);
+ }
+ return offset;
+}
+
+/*
+// a version from sa11xx-uda1341.c...
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+ snd_pcm_substream_t * substream = s->stream;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ unsigned int offset;
+ unsigned long flags;
+ dma_addr_t addr;
+
+ // this must be called w/ interrupts locked out see dma-sa1100.c in the kernel
+ spin_lock_irqsave(&s->dma_lock, flags);
+ //addr = sa1100_get_dma_pos((s)->dma_regs);
+ addr = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+ offset = addr - runtime->dma_addr;
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+
+ offset = bytes_to_frames(runtime, offset);
+ if (offset >= runtime->buffer_size)
+ offset = 0;
+
+ return offset;
+}
+*/
+
+/*
+ * this stops the dma and clears the dma ptrs
+ */
+static void audio_stop_dma(struct audio_stream *s)
+{
+ unsigned long flags;
+
+ ADEBUG();
+ spin_lock_irqsave(&s->dma_lock, flags);
+ s->active = 0;
+ s->period = 0;
+ s->periods = 0;
+
+ /* this stops the dma channel and clears the buffer ptrs */
+ omap_alsa_audio_stop_dma(s);
+ omap_clear_alsa_sound_dma(s);
+
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+/*
+ * Main dma routine, requests dma according where you are in main alsa buffer
+ */
+static void audio_process_dma(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime;
+ int period;
+ unsigned int dma_size;
+ unsigned int offset;
+ int ret;
+
+ runtime = substream->runtime;
+ if (s->active) {
+ dma_size= frames_to_bytes(runtime, runtime->period_size);
+ period = s->period;
+ offset = dma_size * period;
+ snd_assert(dma_size <= DMA_BUF_SIZE,);
+ DPRINTK("started, offset = %u, dma_size = %u, s->period = %d, s->periods = %d, s->dma_q_head = %d, s->offset = %d, rt->buffer_size = %ld, rt->period_size = %ld, rt->frame_bits = %d, runtime->dma_addr = %u, dma_ptr = %d\n",
+ offset,
+ dma_size,
+ period,
+ s->periods,
+ s->dma_q_head,
+ s->offset,
+ runtime->buffer_size,
+ runtime->period_size,
+ runtime->frame_bits,
+ runtime->dma_addr,
+ (dma_addr_t)runtime->dma_area + offset);
+ ret = omap_start_alsa_sound_dma(s,
+ (dma_addr_t)runtime->dma_area + offset,
+ dma_size);
+ if (ret) {
+ printk(KERN_ERR "audio_process_dma(): cannot queue DMA buffer (%i)\n", ret);
+ return;
+ }
+ s->period++;
+ s->period %= runtime->periods;
+ s->periods++;
+ s->offset = offset;
+ DPRINTK("done, offset = %d, dma_size = %u, s->period = %d, s->periods = %d, s->dma_q_head = %d, s->offset = %d, rt->buffer_size = %ld, rt->period_size = %ld, rt->frame_bits = %d, runtime->dma_addr = %u, dma_ptr = %d\n",
+ offset,
+ dma_size,
+ period,
+ s->periods,
+ s->dma_q_head,
+ s->offset,
+ runtime->buffer_size,
+ runtime->period_size,
+ runtime->frame_bits,
+ runtime->dma_addr,
+ (dma_addr_t)runtime->dma_area + offset);
+ }
+ else {
+ DPRINTK("WARNING, stream not active.");
+ }
+}
+
+/*
+// a version from sa11xx-uda1341.c...
+static void audio_process_dma(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime;
+ unsigned int dma_size;
+ unsigned int offset;
+ int ret;
+
+ // we are requested to process synchronization DMA transfer
+
+ if (s->tx_spin) {
+ snd_assert(s->stream_id == SNDRV_PCM_STREAM_PLAYBACK, return);
+ // fill the xmit dma buffers and return
+ while (1) {
+ ret = omap_start_alsa_sound_dma(s->dma_regs,
+ FORCE_CLOCK_
+ ADDR,
+ FORCE_CLOCK_SIZE);
+ if (ret)
+ return;
+ }
+ return;
+ }
+ // must be set here - only valid for running streams, not for forced_clock dma fills
+ runtime = substream->runtime;
+ DPRINTK("s->active = %d, s->periods = %d, s->period = %d, runtime->periods = %d\n", s->active, s->periods, s->period, runtime->periods);
+ while (s->active && s->periods < runtime->periods) {
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ if (s->old_offset) {
+ // a little trick, we need resume from old position
+ offset = frames_to_bytes(runtime, s->old_offset - 1);
+ s->old_offset = 0;
+ s->periods = 0;
+ s->period = offset / dma_size;
+ offset %= dma_size;
+ dma_size = dma_size - offset;
+ if (!dma_size)
+ continue; // special case
+ } else {
+ offset = dma_size * s->period;
+ snd_assert(dma_size <= DMA_BUF_SIZE, );
+ }
+ ret = omap_start_alsa_sound_dma(s, //(s)->dma_regs,
+ runtime->dma_area + offset,
+ dma_size);
+ if (ret) {
+ printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret);
+ return;
+ }
+ s->period++;
+ s->period %= runtime->periods;
+ s->periods++;
+ }
+ DPRINTK("s->active = %d, s->periods = %d, s->period = %d, runtime->periods = %d\n", s->active, s->periods, s->period, runtime->periods);
+}
+*/
+
+/*
+ * This is called when dma IRQ occurs at the end of each transmited block
+ */
+void audio_dma_callback(void *data)
+{
+ struct audio_stream *s = data;
+
+ /*
+ * If we are getting a callback for an active stream then we inform
+ * the PCM middle layer we've finished a period
+ */
+ if (s->active) {
+ DPRINTK("s->active, calling snd_pcm_period_elapsed\n");
+ snd_pcm_period_elapsed(s->stream);
+ }
+ else {
+ DPRINTK("s->active == FALSE\n");
+ }
+ spin_lock(&s->dma_lock);
+ if (s->periods > 0) {
+ //DPRINTK("reducing periods\n");
+ s->periods--;
+ }
+ audio_process_dma(s);
+ spin_unlock(&s->dma_lock);
+}
+
+/*
+ * Alsa section
+ * PCM settings and callbacks
+ */
+
+static int snd_omap_alsa_tsc2101_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+ struct snd_card_omap_alsa_tsc2101 *chip = snd_pcm_substream_chip(substream);
+ int stream_id = substream->pstr->stream;
+ struct audio_stream *s = &chip->s[stream_id];
+ int err = 0;
+
+ DPRINTK("cmd = %d\n", cmd);
+ /* note local interrupts are already disabled in the midlevel code */
+ spin_lock(&s->dma_lock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* requested stream startup */
+ s->active = 1;
+ audio_process_dma(s);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* requested stream shutdown */
+ audio_stop_dma(s);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ spin_unlock(&s->dma_lock);
+
+ return err;
+}
+
+static int snd_omap_alsa_tsc2101_prepare(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_alsa_tsc2101 *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct audio_stream *s = &chip->s[substream->pstr->stream];
+
+ ADEBUG();
+ /* clock configuration, set set requested samplerate */
+ omap_alsa_tsc2101_set_samplerate(chip, runtime->rate);
+
+ s->period = 0;
+ s->periods = 0;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t snd_omap_alsa_tsc2101_pointer(snd_pcm_substream_t *substream)
+{
+ struct snd_card_omap_alsa_tsc2101 *chip = snd_pcm_substream_chip(substream);
+
+ return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+/* Hardware capabilities */
+
+static snd_pcm_hardware_t snd_omap_alsa_tsc2101_capture =
+{
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = DMA_BUF_SIZE,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+/* playback */
+static snd_pcm_hardware_t snd_omap_alsa_tsc2101_playback = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = DMA_BUF_SIZE,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static int snd_card_omap_alsa_tsc2101_open(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_alsa_tsc2101 *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int stream_id = substream->pstr->stream;
+ int err;
+
+ chip->s[stream_id].stream = substream;
+ omap_alsa_tsc2101_clock_on();
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+ DPRINTK("runtime->hw = snd_omap_alsa_tsc2101_playback\n");
+ runtime->hw = snd_omap_alsa_tsc2101_playback;
+ }
+ else {
+ DPRINTK("runtime->hw = snd_omap_alsa_tsc2101_capture\n");
+ runtime->hw = snd_omap_alsa_tsc2101_capture;
+ }
+ if ((err = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {
+ DPRINTK("ERROR snd_pcm_hw_constraint_integer failed, error-code = %d\n", err);
+ return err;
+ }
+ if ((err = snd_pcm_hw_constraint_list(runtime,
+ 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_constraints_rates)) < 0) {
+ DPRINTK("ERROR snd_pcm_hw_constraint_list failed, error-code = %d\n", err);
+ return err;
+ }
+ return 0;
+}
+
+static int snd_card_omap_alsa_tsc2101_close(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_alsa_tsc2101 *chip = snd_pcm_substream_chip(substream);
+
+ ADEBUG();
+ omap_alsa_tsc2101_clock_off();
+ chip->s[substream->pstr->stream].stream = NULL;
+
+ return 0;
+}
+
+/* HW params & free */
+
+static int snd_omap_alsa_tsc2101_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ size_t curSize;
+
+ curSize = params_buffer_bytes(hw_params);
+ DPRINTK("snd_omap_alsa_tsc2101_hw_params(), size = %d\n", curSize);
+ return snd_pcm_lib_malloc_pages(substream,
+ curSize);
+}
+
+static int snd_omap_alsa_tsc2101_hw_free(snd_pcm_substream_t * substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+
+static snd_pcm_ops_t snd_card_omap_alsa_tsc2101_playback_ops = {
+ .open = snd_card_omap_alsa_tsc2101_open,
+ .close = snd_card_omap_alsa_tsc2101_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_alsa_tsc2101_hw_params,
+ .hw_free = snd_omap_alsa_tsc2101_hw_free,
+ .prepare = snd_omap_alsa_tsc2101_prepare,
+ .trigger = snd_omap_alsa_tsc2101_trigger,
+ .pointer = snd_omap_alsa_tsc2101_pointer,
+};
+
+static snd_pcm_ops_t snd_card_omap_alsa_tsc2101_capture_ops = {
+ .open = snd_card_omap_alsa_tsc2101_open,
+ .close = snd_card_omap_alsa_tsc2101_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_alsa_tsc2101_hw_params,
+ .hw_free = snd_omap_alsa_tsc2101_hw_free,
+ .prepare = snd_omap_alsa_tsc2101_prepare,
+ .trigger = snd_omap_alsa_tsc2101_trigger,
+ .pointer = snd_omap_alsa_tsc2101_pointer,
+};
+
+/*
+ * Alsa init and exit section
+ *
+ * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
+static int __init snd_card_omap_alsa_tsc2101_pcm(struct snd_card_omap_alsa_tsc2101 *omap_tsc2101,
+ int device)
+{
+ snd_pcm_t *pcm;
+ int err;
+
+ ADEBUG();
+ err = snd_pcm_new(omap_tsc2101->card, "TSC2101 PCM", device, 1, 1, &pcm);
+ if (err < 0)
+ return err;
+
+ /* sets up initial buffer with continuous allocation */
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data
+ (GFP_KERNEL),
+ 128 * 1024,
+ 128 * 1024);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_card_omap_alsa_tsc2101_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_card_omap_alsa_tsc2101_capture_ops);
+ pcm->private_data = omap_tsc2101;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "omap tsc2101 pcm");
+
+ omap_alsa_tsc2101_audio_init(omap_tsc2101);
+
+ /* setup DMA controller */
+ audio_dma_request(&omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK],
+ audio_dma_callback);
+ audio_dma_request(&omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE],
+ audio_dma_callback);
+ omap_tsc2101->pcm = pcm;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int snd_omap_alsa_tsc2101_suspend(snd_card_t * card, pm_message_t state)
+{
+// struct snd_card_omap_alsa_tsc2101 *chip = card->private_data;
+ ADEBUG();
+/*
+ if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ // Mutes and turn clock off
+ omap_alsa_tsc2101_clock_off();
+ snd_omap_suspend_mixer();
+ }
+*/
+ return 0;
+}
+
+/*
+ * Prepare hardware for resume
+ */
+static int snd_omap_alsa_tsc2101_resume(snd_card_t * card)
+{
+// struct snd_card_omap_alsa_tsc2101 *chip = card->private_data;
+ ADEBUG();
+/*
+ if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+ omap_alsa_tsc2101_clock_on();
+ snd_omap_resume_mixer();
+ }
+*/
+ return 0;
+}
+
+/*
+ * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
+ */
+static int omap_alsa_tsc2101_suspend(struct platform_device *pdev, pm_message_t state)
+{
+// snd_card_t *card = platform_get_drvdata(pdev);
+ ADEBUG();
+/*
+ if (card->power_state != SNDRV_CTL_POWER_D3hot) {
+ snd_omap_alsa_tsc2101_suspend(card, PMSG_SUSPEND);
+ }
+*/
+ return 0;
+}
+
+static int omap_alsa_tsc2101_resume(struct platform_device *pdev)
+{
+// snd_card_t *card = platform_get_drvdata(pdev);
+ ADEBUG();
+/*
+ if (card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_omap_alsa_tsc2101_resume(card);
+ }
+*/
+ return 0;
+}
+
+#else
+#define snd_omap_alsa_tsc2101_suspend NULL
+#define snd_omap_alsa_tsc2101_resume NULL
+#define omap_alsa_tsc2101_suspend NULL
+#define omap_alsa_tsc2101_resume NULL
+
+#endif /* CONFIG_PM */
+
+void snd_omap_alsa_tsc2101_free(snd_card_t * card) {
+ struct snd_card_omap_alsa_tsc2101 *chip = card->private_data;
+ ADEBUG();
+
+ /*
+ * Turn off codec after it is done.
+ * Can't do it immediately, since it may still have
+ * buffered data.
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2);
+
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+/*
+ audio_tsc2101_write(RESET_CONTROL_ADDR, 0);
+ audio_tsc2101_write(POWER_DOWN_CONTROL_ADDR, 0xff);
+*/
+
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+/*
+ * Omap MCBSP clock configuration
+ *
+ * Here we have some functions that allows clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+
+/*
+ * Do clock framework mclk search
+ */
+static __init void omap_alsa_tsc2101_clock_setup(void)
+{
+ tsc2101_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ * turn codec audio on
+ */
+int omap_alsa_tsc2101_clock_on(void)
+{
+ int curUseCount;
+ uint curRate;
+ int err;
+
+ curUseCount = clk_get_usecount(tsc2101_mclk);
+ DPRINTK("clock use count = %d\n", curUseCount);
+ if (curUseCount > 0) {
+ // MCLK is already in use
+ printk(KERN_WARNING
+ "MCLK already in use at %d Hz. We change it to %d Hz\n",
+ (uint) clk_get_rate(tsc2101_mclk),
+ CODEC_CLOCK);
+ }
+ curRate = (uint)clk_get_rate(tsc2101_mclk);
+ DPRINTK("old clock rate = %d\n", curRate);
+ if (curRate != CODEC_CLOCK) {
+ err = clk_set_rate(tsc2101_mclk, CODEC_CLOCK);
+ if (err) {
+ printk(KERN_ERR
+ "Cannot set MCLK clock rate for TSC2101 CODEC, error code = %d\n", err);
+ return -ECANCELED;
+ }
+ }
+ else
+ {
+ printk(KERN_INFO
+ "omap_alsa_tsc2101_clock_on(), no need to change clock rate, rate already %d Hz.\n",
+ CODEC_CLOCK);
+ }
+ err = clk_enable(tsc2101_mclk);
+ curRate = (uint)clk_get_rate(tsc2101_mclk);
+ curUseCount = clk_get_usecount(tsc2101_mclk);
+ DPRINTK("MCLK = %d [%d], usecount = %d, clk_enable retval = %d\n",
+ curRate,
+ CODEC_CLOCK,
+ curUseCount,
+ err);
+
+ // Now turn the audio on
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_CODEC_POWER_CTRL,
+ 0x0000);
+ return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn
+ * codec audio off
+ */
+ // from omap-aic23.c
+int omap_alsa_tsc2101_clock_off(void)
+{
+ int curUseCount;
+ int curRate;
+
+ curUseCount = clk_get_usecount(tsc2101_mclk);
+ DPRINTK("clock use count = %d\n", curUseCount);
+ if (curUseCount > 0) {
+ curRate = clk_get_rate(tsc2101_mclk);
+ DPRINTK("clock rate = %d\n", curRate);
+ if (curRate != CODEC_CLOCK) {
+ printk(KERN_WARNING
+ "MCLK for audio should be %d Hz. But is %d Hz\n",
+ (uint) clk_get_rate(tsc2101_mclk),
+ CODEC_CLOCK);
+ }
+ clk_disable(tsc2101_mclk);
+ DPRINTK("clock disabled\n");
+ }
+ audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
+ ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+ DPRINTK("audio codec off\n");
+ return 0;
+}
+
+/* module init & exit */
+
+/*
+ * Inits alsa soudcard structure
+ */
+static int __init snd_omap_alsa_tsc2101_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ snd_card_t *card;
+
+ ADEBUG();
+ /* gets clock from clock framework */
+ omap_alsa_tsc2101_clock_setup();
+
+ /* register the soundcard */
+ card = snd_card_new(-1, id, THIS_MODULE, sizeof(omap_tsc2101));
+ if (card == NULL)
+ return -ENOMEM;
+
+ omap_tsc2101 = kcalloc(1, sizeof(*omap_tsc2101), GFP_KERNEL);
+ if (omap_tsc2101 == NULL)
+ return -ENOMEM;
+
+ card->private_data = (void *)omap_tsc2101;
+ card->private_free = snd_omap_alsa_tsc2101_free;
+
+ omap_tsc2101->card = card;
+ omap_tsc2101->samplerate = AUDIO_RATE_DEFAULT;
+
+ spin_lock_init(&omap_tsc2101->s[0].dma_lock);
+ spin_lock_init(&omap_tsc2101->s[1].dma_lock);
+
+ /* mixer */
+ if ((err = snd_omap_mixer(omap_tsc2101)) < 0)
+ goto nodev;
+
+ /* PCM */
+ if ((err = snd_card_omap_alsa_tsc2101_pcm(omap_tsc2101, 0)) < 0)
+ goto nodev;
+
+ strcpy(card->driver, "OMAP_ALSA_TSC2101");
+ strcpy(card->shortname, "OMAP_ALSA_TSC2101");
+ sprintf(card->longname, "OMAP_ALSA_TSC2101 driver");
+
+ snd_omap_init_mixer();
+
+ snd_card_set_dev(card, &pdev->dev);
+
+ if ((err = snd_card_register(card)) == 0) {
+ printk(KERN_INFO "OMAP_ALSA_TSC2101 audio support initialized\n");
+ platform_set_drvdata(pdev, card);
+ return 0;
+ }
+
+nodev:
+ snd_omap_alsa_tsc2101_free(card);
+
+ return err;
+}
+
+static int snd_omap_alsa_tsc2101_remove(struct platform_device *pdev)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+ struct snd_card_omap_alsa_tsc2101 *chip = card->private_data;
+
+ snd_card_free(card);
+
+ omap_tsc2101 = NULL;
+ card->private_data = NULL;
+ kfree(chip);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver omap_alsa_driver = {
+ .probe = snd_omap_alsa_tsc2101_probe,
+ .remove = snd_omap_alsa_tsc2101_remove,
+ .suspend = omap_alsa_tsc2101_suspend,
+ .resume = omap_alsa_tsc2101_resume,
+ .driver = {
+ .name = "omap_tsc2101_mcbsp",
+ },
+};
+
+static int __init omap_alsa_tsc2101_init(void)
+{
+ int err;
+
+ ADEBUG();
+ err = platform_driver_register(&omap_alsa_driver);
+ return err;
+}
+
+static void __exit omap_alsa_tsc2101_exit(void)
+{
+ ADEBUG();
+
+ platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2101_init);
+module_exit(omap_alsa_tsc2101_exit);
diff -Naur linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101-dma.c linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101-dma.c
--- linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101-dma.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101-dma.c 2006-02-05 19:37:47.000000000 +0200
@@ -0,0 +1,530 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-dma.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c. This file
+ * will contain only the DMA interface and buffer handling of OMAP
+ * audio driver.
+ *
+ * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking of DMA logical channel.
+ *
+ * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support multi channel chaining.
+ *
+ * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
+ *
+ * 2005-07-19 INdT Kernel Team - Alsa port. Creation of new file omap-alsa-dma.c based in
+ * omap-audio-dma-intfc.c oss file. Support for aic23 codec.
+ * Removal of buffer handling (Alsa does that), modifications
+ * in dma handling and port to alsa structures.
+ *
+ * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ * 2006-02-04 Mika Laitio - Tryed to make work with the OMAP 1510 based iPAQ h6300 that has tsc2101 chipset.
+ * This work is still in progress.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/mcbsp.h>
+
+#include "omap-alsa-tsc2101-dma.h"
+#include "omap-alsa-tsc2101.h"
+
+/* Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+//lamikr: same
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
+#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
+#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
+
+/* TODO: To be moved to more appropriate location */
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE 0x1000000
+//lamikr: cut_dma_size is not used in the alsa version.
+#define CUT_DMA_SIZE 0x1000
+#define DCSR_ERROR 0x3
+
+// lamikr: missing from the oss version
+#define DCSR_END_BLOCK (1 << 5)
+// lamikr: same than in in omap-alsa-dma.c and oss dma version
+#define DCSR_SYNC_SET (1 << 6)
+
+#define DCCR_FS (1 << 5)
+#define DCCR_PRIO (1 << 6)
+#define DCCR_EN (1 << 7)
+#define DCCR_AI (1 << 8)
+#define DCCR_REPEAT (1 << 9)
+/* if 0 the channel works in 3.1 compatible mode*/
+#define DCCR_N31COMP (1 << 10)
+#define DCCR_EP (1 << 11)
+#define DCCR_SRC_AMODE_BIT 12
+#define DCCR_SRC_AMODE_MASK (0x3<<12)
+#define DCCR_DST_AMODE_BIT 14
+#define DCCR_DST_AMODE_MASK (0x3<<14)
+#define AMODE_CONST 0x0
+#define AMODE_POST_INC 0x1
+#define AMODE_SINGLE_INDEX 0x2
+#define AMODE_DOUBLE_INDEX 0x3
+
+/**************************** DATA STRUCTURES *****************************************/
+//lamikr: both of these exist in omap-alsa-dma.c and oss dma.
+static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
+
+static char nr_linked_channels = 1;
+
+/*********************************** MODULE SPECIFIC FUNCTIONS ***********************/
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_start_dma_chain(struct audio_stream * s);
+
+/***************************************************************************************
+ *
+ * DMA channel requests
+ *
+ **************************************************************************************/
+//lamikr:functionality same than with oss and omap-alsa-dma (except audio_stream datatype itself)
+static void omap_sound_dma_link_lch(void *data)
+{
+ struct audio_stream *s = (struct audio_stream *) data;
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (s->linked) {
+ FN_OUT(1);
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ int nex_chan =
+ ((nr_linked_channels - 1 ==
+ i) ? chan[0] : chan[i + 1]);
+ omap_dma_link_lch(cur_chan, nex_chan);
+ }
+ s->linked = 1;
+ FN_OUT(0);
+}
+
+//lamikr: same in oma-alsa-dma.c and omap oss version of dma
+int omap_request_alsa_sound_dma(int device_id,
+ const char *device_name,
+ void *data,
+ int **channels)
+{
+ int i, err = 0;
+ int *chan = NULL;
+ FN_IN;
+ if (unlikely((NULL == channels) || (NULL == device_name))) {
+ BUG();
+ return -EPERM;
+ }
+ /* Try allocate memory for the num channels */
+ *channels = (int *)kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
+ chan = *channels;
+ if (NULL == chan) {
+ ERR("No Memory for channel allocs!\n");
+ FN_OUT(-ENOMEM);
+ return -ENOMEM;
+ }
+ spin_lock(&dma_list_lock);
+ for (i = 0; i < nr_linked_channels; i++) {
+ err = omap_request_dma(device_id,
+ device_name,
+ sound_dma_irq_handler,
+ data,
+ &chan[i]);
+ /* Handle Failure condition here */
+ if (err < 0) {
+ int j;
+ for (j = 0; j < i; j++) {
+ omap_free_dma(chan[j]);
+ }
+ spin_unlock(&dma_list_lock);
+ kfree(chan);
+ *channels = NULL;
+ ERR("Error in requesting channel %d=0x%x\n", i, err);
+ FN_OUT(err);
+ return err;
+ }
+ }
+ /* Chain the channels together */
+ if (!cpu_is_omap1510())
+ {
+ DPRINTK("calling omap_sound_dma_link_lch()\n");
+ omap_sound_dma_link_lch(data);
+ }
+ spin_unlock(&dma_list_lock);
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests Freeing
+ *
+ **************************************************************************************/
+//lamikr:same than with oss and omap-alsa-dma (except audio_stream)
+static void omap_sound_dma_unlink_lch(void *data)
+{
+ struct audio_stream *s = (struct audio_stream *) data;
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (!s->linked) {
+ FN_OUT(1);
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ int nex_chan = ((nr_linked_channels - 1 == i) ? chan[0] : chan[i + 1]);
+ omap_dma_unlink_lch(cur_chan, nex_chan);
+ }
+ s->linked = 0;
+ FN_OUT(0);
+}
+
+//lamikr:same than with oss and omap-alsa-dma
+int omap_free_alsa_sound_dma(void *data,
+ int **channels)
+{
+ int i;
+ int *chan = NULL;
+ FN_IN;
+ if (unlikely(NULL == channels)) {
+ BUG();
+ return -EPERM;
+ }
+ if (unlikely(NULL == *channels)) {
+ BUG();
+ return -EPERM;
+ }
+ chan = (*channels);
+
+ if (!cpu_is_omap1510())
+ omap_sound_dma_unlink_lch(data);
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ omap_stop_dma(cur_chan);
+ omap_free_dma(cur_chan);
+ }
+ kfree(*channels);
+ *channels = NULL;
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************************************************************************
+ *
+ * Stop all the DMA channels of the stream
+ *
+ **************************************************************************************/
+void omap_alsa_audio_stop_dma(struct audio_stream *s)
+{
+ int *chan = s->lch;
+ int i;
+ FN_IN;
+ if (unlikely(NULL == chan)) {
+ BUG();
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ omap_stop_dma(cur_chan);
+ }
+ s->started = 0;
+ FN_OUT(0);
+ return;
+}
+
+/***************************************************************************************
+ *
+ * Clear any pending transfers
+ *
+ **************************************************************************************/
+//oss and alsa has same version (except stream type)
+void omap_clear_alsa_sound_dma(struct audio_stream * s)
+{
+ FN_IN;
+ omap_clear_dma(s->lch[s->dma_q_head]);
+ FN_OUT(0);
+ return;
+}
+
+/***************************************************************************************
+ *
+ * DMA related functions
+ *
+ **************************************************************************************/
+static int audio_set_dma_params_play(int channel,
+ dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int dt;
+ int cen;
+ int cfn;
+ unsigned long dest_start;
+ int dest_port;
+ int sync_dev;
+
+ FN_IN;
+ dt = OMAP_DMA_DATA_TYPE_S16; /* data type 16 */
+ cen = 32; /* Stereo */
+ cfn = dma_size / (2 * cen);
+ dest_start = AUDIO_MCBSP_DATAWRITE;
+ if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ dest_port = OMAP_DMA_PORT_MPUI;
+ sync_dev = 0;
+ }
+ else if (cpu_is_omap24xx()) {
+ dest_port = 0;
+ sync_dev = AUDIO_DMA_TX;
+ }
+ else {
+ DPRINTK("uses default values purposed for omap1510 and omap1610\n");
+ dest_port = OMAP_DMA_PORT_MPUI;
+ sync_dev = 0;
+ }
+ omap_set_dma_dest_params(channel,
+ dest_port,
+ OMAP_DMA_AMODE_CONSTANT,
+ dest_start, // dma physically to
+ 0,
+ 0);
+ omap_set_dma_src_params(channel,
+ 0,
+ OMAP_DMA_AMODE_POST_INC,
+ dma_ptr, // dma physically from
+ 0,
+ 0);
+ omap_set_dma_transfer_params(channel,
+ dt, // datatype
+ cen, // element count
+ cfn, // frame count
+ OMAP_DMA_SYNC_ELEMENT,
+ sync_dev,
+ 0);
+ FN_OUT(0);
+ return 0;
+}
+
+// lamikr: omap-alsa-dma.c for aic23 sets cen to 32 (=stereo) but tsc2101 supports only 16 bit capture. (see tsc2101 oss driver)
+static int audio_set_dma_params_capture(int channel,
+ dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int dt;
+ int cen;
+ int cfn;
+ unsigned long src_start;
+ int src_port;
+ int sync_dev;
+ int src_sync;
+
+ FN_IN;
+ dt = OMAP_DMA_DATA_TYPE_S16; // data type 16
+ cen = 16; // mono
+ cfn = dma_size / (2 * cen);
+ src_start = AUDIO_MCBSP_DATAREAD;
+ if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ src_port = OMAP_DMA_PORT_MPUI;
+ sync_dev = 0;
+ src_sync = 0;
+ }
+ else if (cpu_is_omap24xx()) {
+ src_port = 0;
+ sync_dev = AUDIO_DMA_RX;
+ src_sync = 1;
+ }
+ else {
+ DPRINTK("uses default values purposed for omap1510 and omap1610\n");
+ src_port = OMAP_DMA_PORT_MPUI;
+ sync_dev = 0;
+ src_sync = 0;
+ }
+ omap_set_dma_src_params(channel,
+ src_port,
+ OMAP_DMA_AMODE_CONSTANT,
+ src_start,
+ 0,
+ 0);
+ omap_set_dma_dest_params(channel,
+ 0,
+ OMAP_DMA_AMODE_POST_INC,
+ dma_ptr,
+ 0,
+ 0);
+ omap_set_dma_transfer_params(channel,
+ dt,
+ cen,
+ cfn,
+ OMAP_DMA_SYNC_ELEMENT,
+ sync_dev,
+ src_sync);
+ FN_OUT(0);
+ return 0;
+}
+
+//lamikr: same
+static int audio_start_dma_chain(struct audio_stream * s)
+{
+ int channel = s->lch[s->dma_q_head];
+ FN_IN;
+ if (!s->started) {
+ s->hw_stop(); /* stops McBSP Interface */
+ omap_start_dma(channel);
+ s->started = 1;
+ s->hw_start(); /* start McBSP interface */
+ }
+ /* else the dma itself will progress forward with out our help */
+ FN_OUT(0);
+ return 0;
+}
+
+/* Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+int omap_start_alsa_sound_dma(struct audio_stream *s,
+ dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int ret = -EPERM;
+
+ FN_IN;
+ if (unlikely(dma_size > MAX_DMA_SIZE)) {
+ ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+ MAX_DMA_SIZE);
+ return -EOVERFLOW;
+ }
+/*
+ if (AUDIO_QUEUE_FULL(s)) { // lamikr:should this be removed from comment?
+ printk("KERN_ERR Warning, audio_queue is full!\n");
+ ret = -2;
+ goto sound_out;
+ }
+*/
+
+ if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*playback */
+ DPRINTK("stream_id = playback, dma_ptr = %d, dma_size = %d\n", dma_ptr, dma_size);
+ ret = audio_set_dma_params_play(s->lch[s->dma_q_tail],
+ dma_ptr,
+ dma_size);
+ } else {
+ ret = audio_set_dma_params_capture(s->lch[s->dma_q_tail],
+ dma_ptr,
+ dma_size);
+ }
+ if (ret != 0) {
+ printk(KERN_ERR "Error, audio_queue is full!\n");
+ ret = -3; /* indicate queue full */
+ goto sound_out;
+ }
+ AUDIO_INCREMENT_TAIL(s);
+ ret = audio_start_dma_chain(s);
+ if (ret) {
+ ERR("dma start failed");
+ }
+ sound_out:
+ FN_OUT(ret);
+ return ret;
+}
+
+/*
+ * ISRs have to be short and smart..
+ * Here we call alsa handling, after some error checking
+ */
+ //lamikr: this function is very different in the OSS version
+static void sound_dma_irq_handler(int sound_curr_lch,
+ u16 ch_status,
+ void *data)
+{
+ int dma_status = ch_status;
+ struct audio_stream *s = (struct audio_stream *)data;
+
+ /*
+ * some register checkings
+ */
+ DPRINTK("started, lch = %d, status = 0x%x, dma_status = %d, data = %p\n",
+ sound_curr_lch,
+ ch_status,
+ dma_status,
+ data);
+ if (dma_status & (DCSR_ERROR)) {
+ OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
+ ERR("DCSR_ERROR!\n");
+ FN_OUT(-1);
+ return;
+ }
+ if (ch_status & DCSR_END_BLOCK) {
+ DPRINTK("status = DCSR_END_BLOCK, calling audio_dma_callback()\n");
+ audio_dma_callback(s);
+ }
+ else
+ {
+ DPRINTK("ch_status != DCSR_END_BLOCK\n");
+ }
+ DPRINTK("done\n");
+ return;
+}
+
+MODULE_AUTHOR("Mika Laitio");
+MODULE_DESCRIPTION("DMA handling for TSC2101 sound driver on OMAP processors.");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(omap_start_alsa_sound_dma);
+EXPORT_SYMBOL(omap_clear_alsa_sound_dma);
+EXPORT_SYMBOL(omap_request_alsa_sound_dma);
+EXPORT_SYMBOL(omap_free_alsa_sound_dma);
+EXPORT_SYMBOL(omap_alsa_audio_stop_dma);
diff -Naur linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101-dma.h linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101-dma.h
--- linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101-dma.h 1970-01-01 02:00:00.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101-dma.h 2006-02-05 11:36:45.000000000 +0200
@@ -0,0 +1,61 @@
+/*
+ * sound/arm/oma/omap-alsa-tsc2101-dma.h
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ *
+ * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2005/07/25 INdT Kernel Team - Renamed to omap-alsa-dma.h. Ported to Alsa.
+ * 2006-02-04 Mika Laitio - Tryed to make work with the OMAP 1510 based iPAQ h6300 that has tsc2101 chipset.
+ * This work is still in progress.
+ */
+
+#ifndef OMAPALSATSC2101DMA_H_
+#define OMAPALSATSC2101DMA_H_
+
+/************************** INCLUDES *************************************/
+
+#include "omap-alsa.h"
+
+/************************** GLOBAL MACROS *************************************/
+
+/* Provide the Macro interfaces common across platforms */
+#define DMA_REQUEST(e,s, cb) {e=omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);}
+#define DMA_FREE(s) omap_free_sound_dma(s, &s->lch)
+#define DMA_CLEAR(s) omap_clear_sound_dma(s)
+
+/************************** GLOBAL DATA STRUCTURES *********************************/
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/**************** ARCH SPECIFIC FUNCIONS *******************************************/
+
+void omap_clear_alsa_sound_dma(struct audio_stream * s);
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+ void *data, int **channels);
+int omap_free_alsa_sound_dma(void *data, int **channels);
+
+int omap_start_alsa_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
+ u_int dma_size);
+
+void omap_alsa_audio_stop_dma(struct audio_stream *s);
+
+#endif /*OMAPALSATSC2101DMA_H_*/
diff -Naur linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101.h linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101.h
--- linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101.h 1970-01-01 02:00:00.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101.h 2006-02-05 21:00:19.000000000 +0200
@@ -0,0 +1,75 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101.h
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ * Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Based on omap-aic23.h and tsc2101 OSS drivers.
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Written by Nishanth Menon and Sriram Kannan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-02-04 Mika Laitio - Alsa driver startup for omap boards.
+ * Still a work in progress as at least with h6300 the DMA is somehow
+ * not working. (Producess only a start of the sound)
+ */
+
+#ifndef OMAPALSATSC2101_H_
+#define OMAPALSATSC2101_H_
+
+#include <sound/driver.h>
+#include <asm/arch/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "omap-alsa.h"
+
+#define DEFAULT_BITPERSAMPLE 16
+#define AUDIO_RATE_DEFAULT 44100
+#define AUDIO_MCBSP OMAP_MCBSP1
+#define NUMBER_SAMPLE_RATES_SUPPORTED 16
+#define TSC2101_AUDIO_CODEC_REGISTERS_PAGE2 (2)
+
+#define DMA_BUF_SIZE 8 * 1024
+
+/*
+ * Alsa card structure for aic23
+ */
+struct snd_card_omap_alsa_tsc2101 {
+ snd_card_t *card;
+ snd_pcm_t *pcm;
+ long samplerate;
+ struct audio_stream s[2]; /* playback & capture */
+};
+
+void audio_dma_callback(void *);
+
+/* Clock functions */
+int omap_alsa_tsc2101_clock_on(void);
+int omap_alsa_tsc2101_clock_off(void);
+
+#endif /*OMAPALSATSC2101_H_*/
diff -Naur linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101-mixer.c linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101-mixer.c
--- linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101-mixer.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101-mixer.c 2006-02-05 00:40:00.000000000 +0200
@@ -0,0 +1,645 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.c
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ * Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Board initialization code is based on to TSC2101 OSS driver.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Written by Nishanth Menon and Sriram Kannan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-02-04 Mika Laitio - Alsa driver startup for omap boards.
+ * Still a work in progress as at least with h6300 the DMA is somehow
+ * not working. (Producess only a start of the sound)
+ */
+#include "omap-alsa-tsc2101.h"
+#include "omap-alsa-tsc2101-mixer.h"
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f))
+#define GET_DGC_DALMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15)
+#define GET_DGC_DARMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(7)) >> 7)
+#define IS_DGC_DALMU_UNMUTED(ARG) (((GET_DGC_DALMU_BIT_VALUE(ARG)) == 0))
+#define IS_DGC_DARMU_UNMUTED(ARG) (((GET_DGC_DARMU_BIT_VALUE(ARG)) == 0))
+
+#define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define GET_DGC_HGCMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15)
+#define IS_DGC_HGCMU_UNMUTED(ARG) (((GET_DGC_HGCMU_BIT_VALUE(ARG)) == 0))
+
+#define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define GET_DGC_HNGCMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15)
+#define IS_DGC_HNGCMU_UNMUTED(ARG) (((GET_DGC_HNGCMU_BIT_VALUE(ARG)) == 0))
+
+static int recsrc = SOUND_MASK_LINE;
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to real
+ * Digital Gain Control (DGC) value that can be written
+ * or read from the TSC2101 registry.
+ *
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than OUTPUT_VOLUME_MIN
+ * because DGC works as a volume decreaser. (The more bigger value is put
+ * to DGC, the more the volume of controlled channel is decreased)
+ *
+ * In addition the TCS2101 chip would allow the maximum volume reduction be 63.5 DB
+ * but according to some tests user can not hear anything with this chip
+ * when the volume is set to be less than 25 db.
+ * Therefore this function will return a value that means 38.5 db (63.5 db - 25 db)
+ * reduction in the channel volume, when mixer is set to 0.
+ * For mixer value 100, this will return a value that means 0 db volume reduction.
+ * ([mute_left_bit]0000000[mute_right_bit]0000000)
+*/
+int getMixerVolumeAsDacGainControlVolume(int vol)
+{
+ u16 retVal;
+
+ /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+ retVal = ((vol * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+ /* invert the value for getting the proper range 0 min and 100 max */
+ retVal = OUTPUT_VOLUME_MIN - retVal;
+
+ return retVal;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to TSC2101
+ * Digital Gain Control (DGC) volume. Alsa mixer volume 0
+ * is converted to value meaning the volume reduction of -38.5 db
+ * and Alsa mixer volume 100 is converted to value meaning the
+ * reduction of 0 db.
+ */
+int setMixerVolumeAsDacGainControlVolume(int mixerVolL, int mixerVolR) {
+ u16 val;
+ int retVal;
+ int volL;
+ int volR;
+
+ if ((mixerVolL < 0) ||
+ (mixerVolL > 100) ||
+ (mixerVolR < 0) ||
+ (mixerVolR > 100)) {
+ printk(KERN_ERR "Trying a bad mixer volume as dac gain control volume value, left (%d), right (%d)!\n", mixerVolL, mixerVolR);
+ return -EPERM;
+ }
+ DPRINTK("mixer volume left = %d, right = %d\n", mixerVolL, mixerVolR);
+ volL = getMixerVolumeAsDacGainControlVolume(mixerVolL);
+ volR = getMixerVolumeAsDacGainControlVolume(mixerVolR);
+
+ val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL);
+ // keep the old mute bit settings
+ val &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) | DGC_DARVL(OUTPUT_VOLUME_MIN));
+ val |= DGC_DALVL(volL) | DGC_DARVL(volR);
+ retVal = 2;
+ if (retVal) {
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_DAC_GAIN_CTRL,
+ val);
+ }
+ DPRINTK("to registry: left = %d, right = %d, total = %d\n", DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val);
+ return retVal;
+}
+
+/*
+ * Converts the DGC registry value read from the TSC2101 registry to
+ * Alsa mixer volume format (0 - 100).
+ */
+int getDacGainControlVolumeAsMixerVolume(u16 vol) {
+ u16 retVal;
+
+ retVal = OUTPUT_VOLUME_MIN - vol;
+ retVal = ((retVal - OUTPUT_VOLUME_MAX) * 100) / OUTPUT_VOLUME_RANGE;
+ /* fix scaling error */
+ if ((retVal > 0) && (retVal < 100)) {
+ retVal++;
+ }
+ return retVal;
+}
+
+/*
+ * Converts the headset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int getHeadsetGainControlVolumeAsMixerVolume(u16 registerVal) {
+ u16 retVal;
+
+ retVal = ((registerVal * 100) / INPUT_VOLUME_RANGE);
+ return retVal;
+}
+
+/*
+ * Converts the handset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int getHandsetGainControlVolumeAsMixerVolume(u16 registerVal) {
+ return getHeadsetGainControlVolumeAsMixerVolume(registerVal);
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to
+ * headset gain control volume (0 - 63.5 db)
+ */
+int getMixerVolumeAsHeadsetGainControlVolume(u16 mixerVal) {
+ u16 retVal;
+
+ retVal = ((mixerVal * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+ return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 headset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with "SET_LINE" parameter.
+ */
+int setMixerVolumeAsHeadsetGainControlVolume(int mixerVol) {
+ int volume;
+ int retVal;
+ u16 val;
+
+ if (mixerVol < 0 || mixerVol > 100) {
+ DPRINTK("Trying a bad headset mixer volume value(%d)!\n", mixerVol);
+ return -EPERM;
+ }
+ DPRINTK("mixer volume = %d\n", mixerVol);
+ /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+ /* NOTE: 0 is minimum volume and not mute */
+ volume = getMixerVolumeAsHeadsetGainControlVolume(mixerVol);
+
+ val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HEADSET_GAIN_CTRL);
+ // preserve the old mute settings
+ val &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX));
+ val |= HGC_ADPGA_HED(volume);
+
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_HEADSET_GAIN_CTRL,
+ val);
+ retVal = 1;
+
+ DPRINTK("to registry = %d\n", val);
+ return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 handset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with "SET_MIC" parameter.
+ */
+int setMixerVolumeAsHandsetGainControlVolume(int mixerVol) {
+ int volume;
+ int retVal;
+ u16 val;
+
+ if (mixerVol < 0 || mixerVol > 100) {
+ DPRINTK("Trying a bad mic mixer volume value(%d)!\n", mixerVol);
+ return -EPERM;
+ }
+ DPRINTK("mixer volume = %d\n", mixerVol);
+ /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+ /* NOTE: 0 is minimum volume and not mute */
+ volume = getMixerVolumeAsHeadsetGainControlVolume(mixerVol);
+
+ val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HEADSET_GAIN_CTRL);
+ // preserve the old mute settigns
+ val &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX));
+ val |= HNGC_ADPGA_HND(volume);
+
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_HANDSET_GAIN_CTRL,
+ val);
+ DPRINTK("to registry = %d\n", val);
+ retVal = 1;
+ return retVal;
+}
+
+static int __pcm_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ return 0;
+}
+
+/*
+ * Alsa mixer interface function for getting the volume read from the DGC in a
+ * 0 -100 alsa mixer format.
+ */
+static int __pcm_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ u16 volL;
+ u16 volR;
+ u16 val;
+
+ val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL);
+ DPRINTK("registry value = %d!\n", val);
+ volL = DGC_DALVL_EXTRACT(val);
+ volR = DGC_DARVL_EXTRACT(val);
+ volL = volL & ~DGC_DALMU; // make sure that other bits are not on
+ volR = volR & ~DGC_DARMU;
+
+ volL = getDacGainControlVolumeAsMixerVolume(volL);
+ volR = getDacGainControlVolumeAsMixerVolume(volR);
+
+ ucontrol->value.integer.value[0] = volL; // L
+ ucontrol->value.integer.value[1] = volR; // R
+
+ DPRINTK("mixer volume left = %ld, right = %ld\n", ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]);
+ return 0;
+}
+
+static int __pcm_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ return setMixerVolumeAsDacGainControlVolume(ucontrol->value.integer.value[0],
+ ucontrol->value.integer.value[1]);
+}
+
+static int __pcm_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/*
+ * When DGC_DALMU (bit 15) is 1, the left channel is muted.
+ * When DGC_DALMU is 0, left channel is not muted.
+ * Same logic apply also for the right channel.
+ */
+static int __pcm_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL);
+
+ ucontrol->value.integer.value[0] = IS_DGC_DALMU_UNMUTED(val);
+ ucontrol->value.integer.value[1] = IS_DGC_DARMU_UNMUTED(val);
+ return 0;
+}
+
+static int __pcm_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ u16 val=omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL);
+ int count=0;
+
+ // in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
+ // so if values are same, it's time to change the registry value.
+ if (ucontrol->value.integer.value[0] == GET_DGC_DALMU_BIT_VALUE(val)) {
+ if (ucontrol->value.integer.value[0] == 0)
+ {
+ val = val | DGC_DALMU; // mute --> turn bit on
+ }
+ else
+ {
+ val = val & ~DGC_DALMU; // unmute --> turn bit off
+ }
+ count++;
+ } /* L */
+ if (ucontrol->value.integer.value[1] == GET_DGC_DARMU_BIT_VALUE(val)) {
+ if (ucontrol->value.integer.value[1] == 0)
+ {
+ val = val | DGC_DARMU; // mute --> turn bit on
+ }
+ else
+ {
+ val = val & ~DGC_DARMU; // unmute --> turn bit off
+ }
+ count++;
+ } /* R */
+ if (count) {
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL, val);
+ DPRINTK("changed value, is_unmuted left = %d, right = %d\n",
+ IS_DGC_DALMU_UNMUTED(val),
+ IS_DGC_DARMU_UNMUTED(val));
+ }
+ return count;
+}
+
+static int __headset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ return 0;
+}
+
+static int __headset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ u16 val;
+ u16 vol;
+
+ val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HEADSET_GAIN_CTRL);
+ DPRINTK("registry value = %d\n", val);
+ vol = HGC_ADPGA_HED_EXTRACT(val);
+ vol = vol & ~HGC_ADMUT_HED;
+
+ vol = getHeadsetGainControlVolumeAsMixerVolume(vol);
+ ucontrol->value.integer.value[0] = vol;
+
+ DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int __headset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ return setMixerVolumeAsHeadsetGainControlVolume(ucontrol->value.integer.value[0]);
+}
+
+static int __headset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/* When HGC_ADMUT_HED (bit 15) is 1, the headset is muted.
+ * When HGC_ADMUT_HED is 0, headset is not muted.
+ */
+static int __headset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HEADSET_GAIN_CTRL);
+ ucontrol->value.integer.value[0] = IS_DGC_HGCMU_UNMUTED(val);
+ return 0;
+}
+
+static int __headset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ int count = 0;
+ u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HEADSET_GAIN_CTRL);
+
+ // in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
+ // so if values are same, it's time to change the registry value...
+ if (ucontrol->value.integer.value[0] == GET_DGC_HGCMU_BIT_VALUE(val)) {
+ if (ucontrol->value.integer.value[0] == 0) {
+ val = val | HGC_ADMUT_HED; // mute --> turn bit on
+ }
+ else {
+ val = val & ~HGC_ADMUT_HED; // unmute --> turn bit off
+ }
+ count++;
+ DPRINTK("changed value, is_unmuted = %d\n", IS_DGC_HGCMU_UNMUTED(val));
+ }
+ if (count) {
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_HEADSET_GAIN_CTRL,
+ val);
+ }
+ return count;
+}
+
+static int __handset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ return 0;
+}
+
+static int __handset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ u16 val;
+ u16 vol;
+
+ val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL);
+ DPRINTK("registry value = %d\n", val);
+ vol = HNGC_ADPGA_HND_EXTRACT(val);
+ vol = vol & ~HNGC_ADMUT_HND;
+ vol = getHandsetGainControlVolumeAsMixerVolume(vol);
+ ucontrol->value.integer.value[0] = vol;
+
+ DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int __handset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ return setMixerVolumeAsHandsetGainControlVolume(ucontrol->value.integer.value[0]);
+}
+
+static int __handset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/* When HNGC_ADMUT_HND (bit 15) is 1, the handset is muted.
+ * When HNGC_ADMUT_HND is 0, handset is not muted.
+ */
+static int __handset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL);
+ ucontrol->value.integer.value[0] = IS_DGC_HNGCMU_UNMUTED(val);
+ return 0;
+}
+
+static int __handset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ int count = 0;
+ u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL);
+
+ // in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
+ // so if values are same, it's time to change the registry value...
+ if (ucontrol->value.integer.value[0] == GET_DGC_HNGCMU_BIT_VALUE(val)) {
+ if (ucontrol->value.integer.value[0] == 0) {
+ val = val | HNGC_ADMUT_HND; // mute --> turn bit on
+ }
+ else {
+ val = val & ~HNGC_ADMUT_HND; // unmute --> turn bit off
+ }
+ DPRINTK("changed value, is_unmuted = %d\n", IS_DGC_HNGCMU_UNMUTED(val));
+ count++;
+ }
+ if (count) {
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_HANDSET_GAIN_CTRL,
+ val);
+ }
+ return count;
+}
+
+static snd_kcontrol_new_t tsc2101_control[] __devinitdata={
+ {
+ .name = "PCM Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_volume_info,
+ .get = __pcm_playback_volume_get,
+ .put = __pcm_playback_volume_put,
+ }, {
+ .name = "PCM Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __pcm_playback_switch_info,
+ .get = __pcm_playback_switch_get,
+ .put = __pcm_playback_switch_put,
+ }, {
+ .name = "Headset Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 1,
+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __headset_playback_volume_info,
+ .get = __headset_playback_volume_get,
+ .put = __headset_playback_volume_put,
+ }, {
+ .name = "Headset Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 1,
+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __headset_playback_switch_info,
+ .get = __headset_playback_switch_get,
+ .put = __headset_playback_switch_put,
+ }, {
+ .name = "Handset Playback Volume",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 2,
+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __handset_playback_volume_info,
+ .get = __handset_playback_volume_get,
+ .put = __handset_playback_volume_put,
+ }, {
+ .name = "Handset Playback Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 2,
+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = __handset_playback_switch_info,
+ .get = __handset_playback_switch_get,
+ .put = __handset_playback_switch_put,
+ }
+};
+
+int snd_omap_mixer(struct snd_card_omap_alsa_tsc2101 *tsc2101) {
+ int i=0;
+ int err=0;
+
+ if (!tsc2101) {
+ return -EINVAL;
+ }
+ for (i=0; i < ARRAY_SIZE(tsc2101_control); i++) {
+ if ((err = snd_ctl_add(tsc2101->card,
+ snd_ctl_new1(&tsc2101_control[i],
+ tsc2101->card))) < 0) {
+ return err;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Used for switching between TSC2101 recourd sources.
+ * Logic is adjusted from the TSC2101 OSS code.
+ */
+static int setRecordSource(int val)
+{
+ u16 data;
+
+ FN_IN;
+ /*
+ * If more than one recording device selected,
+ * disable the device that is currently in use.
+ */
+ if (hweight32(val) > 1)
+ val &= ~recsrc;
+ data = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_MIXER_PGA_CTRL);
+ data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+ if (val == SOUND_MASK_MIC) {
+ data |= MPC_MICSEL(1);
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_MIXER_PGA_CTRL,
+ data);
+ }
+ else if (val == SOUND_MASK_LINE) {
+ data |= MPC_MICSEL(0);
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_MIXER_PGA_CTRL,
+ data);
+ }
+ else {
+ printk(KERN_WARNING "omap-alsa-tsc2101-mixer setRecordSource(), Wrong RECSRC (%d) specified,\n", val);
+ return -EINVAL;
+ }
+ recsrc = val;
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*
+ * Used for switching between TSC2101 recourd sources.
+ * Logic is adjusted from the TSC2101 OSS code.
+ */
+void snd_omap_init_mixer(void)
+{
+ FN_IN;
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_CODEC_POWER_CTRL,
+ 0x0000);
+
+ /*Mute Analog Sidetone */
+ /*Select MIC_INHED input for headset */
+ /*Cell Phone In not connected */
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_MIXER_PGA_CTRL,
+ MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
+
+ /* Set record source */
+ setRecordSource(recsrc);
+
+ /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+ /* 1dB AGC hysteresis */
+ /* MICes bias 2V */
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_AUDIO_CTRL_4,
+ AC4_MB_HED(0));
+
+ /* Set codec output volume */
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_DAC_GAIN_CTRL,
+ 0x0000);
+
+ /* DAC left and right routed to SPK2 */
+ /* SPK1/2 unmuted */
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_AUDIO_CTRL_5,
+ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+ AC5_HDSCPTC);
+
+ /* OUT8P/N muted, CPOUT muted */
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_AUDIO_CTRL_6,
+ AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC | AC6_VGNDSCPTC);
+
+ /* Headset/Hook switch detect disabled */
+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
+ TSC2101_AUDIO_CTRL_7,
+ 0x0000);
+
+ /* Left line input volume control */
+ // SET_LINE in the OSS driver
+ setMixerVolumeAsHeadsetGainControlVolume(DEFAULT_INPUT_VOLUME);
+
+ /* mic input volume control */
+ // SET_MIX in the OSS driver
+ setMixerVolumeAsHandsetGainControlVolume(DEFAULT_INPUT_VOLUME);
+
+ /* Left/Right headphone channel volume control */
+ /* Zero-cross detect on */
+ // SET_VOLUME on OSS driver
+ setMixerVolumeAsDacGainControlVolume(DEFAULT_VOLUME, DEFAULT_VOLUME);
+ FN_OUT(0);
+}
diff -Naur linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101-mixer.h linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101-mixer.h
--- linux-omap-2.6/sound/arm/omap/omap-alsa-tsc2101-mixer.h 1970-01-01 02:00:00.000000000 +0200
+++ linux-omap-h6300-2.6/sound/arm/omap/omap-alsa-tsc2101-mixer.h 2006-02-05 00:38:59.000000000 +0200
@@ -0,0 +1,67 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.c
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ * Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Based on omap-aic23.c and sa11xx-uda1341.c
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-02-04 Mika Laitio - Alsa driver startup for omap boards.
+ * Still a work in progress as at least with h6300 the DMA is somehow
+ * not working. (Producess only a start of the sound)
+ */
+
+#ifndef OMAPALSATSC2101MIXER_H_
+#define OMAPALSATSC2101MIXER_H_
+
+#include "omap-alsa-tsc2101-dma.h"
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+
+int snd_omap_mixer(struct snd_card_omap_alsa_tsc2101 *);
+void snd_omap_init_mixer(void);
+
+// following definitions are from the TSC2101 OSS driver
+#define OUTPUT_VOLUME_MIN 0x7F // 1111111 = -63.5 DB
+#define OUTPUT_VOLUME_MAX 0x32 // 110010
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+#define INPUT_VOLUME_MIN 0x0
+#define INPUT_VOLUME_MAX 0x7D
+#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+#define SOUND_MIXER_LINE 6
+#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE)
+#define SOUND_MIXER_MIC 7
+#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC)
+
+#define DEFAULT_VOLUME 93
+#define DEFAULT_INPUT_VOLUME 20 /* An minimal volume */
+
+#endif /*OMAPALSATSC2101MIXER_H_*/
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: omap alsa tsc2101 driver
2006-02-05 21:24 omap alsa tsc2101 driver lamikr
@ 2006-02-06 19:13 ` Daniel Petrini
2006-02-06 20:17 ` lamikr
0 siblings, 1 reply; 13+ messages in thread
From: Daniel Petrini @ 2006-02-06 19:13 UTC (permalink / raw)
To: lamikr; +Cc: OMAP-Linux
Hi Mika,
I have been working in this ALSA driver as well, and I have a
functional patch that plays songs but lacks the mixer support yet.
What do you think of join the drivers to make it work faster?
I am developing it generically in order to take advantage of existing
common code as dma and alsa generic.
Daniel
On 2/5/06, lamikr <lamikr@cc.jyu.fi> wrote:
> Hi
>
> I have not seen anyone working with the tsc2101 Alsa driver, so attached
> are the tsc2101 alsa driver sources I have been working for a while. The
> patch should apply to the omap-driver head. Unfortunately it is still
> non-functional at least with my omap 1510 based iPAQ h6340.
>
> I can hear small start of the song but then nothing happens. I have
> tried to debug the code and I can see that the the driver is able to get
> one callback to sound_dma_irq_handler with DSCR_END_BLOCK set, but after
> it does not continue with a next period of code.
>
> Here is some info from the driver
> - all code is located in /sound/arm/omap as I have wanted to mix it to
> existing aic23 code until this one works
> - based on to aic23 Alsa and tsc2101 OSS drivers. DMA code and driver
> base taken from the aic, but hardware initialization taken from the
> tsc2101 oss driver. (dma has only small changes like 16 bit mono to
> capture params instead of 32 bit ones supported in the aic23)
> - mixer code for DGC, headset and handset
> - debug is mostly printed by using DPRINTK() function and can be enabled
> by uncommenting "#define DEBUG 1" from the omap-alsa.h
> - This is platform driver, so you need to register it to your board-code
> in arch/arm/mach-omap1/board-* in a following way:
> static struct platform_device h6300_mcbsp1_device = {
> .name = "omap_tsc2101_mcbsp",
> .id = 1,
> };
>
> static struct platform_device *h6300_devices[] __initdata = {
> ...
> &h6300_mcbsp1_device,
> };
>
> I have only tested this with omap1510 based iPAQ h6300, so I would
> appreciate if somebody else could test this with other
> devices having tsc2101 chipset to find out whether this is just my hw
> specific problem. (Fixes would ofcource also be nice :-)
>
> For testing the driver I have plugged headset and listened the result of
> following commands
> - aplay song.wav (44100 hz 16 bit little endion format)
> - "speaker-test -r 8000", "-r 44100", etc...
>
> I have also tryed to change the audio_get_dma_pos() method to be like in
> the sa11xx-uda1341.c driver. With implementation
> based on to that, the speaker-test is able to produce somekind of
> periodic "wuff <silence> wuff <silence> wuff..." sound.
> (that method version is commented out in the omap-alsa-tsc2101.c)
>
> In addition to sources, attached is the log from one play attempt.
>
> Mika
>
> root@h6300:~# aplay free_breakbeat.wav
> Playing WAVE 'free_breakbeat.wav' : Signed 16 bit Little Endian, Rate
> 44100 Hz, Stereo
> aplay: pcm_write:1146: write error: Input/output error
> root@h6300:~# dmesg
> XXX Alsa debug f:omap_alsa_tsc2101_init, l:1157
> XXX Alsa debug f:snd_omap_alsa_tsc2101_probe, l:1077
> XXX Alsa debug f:snd_card_omap_alsa_tsc2101_pcm, l:845
> XXX Alsa debug f:omap_alsa_tsc2101_audio_init, l:350
> XXX Alsa debug f:audio_dma_request, l:385
> [omap_request_alsa_sound_dma]: start
> [omap_request_alsa_sound_dma]: end(0)
> XXX Alsa debug f:audio_dma_request, l:385
> [omap_request_alsa_sound_dma]: start
> [omap_request_alsa_sound_dma]: end(0)
> [snd_omap_init_mixer]: start
> [setRecordSource]: start
> [setRecordSource]: end(0)
> [snd_omap_init_mixer]: end(0)
> OMAP_ALSA_TSC2101 audio support initialized
> <omap_alsa_tsc2101_clock_on>: clock use count = 0
> <omap_alsa_tsc2101_clock_on>: old clock rate = 12000000
> omap_alsa_tsc2101_clock_on(), no need to change clock rate, rate already
> 12000000 Hz.
> <omap_alsa_tsc2101_clock_on>: MCLK = 12000000 [12000000], usecount = 1,
> clk_enable retval = 0
> <snd_card_omap_alsa_tsc2101_open>: runtime->hw =
> snd_omap_alsa_tsc2101_playback
> <snd_omap_alsa_tsc2101_hw_params>: snd_omap_alsa_tsc2101_hw_params(),
> size = 131072
> XXX Alsa debug f:snd_omap_alsa_tsc2101_prepare, l:686
> XXX Alsa debug f:omap_alsa_tsc2101_set_samplerate, l:248
> <omap_alsa_tsc2101_set_samplerate>: selected 44.1khz PLL
> <snd_omap_alsa_tsc2101_trigger>: cmd = 1
> <audio_process_dma>: started, offset = 0, dma_size = 8192, s->period =
> 0, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
> 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
> 0, dma_ptr = -1042022400
> [omap_start_alsa_sound_dma]: start
> <omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
> -1042022400, dma_size = 8192
> [audio_set_dma_params_play]: start
> [audio_set_dma_params_play]: end(0)
> [audio_start_dma_chain]: start
> XXX Alsa debug f:audio_ifc_stop, l:229
> XXX Alsa debug f:audio_ifc_start, l:222
> [audio_start_dma_chain]: end(0)
> [omap_start_alsa_sound_dma]: end(0)
> <audio_process_dma>: done, offset = 0, dma_size = 8192, s->period = 0,
> s->periods = 1, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
> 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
> 0, dma_ptr = -1042022400
> <audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
> s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
> = 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
> dma_ptr = -1042023937
> <audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
> <audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
> <sound_dma_irq_handler>: started, lch = 0, status = 0x20, dma_status =
> 32, data = c0b0608c
> <sound_dma_irq_handler>: status = DCSR_END_BLOCK, calling
> audio_dma_callback()
> <audio_dma_callback>: s->active, calling snd_pcm_period_elapsed
> <audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
> s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
> = 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
> dma_ptr = -1042023937
> <audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
> <audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
> <audio_process_dma>: started, offset = 8192, dma_size = 8192, s->period
> = 1, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
> 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
> 0, dma_ptr = -1042014208
> [omap_start_alsa_sound_dma]: start
> <omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
> -1042014208, dma_size = 8192
> [audio_set_dma_params_play]: start
> [audio_set_dma_params_play]: end(0)
> [audio_start_dma_chain]: start
> [audio_start_dma_chain]: end(0)
> [omap_start_alsa_sound_dma]: end(0)
> <audio_process_dma>: done, offset = 8192, dma_size = 8192, s->period =
> 1, s->periods = 1, s->dma_q_head = 0, s->offset = 8192, rt->buffer_size
> = 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr
> = 0, dma_ptr = -1042014208
> <sound_dma_irq_handler>: done
> ALSA
> /home/lamikr/own/h6300/git/linux-omap-h6300-2.6/sound/core/pcm_lib.c:2231:
> playback write error (DMA or IRQ trouble?)
> <snd_omap_alsa_tsc2101_trigger>: cmd = 0
> XXX Alsa debug f:audio_stop_dma, l:488
> [omap_alsa_audio_stop_dma]: start
> [omap_alsa_audio_stop_dma]: end(0)
> [omap_clear_alsa_sound_dma]: start
> [omap_clear_alsa_sound_dma]: end(0)
> XXX Alsa debug f:snd_card_omap_alsa_tsc2101_close, l:785
> <omap_alsa_tsc2101_clock_off>: clock use count = 1
> <omap_alsa_tsc2101_clock_off>: clock rate = 12000000
> <omap_alsa_tsc2101_clock_off>: clock disabled
> <omap_alsa_tsc2101_clock_off>: audio codec off
>
>
>
> _______________________________________________
> Linux-omap-open-source mailing list
> Linux-omap-open-source@linux.omap.com
> http://linux.omap.com/mailman/listinfo/linux-omap-open-source
>
>
>
>
--
INdT - Manaus - Brazil
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: omap alsa tsc2101 driver
2006-02-06 19:13 ` Daniel Petrini
@ 2006-02-06 20:17 ` lamikr
2006-02-06 22:01 ` Daniel Petrini
0 siblings, 1 reply; 13+ messages in thread
From: lamikr @ 2006-02-06 20:17 UTC (permalink / raw)
To: Daniel Petrini; +Cc: OMAP-Linux
Hi Petrini
That sounds good for me, I am happy from anything that works and can try
to continue from that :-)
Can you give more info from your driver like is it already using DMA, is
it using headset or normal speakers for playing, etc?
In addition do you have sources available somewhere so I could check
whether your code works also with my device?
It should be possible to take the existing mixer part from my code to
your driver. As I have not yet been able to play songs properly, I have
sofar only been able to test the volume and mute/unmute settings from
the Mixers Digital Gain Control (DGC) properly.
Headset and handset parts seems to act ok, but only time will tell
whether they really work. But if I can get your driver to play with my
device, I could continue from that.
I think there will also be a need for a somekind of "temp/work"
repository for helping to synchronize the our (and possible others)
work, but I think we can resolve that later.
Mika
Daniel Petrini wrote:
>Hi Mika,
>
>I have been working in this ALSA driver as well, and I have a
>functional patch that plays songs but lacks the mixer support yet.
>What do you think of join the drivers to make it work faster?
>I am developing it generically in order to take advantage of existing
>common code as dma and alsa generic.
>
>Daniel
>
>On 2/5/06, lamikr <lamikr@cc.jyu.fi> wrote:
>
>
>>Hi
>>
>>I have not seen anyone working with the tsc2101 Alsa driver, so attached
>>are the tsc2101 alsa driver sources I have been working for a while. The
>>patch should apply to the omap-driver head. Unfortunately it is still
>>non-functional at least with my omap 1510 based iPAQ h6340.
>>
>>I can hear small start of the song but then nothing happens. I have
>>tried to debug the code and I can see that the the driver is able to get
>>one callback to sound_dma_irq_handler with DSCR_END_BLOCK set, but after
>>it does not continue with a next period of code.
>>
>>Here is some info from the driver
>>- all code is located in /sound/arm/omap as I have wanted to mix it to
>>existing aic23 code until this one works
>>- based on to aic23 Alsa and tsc2101 OSS drivers. DMA code and driver
>>base taken from the aic, but hardware initialization taken from the
>>tsc2101 oss driver. (dma has only small changes like 16 bit mono to
>>capture params instead of 32 bit ones supported in the aic23)
>>- mixer code for DGC, headset and handset
>>- debug is mostly printed by using DPRINTK() function and can be enabled
>>by uncommenting "#define DEBUG 1" from the omap-alsa.h
>>- This is platform driver, so you need to register it to your board-code
>>in arch/arm/mach-omap1/board-* in a following way:
>> static struct platform_device h6300_mcbsp1_device = {
>> .name = "omap_tsc2101_mcbsp",
>> .id = 1,
>> };
>>
>> static struct platform_device *h6300_devices[] __initdata = {
>> ...
>> &h6300_mcbsp1_device,
>> };
>>
>>I have only tested this with omap1510 based iPAQ h6300, so I would
>>appreciate if somebody else could test this with other
>>devices having tsc2101 chipset to find out whether this is just my hw
>>specific problem. (Fixes would ofcource also be nice :-)
>>
>>For testing the driver I have plugged headset and listened the result of
>>following commands
>>- aplay song.wav (44100 hz 16 bit little endion format)
>>- "speaker-test -r 8000", "-r 44100", etc...
>>
>>I have also tryed to change the audio_get_dma_pos() method to be like in
>>the sa11xx-uda1341.c driver. With implementation
>>based on to that, the speaker-test is able to produce somekind of
>>periodic "wuff <silence> wuff <silence> wuff..." sound.
>>(that method version is commented out in the omap-alsa-tsc2101.c)
>>
>>In addition to sources, attached is the log from one play attempt.
>>
>>Mika
>>
>>root@h6300:~# aplay free_breakbeat.wav
>>Playing WAVE 'free_breakbeat.wav' : Signed 16 bit Little Endian, Rate
>>44100 Hz, Stereo
>>aplay: pcm_write:1146: write error: Input/output error
>>root@h6300:~# dmesg
>>XXX Alsa debug f:omap_alsa_tsc2101_init, l:1157
>>XXX Alsa debug f:snd_omap_alsa_tsc2101_probe, l:1077
>>XXX Alsa debug f:snd_card_omap_alsa_tsc2101_pcm, l:845
>>XXX Alsa debug f:omap_alsa_tsc2101_audio_init, l:350
>>XXX Alsa debug f:audio_dma_request, l:385
>>[omap_request_alsa_sound_dma]: start
>>[omap_request_alsa_sound_dma]: end(0)
>>XXX Alsa debug f:audio_dma_request, l:385
>>[omap_request_alsa_sound_dma]: start
>>[omap_request_alsa_sound_dma]: end(0)
>>[snd_omap_init_mixer]: start
>>[setRecordSource]: start
>>[setRecordSource]: end(0)
>>[snd_omap_init_mixer]: end(0)
>>OMAP_ALSA_TSC2101 audio support initialized
>><omap_alsa_tsc2101_clock_on>: clock use count = 0
>><omap_alsa_tsc2101_clock_on>: old clock rate = 12000000
>>omap_alsa_tsc2101_clock_on(), no need to change clock rate, rate already
>>12000000 Hz.
>><omap_alsa_tsc2101_clock_on>: MCLK = 12000000 [12000000], usecount = 1,
>>clk_enable retval = 0
>><snd_card_omap_alsa_tsc2101_open>: runtime->hw =
>>snd_omap_alsa_tsc2101_playback
>><snd_omap_alsa_tsc2101_hw_params>: snd_omap_alsa_tsc2101_hw_params(),
>>size = 131072
>>XXX Alsa debug f:snd_omap_alsa_tsc2101_prepare, l:686
>>XXX Alsa debug f:omap_alsa_tsc2101_set_samplerate, l:248
>><omap_alsa_tsc2101_set_samplerate>: selected 44.1khz PLL
>><snd_omap_alsa_tsc2101_trigger>: cmd = 1
>><audio_process_dma>: started, offset = 0, dma_size = 8192, s->period =
>>0, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
>>32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
>>0, dma_ptr = -1042022400
>>[omap_start_alsa_sound_dma]: start
>><omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
>>-1042022400, dma_size = 8192
>>[audio_set_dma_params_play]: start
>>[audio_set_dma_params_play]: end(0)
>>[audio_start_dma_chain]: start
>>XXX Alsa debug f:audio_ifc_stop, l:229
>>XXX Alsa debug f:audio_ifc_start, l:222
>>[audio_start_dma_chain]: end(0)
>>[omap_start_alsa_sound_dma]: end(0)
>><audio_process_dma>: done, offset = 0, dma_size = 8192, s->period = 0,
>>s->periods = 1, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
>>32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
>>0, dma_ptr = -1042022400
>><audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
>>s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
>>= 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
>>dma_ptr = -1042023937
>><audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
>><audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
>><sound_dma_irq_handler>: started, lch = 0, status = 0x20, dma_status =
>>32, data = c0b0608c
>><sound_dma_irq_handler>: status = DCSR_END_BLOCK, calling
>>audio_dma_callback()
>><audio_dma_callback>: s->active, calling snd_pcm_period_elapsed
>><audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
>>s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
>>= 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
>>dma_ptr = -1042023937
>><audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
>><audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
>><audio_process_dma>: started, offset = 8192, dma_size = 8192, s->period
>>= 1, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
>>32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
>>0, dma_ptr = -1042014208
>>[omap_start_alsa_sound_dma]: start
>><omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
>>-1042014208, dma_size = 8192
>>[audio_set_dma_params_play]: start
>>[audio_set_dma_params_play]: end(0)
>>[audio_start_dma_chain]: start
>>[audio_start_dma_chain]: end(0)
>>[omap_start_alsa_sound_dma]: end(0)
>><audio_process_dma>: done, offset = 8192, dma_size = 8192, s->period =
>>1, s->periods = 1, s->dma_q_head = 0, s->offset = 8192, rt->buffer_size
>>= 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr
>>= 0, dma_ptr = -1042014208
>><sound_dma_irq_handler>: done
>>ALSA
>>/home/lamikr/own/h6300/git/linux-omap-h6300-2.6/sound/core/pcm_lib.c:2231:
>>playback write error (DMA or IRQ trouble?)
>><snd_omap_alsa_tsc2101_trigger>: cmd = 0
>>XXX Alsa debug f:audio_stop_dma, l:488
>>[omap_alsa_audio_stop_dma]: start
>>[omap_alsa_audio_stop_dma]: end(0)
>>[omap_clear_alsa_sound_dma]: start
>>[omap_clear_alsa_sound_dma]: end(0)
>>XXX Alsa debug f:snd_card_omap_alsa_tsc2101_close, l:785
>><omap_alsa_tsc2101_clock_off>: clock use count = 1
>><omap_alsa_tsc2101_clock_off>: clock rate = 12000000
>><omap_alsa_tsc2101_clock_off>: clock disabled
>><omap_alsa_tsc2101_clock_off>: audio codec off
>>
>>
>>
>>_______________________________________________
>>Linux-omap-open-source mailing list
>>Linux-omap-open-source@linux.omap.com
>>http://linux.omap.com/mailman/listinfo/linux-omap-open-source
>>
>>
>>
>>
>>
>>
>
>
>--
>INdT - Manaus - Brazil
>
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: omap alsa tsc2101 driver
2006-02-06 20:17 ` lamikr
@ 2006-02-06 22:01 ` Daniel Petrini
2006-02-07 12:43 ` lamikr
0 siblings, 1 reply; 13+ messages in thread
From: Daniel Petrini @ 2006-02-06 22:01 UTC (permalink / raw)
To: lamikr; +Cc: OMAP-Linux
[-- Attachment #1: Type: text/plain, Size: 10525 bytes --]
Hi Mika,
On 2/6/06, lamikr <lamikr@cc.jyu.fi> wrote:
> Hi Petrini
>
> That sounds good for me, I am happy from anything that works and can try
> to continue from that :-)
Great!
> Can you give more info from your driver like is it already using DMA, is
> it using headset or normal speakers for playing, etc?
> In addition do you have sources available somewhere so I could check
> whether your code works also with my device?
Yes, I am sending it right now (I have just updated my tree). Please
note that it is really work in progress code, with remaining debug
printks and so on. I will clean up soon.
Try to make it work w/ your device, you will have to change the board*
file accordingly H2 or osk in this patch.
>
> It should be possible to take the existing mixer part from my code to
> your driver. As I have not yet been able to play songs properly, I have
> sofar only been able to test the volume and mute/unmute settings from
> the Mixers Digital Gain Control (DGC) properly.
> Headset and handset parts seems to act ok, but only time will tell
> whether they really work. But if I can get your driver to play with my
> device, I could continue from that.
Let me know if you can play sounds with this patch so that I will
prepare it to receive your mixer then you can debug it
> I think there will also be a need for a somekind of "temp/work"
> repository for helping to synchronize the our (and possible others)
> work, but I think we can resolve that later.
Yeah, maybe we can try to keep sending pathes privetely in order to
don't mess the list to much, unless we got a server somewhere.
Please let me know if this patch works for you.
The idea was to change omap-alsa-aic23.c to omap-alsa.c and use
separate codec files for board dependent functions and data. Dma and
mcbsp functions should remain untouched.
> Mika
>
Daniel
> Daniel Petrini wrote:
>
> >Hi Mika,
> >
> >I have been working in this ALSA driver as well, and I have a
> >functional patch that plays songs but lacks the mixer support yet.
> >What do you think of join the drivers to make it work faster?
> >I am developing it generically in order to take advantage of existing
> >common code as dma and alsa generic.
> >
> >Daniel
> >
> >On 2/5/06, lamikr <lamikr@cc.jyu.fi> wrote:
> >
> >
> >>Hi
> >>
> >>I have not seen anyone working with the tsc2101 Alsa driver, so attached
> >>are the tsc2101 alsa driver sources I have been working for a while. The
> >>patch should apply to the omap-driver head. Unfortunately it is still
> >>non-functional at least with my omap 1510 based iPAQ h6340.
> >>
> >>I can hear small start of the song but then nothing happens. I have
> >>tried to debug the code and I can see that the the driver is able to get
> >>one callback to sound_dma_irq_handler with DSCR_END_BLOCK set, but after
> >>it does not continue with a next period of code.
> >>
> >>Here is some info from the driver
> >>- all code is located in /sound/arm/omap as I have wanted to mix it to
> >>existing aic23 code until this one works
> >>- based on to aic23 Alsa and tsc2101 OSS drivers. DMA code and driver
> >>base taken from the aic, but hardware initialization taken from the
> >>tsc2101 oss driver. (dma has only small changes like 16 bit mono to
> >>capture params instead of 32 bit ones supported in the aic23)
> >>- mixer code for DGC, headset and handset
> >>- debug is mostly printed by using DPRINTK() function and can be enabled
> >>by uncommenting "#define DEBUG 1" from the omap-alsa.h
> >>- This is platform driver, so you need to register it to your board-code
> >>in arch/arm/mach-omap1/board-* in a following way:
> >> static struct platform_device h6300_mcbsp1_device = {
> >> .name = "omap_tsc2101_mcbsp",
> >> .id = 1,
> >> };
> >>
> >> static struct platform_device *h6300_devices[] __initdata = {
> >> ...
> >> &h6300_mcbsp1_device,
> >> };
> >>
> >>I have only tested this with omap1510 based iPAQ h6300, so I would
> >>appreciate if somebody else could test this with other
> >>devices having tsc2101 chipset to find out whether this is just my hw
> >>specific problem. (Fixes would ofcource also be nice :-)
> >>
> >>For testing the driver I have plugged headset and listened the result of
> >>following commands
> >>- aplay song.wav (44100 hz 16 bit little endion format)
> >>- "speaker-test -r 8000", "-r 44100", etc...
> >>
> >>I have also tryed to change the audio_get_dma_pos() method to be like in
> >>the sa11xx-uda1341.c driver. With implementation
> >>based on to that, the speaker-test is able to produce somekind of
> >>periodic "wuff <silence> wuff <silence> wuff..." sound.
> >>(that method version is commented out in the omap-alsa-tsc2101.c)
> >>
> >>In addition to sources, attached is the log from one play attempt.
> >>
> >>Mika
> >>
> >>root@h6300:~# aplay free_breakbeat.wav
> >>Playing WAVE 'free_breakbeat.wav' : Signed 16 bit Little Endian, Rate
> >>44100 Hz, Stereo
> >>aplay: pcm_write:1146: write error: Input/output error
> >>root@h6300:~# dmesg
> >>XXX Alsa debug f:omap_alsa_tsc2101_init, l:1157
> >>XXX Alsa debug f:snd_omap_alsa_tsc2101_probe, l:1077
> >>XXX Alsa debug f:snd_card_omap_alsa_tsc2101_pcm, l:845
> >>XXX Alsa debug f:omap_alsa_tsc2101_audio_init, l:350
> >>XXX Alsa debug f:audio_dma_request, l:385
> >>[omap_request_alsa_sound_dma]: start
> >>[omap_request_alsa_sound_dma]: end(0)
> >>XXX Alsa debug f:audio_dma_request, l:385
> >>[omap_request_alsa_sound_dma]: start
> >>[omap_request_alsa_sound_dma]: end(0)
> >>[snd_omap_init_mixer]: start
> >>[setRecordSource]: start
> >>[setRecordSource]: end(0)
> >>[snd_omap_init_mixer]: end(0)
> >>OMAP_ALSA_TSC2101 audio support initialized
> >><omap_alsa_tsc2101_clock_on>: clock use count = 0
> >><omap_alsa_tsc2101_clock_on>: old clock rate = 12000000
> >>omap_alsa_tsc2101_clock_on(), no need to change clock rate, rate already
> >>12000000 Hz.
> >><omap_alsa_tsc2101_clock_on>: MCLK = 12000000 [12000000], usecount = 1,
> >>clk_enable retval = 0
> >><snd_card_omap_alsa_tsc2101_open>: runtime->hw =
> >>snd_omap_alsa_tsc2101_playback
> >><snd_omap_alsa_tsc2101_hw_params>: snd_omap_alsa_tsc2101_hw_params(),
> >>size = 131072
> >>XXX Alsa debug f:snd_omap_alsa_tsc2101_prepare, l:686
> >>XXX Alsa debug f:omap_alsa_tsc2101_set_samplerate, l:248
> >><omap_alsa_tsc2101_set_samplerate>: selected 44.1khz PLL
> >><snd_omap_alsa_tsc2101_trigger>: cmd = 1
> >><audio_process_dma>: started, offset = 0, dma_size = 8192, s->period =
> >>0, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
> >>32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
> >>0, dma_ptr = -1042022400
> >>[omap_start_alsa_sound_dma]: start
> >><omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
> >>-1042022400, dma_size = 8192
> >>[audio_set_dma_params_play]: start
> >>[audio_set_dma_params_play]: end(0)
> >>[audio_start_dma_chain]: start
> >>XXX Alsa debug f:audio_ifc_stop, l:229
> >>XXX Alsa debug f:audio_ifc_start, l:222
> >>[audio_start_dma_chain]: end(0)
> >>[omap_start_alsa_sound_dma]: end(0)
> >><audio_process_dma>: done, offset = 0, dma_size = 8192, s->period = 0,
> >>s->periods = 1, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
> >>32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
> >>0, dma_ptr = -1042022400
> >><audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
> >>s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
> >>= 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
> >>dma_ptr = -1042023937
> >><audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
> >><audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
> >><sound_dma_irq_handler>: started, lch = 0, status = 0x20, dma_status =
> >>32, data = c0b0608c
> >><sound_dma_irq_handler>: status = DCSR_END_BLOCK, calling
> >>audio_dma_callback()
> >><audio_dma_callback>: s->active, calling snd_pcm_period_elapsed
> >><audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
> >>s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
> >>= 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
> >>dma_ptr = -1042023937
> >><audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
> >><audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
> >><audio_process_dma>: started, offset = 8192, dma_size = 8192, s->period
> >>= 1, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
> >>32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
> >>0, dma_ptr = -1042014208
> >>[omap_start_alsa_sound_dma]: start
> >><omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
> >>-1042014208, dma_size = 8192
> >>[audio_set_dma_params_play]: start
> >>[audio_set_dma_params_play]: end(0)
> >>[audio_start_dma_chain]: start
> >>[audio_start_dma_chain]: end(0)
> >>[omap_start_alsa_sound_dma]: end(0)
> >><audio_process_dma>: done, offset = 8192, dma_size = 8192, s->period =
> >>1, s->periods = 1, s->dma_q_head = 0, s->offset = 8192, rt->buffer_size
> >>= 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr
> >>= 0, dma_ptr = -1042014208
> >><sound_dma_irq_handler>: done
> >>ALSA
> >>/home/lamikr/own/h6300/git/linux-omap-h6300-2.6/sound/core/pcm_lib.c:2231:
> >>playback write error (DMA or IRQ trouble?)
> >><snd_omap_alsa_tsc2101_trigger>: cmd = 0
> >>XXX Alsa debug f:audio_stop_dma, l:488
> >>[omap_alsa_audio_stop_dma]: start
> >>[omap_alsa_audio_stop_dma]: end(0)
> >>[omap_clear_alsa_sound_dma]: start
> >>[omap_clear_alsa_sound_dma]: end(0)
> >>XXX Alsa debug f:snd_card_omap_alsa_tsc2101_close, l:785
> >><omap_alsa_tsc2101_clock_off>: clock use count = 1
> >><omap_alsa_tsc2101_clock_off>: clock rate = 12000000
> >><omap_alsa_tsc2101_clock_off>: clock disabled
> >><omap_alsa_tsc2101_clock_off>: audio codec off
> >>
> >>
> >>
> >>_______________________________________________
> >>Linux-omap-open-source mailing list
> >>Linux-omap-open-source@linux.omap.com
> >>http://linux.omap.com/mailman/listinfo/linux-omap-open-source
> >>
> >>
> >>
> >>
> >>
> >>
> >
> >
> >--
> >INdT - Manaus - Brazil
> >
> >
> >
>
>
--
INdT - Manaus - Brazil
[-- Attachment #2: alsa_patch-h2-osk20060206.patch --]
[-- Type: text/x-patch, Size: 61623 bytes --]
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 4cc6a31..ead9ac9 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -41,6 +41,7 @@
#include <asm/arch/usb.h>
#include <asm/arch/keypad.h>
#include <asm/arch/common.h>
+#include <asm/arch/mcbsp.h>
extern int omap_gpio_init(void);
@@ -271,12 +272,48 @@ static struct platform_device h2_irda_de
.resource = h2_irda_resources,
};
+static struct omap_mcbsp_config mcbsp1_config = {
+ .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(1),
+ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+ .srgr1 = FWID(15),
+ .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
+
+ .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
+ //.pcr0 = CLKXP | CLKRP, /* mcbsp: slave */
+ },
+ .codec_configure_dev = tsc2101_configure,
+ .codec_set_samplerate = tsc2101_set_samplerate,
+ .codec_clock_setup = tsc2101_clock_setup,
+ .codec_clock_on = tsc2101_clock_on,
+ .codec_clock_off = tsc2101_clock_off,
+ .codec_write = audio_tsc2101_write,
+ .codec_read = audio_tsc2101_read,
+ .init_audio_controls = tsc2101_init_audio_controls,
+
+};
+
+static struct platform_device h2_mcbsp1_device = {
+ .name = "omap_mcbsp",
+ .id = 1,
+ .dev = {
+ .platform_data = &mcbsp1_config,
+ },
+};
+
static struct platform_device *h2_devices[] __initdata = {
&h2_nor_device,
&h2_nand_device,
&h2_smc91x_device,
&h2_irda_device,
&h2_kp_device,
+ &h2_mcbsp1_device,
};
static void __init h2_init_smc91x(void)
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 9d6098b..fb716df 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -148,10 +148,46 @@ static struct platform_device osk5912_cf
.num_resources = ARRAY_SIZE(osk5912_cf_resources),
.resource = osk5912_cf_resources,
};
+static struct platform_device h2_smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(h2_smc91x_resources),
+ .resource = h2_smc91x_resources,
+};
+
+static struct omap_mcbsp_config mcbsp1_config = {
+ .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(1),
+ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+ .srgr1 = FWID(15),
+ .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
-static struct platform_device osk5912_mcbsp1_device = {
- .name = "omap_mcbsp",
+ .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
+ //.pcr0 = CLKXP | CLKRP, /* mcbsp: slave */
+ },
+ .codec_configure_dev = tsc2101_configure,
+ .codec_set_samplerate = tsc2101_set_samplerate,
+ .codec_clock_setup = tsc2101_clock_setup,
+ .codec_clock_on = tsc2101_clock_on,
+ .codec_clock_off = tsc2101_clock_off,
+ .codec_write = audio_tsc2101_write,
+ .codec_read = audio_tsc2101_read,
+ .init_audio_controls = tsc2101_init_audio_controls,
+
+};
+
+static struct platform_device h2_mcbsp1_device = {
+ .name = "omap_mcbsp",
.id = 1,
+ .dev = {
+ .platform_data = &mcbsp1_config,
+ },
};
static struct resource osk5912_kp_resources[] = {
diff --git a/include/asm-arm/arch-omap/mcbsp.h b/include/asm-arm/arch-omap/mcbsp.h
index d97e031..1b2c95c 100644
--- a/include/asm-arm/arch-omap/mcbsp.h
+++ b/include/asm-arm/arch-omap/mcbsp.h
@@ -312,4 +312,39 @@ void omap_mcbsp_set_spi_mode(unsigned in
int omap_mcbsp_pollread(unsigned int id, u16 * buf);
int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
+/* Codecs - must leave soon */
+//#include "../../../sound/arm/alsa-omap.h"
+struct codec_controls;
+/* for alsa driver must leave */
+struct omap_mcbsp_config {
+ struct omap_mcbsp_reg_cfg mcbsp_regs;
+ void (*codec_configure_dev)(void);
+ void (*codec_set_samplerate)(long, unsigned int *);
+ void (*codec_clock_setup)(void);
+ int (*codec_clock_on)(void);
+ int (*codec_clock_off)(void);
+ void (*codec_write)(u8 address, u16 data);
+ void (*codec_read) (u8 address);
+ void (*init_audio_controls) (struct codec_controls *);
+
+
+};
+
+
+inline void aic23_configure(void);
+void aic23_set_samplerate(long rate, unsigned int rates[]);
+void aic23_clock_setup(void);
+int aic23_clock_on(void);
+int aic23_clock_off(void);
+void audio_aic23_write(u8, u16);
+void aic23_init_audio_controls(struct codec_controls * controls);
+
+inline void tsc2101_configure(void);
+void tsc2101_set_samplerate(long rate, unsigned int rates[]);
+void tsc2101_clock_setup(void);
+int tsc2101_clock_on(void);
+int tsc2101_clock_off(void);
+void audio_tsc2101_write(u8, u16);
+u16 audio_tsc2101_read(u8);
+void tsc2101_init_audio_controls(struct codec_controls * controls);
#endif
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index cf07154..f2e7577 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -7,6 +7,7 @@ config SND_SA11XX_UDA1341
tristate "SA11xx UDA1341TS driver (iPaq H3600)"
depends on ARCH_SA1100 && SND && L3
select SND_PCM
+ select SND_GENERIC_DRIVER
help
Say Y here if you have a Compaq iPaq H3x00 handheld computer
and want to use its Philips UDA 1341 audio chip.
@@ -45,4 +46,17 @@ config SND_OMAP_AIC23
To compile this driver as a module, choose M here: the module
will be called snd-omap-aic23.
+config SND_OMAP_TSC2101
+ tristate "OMAP TSC2101 alsa driver (H2)"
+ depends on ARCH_OMAP && SND
+ select SND_PCM
+ select OMAP_TSC2101
+ select OMAP_UWIRE if ARCH_OMAP
+ help
+ Say Y here if you have a H2 platform board
+ and want to use its TSC2101 audio chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-alsa-tsc2101.
+
endmenu
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index 019a9f0..1215b88 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -14,5 +14,8 @@ snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
-obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-aic23.o
-snd-omap-aic23-objs := omap-aic23.o omap-alsa-dma.o omap-alsa-mixer.o
+obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-alsa-aic23.o
+snd-omap-alsa-aic23-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-mixer.o omap-alsa-aic23.o
+
+obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-alsa-tsc2101.o
+snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-mixer.o omap-alsa-tsc2101.o
diff --git a/sound/arm/omap-aic23.h b/sound/arm/omap-aic23.h
index c8ab42c..ff7385c 100644
--- a/sound/arm/omap-aic23.h
+++ b/sound/arm/omap-aic23.h
@@ -44,6 +44,7 @@
#include <asm/arch/dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
+#include <asm/arch/mcbsp.h>
#define DEFAULT_OUTPUT_VOLUME 0x60
#define DEFAULT_INPUT_VOLUME 0x00 /* 0 ==> mute line in */
@@ -93,7 +94,7 @@ struct audio_stream {
/*
* Alsa card structure for aic23
*/
-struct snd_card_omap_aic23 {
+struct snd_card_omap_codec {
snd_card_t *card;
snd_pcm_t *pcm;
long samplerate;
@@ -103,17 +104,21 @@ struct snd_card_omap_aic23 {
/*********** Function Prototypes *************************/
void audio_dma_callback(void *);
-int snd_omap_mixer(struct snd_card_omap_aic23 *);
-void snd_omap_init_mixer(void);
+int snd_omap_mixer(struct snd_card_omap_codec *);
+void snd_omap_init_mixer(struct omap_mcbsp_config *);
/* Clock functions */
int omap_aic23_clock_on(void);
int omap_aic23_clock_off(void);
+ /* ADDED functions - H2/LDM port */
+void omap_codec_set_samplerate(struct snd_card_omap_codec * , long rate, unsigned int rates[]);
+inline void codec_configure(void);
#ifdef CONFIG_PM
void snd_omap_suspend_mixer(void);
void snd_omap_resume_mixer(void);
#endif
+#if 0
/* Codec AIC23 */
#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
@@ -126,5 +131,5 @@ static __inline__ void audio_aic23_write
}
#endif /* CONFIG_SENSORS_TLV320AIC23 */
-
+#endif
#endif
diff --git a/sound/arm/omap-alsa-aic23.c b/sound/arm/omap-alsa-aic23.c
new file mode 100644
index 0000000..6f7feef
--- /dev/null
+++ b/sound/arm/omap-alsa-aic23.c
@@ -0,0 +1,255 @@
+
+/*
+ * sound/arm/omap-alsa-aic23.c
+ *
+ * Alsa codec Driver for AIC23 codec on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini (d.pensator@gmail.com)
+ *
+ * Based in former alsa driver for osk and oss driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+//#include <linux/config.h>
+//#include <sound/driver.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/hardware/clock.h>
+#include <asm/arch/aic23.h>
+#include "omap-aic23.h"
+#include "omap-alsa.h"
+
+#include "omap-alsa-mixer.h"
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED 10
+
+static struct clk *aic23_mclk = 0;
+
+struct sample_rate_rate_reg_info {
+ u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
+ u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/* aic23 related */
+static const struct sample_rate_rate_reg_info
+ rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+ {0x06, 1}, /* 4000 */
+ {0x06, 0}, /* 8000 */
+ {0x0C, 1}, /* 16000 */
+ {0x11, 1}, /* 22050 */
+ {0x00, 1}, /* 24000 */
+ {0x0C, 0}, /* 32000 */
+ {0x11, 0}, /* 44100 */
+ {0x00, 0}, /* 48000 */
+ {0x1F, 0}, /* 88200 */
+ {0x0E, 0}, /* 96000 */
+};
+/*
+ * Codec/mcbsp init and configuration section
+ * codec dependent code.
+ */
+
+extern int tlv320aic23_write_value(u8 reg, u16 value);
+
+/* TLV320AIC23 is a write only device */
+__inline__ void audio_aic23_write(u8 address, u16 data)
+{
+ tlv320aic23_write_value(address, data);
+}
+
+
+/*
+ * Sample rate changing
+ */
+void aic23_set_samplerate(long rate, unsigned int rates[])
+{
+ u8 count = 0;
+ u16 data = 0;
+
+ /* Fix the rate if it has a wrong value */
+ if (rate >= 96000)
+ rate = 96000;
+ else if (rate >= 88200)
+ rate = 88200;
+ else if (rate >= 48000)
+ rate = 48000;
+ else if (rate >= 44100)
+ rate = 44100;
+ else if (rate >= 32000)
+ rate = 32000;
+ else if (rate >= 24000)
+ rate = 24000;
+ else if (rate >= 22050)
+ rate = 22050;
+ else if (rate >= 16000)
+ rate = 16000;
+ else if (rate >= 8000)
+ rate = 8000;
+ else
+ rate = 4000;
+
+ /* Search for the right sample rate */
+ /* Verify what happens if the rate is not supported
+ * now it goes to 96Khz */
+ while ((rates[count] != rate) &&
+ (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
+ count++;
+ }
+
+ data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
+ (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
+
+ audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
+
+}
+
+
+inline void aic23_configure(void)
+{
+ /* Reset codec */
+ audio_aic23_write(RESET_CONTROL_ADDR, 0);
+
+ /* Initialize the AIC23 internal state */
+
+ /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
+ audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DEFAULT_ANALOG_AUDIO_CONTROL);
+
+ /* Digital audio path control, de-emphasis control 44.1kHz */
+ audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
+
+ /* Digital audio interface, master/slave mode, I2S, 16 bit */
+//#ifdef AIC23_MASTER
+ audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
+ MS_MASTER | IWL_16 | FOR_DSP);
+//#else
+// audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
+//#endif
+
+ /* Enable digital interface */
+ audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+
+
+ printk(KERN_ERR "\n\n TESTE 2 \n\n");
+
+}
+
+/*
+ * Omap MCBSP clock configuration
+ *
+ * Here we have some functions that allows clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+#define CODEC_CLOCK 12000000
+#define AUDIO_RATE_DEFAULT 44100
+
+/*
+ * Do clock framework mclk search
+ */
+void aic23_clock_setup(void)
+{
+ aic23_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ * turn codec audio on
+ */
+int aic23_clock_on(void)
+{
+ if (clk_get_usecount(aic23_mclk) > 0) {
+ /* MCLK is already in use */
+ printk(KERN_WARNING
+ "MCLK in use at %d Hz. We change it to %d Hz\n",
+ (uint) clk_get_rate(aic23_mclk),
+ CODEC_CLOCK);
+ }
+
+ if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
+ printk(KERN_ERR
+ "Cannot set MCLK for AIC23 CODEC\n");
+ return -ECANCELED;
+ }
+
+ clk_use(aic23_mclk);
+
+ printk(KERN_DEBUG
+ "MCLK = %d [%d], usecount = %d\n",
+ (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
+ clk_get_usecount(aic23_mclk));
+
+ /* Now turn the audio on */
+ audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
+ ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
+ ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);
+
+ return 0;
+}
+/*
+ * Do some sanity check, turn clock off and then turn
+ * codec audio off
+ */
+int aic23_clock_off(void)
+{
+ if (clk_get_usecount(aic23_mclk) > 0) {
+ if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
+ printk(KERN_WARNING
+ "MCLK for audio should be %d Hz. But is %d Hz\n",
+ (uint) clk_get_rate(aic23_mclk),
+ CODEC_CLOCK);
+ }
+
+ clk_unuse(aic23_mclk);
+ }
+
+ audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
+ DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
+ ADC_OFF | MIC_OFF | LINE_OFF);
+ return 0;
+}
+
+/*
+ * Mixer part
+ */
+snd_kcontrol_new_t snd_omap_controls[] = {
+ OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+ PCM_INDEX, 0x00),
+ OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+ PCM_INDEX, OUTPUT_VOLUME_MASK),
+ OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, BYPASS_ON, 0),
+ OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+ LINE_INDEX, 0x00),
+ OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+ LINE_INDEX, INPUT_VOLUME_MASK),
+ OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, STE_ENABLED, 0),
+ OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, 5, SIDETONE_MASK),
+ OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICM_MUTED, 1),
+ OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
+ OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
+};
+int omap_controls_size = ARRAY_SIZE(snd_omap_controls);
+
+
+void aic23_init_audio_controls(struct codec_controls * mixer_controls)
+{
+ mixer_controls->left_vol_output = DEFAULT_OUTPUT_VOLUME;
+ mixer_controls->right_vol_output = DEFAULT_OUTPUT_VOLUME;
+ mixer_controls->left_line_input = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+ mixer_controls->right_line_input = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+ mixer_controls->mic_input = 0;
+ mixer_controls->left_vol_address = LEFT_CHANNEL_VOLUME_ADDR;
+ mixer_controls->right_vol_address = RIGHT_CHANNEL_VOLUME_ADDR;
+ mixer_controls->left_line_address = LEFT_LINE_VOLUME_ADDR;
+ mixer_controls->right_line_address = RIGHT_LINE_VOLUME_ADDR;
+}
diff --git a/sound/arm/omap-alsa-mixer.c b/sound/arm/omap-alsa-mixer.c
index 742e5b6..63cf1fe 100644
--- a/sound/arm/omap-alsa-mixer.c
+++ b/sound/arm/omap-alsa-mixer.c
@@ -39,41 +39,56 @@
#include <linux/config.h>
#include <sound/driver.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-
-#include <asm/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/arch/dma.h>
+//#include <linux/module.h>
+//#include <linux/device.h>
+//#include <linux/init.h>
+//#include <linux/errno.h>
+//#include <linux/ioctl.h>
+//#include <linux/delay.h>
+//#include <linux/slab.h>
+
+//#include <asm/hardware.h>
+//#include <asm/mach-types.h>
+//#include <asm/arch/dma.h>
#include <asm/arch/aic23.h>
#include "omap-aic23.h"
#include <sound/initval.h>
#include <sound/control.h>
+#include <asm/arch/mcbsp.h>
+#include "omap-alsa.h"
+#include "omap-alsa-mixer.h"
+
MODULE_AUTHOR("David Cohen, Daniel Petrini - INdT");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
+struct omap_mcbsp_config * pldata = NULL;
+struct codec_controls mixer_controls;
/*
* Codec dependent region
*/
/* Codec AIC23 */
-#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
+//#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
+#if defined(CONFIG_SND_OMAP_AIC23)
extern __inline__ void audio_aic23_write(u8, u16);
#define MIXER_NAME "Mixer AIC23"
#define SND_OMAP_WRITE(reg, val) audio_aic23_write(reg, val)
-#endif
+#else
+
+//extern __inline__ void audio_tsc2101_write(u8 address, u16 data);
+#define MIXER_NAME "Mixer TSC2101"
+//#define SND_OMAP_WRITE(reg, val) audio_tsc2101_write(reg, val)
+#define SND_OMAP_WRITE(reg, val) pldata->codec_write(reg, val)
+
+#endif
+#if 0
/* Callback Functions */
#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
{ \
@@ -117,14 +132,9 @@ extern __inline__ void audio_aic23_write
.put = snd_omap_put_double, \
.private_value = left_reg | (right_reg << 8) | (reg_index << 16) | (mask << 18) \
}
+#endif
/* Local Registers */
-enum snd_device_index {
- PCM_INDEX = 0,
- LINE_INDEX,
- AAC_INDEX, /* Analog Audio Control: reg = l_reg */
-};
-
struct {
u16 l_reg;
u16 r_reg;
@@ -150,7 +160,7 @@ u16 snd_sidetone[6] = {
/* Begin Bool Functions */
-static int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
@@ -160,7 +170,7 @@ static int snd_omap_info_bool(snd_kcontr
return 0;
}
-static int snd_omap_get_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_omap_get_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
int mic_index = (kcontrol->private_value >> 8) & 0x03;
u16 mask = (kcontrol->private_value >> 12) & 0xff;
@@ -174,7 +184,7 @@ static int snd_omap_get_bool(snd_kcontro
return 0;
}
-static int snd_omap_put_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_omap_put_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
int mic_index = (kcontrol->private_value >> 8) & 0x03;
u16 mask = (kcontrol->private_value >> 12) & 0xff;
@@ -203,7 +213,7 @@ static int snd_omap_put_bool(snd_kcontro
/* Begin Mux Functions */
-static int snd_omap_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+int snd_omap_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
/* Mic = 0
* Line = 1 */
@@ -211,7 +221,7 @@ static int snd_omap_info_mux(snd_kcontro
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
+ uinfo->value.enumerated.items = 1/*2 VOLTE AQUI*/;
if (uinfo->value.enumerated.item > 1)
uinfo->value.enumerated.item = 1;
@@ -221,7 +231,7 @@ static int snd_omap_info_mux(snd_kcontro
return 0;
}
-static int snd_omap_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_omap_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
u16 mask = (kcontrol->private_value >> 10) & 0xff;
int mux_index = (kcontrol->private_value >> 8) & 0x03;
@@ -231,7 +241,7 @@ static int snd_omap_get_mux(snd_kcontrol
return 0;
}
-static int snd_omap_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_omap_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
u16 reg = kcontrol->private_value & 0xff;
u16 mask = (kcontrol->private_value >> 10) & 0xff;
@@ -253,7 +263,7 @@ static int snd_omap_put_mux(snd_kcontrol
/* Begin Single Functions */
-static int snd_omap_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+int snd_omap_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
int mask = (kcontrol->private_value >> 18) & 0xff;
int reg_val = (kcontrol->private_value >> 8) & 0xff;
@@ -266,7 +276,7 @@ static int snd_omap_info_single(snd_kcon
return 0;
}
-static int snd_omap_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_omap_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
@@ -275,7 +285,7 @@ static int snd_omap_get_single(snd_kcont
return 0;
}
-static int snd_omap_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_omap_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
@@ -305,7 +315,7 @@ static int snd_omap_put_single(snd_kcont
/* Begin Double Functions */
-static int snd_omap_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+int snd_omap_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
/* mask == 0 : Switch
* mask != 0 : Volume */
@@ -319,7 +329,7 @@ static int snd_omap_info_double(snd_kcon
return 0;
}
-static int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
/* mask == 0 : Switch
* mask != 0 : Volume */
@@ -339,7 +349,7 @@ static int snd_omap_get_double(snd_kcont
return 0;
}
-static int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
/* mask == 0 : Switch
* mask != 0 : Volume */
@@ -393,7 +403,7 @@ static int snd_omap_put_double(snd_kcont
}
/* End Double Functions */
-
+#if 0
static snd_kcontrol_new_t snd_omap_controls[] = {
OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
PCM_INDEX, 0x00),
@@ -410,11 +420,18 @@ static snd_kcontrol_new_t snd_omap_contr
OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
};
+#endif
+extern snd_kcontrol_new_t snd_omap_controls[];
+extern int omap_controls_size;
-void snd_omap_init_mixer(void)
+void snd_omap_init_mixer(struct omap_mcbsp_config *pdata)
{
u16 vol_reg;
+ pldata = pdata;
+
+ pldata->init_audio_controls(&mixer_controls);
+#if 0
/* Line's default values */
omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
@@ -434,6 +451,28 @@ void snd_omap_init_mixer(void)
omap_regs[PCM_INDEX].sw = 1;
SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
+#endif
+
+ /*Line's default values */
+ omap_regs[LINE_INDEX].l_reg = mixer_controls.left_line_input;
+ omap_regs[LINE_INDEX].r_reg = mixer_controls.right_line_input;
+ omap_regs[LINE_INDEX].sw = 0;
+ SND_OMAP_WRITE(mixer_controls.left_line_address, mixer_controls.left_line_input);
+ SND_OMAP_WRITE(mixer_controls.right_line_address, mixer_controls.right_line_input);
+
+ /* Analog Audio Control's default values */
+ omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
+
+ /* Headphone's default values */
+ omap_regs[PCM_INDEX].l_reg = mixer_controls.left_vol_output;
+ omap_regs[PCM_INDEX].r_reg = mixer_controls.right_vol_output;
+ omap_regs[PCM_INDEX].sw = 1;
+// SND_OMAP_WRITE(mixer_controls.left_vol_address, mixer_controls.left_vol_output);
+// SND_OMAP_WRITE(mixer_controls.right_vol_address, mixer_controls.right_vol_output);
+ SND_OMAP_WRITE(mixer_controls.right_vol_address, 0x0f0f);
+
+ printk("Volume:::::::::: %d %d %d %d \n", mixer_controls.left_vol_output, mixer_controls.right_vol_output,
+ mixer_controls.left_vol_address, mixer_controls.right_vol_address);
}
#ifdef CONFIG_PM
@@ -474,7 +513,7 @@ void snd_omap_resume_mixer(void)
}
#endif
-int snd_omap_mixer(struct snd_card_omap_aic23 *chip)
+int snd_omap_mixer(struct snd_card_omap_codec *chip)
{
snd_card_t *card;
unsigned int idx;
@@ -487,7 +526,7 @@ int snd_omap_mixer(struct snd_card_omap_
strcpy(card->mixername, MIXER_NAME);
/* Registering alsa mixer controls */
- for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++)
+ for (idx = 0; idx < omap_controls_size/*ARRAY_SIZE(snd_omap_controls)*/; idx++)
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_omap_controls[idx], chip))) < 0)
return err;
diff --git a/sound/arm/omap-alsa-mixer.h b/sound/arm/omap-alsa-mixer.h
new file mode 100644
index 0000000..02cf761
--- /dev/null
+++ b/sound/arm/omap-alsa-mixer.h
@@ -0,0 +1,72 @@
+
+#include <sound/initval.h>
+#include <sound/control.h>
+
+enum snd_device_index {
+ PCM_INDEX = 0,
+ LINE_INDEX,
+ AAC_INDEX, /* Analog Audio Control: reg = l_reg */
+};
+
+
+int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
+int snd_omap_get_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_omap_put_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_omap_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
+int snd_omap_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_omap_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_omap_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
+int snd_omap_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_omap_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_omap_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
+int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+
+
+
+
+
+/* Callback Functions */
+#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_bool, \
+ .get = snd_omap_get_bool, \
+ .put = snd_omap_put_bool, \
+ .private_value = reg | (reg_index << 8) | (invert << 10) | (mask << 12) \
+}
+
+#define OMAP_MUX(xname, reg, reg_index, mask) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = snd_omap_info_mux, \
+ .get = snd_omap_get_mux, \
+ .put = snd_omap_put_mux, \
+ .private_value = reg | (reg_index << 8) | (mask << 10) \
+}
+
+#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_single, \
+ .get = snd_omap_get_single, \
+ .put = snd_omap_put_single, \
+ .private_value = reg | (reg_val << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_double, \
+ .get = snd_omap_get_double, \
+ .put = snd_omap_put_double, \
+ .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | (mask << 18) \
+}
+
diff --git a/sound/arm/omap-alsa-tsc2101.c b/sound/arm/omap-alsa-tsc2101.c
new file mode 100644
index 0000000..58fc3ac
--- /dev/null
+++ b/sound/arm/omap-alsa-tsc2101.c
@@ -0,0 +1,471 @@
+
+/* routines extracted from file oss/omap-audio-tsc2101.c
+ * or called from drivers/ssi/omap-tsc2101.c */
+
+//#include <linux/module.h>
+//#include <linux/init.h>
+//#include <linux/errno.h>
+//#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+//#include <asm/hardware.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/arch/mcbsp.h>
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+
+#include "omap-alsa.h"
+#include "omap-alsa-mixer.h"
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE 16
+#define AUDIO_RATE_DEFAULT 44100
+#define PAGE2_AUDIO_CODEC_REGISTERS (2)
+#define LEAVE_CS 0x80
+
+/* Tsc Audio Specific */
+#define NUMBER_SAMPLE_RATES_SUPPORTED 16
+#define OUTPUT_VOLUME_MIN 0x7F
+#define OUTPUT_VOLUME_MAX 0x32
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MIN
+#define DEFAULT_VOLUME_LEVEL OUTPUT_VOLUME_MAX
+
+/* use input vol of 75 for 0dB gain */
+#define INPUT_VOLUME_MIN 0x0
+#define INPUT_VOLUME_MAX 0x7D
+#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
+
+#define DEFAULT_VOLUME 20/*93*/
+#define DEFAULT_INPUT_VOLUME 20 /* An minimal volume */
+typedef struct {
+ u8 volume;
+ u8 line;
+ u8 mic;
+ int recsrc;
+ int mod_cnt;
+} tsc2101_local_info;
+
+static tsc2101_local_info tsc2101_local = {
+ volume: DEFAULT_VOLUME,
+ line: DEFAULT_INPUT_VOLUME,
+ mic: DEFAULT_INPUT_VOLUME,
+ recsrc: SOUND_MASK_LINE,
+ mod_cnt: 0
+};
+
+
+#define AUDIO_MCBSP OMAP_MCBSP1
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+#define SET_VOLUME 1
+#define SET_LINE 2
+#define SET_MIC 3
+#define SET_RECSRC 4
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
+#else
+#define ADEBUG() /* nop */
+#endif
+
+
+//deve sair....
+static int tsc2101_update(int flag, int val);
+
+static struct clk *tsc2101_mclk = 0;
+
+struct sample_rate_reg_info {
+ u16 sample_rate;
+ u8 divisor;
+ u8 fs_44kHz; /* if 0 48 khz, if 1 44.1 khz fsref */
+};
+
+/* To Store the default sample rate */
+static long audio_samplerate = AUDIO_RATE_DEFAULT;
+
+static const struct sample_rate_reg_info
+ reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+ /* Div 1 */
+ {48000, 0, 0},
+ {44100, 0, 1},
+ /* Div 1.5 */
+ {32000, 1, 0},
+ {29400, 1, 1},
+ /* Div 2 */
+ {24000, 2, 0},
+ {22050, 2, 1},
+ /* Div 3 */
+ {16000, 3, 0},
+ {14700, 3, 1},
+ /* Div 4 */
+ {12000, 4, 0},
+ {11025, 4, 1},
+ /* Div 5 */
+ {9600, 5, 0},
+ {8820, 5, 1},
+ /* Div 5.5 */
+ {8727, 6, 0},
+ {8018, 6, 1},
+ /* Div 6 */
+ {8000, 7, 0},
+ {7350, 7, 1},
+};
+
+/*
+ * Codec/mcbsp init and configuration section
+ * codec dependent code.
+ */
+
+/*********************************************************************************
+ *
+ * Simplified write for tsc Audio
+ *
+ *********************************************************************************/
+/*inline*/ void audio_tsc2101_write(u8 address, u16 data)
+{
+ printk("WR: ad:0x%x data:0x%x\n", address, data);
+ omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
+}
+
+/*********************************************************************************
+ *
+ * Simplified read for tsc Audio
+ *
+ *********************************************************************************/
+__inline__ u16 audio_tsc2101_read(u8 address)
+{
+ return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+/*
+ * Sample rate changing
+ */
+void tsc2101_set_samplerate(long sample_rate, unsigned int rates[])
+{
+
+ u8 count = 0;
+ u16 data = 0;
+ int clkgdv = 0;
+
+ u16 srgr1, srgr2;
+ /* wait for any frame to complete */
+ udelay(125);
+ ADEBUG();
+
+ /* Search for the right sample rate */
+ while ((reg_info[count].sample_rate != sample_rate) &&
+ (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+ count++;
+ }
+ if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+ printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+ (int)sample_rate);
+ return; // -EPERM;
+ }
+
+ /* Set AC1 */
+ data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
+ /*Clear prev settings */
+ data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+ data |=
+ AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
+ divisor);
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
+
+ /* Set the AC3 */
+ data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
+ /*Clear prev settings */
+ data &= ~(AC3_REFFS | AC3_SLVMS);
+ data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC_MASTER
+ data |= AC3_SLVMS;
+#endif /* #ifdef TSC_MASTER */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
+
+ /* program the PLLs */
+ if (reg_info[count].fs_44kHz) {
+ /* 44.1 khz - 12 MHz Mclk */
+ audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */
+ audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */
+ } else {
+ /* 48 khz - 12 Mhz Mclk */
+ audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */
+ audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */
+ }
+
+ audio_samplerate = sample_rate;
+
+ /* Set the sample rate */
+#ifndef TSC_MASTER
+ clkgdv =
+ DEFAULT_MCBSP_CLOCK / (sample_rate *
+ (DEFAULT_BITPERSAMPLE * 2 - 1));
+ if (clkgdv)
+ //initial_config.srgr1 =
+ srgr1 =
+ (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ else
+ return (1);
+
+ /* Stereo Mode */
+ //initial_config.srgr2 =
+ srgr2 =
+ (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+ //initial_config.srgr1 =
+ srgr1 =
+ (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+ //initial_config.srgr2 =
+ srgr2 =
+ ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif /* end of #ifdef TSC_MASTER */
+ //omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR2, srgr2);
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR1, srgr1);
+
+
+//#define OMAP1610_MCBSP1_BASE 0xe1011800
+
+}
+
+
+inline void tsc2101_configure(void)
+{
+ ADEBUG();
+
+ audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
+
+ /*Mute Analog Sidetone */
+ /*Select MIC_INHED input for headset */
+ /*Cell Phone In not connected */
+ audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
+ MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
+
+ /* Set record source */
+ tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
+
+ /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+ /* 1dB AGC hysteresis */
+ /* MICes bias 2V */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+ /* Set codec output volume */
+ audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
+
+ /* DAC left and right routed to SPK2 */
+ /* SPK1/2 unmuted */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
+ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+ AC5_HDSCPTC);
+
+ /* OUT8P/N muted, CPOUT muted */
+
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
+ AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+ AC6_VGNDSCPTC);
+
+ /* Headset/Hook switch detect disabled */
+ audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
+
+ /* Left line input volume control */
+ tsc2101_update(SET_LINE, tsc2101_local.line);
+
+ /* mic input volume control */
+ tsc2101_update(SET_MIC, tsc2101_local.mic);
+
+ /* Left/Right headphone channel volume control */
+ /* Zero-cross detect on */
+ tsc2101_update(SET_VOLUME, tsc2101_local.volume);
+
+ /* clock configuration */
+ tsc2101_set_samplerate(audio_samplerate, NULL);
+
+//#ifdef TSC_DUMP_REGISTERS
+// tsc2101_dumpRegisters();
+//#endif
+
+ printk(KERN_ERR "\n\n TESTE 2 \n\n");
+
+}
+
+/*
+ * Omap MCBSP clock configuration
+ *
+ * Here we have some functions that allows clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+#define CODEC_CLOCK 12000000
+/*
+ * Do clock framework mclk search
+ */
+void tsc2101_clock_setup(void)
+{
+ tsc2101_mclk = clk_get(0, "mclk");
+ ADEBUG();
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ * turn codec audio on
+ */
+int tsc2101_clock_on(void)
+{
+ omap_tsc2101_enable(); /* */
+
+ return 0;
+}
+/*
+ * Do some sanity check, turn clock off and then turn
+ * codec audio off
+ */
+int tsc2101_clock_off(void)
+{
+ omap_tsc2101_disable();
+
+ return 0;
+}
+
+static int tsc2101_update(int flag, int val)
+{
+ u16 volume;
+ u16 data;
+
+ //FN_IN;
+ ADEBUG();
+ switch (flag) {
+ case SET_VOLUME:
+ if (val < 0 || val > 100) {
+ printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+ return -EPERM;
+ }
+ /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+ volume =
+ ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+ /* invert the value for getting the proper range 0 min and 100 max */
+ volume = OUTPUT_VOLUME_MIN - volume;
+ data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
+ data &=
+ ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
+ DGC_DARVL(OUTPUT_VOLUME_MIN));
+ data |= DGC_DALVL(volume) | DGC_DARVL(volume);
+ audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data);
+ data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
+
+ break;
+
+ case SET_LINE:
+ if (val < 0 || val > 100) {
+ printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+ return -EPERM;
+ }
+ /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+ /* NOTE: 0 is minimum volume and not mute */
+ volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+ /* Handset Input not muted, AGC for Handset In off */
+ audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL,
+ HGC_ADPGA_HED(volume));
+ break;
+
+ case SET_MIC:
+ if (val < 0 || val > 100) {
+ printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+ return -EPERM;
+ }
+ /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+ /* NOTE: 0 is minimum volume and not mute */
+ volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+ /* Handset Input not muted, AGC for Handset In off */
+ audio_tsc2101_write(TSC2101_HANDSET_GAIN_CTRL,
+ HNGC_ADPGA_HND(volume));
+ break;
+
+ case SET_RECSRC:
+ /*
+ * If more than one recording device selected,
+ * disable the device that is currently in use.
+ */
+ if (hweight32(val) > 1)
+ val &= ~tsc2101_local.recsrc;
+
+ data = audio_tsc2101_read(TSC2101_MIXER_PGA_CTRL);
+ data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+
+ if (val == SOUND_MASK_MIC) {
+ data |= MPC_MICSEL(1);
+ audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
+ }
+ else if (val == SOUND_MASK_LINE) {
+ data |= MPC_MICSEL(0);
+ audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
+ }
+ else {
+ printk(KERN_WARNING "omap1610-tsc2101: Wrong RECSRC"
+ " value specified\n");
+ return -EINVAL;
+ }
+ tsc2101_local.recsrc = val;
+ break;
+ default:
+ printk(KERN_WARNING "omap1610-tsc2101: Wrong tsc2101_update "
+ "flag specified\n");
+ break;
+ }
+
+ //FN_OUT(0);
+ return 0;
+}
+
+/*
+ * Mixer part
+ */
+
+/* NOT WORKING *** */
+snd_kcontrol_new_t snd_omap_controls[] = {
+ OMAP_DOUBLE("PCM Playback Switch", 0, TSC2101_DAC_GAIN_CTRL, TSC2101_DAC_GAIN_CTRL,
+ PCM_INDEX, 0x00),
+ OMAP_DOUBLE("PCM Playback Volume", 0, TSC2101_DAC_GAIN_CTRL, TSC2101_DAC_GAIN_CTRL,
+ PCM_INDEX, 0x7f/*OUTPUT_VOLUME_MASK*/),
+ //OMAP_BOOL("Line Playback Switch", 0, TSC2101_HEADSET_GAIN_CTRL, AAC_INDEX, 0x02/*mudeme*/, 0),
+ //OMAP_DOUBLE("Line Capture Switch", 0, TSC2101_HEADSET_GAIN_CTRL, TSC2101_HEADSET_GAIN_CTRL,
+ // LINE_INDEX, 0x00),
+ //OMAP_DOUBLE("Line Capture Volume", 0, TSC2101_HEADSET_GAIN_CTRL, TSC2101_HEADSET_GAIN_CTRL,
+ // LINE_INDEX, 0x7f/*INPUT_VOLUME_MASK*/),
+ //OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, STE_ENABLED, 0),
+ //OMAP_SINGLE("Mic Playback Volume", 0, TSC2101_HANDSET_GAIN_CTRL, AAC_INDEX, 5, SIDETONE_MASK),
+ //OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICM_MUTED, 1),
+ //OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
+ //OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
+};
+int omap_controls_size = ARRAY_SIZE(snd_omap_controls);
+
+void tsc2101_init_audio_controls(struct codec_controls * mixer_controls)
+{
+ mixer_controls->left_vol_output = 0x30;
+ mixer_controls->right_vol_output = 0x30;
+ mixer_controls->left_line_input = 0;
+ mixer_controls->right_line_input = 0;
+ mixer_controls->mic_input = 0;
+ mixer_controls->left_vol_address = TSC2101_DAC_GAIN_CTRL;
+ mixer_controls->right_vol_address = TSC2101_DAC_GAIN_CTRL;
+ mixer_controls->left_line_address = TSC2101_HEADSET_GAIN_CTRL;
+ mixer_controls->right_line_address = TSC2101_HEADSET_GAIN_CTRL;
+}
diff --git a/sound/arm/omap-alsa.c b/sound/arm/omap-alsa.c
new file mode 100644
index 0000000..ab56ac6
--- /dev/null
+++ b/sound/arm/omap-alsa.c
@@ -0,0 +1,757 @@
+/*
+ * sound/arm/omap-aic23.c
+ *
+ * Alsa Driver for AIC23 codec on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Based on sa11xx-uda1341.c,
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-07-29 INdT Kernel Team - Alsa driver for omap osk. Creation of new
+ * file omap-aic23.c
+ *
+ * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#include <linux/config.h>
+#include <sound/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/aic23.h>
+//#include <asm/hardware/clock.h>
+#include <asm/arch/mcbsp.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/memalloc.h>
+
+#include "omap-alsa-dma.h"
+#include "omap-aic23.h"
+
+#undef DEBUG
+//#define DEBUG
+
+#ifdef DEBUG
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
+#else
+#define ADEBUG() /* nop */
+#endif
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE 16
+#define AUDIO_RATE_DEFAULT 44100
+#define AUDIO_MCBSP OMAP_MCBSP1
+#define NUMBER_SAMPLE_RATES_SUPPORTED 10
+
+
+MODULE_AUTHOR("Daniel Petrini, David Cohen, Anderson Briglia - INdT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP driver for ALSA");
+MODULE_SUPPORTED_DEVICE("{{AIC23,OMAP AIC23}}");
+MODULE_ALIAS("omap_mcbsp.1");
+
+static char *id = NULL;
+MODULE_PARM_DESC(id, "OMAP ALSA Driver for AIC23 chip.");
+
+static struct snd_card_omap_codec *omap_alsa = NULL;
+
+struct omap_mcbsp_config * pdata = NULL;
+
+/*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+ 4000, 8000, 16000, 22050,
+ 24000, 32000, 44100,
+ 48000, 88200, 96000,
+};
+
+static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+ omap_mcbsp_start(AUDIO_MCBSP);
+ return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ return 0;
+}
+
+static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
+{
+ /* Setup DMA stuff */
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa AIC23 out";
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
+ SNDRV_PCM_STREAM_PLAYBACK;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
+ OMAP_DMA_MCBSP1_TX;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
+ audio_ifc_start;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
+ audio_ifc_stop;
+
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa AIC23 in";
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
+ SNDRV_PCM_STREAM_CAPTURE;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
+ OMAP_DMA_MCBSP1_RX;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
+ audio_ifc_start;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
+ audio_ifc_stop;
+}
+
+/*
+ * DMA functions
+ * Depends on omap-alsa-dma.c functions and (omap) dma.c
+ *
+ */
+#define DMA_BUF_SIZE 1024 * 8
+
+static int audio_dma_request(struct audio_stream *s,
+ void (*callback) (void *))
+{
+ int err;
+ ADEBUG();
+
+ err = omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "unable to grab audio dma 0x%x\n",
+ s->dma_dev);
+ return err;
+}
+
+static int audio_dma_free(struct audio_stream *s)
+{
+ int err = 0;
+ ADEBUG();
+
+ err = omap_free_sound_dma(s, &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "Unable to free audio dma channels!\n");
+ return err;
+}
+
+/*
+ * This function should calculate the current position of the dma in the
+ * buffer. It will help alsa middle layer to continue update the buffer.
+ * Its correctness is crucial for good functioning.
+ */
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ unsigned int offset;
+ unsigned long flags;
+ dma_addr_t count;
+ ADEBUG();
+
+ /* this must be called w/ interrupts locked as requested in dma.c */
+ spin_lock_irqsave(&s->dma_lock, flags);
+
+ /* For the current period let's see where we are */
+ 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)
+ offset = 0;
+
+ return offset;
+}
+
+/*
+ * this stops the dma and clears the dma ptrs
+ */
+static void audio_stop_dma(struct audio_stream *s)
+{
+ unsigned long flags;
+ ADEBUG();
+
+ spin_lock_irqsave(&s->dma_lock, flags);
+ s->active = 0;
+ s->period = 0;
+ s->periods = 0;
+
+ /* this stops the dma channel and clears the buffer ptrs */
+ omap_audio_stop_dma(s);
+
+ omap_clear_sound_dma(s);
+
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+/*
+ * Main dma routine, requests dma according where you are in main alsa buffer
+ */
+static void audio_process_dma(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime;
+ unsigned int dma_size;
+ unsigned int offset;
+ int ret;
+ ADEBUG();
+
+ runtime = substream->runtime;
+ if (s->active) {
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ offset = dma_size * s->period;
+ snd_assert(dma_size <= DMA_BUF_SIZE,);
+ ret =
+ omap_start_sound_dma(s,
+ (dma_addr_t) runtime->dma_area +
+ offset, dma_size);
+ if (ret) {
+ printk(KERN_ERR
+ "audio_process_dma: cannot queue DMA buffer (%i)\n",
+ ret);
+ return;
+ }
+
+ s->period++;
+ s->period %= runtime->periods;
+ s->periods++;
+ s->offset = offset;
+ }
+}
+
+/*
+ * This is called when dma IRQ occurs at the end of each transmited block
+ */
+void audio_dma_callback(void *data)
+{
+ struct audio_stream *s = data;
+ ADEBUG();
+
+ /*
+ * If we are getting a callback for an active stream then we inform
+ * the PCM middle layer we've finished a period
+ */
+ if (s->active)
+ snd_pcm_period_elapsed(s->stream);
+
+ spin_lock(&s->dma_lock);
+ if (s->periods > 0) {
+ s->periods--;
+ }
+ audio_process_dma(s);
+ spin_unlock(&s->dma_lock);
+}
+
+
+/*
+ * Alsa section
+ * PCM settings and callbacks
+ */
+
+static int snd_omap_alsa_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ int stream_id = substream->pstr->stream;
+ struct audio_stream *s = &chip->s[stream_id];
+ int err = 0;
+ ADEBUG();
+
+ /* note local interrupts are already disabled in the midlevel code */
+ spin_lock(&s->dma_lock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* requested stream startup */
+ s->active = 1;
+ audio_process_dma(s);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* requested stream shutdown */
+ audio_stop_dma(s);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ spin_unlock(&s->dma_lock);
+
+ return err;
+}
+
+static int snd_omap_alsa_prepare(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct audio_stream *s = &chip->s[substream->pstr->stream];
+ ADEBUG();
+
+ /* set requested samplerate */
+ pdata->codec_set_samplerate(runtime->rate, &rates[0]);
+ chip->samplerate = runtime->rate;
+
+ s->period = 0;
+ s->periods = 0;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t snd_omap_alsa_pointer(snd_pcm_substream_t *
+ substream)
+{
+ ADEBUG();
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+
+ return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+/* Hardware capabilities */
+
+static snd_pcm_hardware_t snd_omap_alsa_capture = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static snd_pcm_hardware_t snd_omap_alsa_playback = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static int snd_card_omap_alsa_open(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int stream_id = substream->pstr->stream;
+ int err;
+ ADEBUG();
+
+ chip->s[stream_id].stream = substream;
+
+ pdata->codec_clock_on();
+
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = snd_omap_alsa_playback;
+ else
+ runtime->hw = snd_omap_alsa_capture;
+ if ((err =
+ snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS)) <
+ 0)
+ return err;
+ if ((err =
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_constraints_rates)) < 0)
+ return err;
+
+ return 0;
+}
+
+static int snd_card_omap_alsa_close(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ ADEBUG();
+
+ pdata->codec_clock_off();
+ chip->s[substream->pstr->stream].stream = NULL;
+
+ return 0;
+}
+
+/* HW params & free */
+
+static int snd_omap_alsa_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int snd_omap_alsa_hw_free(snd_pcm_substream_t * substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+
+static snd_pcm_ops_t snd_card_omap_alsa_playback_ops = {
+ .open = snd_card_omap_alsa_open,
+ .close = snd_card_omap_alsa_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_alsa_hw_params,
+ .hw_free = snd_omap_alsa_hw_free,
+ .prepare = snd_omap_alsa_prepare,
+ .trigger = snd_omap_alsa_trigger,
+ .pointer = snd_omap_alsa_pointer,
+};
+
+static snd_pcm_ops_t snd_card_omap_alsa_capture_ops = {
+ .open = snd_card_omap_alsa_open,
+ .close = snd_card_omap_alsa_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_alsa_hw_params,
+ .hw_free = snd_omap_alsa_hw_free,
+ .prepare = snd_omap_alsa_prepare,
+ .trigger = snd_omap_alsa_trigger,
+ .pointer = snd_omap_alsa_pointer,
+};
+
+/*
+ * Alsa init and exit section
+ *
+ * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
+static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec
+ *omap_alsa, int device)
+{
+ snd_pcm_t *pcm;
+ int err;
+ ADEBUG();
+
+ if ((err =
+ snd_pcm_new(omap_alsa->card, "AIC23 PCM", device, 1, 1,
+ &pcm)) < 0)
+ return err;
+
+ /* sets up initial buffer with continuous allocation */
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data
+ (GFP_KERNEL),
+ 128 * 1024, 128 * 1024);
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_card_omap_alsa_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_card_omap_alsa_capture_ops);
+ pcm->private_data = omap_alsa;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "omap aic23 pcm");
+
+ omap_alsa_audio_init(omap_alsa);
+
+ /* setup DMA controller */
+ audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
+ audio_dma_callback);
+ audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
+ audio_dma_callback);
+
+ omap_alsa->pcm = pcm;
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+static int snd_omap_alsa_suspend(snd_card_t * card, pm_message_t state)
+{
+ struct snd_card_omap_codec *chip = card->private_data;
+ ADEBUG();
+
+ if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ /* Mutes and turn clock off */
+ pdata->codec_clock_off();
+ snd_omap_suspend_mixer();
+ }
+
+ return 0;
+}
+
+/*
+ * Prepare hardware for resume
+ */
+static int snd_omap_alsa_resume(snd_card_t * card)
+{
+ struct snd_card_omap_codec *chip = card->private_data;
+ ADEBUG();
+
+ if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+ pdata->codec_clock_on();
+ snd_omap_resume_mixer();
+ }
+
+ return 0;
+}
+
+/*
+ * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
+ */
+static int omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+
+ if (card->power_state != SNDRV_CTL_POWER_D3hot) {
+ snd_omap_alsa_suspend(card, PMSG_SUSPEND);
+ }
+ return 0;
+}
+
+static int omap_alsa_resume(struct platform_device *pdev)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+
+ if (card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_omap_alsa_resume(card);
+ }
+ return 0;
+}
+
+#else
+#define snd_omap_alsa_suspend NULL
+#define snd_omap_alsa_resume NULL
+#define omap_alsa_suspend NULL
+#define omap_alsa_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*
+ */
+void snd_omap_alsa_free(snd_card_t * card)
+{
+ struct snd_card_omap_codec *chip = card->private_data;
+ ADEBUG();
+
+ /*
+ * Turn off codec after it is done.
+ * Can't do it immediately, since it may still have
+ * buffered data.
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2);
+
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+
+ //audio_aic23_write(RESET_CONTROL_ADDR, 0);
+ //audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0xff);
+
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+/* module init & exit */
+
+/*
+ * Inits alsa soudcard structure
+ */
+static int __init snd_omap_alsa_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ snd_card_t *card;
+ ADEBUG();
+
+ pdata = pdev->dev.platform_data;
+
+ if (pdata == NULL) {
+ err = -ENODEV;
+ goto nodev1;
+ }
+
+ pdata->codec_clock_setup();
+ pdata->codec_clock_on();
+
+ omap_mcbsp_request(AUDIO_MCBSP);
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_config(AUDIO_MCBSP, &pdata->mcbsp_regs);
+ omap_mcbsp_start(AUDIO_MCBSP);
+
+ if (pdata && pdata->codec_configure_dev) {
+ pdata->codec_configure_dev();
+ }
+
+ pdata->codec_clock_off();
+
+ /* register the soundcard */
+ card = snd_card_new(-1, id, THIS_MODULE, sizeof(omap_alsa));
+ if (card == NULL)
+ goto nodev2;
+
+ omap_alsa = kcalloc(1, sizeof(*omap_alsa), GFP_KERNEL);
+ if (omap_alsa == NULL)
+ goto nodev3;
+
+ card->private_data = (void *) omap_alsa;
+ card->private_free = snd_omap_alsa_free;
+
+ omap_alsa->card = card;
+ omap_alsa->samplerate = AUDIO_RATE_DEFAULT;
+
+ spin_lock_init(&omap_alsa->s[0].dma_lock);
+ spin_lock_init(&omap_alsa->s[1].dma_lock);
+
+ /* mixer */
+ //if ((err = snd_omap_mixer(omap_alsa)) < 0)
+ // goto nodev4;
+
+ /* PCM */
+ if ((err = snd_card_omap_alsa_pcm(omap_alsa, 0)) < 0)
+ goto nodev4;
+
+ //snd_card_set_pm_callback(card, snd_omap_alsa_suspend,
+ // snd_omap_alsa_resume, omap_alsa);
+
+ strcpy(card->driver, "AIC23");
+ strcpy(card->shortname, "OSK AIC23");
+ sprintf(card->longname, "OMAP OSK with AIC23");
+
+ //snd_omap_init_mixer(pdata);
+
+ snd_card_set_dev(card, &pdev->dev);
+
+ if ((err = snd_card_register(card)) == 0) {
+ printk(KERN_INFO "OSK audio support initialized\n");
+ platform_set_drvdata(pdev, card);
+ return 0;
+ }
+
+
+nodev4:
+ kfree(omap_alsa);
+nodev3:
+ snd_card_free(card);
+nodev2:
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+nodev1:
+ return err;
+}
+
+static int snd_omap_alsa_remove(struct platform_device *pdev)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+ struct snd_card_omap_codec *chip = card->private_data;
+
+ snd_card_free(card);
+
+ omap_alsa = NULL;
+ card->private_data = NULL;
+ kfree(chip);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+
+}
+
+static struct platform_driver omap_alsa_driver = {
+ .probe = snd_omap_alsa_probe,
+ .remove = snd_omap_alsa_remove,
+ .suspend = omap_alsa_suspend,
+ .resume = omap_alsa_resume,
+ .driver = {
+ .name = "omap_mcbsp",
+ },
+};
+
+static int __init omap_alsa_init(void)
+{
+ int err;
+ ADEBUG();
+
+ err = platform_driver_register(&omap_alsa_driver);
+
+ return err;
+}
+
+static void __exit omap_alsa_exit(void)
+{
+ ADEBUG();
+
+ platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_init);
+module_exit(omap_alsa_exit);
+
diff --git a/sound/arm/omap-alsa.h b/sound/arm/omap-alsa.h
new file mode 100644
index 0000000..7867736
--- /dev/null
+++ b/sound/arm/omap-alsa.h
@@ -0,0 +1,16 @@
+
+/*
+ * struct that contais codec audio control values and registers address
+ * to handle them (used by mixer)
+ */
+struct codec_controls {
+ u16 left_vol_output;
+ u16 right_vol_output;
+ u16 left_line_input;
+ u16 right_line_input;
+ u8 left_vol_address;
+ u8 right_vol_address;
+ u8 left_line_address;
+ u8 right_line_address;
+ u16 mic_input;
+} ;
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: omap alsa tsc2101 driver
2006-02-06 22:01 ` Daniel Petrini
@ 2006-02-07 12:43 ` lamikr
2006-02-07 14:34 ` Daniel Petrini
2006-02-07 16:19 ` Anderson Lizardo
0 siblings, 2 replies; 13+ messages in thread
From: lamikr @ 2006-02-07 12:43 UTC (permalink / raw)
To: Daniel Petrini; +Cc: linux-omap-open-source
>Yes, I am sending it right now (I have just updated my tree). Please
>note that it is really work in progress code, with remaining debug
>printks and so on. I will clean up soon.
>Try to make it work w/ your device, you will have to change the board*
>file accordingly H2 or osk in this patch.
>
>
Yes, I made the changes. I kind of liked from the idea to codec
aic/tsc2101 specific
functions in the board, but the side-effect is that I was not able to
build the driver anymore
as a module. (I got unresolved function errors in the end of build). But
when selecting to
build the driver in to image, it compiled just fine.
>Let me know if you can play sounds with this patch so that I will
>prepare it to receive your mixer then you can debug it
>
>
But unfortunately your version seemed to work in a similar way for me
than my one,--> I was able to hear only the beginning of song. The only
code difference for our h6300 board compared to h2/osk is the mcbsp
settings and they could be wrong.
But could they be wrong when with the OSS driver "cat song.wav >
/dev/dsp" works just fine with the same mcbsp settings...
Following questions comes to my mind:
Are you able to play all kind of wav/mp3 songs with your driver by using
aplay?
Any changes you could also test the playback with my driver version, it
could help me to identify the problem
if I know/not know whether that version works with h2 or osk.
I have found at least one difference in my and your driver versions is
that in set_samplerate function
you do not change all mcbsp registers by calling omap_mcbsp_config().
Instead you will only update
srgr1 and srgr2 by calling
OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR2, srgr2);
OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR1, srgr1);
Below is the debug from my attempt with your driver...
Mika
root@h6300:~# aplay 01_the_grudge.mp3
Playing raw data '01_the_grudge.mp3' : Unsigned 8 bit, Rate 8000 Hz, Mono
root@h6300:~# dmesg
=417792)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
checking if image is initramfs...it isn't (bad gzip magic numbers);
looks like an initrd
Freeing initrd memory: 2048K
NET: Registered protocol family 16
MUX: initialized UART3_TX
MUX: initialized UART3_RX
MUX: initialized F18_1610_KBC0
MUX: initialized D20_1610_KBC1
MUX: initialized D19_1610_KBC2
MUX: initialized E18_1610_KBC3
MUX: initialized C21_1610_KBC4
MUX: initialized G18_1610_KBR0
MUX: initialized F19_1610_KBR1
MUX: initialized H14_1610_KBR2
MUX: initialized E20_1610_KBR3
MUX: initialized E19_1610_KBR4
MUX: initialized N19_1610_KBR5
DMA support for OMAP15xx initialized
Initializing OMAP McBSP system
USB: hmc 0
MUX: initialized N14_1510_UWIRE_CS0
MUX: initialized P15_1510_UWIRE_CS3
usbcore: registered new driver usbfs
usbcore: registered new driver hub
Power Management for TI OMAP.
NetWinder Floating Point Emulator V0.97 (extended precision)
OMAP DSP driver initialization
omapdsp: mapping in ARM MMU, v=0xe0fff000, p=0x10ab4000, sz=0x1000
JFFS version 1.0, (C) 1999, 2000 Axis Communications AB
JFFS2 version 2.2. (NAND) (C) 2001-2003 Red Hat, Inc.
Allocated 270656 bytes for deflate workspace
Allocated 46912 bytes for inflate workspace
Registering JFFS2 compressor "zlib"
Compressor "zlib", prio 60
Registering JFFS2 compressor "rtime"
Compressor "zlib", prio 60
Compressor "rtime", prio 50
Registering JFFS2 compressor "rubinmips"
Compressor "zlib", prio 60
Compressor "rtime", prio 50
Compressor "rubinmips", prio 10
Registering JFFS2 compressor "dynrubin"
Compressor "zlib", prio 60
Compressor "rtime", prio 50
Compressor "dynrubin", prio 20
Compressor "rubinmips", prio 10
JFFS2: default compression mode: priority
Initializing Cryptographic API
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered
omapfb: configured for panel h6300
lcd_h6300.c: h6300_panel_init() done
omapfb-lcdc: init
lcd_h6300.c: h6300_panel_enable() done
Console: switching to colour frame buffer device 60x53
omapfb: initialized vram=153600 pixclock 21000 kHz hfreq 77.8 kHz vfreq
229.7 HzOMAP RTC Driver
omap_rtc: RTC already running.
Non-volatile memory driver v1.2
Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0xfffb0000 (irq = 46) is a ST16654
serial8250.0: ttyS1 at MMIO 0xfffb0800 (irq = 47) is a ST16654
serial8250.0: ttyS2 at MMIO 0xfffb9800 (irq = 15) is a ST16654
RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize
loop: loaded (max 8 devices)
PPP generic driver version 2.4.2
PPP Deflate Compression module registered
PPP BSD Compression module registered
NET: Registered protocol family 24
STRIP: Version 1.3A-STUART.CHESHIRE (unlimited channels)
usbmon: debugfs is not available
ohci_hcd: 2005 April 22 USB 1.1 'Open' Host Controller (OHCI) Driver (OMAP)
ohci_hcd: block sizes: ed 64 td 64
usbcore: registered new driver cdc_acm
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/class/cdc-acm.c:
v0.25:USB Abstract Control Model driver for USB modems and ISDN adapters
usbcore: registered new driver asix
usbcore: registered new driver cdc_ether
usbcore: registered new driver net1080
usbcore: registered new driver zaurus
usbcore: registered new driver usbserial
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/serial/usb-serial.c:
USB Serial support registered for generic
usbcore: registered new driver usbserial_generic
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/serial/usb-serial.c:
USB Serial Driver core
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/serial/usb-serial.c:
USB Serial support registered for PocketPC PDA
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/serial/ipaq.c:
USB PocketPC PDA driver v0.5
usbcore: registered new driver ipaq
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/serial/usb-serial.c:
USB Serial support registered for Handspring Visor / Palm OS
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/serial/usb-serial.c:
USB Serial support registered for Sony Clie 3.5
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/serial/usb-serial.c:
USB Serial support registered for Sony Clie 5.0
usbcore: registered new driver visor
/home/lamikr/own/h6300/eclipsewk/h6300_dev/drivers/usb/serial/visor.c:
USB HandSpring Visor / Palm OS driver
udc: OMAP UDC driver, version: 4 October 2004 (iso)
udc: OMAP UDC rev 2.7
udc: hmc mode 0, (unknown) transceiver
udc: fifo mode 3, 648 bytes not used
usb0: Ethernet Gadget, version: May Day 2005
usb0: using omap_udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int
usb0: MAC b2:e5:68:a6:39:c9
usb0: HOST MAC b2:58:90:b3:b8:66
ts: Compaq touchscreen protocol output
Advanced Linux Sound Architecture Driver Version 1.0.11rc2 (Wed Jan 04
08:57:20 2006 UTC).
WR: ad:0x5 data:0x0
WR: ad:0x3 data:0xc010
udc: USB reset done, gadget ether
WR: ad:0x3 data:0xc010
WR: ad:0x1d data:0x0
WR: ad:0x2 data:0x0
WR: ad:0x20 data:0x75d1
usb0: full speed config #1: 100 mA, Ethernet Gadget, using CDC Ethernet
WR: ad:0x21 data:0xf0
WR: ad:0x22 data:0x0
WR: ad:0x1 data:0x1900
WR: ad:0x1e data:0x1900
WR: ad:0x2 data:0x3e3e
WR: ad:0x0 data:0x4100
WR: ad:0x6 data:0x2904
WR: ad:0x1b data:0x811c
WR: ad:0x1c data:0x5240
TESTE 2
OSK audio support initialized
ALSA device list:
#0: OMAP OSK with AIC23
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 2, 16384 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
TCP bic registered
Initializing IPsec netlink socket
NET: Registered protocol family 1
NET: Registered protocol family 10
lo: Disabled Privacy Extensions
IPv6 over IPv4 tunneling driver
NET: Registered protocol family 17
mmcblk0: mmc0:0001 SDR256 250816KiB
mmcblk0: p1 p2
Bridge firewalling registered
IP-Config: Complete:
device=usb0, addr=192.168.2.2, mask=255.0.0.0, gw=192.168.2.1,
host=h6300, domain=, nis-domain=(none),
bootserver=192.168.2.1, rootserver=192.168.2.1, rootpath=
Looking up port of RPC 100003/2 on 192.168.2.1
Looking up port of RPC 100005/1 on 192.168.2.1
VFS: Mounted root (nfs filesystem).
Freeing init memory: 120K
usb0: no IPv6 routers present
MUX: initialized M14_1510_GPIO2
input: omap_ts as /class/input/input0
OMAP touchscreen driver initialized
i2c_omap i2c_omap.1: bus 0 rev1.0 at 100 kHz
pca9535_attach() started
pca9535_attach() ok
OMAP Keypad Driver
omap-keypad: Spurious key event 0-5
omap-keypad: Spurious key event 1-5
omap-keypad: Spurious key event 2-5
omap-keypad: Spurious key event 3-5
omap-keypad: Spurious key event 4-5
omap-keypad: Spurious key event 5-5
omap-keypad: Spurious key event 6-5
omap-keypad: Spurious key event 7-5
input: omap-keypad as /class/input/input1
Bluetooth: Core ver 2.8
NET: Registered protocol family 31
Bluetooth: HCI device and connection manager initialized
Bluetooth: HCI socket layer initialized
Bluetooth: HCI UART driver ver 2.2
Bluetooth: HCI H4 protocol initialized
Bluetooth: HCI BCSP protocol initialized
Bluetooth: L2CAP ver 2.8
Bluetooth: L2CAP socket layer initialized
h6300 Bluetooth Driver init()
h6300_bt_led.c h6300_clear_led() done
h6300_bt_brf6100.c h6300_bt_probe() done
NET: Registered protocol family 23
Bluetooth: HIDP (Human Interface Emulation) ver 1.1
Bluetooth: RFCOMM socket layer initialized
Bluetooth: RFCOMM TTY layer initialized
Bluetooth: RFCOMM ver 1.6
WR: ad:0x0 data:0x413f
WR: ad:0x6 data:0x804
WR: ad:0x1b data:0x8120
WR: ad:0x1c data:0x1e00
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: omap alsa tsc2101 driver
2006-02-07 12:43 ` lamikr
@ 2006-02-07 14:34 ` Daniel Petrini
2006-02-07 20:40 ` lamikr
2006-02-07 16:19 ` Anderson Lizardo
1 sibling, 1 reply; 13+ messages in thread
From: Daniel Petrini @ 2006-02-07 14:34 UTC (permalink / raw)
To: lamikr; +Cc: linux-omap-open-source
Hi,
On 2/7/06, lamikr <lamikr@cc.jyu.fi> wrote:
>
> >Yes, I am sending it right now (I have just updated my tree). Please
> >note that it is really work in progress code, with remaining debug
> >printks and so on. I will clean up soon.
> >Try to make it work w/ your device, you will have to change the board*
> >file accordingly H2 or osk in this patch.
> >
> >
> Yes, I made the changes. I kind of liked from the idea to codec
> aic/tsc2101 specific
> functions in the board, but the side-effect is that I was not able to
> build the driver anymore
> as a module. (I got unresolved function errors in the end of build). But
> when selecting to
> build the driver in to image, it compiled just fine.
That will be fixed. The idea to have separeted file for alsa generic
and codecs is that you can work or improve diferent parts of the
driver indenpendently. And of course reuse code.
> >Let me know if you can play sounds with this patch so that I will
> >prepare it to receive your mixer then you can debug it
> >
> >
> But unfortunately your version seemed to work in a similar way for me
> than my one,--> I was able to hear only the beginning of song. The only
> code difference for our h6300 board compared to h2/osk is the mcbsp
> settings and they could be wrong.
Humm, Maybe the problems dwells in this function:
omap_get_dma_src_addr_counter
(called in alsa-omap driver core file) Please try to analyse its
behavior for omap1510, the idea is to get the current position of a
dma transfer. Maybe the registers are diferent in 1510 which has
different dma engine.
> But could they be wrong when with the OSS driver "cat song.wav >
> /dev/dsp" works just fine with the same mcbsp settings...
>
> Following questions comes to my mind:
> Are you able to play all kind of wav/mp3 songs with your driver by using
> aplay?
Yeah. I can play them. In most of the frequencies although I use
madplay for mp3.
> Any changes you could also test the playback with my driver version, it
> could help me to identify the problem
I compiled but I can not play yet, I think that my alsa programs are
old in my rootfs. I compile them as modules or integrated without
success. I will update my rfs.
It says: alsactl: load_state:1236: No soundcards found...
After I make it run I give you a feedback.
> if I know/not know whether that version works with h2 or osk.
> I have found at least one difference in my and your driver versions is
> that in set_samplerate function
> you do not change all mcbsp registers by calling omap_mcbsp_config().
> Instead you will only update
> srgr1 and srgr2 by calling
>
> OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR2, srgr2);
> OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR1, srgr1);
This means no difference. It is just to avoid callings to mcbsp
function explicitly.
> Below is the debug from my attempt with your driver...
>
> Mika
>
> root@h6300:~# aplay 01_the_grudge.mp3
> Playing raw data '01_the_grudge.mp3' : Unsigned 8 bit, Rate 8000 Hz, Mono
The support for 8Khz is not ok yet although I think that you have
tested for other frequencies. I can see in the remaining of the debug
that it seems ok. Maybe the problem is in that function pointed above.
Daniel
--
INdT - Manaus - Brazil
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: omap alsa tsc2101 driver
2006-02-07 14:34 ` Daniel Petrini
@ 2006-02-07 20:40 ` lamikr
2006-02-07 22:29 ` Daniel Petrini
0 siblings, 1 reply; 13+ messages in thread
From: lamikr @ 2006-02-07 20:40 UTC (permalink / raw)
To: Daniel Petrini; +Cc: linux-omap-open-source
Daniel Petrini wrote:
>Hi,
>
>On 2/7/06, lamikr <lamikr@cc.jyu.fi> wrote:
>
>
>>>Yes, I am sending it right now (I have just updated my tree). Please
>>>note that it is really work in progress code, with remaining debug
>>>printks and so on. I will clean up soon.
>>>Try to make it work w/ your device, you will have to change the board*
>>>file accordingly H2 or osk in this patch.
>>>
>>>
>>>
>>>
>>Yes, I made the changes. I kind of liked from the idea to codec
>>aic/tsc2101 specific
>>functions in the board, but the side-effect is that I was not able to
>>build the driver anymore
>>as a module. (I got unresolved function errors in the end of build). But
>>when selecting to
>>build the driver in to image, it compiled just fine.
>>
>>
>
>That will be fixed. The idea to have separeted file for alsa generic
>and codecs is that you can work or improve diferent parts of the
>driver indenpendently. And of course reuse code.
>
>
Yes, that seems to be very doable. In my driver I just planned to take
the tsc2101 code
totally separately until I can get it somehow working.
>Humm, Maybe the problems dwells in this function:
>omap_get_dma_src_addr_counter
> (called in alsa-omap driver core file) Please try to analyse its
>behavior for omap1510, the idea is to get the current position of a
>dma transfer. Maybe the registers are diferent in 1510 which has
>different dma engine.
>
>
Thanks for the idea, I will try to investigate it later on today. I just
checked
that the OSS code is not relying to omap_get_dma_src_addr_counter()
function at all
so that might explain the reason why the oss version works for me.
>>Any changes you could also test the playback with my driver version, it
>>could help me to identify the problem
>>
>>
>
>I compiled but I can not play yet, I think that my alsa programs are
>old in my rootfs. I compile them as modules or integrated without
>success. I will update my rfs.
>It says: alsactl: load_state:1236: No soundcards found...
>After I make it run I give you a feedback.
>
>
Hmm, did you remember to change the board code, to register the driver?
I use here:
static struct platform_device h6300_mcbsp1_device = {
.name = "omap_tsc2101_mcbsp",
.id = 1,
};
static struct platform_device *h6300_devices[] __initdata = {
&h6300_mcbsp1_device,
};
If the driver loads correctly, you should be able to use alsamixer with
recent alsa utils.
The version I have tested here is from alsa 1.0.9. In addition you can
turn the debug on from omap-alsa.h
>>Below is the debug from my attempt with your driver...
>>
>>Mika
>>
>>root@h6300:~# aplay 01_the_grudge.mp3
>>Playing raw data '01_the_grudge.mp3' : Unsigned 8 bit, Rate 8000 Hz, Mono
>>
>>
>
>The support for 8Khz is not ok yet although I think that you have
>tested for other frequencies. I can see in the remaining of the debug
>that it seems ok. Maybe the problem is in that function pointed above.
>
>
With speaker-test I have used many frequencies but from wav-files I only
tested
"Signed 16 bit Little Indian with 44100 hz". The madplay I have here
requires me to modprobe
snd-pcm-oss OSS compatibility module.
Mika
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: omap alsa tsc2101 driver
2006-02-07 20:40 ` lamikr
@ 2006-02-07 22:29 ` Daniel Petrini
2006-02-07 23:05 ` lamikr
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Daniel Petrini @ 2006-02-07 22:29 UTC (permalink / raw)
To: lamikr; +Cc: linux-omap-open-source
Hi Mika,
On 2/7/06, lamikr <lamikr@cc.jyu.fi> wrote:
> Daniel Petrini wrote:
>
> >Hi,
> >
> >On 2/7/06, lamikr <lamikr@cc.jyu.fi> wrote:
> >
> >
(...)
>
> >Humm, Maybe the problems dwells in this function:
> >omap_get_dma_src_addr_counter
> > (called in alsa-omap driver core file) Please try to analyse its
> >behavior for omap1510, the idea is to get the current position of a
> >dma transfer. Maybe the registers are diferent in 1510 which has
> >different dma engine.
> >
> >
> Thanks for the idea, I will try to investigate it later on today. I just
> checked
> that the OSS code is not relying to omap_get_dma_src_addr_counter()
> function at all
> so that might explain the reason why the oss version works for me.
I guess that the answer might come from there.
> >>Any changes you could also test the playback with my driver version, it
> >>could help me to identify the problem
> >>
> >>
> >
> >I compiled but I can not play yet, I think that my alsa programs are
> >old in my rootfs. I compile them as modules or integrated without
> >success. I will update my rfs.
> >It says: alsactl: load_state:1236: No soundcards found...
> >After I make it run I give you a feedback.
> >
> >
> Hmm, did you remember to change the board code, to register the driver?
> I use here:
> static struct platform_device h6300_mcbsp1_device = {
> .name = "omap_tsc2101_mcbsp",
> .id = 1,
> };
>
> static struct platform_device *h6300_devices[] __initdata = {
> &h6300_mcbsp1_device,
> };
>
ok. It has worked with that. The song played fine in H2.
Cheers,
Daniel
--
INdT - Manaus - Brazil
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: omap alsa tsc2101 driver
2006-02-07 22:29 ` Daniel Petrini
@ 2006-02-07 23:05 ` lamikr
2006-02-07 23:16 ` lamikr
2006-02-08 12:59 ` lamikr
2 siblings, 0 replies; 13+ messages in thread
From: lamikr @ 2006-02-07 23:05 UTC (permalink / raw)
To: Daniel Petrini; +Cc: linux-omap-open-source
Daniel
Thanks for help and info! So now I at least know that it is propably
something h6300 specific. That makes it hard for me to help with the
alsa driver... One more thing, could you enable debug (omap-alsa.h) and
send the dmesg output of "aplay reggae80e.wav" for me?
I just downloaded that wav myself from
http://www.breakbeatsonly.co.uk/demos/december03/reggae80e.wav
and got following log.
<setMixerVolumeAsHeadsetGainControlVolume>: mixer volume = 20
<setMixerVolumeAsHeadsetGainControlVolume>: to registry = 6400
<setMixerVolumeAsHandsetGainControlVolume>: mixer volume = 20
<setMixerVolumeAsHandsetGainControlVolume>: to registry = 6400
<setMixerVolumeAsDacGainControlVolume>: mixer volume left = 93, right = 93
<setMixerVolumeAsDacGainControlVolume>: to registry: left = 6, right =
6, total = 1542
[snd_omap_init_mixer]: end(0)
XXX Alsa debug f:snd_card_omap_alsa_tsc2101_pcm, l:888
XXX Alsa debug f:omap_alsa_tsc2101_audio_init, l:367
XXX Alsa debug f:audio_dma_request, l:393
[omap_request_alsa_sound_dma]: start
[omap_request_alsa_sound_dma]: end(0)
XXX Alsa debug f:audio_dma_request, l:393
[omap_request_alsa_sound_dma]: start
[omap_request_alsa_sound_dma]: end(0)
OMAP_ALSA_TSC2101 audio support initialized
<snd_card_omap_alsa_tsc2101_open>: runtime->hw =
snd_omap_alsa_tsc2101_playback
<snd_omap_alsa_tsc2101_hw_params>: snd_omap_alsa_tsc2101_hw_params(),
size = 131072
XXX Alsa debug f:snd_omap_alsa_tsc2101_prepare, l:729
XXX Alsa debug f:omap_alsa_tsc2101_set_samplerate, l:263
<omap_alsa_tsc2101_set_samplerate>: selected 44.1khz PLL
<snd_omap_alsa_tsc2101_trigger>: cmd = 1
<audio_process_dma>: started, offset = 0, dma_size = 8192, s->period =
0, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1024983040
[omap_start_alsa_sound_dma]: start
<omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
-1024983040, dma_size = 8192
[audio_set_dma_params_play]: start
[audio_set_dma_params_play]: end(0)
[audio_start_dma_chain]: start
XXX Alsa debug f:audio_ifc_stop, l:244
XXX Alsa debug f:audio_ifc_start, l:237
[audio_start_dma_chain]: end(0)
[omap_start_alsa_sound_dma]: end(0)
<audio_process_dma>: done, offset = 0, dma_size = 8192, s->period = 0,
s->periods = 1, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1024983040
<sound_dma_irq_handler>: started, lch = 0, status = 0x20, dma_status =
32, data = c0b4bd4c
<sound_dma_irq_handler>: status = DCSR_END_BLOCK, calling
audio_dma_callback()
<audio_dma_callback>: s->active, calling snd_pcm_period_elapsed
[audio_get_dma_pos]: start
audio_get_dma_pos(), offset = 0, srcPos = -1024983040, dmaAddr = -1024983040
[audio_get_dma_pos]: end(0)
<audio_process_dma>: started, offset = 8192, dma_size = 8192, s->period
= 1, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1024974848
[omap_start_alsa_sound_dma]: start
<omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
-1024974848, dma_size = 8192
[audio_set_dma_params_play]: start
[audio_set_dma_params_play]: end(0)
[audio_start_dma_chain]: start
[audio_start_dma_chain]: end(0)
[omap_start_alsa_sound_dma]: end(0)
<audio_process_dma>: done, offset = 8192, dma_size = 8192, s->period =
1, s->periods = 1, s->dma_q_head = 0, s->offset = 8192, rt->buffer_size
= 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr
= 0, dma_ptr = -1024974848
<sound_dma_irq_handler>: done
[audio_get_dma_pos]: start
audio_get_dma_pos(), offset = 2048, srcPos = -1024974848, dmaAddr =
-1024983040
[audio_get_dma_pos]: end(2048)
[audio_get_dma_pos]: start
audio_get_dma_pos(), offset = 2048, srcPos = -1024974848, dmaAddr =
-1024983040
[audio_get_dma_pos]: end(2048)
ALSA
/home/lamikr/own/h6300/eclipsewk/h6300_dev/sound/core/pcm_lib.c:2231:
playback write error (DMA or IRQ trouble?)
<snd_omap_alsa_tsc2101_trigger>: cmd = 0
XXX Alsa debug f:audio_stop_dma, l:531
[omap_alsa_audio_stop_dma]: start
[omap_alsa_audio_stop_dma]: end(0)
[omap_clear_alsa_sound_dma]: start
[omap_clear_alsa_sound_dma]: end(0)
XXX Alsa debug f:snd_card_omap_alsa_tsc2101_close, l:828
<snd_card_omap_alsa_tsc2101_open>: runtime->hw =
snd_omap_alsa_tsc2101_playback
<snd_omap_alsa_tsc2101_hw_params>: snd_omap_alsa_tsc2101_hw_params(),
size = 131072
XXX Alsa debug f:snd_omap_alsa_tsc2101_prepare, l:729
XXX Alsa debug f:omap_alsa_tsc2101_set_samplerate, l:263
<omap_alsa_tsc2101_set_samplerate>: selected 44.1khz PLL
<snd_omap_alsa_tsc2101_trigger>: cmd = 1
<audio_process_dma>: started, offset = 0, dma_size = 8192, s->period =
0, s->periods = 0, s->dma_q_head = 0, s->offset = 8192, rt->buffer_size
= 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr
= 0, dma_ptr = -1024983040
[omap_start_alsa_sound_dma]: start
<omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
-1024983040, dma_size = 8192
[audio_set_dma_params_play]: start
[audio_set_dma_params_play]: end(0)
[audio_start_dma_chain]: start
XXX Alsa debug f:audio_ifc_stop, l:244
XXX Alsa debug f:audio_ifc_start, l:237
[audio_start_dma_chain]: end(0)
[omap_start_alsa_sound_dma]: end(0)
<audio_process_dma>: done, offset = 0, dma_size = 8192, s->period = 0,
s->periods = 1, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1024983040
<sound_dma_irq_handler>: started, lch = 0, status = 0x20, dma_status =
32, data = c0b4bd4c
<sound_dma_irq_handler>: status = DCSR_END_BLOCK, calling
audio_dma_callback()
<audio_dma_callback>: s->active, calling snd_pcm_period_elapsed
[audio_get_dma_pos]: start
audio_get_dma_pos(), offset = 0, srcPos = -1024983040, dmaAddr = -1024983040
[audio_get_dma_pos]: end(0)
<audio_process_dma>: started, offset = 8192, dma_size = 8192, s->period
= 1, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1024974848
[omap_start_alsa_sound_dma]: start
<omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
-1024974848, dma_size = 8192
[audio_set_dma_params_play]: start
[audio_set_dma_params_play]: end(0)
[audio_start_dma_chain]: start
[audio_start_dma_chain]: end(0)
[omap_start_alsa_sound_dma]: end(0)
<audio_process_dma>: done, offset = 8192, dma_size = 8192, s->period =
1, s->periods = 1, s->dma_q_head = 0, s->offset = 8192, rt->buffer_size
= 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr
= 0, dma_ptr = -1024974848
<sound_dma_irq_handler>: done
[audio_get_dma_pos]: start
audio_get_dma_pos(), offset = 2048, srcPos = -1024974848, dmaAddr =
-1024983040
[audio_get_dma_pos]: end(2048)
[audio_get_dma_pos]: start
audio_get_dma_pos(), offset = 2048, srcPos = -1024974848, dmaAddr =
-1024983040
[audio_get_dma_pos]: end(2048)
ALSA
/home/lamikr/own/h6300/eclipsewk/h6300_dev/sound/core/pcm_lib.c:2231:
playback write error (DMA or IRQ trouble?)
<snd_omap_alsa_tsc2101_trigger>: cmd = 0
XXX Alsa debug f:audio_stop_dma, l:531
[omap_alsa_audio_stop_dma]: start
[omap_alsa_audio_stop_dma]: end(0)
[omap_clear_alsa_sound_dma]: start
[omap_clear_alsa_sound_dma]: end(0)
XXX Alsa debug f:snd_card_omap_alsa_tsc2101_close, l:828
Mika
>ok. It has worked with that. The song played fine in H2.
>
>
>Cheers,
>
>Daniel
>--
>INdT - Manaus - Brazil
>
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: omap alsa tsc2101 driver
2006-02-07 22:29 ` Daniel Petrini
2006-02-07 23:05 ` lamikr
@ 2006-02-07 23:16 ` lamikr
2006-02-08 12:59 ` lamikr
2 siblings, 0 replies; 13+ messages in thread
From: lamikr @ 2006-02-07 23:16 UTC (permalink / raw)
To: Daniel Petrini; +Cc: linux-omap-open-source
Sorry, I send wrong log by myself. Here is the correct one...
<setMixerVolumeAsHeadsetGainControlVolume>: mixer volume = 20
<setMixerVolumeAsHeadsetGainControlVolume>: to registry = 6400
<setMixerVolumeAsHandsetGainControlVolume>: mixer volume = 20
<setMixerVolumeAsHandsetGainControlVolume>: to registry = 6400
<setMixerVolumeAsDacGainControlVolume>: mixer volume left = 93, right = 93
<setMixerVolumeAsDacGainControlVolume>: to registry: left = 6, right =
6, total = 1542
[snd_omap_init_mixer]: end(0)
XXX Alsa debug f:snd_card_omap_alsa_tsc2101_pcm, l:853
XXX Alsa debug f:omap_alsa_tsc2101_audio_init, l:367
XXX Alsa debug f:audio_dma_request, l:393
[omap_request_alsa_sound_dma]: start
[omap_request_alsa_sound_dma]: end(0)
XXX Alsa debug f:audio_dma_request, l:393
[omap_request_alsa_sound_dma]: start
[omap_request_alsa_sound_dma]: end(0)
OMAP_ALSA_TSC2101 audio support initialized
<snd_card_omap_alsa_tsc2101_open>: runtime->hw =
snd_omap_alsa_tsc2101_playback
<snd_omap_alsa_tsc2101_hw_params>: snd_omap_alsa_tsc2101_hw_params(),
size = 131072
XXX Alsa debug f:snd_omap_alsa_tsc2101_prepare, l:694
XXX Alsa debug f:omap_alsa_tsc2101_set_samplerate, l:263
<omap_alsa_tsc2101_set_samplerate>: selected 44.1khz PLL
<snd_omap_alsa_tsc2101_trigger>: cmd = 1
<audio_process_dma>: started, offset = 0, dma_size = 8192, s->period =
0, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1024065536
[omap_start_alsa_sound_dma]: start
<omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
-1024065536, dma_size = 8192
[audio_set_dma_params_play]: start
[audio_set_dma_params_play]: end(0)
[audio_start_dma_chain]: start
XXX Alsa debug f:audio_ifc_stop, l:244
XXX Alsa debug f:audio_ifc_start, l:237
[audio_start_dma_chain]: end(0)
[omap_start_alsa_sound_dma]: end(0)
<audio_process_dma>: done, offset = 0, dma_size = 8192, s->period = 0,
s->periods = 1, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1024065536
<sound_dma_irq_handler>: started, lch = 0, status = 0x20, dma_status =
32, data = c0b4b80c
<sound_dma_irq_handler>: status = DCSR_END_BLOCK, calling
audio_dma_callback()
<audio_dma_callback>: s->active, calling snd_pcm_period_elapsed
<audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 0,
s->period = 1, s->periods = 1, rt->buffer_size = 32768, rt->period_size
= 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = -1537,
dma_ptr = -1024067073
<audio_get_dma_pos>: offsetFrame= 0, countFrame = 1537
<audio_get_dma_pos>: warning, resetted offset to 0, old offset val = 0
<audio_process_dma>: started, offset = 8192, dma_size = 8192, s->period
= 1, s->periods = 0, s->dma_q_head = 0, s->offset = 0, rt->buffer_size =
32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr =
0, dma_ptr = -1024057344
[omap_start_alsa_sound_dma]: start
<omap_start_alsa_sound_dma>: stream_id = playback, dma_ptr =
-1024057344, dma_size = 8192
[audio_set_dma_params_play]: start
[audio_set_dma_params_play]: end(0)
[audio_start_dma_chain]: start
[audio_start_dma_chain]: end(0)
[omap_start_alsa_sound_dma]: end(0)
<audio_process_dma>: done, offset = 8192, dma_size = 8192, s->period =
1, s->periods = 1, s->dma_q_head = 0, s->offset = 8192, rt->buffer_size
= 32768, rt->period_size = 2048, rt->frame_bits = 32, runtime->dma_addr
= 0, dma_ptr = -1024057344
<sound_dma_irq_handler>: done
<audio_get_dma_pos>: count = 6150, s->dma_q_head = 0, s->offset = 8192,
s->period = 2, s->periods = 1, rt->buffer_size = 32768, rt->period_size
= 2048, rt->frame_bits = 32, runtime->dma_addr = 0, offset = 511,
dma_ptr = -1024065025
<audio_get_dma_pos>: offsetFrame= 2048, countFrame = 1537
ALSA
/home/lamikr/own/h6300/eclipsewk/h6300_dev/sound/core/pcm_lib.c:2231:
playback write error (DMA or IRQ trouble?)
<snd_omap_alsa_tsc2101_trigger>: cmd = 0
XXX Alsa debug f:audio_stop_dma, l:496
[omap_alsa_audio_stop_dma]: start
[omap_alsa_audio_stop_dma]: end(0)
[omap_clear_alsa_sound_dma]: start
[omap_clear_alsa_sound_dma]: end(0)
XXX Alsa debug f:snd_card_omap_alsa_tsc2101_close, l:793
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: omap alsa tsc2101 driver
2006-02-07 22:29 ` Daniel Petrini
2006-02-07 23:05 ` lamikr
2006-02-07 23:16 ` lamikr
@ 2006-02-08 12:59 ` lamikr
2 siblings, 0 replies; 13+ messages in thread
From: lamikr @ 2006-02-08 12:59 UTC (permalink / raw)
To: Daniel Petrini; +Cc: linux-omap-open-source
I got my driver version working also with h6300/1510! But the solution
is not perfect and I do not yet understand why it helped.
I did not made any changes to audio_dma_get_pos() method. Instead I just
added dma_close to audio_process_dma() method
before each dma_start call and that forces the DMA to somehow trigger
irq_handler more oftern.
*diff -Naur h6300_dev_old/sound/arm/omap/omap-alsa-tsc2101.c h6300_dev_working/sound/arm/omap/omap-alsa-tsc2101.c*
*--- h6300_dev_old/sound/arm/omap/omap-alsa-tsc2101.c 2006-02-06 15:36:21.000000000 +0200*
*+++ h6300_dev_working/sound/arm/omap/omap-alsa-tsc2101.c 2006-02-08 14:37:27.000000000 +0200*
@@ -508,6 +508,7 @@
int period;
unsigned int dma_size;
unsigned int offset;
+ unsigned long flags;
int ret;
runtime = substream->runtime;
@@ -528,6 +529,11 @@
runtime->frame_bits,
runtime->dma_addr,
(dma_addr_t)runtime->dma_area + offset);
+#ifdef CONFIG_MACH_OMAP_H6300
+ spin_lock_irqsave(&s->dma_lock, flags);
+ omap_alsa_audio_stop_dma(s);
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+#endif
ret = omap_start_alsa_sound_dma(s,
(dma_addr_t)runtime->dma_area + offset,
dma_size);
Now I need to figure out why this fixed the problem and what would be a
smarter solution for this.
In addition I can hear that 41000 hz sound is still not played with full
speed. (Maybe 1/2 speed is more correct...)
Mika
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: omap alsa tsc2101 driver
2006-02-07 12:43 ` lamikr
2006-02-07 14:34 ` Daniel Petrini
@ 2006-02-07 16:19 ` Anderson Lizardo
2006-02-07 20:43 ` lamikr
1 sibling, 1 reply; 13+ messages in thread
From: Anderson Lizardo @ 2006-02-07 16:19 UTC (permalink / raw)
To: lamikr; +Cc: linux-omap-open-source
On 2/7/06, lamikr <lamikr@cc.jyu.fi> wrote:
> root@h6300:~# aplay 01_the_grudge.mp3
> Playing raw data '01_the_grudge.mp3' : Unsigned 8 bit, Rate 8000 Hz, Mono
AFAIK, aplay is not able to play MP3 files directly. try to convert
the file to WAV or use madplay.
Regards,
--
Anderson Lizardo
Embedded Linux Lab - 10LE
Nokia Institute of Technology - INdT
Manaus - Brazil
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: omap alsa tsc2101 driver
2006-02-07 16:19 ` Anderson Lizardo
@ 2006-02-07 20:43 ` lamikr
0 siblings, 0 replies; 13+ messages in thread
From: lamikr @ 2006-02-07 20:43 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: linux-omap-open-source
>>Playing raw data '01_the_grudge.mp3' : Unsigned 8 bit, Rate 8000 Hz, Mono
>>
>>
>
>AFAIK, aplay is not able to play MP3 files directly. try to convert
>the file to WAV or use madplay.
>
That was actually a good point I have not realized earlier!
I have however also tested with the "Signed 16 bit little endian wavs
using 44100 hz" with same results.
Mika
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2006-02-08 12:59 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-02-05 21:24 omap alsa tsc2101 driver lamikr
2006-02-06 19:13 ` Daniel Petrini
2006-02-06 20:17 ` lamikr
2006-02-06 22:01 ` Daniel Petrini
2006-02-07 12:43 ` lamikr
2006-02-07 14:34 ` Daniel Petrini
2006-02-07 20:40 ` lamikr
2006-02-07 22:29 ` Daniel Petrini
2006-02-07 23:05 ` lamikr
2006-02-07 23:16 ` lamikr
2006-02-08 12:59 ` lamikr
2006-02-07 16:19 ` Anderson Lizardo
2006-02-07 20:43 ` lamikr
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox