|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
最近在学2440的裸奔程序,有一个疑问:可不可以把裸奔程序直接套进Linux驱动框架里面而转成Linux驱动呢?
于是尝试了一下,遇到了一些困难,望大家能指导一下。
原始的裸奔程序,是mini2440出厂自带的测试程序,IIC的驱动,在iic.c文件中(中断模式):
- #include <string.h>
- #include "2440addr.h"
- #include "2440lib.h"
- #include "def.h"
- #include "IIC.h"
- static U8 _iicData[IICBUFSIZE];
- static volatile int _iicDataCount;
- static volatile int _iicStatus;
- static volatile int _iicMode;
- static int _iicPt;
- //===================================================================
- // SMDK2440 IIC configuration
- // GPE15=IICSDA, GPE14=IICSCL
- // "Interrupt mode" for IIC block
- //===================================================================
- //******************[ Test_Iic ]**************************************
- void Test_Iic(void)
- {
- unsigned int i,j,save_E,save_PE;
- static U8 data[256];
- Uart_Printf("\nIIC Test(Interrupt) using AT24C02\n");
- save_E = rGPECON;
- save_PE = rGPEUP;
- rGPEUP |= 0xc000; //Pull-up disable
- rGPECON |= 0xa00000; //GPE15:IICSDA , GPE14:IICSCL
- pISR_IIC = (unsigned)IicInt;
- rINTMSK &= ~(BIT_IIC);
- //Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16
- // If PCLK 50.7MHz, IICCLK = 3.17MHz, Tx Clock = 0.198MHz
- rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
- rIICADD = 0x10; //2440 slave address = [7:1]
- rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx)
- rIICLC = (1<<2)|(1); // Filter enable, 15 clocks SDA output delay added by junon
-
- Uart_Printf("Write test data into AT24C02\n");
- for(i=0;i<256;i++)
- Wr24C080(0xa0,(U8)i,i);
-
- for(i=0;i<256;i++)
- data[i] = 0;
- Uart_Printf("Read test data from AT24C02\n");
-
- for(i=0;i<256;i++)
- Rd24C080(0xa0,(U8)i,&(data[i]));
- //Line changed 0 ~ f
- for(i=0;i<16;i++)
- {
- for(j=0;j<16;j++)
- Uart_Printf("%2x ",data[i*16+j]);
- Uart_Printf("\n");
- }
- rINTMSK |= BIT_IIC;
- rGPEUP = save_PE;
- rGPECON = save_E;
- }
- //*************************[ Wr24C080 ]****************************
- void Wr24C080(U32 slvAddr,U32 addr,U8 data)
- {
- _iicMode = WRDATA;
- _iicPt = 0;
- _iicData[0] = (U8)addr;
- _iicData[1] = data;
- _iicDataCount = 2;
-
- rIICDS = slvAddr; //0xa0
- rIICSTAT = 0xf0; //MasTx,Start
- //Clearing the pending bit isn't needed because the pending bit has been cleared.
-
- while(_iicDataCount!=-1);
- _iicMode = POLLACK;
- while(1)
- {
- rIICDS = slvAddr;
- _iicStatus = 0x100;
- rIICSTAT = 0xf0; //MasTx,Start
- rIICCON = 0xaf; //Resumes IIC operation.
-
- while(_iicStatus==0x100);
-
- if(!(_iicStatus&0x1))
- break; //When ACK is received
- }
- rIICSTAT = 0xd0; //Stop MasTx condition
- rIICCON = 0xaf; //Resumes IIC operation.
- Delay(1); //Wait until stop condtion is in effect.
- //Write is completed.
- }
-
- //**********************[ Rd24C080 ] ***********************************
- void Rd24C080(U32 slvAddr,U32 addr,U8 *data)
- {
- _iicMode = SETRDADDR;
- _iicPt = 0;
- _iicData[0] = (U8)addr;
- _iicDataCount = 1;
- rIICDS = slvAddr;
- rIICSTAT = 0xf0; //MasTx,Start
- //Clearing the pending bit isn't needed because the pending bit has been cleared.
- while(_iicDataCount!=-1);
- _iicMode = RDDATA;
- _iicPt = 0;
- _iicDataCount = 1;
-
- rIICDS = slvAddr;
- rIICSTAT = 0xb0; //MasRx,Start
- rIICCON = 0xaf; //Resumes IIC operation.
- while(_iicDataCount!=-1);
- *data = _iicData[1];
- }
- //-------------------------------------------------------------------------
- void __irq IicInt(void)
- {
- U32 iicSt,i;
-
- rSRCPND = BIT_IIC; //Clear pending bit
- rINTPND = BIT_IIC;
- iicSt = rIICSTAT;
-
- if(iicSt & 0x8){} //When bus arbitration is failed.
- if(iicSt & 0x4){} //When a slave address is matched with IICADD
- if(iicSt & 0x2){} //When a slave address is 0000000b
- if(iicSt & 0x1){} //When ACK isn't received
- switch(_iicMode)
- {
- case POLLACK:
- _iicStatus = iicSt;
- break;
- case RDDATA:
- if((_iicDataCount--)==0)
- {
- _iicData[_iicPt++] = rIICDS;
-
- rIICSTAT = 0x90; //Stop MasRx condition
- rIICCON = 0xaf; //Resumes IIC operation.
- Delay(1); //Wait until stop condtion is in effect.
- //Too long time...
- //The pending bit will not be set after issuing stop condition.
- break;
- }
- _iicData[_iicPt++] = rIICDS; //The last data has to be read with no ack.
- if((_iicDataCount)==0)
- rIICCON = 0x2f; //Resumes IIC operation with NOACK.
- else
- rIICCON = 0xaf; //Resumes IIC operation with ACK
- break;
- case WRDATA:
- if((_iicDataCount--)==0)
- {
- rIICSTAT = 0xd0; //Stop MasTx condition
- rIICCON = 0xaf; //Resumes IIC operation.
- Delay(1); //Wait until stop condtion is in effect.
- //The pending bit will not be set after issuing stop condition.
- break;
- }
- rIICDS = _iicData[_iicPt++]; //_iicData[0] has dummy.
- for(i=0;i<10;i++); //for setup time until rising edge of IICSCL
-
- rIICCON = 0xaf; //resumes IIC operation.
- break;
- case SETRDADDR:
- // Uart_Printf("[ S%d ]",_iicDataCount);
- if((_iicDataCount--)==0)
- break; //IIC operation is stopped because of IICCON[4]
- rIICDS = _iicData[_iicPt++];
- for(i=0;i<10;i++); //For setup time until rising edge of IICSCL
- rIICCON = 0xaf; //Resumes IIC operation.
- break;
- default:
- break;
- }
- }
复制代码
相应的,我直接把上面的程序套到Linux字符驱动的框架里面,除了进行地址映射和寄存器使用函数读取和赋值以外,没有大的改动:
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/types.h>
- #include <linux/mm.h>
- #include <linux/gpio.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <linux/device.h>
- #include <linux/miscdevice.h>
- #include <linux/clk.h>
- #include <linux/interrupt.h>
- #include <mach/regs-gpio.h>
- #include <asm/mach/time.h>
- #include <plat/regs-timer.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <mach/hardware.h>
- #include <linux/irq.h>
- #include <linux/kfifo.h>
- #define U32 unsigned long
- static void __iomem *gpio_base_addr;
- static void __iomem *iic_base_addr;
- static void __iomem *timer_base_addr;
- #define TIMER_PA 0x51000000
- #define rTCFG0 (*(volatile unsigned *)(0x00+timer_base_addr)) //Timer 0 configuration
- #define rTCFG1 (*(volatile unsigned *)(0x04+timer_base_addr)) //Timer 1 configuration
- #define rTCON (*(volatile unsigned *)(0x08+timer_base_addr)) //Timer control
- #define rTCNTB3 (*(volatile unsigned *)(0x30+timer_base_addr)) //Timer count buffer 3
- #define rTCMPB3 (*(volatile unsigned *)(0x34+timer_base_addr)) //Timer compare buffer 3
- #define rTCNTO3 (*(volatile unsigned *)(0x38+timer_base_addr)) //Timer count observation 3
- #define GPIO_PA 0x56000040
- #define rGPECON (0x00+gpio_base_addr)
- #define rGPEUP (0x08+gpio_base_addr)
- #define IIC_PA 0x54000000
- #define rIICCON 0x00+iic_base_addr
- #define rIICSTAT 0x04+iic_base_addr
- #define rIICADD 0x08+iic_base_addr
- #define rIICDS 0x0c+iic_base_addr
- #define rIICLC 0x10+iic_base_addr
- #define WRDATA (1)
- #define POLLACK (2)
- #define RDDATA (3)
- #define SETRDADDR (4)
- #define IICBUFSIZE 0x20
- #define DEVICE_NAME "iic"
- MODULE_LICENSE("Dual BSD/GPL");
- static int iic_major=254;
- static unsigned long gpecon_save, gpeup_save;
- module_param(iic_major, int, S_IRUGO);
- struct cdev cdev;
- static struct semaphore lock;
- static unsigned long slvAddr = 0xa0;
- static unsigned char _iicData[IICBUFSIZE];
- static volatile int _iicDataCount;
- static volatile int _iicStatus;
- static volatile int _iicMode;
- static int _iicPt;
- static unsigned long rd_addr = 0;
- static unsigned long wr_addr = 0;
- void Delay(int time)
- {
- unsigned long PCLK = 50000000;
- U32 val = (PCLK>>3)/1000-1;
-
- rTCFG0 &= ~(0xff<<8);
- rTCFG0 |= 3<<8; //prescaler = 3+1
- rTCFG1 &= ~(0xf<<12);
- rTCFG1 |= 0<<12; //mux = 1/2
- rTCNTB3 = val;
- rTCMPB3 = val>>1; // 50%
- rTCON &= ~(0xf<<16);
- rTCON |= 0xb<<16; //interval, inv-off, update TCNTB3&TCMPB3, start timer 3
- rTCON &= ~(2<<16); //clear manual update bit
- while(time--) {
- while(rTCNTO3>=val>>1);
- while(rTCNTO3<val>>1);
- };
- }
- static irqreturn_t iic_interrupt(int irq, void * dev_id)
- {
- U32 iicSt,i;
-
- // rSRCPND = BIT_IIC; //Clear pending bit
- // rINTPND = BIT_IIC;
- iicSt = ioread32(rIICSTAT);
-
- if(iicSt & 0x8){} //When bus arbitration is failed.
- if(iicSt & 0x4){} //When a slave address is matched with IICADD
- if(iicSt & 0x2){} //When a slave address is 0000000b
- if(iicSt & 0x1){} //When ACK isn't received
- switch(_iicMode)
- {
- case POLLACK:
- _iicStatus = iicSt;
- break;
- case RDDATA:
- if((_iicDataCount--)==0)
- {
- _iicData[_iicPt++] = ioread32(rIICDS);
-
- iowrite32(0x90, rIICSTAT); //Stop MasRx condition
- iowrite32(0xaf, rIICCON); //Resumes IIC operation.
- Delay(1); //Wait until stop condtion is in effect.
- //Too long time...
- //The pending bit will not be set after issuing stop condition.
- break;
- }
- _iicData[_iicPt++] = ioread32(rIICDS); //The last data has to be read with no ack.
- if((_iicDataCount)==0)
- iowrite32(0x2f,rIICCON); //Resumes IIC operation with NOACK.
- else
- iowrite32(0xaf,rIICCON); //Resumes IIC operation with ACK
- break;
- case WRDATA:
- printk("write interrupt\n");
- if((_iicDataCount--)==0)
- {
- iowrite32(0xd0,rIICSTAT); //Stop MasTx condition
- iowrite32(0xaf,rIICCON); //Resumes IIC operation.
- Delay(1); //Wait until stop condtion is in effect.
- //The pending bit will not be set after issuing stop condition.
- break;
- }
- iowrite32(_iicData[_iicPt++], rIICDS); //_iicData[0] has dummy.
- for(i=0;i<10;i++); //for setup time until rising edge of IICSCL
-
- iowrite32(0xaf,rIICCON); //resumes IIC operation.
- break;
- case SETRDADDR:
- // Uart_Printf("[ S%d ]",_iicDataCount);
- if((_iicDataCount--)==0)
- break; //IIC operation is stopped because of IICCON[4]
- iowrite32(_iicData[_iicPt++], rIICDS);
- for(i=0;i<10;i++); //For setup time until rising edge of IICSCL
- iowrite32(0xaf,rIICCON); //Resumes IIC operation.
- break;
- default:
- break;
- }
- return IRQ_HANDLED;
- }
- static int iic_open(struct inode *inode, struct file *filp)
- {
- int ret;
- unsigned long gpe;
- // if(!down_trylock(&lock))
- {
- // printk("open succeed.\n");
- // printk("%x\n",S3C2410_TCFG0);
- // unsigned long a=ioread32(S3C2410_TCFG0);
- // printk("%x\n",a);
- gpe = ioread32(rGPECON);
- gpecon_save = gpe;
- iowrite32(gpe|0xa00000, rGPECON);
- gpe = ioread32(rGPEUP);
- gpeup_save = gpe;
- iowrite32(gpe|0xc000, rGPEUP);
-
- ret = request_irq(IRQ_IIC, iic_interrupt, IRQF_DISABLED, DEVICE_NAME,NULL);
- if (ret)
- {
- //DPRINTK("Register IRQ_TIMER0 failed!\n");
- printk("Register IRQ_IIC failed!\n");
- return ret;
- }
- // enable_irq(IRQ_IIC);
-
- iowrite32(0xaf, rIICCON);
- iowrite32(0x10, rIICADD);
- iowrite32(0x10, rIICSTAT);
- iowrite32((1<<2)|(1<<0), rIICLC);
-
- rd_addr=0;
- wr_addr=0;
-
- printk("open succeed\n");
- return 0;
-
- }
- // else
- // return -EBUSY;
- }
- int iic_release(struct inode *inode, struct file *filp)
- {
- // disable_irq(IRQ_IIC);
- free_irq(IRQ_IIC,NULL);
- iowrite32(gpecon_save,rGPECON);
- iowrite32(gpeup_save,rGPEUP);
- // up(&lock);
- return 0;
- }
- static ssize_t iic_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
- {
- _iicMode = SETRDADDR;
- _iicPt = 0;
- _iicData[0] = (unsigned char)rd_addr;
- _iicDataCount = 1;
-
- iowrite32(slvAddr, rIICDS);
- iowrite32(0xf0, rIICSTAT);
-
- while(_iicDataCount != -1);
-
- _iicMode = RDDATA;
- _iicPt = 0;
- _iicDataCount =1;
-
- iowrite32(slvAddr, rIICDS);
- iowrite32(0xb0, rIICSTAT);
- iowrite32(0xaf, rIICCON);
-
- while(_iicDataCount != -1)
-
- *buf = _iicData[1];
- rd_addr++;
- return 1;
-
- }
- static ssize_t iic_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
- {
- _iicMode = WRDATA;
- _iicPt = 0;
- _iicData[0] = (unsigned char)wr_addr;
- _iicData[1] = *buf;
-
- iowrite32(0xaf, rIICCON);
- iowrite32(slvAddr, rIICDS);
- iowrite32(0xf0, rIICSTAT);
-
- while(_iicDataCount != -1);
-
- _iicMode = POLLACK;
-
- while(1)
- {
- iowrite32(slvAddr,rIICDS);
- _iicStatus = 0x100;
- iowrite32(0xf0, rIICSTAT);
- iowrite32(0xaf, rIICCON);
-
- while(_iicStatus == 0x100);
-
- if(!(_iicStatus&0x1))
- break;
- }
- iowrite32(0xd0,rIICSTAT);
- iowrite32(0xaf,rIICCON);
- Delay(1);
- wr_addr++;
- return 1;
- }
- static int iic_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- {
- return 0;
- }
- static const struct file_operations iic_fops =
- {
- .owner = THIS_MODULE,
- .open = iic_open,
- .read = iic_read,
- .write = iic_write,
- .ioctl = iic_ioctl,
- .release = iic_release,
- };
- static int iic_init(void)
- {
- int result;
- dev_t devno = MKDEV(iic_major,0);
- if(iic_major)
- {
- result = register_chrdev_region(devno,1,"iic");
- }
- else /* 动态分配设备号 */
- {
- result = alloc_chrdev_region(&devno, 0, 1, "iic");
- iic_major = MAJOR(devno);
- }
-
- if (result < 0)
- return result;
- /*初始化cdev结构*/
- cdev_init(&cdev, &iic_fops);
- cdev.owner = THIS_MODULE;
- cdev.ops = &iic_fops;
-
- /* 注_册字符设备 */
- cdev_add(&cdev, MKDEV(iic_major, 0), 1);
-
- gpio_base_addr=ioremap(GPIO_PA,0x20);
- if (gpio_base_addr == NULL) {
- printk(KERN_ERR "Failed to remap register block\n");
- return -ENOMEM;
- }
- iic_base_addr=ioremap(IIC_PA,0x20);
- if (iic_base_addr == NULL) {
- printk(KERN_ERR "Failed to remap register block\n");
- iounmap(gpio_base_addr);
- return -ENOMEM;
- }
- timer_base_addr=ioremap(TIMER_PA,0x50);
- if (timer_base_addr == NULL) {
- printk(KERN_ERR "Failed to remap register block\n");
- iounmap(gpio_base_addr);
- iounmap(iic_base_addr);
- return -ENOMEM;
- }
-
- printk("iic_init ok!\n");
- return 0;
- }
- static void iic_exit(void)
- {
- iounmap(gpio_base_addr);
- iounmap(iic_base_addr);
- iounmap(timer_base_addr);
- cdev_del(&cdev); /*注销设备*/
- unregister_chrdev_region(MKDEV(iic_major, 0), 1); /*释放设备号*/
- printk("iic_exit ok!\n");
- }
- module_init(iic_init);
- module_exit(iic_exit);
复制代码
上面的write函数每次往EEPROM中写一个字节的数据,而且每次写完wd_addr都会加1。
测试程序也附上:
- #include <unistd.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <string.h>
- int main(void)
- {
- int fd,i,j;
- unsigned char data[256];
- if((fd=open("/dev/iic",O_RDWR))<0)
- {
- printf("open /dev/iic failed!\n");
- return -1;
- }
-
- for(i=0;i<256;i++)
- {
- write(fd,&i,1);
- }
-
- memset(data,0,sizeof(data));
- for(i=0;i<256;i++)
- {
- read(fd,&data[i],1);
- }
-
- for(i=0;i<16;i++)
- {
- for(j=0;j<16;j++)
- printf("%2x ",data[i*16+j]);
- printf("\n");
- }
-
- close(fd);
- return 0;
-
- }
复制代码
上面的驱动程序,写的时候,中断一直没有产生,不知道是什么原因。不知道是不是这种方法不可行。
希望大家不吝赐教,先谢过。 |
|