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

📄 spi.c

📁 cmmb if101 linux driver sample
💻 C
字号:
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/mm.h>#include <asm/page.h>#include <linux/poll.h>#include <linux/kdev_t.h>#include <asm/semaphore.h>//#include <asm/arch/pxa-regs.h>#include <asm-arm/arch-pxa/pxa-regs.h>#include <linux/slab.h>#include <linux/delay.h>#include <asm/uaccess.h>#include <linux/i2c.h>//#include <asm/arch/gpio.h>//#include <asm/arch/ssp.h>//#include <asm/arch/mfp.h>#include <asm/arch/hardware.h>#include <asm/dma.h>#include <linux/dma-mapping.h>#include "IF101_Operation.h"#include "IF101_Communication.h"#include <linux/interrupt.h>#include <linux/sem.h>/************************************************************************** * *		Declaration for SPI part	 *****************************************************************************/#define SPI_MODE_0  	0     //idle low, transmit falling edge, receive rising edge.#define SPI_MODE_1	1     //idle high, transmit rising edge, receive falling edge#define SPI_MODE_2  	2     //idle low, transmit rising edge, receive falling edge#define SPI_MODE_3  	3     //idle high, transmit falling edge, receive rising edge.#define SSP_PORT	1#define SPI_CLK_PIN	23//MFP_PIN_GPIO85#define SPI_CS_PIN	24//MFP_PIN_GPIO86#define SPI_SDOUT_PIN	25//MFP_PIN_GPIO87#define SPI_SDIN_PIN	26//MFP_PIN_GPIO88#define DMA_BUFFER_SIZE		PAGE_SIZE#if(SSP_PORT==1)#define DRCMR_SPI_RX	DRCMR13#define DRCMR_SPI_TX	DRCMR14#elif(SSP_PORT==2)#define DRCMR_SPI_RX	DRCMR15#define DRCMR_SPI_TX	DRCMR16#elif(SSP_PORT==3)#define DRCMR_SPI_RX	DRCMR66#define DRCMR_SPI_TX	DRCMR67#elif(SSP_PORT==4)#define DRCMR_SPI_RX	DRCMR2#define DRCMR_SPI_TX	DRCMR3#endif#define PXA_SSP_PORTS 	1#if 0static struct mhn_pin_config ssp1_pins[] = {	MHN_MFP_CFG("CLK", SPI_CLK_PIN, MFP_AF1, MFP_DS03X, 0, MFP_LPM_PULL_HIGH, MFP_EDGE_NONE),//	MHN_MFP_CFG("CS",  SPI_CS_PIN, MFP_AF1, MFP_DS03X, 0, MFP_LPM_PULL_HIGH, MFP_EDGE_NONE),	MHN_MFP_CFG("CS",  SPI_CS_PIN, MFP_AF0, MFP_DS03X, 0, MFP_LPM_PULL_HIGH, MFP_EDGE_NONE),	// manual control cs	MHN_MFP_CFG("SOUT",SPI_SDOUT_PIN, MFP_AF1, MFP_DS03X, 0, MFP_LPM_PULL_HIGH, MFP_EDGE_NONE),	MHN_MFP_CFG("SIN", SPI_SDIN_PIN, MFP_AF1, MFP_DS03X, 0, MFP_LPM_PULL_HIGH, MFP_EDGE_NONE),};#endifstruct inno_spi_dma_info{	int		txdma;	int   		rxdma;	void		*txdma_addr;	void      	*rxdma_addr;	dma_addr_t  	txdma_addr_phys;	dma_addr_t  	rxdma_addr_phys;};struct ssp_dev {        u32 port;        u32 mode;        u32 flags;        u32 psp_flags;        u32 speed;};static int spi_inited = 0;static DECLARE_MUTEX(sem);static int use_count[PXA_SSP_PORTS] = {0, 0, 0};static unsigned short clk_mode = SPI_MODE_0;static struct ssp_dev	inno_spi_dev;struct inno_spi_dma_info inno_dma;static DECLARE_MUTEX_LOCKED(dma_sem);static void inno_spi_pin_config(void);static void inno_spi_dma_init(void);static void inno_spi_dma_uninit(void);void inno_spi_write_byte(u8 cmd);void inno_spi_read_bytes(u8* pdata, u32 len);static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct ssp_dev *dev = (struct ssp_dev*) dev_id;	unsigned int status = SSSR_P(dev->port);	SSSR_P(dev->port) = status; /* clear status bits */	if (status & SSSR_ROR)		printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port);	if (status & SSSR_TUR)		printk(KERN_WARNING "SSP(%d): transmitter underrun\n", dev->port);	if (status & SSSR_BCE)		printk(KERN_WARNING "SSP(%d): bit count error\n", dev->port);	return IRQ_HANDLED;}static int ssp_init(struct ssp_dev *dev, u32 port){	int ret, irq;	if (port > PXA_SSP_PORTS || port == 0)		return -ENODEV;	down(&sem);	if (use_count[port - 1]) {		up(&sem);		return -EBUSY;	}	use_count[port - 1]++;	if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {		use_count[port - 1]--;		up(&sem);		return -EBUSY;	}	switch (port) {		case 1:			irq = IRQ_SSP;			break;#if defined (CONFIG_PXA27x)		case 2:			irq = IRQ_SSP2;			break;		case 3:			irq = IRQ_SSP3;			break;#else		case 2:			irq = IRQ_NSSP;			break;		case 3:			irq = IRQ_ASSP;			break;#endif		default:			return -ENODEV;	}	dev->port = port;	ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev);	if (ret)		goto out_region;	/* turn on SSP port clock */	switch (dev->port) {#if defined (CONFIG_PXA27x)		case 1:			pxa_set_cken(CKEN23_SSP1, 1);			break;		case 2:			pxa_set_cken(CKEN3_SSP2, 1);			break;		case 3:			pxa_set_cken(CKEN4_SSP3, 1);			break;#else		case 1:			pxa_set_cken(CKEN3_SSP, 1);			break;		case 2:			pxa_set_cken(CKEN9_NSSP, 1);			break;		case 3:			pxa_set_cken(CKEN10_ASSP, 1);			break;#endif	}	up(&sem);	return 0;out_region:	release_mem_region(__PREG(SSCR0_P(port)), 0x2c);	use_count[port - 1]--;	up(&sem);	return ret;}int ssp_write_word(struct ssp_dev *dev, u32 data){	while (!(SSSR_P(dev->port) & SSSR_TNF))		cpu_relax();	SSDR_P(dev->port) = data;	return 0;}void ssp_flush(struct ssp_dev *dev){	do {		while (SSSR_P(dev->port) & SSSR_RNE) {			(void) SSDR_P(dev->port);		}	} while (SSSR_P(dev->port) & SSSR_BSY);}int ssp_read_word(struct ssp_dev *dev){	int i = 0;	for(i = 0; i< 500; i++);	while (!(SSSR_P(dev->port) & SSSR_RNE))	{		for(i = 0; i < 100; i++);			cpu_relax();	}	return SSDR_P(dev->port);}void ssp_enable(struct ssp_dev *dev){	SSCR0_P(dev->port) |= SSCR0_SSE;}void ssp_disable(struct ssp_dev *dev){	SSCR0_P(dev->port) &= ~SSCR0_SSE;}int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed){	dev->mode = mode;	dev->flags = flags;	dev->psp_flags = psp_flags;	dev->speed = speed;	/* set up port type, speed, port settings */	SSCR0_P(dev->port) = (dev->speed | dev->mode);	SSCR1_P(dev->port) = dev->flags;	SSPSP_P(dev->port) = dev->psp_flags;	return 0;}void ssp_exit(struct ssp_dev *dev){	int irq;	down(&sem);	SSCR0_P(dev->port) &= ~SSCR0_SSE;	/* find irq, save power and turn off SSP port clock */	switch (dev->port) {#if defined (CONFIG_PXA27x)		case 1:			irq = IRQ_SSP;			pxa_set_cken(CKEN23_SSP1, 0);			break;		case 2:			irq = IRQ_SSP2;			pxa_set_cken(CKEN3_SSP2, 0);			break;		case 3:			irq = IRQ_SSP3;			pxa_set_cken(CKEN4_SSP3, 0);			break;#else		case 1:			irq = IRQ_SSP;			pxa_set_cken(CKEN3_SSP, 0);			break;		case 2:			irq = IRQ_NSSP;			pxa_set_cken(CKEN9_NSSP, 0);			break;		case 3:			irq = IRQ_ASSP;			pxa_set_cken(CKEN10_ASSP, 0);			break;#endif		default:			printk(KERN_WARNING "SSP: tried to close invalid port\n");			return;	}	free_irq(irq, dev);	release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);	use_count[dev->port - 1]--;	up(&sem);}static void SPI_StartFrame(void){	GPCR(SPI_CS_PIN) |= GPIO_bit(SPI_CS_PIN);}static void SPI_EndFrame(void){	GPSR(SPI_CS_PIN) |= GPIO_bit(SPI_CS_PIN);}INNO_RETURN_CODE INNO_SPI_Init(int enable){	int ret;	int spi_timming_mode;	if(spi_inited)		return 0;	//printk("clk_mode ====== %d\n", clk_mode);	switch(clk_mode){		case SPI_MODE_3:	//idle high, transmit falling edge, receive rising edge.			spi_timming_mode = SSCR1_SPH | SSCR1_SPO;			break;		case SPI_MODE_1:	//idle high, transmit rising edge, receive falling edge			spi_timming_mode = SSCR1_SPO;	        break;		case SPI_MODE_2:	//idle low,transmit rising edge, receive falling edge		    spi_timming_mode = SSCR1_SPH;			break;		case SPI_MODE_0:	//idle low, transmit falling edge, receive rising edge.		default:			spi_timming_mode = 0;			break;	}	printk("SSP_PORT == %d", SSP_PORT);	if(SSP_PORT == 1)	{		pxa_gpio_mode ( GPIO23_SCLK_MD );		pxa_gpio_mode (SPI_CS_PIN | GPIO_OUT);		pxa_gpio_mode ( GPIO25_STXD_MD );		pxa_gpio_mode ( GPIO26_SRXD_MD );	}	else if(SSP_PORT == 2)	{		pxa_gpio_mode( SPI_SDIN_PIN  | GPIO_ALT_FN_2_IN);		pxa_gpio_mode( SPI_CS_PIN    | GPIO_OUT);		pxa_gpio_mode( SPI_CLK_PIN   | GPIO_ALT_FN_1_OUT);		pxa_gpio_mode( SPI_SDOUT_PIN | GPIO_ALT_FN_2_OUT);	}	else if(SSP_PORT == 3)	{		pxa_gpio_mode( SPI_SDOUT_PIN | GPIO_ALT_FN_1_OUT);		pxa_gpio_mode( SPI_SDIN_PIN  | GPIO_ALT_FN_1_IN);		pxa_gpio_mode( SPI_CS_PIN    | GPIO_OUT);		pxa_gpio_mode( SPI_CLK_PIN   | GPIO_ALT_FN_1_OUT);	}	//initial SPI_nCS level high	GPSR(SPI_CS_PIN) |= GPIO_bit(SPI_CS_PIN);	memzero(&inno_spi_dev, sizeof(struct ssp_dev));	ret = ssp_init(&inno_spi_dev, SSP_PORT);	if(ret){		printk("Unable Init SPI %d.\r\n", SSP_PORT);	}else{		printk("init SPI successfully!!!");		ssp_disable(&inno_spi_dev);		ssp_config(&inno_spi_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07)), // SPI, 8bit data			(spi_timming_mode),	\			0,	\			(1<<8));		//6.5MHz	ssp_enable(&inno_spi_dev);	ssp_flush(&inno_spi_dev);	}	spi_inited = 1;	return INNO_NO_ERROR;#if 0	int ret;	int spi_timming_mode = 0;	if(enable == 1){		inno_spi_pin_config();		memzero(&inno_spi_dev, sizeof(struct ssp_dev));		ret = ssp_init(&inno_spi_dev, SSP_PORT, 0);		if(ret){			printk("Unable Init SPI %d.\r\n", SSP_PORT);		}else{			ssp_disable(&inno_spi_dev);			ssp_config(&inno_spi_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07)), // SPI, 8bit data						(spi_timming_mode),	\						0,	\						SSCR0_SerClkDiv(2));		//6.5MHz			inno_spi_dma_init();			ssp_enable(&inno_spi_dev);			ssp_flush(&inno_spi_dev);		}	}	else{		inno_spi_dma_uninit();		ssp_exit(&inno_spi_dev);	}	return INNO_NO_ERROR;#endif}INNO_RETURN_CODE INNO_SPI_Write_One_Byte(unsigned char data){	inno_spi_write_byte(data);	return INNO_NO_ERROR;}INNO_RETURN_CODE INNO_SPI_Read_One_Byte(unsigned char *data){	inno_spi_read_bytes(data,1); 	return INNO_NO_ERROR;}INNO_RETURN_CODE INNO_SPI_Read_Bytes(unsigned char *buffer, int len){	inno_spi_read_bytes(buffer,len); 	return INNO_NO_ERROR;}/* * inno spi dma functions */static void inno_spi_dma_tx_intr(int dma, void *devid, struct pt_regs *regs){	if (DCSR(inno_dma.txdma) & DCSR_ENDINTR){		DCSR(inno_dma.txdma) |= DCSR_ENDINTR;	}}static void inno_spi_dma_rx_intr(int dma, void *devid, struct pt_regs *regs){	if (DCSR(inno_dma.rxdma) & DCSR_ENDINTR){		DCSR(inno_dma.rxdma) |= DCSR_ENDINTR;	}	up(&dma_sem);}static void inno_spi_dma_init(void){	SSCR1_P(SSP_PORT) |= (SSCR1_TSRE | SSCR1_RSRE); 		//enable DMA request    	SSCR1_P(SSP_PORT) |= SSCR1_TxTresh(8)|SSCR1_RxTresh(8); //set DMA request trig threshold//	SSCR1_P(SSP_PORT) |= SSCR1_TRAIL;	inno_dma.rxdma = pxa_request_dma("Inno Rx SPI DMA", DMA_PRIO_MEDIUM, inno_spi_dma_rx_intr, NULL);    	inno_dma.txdma = pxa_request_dma("Inno TX SPI DMA", DMA_PRIO_MEDIUM, inno_spi_dma_tx_intr, NULL);    	inno_dma.txdma_addr = NULL;	inno_dma.rxdma_addr = NULL;	inno_dma.txdma_addr = dma_alloc_coherent(NULL, DMA_BUFFER_SIZE, &inno_dma.txdma_addr_phys, GFP_KERNEL);	inno_dma.rxdma_addr = dma_alloc_coherent(NULL, DMA_BUFFER_SIZE, &inno_dma.rxdma_addr_phys, GFP_KERNEL);	if((NULL == inno_dma.txdma_addr) || (NULL == inno_dma.rxdma_addr))		printk("SPI DMA alloc memory error");	memzero(inno_dma.txdma_addr, PAGE_ALIGN(DMA_BUFFER_SIZE));	memzero(inno_dma.rxdma_addr, PAGE_ALIGN(DMA_BUFFER_SIZE));		DRCMR_SPI_TX = inno_dma.txdma | DRCMR_MAPVLD;	DRCMR_SPI_RX = inno_dma.rxdma | DRCMR_MAPVLD;}static void inno_spi_dma_uninit(void){	if(inno_dma.txdma != -1){		pxa_free_dma(inno_dma.txdma);		inno_dma.txdma = -1;	}	if(inno_dma.rxdma != -1){		pxa_free_dma(inno_dma.rxdma);		inno_dma.rxdma = -1;	}	if(inno_dma.txdma_addr != NULL){		dma_free_coherent(NULL, DMA_BUFFER_SIZE, inno_dma.txdma_addr, inno_dma.txdma_addr_phys);		inno_dma.txdma_addr = NULL;	}	if(inno_dma.rxdma_addr != NULL){		dma_free_coherent(NULL, DMA_BUFFER_SIZE, inno_dma.rxdma_addr, inno_dma.rxdma_addr_phys);		inno_dma.rxdma_addr = NULL;	}}/* * start launch DMA for transfer @size bytes */static void inno_spi_rxdma_start(u32 size){	DCSR(inno_dma.rxdma)  = DCSR_NODESC;    	DSADR(inno_dma.rxdma) = __PREG(SSDR_P(SSP_PORT));	DTADR(inno_dma.rxdma) = inno_dma.rxdma_addr_phys;	DCMD(inno_dma.rxdma)  = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST8 | (size & DCMD_LENGTH);	DCSR(inno_dma.rxdma) |= DCSR_RUN;}static void inno_spi_txdma_start(u32 size){	DCSR(inno_dma.txdma)  = DCSR_NODESC;	DSADR(inno_dma.txdma) = inno_dma.txdma_addr_phys;	DTADR(inno_dma.txdma) = __PREG(SSDR_P(SSP_PORT));	DCMD(inno_dma.txdma)  =  DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST8 | (size & DCMD_LENGTH);    	DCSR(inno_dma.txdma) |= DCSR_RUN;}static void inno_spi_dma_start(u32 size){	SSCR0_P(SSP_PORT) &= ~SSCR0_SSE;	SSCR0_P(SSP_PORT) |= SSCR0_SSE;		inno_spi_rxdma_start(size);	inno_spi_txdma_start(size);}/* * configure SPI GPIO Setting */static void inno_spi_pin_config(void){#if 0	if(SSP_PORT == 1){		mhn_mfp_set_configs(ssp1_pins, ARRAY_SIZE(ssp1_pins));		mhn_gpio_set_direction(SPI_CLK_PIN, GPIO_DIR_OUT);	//clk		mhn_gpio_set_direction(SPI_CS_PIN, GPIO_DIR_OUT);	//ncs		mhn_gpio_set_direction(SPI_SDOUT_PIN, GPIO_DIR_OUT);	//sdout		mhn_gpio_set_direction(SPI_SDIN_PIN, GPIO_DIR_IN);	//sdin					mhn_gpio_set_level(SPI_CS_PIN, GPIO_LEVEL_HIGH);	//init ncs high	}#endif}static void inno_spi_start_frame(void){//	mhn_gpio_set_level(SPI_CS_PIN, GPIO_LEVEL_LOW);	GPCR(SPI_CS_PIN) |= GPIO_bit(SPI_CS_PIN);}static void inno_spi_end_frame(void){	//mhn_gpio_set_level(SPI_CS_PIN, GPIO_LEVEL_HIGH);	GPSR(SPI_CS_PIN) |= GPIO_bit(SPI_CS_PIN);}/* * inno_spi_write_byte * 		@cmd 		- 8-bit length mmis command * return *		@null */void inno_spi_write_byte(u8 cmd){	inno_spi_start_frame();	ssp_write_word(&inno_spi_dev, cmd);//    /* Read null data back from device to prevent SSP overflow *///    ssp_read_word(&inno_spi_dev);	ssp_flush(&inno_spi_dev);		inno_spi_end_frame();}/*  * note: if101 chip need nCS keep low staus when read until datas read end. * if we use spi controller to control nCS, the nCS will pull high after read every byte,  * so we should manual control nCS pin */void inno_spi_read_bytes(u8* pdata, u32 len){	u32 i;		SPI_StartFrame();	for(i=0; i<len; i++){		ssp_write_word(&inno_spi_dev, 0);	// in order to generate clock to receive		*(pdata+i) = (u8)(ssp_read_word(&inno_spi_dev));	}	SPI_EndFrame();#if 0	u32 count = 0;		u32 len_dma = len;	u8* pbuf = pdata;	inno_spi_start_frame();	if(len > 8){		if(len%8!=0)	//filled to multiple of 8bytes			len_dma = (len+7)/8*8;		while(len_dma > 0){			count = min(len_dma, (u32)DMA_BUFFER_SIZE);			inno_spi_dma_start(count);			down_interruptible(&dma_sem);			len_dma -= count;			memcpy(pbuf, inno_dma.rxdma_addr, min(count, len));			len -= min(count, len);			pbuf += min(count,len);		}		goto out;	}	for(count=0; count<len; count++){		ssp_write_word(&inno_spi_dev, 0);	// in order to generate clock to receive		*(pdata+count) = ssp_read_word(&inno_spi_dev);	}out:		inno_spi_end_frame();#endif}

⌨️ 快捷键说明

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