void aml_spdif_play(void)
{
#if 1
	struct _aiu_958_raw_setting_t set;
	struct _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 (old_samplerate != AUDIO_CLK_FREQ_48) {
		pr_info("enterd %s,set_clock:%d,sample_rate=%d\n",
		__func__, old_samplerate, AUDIO_CLK_FREQ_48);
		old_samplerate = AUDIO_CLK_FREQ_48;
		aml_set_spdif_clk(48000 * 512, 0);
	}
	/* Todo, div can be changed, for most case, div = 2 */
	/* audio_set_spdif_clk_div(); */
	/* 958 divisor: 0=no div; 1=div by 2; 2=div by 3; 3=div by 4. */
	if (IEC958_mode_codec == 4  || IEC958_mode_codec == 5 ||
	IEC958_mode_codec == 7 || IEC958_mode_codec == 8) {
		pr_info("set 4x audio clk for 958\n");
		aml_cbus_update_bits(AIU_CLK_CTRL, 3 << 4, 0 << 4);
	} else if (0) {
		pr_info("share the same clock\n");
		aml_cbus_update_bits(AIU_CLK_CTRL, 3 << 4, 1 << 4);
	} else {
		pr_info("set normal 512 fs /4 fs\n");
		aml_cbus_update_bits(AIU_CLK_CTRL, 3 << 4, 3 << 4);
	}
	/* enable 958 divider */
	aml_cbus_update_bits(AIU_CLK_CTRL, 1 << 1, 1 << 1);
	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, 0);
	audio_set_958_mode(AIU_958_MODE_PCM16, &set);
#if OVERCLOCK == 1 || IEC958_OVERCLOCK == 1
	/* 512fs divide 4 == 128fs */
	aml_cbus_update_bits(AIU_CLK_CTRL, 0x3 << 4, 0x3 << 4);
#else
	/* 256fs divide 2 == 128fs */
	aml_cbus_update_bits(AIU_CLK_CTRL, 0x3 << 4, 0x1 << 4);
#endif
	aout_notifier_call_chain(AOUT_EVENT_IEC_60958_PCM, &substream);
	audio_hw_958_enable(1);
#endif
}
示例#2
0
void	aml_alsa_hw_reprepare(void)
{
	/* diable 958 module before call initiation */
	audio_hw_958_enable(0);
  aml_hw_iec958_init();

}
void am_i2s_trigger_output(void)
{
    audio_stream_t *s = NULL;
	if (g_prtd == NULL)
	{
		printk("am_i2s_trigger_output g_prtd == NULL \n");
		return ;
	}
    s = &g_prtd->s;
	if (s == NULL)
	{

		printk("am_i2s_trigger_output g_prtd->s== NULL \n");
		return ;
	}
	if (s->audio_trigger_disable == 1) {
		unsigned int pts_audio, pts_scr;
		//unsigned int pts_audio_cur = 0;
		int sync_mode;

		pts_audio = tsync_get_firstapts();
		pts_scr = timestamp_pcrscr_get();
		sync_mode = tsync_get_mode();

		// when pcr chase to apts,start audio playback
		if ((sync_mode == TSYNC_MODE_PCRMASTER) &&  ((pts_audio <= pts_scr))) {
			s->disable_count = 0;
			s->audio_trigger_disable = 0;
			if (s->device_type == AML_AUDIO_I2SOUT) {
				printk("trigger aiu i2s playback enable audio %x pcr %x disable count %d \n", pts_audio, pts_scr,
				       s->disable_count);
				audio_out_i2s_enable(1);
				audio_hw_958_enable(1);
			}
			else if (s->device_type == AML_AUDIO_SPDIFOUT) {
				printk("trigger aiu 958 playback enable audio %x pcr %x disable count %d\n", pts_audio, pts_scr, s->disable_count);
				audio_hw_958_enable(1);
			}
		}
	}
	else
	{
		printk("s->audio_trigger_disable   %d \n", s->audio_trigger_disable);
	}

}
示例#4
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 {
示例#5
0
		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);

}
示例#6
0
	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;
示例#7
0
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);
static int aml_i2s_copy_playback(struct snd_pcm_runtime *runtime, int channel,
                                 snd_pcm_uframes_t pos,
                                 void __user *buf, snd_pcm_uframes_t count, struct snd_pcm_substream *substream)
{
    int res = 0;
    int n;
    int i = 0, j = 0;
    int  align = runtime->channels * 32 / runtime->byte_align;
    char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, pos);
    struct aml_runtime_data *prtd = runtime->private_data;
    struct snd_dma_buffer *buffer = &substream->dma_buffer;
    struct aml_audio_buffer *tmp_buf = buffer->private_data;
    void *ubuf = tmp_buf->buffer_start;
    audio_stream_t *s = &prtd->s;
    int force_reinit_958 = 0;
    force_reinit_958 = (IEC958_mode_codec == 0 && (READ_MPEG_REG(AIU_MEM_IEC958_START_PTR) != READ_MPEG_REG(AIU_MEM_I2S_START_PTR)));
    if (s && s->device_type == AML_AUDIO_I2SOUT && (trigger_underrun) && kernel_android_50 == 1) {
        printk("i2s out trigger underrun force_reinit_958/%d trigger_underrun/%d IEC958_mode_codec/%d IEC958_START_PTR/0x%x I2S_START_PTR/0x%x\n",
               force_reinit_958, trigger_underrun, IEC958_mode_codec, READ_MPEG_REG(AIU_MEM_IEC958_START_PTR), READ_MPEG_REG(AIU_MEM_I2S_START_PTR));
        //trigger_underrun = 0;
        return -EFAULT;
    }
    if (s && s->device_type == AML_AUDIO_I2SOUT && force_reinit_958 && kernel_android_50 == 1) {
        printk("i2s out trigger underrun force_reinit_958/%d", force_reinit_958);
        audio_hw_958_enable(0);
        aml_hw_iec958_init(substream);
        audio_hw_958_enable(1);
    }

    if (s->device_type == AML_AUDIO_I2SOUT) {
        aml_i2s_alsa_write_addr = frames_to_bytes(runtime, pos);
    }
    n = frames_to_bytes(runtime, count);
    if (aml_i2s_playback_enable == 0 && s->device_type == AML_AUDIO_I2SOUT) {
        return res;
    }
    res = copy_from_user(ubuf, buf, n);
    if (res) {
        return -EFAULT;
    }
    if (access_ok(VERIFY_READ, buf, frames_to_bytes(runtime, count))) {
        if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {

            int16_t * tfrom, *to, *left, *right;
            tfrom = (int16_t*)ubuf;
            to = (int16_t*)hwbuf;

            left = to;
            right = to + 16;
            if (pos % align) {
                printk("audio data unligned: pos=%d, n=%d, align=%d\n", (int)pos, n, align);
            }
            if (set_android_gain_enable == 0) {
                for (j = 0; j < n; j += 64) {
                    for (i = 0; i < 16; i++) {
                        *left++ = (*tfrom++) ;
                        *right++ = (*tfrom++);
                    }
                    left += 16;
                    right += 16;
                }
            } else {
                for (j = 0; j < n; j += 64) {
                    for (i = 0; i < 16; i++) {
                        *left++ = (int16_t)(((*tfrom++) * android_left_gain) >> 8);
                        *right++ = (int16_t)(((*tfrom++) * android_right_gain) >> 8);
                    }
                    left += 16;
                    right += 16;
                }
            }
        } else if (runtime->format == SNDRV_PCM_FORMAT_S24_LE && I2S_MODE == AIU_I2S_MODE_PCM24) {
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;
}
示例#10
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,
void aml_hw_iec958_init(struct snd_pcm_substream *substream)
{
	struct _aiu_958_raw_setting_t set;
	struct _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) {
		pr_info("buf/%p runtime/%p\n", buf, 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;
	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);
	pr_info("----aml_hw_iec958_init,runtime->rate=%d,sample_rate=%d--\n",
	       runtime->rate, sample_rate);
	/* int srate; */
	/* srate = params_rate(params); */
	if (old_samplerate != sample_rate) {
		old_samplerate = sample_rate;
		aml_set_spdif_clk(runtime->rate * 512, 0);
	}
	/* Todo, div can be changed, for most case, div = 2 */
	/* audio_set_spdif_clk_div(); */
	/* 958 divisor: 0=no div; 1=div by 2; 2=div by 3; 3=div by 4. */
	if (IEC958_mode_codec == 4  || IEC958_mode_codec == 5 ||
	IEC958_mode_codec == 7 || IEC958_mode_codec == 8) {
		pr_info("set 4x audio clk for 958\n");
		aml_cbus_update_bits(AIU_CLK_CTRL, 3 << 4, 0 << 4);
	} else if (0) {
		pr_info("share the same clock\n");
		aml_cbus_update_bits(AIU_CLK_CTRL, 3 << 4, 1 << 4);
	} else {
		pr_info("set normal 512 fs /4 fs\n");
		aml_cbus_update_bits(AIU_CLK_CTRL, 3 << 4, 3 << 4);
	}
	/* enable 958 divider */
	aml_cbus_update_bits(AIU_CLK_CTRL, 1 << 1, 1 << 1);
	audio_util_set_dac_958_format(AUDIO_ALGOUT_DAC_FORMAT_DSP);
	/*clear the same source function as new raw data output */
	audio_i2s_958_same_source(0);

	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;
			pr_info("iec958 mode RAW\n");
		} else {
			/* ac3,use the same pcm mode as i2s configuration */
			iec958_mode = AIU_958_MODE_PCM_RAW;
			pr_info("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;
		pr_info("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) {
			pr_info("----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) {
			pr_info("----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, 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,
				    (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 == 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,
					 substream);
	} else if (IEC958_mode_codec == 5) {
		aout_notifier_call_chain(AOUT_EVENT_RAWDATA_DTS_HD, substream);
	} else if (IEC958_mode_codec == 7 || IEC958_mode_codec == 8) {
		aml_write_cbus(AIU_958_CHSTAT_L0, 0x1902);
		aml_write_cbus(AIU_958_CHSTAT_L1, 0x900);
		aml_write_cbus(AIU_958_CHSTAT_R0, 0x1902);
		aml_write_cbus(AIU_958_CHSTAT_R1, 0x900);
		if (IEC958_mode_codec == 8)
			aout_notifier_call_chain(AOUT_EVENT_RAWDATA_DTS_HD_MA,
			substream);
		else
			aout_notifier_call_chain(AOUT_EVENT_RAWDATA_MAT_MLP,
			substream);
	} else {
		aout_notifier_call_chain(AOUT_EVENT_IEC_60958_PCM, substream);
	}
}
static void aml_spdif_play_stop(void)
{
	audio_hw_958_enable(0);
}