#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");
nfr24l01驅動
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.