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

📄 mcbsp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	io_base = mcbsp[id].io_base;	wait_for_completion(&(mcbsp[id].tx_irq_completion));	if (word_length > OMAP_MCBSP_WORD_16)		OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);	OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);}u32 omap_mcbsp_recv_word(unsigned int id){	u32 io_base;	u16 word_lsb, word_msb = 0;	omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length;	if (omap_mcbsp_check(id) < 0)		return -EINVAL;	io_base = mcbsp[id].io_base;	wait_for_completion(&(mcbsp[id].rx_irq_completion));	if (word_length > OMAP_MCBSP_WORD_16)		word_msb = OMAP_MCBSP_READ(io_base, DRR2);	word_lsb = OMAP_MCBSP_READ(io_base, DRR1);	return (word_lsb | (word_msb << 16));}int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word){	u32 io_base = mcbsp[id].io_base;	omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length;	omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length;	u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;	if (tx_word_length != rx_word_length)		return -EINVAL;	/* First we wait for the transmitter to be ready */	spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);	while (!(spcr2 & XRDY)) {		spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);		if (attempts++ > 1000) {			/* We must reset the transmitter */			OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST));			udelay(10);			OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);			udelay(10);			printk("McBSP transmitter not ready\n");			return -EAGAIN;		}	}	/* Now we can push the data */	if (tx_word_length > OMAP_MCBSP_WORD_16)		OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);	OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);	/* We wait for the receiver to be ready */	spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);	while (!(spcr1 & RRDY)) {		spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);		if (attempts++ > 1000) {			/* We must reset the receiver */			OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST));			udelay(10);			OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);			udelay(10);			printk("McBSP receiver not ready\n");			return -EAGAIN;		}	}	/* Receiver is ready, let's read the dummy data */	if (rx_word_length > OMAP_MCBSP_WORD_16)		word_msb = OMAP_MCBSP_READ(io_base, DRR2);	word_lsb = OMAP_MCBSP_READ(io_base, DRR1);	return 0;}int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word){	u32 io_base = mcbsp[id].io_base, clock_word = 0;	omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length;	omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length;	u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;	if (tx_word_length != rx_word_length)		return -EINVAL;	/* First we wait for the transmitter to be ready */	spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);	while (!(spcr2 & XRDY)) {		spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);		if (attempts++ > 1000) {			/* We must reset the transmitter */			OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST));			udelay(10);			OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);			udelay(10);			printk("McBSP transmitter not ready\n");			return -EAGAIN;		}	}	/* We first need to enable the bus clock */	if (tx_word_length > OMAP_MCBSP_WORD_16)		OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16);	OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff);	/* We wait for the receiver to be ready */	spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);	while (!(spcr1 & RRDY)) {		spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);		if (attempts++ > 1000) {			/* We must reset the receiver */			OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST));			udelay(10);			OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);			udelay(10);			printk("McBSP receiver not ready\n");			return -EAGAIN;		}	}	/* Receiver is ready, there is something for us */	if (rx_word_length > OMAP_MCBSP_WORD_16)		word_msb = OMAP_MCBSP_READ(io_base, DRR2);	word_lsb = OMAP_MCBSP_READ(io_base, DRR1);	word[0] = (word_lsb | (word_msb << 16));	return 0;}/* * Simple DMA based buffer rx/tx routines. * Nothing fancy, just a single buffer tx/rx through DMA. * The DMA resources are released once the transfer is done. * For anything fancier, you should use your own customized DMA * routines and callbacks. */int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length){	int dma_tx_ch;	int src_port = 0;	int dest_port = 0;	int sync_dev = 0;	if (omap_mcbsp_check(id) < 0)		return -EINVAL;	if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback,			     &mcbsp[id],			     &dma_tx_ch)) {		printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1);		return -EAGAIN;	}	mcbsp[id].dma_tx_lch = dma_tx_ch;	DBG("TX DMA on channel %d\n", dma_tx_ch);	init_completion(&(mcbsp[id].tx_dma_completion));	if (cpu_class_is_omap1()) {		src_port = OMAP_DMA_PORT_TIPB;		dest_port = OMAP_DMA_PORT_EMIFF;	}	if (cpu_is_omap24xx())		sync_dev = mcbsp[id].dma_tx_sync;	omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,				     OMAP_DMA_DATA_TYPE_S16,				     length >> 1, 1,				     OMAP_DMA_SYNC_ELEMENT,	 sync_dev, 0);	omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,				 src_port,				 OMAP_DMA_AMODE_CONSTANT,				 mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1,				 0, 0);	omap_set_dma_src_params(mcbsp[id].dma_tx_lch,				dest_port,				OMAP_DMA_AMODE_POST_INC,				buffer,				0, 0);	omap_start_dma(mcbsp[id].dma_tx_lch);	wait_for_completion(&(mcbsp[id].tx_dma_completion));	return 0;}int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length){	int dma_rx_ch;	int src_port = 0;	int dest_port = 0;	int sync_dev = 0;	if (omap_mcbsp_check(id) < 0)		return -EINVAL;	if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback,			     &mcbsp[id],			     &dma_rx_ch)) {		printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1);		return -EAGAIN;	}	mcbsp[id].dma_rx_lch = dma_rx_ch;	DBG("RX DMA on channel %d\n", dma_rx_ch);	init_completion(&(mcbsp[id].rx_dma_completion));	if (cpu_class_is_omap1()) {		src_port = OMAP_DMA_PORT_TIPB;		dest_port = OMAP_DMA_PORT_EMIFF;	}	if (cpu_is_omap24xx())		sync_dev = mcbsp[id].dma_rx_sync;	omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,				     OMAP_DMA_DATA_TYPE_S16,				     length >> 1, 1,				     OMAP_DMA_SYNC_ELEMENT,	 sync_dev, 0);	omap_set_dma_src_params(mcbsp[id].dma_rx_lch,				src_port,				OMAP_DMA_AMODE_CONSTANT,				mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1,				0, 0);	omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,				 dest_port,				 OMAP_DMA_AMODE_POST_INC,				 buffer,				 0, 0);	omap_start_dma(mcbsp[id].dma_rx_lch);	wait_for_completion(&(mcbsp[id].rx_dma_completion));	return 0;}/* * SPI wrapper. * Since SPI setup is much simpler than the generic McBSP one, * this wrapper just need an omap_mcbsp_spi_cfg structure as an input. * Once this is done, you can call omap_mcbsp_start(). */void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg){	struct omap_mcbsp_reg_cfg mcbsp_cfg;	if (omap_mcbsp_check(id) < 0)		return;	memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg));	/* SPI has only one frame */	mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0));	mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0));        /* Clock stop mode */	if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY)		mcbsp_cfg.spcr1 |= (1 << 12);	else		mcbsp_cfg.spcr1 |= (3 << 11);	/* Set clock parities */	if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING)		mcbsp_cfg.pcr0 |= CLKRP;	else		mcbsp_cfg.pcr0 &= ~CLKRP;	if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING)		mcbsp_cfg.pcr0 &= ~CLKXP;	else		mcbsp_cfg.pcr0 |= CLKXP;	/* Set SCLKME to 0 and CLKSM to 1 */	mcbsp_cfg.pcr0 &= ~SCLKME;	mcbsp_cfg.srgr2 |= CLKSM;	/* Set FSXP */	if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH)		mcbsp_cfg.pcr0 &= ~FSXP;	else		mcbsp_cfg.pcr0 |= FSXP;	if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) {		mcbsp_cfg.pcr0 |= CLKXM;		mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1);		mcbsp_cfg.pcr0 |= FSXM;		mcbsp_cfg.srgr2 &= ~FSGM;		mcbsp_cfg.xcr2 |= XDATDLY(1);		mcbsp_cfg.rcr2 |= RDATDLY(1);	}	else {		mcbsp_cfg.pcr0 &= ~CLKXM;		mcbsp_cfg.srgr1 |= CLKGDV(1);		mcbsp_cfg.pcr0 &= ~FSXM;		mcbsp_cfg.xcr2 &= ~XDATDLY(3);		mcbsp_cfg.rcr2 &= ~RDATDLY(3);	}	mcbsp_cfg.xcr2 &= ~XPHASE;	mcbsp_cfg.rcr2 &= ~RPHASE;	omap_mcbsp_config(id, &mcbsp_cfg);}/* * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. * 730 has only 2 McBSP, and both of them are MPU peripherals. */struct omap_mcbsp_info {	u32 virt_base;	u8 dma_rx_sync, dma_tx_sync;	u16 rx_irq, tx_irq;};#ifdef CONFIG_ARCH_OMAP730static const struct omap_mcbsp_info mcbsp_730[] = {	[0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE),		.dma_rx_sync = OMAP_DMA_MCBSP1_RX,		.dma_tx_sync = OMAP_DMA_MCBSP1_TX,		.rx_irq = INT_730_McBSP1RX,		.tx_irq = INT_730_McBSP1TX },	[1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE),		.dma_rx_sync = OMAP_DMA_MCBSP3_RX,		.dma_tx_sync = OMAP_DMA_MCBSP3_TX,		.rx_irq = INT_730_McBSP2RX,		.tx_irq = INT_730_McBSP2TX },};#endif#ifdef CONFIG_ARCH_OMAP15XXstatic const struct omap_mcbsp_info mcbsp_1510[] = {	[0] = { .virt_base = OMAP1510_MCBSP1_BASE,		.dma_rx_sync = OMAP_DMA_MCBSP1_RX,		.dma_tx_sync = OMAP_DMA_MCBSP1_TX,		.rx_irq = INT_McBSP1RX,		.tx_irq = INT_McBSP1TX },	[1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE),		.dma_rx_sync = OMAP_DMA_MCBSP2_RX,		.dma_tx_sync = OMAP_DMA_MCBSP2_TX,		.rx_irq = INT_1510_SPI_RX,		.tx_irq = INT_1510_SPI_TX },	[2] = { .virt_base = OMAP1510_MCBSP3_BASE,		.dma_rx_sync = OMAP_DMA_MCBSP3_RX,		.dma_tx_sync = OMAP_DMA_MCBSP3_TX,		.rx_irq = INT_McBSP3RX,		.tx_irq = INT_McBSP3TX },};#endif#if defined(CONFIG_ARCH_OMAP16XX)static const struct omap_mcbsp_info mcbsp_1610[] = {	[0] = { .virt_base = OMAP1610_MCBSP1_BASE,		.dma_rx_sync = OMAP_DMA_MCBSP1_RX,		.dma_tx_sync = OMAP_DMA_MCBSP1_TX,		.rx_irq = INT_McBSP1RX,		.tx_irq = INT_McBSP1TX },	[1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE),		.dma_rx_sync = OMAP_DMA_MCBSP2_RX,		.dma_tx_sync = OMAP_DMA_MCBSP2_TX,		.rx_irq = INT_1610_McBSP2_RX,		.tx_irq = INT_1610_McBSP2_TX },	[2] = { .virt_base = OMAP1610_MCBSP3_BASE,		.dma_rx_sync = OMAP_DMA_MCBSP3_RX,		.dma_tx_sync = OMAP_DMA_MCBSP3_TX,		.rx_irq = INT_McBSP3RX,		.tx_irq = INT_McBSP3TX },};#endif#if defined(CONFIG_ARCH_OMAP24XX)static const struct omap_mcbsp_info mcbsp_24xx[] = {	[0] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE),		.dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX,		.dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,		.rx_irq = INT_24XX_MCBSP1_IRQ_RX,		.tx_irq = INT_24XX_MCBSP1_IRQ_TX,		},	[1] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE),		.dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX,		.dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,		.rx_irq = INT_24XX_MCBSP2_IRQ_RX,		.tx_irq = INT_24XX_MCBSP2_IRQ_TX,		},};#endifstatic int __init omap_mcbsp_init(void){	int mcbsp_count = 0, i;	static const struct omap_mcbsp_info *mcbsp_info;	printk("Initializing OMAP McBSP system\n");#ifdef CONFIG_ARCH_OMAP1	mcbsp_dsp_ck = clk_get(0, "dsp_ck");	if (IS_ERR(mcbsp_dsp_ck)) {		printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n");		return PTR_ERR(mcbsp_dsp_ck);	}	mcbsp_api_ck = clk_get(0, "api_ck");	if (IS_ERR(mcbsp_api_ck)) {		printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n");		return PTR_ERR(mcbsp_api_ck);	}	mcbsp_dspxor_ck = clk_get(0, "dspxor_ck");	if (IS_ERR(mcbsp_dspxor_ck)) {		printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n");		return PTR_ERR(mcbsp_dspxor_ck);	}#endif#ifdef CONFIG_ARCH_OMAP2	mcbsp1_ick = clk_get(0, "mcbsp1_ick");	if (IS_ERR(mcbsp1_ick)) {		printk(KERN_ERR "mcbsp: could not acquire mcbsp1_ick handle.\n");		return PTR_ERR(mcbsp1_ick);	}	mcbsp1_fck = clk_get(0, "mcbsp1_fck");	if (IS_ERR(mcbsp1_fck)) {		printk(KERN_ERR "mcbsp: could not acquire mcbsp1_fck handle.\n");		return PTR_ERR(mcbsp1_fck);	}	mcbsp2_ick = clk_get(0, "mcbsp2_ick");	if (IS_ERR(mcbsp2_ick)) {		printk(KERN_ERR "mcbsp: could not acquire mcbsp2_ick handle.\n");		return PTR_ERR(mcbsp2_ick);	}	mcbsp2_fck = clk_get(0, "mcbsp2_fck");	if (IS_ERR(mcbsp2_fck)) {		printk(KERN_ERR "mcbsp: could not acquire mcbsp2_fck handle.\n");		return PTR_ERR(mcbsp2_fck);	}#endif#ifdef CONFIG_ARCH_OMAP730	if (cpu_is_omap730()) {		mcbsp_info = mcbsp_730;		mcbsp_count = ARRAY_SIZE(mcbsp_730);	}#endif#ifdef CONFIG_ARCH_OMAP15XX	if (cpu_is_omap15xx()) {		mcbsp_info = mcbsp_1510;		mcbsp_count = ARRAY_SIZE(mcbsp_1510);	}#endif#if defined(CONFIG_ARCH_OMAP16XX)	if (cpu_is_omap16xx()) {		mcbsp_info = mcbsp_1610;		mcbsp_count = ARRAY_SIZE(mcbsp_1610);	}#endif#if defined(CONFIG_ARCH_OMAP24XX)	if (cpu_is_omap24xx()) {		mcbsp_info = mcbsp_24xx;		mcbsp_count = ARRAY_SIZE(mcbsp_24xx);		omap2_mcbsp2_mux_setup();	}#endif	for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {		if (i >= mcbsp_count) {			mcbsp[i].io_base = 0;			mcbsp[i].free = 0;                        continue;		}		mcbsp[i].id = i + 1;		mcbsp[i].free = 1;		mcbsp[i].dma_tx_lch = -1;		mcbsp[i].dma_rx_lch = -1;		mcbsp[i].io_base = mcbsp_info[i].virt_base;		mcbsp[i].io_type = OMAP_MCBSP_IRQ_IO; /* Default I/O is IRQ based */		mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;		mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;		mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;		mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync;		spin_lock_init(&mcbsp[i].lock);	}	return 0;}arch_initcall(omap_mcbsp_init);EXPORT_SYMBOL(omap_mcbsp_config);EXPORT_SYMBOL(omap_mcbsp_request);EXPORT_SYMBOL(omap_mcbsp_set_io_type);EXPORT_SYMBOL(omap_mcbsp_free);EXPORT_SYMBOL(omap_mcbsp_start);EXPORT_SYMBOL(omap_mcbsp_stop);EXPORT_SYMBOL(omap_mcbsp_xmit_word);EXPORT_SYMBOL(omap_mcbsp_recv_word);EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);EXPORT_SYMBOL(omap_mcbsp_recv_buffer);EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll);EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll);EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);

⌨️ 快捷键说明

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