SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE),}, .capture = {
__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 {
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;
/* the I2S hw and IEC958 PCM output initation,958 initation here, for the case that only use our ALSA driver for PCM s/pdif output. */ static void aml_hw_i2s_init(struct snd_pcm_runtime *runtime) { unsigned i2s_mode = AIU_I2S_MODE_PCM16; switch (runtime->format) { case SNDRV_PCM_FORMAT_S32_LE: i2s_mode = AIU_I2S_MODE_PCM32; break; case SNDRV_PCM_FORMAT_S24_LE: i2s_mode = AIU_I2S_MODE_PCM24; break; case SNDRV_PCM_FORMAT_S16_LE: i2s_mode = AIU_I2S_MODE_PCM16; break; } audio_set_i2s_mode(i2s_mode); audio_set_aiubuf(runtime->dma_addr, runtime->dma_bytes, runtime->channels); ALSA_PRINT("i2s dma %x,phy addr %x,mode %d,ch %d \n", (unsigned)runtime->dma_area, (unsigned)runtime->dma_addr, i2s_mode, runtime->channels);
void aml_spdif_play(void) { _aiu_958_raw_setting_t set; _aiu_958_channel_status_t chstat; struct snd_pcm_substream substream; struct snd_pcm_runtime runtime; substream.runtime = &runtime; runtime.rate = 48000; runtime.format = SNDRV_PCM_FORMAT_S16_LE; runtime.channels = 2; runtime.sample_bits = 16; memset((void *)(&set), 0, sizeof(set)); memset((void *)(&chstat), 0, sizeof(chstat)); set.chan_stat = &chstat; set.chan_stat->chstat0_l = 0x0100; set.chan_stat->chstat0_r = 0x0100; set.chan_stat->chstat1_l = 0X200; set.chan_stat->chstat1_r = 0X200; audio_hw_958_enable(0); if (last_iec_clock != AUDIO_CLK_FREQ_48) { ALSA_PRINT("enterd %s,set_clock:%d,sample_rate=%d\n", __func__, last_iec_clock, AUDIO_CLK_FREQ_48); last_iec_clock = AUDIO_CLK_FREQ_48; audio_set_958_clk(AUDIO_CLK_FREQ_48, AUDIO_CLK_256FS); } audio_util_set_dac_958_format(AUDIO_ALGOUT_DAC_FORMAT_DSP); memset(iec958buf, 0, sizeof(iec958buf)); audio_set_958outbuf((virt_to_phys(iec958buf) + 63) & (~63), 128, 2, 0); audio_set_958_mode(AIU_958_MODE_PCM16, &set); #if OVERCLOCK == 1 || IEC958_OVERCLOCK == 1 WRITE_MPEG_REG_BITS(AIU_CLK_CTRL, 3, 4, 2); /* 512fs divide 4 == 128fs */ #else WRITE_MPEG_REG_BITS(AIU_CLK_CTRL, 1, 4, 2); /* 256fs divide 2 == 128fs */ #endif aout_notifier_call_chain(AOUT_EVENT_IEC_60958_PCM, &substream);
}; EXPORT_SYMBOL_GPL(aml_i2s_dai); static const struct snd_soc_component_driver aml_component = { .name = "aml-i2s-dai", }; static int aml_i2s_dai_probe(struct platform_device *pdev) { struct aml_i2s *i2s = NULL; int ret = 0; printk(KERN_DEBUG "enter %s\n", __func__); i2s = kzalloc(sizeof(struct aml_i2s), GFP_KERNEL); if (!i2s) { dev_err(&pdev->dev, "Can't allocate aml_i2s\n"); ret = -ENOMEM; goto exit; } dev_set_drvdata(&pdev->dev, i2s); if (of_property_read_u32(pdev->dev.of_node, "clk_src_mpll", &i2s->mpll)) { printk(KERN_INFO "i2s get no clk src setting in dts, use the default mpll 0\n"); i2s->mpll = 0; } /* enable i2s MPLL and power gate first */ WRITE_MPEG_REG_BITS(MPLL_I2S_CNTL, 1, 14, 1); audio_aiu_pg_enable(1); /* enable the mclk because m8 codec need it to setup */ if (i2s->old_samplerate != 48000) { ALSA_PRINT("enterd %s,old_samplerate:%d,sample_rate=%d\n", __func__, i2s->old_samplerate, 48000);
static int aml_dai_spdif_remove(struct platform_device *pdev) { snd_soc_unregister_component(&pdev->dev); return 0; }
1)NONE-PCM raw output ,only available when ac3/dts audio,when raw output mode is selected by user. 2)PCM output for all audio, when pcm mode is selected by user . 3)PCM output for audios except ac3/dts,when raw output mode is selected by user */ void aml_hw_iec958_init(struct snd_pcm_substream *substream) { _aiu_958_raw_setting_t set; _aiu_958_channel_status_t chstat; unsigned i2s_mode, iec958_mode; unsigned start, size; int sample_rate; struct snd_dma_buffer *buf = &substream->dma_buffer; struct snd_pcm_runtime *runtime = substream->runtime; if (buf == NULL && runtime == NULL) { printk("buf/0x%x runtime/0x%x\n", (unsigned)buf, (unsigned)runtime); return; } i2s_mode = AIU_I2S_MODE_PCM16; sample_rate = AUDIO_CLK_FREQ_48; memset((void *)(&set), 0, sizeof(set)); memset((void *)(&chstat), 0, sizeof(chstat)); set.chan_stat = &chstat; printk("----aml_hw_iec958_init,runtime->rate=%d--\n", runtime->rate); switch (runtime->rate) { case 192000: sample_rate = AUDIO_CLK_FREQ_192; break; case 176400: sample_rate = AUDIO_CLK_FREQ_1764; break; case 96000: sample_rate = AUDIO_CLK_FREQ_96; break; case 88200: sample_rate = AUDIO_CLK_FREQ_882; break; case 48000: sample_rate = AUDIO_CLK_FREQ_48; break; case 44100: sample_rate = AUDIO_CLK_FREQ_441; break; case 32000: sample_rate = AUDIO_CLK_FREQ_32; break; case 8000: sample_rate = AUDIO_CLK_FREQ_8; break; case 11025: sample_rate = AUDIO_CLK_FREQ_11; break; case 16000: sample_rate = AUDIO_CLK_FREQ_16; break; case 22050: sample_rate = AUDIO_CLK_FREQ_22; break; case 12000: sample_rate = AUDIO_CLK_FREQ_12; break; case 24000: sample_rate = AUDIO_CLK_FREQ_22; break; default: sample_rate = AUDIO_CLK_FREQ_441; break; }; audio_hw_958_enable(0); if (last_iec_clock != sample_rate) { ALSA_PRINT("enterd %s,set_clock:%d,sample_rate=%d\n", __func__, last_iec_clock, sample_rate); last_iec_clock = sample_rate; audio_set_958_clk(sample_rate, AUDIO_CLK_256FS); } printk("----aml_hw_iec958_init,runtime->rate=%d,sample_rate=%d--\n", runtime->rate, sample_rate); audio_util_set_dac_958_format(AUDIO_ALGOUT_DAC_FORMAT_DSP); /*clear the same source function as new raw data output */ WRITE_MPEG_REG_BITS(AIU_I2S_MISC, 0, 3, 1); switch (runtime->format) { case SNDRV_PCM_FORMAT_S32_LE: i2s_mode = AIU_I2S_MODE_PCM32; break; case SNDRV_PCM_FORMAT_S24_LE: i2s_mode = AIU_I2S_MODE_PCM24; break; case SNDRV_PCM_FORMAT_S16_LE: i2s_mode = AIU_I2S_MODE_PCM16; break; } /* audio_set_i2s_mode(i2s_mode); */ /* case 1,raw mode enabled */ if (IEC958_mode_codec) { if (IEC958_mode_codec == 1) { /* dts, use raw sync-word mode */ iec958_mode = AIU_958_MODE_RAW; printk("iec958 mode RAW\n"); } else { /* ac3,use the same pcm mode as i2s configuration */ iec958_mode = AIU_958_MODE_PCM_RAW; printk("iec958 mode %s\n", (i2s_mode == AIU_I2S_MODE_PCM32) ? "PCM32_RAW" : ((I2S_MODE == AIU_I2S_MODE_PCM24) ? "PCM24_RAW" : "PCM16_RAW")); } } else { if (i2s_mode == AIU_I2S_MODE_PCM32) iec958_mode = AIU_958_MODE_PCM32; else if (i2s_mode == AIU_I2S_MODE_PCM24) iec958_mode = AIU_958_MODE_PCM24; else iec958_mode = AIU_958_MODE_PCM16; printk("iec958 mode %s\n", (i2s_mode == AIU_I2S_MODE_PCM32) ? "PCM32" : ((i2s_mode == AIU_I2S_MODE_PCM24) ? "PCM24" : "PCM16")); } if (iec958_mode == AIU_958_MODE_PCM16 || iec958_mode == AIU_958_MODE_PCM24 || iec958_mode == AIU_958_MODE_PCM32) { set.chan_stat->chstat0_l = 0x0100; set.chan_stat->chstat0_r = 0x0100; set.chan_stat->chstat1_l = 0x200; set.chan_stat->chstat1_r = 0x200; if (sample_rate == AUDIO_CLK_FREQ_882) { printk("----sample_rate==AUDIO_CLK_FREQ_882---\n"); set.chan_stat->chstat1_l = 0x800; set.chan_stat->chstat1_r = 0x800; } if (sample_rate == AUDIO_CLK_FREQ_96) { printk("----sample_rate==AUDIO_CLK_FREQ_96---\n"); set.chan_stat->chstat1_l = 0xa00; set.chan_stat->chstat1_r = 0xa00; } start = buf->addr; size = snd_pcm_lib_buffer_bytes(substream); audio_set_958outbuf(start, size, runtime->channels, 0); /* audio_set_i2s_mode(AIU_I2S_MODE_PCM16); */ /* audio_set_aiubuf(start, size); */ } else { set.chan_stat->chstat0_l = 0x1902; set.chan_stat->chstat0_r = 0x1902; if (IEC958_mode_codec == 4 || IEC958_mode_codec == 5) { /* DD+ */ if (runtime->rate == 32000) { set.chan_stat->chstat1_l = 0x300; set.chan_stat->chstat1_r = 0x300; } else if (runtime->rate == 44100) { set.chan_stat->chstat1_l = 0xc00; set.chan_stat->chstat1_r = 0xc00; } else { set.chan_stat->chstat1_l = 0Xe00; set.chan_stat->chstat1_r = 0Xe00; } } else { /* DTS,DD */ if (runtime->rate == 32000) { set.chan_stat->chstat1_l = 0x300; set.chan_stat->chstat1_r = 0x300; } else if (runtime->rate == 44100) { set.chan_stat->chstat1_l = 0; set.chan_stat->chstat1_r = 0; } else { set.chan_stat->chstat1_l = 0x200; set.chan_stat->chstat1_r = 0x200; } } start = buf->addr; size = snd_pcm_lib_buffer_bytes(substream); audio_set_958outbuf(start, size, runtime->channels, (iec958_mode == AIU_958_MODE_RAW) ? 1 : 0); memset((void *)buf->area, 0, size); } ALSA_DEBUG("aiu 958 pcm buffer size %d \n", size); audio_set_958_mode(iec958_mode, &set); if (IEC958_mode_codec == 4 || IEC958_mode_codec == 5 || IEC958_mode_codec == 7 || IEC958_mode_codec == 8) { WRITE_MPEG_REG_BITS(AIU_CLK_CTRL, 0, 4, 2); /* 4x than i2s */ printk("IEC958_mode_codec/%d 4x than i2s\n", IEC958_mode_codec); } else { #if OVERCLOCK == 1 || IEC958_OVERCLOCK == 1 WRITE_MPEG_REG_BITS(AIU_CLK_CTRL, 3, 4, 2); /* 512fs divide 4 == 128fs */ #else WRITE_MPEG_REG_BITS(AIU_CLK_CTRL, 1, 4, 2); /* 256fs divide 2 == 128fs */ #endif } if (IEC958_mode_codec == 2) { aout_notifier_call_chain(AOUT_EVENT_RAWDATA_AC_3, substream); } else if (IEC958_mode_codec == 3) { aout_notifier_call_chain(AOUT_EVENT_RAWDATA_DTS, substream); } else if (IEC958_mode_codec == 4) { aout_notifier_call_chain(AOUT_EVENT_RAWDATA_DOBLY_DIGITAL_PLUS,
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) {