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

📄 can.c

📁 车载信息系统开发源码
💻 C
字号:
#ifndef __KERNEL__
#  define __KERNEL__
#endif
#ifndef MODULE
#  define MODULE
#endif

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/blkpg.h>
#include <linux/hdreg.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/fcntl.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/compatmac.h>
#include <linux/vmalloc.h>
#include <linux/config.h>
#include <asm/uaccess.h>
#include <linux/pm.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/wait.h>
#include <asm/dma.h>
#include <linux/genhd.h>

#include "mx1_def.h"
#include "can.h"
#include "error.h"
#include "mx1_gpio.h"
#include "mx1_spi.h"
#include "spi_cmd.h"
#include "mcp2510.h"
#include "mx1.h"

int spi_open(struct inode * inode, struct file * filp);
int spi_release(struct inode * inode, struct file * filp);
ssize_t spi_read(struct file * filp, char * buf, size_t count, loff_t * l);
ssize_t spi_write(struct file * filp, const char * buf, size_t count, loff_t * l);
U32 getclkdiv(U32 khz);

struct file_operations spi_fops = {
	owner:		THIS_MODULE,
	open:	        spi_open,
	release:   	spi_release,
	read:		spi_read,
	write:	       spi_write,
};

#define DEVICE_NAME		"spi_can"
int spi_major = SPI_MAJOR;
unsigned char spi_usage=0;


U32 getclkdiv(U32 khz)
{
	unsigned int PCLKDIV2=0, reg=0, SPIDIV=0, SPD=0,
		      SMFD=0, SMFI=0, SMFN=0,  CLK=0;
    
	reg = V_ADDRESS(PLL_UPCTL0);
	SPD = (reg & 0x3C000000)>>26;
	SMFD=(reg & 0x03ff0000)>>16;
	SMFI= (reg & 0x00003c00)>>10;
	SMFN=(reg & 0x000003ff);
	reg=V_ADDRESS(PLL_PCDR);
	PCLKDIV2=(reg &	0x000000f0)>>4;
	CLK=2*16384*(SMFI+(SMFN/(SMFD+1)))/(SPD+1);
	CLK=CLK/(PCLKDIV2+1);
	SPIDIV=(CLK/(khz*1000));

	if(SPIDIV < 4) 		return 0;
	if(SPIDIV < 8) 		return (0x001 << 13);
	if(SPIDIV < 16) 		return (0x010 << 13);
	if(SPIDIV < 32) 		return (0x011 << 13);
	if(SPIDIV < 64) 		return (0x100 << 13);
	if(SPIDIV < 128) 		return (0x101 << 13);
	if(SPIDIV < 256) 		return (0x110 << 13);
	else 				return (0x111 << 13);

}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int spi_open (struct inode *inode, struct file *filp)
{

	if(spi_usage) 	return -EBUSY;
	MCP2510_Init();
 	MOD_INC_USE_COUNT;
	return 0;          /* success */
}

int spi_release (struct inode *inode, struct file *filp)
{

	MOD_DEC_USE_COUNT;
	return 0;
}

ssize_t spi_read (struct file *filp, char *buf, 
				size_t count, loff_t *f_pos)
{
	int i;
	char bf[count];

	if(count > 8)
		count=8;

	memset(bf,0,count);


	for(i=0; i<count;i++)
	{
		while ( !( CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANINTF)), ARG_UNUSED, ARG_UNUSED )&0x01 ))
		{
			mdelay(100);
		}
	
	        mdelay(100);
		bf[i]=CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0D0))+i, ARG_UNUSED, ARG_UNUSED ) ;
		CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANINTF)), 0x01, 0x00 );

	}
	copy_to_user(buf,bf,count);
	return count;
}

void MCP2510_TX( int TxBuf, int IdType, unsigned int id, int DataLen, char * data )
{
	int i, offset=0;

	if( DataLen>8 )
		DataLen = 8;

	switch( TxBuf ){
		case TXBUF0:
			offset = 0;
			break;
		case TXBUF1:
			offset = 0x10;
			break;
		case TXBUF2:
			offset = 0x20;
			break;
	}
	// Set the frame identifier
	if( IdType==STANDID ){
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0SIDL))+offset, (id&0x7)<<5, ARG_UNUSED );
		mdelay(100);
		
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0SIDH))+offset, (id>>3)&0xff, ARG_UNUSED );
		mdelay(100);
		

	}else if( IdType==EXTID ){
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0EID0))+offset, id&0xff, ARG_UNUSED );
		mdelay(100);
		
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0EID8))+offset, (id>>8)&0xff, ARG_UNUSED );		
		mdelay(100);
		

		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0SIDL)), ((id>>16)&0x3)|0x08, ARG_UNUSED );
		mdelay(100);

	}
	// Set the data length
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0DLC))+offset, DataLen, ARG_UNUSED );
	mdelay(100);

	
	// fill the data
	for( i=0; i<DataLen; i++ ){
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0D0))+offset+i, data[i], ARG_UNUSED );
		mdelay(100);

	}
	// initiate transmit
	while( CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->TXB0CTRL))+offset, ARG_UNUSED, ARG_UNUSED )&0x08 );
	mdelay(100);

	CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->TXB0CTRL))+offset, 0x08, 0x08 );
}


ssize_t spi_write (struct file *filp, const char *buf,size_t count,  loff_t *f_pos)
{

	char bf[count];
//	int i;

	if(count >8)
		count=8;

	copy_from_user(bf,buf,count);

	MCP2510_TX(TXBUF2, STANDID, 23, count , bf);

	return count;
}

int MX1_GPIO_Conf( T_MX1_GPIO *port, unsigned char pin, unsigned char func, unsigned char dir, unsigned char src )
{
	// Check the validation of pins, because not all pins are usable
	if( pin>31 ){
		printk( "Pin number is out of boundary!" );
		return -1;
	}
	else if( port==MX1_GPIO_PB&&((1<<pin)&MX1_GPIO_PB_USABLE)==0 ){
		printk( "This pin of port B is not usable!" );
		return -1;
	}
	else if( port==MX1_GPIO_PC&&((1<<pin)&MX1_GPIO_PC_USABLE)==0 ){
		printk( "This pin of port C is not usable!" );
		return -1;
	}
	else if( port==MX1_GPIO_PD&&((1<<pin)&MX1_GPIO_PD_USABLE)==0 ){
		printk( "This pin of port D is not usable!" );
		return -1;
	}
	// configure the function
	switch( func ){
		case FUNC_IO:
			GIUS_FOR_IO(port, pin);
			break;
		case FUNC_PRI:	
			GIUS_FOR_MUX( port, pin );
			GPR_SEL_PRI( port, pin ); 
			break;
		case FUNC_ALT:	
			GIUS_FOR_MUX( port, pin );
			GPR_SEL_ALT( port, pin ); 
			break;
		default:
			printk( "Invalid gpio function parameter!" );
			return -1;
	}
	// configure the data direction
	switch( dir ){
		case DIR_IN:	
			DDIR_IN( port, pin );
			///////////////Not finished/////////////////
			switch( src ){
				case SRC_IN_ANY:	break;
				case SRC_IN_GPIO:
					ICONFA_SEL_IN( port, pin );
					ICONFB_SEL_IN( port, pin );	
					break;
				case SRC_IN_INTSTA:
					ICONFA_SEL_ISR( port, pin );
					ICONFB_SEL_ISR( port, pin );	
					break;
				case SRC_IN_0:
					ICONFA_SEL_0( port, pin );
					ICONFB_SEL_0( port, pin );	
					break;
				case SRC_IN_1:
					ICONFA_SEL_1( port, pin );	
					ICONFB_SEL_1( port, pin );	
					break;
				default:
					printk( "Invalid input source parameter!" );
					return -1;
			}
			break;
			/////////////////////////////////////////
		case DIR_OUT:	
			DDIR_OUT( port, pin ); 
			switch( src ){
				case SRC_OUT_ANY:	break;
				case SRC_OUT_A:
					OCR_SEL_A(port, pin); break;
				case SRC_OUT_B:
					OCR_SEL_B(port, pin); break;
				case SRC_OUT_C:
					OCR_SEL_C(port, pin); break;
				case SRC_OUT_DR:
					OCR_SEL_DR(port, pin); break;
				default:
					printk("Invalid output source parameter!");
					return -1;
			}
			break;
		default:		
			printk( "Invalid gpio direction parameter!" );
			return -1;
	}
	return 0;
}
 


void MX1_SPI_Init( T_MX1_SPI* spi_module )
{
	// Software Reset
	spi_module->RESETREG = RESETREG_START;
	// Configure the GPIO port pins for SPI
	if( spi_module==MX1_SPI1 ){
		// SPI1_RDY pin
		//MX1_GPIO_Conf( MX1_GPIO_PC, 13, FUNC_PRI, DIR_IN, SRC_IN_ANY );
		// SPI1_SCLK pin
		MX1_GPIO_Conf( MX1_GPIO_PC, 14, FUNC_PRI, DIR_OUT, SRC_OUT_ANY );
		// SPI1_SS
		MX1_GPIO_Conf( MX1_GPIO_PC, 15, FUNC_PRI, DIR_OUT, SRC_OUT_ANY ); 
		// SPI1_MISO
		MX1_GPIO_Conf( MX1_GPIO_PC, 16, FUNC_PRI, DIR_IN, SRC_IN_ANY );
		// SPI1_MOSI
		MX1_GPIO_Conf( MX1_GPIO_PC, 17, FUNC_PRI, DIR_OUT, SRC_OUT_ANY );
	}else{
		printk( "Not implemented!" );
	}
	// set Loop Back Mode for testing
	spi_module->TESTREG = LBC_DISABLE;
//	V_ADDRESS(0x00213010) =0x4000; 

	//spi_module->PERIODREG = CSRC_32K|WAIT( 128 );
	//spi_module->INTREG = 0x0;
	// set the control register and enable the module
	spi_module->CONTROLREG = DATARATE_BY128|MODE_MASTER|SSPOL_LOW|SSCTL_STAY_LOW|SPIEN_ENABLE|PHA_Phase1|POL_LOW|(BIT_COUNT(7));
//	spi_module->CONTROLREG = DATARATE_BY128|MODE_MASTER|SSPOL_LOW|SSCTL_STAY_LOW|SPIEN_ENABLE|PHA_Phase1|POL_LOW|(BIT_COUNT(7)); 
#if 0
	CAN_SPI_MODULE->TXDATAREG =0xa95a;
	CAN_SPI_MODULE->CONTROLREG |= XCH_INITIATE;
	mdelay(1000);
	printk("\n test:%x", CAN_SPI_MODULE->RXDATAREG);
#endif
}

void MX1_SPI_RXFlush( T_MX1_SPI* spi_module )
{
	int tmp;

	while( spi_module->INTREG&INTREG_RR )
		tmp = spi_module->RXDATAREG;
//	printk("MX1_SPI_RXFlush = %x", spi_module->INTREG);
	
}
void MX1_SPI_TXFlush( T_MX1_SPI* spi_module )
{

	while( !(spi_module->INTREG&INTREG_TE) )
		spi_module->CONTROLREG |= XCH_INITIATE;
}


unsigned char CAN_SPI_CMD( unsigned char cmd, unsigned long addr, unsigned char arg1, unsigned char arg2 )
{
	unsigned char ret=0;

	// Empty the spi's transfer and receive buffer
	MX1_SPI_TXFlush( CAN_SPI_MODULE );
	MX1_SPI_RXFlush( CAN_SPI_MODULE );
	switch( cmd ){
		case SPI_CMD_READ:
			while( !(CAN_SPI_MODULE->INTREG&INTREG_TE) );
			CAN_SPI_MODULE->TXDATAREG = cmd;
			CAN_SPI_MODULE->TXDATAREG = addr;
			CAN_SPI_MODULE->TXDATAREG = 0xff; // maintain the SCK clock for CAN to transfer the result
			CAN_SPI_MODULE->CONTROLREG |= XCH_INITIATE;	// Initiate the transmission
		
			while( !(CAN_SPI_MODULE->INTREG&INTREG_RR) );	// read the result from can-spi
			ret = CAN_SPI_MODULE->RXDATAREG;
			while( !(CAN_SPI_MODULE->INTREG&INTREG_RR) );
			ret = CAN_SPI_MODULE->RXDATAREG;
			while( !(CAN_SPI_MODULE->INTREG&INTREG_RR) );
			ret = CAN_SPI_MODULE->RXDATAREG;
			break;
		case SPI_CMD_WRITE:
			while( !(CAN_SPI_MODULE->INTREG&INTREG_TE) );
			CAN_SPI_MODULE->TXDATAREG = cmd;
			CAN_SPI_MODULE->TXDATAREG = addr;
			CAN_SPI_MODULE->TXDATAREG = arg1;
			CAN_SPI_MODULE->CONTROLREG |= XCH_INITIATE;	// Initiate the transmission
			break;
		case SPI_CMD_RTS:
			while( !(CAN_SPI_MODULE->INTREG&INTREG_TE) );
			CAN_SPI_MODULE->TXDATAREG = cmd;
			CAN_SPI_MODULE->CONTROLREG |= XCH_INITIATE;	// Initiate the transmission
			break;
		case SPI_CMD_READSTA:
			while( !(CAN_SPI_MODULE->INTREG&INTREG_TE) );
			CAN_SPI_MODULE->TXDATAREG = cmd;
			CAN_SPI_MODULE->TXDATAREG = 0xff; // maintain the SCK clock for CAN to transfer the result
			CAN_SPI_MODULE->CONTROLREG |= XCH_INITIATE;	// Initiate the transmission
			
			while( !(CAN_SPI_MODULE->INTREG&INTREG_RR) );	// read the result from can-spi
			ret = CAN_SPI_MODULE->RXDATAREG;
			while( !(CAN_SPI_MODULE->INTREG&INTREG_RR) );
			ret = CAN_SPI_MODULE->RXDATAREG;
			break;
		case SPI_CMD_BITMOD:
			while( !(CAN_SPI_MODULE->INTREG&INTREG_TE) );
			CAN_SPI_MODULE->TXDATAREG = cmd;
			CAN_SPI_MODULE->TXDATAREG = addr;
			CAN_SPI_MODULE->TXDATAREG = arg1;
			CAN_SPI_MODULE->TXDATAREG = arg2;
			CAN_SPI_MODULE->CONTROLREG |= XCH_INITIATE;	// Initiate the transmission
			break;
		case SPI_CMD_RESET:
			while( !(CAN_SPI_MODULE->INTREG&INTREG_TE) );
			CAN_SPI_MODULE->TXDATAREG = cmd;
			CAN_SPI_MODULE->CONTROLREG |= XCH_INITIATE;	// Initiate the transmission
//			while(!(CAN_SPI_MODULE->INTREG&INTREG_RR ));
//				printk("\n rx reset:  %x", CAN_SPI_MODULE->RXDATAREG);
			break;
		default:
			break;	// any value is ok
	}
	MX1_SPI_TXFlush( CAN_SPI_MODULE );
	MX1_SPI_RXFlush( CAN_SPI_MODULE );
	return ret;
}


void MCP2510_Init( void )
{
	// Configure the SPI Interface in MX1
	MX1_SPI_Init( CAN_SPI_MODULE ); 
	// Configure the mcp2510 through spi interface

	// Reset controller
	CAN_SPI_CMD( SPI_CMD_RESET, ARG_UNUSED, ARG_UNUSED, ARG_UNUSED );
	// make sure we are in configuration mode
	mdelay(100);
	while( (CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANSTAT)), ARG_UNUSED, ARG_UNUSED )>>5)!=0x04 );
	// start configuration
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->BFPCTRL)), BFPCTRL_INIT_VAL, ARG_UNUSED);
	mdelay(100);

	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXRTSCTRL)), TXRTSCTRL_INIT_VAL, ARG_UNUSED);
	mdelay(100);

	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CNF3)), CNF3_INIT_VAL, ARG_UNUSED);
	mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CNF2)), CNF2_INIT_VAL, ARG_UNUSED);
	mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CNF1)), CNF1_INIT_VAL, ARG_UNUSED);
        mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CANINTE)), CANINTE_INIT_VAL, ARG_UNUSED);
        mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CANINTF)), CANINTF_INIT_VAL, ARG_UNUSED);
	 mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->EFLG)), EFLG_INIT_VAL, ARG_UNUSED);
	mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0CTRL)), TXBnCTRL_INIT_VAL, ARG_UNUSED);
        mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB1CTRL)), TXBnCTRL_INIT_VAL, ARG_UNUSED);
	mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB2CTRL)), TXBnCTRL_INIT_VAL, ARG_UNUSED);
	mdelay(100);


	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->RXB0CTRL)), RXB1CTRL_INIT_VAL, ARG_UNUSED);
	mdelay(100);

	
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->RXB1CTRL)), RXB1CTRL_INIT_VAL, ARG_UNUSED);
	mdelay(100);

	
	// switch to normal mode or loopback mode ( for testing)
	CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANCTRL)), 0xe0, 0x40 );	// LOOP BACK MODE
	mdelay(100);

	mdelay(100);

//	CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANCTRL)), 0xe0, 0x00 );	// NORMAL OPERATION MODE
	// Flush the MX1 SPI receive buffer
}


int __init spi_init(void)
{
	int result = 0;

	result = register_chrdev(spi_major, DEVICE_NAME, &spi_fops);
	if (result < 0) 	{
		printk("SPI ERROR: Can't  get MAJOR %d", spi_major);
		return result;
	}
	if (spi_major == 0)  spi_major = result; /* dynamic */
//	MCP2510_Init();

	return 0;
}

void __exit spi_cleanup(void)
{

	unregister_chrdev(spi_major, DEVICE_NAME);
}

module_init(spi_init);
module_exit(spi_cleanup);

⌨️ 快捷键说明

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