static int aml_i2s_close(struct snd_pcm_substream *substream) { struct aml_runtime_data *prtd = substream->runtime->private_data; audio_stream_t *s = &prtd->s; ALSA_TRACE(); mutex_lock(&gate_mutex); audio_gate_status &= ~s->device_type; if (audio_gate_status == 0) { ALSA_DEBUG("aml_pcm_close device type %x \n", s->device_type); //audio_aiu_pg_enable(0); } mutex_unlock(&gate_mutex); // if(s->device_type == AML_AUDIO_SPDIFOUT) // WRITE_MPEG_REG_BITS( HHI_MPLL_CNTL8, 0,14, 1); #if USE_HRTIMER == 0 printk("aml_i2s_close device type %d \n", s->device_type); #ifdef USE_HW_TIMER snd_free_hw_timer_irq(prtd); #else del_timer_sync(&prtd->timer); #endif #else hrtimer_cancel(&prtd->hrtimer); #endif if (prtd) { kfree(prtd); prtd = NULL; substream->runtime->private_data = NULL; } return 0; }
static int aml_dai_spdif_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct aml_runtime_data *prtd = runtime->private_data; struct audio_stream *s; ALSA_TRACE(); if (!prtd) { prtd = (struct aml_runtime_data *) kzalloc(sizeof(struct aml_runtime_data), GFP_KERNEL); if (prtd == NULL) { pr_err("alloc aml_runtime_data error\n"); ret = -ENOMEM; goto out; } prtd->substream = substream; runtime->private_data = prtd; } s = &prtd->s; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s->device_type = AML_AUDIO_SPDIFOUT; /* audio_spdifout_pg_enable(1); */ /*aml_spdif_play_stop(); */ } else { s->device_type = AML_AUDIO_SPDIFIN; } return 0; out: return ret; }
} break; default: return -EINVAL; } return 0;
} static int aml_dai_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct aml_runtime_data *prtd = (struct aml_runtime_data *)runtime->private_data; audio_stream_t *s; ALSA_TRACE(); if (prtd == NULL) { prtd = (struct aml_runtime_data *) kzalloc(sizeof(struct aml_runtime_data), GFP_KERNEL); if (prtd == NULL) { printk("alloc aml_runtime_data error\n"); ret = -ENOMEM; goto out; } prtd->substream = substream; runtime->private_data = prtd; } s = &prtd->s; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s->device_type = AML_AUDIO_I2SOUT; } else { s->device_type = AML_AUDIO_I2SIN; } return 0; out:
static void aml_dai_spdif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; /* struct snd_dma_buffer *buf = &substream->dma_buffer; */ ALSA_TRACE(); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { memset((void *)runtime->dma_area, 0, snd_pcm_lib_buffer_bytes(substream)); if (IEC958_mode_codec == 6) { printk ("[%s %d]8chPCM output:disable aml_spdif_play()\n", __func__, __LINE__); } else { aml_spdif_play(); } /* audio_spdifout_pg_enable(0); */ } } static int aml_dai_spdif_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {
static int aml_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *rtd = substream->runtime; struct aml_runtime_data *prtd = rtd->private_data; audio_stream_t *s = &prtd->s; int ret = 0; ALSA_TRACE(); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: #if USE_HRTIMER == 0 del_timer_sync(&prtd->timer); #endif spin_lock(&s->lock); #if USE_HRTIMER == 0 prtd->timer.expires = jiffies + 1; del_timer(&prtd->timer); add_timer(&prtd->timer); #endif s->xrun_num = 0; s->active = 1; spin_unlock(&s->lock); break; /* SNDRV_PCM_TRIGGER_START */ case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: // TODO spin_lock(&s->lock); s->active = 0; s->xrun_num = 0; spin_unlock(&s->lock); break; default: ret = -EINVAL; } /* if(clock_gating_status&clock_gating_playback){ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) aml_pcm_work.substream = substream; } else aml_pcm_work.substream = substream; if(clock_gating_status) { schedule_work(&aml_pcm_work.aml_codec_workqueue); } */ //schedule_work(&aml_pcm_work.aml_codec_workqueue); return ret; }
struct snd_pcm_runtime *runtime = substream->runtime; /* struct aml_runtime_data *prtd = runtime->private_data; */ /* audio_stream_t *s = &prtd->s; */ ALSA_TRACE(); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { aml_hw_iec958_init(substream); } else { audio_in_spdif_set_buf(runtime->dma_addr, runtime->dma_bytes * 2); memset((void *)runtime->dma_area, 0, runtime->dma_bytes * 2);
WRITE_MPEG_REG(AIU_958_CHSTAT_R0, 0x1902); WRITE_MPEG_REG(AIU_958_CHSTAT_R1, 0x900); aout_notifier_call_chain(AOUT_EVENT_RAWDATA_MAT_MLP, substream); } else { aout_notifier_call_chain(AOUT_EVENT_IEC_60958_PCM, substream); } ALSA_PRINT("spdif dma %x,phy addr %x\n", (unsigned)runtime->dma_area, (unsigned)runtime->dma_addr); }
static int aml_dai_spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { #if 0 int srate; srate = params_rate(params); aml_set_spdif_clk(srate * 512, 0); #endif ALSA_TRACE(); return 0; }
static int aml_i2s_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct aml_runtime_data *prtd = runtime->private_data; audio_stream_t *s = &prtd->s; ALSA_TRACE(); if (s && s->device_type == AML_AUDIO_I2SOUT && trigger_underrun) { printk("clear i2s out trigger underrun \n"); trigger_underrun = 0; } return 0; }
__LINE__); aout_notifier_call_chain(AOUT_EVENT_IEC_60958_PCM, substream); } return 0; } static int aml_dai_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_pcm_runtime *rtd = substream->runtime; int *ppp = NULL; ALSA_TRACE(); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* TODO */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ALSA_PRINT("aiu i2s playback enable\n\n"); audio_out_i2s_enable(1); if (IEC958_mode_codec == 0) { ALSA_PRINT("audio_hw_958_enable 1\n"); audio_hw_958_enable(1); } } else { audio_in_i2s_enable(1); ppp = (int *)(rtd->dma_area + rtd->dma_bytes * 2 - 8); ppp[0] = 0x78787878; ppp[1] = 0x78787878; } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ALSA_PRINT("aiu i2s playback disable\n\n"); audio_out_i2s_enable(0); if (IEC958_mode_codec == 0) { ALSA_PRINT("audio_hw_958_enable 0\n"); audio_hw_958_enable(0); } } else {
static int aml_dai_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { ALSA_TRACE(); return 0; } static int aml_dai_set_i2s_fmt(struct snd_soc_dai *dai, unsigned int fmt) { ALSA_TRACE(); if (fmt & SND_SOC_DAIFMT_CBS_CFS) /* slave mode */ dai_info[dai->id].i2s_mode = I2S_SLAVE_MODE; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: i2s_pos_sync = 0;
printk("alloc aml_runtime_data error\n"); ret = -ENOMEM; goto out; } prtd->substream = substream; runtime->private_data = prtd; } s = &prtd->s; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s->device_type = AML_AUDIO_SPDIFOUT; audio_spdifout_pg_enable(1); /* aml_spdif_play_stop(); */ } else { s->device_type = AML_AUDIO_SPDIFIN; } return 0; out: return ret; }
ALSA_TRACE(); return 0; } static int aml_dai_spdif_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = NULL; ALSA_TRACE(); rtd = (struct snd_soc_pcm_runtime *)substream->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ALSA_PRINT("aiu 958 playback enable\n"); audio_hw_958_enable(1); } else { ALSA_PRINT("spdif in capture enable\n"); audio_in_spdif_enable(1); } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ALSA_PRINT("aiu 958 playback disable\n"); audio_hw_958_enable(0); } else { ALSA_PRINT("spdif in capture disable\n"); audio_in_spdif_enable(0); } break; default: return -EINVAL;
extern void aml_hw_iec958_init(struct snd_pcm_substream *substream); static int aml_dai_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct aml_runtime_data *prtd = runtime->private_data; struct aml_i2s *i2s = snd_soc_dai_get_drvdata(dai); int audio_clk_config = AUDIO_CLK_FREQ_48; audio_stream_t *s = &prtd->s; ALSA_TRACE(); switch (runtime->rate) { case 192000: audio_clk_config = AUDIO_CLK_FREQ_192; break; case 176400: audio_clk_config = AUDIO_CLK_FREQ_1764; break; case 96000: audio_clk_config = AUDIO_CLK_FREQ_96; break; case 88200: audio_clk_config = AUDIO_CLK_FREQ_882; break; case 48000: audio_clk_config = AUDIO_CLK_FREQ_48; break; case 44100: audio_clk_config = AUDIO_CLK_FREQ_441; break; case 32000: audio_clk_config = AUDIO_CLK_FREQ_32; break; case 8000: audio_clk_config = AUDIO_CLK_FREQ_8; break; case 11025: audio_clk_config = AUDIO_CLK_FREQ_11; break; case 16000: audio_clk_config = AUDIO_CLK_FREQ_16; break; case 22050: audio_clk_config = AUDIO_CLK_FREQ_22; break; case 12000: audio_clk_config = AUDIO_CLK_FREQ_12; break; case 24000: audio_clk_config = AUDIO_CLK_FREQ_22; break; default: audio_clk_config = AUDIO_CLK_FREQ_441; break; }; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) audio_out_i2s_enable(0); if (i2s->old_samplerate != runtime->rate) { ALSA_PRINT("enterd %s,old_samplerate:%d,sample_rate=%d\n", __func__, i2s->old_samplerate, runtime->rate); i2s->old_samplerate = runtime->rate; audio_set_i2s_clk(audio_clk_config, AUDIO_CLK_256FS, i2s->mpll); } audio_util_set_dac_i2s_format(AUDIO_ALGOUT_DAC_FORMAT_DSP); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { s->i2s_mode = dai_info[dai->id].i2s_mode; audio_in_i2s_set_buf(runtime->dma_addr, runtime->dma_bytes * 2, 0, i2s_pos_sync); memset((void *)runtime->dma_area, 0, runtime->dma_bytes * 2); { int *ppp = (int *)(runtime->dma_area + runtime->dma_bytes * 2 - 8); ppp[0] = 0x78787878; ppp[1] = 0x78787878; } s->device_type = AML_AUDIO_I2SIN; } else { s->device_type = AML_AUDIO_I2SOUT; aml_hw_i2s_init(runtime); /* i2s/958 share the same audio hw buffer when PCM mode */ if (IEC958_mode_codec == 0) { aml_hw_iec958_init(substream); /* use the hw same sync for i2s/958 */ WRITE_MPEG_REG_BITS(AIU_I2S_MISC, 1, 3, 1); } else WRITE_MPEG_REG_BITS(AIU_I2S_MISC, 0, 3, 1); } if (runtime->channels == 8) {
static int aml_i2s_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct aml_runtime_data *prtd = runtime->private_data; struct snd_dma_buffer *buf = &substream->dma_buffer; audio_stream_t *s = &prtd->s; int ret = 0; ALSA_TRACE(); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { snd_soc_set_runtime_hwparams(substream, &aml_i2s_hardware); if (s->device_type == AML_AUDIO_I2SOUT) { aml_i2s_playback_start_addr = (unsigned int)buf->area; aml_i2s_playback_phy_start_addr = buf->addr; } } else { snd_soc_set_runtime_hwparams(substream, &aml_i2s_capture); if (s->device_type == AML_AUDIO_I2SIN) { aml_i2s_capture_start_addr = (unsigned int)buf->area; aml_i2s_capture_phy_start_addr = buf->addr; } } /* ensure that peroid size is a multiple of 32bytes */ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_sizes); if (ret < 0) { printk("set period bytes constraint error\n"); goto out; } /* ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) { printk("set period error\n"); goto out; } if (!prtd) { prtd = kzalloc(sizeof(struct aml_runtime_data), GFP_KERNEL); if (prtd == NULL) { printk("alloc aml_runtime_data error\n"); ret = -ENOMEM; goto out; } prtd->substream = substream; runtime->private_data = prtd; g_prtd = prtd; printk("ml_i2s_open g_prtd %p \n", g_prtd); } else { g_prtd = prtd; } // WRITE_MPEG_REG_BITS( HHI_MPLL_CNTL8, 1,14, 1); #if USE_HRTIMER == 0 #ifndef USE_HW_TIMER prtd->timer.function = &aml_i2s_timer_callback; prtd->timer.data = (unsigned long)substream; init_timer(&prtd->timer); #else ret = snd_request_hw_timer(prtd); if (ret < 0) { printk("request audio hw timer failed \n"); goto out; } #endif #else hrtimer_init(&prtd->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); prtd->hrtimer.function = aml_i2s_hrtimer_callback; hrtimer_start(&prtd->hrtimer, ns_to_ktime(HRTIMER_PERIOD), HRTIMER_MODE_REL); printk("hrtimer inited..\n"); #endif spin_lock_init(&prtd->s.lock); s = &prtd->s; //WRITE_MPEG_REG_BITS(MPLL_I2S_CNTL, 1,14, 1); mutex_lock(&gate_mutex); if (!num_clk_gate) { num_clk_gate = 1; if (audio_gate_status == 0) { // audio_aiu_pg_enable(1); ALSA_DEBUG("aml_pcm_open device type %x \n", s->device_type); } } audio_gate_status |= s->device_type; mutex_unlock(&gate_mutex); out: return ret; }
static int aml_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *rtd = substream->runtime; struct aml_runtime_data *prtd = rtd->private_data; audio_stream_t *s = &prtd->s; int ret = 0; unsigned int pts_audio, pts_scr; unsigned int diff = 0; int sync_mode; ALSA_TRACE(); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: #if USE_HRTIMER == 0 && !defined(USE_HW_TIMER) del_timer_sync(&prtd->timer); #endif spin_lock(&s->lock); #if USE_HRTIMER == 0 && !defined(USE_HW_TIMER) prtd->timer.expires = jiffies + 1; del_timer(&prtd->timer); add_timer(&prtd->timer); #endif pts_audio = tsync_get_firstapts(); pts_scr = timestamp_pcrscr_get(); sync_mode = tsync_get_mode(); #if 1 if (pts_audio > pts_scr) diff = pts_audio - pts_scr; else diff = pts_scr - pts_audio; if (IEC958_mode_codec == 0 && sync_mode == TSYNC_MODE_PCRMASTER && pts_audio > pts_scr && (pts_audio - pts_scr) < 90 * MAX_APTS_SCR_DELTA) { printk("aiu i2s playback enable trigger mode sync_mode %d audio %x pcr %x diff %d \n", sync_mode, pts_audio, pts_scr, diff); s->audio_trigger_disable = 1; } else #endif { printk("aiu i2s/958 playback enable sync_mode %d audio %x pcr %x diff %d IEC958_mode_codec %d\n", sync_mode, pts_audio, pts_scr, diff, IEC958_mode_codec); s->disable_count = 0; s->audio_trigger_disable = 0; if (IEC958_mode_codec == 0) { printk("aiu i2s/958 playback enable sync_mode %d audio %x pcr %x diff %d \n", sync_mode, pts_audio, pts_scr, diff); audio_out_i2s_enable(1); audio_hw_958_enable(1); } } s->active = 1; spin_unlock(&s->lock); break; /* SNDRV_PCM_TRIGGER_START */ case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: // TODO spin_lock(&s->lock); s->audio_trigger_disable = 0; s->disable_count = 0; if (IEC958_mode_codec == 0) { printk("aiu i2s playback disable\n"); audio_out_i2s_enable(0); printk("aiu 958 playback disable\n"); audio_hw_958_enable(0); } s->active = 0; spin_unlock(&s->lock); break; default: ret = -EINVAL; } /* if(clock_gating_status&clock_gating_playback){ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) aml_pcm_work.substream = substream; } else aml_pcm_work.substream = substream; if (clock_gating_status) { schedule_work(&aml_pcm_work.aml_codec_workqueue); } */ //schedule_work(&aml_pcm_work.aml_codec_workqueue); return ret; }
static int aml_dai_set_i2s_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { ALSA_TRACE();
/*--------------------------------------------------------------------------*\ * Helper functions \*--------------------------------------------------------------------------*/ static int aml_i2s_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; struct aml_audio_buffer *tmp_buf = NULL; size_t size = 0; tmp_buf = kzalloc(sizeof(struct aml_audio_buffer), GFP_KERNEL); if (tmp_buf == NULL) { printk("alloc tmp buffer struct error\n"); return -ENOMEM; } buf->private_data = tmp_buf; ALSA_TRACE(); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { //malloc DMA buffer size = aml_i2s_hardware.buffer_bytes_max; buf->dev.type = SNDRV_DMA_TYPE_DEV; buf->dev.dev = pcm->card->dev; /* one size for i2s output, another for 958, and 128 for alignment */ buf->area = dma_alloc_coherent(pcm->card->dev, size + 4096, &buf->addr, GFP_KERNEL); printk("aml-i2s %d:" "playback preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", stream, (void *) buf->area, (void *) buf->addr, size); if (!buf->area) { printk("alloc playback DMA buffer error\n"); kfree(tmp_buf); buf->private_data = NULL; return -ENOMEM; } //malloc tmp buffer size = aml_i2s_hardware.period_bytes_max; tmp_buf->buffer_start = (void *)kzalloc(size, GFP_KERNEL); if (tmp_buf->buffer_start == NULL) { printk("alloc playback tmp buffer error\n"); kfree(tmp_buf); buf->private_data = NULL; return -ENOMEM; } tmp_buf->buffer_size = size; } else { //malloc DMA buffer size = aml_i2s_capture.buffer_bytes_max; buf->dev.type = SNDRV_DMA_TYPE_DEV; buf->dev.dev = pcm->card->dev; buf->area = dma_alloc_coherent(pcm->card->dev, size * 2, &buf->addr, GFP_KERNEL); printk("aml-i2s %d:" "capture preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", stream, (void *) buf->area, (void *) buf->addr, size); if (!buf->area) { printk("alloc capture DMA buffer error\n"); kfree(tmp_buf); buf->private_data = NULL; return -ENOMEM; } //malloc tmp buffer size = aml_i2s_capture.period_bytes_max; tmp_buf->buffer_start = (void *)kzalloc(size, GFP_KERNEL); if (tmp_buf->buffer_start == NULL) { printk("alloc capture tmp buffer error\n"); kfree(tmp_buf); buf->private_data = NULL; return -ENOMEM; } tmp_buf->buffer_size = size; } buf->bytes = size; return 0; }
audio_spdifout_pg_enable(1); audio_hw_958_enable(1); } static int aml_dai_spdif_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir)
return 0; } static int aml_dai_spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
int *ppp = (int *)(runtime->dma_area + runtime->dma_bytes * 2 - 8); ppp[0] = 0x78787878; ppp[1] = 0x78787878; }
} #ifdef CONFIG_PM static int aml_dai_i2s_suspend(struct snd_soc_dai *dai) {
static int aml_i2s_prepare(struct snd_pcm_substream *substream) { ALSA_TRACE(); return 0; }