mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-29 16:05:13 +02:00
jz4740: new dma api. cleanup audio pcm module
This commit is contained in:
parent
9d14f68289
commit
5ae0421a75
@ -15,251 +15,75 @@
|
|||||||
#ifndef __ASM_JZ4740_DMA_H__
|
#ifndef __ASM_JZ4740_DMA_H__
|
||||||
#define __ASM_JZ4740_DMA_H__
|
#define __ASM_JZ4740_DMA_H__
|
||||||
|
|
||||||
#include <linux/interrupt.h>
|
struct jz4740_dma_chan;
|
||||||
#include <asm/io.h> /* need byte IO */
|
|
||||||
#include <linux/spinlock.h> /* And spinlocks */
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <asm/mach-jz4740/regs.h>
|
|
||||||
#include <asm/mach-jz4740/ops.h>
|
|
||||||
|
|
||||||
/*
|
enum jz4740_dma_request_type {
|
||||||
* Descriptor structure for JZ4740 DMA engine
|
JZ4740_DMA_TYPE_AUTO_REQUEST = 8,
|
||||||
* Note: this structure must always be aligned to a 16-bytes boundary.
|
JZ4740_DMA_TYPE_UART_TRANSMIT = 20,
|
||||||
*/
|
JZ4740_DMA_TYPE_UART_RECEIVE = 21,
|
||||||
|
JZ4740_DMA_TYPE_SPI_TRANSMIT = 22,
|
||||||
typedef struct {
|
JZ4740_DMA_TYPE_SPI_RECEIVE = 23,
|
||||||
volatile u32 dcmd; /* DCMD value for the current transfer */
|
JZ4740_DMA_TYPE_AIC_TRANSMIT = 24,
|
||||||
volatile u32 dsadr; /* DSAR value for the current transfer */
|
JZ4740_DMA_TYPE_AIC_RECEIVE = 25,
|
||||||
volatile u32 dtadr; /* DTAR value for the current transfer */
|
JZ4740_DMA_TYPE_MMC_TRANSMIT = 26,
|
||||||
volatile u32 ddadr; /* Points to the next descriptor + transfer count */
|
JZ4740_DMA_TYPE_MMC_RECEIVE = 27,
|
||||||
} jz_dma_desc;
|
JZ4740_DMA_TYPE_TCU = 28,
|
||||||
|
JZ4740_DMA_TYPE_SADC = 29,
|
||||||
|
JZ4740_DMA_TYPE_SLCD = 30,
|
||||||
/* DMA Device ID's follow */
|
|
||||||
enum {
|
|
||||||
DMA_ID_UART0_TX = 0,
|
|
||||||
DMA_ID_UART0_RX,
|
|
||||||
DMA_ID_SSI_TX,
|
|
||||||
DMA_ID_SSI_RX,
|
|
||||||
DMA_ID_AIC_TX,
|
|
||||||
DMA_ID_AIC_RX,
|
|
||||||
DMA_ID_MSC_TX,
|
|
||||||
DMA_ID_MSC_RX,
|
|
||||||
DMA_ID_TCU_OVERFLOW,
|
|
||||||
DMA_ID_AUTO,
|
|
||||||
DMA_ID_RAW_SET,
|
|
||||||
DMA_ID_MAX
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* DMA modes, simulated by sw */
|
enum jz4740_dma_width {
|
||||||
#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */
|
JZ4740_DMA_WIDTH_8BIT,
|
||||||
#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */
|
JZ4740_DMA_WIDTH_16BIT,
|
||||||
#define DMA_AUTOINIT 0x2
|
JZ4740_DMA_WIDTH_32BIT,
|
||||||
#define DMA_MODE_MASK 0x3
|
|
||||||
|
|
||||||
struct jz_dma_chan {
|
|
||||||
int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
|
|
||||||
unsigned int io; /* DMA channel number */
|
|
||||||
const char *dev_str; /* string describes the DMA channel */
|
|
||||||
int irq; /* DMA irq number */
|
|
||||||
void *irq_dev; /* DMA private device structure */
|
|
||||||
unsigned int fifo_addr; /* physical fifo address of the requested device */
|
|
||||||
unsigned int cntl; /* DMA controll */
|
|
||||||
unsigned int mode; /* DMA configuration */
|
|
||||||
unsigned int source; /* DMA request source */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct jz_dma_chan jz_dma_table[];
|
enum jz4740_dma_transfer_size {
|
||||||
|
JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0,
|
||||||
|
JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1,
|
||||||
|
JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2,
|
||||||
|
JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3,
|
||||||
|
JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum jz4740_dma_flags {
|
||||||
|
JZ4740_DMA_SRC_AUTOINC = 0x2,
|
||||||
|
JZ4740_DMA_DST_AUTOINC = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum jz4740_dma_mode {
|
||||||
|
JZ4740_DMA_MODE_SINGLE = 0,
|
||||||
|
JZ4740_DMA_MODE_BLOCK = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4740_dma_config {
|
||||||
|
enum jz4740_dma_width src_width;
|
||||||
|
enum jz4740_dma_width dst_width;
|
||||||
|
enum jz4740_dma_transfer_size transfer_size;
|
||||||
|
enum jz4740_dma_request_type request_type;
|
||||||
|
enum jz4740_dma_flags flags;
|
||||||
|
enum jz4740_dma_mode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*jz4740_dma_complete_callback_t)(struct jz4740_dma_chan *, int , void *);
|
||||||
|
|
||||||
|
struct jz4740_dma_chan* jz4740_dma_request(void *dev, const char *name);
|
||||||
|
void jz4740_dma_free(struct jz4740_dma_chan *dma);
|
||||||
|
|
||||||
|
void jz4740_dma_configure(struct jz4740_dma_chan *dma,
|
||||||
|
const struct jz4740_dma_config *config);
|
||||||
|
|
||||||
|
|
||||||
#define DMA_8BIT_RX_CMD \
|
void jz4740_dma_enable(struct jz4740_dma_chan *dma);
|
||||||
DMAC_DCMD_DAI | \
|
void jz4740_dma_disable(struct jz4740_dma_chan *dma);
|
||||||
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
|
|
||||||
DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_8BIT_TX_CMD \
|
void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src);
|
||||||
DMAC_DCMD_SAI | \
|
void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst);
|
||||||
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
|
void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count);
|
||||||
DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_16BIT_RX_CMD \
|
uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma);
|
||||||
DMAC_DCMD_DAI | \
|
|
||||||
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \
|
|
||||||
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_16BIT_TX_CMD \
|
void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
|
||||||
DMAC_DCMD_SAI | \
|
jz4740_dma_complete_callback_t cb);
|
||||||
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
|
|
||||||
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_32BIT_RX_CMD \
|
|
||||||
DMAC_DCMD_DAI | \
|
|
||||||
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
|
|
||||||
DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_32BIT_TX_CMD \
|
|
||||||
DMAC_DCMD_SAI | \
|
|
||||||
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
|
|
||||||
DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_16BYTE_RX_CMD \
|
|
||||||
DMAC_DCMD_DAI | \
|
|
||||||
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
|
|
||||||
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_16BYTE_TX_CMD \
|
|
||||||
DMAC_DCMD_SAI | \
|
|
||||||
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
|
|
||||||
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_32BYTE_RX_CMD \
|
|
||||||
DMAC_DCMD_DAI | \
|
|
||||||
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
|
|
||||||
DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_32BYTE_TX_CMD \
|
|
||||||
DMAC_DCMD_SAI | \
|
|
||||||
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
|
|
||||||
DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_AIC_32_16BYTE_TX_CMD \
|
|
||||||
DMAC_DCMD_SAI | \
|
|
||||||
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
|
|
||||||
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_AIC_32_16BYTE_RX_CMD \
|
|
||||||
DMAC_DCMD_DAI | \
|
|
||||||
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
|
|
||||||
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_AIC_16BIT_TX_CMD \
|
|
||||||
DMAC_DCMD_SAI | \
|
|
||||||
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
|
|
||||||
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_AIC_16BIT_RX_CMD \
|
|
||||||
DMAC_DCMD_DAI | \
|
|
||||||
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
|
|
||||||
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_AIC_16BYTE_RX_CMD \
|
|
||||||
DMAC_DCMD_DAI | \
|
|
||||||
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
|
|
||||||
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
#define DMA_AIC_16BYTE_TX_CMD \
|
|
||||||
DMAC_DCMD_SAI | \
|
|
||||||
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
|
|
||||||
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
|
||||||
|
|
||||||
extern int jz_request_dma(int dev_id,
|
|
||||||
const char *dev_str,
|
|
||||||
irqreturn_t (*irqhandler)(int, void *),
|
|
||||||
unsigned long irqflags,
|
|
||||||
void *irq_dev_id);
|
|
||||||
extern void jz_free_dma(unsigned int dmanr);
|
|
||||||
|
|
||||||
extern int jz_dma_read_proc(char *buf, char **start, off_t fpos,
|
|
||||||
int length, int *eof, void *data);
|
|
||||||
extern void dump_jz_dma_channel(unsigned int dmanr);
|
|
||||||
|
|
||||||
extern void enable_dma(unsigned int dmanr);
|
|
||||||
extern void disable_dma(unsigned int dmanr);
|
|
||||||
extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr);
|
|
||||||
extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt);
|
|
||||||
extern void set_dma_mode(unsigned int dmanr, unsigned int mode);
|
|
||||||
extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
|
|
||||||
extern unsigned int get_dma_residue(unsigned int dmanr);
|
|
||||||
|
|
||||||
extern spinlock_t dma_spin_lock;
|
|
||||||
|
|
||||||
static __inline__ unsigned long claim_dma_lock(void)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
spin_lock_irqsave(&dma_spin_lock, flags);
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void release_dma_lock(unsigned long flags)
|
|
||||||
{
|
|
||||||
spin_unlock_irqrestore(&dma_spin_lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the 'DMA Pointer Flip Flop'.
|
|
||||||
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
|
|
||||||
*/
|
|
||||||
#define clear_dma_ff(channel)
|
|
||||||
|
|
||||||
static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr)
|
|
||||||
{
|
|
||||||
if (dmanr > MAX_DMA_NUM
|
|
||||||
|| jz_dma_table[dmanr].dev_id < 0)
|
|
||||||
return NULL;
|
|
||||||
return &jz_dma_table[dmanr];
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ int dma_halted(unsigned int dmanr)
|
|
||||||
{
|
|
||||||
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
|
||||||
if (!chan)
|
|
||||||
return 1;
|
|
||||||
return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
|
|
||||||
{
|
|
||||||
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
|
||||||
if (!chan)
|
|
||||||
return 0;
|
|
||||||
return chan->mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void clear_dma_done(unsigned int dmanr)
|
|
||||||
{
|
|
||||||
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
|
||||||
if (!chan)
|
|
||||||
return;
|
|
||||||
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void clear_dma_halt(unsigned int dmanr)
|
|
||||||
{
|
|
||||||
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
|
||||||
if (!chan)
|
|
||||||
return;
|
|
||||||
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT);
|
|
||||||
REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void clear_dma_flag(unsigned int dmanr)
|
|
||||||
{
|
|
||||||
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
|
||||||
if (!chan)
|
|
||||||
return;
|
|
||||||
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
|
|
||||||
REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ unsigned int get_dma_done_status(unsigned int dmanr)
|
|
||||||
{
|
|
||||||
unsigned long dccsr;
|
|
||||||
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
|
||||||
if (!chan)
|
|
||||||
return 0;
|
|
||||||
dccsr = REG_DMAC_DCCSR(chan->io);
|
|
||||||
return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ int get_dma_done_irq(unsigned int dmanr)
|
|
||||||
{
|
|
||||||
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
|
||||||
if (!chan)
|
|
||||||
return -1;
|
|
||||||
return chan->irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __ASM_JZ4740_DMA_H__ */
|
#endif /* __ASM_JZ4740_DMA_H__ */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,28 +24,6 @@
|
|||||||
#include "jz4740-pcm.h"
|
#include "jz4740-pcm.h"
|
||||||
#include "jz4740-i2s.h"
|
#include "jz4740-i2s.h"
|
||||||
|
|
||||||
static struct jz4740_dma_client jz4740_dma_client_out = {
|
|
||||||
.name = "I2S PCM Stereo out"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_dma_client jz4740_dma_client_in = {
|
|
||||||
.name = "I2S PCM Stereo in"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = {
|
|
||||||
.client = &jz4740_dma_client_out,
|
|
||||||
.channel = DMA_ID_AIC_TX,
|
|
||||||
.dma_addr = AIC_DR,
|
|
||||||
.dma_size = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = {
|
|
||||||
.client = &jz4740_dma_client_in,
|
|
||||||
.channel = DMA_ID_AIC_RX,
|
|
||||||
.dma_addr = AIC_DR,
|
|
||||||
.dma_size = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int jz4740_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
static int jz4740_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||||
{
|
{
|
||||||
/*struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
/*struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
@ -136,14 +114,6 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
|
|||||||
|
|
||||||
jz4740_snd_rx_ctrl(0);
|
jz4740_snd_rx_ctrl(0);
|
||||||
jz4740_snd_rx_ctrl(0);
|
jz4740_snd_rx_ctrl(0);
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_out;
|
|
||||||
/*if (channels == 1)
|
|
||||||
__aic_enable_mono2stereo();
|
|
||||||
else
|
|
||||||
__aic_disable_mono2stereo();*/
|
|
||||||
} else
|
|
||||||
cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_in;
|
|
||||||
|
|
||||||
switch (params_format(params)) {
|
switch (params_format(params)) {
|
||||||
case SNDRV_PCM_FORMAT_S8:
|
case SNDRV_PCM_FORMAT_S8:
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
*
|
*
|
||||||
* 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 <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
@ -17,68 +23,34 @@
|
|||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
#include <sound/soc.h>
|
#include <sound/soc.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/mach-jz4740/dma.h>
|
||||||
|
#include <asm/mach-jz4740/regs.h>
|
||||||
#include "jz4740-pcm.h"
|
#include "jz4740-pcm.h"
|
||||||
|
|
||||||
static long sum_bytes = 0;
|
|
||||||
static int first_transfer = 0;
|
|
||||||
static int printk_flag = 0;
|
|
||||||
static int tran_bit = 0;
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
|
||||||
static int hw_params_cnt = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct jz4740_dma_client jz4740_dma_client_out = {
|
|
||||||
.name = "I2S PCM Stereo out"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_dma_client jz4740_dma_client_in = {
|
|
||||||
.name = "I2S PCM Stereo in"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = {
|
|
||||||
.client = &jz4740_dma_client_out,
|
|
||||||
.channel = DMA_ID_AIC_TX,
|
|
||||||
.dma_addr = AIC_DR,
|
|
||||||
.dma_size = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = {
|
|
||||||
.client = &jz4740_dma_client_in,
|
|
||||||
.channel = DMA_ID_AIC_RX,
|
|
||||||
.dma_addr = AIC_DR,
|
|
||||||
.dma_size = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct jz4740_dma_buf_aic {
|
|
||||||
struct jz4740_dma_buf_aic *next;
|
|
||||||
int size; /* buffer size in bytes */
|
|
||||||
dma_addr_t data; /* start of DMA data */
|
|
||||||
dma_addr_t ptr; /* where the DMA got to [1] */
|
|
||||||
void *id; /* client's id */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct jz4740_runtime_data {
|
struct jz4740_runtime_data {
|
||||||
spinlock_t lock;
|
|
||||||
int state;
|
|
||||||
int aic_dma_flag; /* start dma transfer or not */
|
|
||||||
unsigned int dma_loaded;
|
|
||||||
unsigned int dma_limit;
|
|
||||||
unsigned int dma_period;
|
unsigned int dma_period;
|
||||||
dma_addr_t dma_start;
|
dma_addr_t dma_start;
|
||||||
dma_addr_t dma_pos;
|
dma_addr_t dma_pos;
|
||||||
dma_addr_t dma_end;
|
dma_addr_t dma_end;
|
||||||
struct jz4740_pcm_dma_params *params;
|
struct jz4740_dma_chan *dma;
|
||||||
|
};
|
||||||
|
|
||||||
dma_addr_t user_cur_addr; /* user current write buffer start address */
|
static struct jz4740_dma_config jz4740_pcm_dma_playback_config = {
|
||||||
unsigned int user_cur_len; /* user current write buffer length */
|
.src_width = JZ4740_DMA_WIDTH_16BIT,
|
||||||
|
.dst_width = JZ4740_DMA_WIDTH_32BIT,
|
||||||
/* buffer list and information */
|
.transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE,
|
||||||
struct jz4740_dma_buf_aic *curr; /* current dma buffer */
|
.request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT,
|
||||||
struct jz4740_dma_buf_aic *next; /* next buffer to load */
|
.flags = JZ4740_DMA_SRC_AUTOINC,
|
||||||
struct jz4740_dma_buf_aic *end; /* end of queue */
|
.mode = JZ4740_DMA_MODE_SINGLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_dma_config jz4740_pcm_dma_capture_config = {
|
||||||
|
.src_width = JZ4740_DMA_WIDTH_32BIT,
|
||||||
|
.dst_width = JZ4740_DMA_WIDTH_16BIT,
|
||||||
|
.transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE,
|
||||||
|
.request_type = JZ4740_DMA_TYPE_AIC_RECEIVE,
|
||||||
|
.flags = JZ4740_DMA_DST_AUTOINC,
|
||||||
|
.mode = JZ4740_DMA_MODE_SINGLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* identify hardware playback capabilities */
|
/* identify hardware playback capabilities */
|
||||||
@ -89,270 +61,111 @@ static const struct snd_pcm_hardware jz4740_pcm_hardware = {
|
|||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||||
SNDRV_PCM_FMTBIT_S8,
|
SNDRV_PCM_FMTBIT_S8,
|
||||||
.rates = SNDRV_PCM_RATE_8000_48000/*0x3fe*/,
|
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||||
.rate_min = 8000,
|
.channels_min = 1,
|
||||||
.rate_min = 48000,
|
|
||||||
.channels_min = 2,
|
|
||||||
.channels_max = 2,
|
.channels_max = 2,
|
||||||
.buffer_bytes_max = 128 * 1024,//16 * 1024
|
.period_bytes_min = 32,
|
||||||
.period_bytes_min = PAGE_SIZE,
|
.period_bytes_max = 2 * PAGE_SIZE,
|
||||||
.period_bytes_max = PAGE_SIZE * 2,
|
|
||||||
.periods_min = 2,
|
.periods_min = 2,
|
||||||
.periods_max = 128,//16,
|
.periods_max = 128,
|
||||||
|
.buffer_bytes_max = 128 * 2 * PAGE_SIZE,
|
||||||
.fifo_size = 32,
|
.fifo_size = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* jz4740__dma_buf_enqueue
|
static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd, int stream)
|
||||||
*
|
|
||||||
* queue an given buffer for dma transfer.
|
|
||||||
*
|
|
||||||
* data the physical address of the buffer data
|
|
||||||
* size the size of the buffer in bytes
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static int jz4740_dma_buf_enqueue(struct jz4740_runtime_data *prtd, dma_addr_t data, int size)
|
|
||||||
{
|
{
|
||||||
struct jz4740_dma_buf_aic *aic_buf;
|
unsigned int count;
|
||||||
|
|
||||||
aic_buf = kzalloc(sizeof(struct jz4740_dma_buf_aic), GFP_KERNEL);
|
if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
|
||||||
if (aic_buf == NULL) {
|
count = prtd->dma_end - prtd->dma_pos;
|
||||||
printk("aic buffer allocate failed,no memory!\n");
|
else
|
||||||
return -ENOMEM;
|
count = prtd->dma_period;
|
||||||
}
|
|
||||||
aic_buf->next = NULL;
|
jz4740_dma_disable(prtd->dma);
|
||||||
aic_buf->data = aic_buf->ptr = data;
|
|
||||||
aic_buf->size = size;
|
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
if( prtd->curr == NULL) {
|
jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos);
|
||||||
prtd->curr = aic_buf;
|
jz4740_dma_set_dst_addr(prtd->dma, CPHYSADDR(AIC_DR));
|
||||||
prtd->end = aic_buf;
|
|
||||||
prtd->next = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
if (prtd->end == NULL)
|
jz4740_dma_set_src_addr(prtd->dma, CPHYSADDR(AIC_DR));
|
||||||
printk("prtd->end is NULL\n");
|
jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos);
|
||||||
prtd->end->next = aic_buf;
|
|
||||||
prtd->end = aic_buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if necessary, update the next buffer field */
|
jz4740_dma_set_transfer_count(prtd->dma, count);
|
||||||
if (prtd->next == NULL)
|
|
||||||
prtd->next = aic_buf;
|
|
||||||
|
|
||||||
return 0;
|
jz4740_dma_enable(prtd->dma);
|
||||||
|
|
||||||
|
prtd->dma_pos += prtd->dma_period;
|
||||||
|
if (prtd->dma_pos >= prtd->dma_end)
|
||||||
|
prtd->dma_pos = prtd->dma_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err,
|
||||||
void audio_start_dma(struct jz4740_runtime_data *prtd, int mode)
|
void *dev_id)
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
struct jz4740_dma_buf_aic *aic_buf;
|
|
||||||
int channel;
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case DMA_MODE_WRITE:
|
|
||||||
/* free cur aic_buf */
|
|
||||||
if (first_transfer == 1) {
|
|
||||||
first_transfer = 0;
|
|
||||||
} else {
|
|
||||||
aic_buf = prtd->curr;
|
|
||||||
if (aic_buf != NULL) {
|
|
||||||
prtd->curr = aic_buf->next;
|
|
||||||
prtd->next = aic_buf->next;
|
|
||||||
aic_buf->next = NULL;
|
|
||||||
kfree(aic_buf);
|
|
||||||
aic_buf = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aic_buf = prtd->next;
|
|
||||||
channel = prtd->params->channel;
|
|
||||||
if (aic_buf) {
|
|
||||||
disable_dma(channel);
|
|
||||||
jz_set_alsa_dma(channel, mode, tran_bit);
|
|
||||||
set_dma_addr(channel, aic_buf->data);
|
|
||||||
set_dma_count(channel, aic_buf->size);
|
|
||||||
enable_dma(channel);
|
|
||||||
prtd->aic_dma_flag |= AIC_START_DMA;
|
|
||||||
} else {
|
|
||||||
printk("next buffer is NULL for playback\n");
|
|
||||||
prtd->aic_dma_flag &= ~AIC_START_DMA;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DMA_MODE_READ:
|
|
||||||
/* free cur aic_buf */
|
|
||||||
if (first_transfer == 1) {
|
|
||||||
first_transfer = 0;
|
|
||||||
} else {
|
|
||||||
aic_buf = prtd->curr;
|
|
||||||
if (aic_buf != NULL) {
|
|
||||||
prtd->curr = aic_buf->next;
|
|
||||||
prtd->next = aic_buf->next;
|
|
||||||
aic_buf->next = NULL;
|
|
||||||
kfree(aic_buf);
|
|
||||||
aic_buf = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aic_buf = prtd->next;
|
|
||||||
channel = prtd->params->channel;
|
|
||||||
|
|
||||||
if (aic_buf) {
|
|
||||||
disable_dma(channel);
|
|
||||||
jz_set_alsa_dma(channel, mode, tran_bit);
|
|
||||||
set_dma_addr(channel, aic_buf->data);
|
|
||||||
set_dma_count(channel, aic_buf->size);
|
|
||||||
enable_dma(channel);
|
|
||||||
prtd->aic_dma_flag |= AIC_START_DMA;
|
|
||||||
} else {
|
|
||||||
printk("next buffer is NULL for capture\n");
|
|
||||||
prtd->aic_dma_flag &= ~AIC_START_DMA;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* dump_jz_dma_channel(channel); */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* place a dma buffer onto the queue for the dma system to handle.
|
|
||||||
*/
|
|
||||||
static void jz4740_pcm_enqueue(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
struct jz4740_runtime_data *prtd = runtime->private_data;
|
|
||||||
/*struct snd_dma_buffer *buf = &substream->dma_buffer;*/
|
|
||||||
dma_addr_t pos = prtd->dma_pos;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while (prtd->dma_loaded < prtd->dma_limit) {
|
|
||||||
unsigned long len = prtd->dma_period;
|
|
||||||
|
|
||||||
if ((pos + len) > prtd->dma_end) {
|
|
||||||
len = prtd->dma_end - pos;
|
|
||||||
}
|
|
||||||
ret = jz4740_dma_buf_enqueue(prtd, pos, len);
|
|
||||||
if (ret == 0) {
|
|
||||||
prtd->dma_loaded++;
|
|
||||||
pos += prtd->dma_period;
|
|
||||||
if (pos >= prtd->dma_end)
|
|
||||||
pos = prtd->dma_start;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prtd->dma_pos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call the function:jz4740_pcm_dma_irq() after DMA has transfered the current buffer
|
|
||||||
*/
|
|
||||||
static irqreturn_t jz4740_pcm_dma_irq(int dma_ch, void *dev_id)
|
|
||||||
{
|
{
|
||||||
struct snd_pcm_substream *substream = dev_id;
|
struct snd_pcm_substream *substream = dev_id;
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct jz4740_runtime_data *prtd = runtime->private_data;
|
struct jz4740_runtime_data *prtd = runtime->private_data;
|
||||||
/*struct jz4740_dma_buf_aic *aic_buf = prtd->curr;*/
|
|
||||||
int channel = prtd->params->channel;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
disable_dma(channel);
|
|
||||||
prtd->aic_dma_flag &= ~AIC_START_DMA;
|
|
||||||
/* must clear TT bit in DCCSR to avoid interrupt again */
|
|
||||||
if (__dmac_channel_transmit_end_detected(channel)) {
|
|
||||||
__dmac_channel_clear_transmit_end(channel);
|
|
||||||
}
|
|
||||||
if (__dmac_channel_transmit_halt_detected(channel)) {
|
|
||||||
__dmac_channel_clear_transmit_halt(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__dmac_channel_address_error_detected(channel)) {
|
|
||||||
__dmac_channel_clear_address_error(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (substream)
|
|
||||||
snd_pcm_period_elapsed(substream);
|
snd_pcm_period_elapsed(substream);
|
||||||
|
|
||||||
spin_lock(&prtd->lock);
|
jz4740_pcm_start_transfer(prtd, substream->stream);
|
||||||
prtd->dma_loaded--;
|
|
||||||
if (prtd->state & ST_RUNNING) {
|
|
||||||
jz4740_pcm_enqueue(substream);
|
|
||||||
}
|
|
||||||
spin_unlock(&prtd->lock);
|
|
||||||
|
|
||||||
local_irq_save(flags);
|
|
||||||
if (prtd->state & ST_RUNNING) {
|
|
||||||
if (prtd->dma_loaded) {
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
||||||
audio_start_dma(prtd, DMA_MODE_WRITE);
|
|
||||||
else
|
|
||||||
audio_start_dma(prtd, DMA_MODE_READ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
local_irq_restore(flags);
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some parameter about DMA operation */
|
|
||||||
static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
|
static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params *params)
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct jz4740_runtime_data *prtd = runtime->private_data;
|
struct jz4740_runtime_data *prtd = runtime->private_data;
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
unsigned int size = params_buffer_bytes(params);
|
||||||
struct jz4740_pcm_dma_params *dma = &jz4740_i2s_pcm_stereo_out;
|
struct jz4740_dma_config *dma_config;
|
||||||
size_t totbytes = params_buffer_bytes(params);
|
enum jz4740_dma_width width;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!dma)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (params_format(params)) {
|
switch (params_format(params)) {
|
||||||
case SNDRV_PCM_FORMAT_S8:
|
case SNDRV_PCM_FORMAT_S8:
|
||||||
tran_bit = 8;
|
width = JZ4740_DMA_WIDTH_8BIT;
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_FORMAT_S16_LE:
|
case SNDRV_PCM_FORMAT_S16_LE:
|
||||||
tran_bit = 16;
|
width = JZ4740_DMA_WIDTH_16BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prepare DMA */
|
|
||||||
prtd->params = dma;
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name,
|
dma_config = &jz4740_pcm_dma_playback_config;
|
||||||
jz4740_pcm_dma_irq, IRQF_DISABLED, substream);
|
dma_config->src_width = width;
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
prtd->dma = jz4740_dma_request(substream, "PCM Playback");
|
||||||
prtd->params->channel = ret;
|
|
||||||
} else {
|
} else {
|
||||||
ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name,
|
dma_config = &jz4740_pcm_dma_capture_config;
|
||||||
jz4740_pcm_dma_irq, IRQF_DISABLED, substream);
|
dma_config->dst_width = width;
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
prtd->dma = jz4740_dma_request(substream, "PCM Capture");
|
||||||
prtd->params->channel = ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
if (!prtd->dma)
|
||||||
runtime->dma_bytes = totbytes;
|
return -EBUSY;
|
||||||
|
|
||||||
|
jz4740_dma_configure(prtd->dma, dma_config);
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
jz4740_dma_set_dst_addr(prtd->dma, CPHYSADDR(AIC_DR));
|
||||||
|
else
|
||||||
|
jz4740_dma_set_src_addr(prtd->dma, CPHYSADDR(AIC_DR));
|
||||||
|
|
||||||
|
jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done);
|
||||||
|
|
||||||
|
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||||
|
runtime->dma_bytes = size;
|
||||||
|
|
||||||
spin_lock_irq(&prtd->lock);
|
|
||||||
prtd->dma_loaded = 0;
|
|
||||||
prtd->aic_dma_flag = 0;
|
|
||||||
prtd->dma_limit = runtime->hw.periods_min;
|
|
||||||
prtd->dma_period = params_period_bytes(params);
|
prtd->dma_period = params_period_bytes(params);
|
||||||
prtd->dma_start = runtime->dma_addr;
|
prtd->dma_start = runtime->dma_addr;
|
||||||
prtd->dma_pos = prtd->dma_start;
|
prtd->dma_pos = prtd->dma_start;
|
||||||
prtd->dma_end = prtd->dma_start + totbytes;
|
prtd->dma_end = prtd->dma_start + size;
|
||||||
prtd->curr = NULL;
|
|
||||||
prtd->next = NULL;
|
|
||||||
prtd->end = NULL;
|
|
||||||
sum_bytes = 0;
|
|
||||||
first_transfer = 1;
|
|
||||||
printk_flag = 0;
|
|
||||||
|
|
||||||
__dmac_disable_descriptor(prtd->params->channel);
|
return 0;
|
||||||
__dmac_channel_disable_irq(prtd->params->channel);
|
|
||||||
spin_unlock_irq(&prtd->lock);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
|
static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||||
@ -360,55 +173,23 @@ static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||||||
struct jz4740_runtime_data *prtd = substream->runtime->private_data;
|
struct jz4740_runtime_data *prtd = substream->runtime->private_data;
|
||||||
|
|
||||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||||
if (prtd->params) {
|
if (prtd->dma)
|
||||||
jz_free_dma(prtd->params->channel);
|
jz4740_dma_free(prtd->dma);
|
||||||
prtd->params = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set some dma para for playback/capture */
|
|
||||||
static int jz4740_dma_ctrl(int channel)
|
|
||||||
{
|
|
||||||
|
|
||||||
disable_dma(channel);
|
|
||||||
|
|
||||||
/* must clear TT bit in DCCSR to avoid interrupt again */
|
|
||||||
if (__dmac_channel_transmit_end_detected(channel)) {
|
|
||||||
__dmac_channel_clear_transmit_end(channel);
|
|
||||||
}
|
|
||||||
if (__dmac_channel_transmit_halt_detected(channel)) {
|
|
||||||
__dmac_channel_clear_transmit_halt(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__dmac_channel_address_error_detected(channel)) {
|
|
||||||
__dmac_channel_clear_address_error(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
|
static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct jz4740_runtime_data *prtd = substream->runtime->private_data;
|
struct jz4740_runtime_data *prtd = substream->runtime->private_data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* return if this is a bufferless transfer e.g */
|
if (!prtd->dma)
|
||||||
if (!prtd->params)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* flush the DMA channel and DMA channel bit check */
|
|
||||||
jz4740_dma_ctrl(prtd->params->channel);
|
|
||||||
prtd->dma_loaded = 0;
|
|
||||||
prtd->dma_pos = prtd->dma_start;
|
prtd->dma_pos = prtd->dma_start;
|
||||||
|
|
||||||
/* enqueue dma buffers */
|
|
||||||
jz4740_pcm_enqueue(substream);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
@ -420,28 +201,15 @@ static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
prtd->state |= ST_RUNNING;
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
audio_start_dma(prtd, DMA_MODE_WRITE);
|
jz4740_pcm_start_transfer(prtd, substream->stream);
|
||||||
} else {
|
|
||||||
audio_start_dma(prtd, DMA_MODE_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
prtd->state &= ~ST_RUNNING;
|
jz4740_dma_disable(prtd->dma);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
|
||||||
printk(" RESUME \n");
|
|
||||||
break;
|
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
||||||
printk(" RESTART \n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
@ -449,69 +217,25 @@ static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static snd_pcm_uframes_t
|
static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream)
|
||||||
jz4740_pcm_pointer(struct snd_pcm_substream *substream)
|
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct jz4740_runtime_data *prtd = runtime->private_data;
|
struct jz4740_runtime_data *prtd = runtime->private_data;
|
||||||
struct jz4740_dma_buf_aic *aic_buf = prtd->curr;
|
unsigned long count, pos;
|
||||||
long count,res;
|
snd_pcm_uframes_t offset;
|
||||||
|
struct jz4740_dma_chan *dma = prtd->dma;
|
||||||
|
|
||||||
dma_addr_t ptr;
|
count = jz4740_dma_get_residue(dma);
|
||||||
snd_pcm_uframes_t x;
|
if (prtd->dma_pos == prtd->dma_start)
|
||||||
int channel = prtd->params->channel;
|
pos = prtd->dma_end - prtd->dma_start - count;
|
||||||
|
else
|
||||||
|
pos = prtd->dma_pos - prtd->dma_start - count;
|
||||||
|
|
||||||
spin_lock(&prtd->lock);
|
offset = bytes_to_frames(runtime, pos);
|
||||||
#if 1
|
if (offset >= runtime->buffer_size)
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
return offset;
|
||||||
count = get_dma_residue(channel);
|
|
||||||
count = aic_buf->size - count;
|
|
||||||
ptr = aic_buf->data + count;
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
} else {
|
|
||||||
count = get_dma_residue(channel);
|
|
||||||
count = aic_buf->size - count;
|
|
||||||
ptr = aic_buf->data + count;
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
# else
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) {
|
|
||||||
count = get_dma_residue(channel);
|
|
||||||
count = aic_buf->size - count;
|
|
||||||
ptr = aic_buf->data + count;
|
|
||||||
REG_DMAC_DSAR(channel) = ptr;
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
} else {
|
|
||||||
ptr = REG_DMAC_DSAR(channel);
|
|
||||||
if (ptr == 0x0)
|
|
||||||
printk("\ndma address is 00000000 in running!\n");
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) {
|
|
||||||
count = get_dma_residue(channel);
|
|
||||||
count = aic_buf->size - count;
|
|
||||||
ptr = aic_buf->data + count;
|
|
||||||
REG_DMAC_DTAR(channel) = ptr;
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
} else {
|
|
||||||
ptr = REG_DMAC_DTAR(channel);
|
|
||||||
if (ptr == 0x0)
|
|
||||||
printk("\ndma address is 00000000 in running!\n");
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
spin_unlock(&prtd->lock);
|
|
||||||
x = bytes_to_frames(runtime, res);
|
|
||||||
if (x == runtime->buffer_size)
|
|
||||||
x = 0;
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jz4740_pcm_open(struct snd_pcm_substream *substream)
|
static int jz4740_pcm_open(struct snd_pcm_substream *substream)
|
||||||
@ -519,18 +243,13 @@ static int jz4740_pcm_open(struct snd_pcm_substream *substream)
|
|||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct jz4740_runtime_data *prtd;
|
struct jz4740_runtime_data *prtd;
|
||||||
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
|
||||||
hw_params_cnt = 0;
|
|
||||||
#endif
|
|
||||||
snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
|
snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
|
||||||
prtd = kzalloc(sizeof(struct jz4740_runtime_data), GFP_KERNEL);
|
prtd = kzalloc(sizeof(struct jz4740_runtime_data), GFP_KERNEL);
|
||||||
|
|
||||||
if (prtd == NULL)
|
if (prtd == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_init(&prtd->lock);
|
|
||||||
|
|
||||||
runtime->private_data = prtd;
|
runtime->private_data = prtd;
|
||||||
REG_AIC_I2SCR = 0x10;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,30 +257,8 @@ static int jz4740_pcm_close(struct snd_pcm_substream *substream)
|
|||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct jz4740_runtime_data *prtd = runtime->private_data;
|
struct jz4740_runtime_data *prtd = runtime->private_data;
|
||||||
struct jz4740_dma_buf_aic *aic_buf = NULL;
|
|
||||||
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
|
||||||
hw_params_cnt = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (prtd)
|
|
||||||
aic_buf = prtd->curr;
|
|
||||||
|
|
||||||
while (aic_buf != NULL) {
|
|
||||||
prtd->curr = aic_buf->next;
|
|
||||||
prtd->next = aic_buf->next;
|
|
||||||
aic_buf->next = NULL;
|
|
||||||
kfree(aic_buf);
|
|
||||||
aic_buf = NULL;
|
|
||||||
aic_buf = prtd->curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prtd) {
|
|
||||||
prtd->curr = NULL;
|
|
||||||
prtd->next = NULL;
|
|
||||||
prtd->end = NULL;
|
|
||||||
kfree(prtd);
|
kfree(prtd);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -569,8 +266,6 @@ static int jz4740_pcm_close(struct snd_pcm_substream *substream)
|
|||||||
static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
|
static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
|
||||||
struct vm_area_struct *vma)
|
struct vm_area_struct *vma)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
|
|
||||||
return remap_pfn_range(vma, vma->vm_start,
|
return remap_pfn_range(vma, vma->vm_start,
|
||||||
substream->dma_buffer.addr >> PAGE_SHIFT,
|
substream->dma_buffer.addr >> PAGE_SHIFT,
|
||||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||||
@ -593,17 +288,18 @@ static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
|
|||||||
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
|
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
|
||||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||||
size_t size = jz4740_pcm_hardware.buffer_bytes_max;
|
size_t size = jz4740_pcm_hardware.buffer_bytes_max;
|
||||||
|
|
||||||
buf->dev.type = SNDRV_DMA_TYPE_DEV;
|
buf->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||||
buf->dev.dev = pcm->card->dev;
|
buf->dev.dev = pcm->card->dev;
|
||||||
buf->private_data = NULL;
|
buf->private_data = NULL;
|
||||||
|
|
||||||
/*buf->area = dma_alloc_coherent(pcm->card->dev, size,
|
|
||||||
&buf->addr, GFP_KERNEL);*/
|
|
||||||
buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
|
buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
|
||||||
&buf->addr, GFP_KERNEL);
|
&buf->addr, GFP_KERNEL);
|
||||||
if (!buf->area)
|
if (!buf->area)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
buf->bytes = size;
|
buf->bytes = size;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,10 +331,9 @@ int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
printk("pcm new\n");
|
|
||||||
|
|
||||||
if (!card->dev->dma_mask)
|
if (!card->dev->dma_mask)
|
||||||
card->dev->dma_mask = &jz4740_pcm_dmamask;
|
card->dev->dma_mask = &jz4740_pcm_dmamask;
|
||||||
|
|
||||||
if (!card->dev->coherent_dma_mask)
|
if (!card->dev->coherent_dma_mask)
|
||||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||||
|
|
||||||
@ -646,27 +341,26 @@ int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||||||
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
|
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
|
||||||
SNDRV_PCM_STREAM_PLAYBACK);
|
SNDRV_PCM_STREAM_PLAYBACK);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dai->capture.channels_min) {
|
if (dai->capture.channels_min) {
|
||||||
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
|
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
|
||||||
SNDRV_PCM_STREAM_CAPTURE);
|
SNDRV_PCM_STREAM_CAPTURE);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto err;
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
|
|
||||||
|
err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct snd_soc_platform jz4740_soc_platform = {
|
struct snd_soc_platform jz4740_soc_platform = {
|
||||||
.name = "jz4740-audio",
|
.name = "jz4740-pcm",
|
||||||
.pcm_ops = &jz4740_pcm_ops,
|
.pcm_ops = &jz4740_pcm_ops,
|
||||||
.pcm_new = jz4740_pcm_new,
|
.pcm_new = jz4740_pcm_new,
|
||||||
.pcm_free = jz4740_pcm_free_dma_buffers,
|
.pcm_free = jz4740_pcm_free_dma_buffers,
|
||||||
};
|
};
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(jz4740_soc_platform);
|
EXPORT_SYMBOL_GPL(jz4740_soc_platform);
|
||||||
|
|
||||||
static int __init jz4740_soc_platform_init(void)
|
static int __init jz4740_soc_platform_init(void)
|
||||||
@ -681,6 +375,6 @@ static void __exit jz4740_soc_platform_exit(void)
|
|||||||
}
|
}
|
||||||
module_exit(jz4740_soc_platform_exit);
|
module_exit(jz4740_soc_platform_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Richard");
|
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||||
MODULE_DESCRIPTION("Ingenic Jz4740 PCM DMA module");
|
MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -8,25 +8,6 @@
|
|||||||
#ifndef _JZ4740_PCM_H
|
#ifndef _JZ4740_PCM_H
|
||||||
#define _JZ4740_PCM_H
|
#define _JZ4740_PCM_H
|
||||||
|
|
||||||
#include <asm/mach-jz4740/dma.h>
|
|
||||||
|
|
||||||
#define ST_RUNNING (1<<0)
|
|
||||||
#define ST_OPENED (1<<1)
|
|
||||||
|
|
||||||
#define AIC_START_DMA (1<<0)
|
|
||||||
#define AIC_END_DMA (1<<1)
|
|
||||||
|
|
||||||
struct jz4740_dma_client {
|
|
||||||
char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct jz4740_pcm_dma_params {
|
|
||||||
struct jz4740_dma_client *client; /* stream identifier */
|
|
||||||
int channel; /* Channel ID */
|
|
||||||
dma_addr_t dma_addr;
|
|
||||||
int dma_size; /* Size of the DMA transfer */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* platform data */
|
/* platform data */
|
||||||
extern struct snd_soc_platform jz4740_soc_platform;
|
extern struct snd_soc_platform jz4740_soc_platform;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user