📄 cci2c.c
字号:
/*!****************************************************************************! 05.03.2002 splitted huge cmoscam.c*! removed all sensor specifics (shadow registers, invalidate window)*! FILE NAME : cci2c.c*!*! DESCRIPTION: TBD*! used i2.c v2.2 by Axis* removed all "CLI-s" they could be needed for delay counter ?*//****************** INCLUDE FILES SECTION ***********************************/#include <linux/module.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/string.h>#include <linux/init.h>#include <linux/config.h>#include <asm/system.h>#include <asm/svinto.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/delay.h>#include <asm/uaccess.h>#include <asm/cmoscama.h>#include "cc303.h"#include "cci2c.h"#define D(x)/****************** I2C DEFINITION SECTION *************************/#define CLOCK_LOW_TIME 8#define CLOCK_HIGH_TIME 8#define START_CONDITION_HOLD_TIME 8#define STOP_CONDITION_HOLD_TIME 8#define ENABLE_OUTPUT 0x01#define ENABLE_INPUT 0x00#define I2C_CLOCK_HIGH 1#define I2C_CLOCK_LOW 0#define I2C_DATA_HIGH 1#define I2C_DATA_LOW 0/* use the kernels delay routine */#define i2c_delay(usecs) udelay(usecs)void i2c_disable(int n);void i2c_dir_out(int n);void i2c_dir_in (int n);void i2c_scl_0 (int n);void i2c_scl_1 (int n);void i2c_sda (int n, int d); /* d is checked against zero only, it does not need to be "1" */ int i2c_getbit (int n);int i2c_getscl(int n); /* just for i2c testing */int i2c_diagnose(int n);int i2c_start(int n);void i2c_stop(int n);int i2c_outbyte(int n, unsigned char d);unsigned char i2c_inbyte(int n);void i2c_sendack(int n);/* I2C functions */void i2c_disable(int n) { //first disable, then set high if (n) { ccamCRAnd(~CCAM_BITS(SCL1_EN,1) & ~CCAM_BITS(SDA1_EN,1)); ccamCROr (CCAM_BITS(SCL1,1) | CCAM_BITS(SDA1,1)); } else { ccamCRAnd(~CCAM_BITS(SCL0_EN,1) & ~CCAM_BITS(SDA0_EN,1)); ccamCROr (CCAM_BITS(SCL0,1) | CCAM_BITS(SDA0,1)); }}void i2c_dir_out(int n) { //first set high, then enable D(printk("i2c_dir_out bus= %x, was port= %x\n\r",n,ccam_cr_shadow)); if (n) { ccamCROr (CCAM_BITS(SCL1,1) | CCAM_BITS(SDA1,1)); ccamCROr (CCAM_BITS(SCL1_EN,1) | CCAM_BITS(SDA1_EN,1)); } else { ccamCROr (CCAM_BITS(SCL0,1) | CCAM_BITS(SDA0,1)); ccamCROr (CCAM_BITS(SCL0_EN,1) | CCAM_BITS(SDA0_EN,1)); } D(printk("i2c_dir_out new port= %x\n\r",ccam_cr_shadow));}void i2c_dir_in(int n) { // should be called after i2c_dir_out if (n) { ccamCROr (CCAM_BITS(SDA1,1)); ccamCRAnd (~CCAM_BITS(SDA1_EN,1)); } else { ccamCROr (CCAM_BITS(SDA0,1)); ccamCRAnd (~CCAM_BITS(SDA0_EN,1)); }}void i2c_scl_0(int n) { if (n) ccamCRAnd (~CCAM_BITS(SCL1,1)); else ccamCRAnd (~CCAM_BITS(SCL0,1)); }void i2c_scl_1(int n) { if (n) ccamCROr (CCAM_BITS(SCL1,1)); else ccamCROr (CCAM_BITS(SCL0,1)); }void i2c_sda (int n, int d) { // will also force sda enable if (n) { if (d) ccamCROr ( CCAM_BITS(SDA1,1)); else ccamCRAnd (~CCAM_BITS(SDA1,1)); ccamCROr (CCAM_BITS(SDA1_EN,1)); } else { if (d) ccamCROr ( CCAM_BITS(SDA0,1)); else ccamCRAnd (~CCAM_BITS(SDA0,1)); ccamCROr (CCAM_BITS(SDA0_EN,1)); }}// #define CCAM_SR(x) ((port_csp0_addr[CCAM__RA__SR] >> CCAM_SR__##x ) & 1)int i2c_getbit(int n) { return n? CCAM_SR(SDA1) : CCAM_SR(SDA0);}int i2c_getscl(int n) { return n? CCAM_SR(SCL1) : CCAM_SR(SCL0);}/* diagnose i2c bus problems. Will always return non-zeroNormally is called from i2c_start, if it detects problem */int i2c_diagnose(int n) { int error=0; D(printk("i2c_diagnose: bus=%x\r\n", n)); while (!error) { i2c_dir_out(n); // will force high SCL, SDA i2c_delay(CLOCK_HIGH_TIME); if (!i2c_getbit(n)) error |= ERR_I2C_SDA_ST0; if (!i2c_getscl(n)) error |= ERR_I2C_SCL_ST0; if (error) break; i2c_scl_0(n); i2c_sda (n,0); i2c_delay(CLOCK_LOW_TIME); if (!i2c_getbit(n)) error |= ERR_I2C_SDA_ST0; if (!i2c_getscl(n)) error |= ERR_I2C_SCL_ST0; if (error) break; i2c_disable(n); // first diseble, then sets high i2c_delay(CLOCK_HIGH_TIME*2); if (!i2c_getbit(n)) error |= ERR_I2C_SDA_NOPULLUP; if (!i2c_getscl(n)) error |= ERR_I2C_SCL_NOPULLUP; if (error) break; i2c_sda(n,0); // scl will be left disabled (high) if (!i2c_getscl(n)) error |= ERR_I2C_SHORT; break; } if (!error) error = ERR_I2C_NOTDETECTED; /* try start-stop to reset effects of playing with sda/scl lines */ i2c_dir_out(n); // will force high SCL, SDA i2c_sda (n,0); i2c_delay(START_CONDITION_HOLD_TIME); i2c_scl_0(n); i2c_delay(CLOCK_LOW_TIME*2); i2c_scl_1(n); i2c_delay(CLOCK_HIGH_TIME*2); i2c_sda (n,1); i2c_delay(STOP_CONDITION_HOLD_TIME); i2c_disable(n); return error;}/* generate i2c start condition and test bus */int i2c_start(int n) {// int error=0; int i; D(printk("i2c_start: bus=%x\r\n", n)); /* SCL=1 SDA=1 */ i2c_dir_out(n); // will set high SCL, SDA i2c_delay(CLOCK_HIGH_TIME/2); /* if the periferial (?) driving sda low (after being interrupted)? - try to recover */ i2c_dir_in(n); i2c_delay(CLOCK_HIGH_TIME/2); if (!i2c_getbit(n)) { for (i=0;(i<9) && !i2c_getbit(n);i++) { i2c_scl_0(n); i2c_delay(CLOCK_LOW_TIME); i2c_scl_1(n); i2c_delay(CLOCK_HIGH_TIME); } if (!i2c_getbit(n)) return i2c_diagnose(n); // did not help - really stuck /* it is breathing - try "START"-"STOP" */ i2c_sda (n,0); i2c_delay(START_CONDITION_HOLD_TIME); i2c_scl_0(n); i2c_delay(CLOCK_LOW_TIME*2); i2c_scl_1(n); i2c_delay(CLOCK_HIGH_TIME*2); i2c_sda (n,1); i2c_delay(STOP_CONDITION_HOLD_TIME); } /* SCL=1 SDA=1 */ i2c_dir_out(n); // will set high SCL, SDA i2c_delay(CLOCK_HIGH_TIME/2); if ((!i2c_getbit(n)) || (!i2c_getscl(n))) return i2c_diagnose(n); /* SCL=1 SDA=0 */ i2c_sda (n,0); i2c_delay(START_CONDITION_HOLD_TIME); if (( i2c_getbit(n)) || (!i2c_getscl(n))) return i2c_diagnose(n); /* SCL=0 SDA=0 */ i2c_scl_0(n); i2c_delay(CLOCK_LOW_TIME); if (( i2c_getbit(n)) || ( i2c_getscl(n))) return i2c_diagnose(n); return 0;}/* generate i2c stop condition */void i2c_stop(int n) { // assumed to be enabled /* SCL=0 SDA=0 */ D(printk("i2c_stop: bus=%x\r\n", n)); i2c_scl_0(n); i2c_sda (n,0); i2c_delay(CLOCK_LOW_TIME*2); /* SCL=1 SDA=0 */ i2c_scl_1(n); i2c_delay(CLOCK_HIGH_TIME*2); /* SCL=1 SDA=1 */ i2c_sda (n,1); i2c_delay(STOP_CONDITION_HOLD_TIME); i2c_disable(n); // both high with resistor pull-up}/* write a byte to the i2c interface , return acknowledge */int i2c_outbyte(int n, unsigned char d) { int i; unsigned char x=d; // make it non-destructive D(printk("i2c_outbyte: bus=%x byte=%x\r\n", n, x)); for (i = 0; i < 8; i++) { // assumed to be with SCL=0; i2c_sda (n,(x & 0x80)); // checks only on non-zero, so no need to '>>' i2c_delay(CLOCK_LOW_TIME/2); i2c_scl_1(n); i2c_delay(CLOCK_HIGH_TIME); i2c_scl_0(n); i2c_delay(CLOCK_LOW_TIME/2); x <<= 1; } /* enable input */ i2c_dir_in(n); i2c_delay(CLOCK_LOW_TIME/2); i2c_scl_1(n); i2c_delay(CLOCK_HIGH_TIME); i= (1-i2c_getbit(n)); i2c_scl_0(n); i2c_delay(CLOCK_LOW_TIME/2); D(printk("i2c_outbyte: ACK=%x\r\n", i)); return i;}/* read a byte from the i2c interface */unsigned char i2c_inbyte(int n) { // assumed SCL=0, SDA=X unsigned char aBitByte = 0; int i; /* enable input */ D(printk("i2c_inbyte: bus=%x\r\n", n)); i2c_dir_in(n); /* get bits */ for (i = 0; i < 8; i++) { i2c_delay(CLOCK_LOW_TIME/2); /* low clock period */ i2c_scl_1(n); i2c_delay(CLOCK_HIGH_TIME); aBitByte = (aBitByte << 1) | i2c_getbit(n); i2c_scl_0(n); i2c_delay(CLOCK_LOW_TIME/2); } D(printk("i2c_inbyte: data=%x\r\n", aBitByte)); return aBitByte; // returns with SCL=0, SDA - OFF}/*#---------------------------------------------------------------------------*#*# FUNCTION NAME: I2C::sendAck*#*# DESCRIPTION : Send ACK on received data*#*#--------------------------------------------------------------------------*/void i2c_sendack(int n) { D(printk("i2c_sendack: bus=%x\r\n", n)); i2c_sda (n,0); i2c_delay(CLOCK_LOW_TIME/2); i2c_scl_1(n); i2c_delay(CLOCK_HIGH_TIME); i2c_scl_0(n); i2c_delay(CLOCK_LOW_TIME/2);}/*#---------------------------------------------------------------------------*#*# FUNCTION NAME: i2c_writeData*#*# DESCRIPTION : Writes a sequence of bytes to an I2C device*# removed retries, will add test-ready later as a separate function*# removed all "dummy stuff" - I never needed that*#*#--------------------------------------------------------------------------*/int i2c_writeData(int n, unsigned char theSlave, unsigned char *theData, int size) { int i,error=0; /* we don't like to be interrupted *** WHY??? *** */ D(printk("i2c_writeData: bus=%x theSlave=%x data=%x %x size=%x\r\n", n, theSlave, theData[0], theData[1], size)); /* generate start condition, test bus */ if ((error=i2c_start(n))) return error; /* send slave address, wait for ack */ if(!i2c_outbyte(n,theSlave)) { i2c_stop(n); return ERR_I2C_BSY; // device does not exist or not ready }// OK, now send theData verifying ACK goes after each byte for (i=0;i<size;i++) { if(!i2c_outbyte(n,theData[i])) { i2c_stop(n); return ERR_I2C_NACK; // device failure } } i2c_stop(n); return 0;}/*#---------------------------------------------------------------------------*#*# FUNCTION NAME: i2c_readData*#*# DESCRIPTION : Reads a data from the i2c device, returns 0- OK, else - error code*#*#--------------------------------------------------------------------------*/int i2c_readData(int n, unsigned char theSlave, unsigned char *theData, int size) { int i, error=0; if ((error=i2c_start(n))) return error; /* send slave address, wait for ack */ D(printk("i2c_readData: bus=%x theSlave=%x size=%x\r\n", n, theSlave, size)); if(!i2c_outbyte(n,theSlave)) { i2c_stop(n); return ERR_I2C_BSY; // device does not exist or not ready } for (i=0;i<size;i++) { theData[i]=i2c_inbyte(n); i2c_sendack(n); } i2c_stop(n); return 0; }/* Main device API. ioctl's to write or read to/from i2c registers. */// for now - single register read/write onlyint i2c_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned char data[2]; int error=0; D(printk("i2c_ioctl cmd= %x, arg= %x\n\r",cmd,arg)); D(printk("i2c_ioctl: ((int *)file->private_data)[0]= %x\n\r",((int *)file->private_data)[0])); if(_IOC_TYPE(cmd) != CMOSCAM_IOCTYPE) { return -EINVAL; }//int i2c_writeData(int n, unsigned char theSlave, unsigned char *theData, int size) { switch (_IOC_NR(cmd)) { case I2C_WRITEREG:/* if ( (( I2C_ARGBUS(arg)) == 0) && // copy zr32112 parameters ((I2C_ARGSLAVE(arg)) == sensor_i2c_addr) //&& // was 0x60 ) { set_imageParamsR (P_DMA_VALID, 0); sensor_i2c_regs[ I2C_ARGREG(arg) ] = ( I2C_ARGVALUE(arg) ); }*/ /* write to an i2c slave */ D(printk("i2cw bus=%d, slave=%d, reg=%d, value=%d\n", I2C_ARGBUS(arg), I2C_ARGSLAVE(arg), I2C_ARGREG(arg), I2C_ARGVALUE(arg))); data[0]=I2C_ARGREG(arg); data[1]=I2C_ARGVALUE(arg); return -i2c_writeData(I2C_ARGBUS(arg), I2C_ARGSLAVE(arg) & 0xfe, &data[0], 2); case I2C_READREG: { /* read from an i2c slave */ D(printk("i2cr bus=%d, slave=%d, reg=%d ", I2C_ARGBUS(arg), I2C_ARGSLAVE(arg), I2C_ARGREG(arg))); data[0]=I2C_ARGREG(arg); error=i2c_writeData(I2C_ARGBUS(arg), I2C_ARGSLAVE(arg) & 0xfe, &data[0], 1); if (error) return -error; error=i2c_readData(I2C_ARGBUS(arg), I2C_ARGSLAVE(arg) | 0x01, &data[1], 1); if (error) return -error; D(printk("returned %d\n", data[1]));/* if ( (( I2C_ARGBUS(arg)) == 0) && // copy zr32112 parameters ((I2C_ARGSLAVE(arg)) == sensor_i2c_addr) // && // was 0x60 ) sensor_i2c_regs[ I2C_ARGREG(arg) ] = data[1];*/ return data[1]; } default: return -EINVAL; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -