-
-/* rockchip_pcm_enqueue
- *
- * place a dma buffer onto the queue for the dma system
- * to handle.
-*/
-static void rockchip_pcm_enqueue(struct snd_pcm_substream *substream)
-{
- struct rockchip_runtime_data *prtd = substream->runtime->private_data;
- dma_addr_t pos = prtd->dma_pos;
- unsigned int limit;
- int ret;
-
- DBG("Enter::%s----%d prtd->dma_period = %d prtd->dma_limit = %d\n",__FUNCTION__,__LINE__,prtd->dma_period,prtd->dma_limit);
-
- if (rk29_dma_has_circular())
- limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
- else
- limit = prtd->dma_limit;
-
- if (DMA_INFIN_LOOP()) {
- if(prtd->dma_period % (prtd->params->dma_size*16)){
- printk("dma_period(%d) is not an integer multiple of dma_size(%d)",prtd->dma_period,prtd->params->dma_size*16);
- rk29_dma_config(prtd->params->channel,
- prtd->params->dma_size, 1);
- }
- else
- rk29_dma_config(prtd->params->channel,
- prtd->params->dma_size, 16);
- ret = rk29_dma_enqueue_ring(prtd->params->channel,
- substream, pos, prtd->dma_period, limit ,true);
- if (ret == 0)
- pos = prtd->dma_start;
- } else {
- while (prtd->dma_loaded < prtd->dma_limit) {
- unsigned long len = prtd->dma_period;
- // DBG("dma_loaded: %d\n", prtd->dma_loaded);
- if ((pos + len) > prtd->dma_end) {
- len = prtd->dma_end - pos;
- }
-
- if((len%(prtd->params->dma_size*16) == 0) && (prtd->params->flag == 1))
- {
- ret = rk29_dma_config(prtd->params->channel,
- prtd->params->dma_size, 16);
- prtd->params->flag = 0;
- DBG("size = 16, channel = %d, flag = %d\n",prtd->params->channel,prtd->params->flag);
- }
- else if((len%(prtd->params->dma_size*16) != 0) && (prtd->params->flag == 0))
- {
- ret = rk29_dma_config(prtd->params->channel,
- prtd->params->dma_size, 1);
- prtd->params->flag = 1;
- DBG("size = 1, channel = %d, flag = %d\n",prtd->params->channel,prtd->params->flag);
- }
-
- ret = rk29_dma_enqueue(prtd->params->channel,substream, pos, len);
- // if(prtd->params->channel == 2)
- DBG("Enter::%s, %d, ret=%d, Channel=%d, Addr=0x%X, Len=%lu\n",
- __FUNCTION__,__LINE__, ret, prtd->params->channel, 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;
-}
-
-void rk29_audio_buffdone(void *dev_id, int size,
- enum rk29_dma_buffresult result)
-{
- struct snd_pcm_substream *substream = dev_id;
- struct rockchip_runtime_data *prtd;
-#if PCM_DMA_DEBUG
- static ktime_t before = {0},after = {0};
- s64 t;
- before = after;
- after = ktime_get();
- t = ktime_to_us(ktime_sub(after, before));
- if(result == RK29_RES_OK)
- {
- if(t > prtd->dma_period/4/44100 +73 && t != ktime_to_us(after)) // (23220)4096/4/44100 + 32/44100
- {
- printk(KERN_DEBUG "Time out:: Audio DMA buffdone time out!!! the time = %lld!\n", t);
- }
- printk(KERN_DEBUG "audio DMA callback time = %lld\n", t);
- }
-// printk(KERN_DEBUG "a %d %d\n", size, result);
-#endif
- DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
-
- if (!substream){
- DBG("substream is free\n");
- return;
- }
- if (!substream->runtime){
- DBG("substream->runtime is free\n");
- return;
- }
- switch(result)
- {
- case RK29_RES_OK:
- break;
- case RK29_RES_ERR:
- case RK29_RES_ABORT:
- DBG("Enter::%s dma about or error result = %d \n",__FUNCTION__,result);
- return;
- }
-
- prtd = substream->runtime->private_data;
-
-// if(prtd->params->channel == 2)
- DBG("Enter::%s----%d channel =%d \n",__FUNCTION__,__LINE__,prtd->params->channel);
- if(!(prtd->state & ST_RUNNING))
- return;
- if (substream){
- snd_pcm_period_elapsed(substream);
- }
- spin_lock(&prtd->lock);
- if (!DMA_INFIN_LOOP() && prtd->state & ST_RUNNING) {
- prtd->dma_loaded--;
- rockchip_pcm_enqueue(substream);
- }
- spin_unlock(&prtd->lock);
-}
-
-static int rockchip_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct rockchip_runtime_data *prtd = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
- struct rockchip_pcm_dma_params *dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
- struct rockchip_pcm_dma_params *dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
-#else
- struct rockchip_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
-#endif
- unsigned long totbytes = params_buffer_bytes(params);
- int ret = 0;
-
- DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
- /* return if this is a bufferless transfer e.g.
- * codec <--> BT codec or GSM modem -- lg FIXME */
- if (!dma)
- return 0;
-
- /* this may get called several times by oss emulation
- * with different params -HW */
- if (prtd->params == NULL) {
- /* prepare DMA */
- prtd->params = dma;
-#ifdef CONFIG_SND_I2S_DMA_EVENT_DYNAMIC
- DBG("params %p, client %p, channel %d\n", prtd->params,prtd->params->client, prtd->params->channel);
- ret = rk29_dma_request(prtd->params->channel, prtd->params->client, NULL);
- DBG("Enter::%s, %d, ret=%d, Channel=%d\n", __FUNCTION__, __LINE__, ret, prtd->params->channel);
- if (ret) {
- DBG(KERN_ERR "failed to get dma channel\n");
- return ret;
- }
-#endif
- }
-
- ret = rk29_dma_set_buffdone_fn(prtd->params->channel, rk29_audio_buffdone);
- if(ret < 0){
- DBG(KERN_ERR "failed to rk29_dma_set_buffdone_fn\n");
- return ret;
- }
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
- runtime->dma_bytes = totbytes;
-
- spin_lock_irq(&prtd->lock);
- prtd->dma_loaded = 0;
- prtd->dma_limit = params_periods(params);//runtime->hw.periods_min;
- prtd->dma_period = params_period_bytes(params);
- prtd->dma_start = runtime->dma_addr;
- prtd->dma_pos = prtd->dma_start;
- prtd->dma_end = prtd->dma_start + prtd->dma_limit*prtd->dma_period;
- prtd->transfer_first = 1;
- prtd->curr = NULL;
- prtd->next = NULL;
- prtd->end = NULL;
- spin_unlock_irq(&prtd->lock);
- printk(KERN_DEBUG "i2s dma info:periodsize(%ld),limit(%d),buffersize(%d),over(%d)\n",
- prtd->dma_period,prtd->dma_limit,totbytes,totbytes-(prtd->dma_period*prtd->dma_limit));
- return ret;
-}
-
-static int rockchip_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- struct rockchip_runtime_data *prtd = substream->runtime->private_data;
-
- DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
- /* TODO - do we need to ensure DMA flushed */
- snd_pcm_set_runtime_buffer(substream, NULL);
-
- if (prtd->params) {
-#ifdef CONFIG_SND_I2S_DMA_EVENT_DYNAMIC
- rk29_dma_free(prtd->params->channel, prtd->params->client);
- prtd->params = NULL;
-#endif
- }
-
- return 0;
-}
-
-static int rockchip_pcm_prepare(struct snd_pcm_substream *substream)
-{
- struct rockchip_runtime_data *prtd = substream->runtime->private_data;
- int ret = 0;
-
- DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
-
- /* return if this is a bufferless transfer e.g.
- * codec <--> BT codec or GSM modem -- lg FIXME */
- if (!prtd->params)
- return 0;
-
- if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = rk29_dma_devconfig(prtd->params->channel,
- RK29_DMASRC_MEM,
- prtd->params->dma_addr);
- }else{
- ret = rk29_dma_devconfig(prtd->params->channel,
- RK29_DMASRC_HW,
- prtd->params->dma_addr);
- }
- DBG("Enter::%s, %d, ret=%d, Channel=%d, Addr=0x%X\n", __FUNCTION__, __LINE__, ret, prtd->params->channel, prtd->params->dma_addr);
- ret = rk29_dma_config(prtd->params->channel,
- prtd->params->dma_size, 1);
- prtd->params->flag = 1;
-
- DBG("Enter:%s, %d, ret = %d, Channel=%d, Size=%d\n",
- __FUNCTION__, __LINE__, ret, prtd->params->channel,
- prtd->params->dma_size);
-
- ret= rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_FLUSH);
- DBG("Enter:%s, %d, ret = %d, Channel=%d\n",
- __FUNCTION__, __LINE__, ret, prtd->params->channel);
-
- prtd->dma_loaded = 0;
- prtd->dma_pos = prtd->dma_start;
-
- /* enqueue dma buffers */
- rockchip_pcm_enqueue(substream);
- return ret;
-}
-
-static int rockchip_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct rockchip_runtime_data *prtd = substream->runtime->private_data;
- int ret = 0;
- /**************add by qiuen for volume*****/
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
- struct snd_soc_dai *pCodec_dai = rtd->codec_dai;
-#else
- struct snd_soc_dai *pCodec_dai = rtd->dai->codec_dai;
-#endif
- int vol = 0;
- int streamType = 0;
-
- DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
-
- if(cmd==SNDRV_PCM_TRIGGER_VOLUME){
- vol = substream->number % 100;
- streamType = (substream->number / 100) % 100;
- DBG("enter:vol=%d,streamType=%d\n",vol,streamType);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
- if(pCodec_dai->driver->ops->set_volume)
- pCodec_dai->driver->ops->set_volume(streamType, vol);
-#else
- if(pCodec_dai->ops->set_volume)
- pCodec_dai->ops->set_volume(streamType, vol);
-#endif
- }
- /****************************************************/
- spin_lock(&prtd->lock);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- DBG(" START \n");
- prtd->state |= ST_RUNNING;
- rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_START);
- break;
- case SNDRV_PCM_TRIGGER_RESUME:
- DBG(" RESUME \n");
- break;
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- DBG(" RESTART \n");
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- DBG(" STOPS \n");
- prtd->state &= ~ST_RUNNING;
- rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_STOP);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- spin_unlock(&prtd->lock);
- return ret;
-}
-
-
-static snd_pcm_uframes_t
-rockchip_pcm_pointer(struct snd_pcm_substream *substream)