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;
}
/*--------------------------------------------------------------------------*\
 * i2s operations
\*--------------------------------------------------------------------------*/
static int aml_i2s_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
{
    struct snd_pcm_runtime *runtime = substream->runtime;
    struct aml_runtime_data *prtd = runtime->private_data;
    //  struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
    audio_stream_t *s = &prtd->s;

    /* this may get called several times by oss emulation
     * with different params */

    snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
    runtime->dma_bytes = params_buffer_bytes(params);
    ALSA_DEBUG("runtime dma_bytes %d,stream type %d \n", runtime->dma_bytes, substream->stream);
    s->I2S_addr = runtime->dma_addr;

    /*
     * Both capture and playback need to reset the last ptr to the start address,
       playback and capture use different address calculate, so we reset the different
       start address to the last ptr
    * */
    if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
        /* s->last_ptr must initialized as dma buffer's start addr */
        s->last_ptr = runtime->dma_addr;
    } else {

        s->last_ptr = 0;
    }

    return 0;
}
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;
}
Exemplo n.º 4
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);
	}
}