📄 can.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 + -