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

📄 mcbsp.c

📁 TI达芬奇 arm+dsp双核平台Davinci 6446 EVM板的linux下的 处理器平台底层代码
💻 C
字号:
/* * arch/arm/mach-davinci/mcbsp.c * * Copyright (C) 2004 Nokia Corporation * Author: Samuel Ortiz <samuel.ortiz@nokia.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Multichannel mode not supported. * * 2005-10-01   Rishi Bhattacharya / Sharath Kumar - Modified to support TI *		Davinci DM644x processor */#include <linux/module.h>#include <linux/init.h>#include <linux/device.h>#include <linux/wait.h>#include <linux/completion.h>#include <linux/interrupt.h>#include <linux/err.h>#include <asm/delay.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/arch/memory.h>#include <asm/arch/edma.h>#include <asm/arch/irqs.h>#include <asm/arch/mcbsp.h>#include <asm/hardware/clock.h>struct clk *mbspclk = NULL;/* #define CONFIG_MCBSP_DEBUG */#ifdef CONFIG_MCBSP_DEBUG#define DBG(x...)       printk(KERN_INFO x)#else#define DBG(x...)       do { } while (0)#endifstruct davinci_mcbsp {	u32 io_base;	u8 id;	u8 free;	davinci_mcbsp_word_length rx_word_length;	davinci_mcbsp_word_length tx_word_length;	/* IRQ based TX/RX */	int rx_irq;	int tx_irq;	/* DMA stuff */	u8 dma_rx_sync;	short dma_rx_lch;	u8 dma_tx_sync;	short dma_tx_lch;	/* Completion queues */	struct completion tx_irq_completion;	struct completion rx_irq_completion;	struct completion tx_dma_completion;	struct completion rx_dma_completion;	spinlock_t lock;};static struct davinci_mcbsp mcbsp[DAVINCI_MAX_MCBSP_COUNT];unsigned short DAVINCI_MCBSP_READ(int base, int reg){	unsigned long data, temp, *p = (unsigned long *)(base + reg);	temp = (unsigned long)p;	if (temp & 0x2) {		/*non word offset */		temp &= 0xfffffffc;		p = (unsigned long *)temp;		data = inl(p);		return (unsigned short)(data >> 16);	} else {		/*word offset */		return ((unsigned short)inl(p));	}}void DAVINCI_MCBSP_WRITE(int base, int reg, unsigned short val){	unsigned long data, temp, *p = (unsigned long *)(base + reg);	temp = (unsigned long)p;	if (temp & 0x2) {		/*non word offset */		temp &= 0xfffffffc;		p = (unsigned long *)temp;		data = inl(p);		data &= 0x0000ffff;		data |= ((unsigned long)val << 16);		outl(data, p);	} else {		/*word offset */		data = inl(p);		data &= 0xffff0000;		data |= val;		outl(data, p);	}}#if 0static void davinci_mcbsp_dump_reg(u8 id){	DBG("**** MCBSP%d regs ****\n", mcbsp[id].id);	DBG("SPCR2: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, SPCR2));	DBG("SPCR1: 0x%04x\n",	DAVINCI_MCBSP_READ(mcbsp[id].io_base, SPCR1));	DBG("RCR2:  0x%04x\n",	DAVINCI_MCBSP_READ(mcbsp[id].io_base, RCR2));	DBG("RCR1:  0x%04x\n",	DAVINCI_MCBSP_READ(mcbsp[id].io_base, RCR1));	DBG("XCR2:  0x%04x\n",	DAVINCI_MCBSP_READ(mcbsp[id].io_base, XCR2));	DBG("XCR1:  0x%04x\n",	DAVINCI_MCBSP_READ(mcbsp[id].io_base, XCR1));	DBG("SRGR2: 0x%04x\n",	DAVINCI_MCBSP_READ(mcbsp[id].io_base, SRGR2));	DBG("SRGR1: 0x%04x\n",	DAVINCI_MCBSP_READ(mcbsp[id].io_base, SRGR1));	DBG("PCR0:  0x%04x\n",	DAVINCI_MCBSP_READ(mcbsp[id].io_base, PCR0));	DBG("***********************\n");}#endifstatic void davinci_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data){	struct davinci_mcbsp *mcbsp_dma_tx = (struct davinci_mcbsp *)(data);	DBG("TX DMA callback : 0x%x\n",	    DAVINCI_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));	/* We can free the channels */	DBG("mcbsp_dma_tx->dma_tx_lch = %d\n",	       mcbsp_dma_tx->dma_tx_lch);	davinci_stop_dma(mcbsp_dma_tx->dma_tx_lch);	davinci_free_dma(mcbsp_dma_tx->dma_tx_lch);	mcbsp_dma_tx->dma_tx_lch = -1;	complete(&mcbsp_dma_tx->tx_dma_completion);}static void davinci_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data){	struct davinci_mcbsp *mcbsp_dma_rx = (struct davinci_mcbsp *)(data);	DBG("RX DMA callback : 0x%x\n",	    DAVINCI_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));	/* We can free the channels */	davinci_free_dma(mcbsp_dma_rx->dma_rx_lch);	mcbsp_dma_rx->dma_rx_lch = -1;	complete(&mcbsp_dma_rx->rx_dma_completion);}/* * davinci_mcbsp_config simply write a config to the * appropriate McBSP. * You either call this function or set the McBSP registers * by yourself before calling davinci_mcbsp_start(). */void davinci_mcbsp_config(unsigned int id,			  const struct davinci_mcbsp_reg_cfg *config){	u32 io_base = mcbsp[id].io_base;	DBG("davinci-McBSP: McBSP%d  io_base: 0x%8x\n", id + 1, io_base);	DAVINCI_MCBSP_WRITE(io_base, PCR0, config->pcr0);	DAVINCI_MCBSP_WRITE(io_base, RCR2, config->rcr2);	DAVINCI_MCBSP_WRITE(io_base, RCR1, config->rcr1);	DAVINCI_MCBSP_WRITE(io_base, XCR2, config->xcr2);	DAVINCI_MCBSP_WRITE(io_base, XCR1, config->xcr1);	DAVINCI_MCBSP_WRITE(io_base, SRGR2, config->srgr2);	DAVINCI_MCBSP_WRITE(io_base, SRGR1, config->srgr1);	/* We write the given config */	DAVINCI_MCBSP_WRITE(io_base, SPCR2, config->spcr2);	DAVINCI_MCBSP_WRITE(io_base, SPCR1, config->spcr1);	return;}static int davinci_mcbsp_check(unsigned int id){	if (id > DAVINCI_MAX_MCBSP_COUNT - 1) {		DBG("DAVINCI-McBSP: McBSP%d doesn't exist\n", id + 1);		return -1;	}	return 0;}int davinci_mcbsp_request(unsigned int id){	if (davinci_mcbsp_check(id) < 0)		return -EINVAL;	spin_lock(&mcbsp[id].lock);	if (!mcbsp[id].free) {		DBG("DAVINCI-McBSP: McBSP%d is currently in use\n", id + 1);		spin_unlock(&mcbsp[id].lock);		return -1;	}	mcbsp[id].free = 0;	spin_unlock(&mcbsp[id].lock);	return 0;}void davinci_mcbsp_free(unsigned int id){	if (davinci_mcbsp_check(id) < 0)		return;	spin_lock(&mcbsp[id].lock);	if (mcbsp[id].free) {		DBG("DAVINCI-McBSP: McBSP%d was not reserved\n", id + 1);		spin_unlock(&mcbsp[id].lock);		return;	}	mcbsp[id].free = 1;	spin_unlock(&mcbsp[id].lock);	return;}/* * Here we start the McBSP, by enabling the sample * generator, both transmitter and receivers, * and the frame sync. */void davinci_mcbsp_start(unsigned int id){	u32 io_base;	u16 w;	if (davinci_mcbsp_check(id) < 0)		return;	io_base = mcbsp[id].io_base;	mcbsp[id].rx_word_length =	    ((DAVINCI_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);	mcbsp[id].tx_word_length =	    ((DAVINCI_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);	/* Start the sample generator */	w = DAVINCI_MCBSP_READ(io_base, SPCR2);	DAVINCI_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));	/* Enable transmitter and receiver */	w = DAVINCI_MCBSP_READ(io_base, SPCR2);	DAVINCI_MCBSP_WRITE(io_base, SPCR2, w | 1);	w = DAVINCI_MCBSP_READ(io_base, SPCR1);	DAVINCI_MCBSP_WRITE(io_base, SPCR1, w | 1);	udelay(100);	/* Start frame sync */	w = DAVINCI_MCBSP_READ(io_base, SPCR2);	DAVINCI_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));	return;}void davinci_mcbsp_stop(unsigned int id){	u32 io_base;	u16 w;	if (davinci_mcbsp_check(id) < 0)		return;	io_base = mcbsp[id].io_base;	/* Reset transmitter */	w = DAVINCI_MCBSP_READ(io_base, SPCR2);	DAVINCI_MCBSP_WRITE(io_base, SPCR2, w & ~(1));	/* Reset receiver */	w = DAVINCI_MCBSP_READ(io_base, SPCR1);	DAVINCI_MCBSP_WRITE(io_base, SPCR1, w & ~(1));	/* Reset the sample rate generator */	w = DAVINCI_MCBSP_READ(io_base, SPCR2);	DAVINCI_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));	/* Reset the frame sync generator */	w = DAVINCI_MCBSP_READ(io_base, SPCR2);	DAVINCI_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 7));	return;}/* * IRQ based word transmission. */void davinci_mcbsp_xmit_word(unsigned int id, u32 word){	u32 io_base;	davinci_mcbsp_word_length word_length = mcbsp[id].tx_word_length;	if (davinci_mcbsp_check(id) < 0)		return;	io_base = mcbsp[id].io_base;	DBG(" io_base = 0x%x\n", io_base);	if (word_length > DAVINCI_MCBSP_WORD_16) {		DBG(" writing DXR2 register \n");		DAVINCI_MCBSP_WRITE(io_base, DXR2, word >> 16);	}	DBG(" writing DXR1 register \n");	DAVINCI_MCBSP_WRITE(io_base, DXR1, word & 0xffff);}u32 davinci_mcbsp_recv_word(unsigned int id){	u32 io_base;	u16 word_lsb, word_msb = 0;	davinci_mcbsp_word_length word_length = mcbsp[id].rx_word_length;	if (davinci_mcbsp_check(id) < 0)		return -EINVAL;	io_base = mcbsp[id].io_base;	if (word_length > DAVINCI_MCBSP_WORD_16)		word_msb = DAVINCI_MCBSP_READ(io_base, DRR2);	word_lsb = DAVINCI_MCBSP_READ(io_base, DRR1);	return (word_lsb | (word_msb << 16));}/* * 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 davinci_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,			      unsigned int length){	int dma_tx_ch;	int tcc;	if (davinci_mcbsp_check(id) < 0)		return -EINVAL;	if (davinci_request_dma	    (mcbsp[id].dma_tx_sync, "McBSP TX", davinci_mcbsp_tx_dma_callback,	     &mcbsp[id], &dma_tx_ch, &tcc, EVENTQ_0)) {		DBG("DAVINCI-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));	davinci_set_dma_transfer_params(mcbsp[id].dma_tx_lch, 2, length / 2, 1,					0, ASYNC);	davinci_set_dma_dest_params(mcbsp[id].dma_tx_lch,				    (unsigned long)0x01E02004, 0, 0);	davinci_set_dma_src_params(mcbsp[id].dma_tx_lch, (buffer), 0, 0);	davinci_set_dma_src_index(mcbsp[id].dma_tx_lch, 2, 0);	davinci_set_dma_dest_index(mcbsp[id].dma_tx_lch, 0, 0);	davinci_start_dma(mcbsp[id].dma_tx_lch);	wait_for_completion(&(mcbsp[id].tx_dma_completion));	return 0;}int davinci_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer,			      unsigned int length){	int dma_rx_ch;	int tcc;	if (davinci_mcbsp_check(id) < 0)		return -EINVAL;	if (davinci_request_dma	    (mcbsp[id].dma_rx_sync, "McBSP RX", davinci_mcbsp_rx_dma_callback,	     &mcbsp[id], &dma_rx_ch, &tcc, EVENTQ_0)) {		DBG("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));	davinci_set_dma_transfer_params(mcbsp[id].dma_rx_lch, 2, length / 2, 1,					0, ASYNC);	davinci_set_dma_src_params(mcbsp[id].dma_rx_lch,				   (unsigned long)0x01E02000, 0, 0);	davinci_set_dma_dest_params(mcbsp[id].dma_rx_lch,				    (unsigned long)virt_to_phys((void *)buffer),				    0, 0);	davinci_set_dma_src_index(mcbsp[id].dma_rx_lch, 0, 0);	davinci_set_dma_dest_index(mcbsp[id].dma_rx_lch, 2, 0);	davinci_start_dma(mcbsp[id].dma_rx_lch);	wait_for_completion(&(mcbsp[id].rx_dma_completion));	DBG(" davinci_mcbsp_recv_buffer: after wait_for_completion\n");	return 0;}struct clk * davinci_mcbsp_get_clock(void){	return mbspclk;}struct davinci_mcbsp_info {	u32 virt_base;	u8 dma_rx_sync, dma_tx_sync;	u16 rx_irq, tx_irq;};static const struct davinci_mcbsp_info mcbsp_davinci[] = {	[0] = {.virt_base = IO_ADDRESS(DAVINCI_MCBSP1_BASE),	       .dma_rx_sync = DAVINCI_DMA_MCBSP1_RX,	       .dma_tx_sync = DAVINCI_DMA_MCBSP1_TX,	       .rx_irq = DAVINCI_McBSP1RX,	       .tx_irq = DAVINCI_McBSP1TX},};static int __init davinci_mcbsp_init(void){	int mcbsp_count = 0, i;	static const struct davinci_mcbsp_info *mcbsp_info;	struct clk *clkp;	clkp = clk_get (NULL, "McBSPCLK");	if (IS_ERR(clkp)) {		return -1;	}	else	{		mbspclk = clkp;		clk_use (mbspclk);		clk_enable (mbspclk);		mcbsp_info = mcbsp_davinci;		mcbsp_count = ARRAY_SIZE(mcbsp_davinci);		for (i = 0; i < DAVINCI_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].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;}static void __exit davinci_mcbsp_exit(void){	int i;    for( i = 0; i < DAVINCI_MAX_MCBSP_COUNT; i++) {	    mcbsp[i].free = 0;		mcbsp[i].dma_tx_lch = -1;		mcbsp[i].dma_rx_lch = -1;    }    clk_disable (mbspclk);    clk_unuse (mbspclk);	return;}module_init(davinci_mcbsp_init);module_exit(davinci_mcbsp_exit);EXPORT_SYMBOL(davinci_mcbsp_config);EXPORT_SYMBOL(davinci_mcbsp_request);EXPORT_SYMBOL(davinci_mcbsp_free);EXPORT_SYMBOL(davinci_mcbsp_start);EXPORT_SYMBOL(davinci_mcbsp_stop);EXPORT_SYMBOL(davinci_mcbsp_xmit_word);EXPORT_SYMBOL(davinci_mcbsp_recv_word);EXPORT_SYMBOL(davinci_mcbsp_xmit_buffer);EXPORT_SYMBOL(davinci_mcbsp_recv_buffer);EXPORT_SYMBOL(davinci_mcbsp_get_clock);MODULE_AUTHOR("Texas Instruments");MODULE_DESCRIPTION("McBSP driver for DaVinci.");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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