[Armadeus-commitlog] SF.net SVN: armadeus:[1015] branches/tsc210x/buildroot/target/device/ armadeu
Brought to you by:
sszy
Revision: 1015
http://armadeus.svn.sourceforge.net/armadeus/?rev=1015&view=rev
Author: artemys
Date: 2009-01-14 12:59:57 +0000 (Wed, 14 Jan 2009)
Log Message:
-----------
[TSC BRANCH] [LINUX] Makes alsa pcm driver independent of i.MXL (at least try to) + makes it use DMA scatter-gather + removes i.MX dependancies in TSC mixer
Modified Paths:
--------------
branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-091-armadeus-alsa-add_imx_ssi_tsc2102_driver.patch
Modified: branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-091-armadeus-alsa-add_imx_ssi_tsc2102_driver.patch
===================================================================
--- branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-091-armadeus-alsa-add_imx_ssi_tsc2102_driver.patch 2009-01-14 09:37:05 UTC (rev 1014)
+++ branches/tsc210x/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-091-armadeus-alsa-add_imx_ssi_tsc2102_driver.patch 2009-01-14 12:59:57 UTC (rev 1015)
@@ -3,7 +3,7 @@
(Take a look at armadeus/target/linux/ directory to know how to generate it)
--- linux-2.6.27.2.original/sound/arm/imx-alsa.c
+++ linux-2.6.27.2.mod/sound/arm/imx-alsa.c
-@@ -0,0 +1,683 @@
+@@ -0,0 +1,658 @@
+/*
+ * sound/arm/imx-alsa.c
+ *
@@ -34,138 +34,134 @@
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
++#define DEBUG
+
+#include <linux/platform_device.h>
-+#include <linux/spi/tsc2102.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+#include <sound/core.h>
+#include <sound/pcm.h>
++#include <sound/pcm_params.h>
+
+#include <mach/imx-alsa.h>
+#include <linux/dma-mapping.h>
++
++#ifdef CONFIG_ARCH_MX2
++#include <mach/dma-mx1-mx2.h>
++#else
+#include <mach/imx-dma.h>
++#include "imx-ssi.h"
++#endif
+
++#include "devdma.h"
++
++#define DRIVER_NAME "imx-alsa"
+#define TSC_MASTER
+
-+#define TRANSMIT_WM_LEVEL 8 // (in free places)
-+#define SSI_DMA_BLR_TRANSMIT 16 // (3*2) // DMA Burst Length (in bytes)
++#define SSI_DMA_BLR_TRANSMIT 16 /* (3*2) DMA Burst Length (in bytes) */
+#define SSI_DMA_BLR 8
+
+MODULE_AUTHOR("Nicolas Colombain / Julien Boibessot - Armadeus Systems");
+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("i.MX1/L driver for ALSA");
++MODULE_DESCRIPTION("i.MX1/L PCM driver for ALSA");
+MODULE_ALIAS("iMX_alsa_ssi");
+
+static struct snd_card_imx_codec *alsa_codec = NULL;
+static struct imx_alsa_codec_config *alsa_codec_config = NULL;
+
+
-+/*
-+ * HW interface start and stop helper functions
-+ */
-+static int audio_ifc_start(void)
-+{
-+ printk("Starting HW\n");
-+ SSI_SCSR |= SSI_TE; /* TE enable */
-+ return 0;
-+}
-+
-+static int audio_ifc_stop(void)
++/* Called by the DMA framework when a period has elapsed */
++static void snd_imx_dma_progression(int channel, void *data,
++ struct scatterlist *sg)
+{
-+ printk("Stopping HW\n");
-+ SSI_SCSR &= ~SSI_TE; /* TE disable */
-+ return 0;
-+}
++ struct audio_stream *s = data;
++ struct snd_pcm_substream *substream = s->stream;
++ struct snd_pcm_runtime *runtime;
+
-+#ifdef DEBUG
-+static void dump_ssi_registers(void)
-+{
-+ printk("SSI_STX: 0x%x\n", SSI_STX);
-+ printk("SSI_SRX: 0x%x\n", SSI_SRX);
-+ printk("SSI_SCSR: 0x%x\n", SSI_SCSR);
-+ printk("SSI_STCR: 0x%x\n", SSI_STCR);
-+ printk("SSI_SRCR: 0x%x\n", SSI_SRCR);
-+ printk("SSI_STCCR: 0x%x\n", SSI_STCCR);
-+ printk("SSI_SRCCR: 0x%x\n", SSI_SRCCR);
-+ printk("SSI_STSR: 0x%x\n", SSI_STSR);
-+ printk("SSI_SFCSR: 0x%x\n", SSI_SFCSR);
-+ printk("SSI_STR: 0x%x\n", SSI_STR);
-+ printk("SSI_SOR: 0x%x\n", SSI_SOR);
++ runtime = substream->runtime;
++
++ if (sg) {
++/* channel_info->offset = (unsigned long)sg->dma_address -
++ (unsigned long)channel_info->base;*/
++ s->periods++;
++ s->periods %= runtime->periods;
++
++ snd_pcm_period_elapsed(substream);
++ }
+}
-+#endif
+
-+static void imx_alsa_audio_init(struct snd_card_imx_codec *imx_alsa)
++/* called when the DMA unit has finished the buffer.
++ * it should not happen, but whith a playback or capturing
++ * size of 2^32 bytes it will happen!
++ */
++static void snd_imx_dma_callback(int channel, void *data)
+{
-+ /* Setup DMA stuff */
-+ imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa imx out";
-+ imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
-+ SNDRV_PCM_STREAM_PLAYBACK;
-+ imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
-+ IMX_DMA_CHANNELS-1;
-+ imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
-+ audio_ifc_start;
-+ imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
-+ audio_ifc_stop;
++ struct audio_stream *s = data;
++ struct snd_pcm_substream *substream = s->stream;
+
-+ imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa imx in";
-+ imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
-+ SNDRV_PCM_STREAM_CAPTURE;
-+ imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
-+ IMX_DMA_CHANNELS-2;
-+ imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
-+ audio_ifc_start;
-+ imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
-+ audio_ifc_stop;
++ pr_err("%s shouldn't be called\n", __func__);
++
++ /* report period's end */
++ snd_pcm_period_elapsed(substream);
+}
+
-+static void dma_err_handler(int channel, void *data, int errcode)
++/* Called by the DMA framework when an error has occured */
++static void snd_imx_dma_err_handler(int channel, void *data, int err)
+{
-+ printk("dma_err_handler %d %d\n",channel, errcode);
++ printk("dma_err_handler %d %d\n",channel, err);
+
++ printk("DMA timeout on channel %d -%s%s%s%s\n",
++ channel,
++ err & IMX_DMA_ERR_BURST ? " burst":"",
++ err & IMX_DMA_ERR_REQUEST ? " request":"",
++ err & IMX_DMA_ERR_TRANSFER ? " transfer":"",
++ err & IMX_DMA_ERR_BUFFER ? " buffer":"");
++
+ imx_dma_disable(channel);
+}
+
-+/*
-+ * DMA functions
-+ * Depends on imx-alsa-dma.c functions and (imx) dma.c
-+ *
-+ */
-+static int audio_dma_request(struct audio_stream *s,
-+ void (*callback) (int, void *))
++/* configure DMA channel of a given substream */
++static int snd_imx_dma_request(struct audio_stream *s)
+{
+ int err=0, chan=0;
+ ADEBUG();
+
-+ chan = imx_dma_request_by_prio(s->id, DMA_PRIO_HIGH);
++ chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH);
+ if (chan < 0) {
-+ printk(KERN_ERR "Unable to grab dma channel: %d\n", s->dma_dev);
-+ } else {
-+ s->dma_dev = chan;
-+ err = imx_dma_setup_handlers(s->dma_dev,
-+ snd_imx_alsa_dma_interrupt,
-+ dma_err_handler,
-+ s);
-+ if (err < 0)
-+ printk(KERN_ERR "Unable to setup dma handler for channel %d\n", s->dma_dev);
++ printk(KERN_ERR "Unable to grab a DMA channel\n");
++ err = chan;
++ goto on_error_1;
+ }
-+ printk("audio_dma_request done (%d)\n", s->dma_dev);
-+ imx_dma_disable(s->dma_dev);
-+ return err;
-+}
++ s->dma_dev = chan;
+
-+static int audio_dma_free(struct audio_stream *s)
-+{
-+ int err = 0;
-+ ADEBUG();
++ err = imx_dma_setup_handlers(s->dma_dev,
++ snd_imx_dma_callback,
++ snd_imx_dma_err_handler, s);
++ if (err < 0) {
++ printk(KERN_ERR "Unable to setup DMA handler for channel %d\n", s->dma_dev);
++ err = -EIO;
++ goto on_error_2;
++ }
+
-+ imx_dma_free(s->dma_dev); // doesn't return an error if failed
++ err = imx_dma_setup_progression_handler(s->dma_dev,
++ snd_imx_dma_progression);
++ if (err != 0) {
++ pr_err("Failed to setup the DMA handler\n");
++ err = -EIO;
++ goto on_error_2;
++ }
+
++ pr_debug("snd_imx_dma_request done (%d)\n", s->dma_dev);
++ imx_dma_disable(s->dma_dev);
++ return 0;
++
++on_error_2:
++ imx_dma_free(s->dma_dev);
++on_error_1:
+ 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.
@@ -201,174 +197,87 @@
+}
+
+/*
-+ * 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 */
-+ imx_dma_disable(s->dma_dev);
-+
-+ 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)
-+{
-+ //#define IMX_SSI_BASE (0x00218000) /* a retrouver depuis le plateform data !!! */
-+ struct snd_pcm_substream *substream = s->stream;
-+ struct snd_pcm_runtime *runtime;
-+ unsigned int dma_size;
-+ unsigned int offset;
-+ int ret;
-+ dma_addr_t source;
-+
-+ runtime = substream->runtime;
-+ imx_dma_disable(s->dma_dev);
-+
-+ if (s->active) {
-+ dma_size = frames_to_bytes(runtime, runtime->period_size);
-+ offset = dma_size * s->period;
-+// printk("dma_size %d, off %d psize %d from 0x%x\n", dma_size, offset, runtime->period_size, (dma_addr_t)runtime->dma_area);
-+ snd_assert(dma_size <= DMA_BUF_SIZE,);
-+
-+ source = dma_map_single(NULL,
-+ runtime->dma_area + offset,
-+ dma_size,
-+ DMA_TO_DEVICE);
-+ if (dma_mapping_error((struct device*)NULL, source)) {
-+ printk("Unable to map DMA buffer\n");
-+ return;
-+ }
-+
-+ ret = imx_dma_setup_single(s->dma_dev,
-+ source, dma_size,
-+ 0x00218000, DMA_MODE_WRITE);
-+ if (ret) {
-+ printk(KERN_ERR
-+ "audio_process_dma: cannot queue DMA buffer (%i)\n", ret);
-+ return;
-+ }
-+ imx_dma_enable(s->dma_dev);
-+
-+ s->dma_in_progress = 1;
-+ s->period++;
-+ s->period %= runtime->periods;
-+// s->periods++;
-+ s->offset = offset;
-+
-+ } else {
-+ printk("stream not active\n");
-+ }
-+}
-+
-+/*
-+ * This is called when dma IRQ occurs at the end of each transmited block
-+ */
-+void snd_imx_alsa_dma_interrupt(int channel, void *data)
-+{
-+ struct audio_stream *s = data;
-+ struct snd_pcm_substream *substream = s->stream;
-+ struct snd_pcm_runtime *runtime;
-+// unsigned int dma_size;
-+// unsigned int offset;
-+// unsigned long temp;
-+// int ret, i;
-+// dma_addr_t source;
-+
-+ runtime = substream->runtime;
-+
-+ //printk("[%x] <dma %d>\n",IMX_TCN(IMX_TIM2_BASE), channel);
-+/* // Reset DMA channel
-+ CCR(channel) &= ~CCR_CEN; TO REMOVE
-+ CCR(channel) |= CCR_CEN;*/
-+ /*
-+ * 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);
-+ s->dma_in_progress = 0;
-+ s->periods++;
-+ s->periods %= runtime->periods;
-+
-+// if (s->periods > 0)
-+// s->periods--;
-+
-+ /* Trig next DMA transfer */
-+ audio_process_dma(s);
-+ spin_unlock(&s->dma_lock);
-+}
-+
-+/*
+ * Alsa section
+ * PCM settings and callbacks
+ */
+static int snd_imx_alsa_trigger(struct snd_pcm_substream * substream, int cmd)
+{
-+ struct snd_card_imx_codec *chip =
-+ snd_pcm_substream_chip(substream);
++ struct snd_card_imx_codec *chip = snd_pcm_substream_chip(substream);
+ int stream_id = substream->pstr->stream;
+ struct audio_stream *s = &chip->s[stream_id];
-+ int err = 0;
-+ u32 temp;
+
-+ /* note local interrupts are already disabled in the midlevel code */
++ pr_debug("%s called\n", __func__);
+
++ /* 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 */
-+ // clear SSI underrun
-+ temp = SSI_SCSR;
-+ SSI_STX = 0x0000;
-+
-+ s->active = 1;
-+ s->dma_in_progress = 0;
-+ audio_process_dma(s);
-+ SSI_SCSR |= SSI_TE;
++ imx_dma_enable(s->dma_dev);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* requested stream shutdown */
-+ audio_stop_dma(s);
-+ SSI_SCSR &= ~SSI_TE;
++ imx_dma_disable(s->dma_dev);
+ break;
+
+ default:
+ printk("Not supported (yet?) ALSA trigger: 0x%x\n", cmd);
-+ err = -EINVAL;
++ return -EINVAL;
+ break;
+ }
+ spin_unlock(&s->dma_lock);
+
-+ return err;
++ /* SSI activation done here */
++ return imx_ssi_trigger(substream, cmd, /*channel_info->ssi*/0);
+}
+
-+static int snd_imx_alsa_prepare(struct snd_pcm_substream * substream)
++static int snd_imx_pcm_prepare(struct snd_pcm_substream * substream)
+{
+ struct snd_card_imx_codec *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct audio_stream *s = &chip->s[substream->pstr->stream];
-+
++ struct audio_stream *channel_info = &chip->s[substream->pstr->stream];
++// int stream_id = substream->pstr->stream;
++ unsigned int dma_chan = channel_info->dma_dev;
++ int err = -EINVAL;
++ void __iomem *fifo_io;
++
++ pr_debug("%s called\n", __func__);
++
+ /* set requested samplerate */
+ alsa_codec_config->codec_set_samplerate(runtime->rate);
+ chip->samplerate = runtime->rate;
+
-+ s->period = 0;
-+ s->periods = 0;
++ channel_info->period = 0;
++ channel_info->periods = 0;
+
++#ifdef TSC_MASTER
++ imx_ssi_setup_unit_to_iis_slave(0);
++#else
++ imx_ssi_setup_unit_to_iis_master(0);
++#endif /* TSC_MASTER */
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ fifo_io = imx_ssi_get_dma_tx_address(/*channel_info->ssi*/0, 0);
++ err = imx_dma_setup_sg(dma_chan, channel_info->sg_list,
++ channel_info->sg_count,
++ -1, /* TODO largest possible size */
++ (unsigned int)fifo_io,
++ DMA_MODE_WRITE);
++ }
++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
++ fifo_io = imx_ssi_get_dma_rx_address(/*channel_info->ssi*/0, 0);
++ err = imx_dma_setup_sg(dma_chan, channel_info->sg_list,
++ channel_info->sg_count,
++ -1, /* TODO largest possible size */
++ (unsigned int)fifo_io,
++ DMA_MODE_READ);
++ }
++ if (err < 0) {
++ pr_err("Can't setup scatter/gather DMA\n");
++ return err;
++ }
++
+ return 0;
+}
+
@@ -380,98 +289,222 @@
+ return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
-+static int snd_card_imx_alsa_open(struct snd_pcm_substream * substream)
++static int snd_imx_pcm_open(struct snd_pcm_substream * substream)
+{
-+ struct snd_card_imx_codec *chip =
-+ snd_pcm_substream_chip(substream);
++ struct snd_card_imx_codec *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int stream_id = substream->pstr->stream;
-+ int err;
++ int err, dma_req;
++ char *type;
++ unsigned int burstlen;
+
-+ printk ("%s substream @: 0x%x\n", __func__, (unsigned int)substream);
++ type = (stream_id == SNDRV_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
++ printk ("%s %s stream @: 0x%x\n", __func__, type, (unsigned int)substream);
++
+ chip->s[stream_id].stream = substream;
+ alsa_codec_config->codec_clock_on();
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = *(alsa_codec_config->snd_imx_alsa_playback);
-+ }
-+ else{
++ burstlen = SSI_DMA_BLR_TRANSMIT;
++ dma_req = imx_ssi_get_dma_tx_channel(0, 0);
++ printk("imx_ssi_get_dma_tx_channel = %d\n", dma_req);
++ if (dma_req < 0)
++ return dma_req;
++ } else {
+ runtime->hw = *(alsa_codec_config->snd_imx_alsa_capture);
-+ printk ("capture not supported\n");
++ burstlen = SSI_DMA_BLR;
++ printk("capture not supported\n");
++ dma_req = imx_ssi_get_dma_rx_channel(0, 0);
++ if (dma_req < 0)
++ return dma_req;
+ }
+ if ((err = snd_pcm_hw_constraint_integer(runtime,
-+ SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
++ SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+ return err;
+
-+ printk ("playback supported %d\n",runtime->hw.rate_min);
++ printk("playback supported\n");
+ if ((err = snd_pcm_hw_constraint_list(runtime,
+ 0,
+ SNDRV_PCM_HW_PARAM_RATE,
-+ alsa_codec_config->hw_constraints_rates)) < 0)
++ alsa_codec_config->hw_constraints_rates)) < 0)
+ return err;
-+ printk("success\n");
++
++ /* request DMA channel */
++ err = snd_imx_dma_request(&chip->s[stream_id]);
++ if (err < 0)
++ return err;
++
++ /* configure i.MX DMA control register for given channel */
++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
++ err = imx_dma_config_channel(chip->s[stream_id].dma_dev,
++ IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
++ IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
++ dma_req, 1);
++ } else {
++ err = imx_dma_config_channel(chip->s[stream_id].dma_dev,
++ IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
++ IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
++ dma_req, 1);
++ }
++ if (err < 0) {
++ printk("Cannot configure DMA for %s channel\n", type);
++ }
++
++ /* configure DMA burst length for channel */
++ imx_dma_config_burstlen(chip->s[stream_id].dma_dev, burstlen);
++
+ return 0;
+}
+
-+static int snd_card_imx_alsa_close(struct snd_pcm_substream * substream)
++static int snd_imx_pcm_close(struct snd_pcm_substream * substream)
+{
+ struct snd_card_imx_codec *chip = snd_pcm_substream_chip(substream);
-+
++ int stream_id = substream->pstr->stream;
++ struct audio_stream *channel_info = &chip->s[substream->pstr->stream];
++
+ ADEBUG();
++
++ imx_dma_disable(chip->s[stream_id].dma_dev);
++ imx_dma_free(chip->s[stream_id].dma_dev);
++
+ alsa_codec_config->codec_clock_off();
++
++ if (channel_info->sg_list != NULL)
++ kfree(channel_info->sg_list);
++
+ chip->s[substream->pstr->stream].stream = NULL;
+
+ return 0;
+}
+
+/* HW params & free */
-+static int snd_imx_alsa_hw_params(struct snd_pcm_substream * substream,
++static int snd_imx_pcm_hw_params(struct snd_pcm_substream * substream,
+ struct snd_pcm_hw_params * hw_params)
+{
++ struct snd_card_imx_codec *chip = snd_pcm_substream_chip(substream);
++ struct audio_stream *channel_info = &chip->s[substream->pstr->stream];
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ unsigned char *dma_adr;
++ int err = -EINVAL, i;
++
++ pr_debug("%s called\n", __func__);
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ err = devdma_hw_alloc(chip[0].card->dev, substream,
++ params_buffer_bytes(hw_params));
++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
++ err = devdma_hw_alloc(chip[1].card->dev, substream,
++ params_buffer_bytes(hw_params));
++ if (err < 0)
++ return err;
++
++ pr_debug("DMA area: 0x%p, addr: 0x%p, size: %u\n",
++ runtime->dma_area, (void*)runtime->dma_addr, runtime->dma_bytes);
++
++// channel_info->base = (void*)runtime->dma_addr;
++ channel_info->base = (void*)dma_map_single(NULL,
++ (void*)runtime->dma_area,
++ runtime->dma_bytes,
++ DMA_TO_DEVICE);
++ pr_debug("DMA phys: 0x%p\n", channel_info->base);
++ channel_info->adr = runtime->dma_area ;
++ channel_info->offset = 0;
++ channel_info->size = params_buffer_bytes(hw_params);
++ channel_info->periods = params_periods(hw_params);
++ channel_info->period = params_period_bytes(hw_params);
++
++ pr_debug("Size: %d periods: %d period_size: %d\n", channel_info->size, channel_info->periods, channel_info->period);
++ dma_adr = channel_info->base;
++
++ if (channel_info->sg_count != channel_info->periods) {
++ if (channel_info->sg_list)
++ kfree(channel_info->sg_list);
++ /* using sg_alloc_table() instead? */
++ channel_info->sg_list = kcalloc(channel_info->periods + 1,
++ sizeof(struct scatterlist), GFP_KERNEL);
++ pr_debug("Allocating scatter/gather list with %d+1 entries\n",
++ channel_info->periods);
++ if (!channel_info->sg_list)
++ return -ENOMEM;
++ channel_info->sg_count = channel_info->periods + 1;
++ } else
++ pr_debug("Reuse previous scatter/gather memory\n");
++
++ sg_init_table(channel_info->sg_list, channel_info->sg_count);
++
++ for (i = 0; i < channel_info->periods; i++) {
++ channel_info->sg_list[i].page_link = 0;
++ channel_info->sg_list[i].offset = 0; /* FIXME */
++ channel_info->sg_list[i].dma_address = (dma_addr_t)dma_adr;
++ channel_info->sg_list[i].length = channel_info->period;
++
++ dma_adr += channel_info->period;
++ }
++
++ /* close the loop */
++ sg_chain(channel_info->sg_list, channel_info->sg_count, channel_info->sg_list);
++
++ pr_debug("Activating %d periods with %d bytes each\n",
++ channel_info->periods, channel_info->period);
++
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
-+static int snd_imx_alsa_hw_free(struct snd_pcm_substream * substream)
++static int snd_imx_pcm_hw_free(struct snd_pcm_substream * substream)
+{
++ struct snd_card_imx_codec *chip = snd_pcm_substream_chip(substream);
++ struct audio_stream *channel_info = &chip->s[substream->pstr->stream];
++// struct snd_pcm_runtime *runtime = substream->runtime;
++
++ pr_debug("%s called\n", __func__);
++
++ if (channel_info->sg_list != NULL) {
++ kfree(channel_info->sg_list);
++ channel_info->sg_list = NULL;
++ }
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ devdma_hw_free(chip[0].card->dev, substream);
++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
++ devdma_hw_free(chip[1].card->dev, substream);
++
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
-+static struct snd_pcm_ops snd_card_imx_alsa_playback_ops = {
-+ .open = snd_card_imx_alsa_open,
-+ .close = snd_card_imx_alsa_close,
++static struct snd_pcm_ops snd_card_imx_ops = {
++ .open = snd_imx_pcm_open,
++ .close = snd_imx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
-+ .hw_params = snd_imx_alsa_hw_params,
-+ .hw_free = snd_imx_alsa_hw_free,
-+ .prepare = snd_imx_alsa_prepare,
++ .hw_params = snd_imx_pcm_hw_params,
++ .hw_free = snd_imx_pcm_hw_free,
++ .prepare = snd_imx_pcm_prepare,
+ .trigger = snd_imx_alsa_trigger,
+ .pointer = snd_imx_alsa_pointer,
+};
+
-+static struct snd_pcm_ops snd_card_imx_alsa_capture_ops = {
-+ .open = snd_card_imx_alsa_open,
-+ .close = snd_card_imx_alsa_close,
-+ .ioctl = snd_pcm_lib_ioctl,
-+ .hw_params = snd_imx_alsa_hw_params,
-+ .hw_free = snd_imx_alsa_hw_free,
-+ .prepare = snd_imx_alsa_prepare,
-+ .trigger = snd_imx_alsa_trigger,
-+ .pointer = snd_imx_alsa_pointer,
-+};
-+
+/*
+ * Alsa init and exit section
-+ *
++ *
+ * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
-+static int __init snd_card_imx_alsa_pcm(struct snd_card_imx_codec *imx_alsa,
++#define CHIP_NAME "i.MX SSI"
++static int __init snd_imx_new_pcm(struct snd_card_imx_codec *imx_alsa,
+ int device)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ ADEBUG();
-+ if ((err = snd_pcm_new(imx_alsa->card, "IMX PCM", device, 1, 1, &pcm)) < 0)
++ err = snd_pcm_new(imx_alsa->card,
++ CHIP_NAME,
++ device,
++ 1, /* one playback strean */
++ 1, /* one capture stream */
++ &pcm);
++
++ if (err < 0)
+ return err;
+
+ /* sets up initial buffer with continuous allocation */
@@ -481,63 +514,14 @@
+ (GFP_KERNEL),
+ 8 * 1024, 8 * 1024);
+
-+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-+ &snd_card_imx_alsa_playback_ops);
++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
++ &snd_card_imx_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-+ &snd_card_imx_alsa_capture_ops);
++ &snd_card_imx_ops);
+ pcm->private_data = imx_alsa;
+ pcm->info_flags = 0;
-+ strcpy(pcm->name, "imx alsa pcm");
++ strcpy(pcm->name, CHIP_NAME);
+
-+ imx_alsa_audio_init(imx_alsa);
-+
-+ /* request DMA channels */
-+ audio_dma_request(&imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
-+ snd_imx_alsa_dma_interrupt);
-+ audio_dma_request(&imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
-+ snd_imx_alsa_dma_interrupt);
-+
-+ /* configure i.MXL DMA control register for given channels */
-+ CCR(imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev) =
-+ CCR_DMOD_FIFO |
-+ CCR_SMOD_LINEAR |
-+ CCR_SSIZ_32 | CCR_DSIZ_16 |
-+ CCR_REN;
-+ CCR(imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev) =
-+ CCR_DMOD_LINEAR |
-+ CCR_SMOD_FIFO |
-+ CCR_SSIZ_16 | CCR_DSIZ_32 |
-+ CCR_REN;
-+ /* configure i.MXL DMA request channel */
-+ RSSR(imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev) = DMA_REQ_SSI_T;
-+ RSSR(imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev) = DMA_REQ_SSI_R;
-+ /* configure DMA burst length per channel */
-+ BLR(imx_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev) = SSI_DMA_BLR_TRANSMIT;
-+ BLR(imx_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev) = SSI_DMA_BLR;
-+
-+ /* Reset SSI before configuring it */
-+ SSI_SCSR &= ~SSI_EN;
-+ SSI_SCSR |= SSI_EN;
-+ /* SSI FIFO watermark */
-+ SSI_SFCSR = SSI_RFWM(8) | SSI_TFWM(TRANSMIT_WM_LEVEL);
-+#ifdef TSC_MASTER
-+ /* Clocks */
-+ SSI_STCCR = SSI_WL_16 | SSI_DC(0);
-+ SSI_SRCCR = SSI_WL_16 | SSI_DC(0);
-+ /* Control */
-+ SSI_SCSR = SSI_I2S_SLAVE_MODE | SSI_SYN | SSI_EN;
-+ /* Transmit config */
-+ SSI_STCR = SSI_MAE | SSI_FEN | SSI_SCKP | SSI_FSI | SSI_EFS;
-+#else
-+ /* Clocks */
-+ SSI_STCCR = 0x00006103;
-+ SSI_SRCCR = 0x00006103;
-+ /* Transmit config */
-+ SSI_STCR = SSI_MAE | SSI_FEN | SSI_FDIR | SSI_DIR | SSI_SCKP | SSI_FSI | SSI_EFS;
-+ /* Control */
-+ SSI_SCSR = /*SSI_SYS_CLK_EN |*/ SSI_I2S_MASTER_MODE | SSI_SYN | /*SSI_TE |*/ SSI_EN;
-+#endif // TSC_MASTER
-+
+ imx_alsa->pcm = pcm;
+
+ return 0;
@@ -571,7 +555,7 @@
+ struct snd_card_imx_codec *chip;
+ struct snd_card *card = platform_get_drvdata(pdev);
+
-+ if (card->power_state != SNDRV_CTL_POWER_D0) {
++ if (card->power_state != SNDRV_CTL_POWER_D0) {
+ chip = card->private_data;
+ if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
@@ -584,90 +568,81 @@
+
+#endif /* CONFIG_PM */
+
-+void snd_imx_alsa_free(struct snd_card * card)
-+{
-+ struct snd_card_imx_codec *chip = card->private_data;
-+
-+ /*
-+ * Turn off codec after it is done.
-+ * Can't do it immediately, since it may still have
-+ * buffered data.
-+ */
-+ schedule_timeout_interruptible(2);
-+
-+/* omap_mcbsp_stop(AUDIO_MCBSP);
-+ omap_mcbsp_free(AUDIO_MCBSP);
-+*/
-+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
-+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
-+}
-+
+/* module init & exit */
+
-+/*
++/*
+ * Inits alsa soundcard structure.
+ * Called by the probe method in codec after function pointers has been set.
+ */
+int snd_imx_alsa_post_probe(struct platform_device *pdev, struct imx_alsa_codec_config *config)
+{
+ int err = 0;
-+ int def_rate;
+ struct snd_card *card;
-+
-+ alsa_codec_config = config;
++ struct imx_sound_platform_data *pdata;
+
++ pr_debug("%s\n", __func__);
++
++ pdata = pdev->dev.platform_data;
++ if (pdata == NULL) {
++ pr_err("No platform data available. Giving up\n");
++ err = -ENODEV;
++ goto nodev1;
++ }
++
++ alsa_codec_config = config;
+ alsa_codec_config->codec_clock_setup();
-+ alsa_codec_config->codec_clock_on();
++ alsa_codec_config->codec_clock_on();
+
+ if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
+ alsa_codec_config->codec_configure_dev();
+
+ alsa_codec_config->codec_clock_off();
+
-+ /* create the soundcard */
-+ card = snd_card_new(-1, "IMX-ALSA", THIS_MODULE, sizeof(alsa_codec));
++ /* instantiate a new soundcard */
++ card = snd_card_new(-1, "IMX-ALSA", THIS_MODULE, sizeof(*alsa_codec));
+ if (card == NULL)
+ goto nodev1;
++ alsa_codec = card->private_data;
++ alsa_codec->card = card;
+
-+ alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
-+ if (alsa_codec == NULL)
-+ goto nodev2;
-+
-+ card->private_data = (void *)alsa_codec;
-+ card->private_free = snd_imx_alsa_free;
-+ alsa_codec->card = card;
-+ def_rate = alsa_codec_config->get_default_samplerate();
-+ alsa_codec->samplerate = def_rate;
++ alsa_codec->samplerate = alsa_codec_config->get_default_samplerate();
+ spin_lock_init(&alsa_codec->s[0].dma_lock);
+ spin_lock_init(&alsa_codec->s[1].dma_lock);
+
-+ /* mixer */
++ /* add it a mixer */
+ if ((err = snd_imx_mixer(alsa_codec)) < 0)
-+ goto nodev3;
++ goto nodev2;
+
-+ /* PCM */
-+ if ((err = snd_card_imx_alsa_pcm(alsa_codec, 0)) < 0)
-+ goto nodev3;
-+ strcpy(card->driver, "IMXALSA");
-+ strcpy(card->shortname, "ARMADEUS IMX_ALSA");
-+ sprintf(card->longname, "ARMADEUS IMX_ALSA");
++ /* add it a PCM interface */
++ if ((err = snd_imx_new_pcm(alsa_codec, 0)) < 0)
++ goto nodev2;
+
++ strcpy(card->driver, "i.MX");
++ sprintf(card->shortname, "i.MX+%s audio", alsa_codec_config->name);
++ sprintf(card->longname, "Freescale i.MX with %s codec", alsa_codec_config->name);
++
+ snd_imx_init_mixer();
+ snd_card_set_dev(card, &pdev->dev);
+
+ /* Register the created soundcard */
-+ if ((err = snd_card_register(card)) == 0) {
-+ printk(KERN_INFO "audio support initialized\n");
-+ platform_set_drvdata(pdev, card);
-+ return 0;
++ err = snd_card_register(card);
++ if (err < 0) {
++ pr_err("Cannot register sound card. Giving up\n");
++ goto nodev2;
+ }
+
-+nodev3:
-+ kfree(alsa_codec);
++ pr_info("audio support initialized\n");
++ platform_set_drvdata(pdev, card);
++
++ /* activate the external SSI pins (should be done in imx-ssi !?) */
++ if (pdata->init)
++ pdata->init(pdev);
++
++ return 0;
++
+nodev2:
+ snd_card_free(card);
+nodev1:
-+
+ return err;
+}
+
@@ -748,7 +723,7 @@
(Take a look at armadeus/target/linux/ directory to know how to generate it)
--- linux-2.6.27.2.original/sound/arm/imx-alsa-tsc2102.c
+++ linux-2.6.27.2.mod/sound/arm/imx-alsa-tsc2102.c
-@@ -0,0 +1,378 @@
+@@ -0,0 +1,389 @@
+/*
+ * sound/arm/imx-alsa-tsc2102.c
+ *
@@ -822,7 +797,7 @@
+ .fifo_size = 0,
+};
+
-+#define DUMP_TSC2102_AUDIO_REGISTERS 1
++// #define DUMP_TSC2102_AUDIO_REGISTERS 1
+#ifdef DUMP_TSC2102_AUDIO_REGISTERS
+static void dump_tsc2102_audio_regs(int show_coef)
+{
@@ -913,6 +888,11 @@
+ tsc210x_read_sync(TSC2101_CELL_PHONE_AGC_CTRL));
+// #endif /* CONFIG_TSC2101 */
+}
++#else
++static void dump_tsc2102_audio_regs(int show_coef)
++{
++ return;
++}
+#endif /* DUMP_TSC2102_AUDIO_REGISTERS */
+
+/*
@@ -1066,21 +1046,27 @@
+
+static int __init snd_imx_alsa_tsc210x_probe(struct platform_device *pdev)
+{
-+ int ret = 0;
-+ struct imx_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
++ int ret;
++ struct imx_alsa_codec_config *codec_cfg;
++// pdev->dev.platform_data;
+
++ printk("*** snd_imx_alsa_tsc2102_probe\n");
++
++ codec_cfg = kmalloc(sizeof(*codec_cfg), GFP_KERNEL);
+ if (codec_cfg) {
-+ codec_cfg->hw_constraints_rates =
-+ &tsc2102_hw_constraints_rates;
-+ codec_cfg->snd_imx_alsa_playback =
-+ &tsc2102_snd_imx_alsa_playback;
-+ codec_cfg->codec_configure_dev = tsc2102_configure;
-+ codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
-+ codec_cfg->codec_clock_setup = tsc2102_clock_setup;
-+ codec_cfg->codec_clock_on = tsc2102_clock_on;
-+ codec_cfg->codec_clock_off = tsc2102_clock_off;
++ codec_cfg->name = "TSC210x";
++ codec_cfg->hw_constraints_rates =
++ &tsc2102_hw_constraints_rates;
++ codec_cfg->snd_imx_alsa_playback =
++ &tsc2102_snd_imx_alsa_playback;
++ codec_cfg->codec_configure_dev = tsc2102_configure;
++ codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
++ codec_cfg->codec_clock_setup = tsc2102_clock_setup;
++ codec_cfg->codec_clock_on = tsc2102_clock_on;
++ codec_cfg->codec_clock_off = tsc2102_clock_off;
+ codec_cfg->get_default_samplerate =
-+ tsc2102_get_default_samplerate;
++ tsc2102_get_default_samplerate;
++ /* forward codec config to PCM layer */
+ ret = snd_imx_alsa_post_probe(pdev, codec_cfg);
+ } else
+ ret = -ENODEV;
@@ -1184,13 +1170,13 @@
(Take a look at armadeus/target/linux/ directory to know how to generate it)
--- linux-2.6.27.2.original/sound/arm/imx-alsa-tsc2102-mixer.c
+++ linux-2.6.27.2.mod/sound/arm/imx-alsa-tsc2102-mixer.c
-@@ -0,0 +1,287 @@
+@@ -0,0 +1,293 @@
+/*
+ * sound/arm/imx-alsa-tsc2102-mixer.c
+ *
-+ * Alsa codec driver for TSC2102 chip for iMXL platforms.
++ * Alsa mixer driver for TSC210x chips.
+ *
-+ * Copyright (c) 2008 Jorasse <jo...@ar...>
++ * Copyright (c) 2008 Armadeus systems - Jorasse <jo...@ar...>
+ * Code based on the TSC2101 ALSA driver for omap platforms.
+ * Copyright (c) 2006 Andrzej Zaborowski <ba...@za...>
+ * Code based on the TSC2101 ALSA driver.
@@ -1275,7 +1261,7 @@
+}
+
+/*
-+ * Initializes TSC 2102 and playback target.
++ * Initializes TSC210x and playback target.
+ */
+void snd_imx_init_mixer(void)
+{
@@ -1435,12 +1421,12 @@
+};
+
+#ifdef CONFIG_PM
-+void snd_imx_suspend_mixer(void)
++void snd_tsc210x_suspend_mixer(void)
+{
+ /* Nothing to do */
+}
+
-+void snd_imx_resume_mixer(void)
++void snd_tsc210x_resume_mixer(void)
+{
+ /* The chip was reset, restore the last used values */
+ set_dac_gain_stereo(vol[0], vol[1]);
@@ -1451,24 +1437,30 @@
+}
+#endif
+
-+int snd_imx_mixer(struct snd_card_imx_codec *tsc2102)
++/* To be called by upper layer to add a tsc210x mixer to a given soundcard */
++int snd_imx_mixer(struct snd_card_imx_codec *tsc210x)
+{
+ int i, err;
+
-+ if (!tsc2102)
++ if (!tsc210x)
+ return -EINVAL;
+
++ /* TSC2102/TSC2101 common part */
+ for (i = 0; i < ARRAY_SIZE(tsc2102_control); i ++) {
-+ err = snd_ctl_add(tsc2102->card,
-+ snd_ctl_new1(&tsc2102_control[i],
-+ tsc2102->card));
++ err = snd_ctl_add(tsc210x->card,
++ snd_ctl_new1(&tsc2102_control[i],
++ tsc210x->card));
+
+ if (err < 0)
+ return err;
+ }
++
++ /* TSC2101 specific part */
++ /* TBDL */
++
+ return 0;
+}
+
+MODULE_AUTHOR("Andrzej Zaborowski, Eric Jarrige, Julien Boibessot");
-+MODULE_DESCRIPTION("Interface driver for TI TSC210x chips.");
++MODULE_DESCRIPTION("Mixer interface driver for TI TSC210x chips.");
+MODULE_LICENSE("GPL");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|