nfr24l01驅動

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>

#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <mach/gpio.h>

#include <plat/gpio-cfg.h>
#define uchar unsigned char

#define S3C64XX_GPICON (S3C64XX_GPI_BASE+0x00)
#define S3C64XX_GPIDAT (S3C64XX_GPI_BASE+0x04)
#define S3C64XX_GPIPUD (S3C64XX_GPI_BASE+0x08)

/**NRF24L01 command**/
#define READ_REG 0x00 
#define WRITE_REG 0x20 
#define RD_RX_PLOAD 0x61 
#define WR_TX_PLOAD 0xA0 
#define FLUSH_TX 0xE1 
#define FLUSH_RX 0xE2 
#define REUSE_TX_PL 0xE3 
#define NOP 0xFF 

/**NRF24L01 Register addr**/
#define CONFIG 0x00 // 'Config' register address
#define EN_AA 0x01 // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR 0x02 // 'Enabled RX addresses' register address
#define SETUP_AW 0x03 // 'Setup address width' register address
#define SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address
#define RF_CH 0x05 // 'RF channel' register address
#define RF_SETUP 0x06 // 'RF setup' register address
#define STATUS 0x07 // 'Status' register address
#define OBSERVE_TX 0x08 // 'Observe TX' register address
#define CD 0x09 // 'Carrier Detect' register address
#define RX_ADDR_P0 0x0A // 'RX address pipe0' register address
#define RX_ADDR_P1 0x0B // 'RX address pipe1' register address
#define RX_ADDR_P2 0x0C // 'RX address pipe2' register address
#define RX_ADDR_P3 0x0D // 'RX address pipe3' register address
#define RX_ADDR_P4 0x0E // 'RX address pipe4' register address
#define RX_ADDR_P5 0x0F // 'RX address pipe5' register address
#define TX_ADDR 0x10 // 'TX address' register address
#define RX_PW_P0 0x11 // 'RX payload width, pipe0' register address
#define RX_PW_P1 0x12 // 'RX payload width, pipe1' register address
#define RX_PW_P2 0x13 // 'RX payload width, pipe2' register address
#define RX_PW_P3 0x14 // 'RX payload width, pipe3' register address
#define RX_PW_P4 0x15 // 'RX payload width, pipe4' register address
#define RX_PW_P5 0x16 // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17 // 'FIFO Status Register' register address

/**bus width**/
#define TX_ADR_WIDTH    5   //5×??úμ?μ??·?í?è
#define RX_ADR_WIDTH    5   //5×??úμ?μ??·?í?è
#define TX_PLOAD_WIDTH  32  //2×??úμ?ó??§êy?Y?í?è
#define RX_PLOAD_WIDTH  32  //2×??úμ?ó??§êy?Y?í?è
/**functions**/
uchar init_NRF24L01(void);
uchar SPI_RW(uchar tmp);
uchar SPI_Read(uchar reg);
void SetRX_Mode(void);
uchar SPI_RW_Reg(uchar reg, uchar value);
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars);
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);
unsigned char nRF24L01_RxPacket(unsigned char* rx_buf);
void nRF24L01_TxPacket(unsigned char * tx_buf);

/** I/O function**/
void write_con(unsigned int mask,unsigned int con);
void write_dat(unsigned int mask,unsigned int dat);
void write_pud(unsigned int mask,unsigned int pud);
unsigned int get_MISO(void); 

unsigned char TX_ADDRESS[]={0x34,0x43,0x10,0x10,0x01};
unsigned char RX_ADDRESS[]={0x34,0x43,0x10,0x10,0x01};

#define TxBufSize 32
unsigned char  TxBuf[TxBufSize]={
 0x01,0x02,0x03,0x4,0x05,0x06,0x07,0x08,
 0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
 0x17,0x18,0x19,0x20,0x21,0x22,0x23,0x24,
 0x25,0x26,0x27,0x28,0x29,0x30,0x31,0x32,
};

uchar opencount = 0;

unsigned int     sta;   //×?ì?±ê??
#define   RX_DR    6
#define   TX_DS    5
#define   MAX_RT   4

#define DEVICE_NAME "NRF24L01"
#define NRF_MAJOR 97
static int nrf_major=NRF_MAJOR;
static int nrf_minor;

struct nrf_dev{
	struct cdev cdev;
	char data_tx[TX_PLOAD_WIDTH];
	char data_rx[RX_PLOAD_WIDTH];
};

struct nrf_dev *nrf_devp;

/**pin configure**/
//GPI0
#define CE_OUT write_con(0x03,0x01)  //數據線設置爲輸出
#define CE_UP write_pud(0x03,0x02)  //打開上拉電阻
#define CE_L write_dat(0x01,0)     //拉低數據線電平
#define CE_H write_dat(0x01,1)    //拉高數據線電平
//GPI1
#define CSN_OUT write_con(0x03<<2,0x01<<2)   //數據線設置爲輸出
#define CSN_UP write_pud(0x03<<2,0x02<<2   )   //打開上拉電阻
#define CSN_L write_dat(0x01<<1,0<<1)   //拉低數據線電平
#define CSN_H write_dat(0x01<<1,1<<1)  //拉高數據線電平
//GPI2
#define SCK_OUT write_con(0x03<<4,0x01<<4)   //數據線設置爲輸出
#define SCK_UP write_pud(0x03<<4,0x02<<4)  //打開上拉電阻
#define SCK_L write_dat(0x01<<2,0<<2)     //拉低數據線電平
#define SCK_H write_dat(0x01<<2,1<<2)   //拉高數據線電平
//GPI3
#define MOSI_OUT write_con(0x03<<6,0x01<<6)   //數據線設置爲輸出
#define MOSI_UP write_pud(0x03<<6,0x02<<6)  //打開上拉電阻
#define MOSI_L write_dat(0x01<<3,0<<3)  //拉低數據線電平
#define MOSI_H write_dat(0x01<<3,1<<3)  //拉高數據線電平
//GPI4
#define MISO_IN write_con(0x03<<8,0x00<<8)    //數據線設置爲輸出
#define MISO_UP write_pud(0x03<<8,0x02<<8)   //打開上拉電阻
#define MISO_STU  get_MISO()   //數據狀態
//GPI5
#define IRQ_IN write_con(0x03<<10,0x00<<10)   //數據線設置爲輸出
#define IRQ_UP write_pud(0x03<<10,0x02<<10)  //打開上拉電阻
#define IRQ_L write_dat(0x01<<5,0<<5)   //拉低數據線電平
#define IRQ_H write_dat(0x01<<5,1<<5)  //拉高數據線電平



/*pin & nrf*/
/*******************
CE-GPI0
CSN-GPI1
SCK-GPI2
MOSI-GPI3
MISO-GPI4
IRQ-GPI5
********************/

void write_con(unsigned int mask,unsigned int con)
{
	unsigned int tmp;

	tmp=readl(S3C64XX_GPICON);
	tmp=((tmp&(~mask))|con);
	writel(tmp,S3C64XX_GPICON);
}



void write_dat(unsigned int mask,unsigned int dat)
{
	unsigned int tmp;

	tmp=readl(S3C64XX_GPIDAT);
	tmp=((tmp&(~mask))|dat);
	writel(tmp,S3C64XX_GPIDAT);
}

void write_pud(unsigned int mask,unsigned int pud)
{
	unsigned int tmp;

	tmp=readl(S3C64XX_GPIPUD);
	tmp=((tmp&(~mask))|pud);
	writel(tmp,S3C64XX_GPIPUD);
}

unsigned int get_MISO(void)
{
	unsigned int tmp=0;	

	tmp=readl(S3C64XX_GPIDAT);

	if(tmp&(1<<4))
		return 1;
	else 
		return 0;
}



uchar init_NRF24L01(void)
{
    MISO_UP;
    CE_OUT;
   CSN_OUT;
    SCK_OUT;
    MOSI_OUT;
    MISO_IN;
    IRQ_IN;
    udelay(500);
    CE_L;    // chip enable
    ndelay(60);
    CSN_H;   // Spi disable 
    ndelay(60);
    SCK_L;   // Spi clock line init high
    ndelay(60);
    SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);
    SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH);
    SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);
    SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);
    SPI_RW_Reg(WRITE_REG + RF_CH, 0); 
    SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);
    SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); 

    return 1;
}



uchar SPI_RW(uchar tmp)
{
  uchar bit_ctr;
  for(bit_ctr=0 ;bit_ctr<8 ;bit_ctr++) // output 8-bit
  {
	if(tmp & 0x80)         // output 'tmp', MSB to MOSI
		MOSI_H;
	else
		MOSI_L;
	tmp = (tmp<<1);           // shift next bit into MSB..
	SCK_H;               // Set SCK high..
	ndelay(60);
	tmp |= get_MISO();          // capture current MISO bit
	SCK_L;                //then set SCK low again
	ndelay(60);
  }
	return tmp;            // return read tmp 
}



uchar SPI_Read(uchar reg)
{
  uchar reg_val;
  CSN_L;                // CSN low, initialize SPI communication...
  ndelay(60);
  SPI_RW(reg);             // Select register to read from..
  reg_val = SPI_RW(0);     // ..then read registervalue
  CSN_H;               // CSN high, terminate SPI communication
  ndelay(60);

  return reg_val;           // return register value
}



void SetRX_Mode(void)
{
  CE_L;
  ndelay(60);
  SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);
  udelay(1);
  CE_H;
  udelay(130);
}

uchar SPI_RW_Reg(uchar reg, uchar value)
{
	uchar status;   
  CSN_L;    
  ndelay(60);
  status = SPI_RW(reg); 
  SPI_RW(value);        
  CSN_H;        
  ndelay(60);   

  return status;
}

uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
{
	uchar status,uint8_ctr;   

  CSN_L;
  ndelay(60);
	status = SPI_RW(reg);

  for(uint8_ctr=0;uint8_ctr<uchars;uint8_ctr++)
  {
    pBuf[uint8_ctr] = SPI_RW(0);
    ndelay(20);
  }

  CSN_H;
  ndelay(60);  

  return status;
}



uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
{
	 uchar status,uint8_ctr;
  CSN_L;
  ndelay(60);
 	status = SPI_RW(reg);   
  for(uint8_ctr=0; uint8_ctr<uchars; uint8_ctr++)
  {
     SPI_RW(*pBuf++);
     ndelay(20);
  }
  CSN_H;   
  ndelay(60);
  
  return status;
}



unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)
{
  unsigned char revale=0;
  sta=SPI_Read(STATUS); 
  if(sta&(1<<RX_DR))
  {
     CE_L;            
	  udelay(50);
     SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);
     SPI_RW_Reg(FLUSH_RX,0);
     revale =1;
  }
  SPI_RW_Reg(WRITE_REG+STATUS,sta);
  return revale;

}



void nRF24L01_TxPacket(unsigned char * tx_buf)
{
	CE_L; 
  	ndelay(60);
 	SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);
  	SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);
  	SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);
  	CE_H;
  	udelay(10);
}



static int nrf_open(struct inode *inode,struct file *filp)
{
	uchar flag=0;
	if(opencount==1)
		return -EBUSY;

	flag=init_NRF24L01();
	mdelay(100);
	if(flag==0){
		printk("unable to init device!\n");
	return -1;
	}
	else{
		opencount++;
		printk("device open success!\n");
		return 0;
	}
}



static ssize_t nrf_read(struct file *filp,char __user *buf,size_t count,loff_t *pos)
{
	uchar temp[32]={0};
	SetRX_Mode();
	mdelay(1000);
 	if(nRF24L01_RxPacket(temp)){
		copy_to_user(buf,temp,count);
	}
	else{
		printk("Can't Receive data!\n");
		return 1;
	}

	printk("Read OK!\n");
	return 0;
}

static ssize_t nrf_write(struct file *filp,const char __user *buf,size_t count,loff_t *pos)
{
	if(copy_from_user(nrf_devp->data_tx,buf,count))    //?ó?úo?????????μ?ó??§????
  	{
  		printk("Can't Send Data !\n");
 		return -EFAULT;
  	}
  	nRF24L01_TxPacket(nrf_devp->data_tx);
	mdelay(1000);
  	SPI_RW_Reg(WRITE_REG+STATUS,0XFF); 
  	printk("Write OK! \n");
  	return 0;
}

static int nrf_release(struct inode *inode,struct file *filp)
{
	printk("Device has been closed!\n");
	opencount--;
	return 0;
}

static struct file_operations nrf_fops={
	.owner=THIS_MODULE,
	.open=nrf_open,
	.release=nrf_release,
	.read=nrf_read,
	.write=nrf_write,
};

static int __init nrf_init(void)
{
	int ret,err;
	dev_t devno;

	
	ret=alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
	nrf_major=MAJOR(devno);
	nrf_minor=MINOR(devno);
	#if 0
	devno=MKDEV(nrf_major,0);
	if(devno){
		ret=register_chrdev_region(devno,3,DEVICE_NAME);
	}
	else{
		ret=alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
		nrf_major=MAJOR(devno);
	}
	#endif
	if(ret<0)
		return ret;

	nrf_devp=kmalloc(sizeof(struct nrf_dev),GFP_KERNEL);
	if(!nrf_devp){
		printk("Error get dev memory!\n");
		ret=-ENOMEM;
		goto fail_malloc;
	}
	memset(nrf_devp,0,sizeof(struct nrf_dev));

	cdev_init(&nrf_devp->cdev,&nrf_fops);
	nrf_devp->cdev.owner=THIS_MODULE;
	err=cdev_add(&nrf_devp->cdev,devno,1);
	if(err)
		printk("Add dev error!\n");
	return 0;

fail_malloc:
	unregister_chrdev_region(devno,1);
	return ret;
}

static void __exit nrf_exit(void)
{
	cdev_del(&nrf_devp->cdev);
	kfree(nrf_devp);
	unregister_chrdev_region(MKDEV(nrf_major,0),1);
}

module_init(nrf_init);
module_exit(nrf_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("TANG");

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章