⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91-ssc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		break;	case SNDRV_PCM_FORMAT_S16_LE:		bits = 16;		dma_params->pdc_xfer_size = 2;		break;	case SNDRV_PCM_FORMAT_S24_LE:		bits = 24;		dma_params->pdc_xfer_size = 4;		break;	case SNDRV_PCM_FORMAT_S32_LE:		bits = 32;		dma_params->pdc_xfer_size = 4;		break;	default:		printk(KERN_WARNING "at91-ssc: unsupported PCM format");		return -EINVAL;	}	/*	 * The SSC only supports up to 16-bit samples in I2S format, due	 * to the size of the Frame Mode Register FSLEN field.	 */	if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S		&& bits > 16) {		printk(KERN_WARNING			"at91-ssc: sample size %d is too large for I2S\n", bits);		return -EINVAL;	}	/*	 * Compute SSC register settings.	 */	switch (ssc_p->daifmt		& (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:		/*		 * I2S format, SSC provides BCLK and LRC clocks.		 *		 * The SSC transmit and receive clocks are generated from the		 * MCK divider, and the BCLK signal is output on the SSC TK line.		 */		rcmr =	  (( ssc_p->rcmr_period		<< 24) & AT91_SSC_PERIOD)			| (( 1				<< 16) & AT91_SSC_STTDLY)			| (( AT91_SSC_START_FALLING_RF	     ) & AT91_SSC_START)			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);		rfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)			| (( AT91_SSC_FSOS_NEGATIVE	     ) & AT91_SSC_FSOS)			| (((bits - 1)			<< 16) & AT91_SSC_FSLEN)			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)			| (( 1				<<  7) & AT91_SSC_MSBF)			| (( 0				<<  5) & AT91_SSC_LOOP)			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);		tcmr =	  (( ssc_p->tcmr_period		<< 24) & AT91_SSC_PERIOD)			| (( 1				<< 16) & AT91_SSC_STTDLY)			| (( AT91_SSC_START_FALLING_RF       ) & AT91_SSC_START)			| (( AT91_SSC_CKI_FALLING	     ) & AT91_SSC_CKI)			| (( AT91_SSC_CKO_CONTINUOUS	     ) & AT91_SSC_CKO)			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);		tfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)			| (( 0				<< 23) & AT91_SSC_FSDEN)			| (( AT91_SSC_FSOS_NEGATIVE	     ) & AT91_SSC_FSOS)			| (((bits - 1)			<< 16) & AT91_SSC_FSLEN)			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)			| (( 1				<<  7) & AT91_SSC_MSBF)			| (( 0				<<  5) & AT91_SSC_DATDEF)			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);		break;	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:		/*		 * I2S format, CODEC supplies BCLK and LRC clocks.		 *		 * The SSC transmit clock is obtained from the BCLK signal on		 * on the TK line, and the SSC receive clock is generated from the		 * transmit clock.		 *		 * For single channel data, one sample is transferred on the falling		 * edge of the LRC clock.  For two channel data, one sample is		 * transferred on both edges of the LRC clock.		 */		start_event = channels == 1				? AT91_SSC_START_FALLING_RF				: AT91_SSC_START_EDGE_RF;		rcmr =	  (( 0				<< 24) & AT91_SSC_PERIOD)			| (( 1				<< 16) & AT91_SSC_STTDLY)			| (( start_event		     ) & AT91_SSC_START)			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)			| (( AT91_SSC_CKS_CLOCK		     ) & AT91_SSC_CKS);		rfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)			| (( AT91_SSC_FSOS_NONE		     ) & AT91_SSC_FSOS)			| (( 0				<< 16) & AT91_SSC_FSLEN)			| (( 0				<<  8) & AT91_SSC_DATNB)			| (( 1				<<  7) & AT91_SSC_MSBF)			| (( 0				<<  5) & AT91_SSC_LOOP)			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);		tcmr =	  (( 0				<< 24) & AT91_SSC_PERIOD)			| (( 1				<< 16) & AT91_SSC_STTDLY)			| (( start_event		     ) & AT91_SSC_START)			| (( AT91_SSC_CKI_FALLING	     ) & AT91_SSC_CKI)			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)			| (( AT91_SSC_CKS_PIN		     ) & AT91_SSC_CKS);		tfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)			| (( 0				<< 23) & AT91_SSC_FSDEN)			| (( AT91_SSC_FSOS_NONE		     ) & AT91_SSC_FSOS)			| (( 0				<< 16) & AT91_SSC_FSLEN)			| (( 0				<<  8) & AT91_SSC_DATNB)			| (( 1				<<  7) & AT91_SSC_MSBF)			| (( 0				<<  5) & AT91_SSC_DATDEF)			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);		break;	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:		/*		 * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.		 *		 * The SSC transmit and receive clocks are generated from the		 * MCK divider, and the BCLK signal is output on the SSC TK line.		 */		rcmr =	  (( ssc_p->rcmr_period		<< 24) & AT91_SSC_PERIOD)			| (( 1				<< 16) & AT91_SSC_STTDLY)			| (( AT91_SSC_START_RISING_RF	     ) & AT91_SSC_START)			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);		rfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)			| (( AT91_SSC_FSOS_POSITIVE	     ) & AT91_SSC_FSOS)			| (( 0				<< 16) & AT91_SSC_FSLEN)			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)			| (( 1				<<  7) & AT91_SSC_MSBF)			| (( 0				<<  5) & AT91_SSC_LOOP)			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);		tcmr =	  (( ssc_p->tcmr_period		<< 24) & AT91_SSC_PERIOD)			| (( 1				<< 16) & AT91_SSC_STTDLY)			| (( AT91_SSC_START_RISING_RF        ) & AT91_SSC_START)			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)			| (( AT91_SSC_CKO_CONTINUOUS	     ) & AT91_SSC_CKO)			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);		tfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)			| (( 0				<< 23) & AT91_SSC_FSDEN)			| (( AT91_SSC_FSOS_POSITIVE	     ) & AT91_SSC_FSOS)			| (( 0				<< 16) & AT91_SSC_FSLEN)			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)			| (( 1				<<  7) & AT91_SSC_MSBF)			| (( 0				<<  5) & AT91_SSC_DATDEF)			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);			break;	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:	default:		printk(KERN_WARNING "at91-ssc: unsupported DAI format 0x%x.\n",			ssc_p->daifmt);		return -EINVAL;		break;	}	DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr);	if (!ssc_p->initialized) {		/* Enable PMC peripheral clock for this SSC */		DBG("Starting pid %d clock\n", ssc_p->ssc.pid);		at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);		/* Reset the SSC and its PDC registers */		at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0);		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0);		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0);		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0);		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0);		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0);		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0);		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0);		if ((ret = request_irq(ssc_p->ssc.pid, at91_ssc_interrupt,					0, ssc_p->name, ssc_p)) < 0) {			printk(KERN_WARNING "at91-ssc: request_irq failure\n");			DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);			at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);			return ret;		}		ssc_p->initialized = 1;	}	/* set SSC clock mode register */	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div);	/* set receive clock mode and format */	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr);	/* set transmit clock mode and format */	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr);	DBG("hw_params: SSC initialized\n");	return 0;}static int at91_ssc_prepare(struct snd_pcm_substream *substream){	struct snd_soc_pcm_runtime *rtd = substream->private_data;	struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];	struct at91_pcm_dma_params *dma_params;	int dir;	dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;	dma_params = ssc_p->dma_params[dir];	at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,			dma_params->mask->ssc_enable);	DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit",		at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR));	return 0;}#ifdef CONFIG_PMstatic int at91_ssc_suspend(struct platform_device *pdev,	struct snd_soc_cpu_dai *cpu_dai){	struct at91_ssc_info *ssc_p;	if(!cpu_dai->active)		return 0;	ssc_p = &ssc_info[cpu_dai->id];	/* Save the status register before disabling transmit and receive. */	ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,			AT91_SSC_TXDIS | AT91_SSC_RXDIS);	/* Save the current interrupt mask, then disable unmasked interrupts. */	ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr);	ssc_p->ssc_state.ssc_cmr  = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR);	ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);	ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR);	ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR);	ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR);	return 0;}static int at91_ssc_resume(struct platform_device *pdev,	struct snd_soc_cpu_dai *cpu_dai){	struct at91_ssc_info *ssc_p;	if(!cpu_dai->active)		return 0;	ssc_p = &ssc_info[cpu_dai->id];	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR,  ssc_p->ssc_state.ssc_cmr);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER,  ssc_p->ssc_state.ssc_imr);	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,		((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |		((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));	return 0;}#else#define at91_ssc_suspend	NULL#define at91_ssc_resume		NULL#endif#define AT91_SSC_RATES (SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 |\			SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\			SNDRV_PCM_RATE_96000)#define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\			  SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)struct snd_soc_cpu_dai at91_ssc_dai[NUM_SSC_DEVICES] = {	{	.name = "at91-ssc0",		.id = 0,		.type = SND_SOC_DAI_PCM,		.suspend = at91_ssc_suspend,		.resume = at91_ssc_resume,		.playback = {			.channels_min = 1,			.channels_max = 2,			.rates = AT91_SSC_RATES,			.formats = AT91_SSC_FORMATS,},		.capture = {			.channels_min = 1,			.channels_max = 2,			.rates = AT91_SSC_RATES,			.formats = AT91_SSC_FORMATS,},		.ops = {			.startup = at91_ssc_startup,			.shutdown = at91_ssc_shutdown,			.prepare = at91_ssc_prepare,			.hw_params = at91_ssc_hw_params,},		.dai_ops = {			.set_sysclk = at91_ssc_set_dai_sysclk,			.set_fmt = at91_ssc_set_dai_fmt,			.set_clkdiv = at91_ssc_set_dai_clkdiv,},		.private_data = &ssc_info[0].ssc,	},#if NUM_SSC_DEVICES == 3	{	.name = "at91-ssc1",		.id = 1,		.type = SND_SOC_DAI_PCM,		.suspend = at91_ssc_suspend,		.resume = at91_ssc_resume,		.playback = {			.channels_min = 1,			.channels_max = 2,			.rates = AT91_SSC_RATES,			.formats = AT91_SSC_FORMATS,},		.capture = {			.channels_min = 1,			.channels_max = 2,			.rates = AT91_SSC_RATES,			.formats = AT91_SSC_FORMATS,},		.ops = {			.startup = at91_ssc_startup,			.shutdown = at91_ssc_shutdown,			.prepare = at91_ssc_prepare,			.hw_params = at91_ssc_hw_params,},		.dai_ops = {			.set_sysclk = at91_ssc_set_dai_sysclk,			.set_fmt = at91_ssc_set_dai_fmt,			.set_clkdiv = at91_ssc_set_dai_clkdiv,},		.private_data = &ssc_info[1].ssc,	},	{	.name = "at91-ssc2",		.id = 2,		.type = SND_SOC_DAI_PCM,		.suspend = at91_ssc_suspend,		.resume = at91_ssc_resume,		.playback = {			.channels_min = 1,			.channels_max = 2,			.rates = AT91_SSC_RATES,			.formats = AT91_SSC_FORMATS,},		.capture = {			.channels_min = 1,			.channels_max = 2,			.rates = AT91_SSC_RATES,			.formats = AT91_SSC_FORMATS,},		.ops = {			.startup = at91_ssc_startup,			.shutdown = at91_ssc_shutdown,			.prepare = at91_ssc_prepare,			.hw_params = at91_ssc_hw_params,},		.dai_ops = {			.set_sysclk = at91_ssc_set_dai_sysclk,			.set_fmt = at91_ssc_set_dai_fmt,			.set_clkdiv = at91_ssc_set_dai_clkdiv,},		.private_data = &ssc_info[2].ssc,	},#endif};EXPORT_SYMBOL_GPL(at91_ssc_dai);/* Module information */MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");MODULE_DESCRIPTION("AT91 SSC ASoC Interface");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -