📄 i2c-algo-bit.c
字号:
}/* ----- Utility functions *//* try_address tries to contact a chip for a number of * times before it gives up. * return values: * 1 chip answered * 0 chip did not answer * -x transmission error */static inline int try_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries){ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; int i,ret = -1; for (i=0;i<=retries;i++) { ret = i2c_outb(i2c_adap,addr); if (ret==1) break; /* success! */ i2c_stop(adap); udelay(5/*adap->udelay*/); if (i==retries) /* no success */ break; i2c_start(adap); udelay(adap->udelay); } DEB2(if (i) printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n", i+1, addr & 1 ? "read" : "write", addr>>1, ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" ) ); return ret;}static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg){ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; char c; const char *temp = msg->buf; int count = msg->len; unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; int retval; int wrcount=0; while (count > 0) { c = *temp; DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: %s sendbytes: writing %2.2X\n", i2c_adap->name, c&0xff)); retval = i2c_outb(i2c_adap,c); if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ count--; temp++; wrcount++; } else { /* arbitration or no acknowledge */ printk(KERN_ERR "i2c-algo-bit.o: %s sendbytes: error - bailout.\n", i2c_adap->name); i2c_stop(adap); return (retval<0)? retval : -EFAULT; /* got a better one ?? */ }#if 0 /* from asm/delay.h */ __delay(adap->mdelay * (loops_per_sec / 1000) );#endif } return wrcount;}static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg){ int inval; int rdcount=0; /* counts bytes read */ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; char *temp = msg->buf; int count = msg->len; int recv_len = 0; /* Receive [Count] for I2C_SMBUS_BLOCK_DATA or I2C_SMBUS_BLOCK_PROC_CALL protocol */ if (msg->flags & I2C_M_RECV_LEN) recv_len = 1; while (count > 0) { inval = i2c_inb(i2c_adap);/*printk("%#02x ",inval); if ( ! (count % 16) ) printk("\n"); */ if (inval>=0) { *temp = inval; rdcount++; } else { /* read timed out */ printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n"); break; } if (recv_len) { recv_len = 0; /* [Count] should be between 1 and 31 (I2C_SMBUS_BLOCK_MAX - 1). */ if (inval > 0 && inval < I2C_SMBUS_BLOCK_MAX) { count = inval + 1; /* plus one for [Count] itself */ msg->len = count; if (msg->flags & I2C_M_RECV_PEC) count++; /* plus one for PEC */ } else { printk(KERN_ERR "i2c-algo-bit.o: readbytes: bad block count (%d).\n", inval); break; } } if ( count > 1 ) { /* send ack */ sdalo(adap); DEBPROTO(printk(" Am ")); } else { sdahi(adap); /* neg. ack on last byte */ DEBPROTO(printk(" NAm ")); } if (sclhi(adap)<0) { /* timeout */ sdahi(adap); printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n"); return -ETIMEDOUT; }; scllo(adap); sdahi(adap); temp++; count--; } return rdcount;}/* doAddress initiates the transfer by generating the start condition (in * try_address) and transmits the address in the necessary format to handle * reads, writes as well as 10bit-addresses. * returns: * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set * -x an error occurred (like: -EREMOTEIO if the device did not answer, or * -ETIMEDOUT, for example if the lines are stuck...) */static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { unsigned short flags = msg->flags; unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; struct i2c_algo_bit_data *adap = i2c_adap->algo_data; unsigned char addr; int ret, retries; retries = nak_ok ? 0 : i2c_adap->retries; if ( (flags & I2C_M_TEN) ) { /* a ten bit address */ addr = 0xf0 | (( msg->addr >> 7) & 0x03); DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); if ((ret != 1) && !nak_ok) { printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } /* the remaining 8 bit address */ ret = i2c_outb(i2c_adap,msg->addr & 0x7f); if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ printk(KERN_ERR "died at 2nd address code.\n"); return -EREMOTEIO; } if ( flags & I2C_M_RD ) { i2c_repstart(adap); /* okay, now switch into reading mode */ addr |= 0x01; ret = try_address(i2c_adap, addr, retries); if ((ret!=1) && !nak_ok) { printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } } } else { /* normal 7bit address */ addr = ( msg->addr << 1 ); if (flags & I2C_M_RD ) addr |= 1; if (flags & I2C_M_REV_DIR_ADDR ) addr ^= 1; ret = try_address(i2c_adap, addr, retries); if ((ret!=1) && !nak_ok) return -EREMOTEIO; } return 0;}static int bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num){ struct i2c_msg *pmsg; struct i2c_algo_bit_data *adap = i2c_adap->algo_data; int i,ret; unsigned short nak_ok; i2c_start(adap); for (i=0;i<num;i++) { pmsg = &msgs[i]; nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; if (!(pmsg->flags & I2C_M_NOSTART)) { if (i) { i2c_repstart(adap); } ret = bit_doAddress(i2c_adap, pmsg); if ((ret != 0) && !nak_ok) { DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n", msgs[i].addr,i)); return (ret<0) ? ret : -EREMOTEIO; } } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ ret = readbytes(i2c_adap, pmsg); DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret)); if (ret < pmsg->len ) { return (ret<0)? ret : -EREMOTEIO; } } else { /* write bytes from buffer */ ret = sendbytes(i2c_adap, pmsg); DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret)); if (ret < pmsg->len ) { return (ret<0) ? ret : -EREMOTEIO; } } } i2c_stop(adap); return num;}static u32 bit_func(struct i2c_adapter *i2c_adap){ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_SMBUS_READ_BLOCK_DATA;}/* -----exported algorithm data: ------------------------------------- */static struct i2c_algorithm i2c_bit_algo = { .name = "Bit-shift algorithm", .id = I2C_ALGO_BIT, .master_xfer = bit_xfer, .functionality = bit_func,};/* * registering functions to load algorithms at runtime */int i2c_bit_add_bus(struct i2c_adapter *adap){ struct i2c_algo_bit_data *bit_adap = adap->algo_data; if (bit_test) { int ret = test_bus(bit_adap, adap->name); if (ret<0) return -ENODEV; } DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: hw routines for %s registered.\n", adap->name)); /* register new adapter to i2c module... */ adap->id |= i2c_bit_algo.id; adap->algo = &i2c_bit_algo; adap->timeout = 100; /* default values, should */ adap->retries = 3; /* be replaced by defines */ i2c_add_adapter(adap); return 0;}int i2c_bit_del_bus(struct i2c_adapter *adap){ return i2c_del_adapter(adap);}EXPORT_SYMBOL(i2c_bit_add_bus);EXPORT_SYMBOL(i2c_bit_del_bus);MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");MODULE_LICENSE("GPL");MODULE_PARM(bit_test, "i");MODULE_PARM(i2c_debug,"i");MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -