📄 i2c-algo-bit.c
字号:
* 0 chip did not answer * -x transmission error */static 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 || i == retries) break; bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); i2c_stop(adap); udelay(adap->udelay); yield(); bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); i2c_start(adap); } if (i && ret) bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " "0x%02x: %s\n", i + 1, addr & 1 ? "read from" : "write to", addr >> 1, ret == 1 ? "success" : "failed, timeout?"); return ret;}static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg){ const unsigned 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) { retval = i2c_outb(i2c_adap, *temp); if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ count--; temp++; wrcount++; } else { /* arbitration or no acknowledge */ dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n"); return (retval<0)? retval : -EFAULT; /* got a better one ?? */ } } return wrcount;}static int acknak(struct i2c_adapter *i2c_adap, int is_ack){ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; /* assert: sda is high */ if (is_ack) /* send ack */ setsda(adap, 0); udelay((adap->udelay + 1) / 2); if (sclhi(adap) < 0) { /* timeout */ dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); return -ETIMEDOUT; } scllo(adap); return 0;}static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg){ int inval; int rdcount=0; /* counts bytes read */ unsigned char *temp = msg->buf; int count = msg->len; const unsigned flags = msg->flags; while (count > 0) { inval = i2c_inb(i2c_adap); if (inval>=0) { *temp = inval; rdcount++; } else { /* read timed out */ break; } temp++; count--; /* Some SMBus transactions require that we receive the transaction length as the first read byte. */ if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) { if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { if (!(flags & I2C_M_NO_RD_ACK)) acknak(i2c_adap, 0); dev_err(&i2c_adap->dev, "readbytes: invalid " "block length (%d)\n", inval); return -EREMOTEIO; } /* The original count value accounts for the extra bytes, that is, either 1 for a regular transaction, or 2 for a PEC transaction. */ count += inval; msg->len += inval; } bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n", inval, (flags & I2C_M_NO_RD_ACK) ? "(no ack/nak)" : (count ? "A" : "NA")); if (!(flags & I2C_M_NO_RD_ACK)) { inval = acknak(i2c_adap, count); if (inval < 0) return inval; } } 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 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); bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); if ((ret != 1) && !nak_ok) { dev_err(&i2c_adap->dev, "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 */ dev_err(&i2c_adap->dev, "died at 2nd address code\n"); return -EREMOTEIO; } if ( flags & I2C_M_RD ) { bit_dbg(3, &i2c_adap->dev, "emitting repeated " "start condition\n"); i2c_repstart(adap); /* okay, now switch into reading mode */ addr |= 0x01; ret = try_address(i2c_adap, addr, retries); if ((ret!=1) && !nak_ok) { dev_err(&i2c_adap->dev, "died at repeated 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; bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); 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) { bit_dbg(3, &i2c_adap->dev, "emitting " "repeated start condition\n"); i2c_repstart(adap); } ret = bit_doAddress(i2c_adap, pmsg); if ((ret != 0) && !nak_ok) { bit_dbg(1, &i2c_adap->dev, "NAK from " "device addr 0x%02x msg #%d\n", msgs[i].addr, i); goto bailout; } } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ ret = readbytes(i2c_adap, pmsg); if (ret >= 1) bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n", ret, ret == 1 ? "" : "s"); if (ret < pmsg->len) { if (ret >= 0) ret = -EREMOTEIO; goto bailout; } } else { /* write bytes from buffer */ ret = sendbytes(i2c_adap, pmsg); if (ret >= 1) bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n", ret, ret == 1 ? "" : "s"); if (ret < pmsg->len) { if (ret >= 0) ret = -EREMOTEIO; goto bailout; } } } ret = i;bailout: bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); i2c_stop(adap); return ret;}static u32 bit_func(struct i2c_adapter *adap){ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;}/* -----exported algorithm data: ------------------------------------- */static const struct i2c_algorithm i2c_bit_algo = { .master_xfer = bit_xfer, .functionality = bit_func,};/* * registering functions to load algorithms at runtime */static int i2c_bit_prepare_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; } /* register new adapter to i2c module... */ adap->algo = &i2c_bit_algo; adap->timeout = 100; /* default values, should */ adap->retries = 3; /* be replaced by defines */ return 0;}int i2c_bit_add_bus(struct i2c_adapter *adap){ int err; err = i2c_bit_prepare_bus(adap); if (err) return err; return i2c_add_adapter(adap);}EXPORT_SYMBOL(i2c_bit_add_bus);int i2c_bit_add_numbered_bus(struct i2c_adapter *adap){ int err; err = i2c_bit_prepare_bus(adap); if (err) return err; return i2c_add_numbered_adapter(adap);}EXPORT_SYMBOL(i2c_bit_add_numbered_bus);MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -