?? s3c2410-iic.c
字號:
/*this is a simple driver for s3c2410'iic writer is cahill date 2006.10.20*/#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/version.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/ioport.h>//#include <asm-asm/irq.h>#include <linux/errno.h>#include <asm/arch/irq.h>#include <linux/sched.h>#include <linux/i2c.h>#include <asm-arm/irq.h>#include <asm-arm/arch-s3c2410/cpu_s3c2410.h> //added by cahill#include <linux/i2c-algo-s3c2410.h>#include <linux/i2c-algo-s3c2410.h>#include <asm-arm/arch-s3c2410/irqs.h>#include <asm-arm/io.h> //added by cahill#include "i2c-s3c2410.h"/*------------globle value-------------------*/static wait_queue_head_t iic_wait;static unsigned int *r_GPECON;static unsigned int *r_GPEDAT;static unsigned int *r_GPEUP;static unsigned int *r_IICCON;static unsigned int *r_IICSTAT;static unsigned int *r_IICADD;static unsigned int *r_IICDS;static int iic_irq;static int iic_pending = 0;static int DevMojor;static int read_flag=0;//static unsigned int iic_flag = 1; //the flag of iic's operation, 0 = ok 1 = no; //static unsigned u8 *iic_data;static u8 real_val = 59;static int real_count = 0;static u8 real_buf[20];/*----------------globle value define over--------------------*///#define VA_IIC_BASE __ioremap(0x54000000, 4, 0)#define S3C2410_GPECON *r_GPECON#define S3C2410_GPEDAT *r_GPEDAT #define S3C2410_GPEUP *r_GPEUP#define S3C2410_IICCON *r_IICCON // (VA_IIC_BASE + 0x0)#define S3C2410_IICSTAT *r_IICSTAT // (VA_IIC_BASE + 0x4)#define S3C2410_IICADD *r_IICADD // (VA_IIC_BASE + 0x8)#define S3C2410_IICDS *r_IICDS // (VA_IIC_BASE + 0xC)#define I2C_M_WR 0#define I2C_M_RD 1 /* ----- local functions ---------------------------------------------- */static int address_map(void){ r_GPECON = __ioremap(0x56000040,4,0); r_GPEDAT = __ioremap(0x56000044,4,0); r_GPEUP = __ioremap(0x56000048,4,0); r_IICCON = __ioremap(0x54000000,4,0); r_IICSTAT= __ioremap(0x54000004,4,0); r_IICADD = __ioremap(0x54000008,4,0); r_IICDS = __ioremap(0x5400000C,4,0); return 0;}static void s3c2410_init(void){ S3C2410_GPECON |= 0xa0000000; //set the iic pin to iic function S3C2410_GPEUP |= 0xc000; //disable pull up S3C2410_IICCON = (1<<7)|(1<<6)| (1<<5)|(0x0f); //enable iic|iicclk=fpclk/512|enable interrupt|iicclk/0x0f+1 }static int inter_count = 50; static int real_status ;static int ok_or;/* disable iic interrupt*/ static void cliic(void){ S3C2410_IICCON &= 0xdf;}/*enable iic interrupt*/static void stiic(void){ S3C2410_IICCON |=0x20;}/* s3c2410 iic bus demands that it is not busy when a send/receive cycle is begainning this function detect the iic bus is busy or not if the bus is busy return -1, else 0;*/static int busy_or(void) { if(S3C2410_IICSTAT & 0x20){ return -1; }else{ return 0; }}/* send one byte one time*/ static int send_one(u8 buf){ int i = 0; int ret; while(busy_or() == -1){ i++; udelay(5); //printk("the bus is busy ,wait it\n"); if(i>15){ //printk("the bus is busy , but for a long time ! maybe, erros are occured!\n "); break; } } i = 0; udelay(5); S3C2410_IICDS = buf; ret = S3C2410_IICCON; S3C2410_IICCON = ret & ~S3C2410_IICCON_INT_PEND; while(iic_pending == 0){ i++; udelay(5); if(i>15) break; } iic_pending = 0; if (ok_or == 0){ printk("send ok!\n"); printk("send %d to device\n",buf); }else{ printk("in send :> send erro!\n"); return -1; } return 0; }/* read one byte one time*/static void read_one(){ int i = 0; int ret; u8 buf; while(busy_or() == -1){ i++; udelay(5); //printk("the bus is busy ,wait it\n"); if(i>15){ //printk("the bus is busy , but for a long time ! maybe, erros are occured!\n "); break; } } i = 0; udelay(5); ret = S3C2410_IICCON; S3C2410_IICCON = ret & ~S3C2410_IICCON_INT_PEND; while(iic_pending == 0){ i++; udelay(5); //printk("wait for interrupt!\n"); if(i>60) break; } iic_pending = 0; buf = S3C2410_IICDS ; printk(":> read %d from device\n", buf); if (buf == real_val) { real_count++; } real_val++; udelay(5);}/* send a command head for memory device if you control other device , this function should be changed for demands */static int write_head(void){ int ret,i=0; printk( "s3c2410_sendbytes: Set transmit mode\n"); ret = S3C2410_IICCON; S3C2410_IICCON = ret & ~S3C2410_IICCON_INT_PEND; while(busy_or() == -1){ i++; udelay(5); //printk("the bus is busy ,wait it\n"); if(i>15) break; } i = 0; ret = S3C2410_IICSTAT_MTX_ENABLE; S3C2410_IICSTAT = ret; udelay(100); S3C2410_IICDS=0xa0; //udelay(5); while(iic_pending == 0){ i++; udelay(5); //printk("wait for interrupt!\n"); if(i>15) return -1; } iic_pending = 0; if (ok_or == 0){ printk("send ok!\n"); printk("the commond is %d \n",S3C2410_IICDS); //ret = S3C2410_IICCON; //S3C2410_IICCON = ret & ~S3C2410_IICCON_INT_PEND; }else{ printk("in write head :> send erro!\n"); return -1; //s3c2410_init(); //goto reset; } return 0 ;}/* send a command head for memory device if you control other device , this function should be changed for demands */static int read_head(void){ int ret,i=0; printk( "s3c2410_sendbytes: Set transmit mode\n"); //stiic(); ret = S3C2410_IICCON; S3C2410_IICCON = ret & ~S3C2410_IICCON_INT_PEND; while(busy_or() == -1){ i++; udelay(5); //printk("the bus is busy ,wait it\n"); if(i>15) break; } S3C2410_IICDS=0xa1; ret = S3C2410_IICSTAT_MRX_ENABLE; //ret = S3C2410_IICSTAT_MTX_ENABLE; S3C2410_IICSTAT = ret; //udelay(100); //S3C2410_IICSTAT &= 0xbf; //set receive mode S3C2410_IICDS=0xa1; //udelay(5); while(iic_pending == 0){ i++; udelay(5); //printk("wait for interrupt!\n"); if(i>15) return -1; } iic_pending = 0; if (ok_or == 0){ printk("send ok!\n"); //ret = S3C2410_IICCON; //S3C2410_IICCON = ret & ~S3C2410_IICCON_INT_PEND; }else{ printk("in read head :>send erro!\n"); return -1; //s3c2410_init(); //goto reset; } //S3C2410_IICSTAT &= 0xbf; //set receive mode printk( "s3c2410_sendbytes: Set receive mode\n"); return 0 ;}/* this function create a stop pulse, */static int iic_stop(void){ int ret; // generate a STOP condition //udelay(5000); ret = S3C2410_IICSTAT; S3C2410_IICSTAT = ret & ~S3C2410_IICSTAT_BUSY; //udelay(10000); // clear the pending bit and re-enable ACK generation ret = S3C2410_IICCON; ret = (ret & ~S3C2410_IICCON_INT_PEND) | S3C2410_IICCON_ACK_EN; S3C2410_IICCON = ret; return 0 ;}/* this function is important ,it send several bytes one time*/static int try_interrupt(u8 data){ int ret ,i=0; stiic(); while(1){ if((ret=write_head())==0) break; } //send_addr(0); send_one(0); send_one(0); for(i = 0; i<8; i++){ send_one(data); } iic_stop(); printk(" write over !\n\n\n");}/* read serval bytes one time*/static int try_read( ){ int ret ,i=0; int busystat; //stiic(); while(1) { if((ret=write_head())==0) break; } //send_addr(0); send_one(0); send_one(0); read_head() ; busystat = S3C2410_IICSTAT; i = (busystat & S3C2410_IICSTAT_BUSY)?0:1; if(i == 0){ printk("this data is erro"); read_one(); //dump read; } for(i=0;i<7;i++){ read_one(); } ret = S3C2410_IICCON; ret = ret & ~S3C2410_IICCON_ACK_EN; S3C2410_IICCON = ret; read_one(); iic_stop(); ret = S3C2410_IICCON; ret = ret | S3C2410_IICCON_ACK_EN; S3C2410_IICCON = ret; printk(" read over !\n\n\n"); return 0;} //// Description: The registered interrupt handler//static int iic_s3c2410_handler(int irq, void *dev_id, struct pt_regs *regs) { int ret; // iic_pending = 1; iic_pending = 1; printk("now, it's in iic_s3c2410_handler!\n"); real_status = S3C2410_IICSTAT; if(read_flag == 1){ ret = S3C2410_IICDS; printk("interrup say:> the %d was received!\n",ret ); } // Clear interrupt pending bit /* ret = S3C2410_IICCON; S3C2410_IICCON = ret & ~S3C2410_IICCON_INT_PEND; cliic(); */ //S3C2410_IICCON = (1<<7)|(1<<6)| (0<<5)|(0<<4)|(0x07); //S3C2410_IICCON &= 0xdf; if ( S3C2410_IICSTAT & S3C2410_IICSTAT_NACK) { printk( "Master transfer aborted by a NACK during the transfer of the address byte\n"); ok_or = 1; // sti(); return 1; }else { printk("recieve the ACK !\n ") ; ok_or = 0 ; //sti(); return 0; } if(read_flag == 1){ ret = S3C2410_IICDS; printk("interrup say:> the %d was received!\n",ret ); } }//// Description: This function is very hardware dependent. First, we lock// the region of memory where out registers exist. Next, we request our// interrupt line and register its associated handler.//static int iic_hw_resrc_init(void){ if (request_irq(iic_irq, iic_s3c2410_handler, 0, "s3c2410 IIC", 0) < 0) { printk( "iic_hw_resrc_init: Request irq%d failed\n", iic_irq); iic_irq = 0; } else { printk("iic_hw_resrc_init: Enabled interrupt (irq%d)\n", iic_irq); enable_irq(iic_irq); } return 0;}static int s3c2410_iic_open(struct inode * inode, struct file * filp){ MOD_INC_USE_COUNT; printk("s3c2410 iic is opened !\n"); return 0;}static int s3c2410_iic_release(struct inode *inode, struct file *filp){ MOD_DEC_USE_COUNT; //iic_s3c2410_release(); printk("s3c2410 iic released!\n"); return 0;}static int s3c2410_iic_write(struct file *file, const u8 *buffer, size_t count, loff_t *ppos){ u8 data, databuf[100]; u8 addr[2]={0x00,0x00}; int i; int j; address_map(); real_count = 0 ; s3c2410_init(); copy_from_user(&data, buffer, sizeof(data)); //databuf[0] = 0x00; //databuf[1] = 0x00; for (i=0 ;i<64;i++){ databuf[i]=i+ '0'; printk("%d ", databuf[i]); } printk("\n\n"); //static int s3c2410_sendbytes(u8 buf[], int count );//static int s3c2410_readbytes(u8 buf[], int count, u8 address[] ) udelay(10000); //try_interrupt(databuf); iic_stop(); if(data){ stiic(); //for(i=0;i<150;i++){ udelay(5000); try_interrupt(data); //s3c2410_init(); for(i=0;i<21;i++) udelay(5000); try_read(); //s3c2410_init(); udelay(5000);// } } printk("ritght %d\n",real_count); return sizeof(data);}static struct file_operations s3c2410_iic_fops = { owner: THIS_MODULE, open : s3c2410_iic_open, write: s3c2410_iic_write, release: s3c2410_iic_release,};#ifdef CONFIG_DEVFS_FS static devfs_handle_t devfs_Dbled_dir, devfs_Dbledraw;#endifstatic int __init iic_s3c2410_init(void) { int ret,i; printk( "iic_s3c2410_init: Samsung S3C2410X iic adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); iic_irq = IRQ_IIC; address_map(); //added by cahill init_waitqueue_head(&iic_wait); s3c2410_init(); ret = register_chrdev(0, "s3c2410_iic",&s3c2410_iic_fops ); if(ret < 0){ printk("can't get major number!\n"); } DevMojor = ret; //init_waitqueue_head(iic_wait); i = iic_hw_resrc_init(); if(i!= 0 ){ printk("set interrupt is erro!\n "); }else{ printk("set interrupt successfully!\n"); }#ifdef CONFIG_DEVFS_FS devfs_Dbled_dir = devfs_mk_dir(NULL, "s3c2410_iic", NULL); devfs_Dbledraw = devfs_register(devfs_Dbled_dir,"0" , DEVFS_FL_DEFAULT,ret,1,S_IFCHR | S_IRUSR | S_IWUSR, &s3c2410_iic_fops,NULL);#endif printk( "iic_s3c2410_init: initialized iic-bus successfully! \n "); return 0;}static void __exit iic_s3c2410_exit(void){ //i2c_s3c2410_del_bus(&iic_s3c2410_ops); //iic_s3c2410_release(); devfs_unregister(devfs_Dbledraw); devfs_unregister(devfs_Dbled_dir); unregister_chrdev(DevMojor,"s3c2410_iic"); }module_init(iic_s3c2410_init);module_exit(iic_s3c2410_exit); MODULE_LICENSE("GPL");MODULE_AUTHOR("cahill<dapengbird2g@163.com>");MODULE_DESCRIPTION("S3C2410+LINUX-IIC-DRIVERS");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -