diff options
Diffstat (limited to 'sound/soc/u8500/u8500_pcm.c')
-rwxr-xr-x | sound/soc/u8500/u8500_pcm.c | 427 |
1 files changed, 0 insertions, 427 deletions
diff --git a/sound/soc/u8500/u8500_pcm.c b/sound/soc/u8500/u8500_pcm.c deleted file mode 100755 index edd22bec215..00000000000 --- a/sound/soc/u8500/u8500_pcm.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * Author: Ola Lilja ola.o.lilja@stericsson.com, - * Roger Nilsson roger.xr.nilsson@stericsson.com - * for ST-Ericsson. - * - * License terms: - * - * This program 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. - */ -#include <asm/page.h> - -#include <linux/dma-mapping.h> -#include <linux/dmaengine.h> - -#include <linux/dma-mapping.h> - -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "u8500_pcm.h" -#include "u8500_msp_dai.h" - - - -// Local variables ------------------------------------------------------------------- - -// struct dma_chan -struct u8500_pcm_transfer { - spinlock_t lock; - dma_addr_t addr; - u32 dma_chan_id; - u32 period; - struct dma_chan *dma_chan; -}; - -static struct snd_pcm_hardware u8500_pcm_hw_playback = { - .info = - (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE), - .formats = - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | - SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = U8500_PLATFORM_MIN_RATE_PLAYBACK, - .rate_max = U8500_PLATFORM_MAX_RATE_PLAYBACK, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = NMDK_BUFFER_SIZE, - .period_bytes_min = 128, - .period_bytes_max = PAGE_SIZE, - .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE, - .periods_max = NMDK_BUFFER_SIZE / 128 -}; - -static struct snd_pcm_hardware u8500_pcm_hw_capture = { - .info = - (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE), - .formats = - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | - SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = U8500_PLATFORM_MIN_RATE_CAPTURE, - .rate_max = U8500_PLATFORM_MAX_RATE_CAPTURE, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = NMDK_BUFFER_SIZE, - .period_bytes_min = 128, - .period_bytes_max = PAGE_SIZE, - .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE, - .periods_max = NMDK_BUFFER_SIZE / 128 -}; - -static struct u8500_pcm_private_t u8500_pcm_private; - - - -// DMA operations ----------------------------------------------------------------------------- - -/** - * nomadik_alsa_dma_start - used to transmit or recive a dma chunk - * @stream - specifies the playback/record stream structure - */ -static void u8500_pcm_dma_start(struct snd_pcm_substream *substream) -{ - unsigned int offset, dma_size; - struct snd_pcm_runtime *runtime = substream->runtime; - int stream_id = substream->pstr->stream; - u8500_pcm_stream_t* stream_p = &u8500_pcm_private.streams[stream_id]; - - printk(KERN_DEBUG "u8500_pcm_dma_start: Enter.\n"); - - dma_size = frames_to_bytes(runtime, runtime->period_size); - offset = dma_size * stream_p->period; - stream_p->old_offset = offset; - printk(KERN_DEBUG "u8500_pcm_dma_start: address = %x size=%d\n", (runtime->dma_addr + offset), dma_size); - - if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { - u8500_i2s_send_data((void*)(runtime->dma_addr + offset), dma_size, 0); - } - else { - u8500_i2s_receive_data((void *)(runtime->dma_addr + offset), dma_size, 0); - } - - stream_p->period++; - stream_p->period %= runtime->periods; - stream_p->periods++; -} - -static void u8500_pcm_dma_hw_free(struct device *dev, struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - - if (runtime->dma_area == NULL) - return; - - if (buf != &substream->dma_buffer) { - dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr); - kfree(runtime->dma_buffer_p); - } - - snd_pcm_set_runtime_buffer(substream, NULL); -} - -/** - * dma_eot_handler - * @data - pointer to structure set in the dma callback handler - * @event - specifies the DMA event: transfer complete/error - * - * This is the PCM tasklet handler linked to a pipe, its role is to tell - * the PCM middler layer whene the buffer position goes across the prescribed - * period size.To inform of this the snd_pcm_period_elapsed is called. - * - * this callback will be called in case of DMA_EVENT_TC only - */ -irqreturn_t u8500_pcm_dma_eot_handler(void *data, int irq) -{ - struct snd_pcm_substream *substream = data; - int stream_id = substream->pstr->stream; - u8500_pcm_stream_t* stream_p = &u8500_pcm_private.streams[stream_id]; - - /* snd_pcm_period_elapsed() is _not_ to be protected - */ - printk(KERN_DEBUG "u8500_pcm_dma_eot_handler: Enter.\n"); - - if (substream) - snd_pcm_period_elapsed(substream); - if(stream_p->state == ALSA_STATE_PAUSED) - return IRQ_HANDLED; - if (stream_p->active == 1) { - u8500_pcm_dma_start(substream); - } - return IRQ_HANDLED; -} -EXPORT_SYMBOL(u8500_pcm_dma_eot_handler); - - - - -// snd_pcm_ops ----------------------------------------------------------------------------- - -static int u8500_pcm_open(struct snd_pcm_substream *substream) -{ - int status; - struct snd_pcm_runtime *runtime = substream->runtime; - int stream_id = substream->pstr->stream; - u8500_pcm_stream_t* stream_p = &u8500_pcm_private.streams[stream_id]; - - printk(KERN_DEBUG "u8500_pcm_open: Enter.\n"); - - status = 0; - printk(KERN_DEBUG "u8500_pcm_open: Setting HW-config.\n"); - if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) - { - runtime->hw = u8500_pcm_hw_playback; - } - else - { - runtime->hw = u8500_pcm_hw_capture; - } - - init_MUTEX(&(stream_p->alsa_sem)); - init_completion(&(stream_p->alsa_com)); - stream_p->state = ALSA_STATE_RUNNING; - printk(KERN_ALERT "u8500_pcm_open: Exit.\n"); - - return 0; -} - -static int u8500_pcm_close(struct snd_pcm_substream *substream) -{ - printk(KERN_DEBUG "u8500_pcm_close: Enter.\n"); - - return 0; -} - -static int u8500_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - int ret = 0; - int size; - - printk(KERN_DEBUG "u8500_pcm_hw_params: Enter.\n"); - - size = params_buffer_bytes(hw_params); - - if (buf) { - if (buf->bytes >= size) - goto out; - u8500_pcm_dma_hw_free(NULL, substream); - } - - if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { - buf = &substream->dma_buffer; - } else { - buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); - if (!buf) - goto nomem; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = NULL; - buf->area = dma_alloc_coherent(NULL, size, &buf->addr, GFP_KERNEL); - buf->bytes = size; - buf->private_data = NULL; - - if (!buf->area) - goto free; - } - snd_pcm_set_runtime_buffer(substream, buf); - ret = 1; - out: - runtime->dma_bytes = size; - return ret; - - free: - kfree(buf); - nomem: - return -ENOMEM; -} - -static int u8500_pcm_hw_free(struct snd_pcm_substream *substream) -{ - printk(KERN_ALERT "u8500_pcm_hw_free: Enter.\n"); - - u8500_pcm_dma_hw_free(NULL, substream); - - return 0; -} - -static int u8500_pcm_prepare(struct snd_pcm_substream *substream) -{ - printk(KERN_DEBUG "u8500_pcm_prepare: Enter.\n"); - - return 0; -} - -static int u8500_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - int stream_id = substream->pstr->stream; - u8500_pcm_stream_t* stream_p = &u8500_pcm_private.streams[stream_id]; - - printk(KERN_DEBUG "u8500_pcm_trigger: Enter.\n"); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - // Start DMA transfer - printk(KERN_DEBUG "u8500_pcm_trigger: TRIGGER START\n"); - if (stream_p->active == 0) { - stream_p->active = 1; - u8500_pcm_dma_start(substream); - break; - } - printk(KERN_DEBUG "u8500_pcm_trigger: Error: H/w is busy\n"); - return -EINVAL; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - // Pause DMA transfer - printk(KERN_ALERT "u8500_pcm_trigger: SNDRV_PCM_TRIGGER_PAUSE\n"); - if (stream_p->state == ALSA_STATE_RUNNING) { - stream_p->state = ALSA_STATE_PAUSED; - } - - break; - - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - // Resume DMA transfer - printk(KERN_DEBUG "u8500_pcm_trigger: SNDRV_PCM_TRIGGER_RESUME\n"); - if (stream_p->state == ALSA_STATE_PAUSED) { - stream_p->state = ALSA_STATE_RUNNING; - u8500_pcm_dma_start(substream); - } - break; - - case SNDRV_PCM_TRIGGER_STOP: - // Stop DMA transfer - printk(KERN_DEBUG "u8500_pcm_trigger: SNDRV_PCM_TRIGGER_STOP\n"); - if (stream_p->active == 1) { - stream_p->active = 0; - stream_p->period = 0; - } - break; - - default: - printk(KERN_ERR "u8500_pcm_trigger: Invalid command in pcm trigger.\n"); - return -EINVAL; - } - - return 0; -} - -static snd_pcm_uframes_t u8500_pcm_pointer(struct snd_pcm_substream *substream) -{ - unsigned int offset; - struct snd_pcm_runtime *runtime = substream->runtime; - int stream_id = substream->pstr->stream; - u8500_pcm_stream_t* stream_p = &u8500_pcm_private.streams[stream_id]; - - printk(KERN_DEBUG "u8500_pcm_pointer: Enter.\n"); - - offset = bytes_to_frames(runtime, stream_p->old_offset); - if (offset < 0 || stream_p->old_offset < 0) - printk(KERN_DEBUG "u8500_pcm_pointer: Offset=%i %i\n", offset, stream_p->old_offset); - - return offset; -} - -static int u8500_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - printk(KERN_DEBUG "u8500_pcm_mmap: Enter.\n"); - - return dma_mmap_coherent(NULL, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); -} - -static struct snd_pcm_ops u8500_pcm_ops = { - .open = u8500_pcm_open, - .close = u8500_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = u8500_pcm_hw_params, - .hw_free = u8500_pcm_hw_free, - .prepare = u8500_pcm_prepare, - .trigger = u8500_pcm_trigger, - .pointer = u8500_pcm_pointer, - .mmap = u8500_pcm_mmap -}; - - - -// snd_soc_platform ----------------------------------------------------------------------------- - -int u8500_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) -{ - int i; - - printk(KERN_DEBUG "u8500_pcm_new: Enter.\n"); - - printk(KERN_DEBUG "u8500_pcm_new: pcm = %d\n", (int)pcm); - - pcm->info_flags = 0; - strcpy(pcm->name, "nomadik_asoc"); - - for (i = 0; i < NO_OF_STREAMS; i++) - { - ; - u8500_pcm_private.streams[i].active = 0; - u8500_pcm_private.streams[i].period = 0; - u8500_pcm_private.streams[i].periods = 0; - u8500_pcm_private.streams[i].old_offset = 0; - } - - printk(KERN_DEBUG "u8500_pcm_new: pcm->name = %s\n", pcm->name); - - return 0; -} - -static void u8500_pcm_free(struct snd_pcm *pcm) -{ - printk(KERN_DEBUG "u8500_pcm_free: Enter.\n"); - - //u8500_pcm_dma_hw_free(NULL, substream); -} - -static int u8500_pcm_suspend(struct snd_soc_dai *dai) -{ - printk(KERN_DEBUG "u8500_pcm_suspend: Enter.\n"); - - return 0; -} - -static int u8500_pcm_resume(struct snd_soc_dai *dai) -{ - printk(KERN_DEBUG "u8500_pcm_resume: Enter.\n"); - - return 0; -} - -struct snd_soc_platform u8500_soc_platform = { - .name = "u8500-audio", - .pcm_ops = &u8500_pcm_ops, - .pcm_new = u8500_pcm_new, - .pcm_free = u8500_pcm_free, - .suspend = u8500_pcm_suspend, - .resume = u8500_pcm_resume, -}; -EXPORT_SYMBOL(u8500_soc_platform); - - - - - - - - - - - - |