📄 i2c-algo-gm.c
字号:
/* ------------------------------------------------------------------------- i2c-algo-GM.c i2c driver algorithms for GM adapters learned from the original source - i2c-algo-ite.c Copyright 2006 GM Inc. --------------------------------------------------------------------------- This file was highly leveraged from i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund: Copyright (C) 1995-1997 Simon G. Vogl 1998-2000 Hans Berglund This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* ------------------------------------------------------------------------- *//* With some changes from Ky?sti M?lkki <kmalkki@cc.hut.fi> and Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey <mbailey@littlefeet-inc.com> */#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/i2c.h>#include "i2c-algo-GM.h"/* ----- global defines ----------------------------------------------- */#define DEB2(x) if (i2c_debug>=2) x#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/#define DEF_TIMEOUT 16/* module parameters: */static int i2c_debug=1;static int iic_test=1;#define I2C_Status 0x4/* I2C Status Register */#define I2C_CLRAL 0x400#define I2C_CLRGC 0x200#define I2C_CLRSAM 0x100#define I2C_CLRSTOP 0x80#define I2C_CLRBERR 0x40#define I2C_DR 0x20#define I2C_DT 0x10#define I2C_BB 0x8#define I2C_BUSY 0x4#define I2C_NACK 0x2#define I2C_RW 0x1/* exclusive access to the bus *///#define I2C_LOCK(adap) down(&adap->lock)//#define I2C_UNLOCK(adap) up(&adap->lock)//#define ADAP_LOCK() down(&adap_lock)//#define ADAP_UNLOCK() up(&adap_lock)//#define DRV_LOCK() down(&driver_lock)//#define DRV_UNLOCK() up(&driver_lock)#define I2C_LOCK(adap) #define I2C_UNLOCK(adap) #define ADAP_LOCK() #define ADAP_UNLOCK() #define DRV_LOCK() #define DRV_UNLOCK() //#define DEB(x) if (i2c_debug>=1) x;//#define DEB2(x) if (i2c_debug>=2) x;//#define DEBUG 1/* --- setting states on the bus with the right timing: --------------- */#define get_clock(adap) adap->getclock(adap->data)#define iic_outw(adap, reg, val) adap->setiic(adap->data, reg, val)#define iic_inw(adap, reg) adap->getiic(adap->data, reg)//Add By Ken.Hsieh//static wid =EEPROM_ID_WRITE ; //replace with adapter->id//static rid =EEPROM_ID_READ ; //replave with adapter->id+1#define I2C_ALGO_GM_VERSION "0.2"/* --- other auxiliary functions -------------------------------------- */void I2C_WriteData(unsigned char dat){ *(volatile unsigned int *)(I2C_ADDR+0xc)=dat;// printk("i2c wd : %02x\n", dat);}unsigned char I2C_ReadData(void){ unsigned char ret; ret = *(volatile unsigned int *)(I2C_ADDR+0xc);// printk("i2c rd : %02x\n", ret); return ret;// return *(volatile unsigned int *)(I2C_ADDR+0xc);}void I2C_IOCtrl(unsigned int dat){ *(volatile unsigned int *)(I2C_ADDR)=dat;// printk("i2c wc : %02x\n", dat);}unsigned int I2C_ReadStatus(void){ unsigned int ret; ret = *(volatile unsigned int *)(I2C_ADDR+0x4); //printk("i2c rc : %08x\n", ret); return ret;// return *(volatile unsigned int *)(I2C_ADDR+0x4);}int i2c_WaitEndOfStatus_ken(unsigned long status_type, unsigned int time_out){ unsigned long status; for (; time_out>0; --time_out) { //status = inw(CPE_I2C_VA_BASE + I2C_Status); status=I2C_ReadStatus(); if (( status & status_type ) == 0) { break; } set_current_state(TASK_INTERRUPTIBLE); schedule_timeout (1); } return (time_out>0);}/*int WaitDT() { if (i2c_WaitEndOfStatus_ken(I2C_BB, 1000) == 0){ printk ("I2C bus busy, pls reset I2C device!\n"); return 0; }; return 1;}*/int WaitDR(void){ volatile unsigned int status=0,count=0;; while(1) { if(status&0x20) { //printk("<0>DR is set!\n"); return 1; } //mdelay(10); status=I2C_ReadStatus(); count++; if(count>0x10000) { mdelay(4); //note by Ken.Hsieh: eeprom must use this so that eeprom will write successfully; if mdelay(3) will fail on writing due to the less the value //mdelay(10); //note by Ken.Hsieh: eeprom must use this so that eeprom will write successfully; if mdelay(3) will fail on writing due to the less the value } if(count>0x10002) //if(count>0x200000) return 0; } return 1;} int WaitDT(void){ volatile unsigned int status=0,count=0;; while(1) { //Add By Ken.Hsieh to check ACK in I2C Status Register /*if (status&0x02) { printk("ACK is set..and set I2C_STOP\n"); I2C_IOCtrl(I2C_STOP); return 0; } */ if(status&0x10) { //printk("<0>DT is set!\n"); if (status&0x02) { //Non-ACK happens //printk("ACK is set and set I2C_STOP\n"); I2C_IOCtrl(I2C_STOP); return 0; } return 1; } if(status&0x20) { //rintk("<0>DR is set!\n"); return 1; } //mdelay(10); status=I2C_ReadStatus(); count++; if(count>0x10000) { mdelay(4); //note by Ken.Hsieh: eeprom must use this so that eeprom will write successfully; if mdelay(3) will fail on writing due to the less the value //mdelay(10); //note by Ken.Hsieh: eeprom must use this so that eeprom will write successfully; if mdelay(3) will fail on writing due to the less the value } if(count>0x10002) //if(count>0x200000) return 0; } return 1;} static void iic_start(struct i2c_algo_iic_data *adap){ //iic_outw(adap,ITE_I2CHCR,ITE_CMD);}static void iic_stop(struct i2c_algo_iic_data *adap){// iic_outw(adap,ITE_I2CHCR,0);// iic_outw(adap,ITE_I2CHSR,ITE_I2CHSR_TDI);}static void iic_reset(struct i2c_algo_iic_data *adap){// iic_outw(adap, PM_IBSR, iic_inw(adap, PM_IBSR) | 0x80);}static int wait_for_bb(struct i2c_algo_iic_data *adap){ //return(timeout<=0);}/* * Puts this process to sleep for a period equal to timeout */static inline void iic_sleep(unsigned long timeout){ schedule_timeout( timeout * HZ);}/* After we issue a transaction on the IIC bus, this function * is called. It puts this process to sleep until we get an interrupt from * from the controller telling us that the transaction we requested in complete. */static int wait_for_pin(struct i2c_algo_iic_data *adap, short *status) {}/* * Sanity check for the adapter hardware - check the reaction of * the bus lines only if it seems to be idle. */static int test_bus(struct i2c_algo_iic_data *adap, char *name) { return (0);}/* ----- Utility functions *//* Verify the device we want to talk to on the IIC bus really exists. */#if 0static inline int try_address(struct i2c_algo_iic_data *adap, unsigned int addr, int retries){ //return ret;}#endif//static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,int i2c_sendbytes(struct i2c_adapter *i2c_adap,unsigned char *buf, int count){ int i; char *p_temp ; struct GMi2c_info *fara_info; fara_info=i2c_adap; //struct i2c_algo_iic_data *adap = i2c_adap->algo_data; //write slave address to device if (count<1) { printk("i2c-algo-GM.o:i2c_sendbytes count:%d can't less than 1!\n",count); return 0; } p_temp = buf; I2C_WriteData(fara_info->flags); // specify the I2C device address I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_START); //0x3f96 if(WaitDT()==0) return 0; if (count == 1 ) { I2C_WriteData(fara_info->data); // specify I2C offset I2C_IOCtrl(I2C_ENABLE|I2C_TBEN);//0x3f86 if(WaitDT()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_sendbytes offset(0x%x) error 11111!\n",fara_info->flags,fara_info->data); return 0; } } //write data to device for (i=0 ; i<count-1 ; i++) { I2C_WriteData(*p_temp); I2C_IOCtrl(I2C_ENABLE|I2C_TBEN);//0x3f86 if(WaitDT()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_sendbytes data error 22222!\n",fara_info->flags); return 0; } p_temp++; fara_info->data ++ ; } I2C_WriteData(*p_temp); I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_STOP); //0x3fa6 if(WaitDT()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_sendbytes data error 33333!\n",fara_info->flags); return 0; } //for OV7640 reset,it must delay more than 1 ms /* if ((fara_info->flags == 0x42) && (fara_info->data==0x12) && (*buf ==0x80)) { //printk("<0>i2c-algo-GM.o:mdelay(2) for OV7640..\n"); printk("<0>i2c-algo-GM.o:udelay(1000) for OV7640 reset all register\n"); //mdelay(2); udelay(1000); } */ return 1;}EXPORT_SYMBOL_GPL(i2c_sendbytes);/* GM I2C bus interface for device drvier by Ken.Hsieh,instead of ii2_readbytes on 2006.6.1*///static int i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count,int i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int sread) { struct GMi2c_info *fara_info; int i; char *p_buf ; fara_info=i2c_adap; p_buf = buf; sread = 0 ; //write address to device if ( (count == 1) || (count>1 && fara_info->adap.retries ==0) ) { //write slave address to device //I2C_WriteData(wid); //printk("88888888888888888888888888888888888\n"); for (i=0 ; i<count ; i++) { //I2C_WriteData(fara_info->flags-1); I2C_WriteData(fara_info->flags|1); I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_START); if (WaitDT() ==0) {#ifdef DEBUG printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error 00000!\n",fara_info->flags);#endif I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_START); if (WaitDT() ==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error 111111!\n",fara_info->flags); sread = -1 ; return -1; } } //write address to device I2C_WriteData(fara_info->data); // ? if (fara_info->flags == 0x43) { I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_STOP); //Try for OV7660 } else { I2C_IOCtrl(I2C_ENABLE|I2C_TBEN); } if (WaitDT() ==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error 22222!\n",fara_info->flags); sread = -1 ; return -1; } //read data //I2C_WriteData(rid); I2C_WriteData(fara_info->flags); I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_START); //0x3f96 if(WaitDT()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error 333333!\n",fara_info->flags); sread = -1 ; return -1; } I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_STOP|I2C_ACKNAK); if(WaitDT()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error 4444444!\n",fara_info->flags); sread = -1 ; return -1; } *p_buf = *((char *)(I2C_ADDR+0xc));#ifdef DEBUG printk("Read address 0x%02x with 0x%02x\n",fara_info->data,*p_buf);#endif if (count ==1 || i==count-1) break; p_buf++; fara_info->data++; } } else { if (fara_info->adap.retries ==1 ) { //write slave address to device //I2C_WriteData(wid); I2C_WriteData(fara_info->flags | 0x1); I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_START); //printk("777777777777777777777777777777777777\n"); //while(1); if (WaitDT() ==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error 111111!\n",fara_info->flags); sread = -1 ; return -1; } //printk("222\n"); I2C_IOCtrl(I2C_ENABLE|I2C_TBEN); if(WaitDR()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error multi-read once 1111!\n",fara_info->flags); sread = -1 ; return -1; } *p_buf = *((char *)(I2C_ADDR+0xc)); //printk("byte 1 = %x\n",*p_buf); p_buf++; I2C_IOCtrl(I2C_ENABLE|I2C_TBEN); if(WaitDR()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error multi-read once 1111!\n",fara_info->flags); sread = -1 ; return -1; } for (i=2 ; i<count-1 ; i++) { *p_buf = *((char *)(I2C_ADDR+0xc)); //printk("byte %d = %x\n",i,*p_buf); p_buf++; I2C_IOCtrl(I2C_ENABLE|I2C_TBEN); if(WaitDR()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error multi-read once 222!\n",fara_info->flags); sread = -1 ; return -1; } } *p_buf = *((char *)(I2C_ADDR+0xc)); //printk("byte 4 = %x\n",*p_buf); p_buf++; I2C_IOCtrl(I2C_ENABLE|I2C_TBEN|I2C_STOP|I2C_ACKNAK); if(WaitDR()==0) { printk("i2c-algo-GM.o:device 0x%x i2c_readbytes data error multi-read once 1111!\n",fara_info->flags); sread = -1 ; return -1; } *p_buf = *((char *)(I2C_ADDR+0xc)); //printk("byte 5 = %x\n",*p_buf); } } //printk("Read address 0x%02x with 0x%02x\n",fara_info->data,*buf); //count =1 ; return count;}EXPORT_SYMBOL_GPL(i2c_readbytes);/* Description: Prepares the controller for a transaction (clearing status * registers, data buffers, etc), and then calls either iic_readbytes or * iic_sendbytes to do the actual transaction. * * still to be done: Before we issue a transaction, we should * verify that the bus is not busy or in some unknown state. *///static int iic_xfer(struct i2c_adapter *i2c_adap,#ifdef CONFIG_PLATFORM_GM8120int iic_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num){ struct i2c_algo_iic_data *adap = i2c_adap->algo_data; struct i2c_msg *pmsg; int ret, timeout; char *p; int i=0; struct GMi2c_info *fara_info; fara_info=i2c_adap; #ifdef DEBUG printk("iic_xfer start\n"); #endif pmsg = &msgs[i]; pmsg->len = num; p=pmsg->buf; if (fara_info->client_count >=0 ) { ret = GM_fLib_I2C_SetClockdiv(fara_info->client_count); if (ret !=0 ) { printk("i2c-algo-GM.o:Error in GM_fLib_I2C_SetClockdiv\n"); return ret; } } if(fara_info->flags & I2C_M_RD) { /* Read */#ifdef DEBUG printk("addr = 0x%x,waddr = 0x%x,client_count = 0x%x,buf = 0x%x\n",fara_info->flags,fara_info->data,fara_info->client_count,pmsg->buf);#endif ret = i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len, 0); } else { /* Write */ ret = i2c_sendbytes(i2c_adap, pmsg->buf, pmsg->len); } if (ret != pmsg->len) DEB3(printk("iic_xfer: error or fail on read/write %d bytes.\n",ret)); else DEB3(printk("iic_xfer: read/write %d bytes.\n",ret)); return ret;}EXPORT_SYMBOL_GPL(iic_xfer);#elseint iic_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num){ int ret; struct GMi2c_info *fara_info; fara_info=i2c_adap; #ifdef DEBUG printk("iic_xfer start\n"); #endif msgs->addr=fara_info->flags; msgs->flags=fara_info->data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -