📄 mx27-wm8782-pcm.c.bak
字号:
s->periods++;
s->periods %= runtime->periods;
/*
* Give back to the CPU the access to the non cached memory
*/
dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
DMA_TO_DEVICE);
/*
* 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->substream);
spin_lock(&s->dma_lock);
/*
* Trig next DMA transfer
*/
audio_playback_dma(s);
spin_unlock(&s->dma_lock);
}
/*!
* This is a callback which will be called when a RX transfer finishes.
* The call occurs in interrupt context.
* @param substream pointer to the structure of the current stream.
*/
static void audio_capture_dma_callback(void *data, int error,
unsigned int count)
{
audio_stream_t *s;
snd_pcm_substream_t *substream;
snd_pcm_runtime_t *runtime;
unsigned int dma_size;
unsigned int previous_period;
unsigned int offset;
s = data;
substream = s->substream;
runtime = substream->runtime;
previous_period = s->periods;
dma_size = frames_to_bytes(runtime, runtime->period_size);
offset = dma_size * previous_period;
//ENTRY(0);
//printk("zd audio capture dma callback entry!\n");
s->tx_spin = 0;
s->periods++;
s->periods %= runtime->periods;
// printk("zd:audio capture dma callback s->periods=%d\n",s->periods);
/*
* Give back to the CPU the access to the non cached memory
*/
dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
DMA_FROM_DEVICE);
/*
* 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->substream);
spin_lock(&s->dma_lock);
/*
* Trig next DMA transfer
*/
audio_capture_dma(s);
spin_unlock(&s->dma_lock);
}
static int wm8782_pcm_prepare(struct snd_pcm_substream *substream)
{
//mx27_codec_t* codec = snd_pcm_substream_chip (substream);
//struct wm8782_platform_data * pdata = codec->pdata;
struct snd_pcm_runtime * runtime = substream->runtime;
int rate = runtime->rate;
// int sample_bits = runtime->sample_bits;
u16 srate = 0;//iface = 0;
int i = get_coeff(12000000,rate);
printk(KERN_INFO "%s\n",__FUNCTION__);
printk("zd:rate=%d\n", rate);
/*set inactive*/
// pdata->write(WM8782_ACTIVE, 0x0000);
/*set codec sampling rate*/
srate = (coeff_div[i].sr << 2) |
(coeff_div[i].bosr << 1) | coeff_div[i].usb;
// pdata->write(WM8782_SRATE, srate);
#if 0
iface = pdata->read(WM8782_IFACE);
iface &= ~(3<<2);
/* bit size */
switch (sample_bits) {
case 16:
iface |= 0x0000;
break;
case 20:
iface |= 0x0004;
break;
case 24:
iface |= 0x0008;
break;
case 32:
iface |= 0x000c;
break;
}
/* clock inversion */
//bclk don't inversion
/* set iface */
pdata->write(WM8782_IFACE, iface);
#endif
/* set active */
// pdata->write(WM8731_ACTIVE, 0x0001);
/*set output power on*/
//reg = pdata->read(WM8782_PWR);
//reg &= ~(1<<4);
//pdata->write(WM8782_PWR,reg);
return 0;
}
static int mx27_codec_open(snd_pcm_substream_t * substream)
{
mx27_codec_t* codec = snd_pcm_substream_chip (substream);
snd_pcm_runtime_t* runtime = substream->runtime;
int stream_id = substream->pstr->stream;
int result;
int err;
ENTRY (0);
// printk("%s\n",__FUNCTION__);
codec->s[stream_id].substream = substream;
if (stream_id == SNDRV_PCM_STREAM_PLAYBACK){
runtime->hw = mx27_codec_playback_hw;
if ((err =
configure_write_channel(&codec->s[SNDRV_PCM_STREAM_PLAYBACK],
audio_playback_dma_callback)) < 0)
return err;
}
else if(stream_id == SNDRV_PCM_STREAM_CAPTURE){
// printk("zd:mx27_codec_open!\n");
runtime->hw = mx27_codec_capture_hw;
if ((err =
configure_read_channel(&codec->s[SNDRV_PCM_STREAM_CAPTURE],
audio_capture_dma_callback)) < 0){
//printk("zd:configure read channel fail!\n");
return err;
}
}
else{
//printk("zd:stream_id fail!\n");
return -ENODEV;
}
result = snd_pcm_hw_constraint_integer(runtime,SNDRV_PCM_HW_PARAM_PERIODS);
if (result < 0)
return result;
// printk("zd:result before!\n");
result = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&hw_constraints_rates);
//printk("Zd:%d\n", result);
return result < 0 ? result : 0;
}
static int mx27_codec_close (snd_pcm_substream_t * substream)
{
mx27_codec_t* codec = snd_pcm_substream_chip (substream);
//struct wm8782_platform_data * pdata = codec->pdata;
int stream_id = substream->pstr->stream;
int channel=-1;
int result ;
ENTRY(1);
// printk("%s\n",__FUNCTION__);
codec->s[substream->pstr->stream].substream = NULL;
channel=codec->s[substream->pstr->stream].dma_channel;
result=mxc_dma_free(channel);
if (stream_id == SNDRV_PCM_STREAM_PLAYBACK){
ssi_interrupt_disable(SSI_CODEC, ssi_tx_dma_interrupt_enable);
ssi_interrupt_disable(SSI_CODEC, ssi_tx_fifo_0_empty);
ssi_transmit_enable(SSI_CODEC, 0);
ssi_tx_flush_fifo(SSI_CODEC);
}
if (stream_id == SNDRV_PCM_STREAM_CAPTURE){
//ssi_dump();
ssi_interrupt_disable(SSI_CODEC, ssi_rx_dma_interrupt_enable);
ssi_interrupt_disable(SSI_CODEC, ssi_rx_fifo_0_full);
ssi_receive_enable(SSI_CODEC,0);
ssi_rx_flush_fifo(SSI_CODEC);
}
//pdata->write(WM8782_ACTIVE,0x0000);
//ssi_dump();
return result < 0 ?result:0;
}
static int mx27_codec_hw_params (snd_pcm_substream_t* substream,
snd_pcm_hw_params_t* hw_params)
{
snd_pcm_runtime_t *runtime;
int result;
ENTRY (0);
runtime=substream->runtime;
//printk("%s\n",__FUNCTION__);
printk("dma_addr=%x\n",substream->runtime->dma_addr);
result = snd_pcm_lib_malloc_pages (substream,
params_buffer_bytes (hw_params));
if(result<0)
return result;
runtime->dma_addr = virt_to_phys(runtime->dma_area);
DBG(1,"%s: dma_area=%x ",__FUNCTION__, (int)substream->runtime->dma_area);
DBG(1,"dma_addr=%x,dma_bytes=%d\n",
substream->runtime->dma_addr,substream->runtime->dma_bytes);
return result;
}
static int mx27_codec_hw_free (snd_pcm_substream_t* substream)
{
ENTRY (0);
return snd_pcm_lib_free_pages (substream);
}
//start the codec.
static int mx27_codec_trigger(snd_pcm_substream_t* substream, int cmd)
{
mx27_codec_t* codec = snd_pcm_substream_chip (substream);
int stream_id = substream->pstr->stream;
audio_stream_t* s= &codec->s[stream_id];
int result = 0;
ENTRY (0);
#if 0
printk("%s\n",__FUNCTION__);
printk("rate=%d \n",substream->runtime->rate);
printk("channel=%d \n",substream->runtime->channels);
printk("frame_bits=%d \n",substream->runtime->frame_bits);
printk("sample_bits=%d \n",substream->runtime->sample_bits);
printk("periods=%d \n",substream->runtime->periods);
printk("period_size=%ld \n",substream->runtime->period_size);
printk("zd:s->period=%d\n",s->period);
printk("zd:s->periods=%d\n",s->periods);
printk("zd:s->active=%d\n",s->active);
printk("zd:s->dma_channel=%d\n",s->dma_channel);
printk("zd:s->tx_spin=%d\n",s->tx_spin);
printk("zd:s->active=%d\n",s->active);
#endif
DBG(0, "%s: trigger id %d cmd %d\n", __FUNCTION__, stream_id, cmd);
if(stream_id==0)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
DBG (1, "trigger start stream %d\n", stream_id);
s->tx_spin = 0;
s->active = 1;
audio_playback_dma(s);
break;
case SNDRV_PCM_TRIGGER_STOP:
DBG (1, "trigger stop entry\n");
s->tx_spin=0;
s->active=0;
audio_playback_stop_dma(s);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
break;
case SNDRV_PCM_TRIGGER_RESUME:
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
break;
default:
result = -EINVAL;
break;
}
if(stream_id==1)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
DBG (1, "trigger start stream %d\n", stream_id);
s->tx_spin = 0;
s->active = 1;
audio_capture_dma(s);
// sleep(10);
//ssi_dump();
break;
case SNDRV_PCM_TRIGGER_STOP:
DBG (1, "trigger stop\n");
s->tx_spin=0;
s->active=0;
audio_capture_stop_dma(s);
// ssi_dump();
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
break;
case SNDRV_PCM_TRIGGER_RESUME:
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
break;
default:
result = -EINVAL;
break;
}
return result;
}
static int mx27_codec_prepare (snd_pcm_substream_t* substream)
{
mx27_codec_t* codec = snd_pcm_substream_chip (substream);
//snd_pcm_runtime_t* runtime = substream->runtime;
audio_stream_t* s = &codec->s[substream->pstr->stream];
int id = substream->pstr->stream;
int channel = substream->runtime->channels;
ENTRY (0);
// printk("%s\n",__FUNCTION__);
s->period = 0;
s->periods = 0;
//ssi_receive_enable(SSI_CODEC, 0);
wm8782_pcm_prepare(substream);
// printk("zd:sub->runtime->channel=%d\n", channel);
// printk("zd:sample_bits=%d\n", runtime->sample_bits);
if(id==0){
printk("zd:it's playback!\n");
}
if(id==1){
#if 0
ssi_receive_enable(SSI_CODEC, 0);
if(runtime->sample_bits == 16)
{
ssi_tx_word_length(SSI_CODEC, ssi_16_bits);
ssi_rx_word_length(SSI_CODEC, ssi_16_bits);
}
if(runtime->sample_bits == 8)
{
ssi_tx_word_length(SSI_CODEC, ssi_8_bits);
ssi_rx_word_length(SSI_CODEC, ssi_8_bits);
}
#endif
ssi_receive_enable(SSI_CODEC, 0);
// printk("zd:codec prepare channel= %d\n", channel);
#if 0
if(channel == 1)
{
// ssi_rx_frame_rate(SSI_CODEC, 1);
mx27_i2s_normal_mode_config();
}
else
{
// ssi_rx_frame_rate(SSI_CODEC, 2);
mx27_i2s_slave_mode_config();
}
#endif
mx27_i2s_slave_mode_config();
ssi_interrupt_enable(SSI_CODEC, ssi_rx_dma_interrupt_enable);
ssi_interrupt_enable(SSI_CODEC, ssi_rx_fifo_0_full);
//ssi_interrupt_enable(SSI_CODEC, ssi_tx_dma_interrupt_enable); //add by zd
//ssi_interrupt_enable(SSI_CODEC, ssi_tx_fifo_0_empty); //add by zd
ssi_receive_enable(SSI_CODEC,1);
}
return 0;
}
static snd_pcm_uframes_t mx27_codec_pointer (snd_pcm_substream_t* substream)
{
mx27_codec_t* codec = snd_pcm_substream_chip (substream);
audio_stream_t* s = (audio_stream_t *)(&(codec->s[substream->pstr->stream]));
int stream_id=substream->pstr->stream;
unsigned int c=0;
ENTRY (3);
//printk("sisr=0x%x\n",__raw_readl(IO_ADDRESS(SSI1_BASE_ADDR)+MXC_SSISISR));
//printk("satag=0x%x\n",__raw_readl(IO_ADDRESS(SSI1_BASE_ADDR)+MXC_SSISATAG));
if(stream_id==0){
c = audio_get_playback_dma_pos(s);
DBG (3,"ID0 pos c=0x%x\n", c);
}
if(stream_id==1){
c = audio_get_capture_dma_pos(s);
DBG(3,"ID1 pos c=%x\n", c);
}
return c;
}
static snd_pcm_ops_t mx27_codec_playback_ops = {
.open = mx27_codec_open,
.close = mx27_codec_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = mx27_codec_hw_params,
.hw_free = mx27_codec_hw_free,
.prepare = mx27_codec_prepare,
.trigger = mx27_codec_trigger,
.pointer = mx27_codec_pointer,
};
static snd_pcm_ops_t mx27_codec_capture_ops = {
.open = mx27_codec_open,
.close = mx27_codec_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = mx27_codec_hw_params,
.hw_free = mx27_codec_hw_free,
.prepare = mx27_codec_prepare,
.trigger = mx27_codec_trigger,
.pointer = mx27_codec_pointer,
};
/* mx27_codec_pcm_init
performs the hardware initialization for the PCM device.
*/
int mx27_codec_pcm_init (mx27_codec_t* codec, int device)
{
snd_pcm_t* pcm;
int result = 0;
ENTRY (0);
result = snd_pcm_new (codec->card,
"mx27 PCM", device, 1, 1, &pcm);
if (result)
goto done;
snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK,
&mx27_codec_playback_ops);
snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_CAPTURE,
&mx27_codec_capture_ops);
snd_pcm_lib_preallocate_pages_for_all (pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
//((struct device *)(unsigned long)(GFP_KERNEL)),
snd_dma_continuous_data(GFP_KERNEL),
MAX_BUFFER_SIZE * 2 , MAX_BUFFER_SIZE * 2 );
pcm->private_data = codec;
pcm->info_flags = 0;
strcpy (pcm->name, "mx27 PCM");
mx27_codec_init (codec);
// audio_stream init
codec->pcm = pcm;
done:
return result;
}
EXPORT_SYMBOL_GPL(mx27_codec_pcm_init);
static int __init mx27_codec_driver_init (void)
{
printk(KERN_INFO "MXC-WM8782 PCM module loaded successfully\n");
// mx27_codec = kcalloc (1, sizeof (mx27_codec_t), GFP_KERNEL);
// if (mx27_codec == NULL)
// return -ENOMEM;
return 0;
}
static void __exit mx27_codec_driver_exit (void)
{
printk(KERN_INFO "MXC-WM8782 PCM module unloaded successfully\n");
// kfree(mx27_codec);
}
module_init(mx27_codec_driver_init);
module_exit(mx27_codec_driver_exit);
MODULE_AUTHOR("Sitek Hengke, Ltd");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("xtp-d501 driver for ALSA");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -