📄 i2c-core.c
字号:
address_data->normal_i2c[i]); err = i2c_probe_address(adapter, address_data->normal_i2c[i], -1, found_proc); if (err) return err; } return 0;}struct i2c_adapter* i2c_get_adapter(int id){ struct i2c_adapter *adapter; mutex_lock(&core_lists); adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; mutex_unlock(&core_lists); return adapter;}void i2c_put_adapter(struct i2c_adapter *adap){ module_put(adap->owner);}/* The SMBus parts */#define POLY (0x1070U << 3) static u8crc8(u16 data){ int i; for(i = 0; i < 8; i++) { if (data & 0x8000) data = data ^ POLY; data = data << 1; } return (u8)(data >> 8);}/* Incremental CRC8 over count bytes in the array pointed to by p */static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count){ int i; for(i = 0; i < count; i++) crc = crc8((crc ^ p[i]) << 8); return crc;}/* Assume a 7-bit address, which is reasonable for SMBus */static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg){ /* The address will be sent first */ u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD); pec = i2c_smbus_pec(pec, &addr, 1); /* The data buffer follows */ return i2c_smbus_pec(pec, msg->buf, msg->len);}/* Used for write only transactions */static inline void i2c_smbus_add_pec(struct i2c_msg *msg){ msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg); msg->len++;}/* Return <0 on CRC error If there was a write before this read (most cases) we need to take the partial CRC from the write part into account. Note that this function does modify the message (we need to decrease the message length to hide the CRC byte from the caller). */static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg){ u8 rpec = msg->buf[--msg->len]; cpec = i2c_smbus_msg_pec(cpec, msg); if (rpec != cpec) { pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); return -1; } return 0; }s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value){ return i2c_smbus_xfer(client->adapter,client->addr,client->flags, value,0,I2C_SMBUS_QUICK,NULL);}s32 i2c_smbus_read_byte(struct i2c_client *client){ union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data)) return -1; else return data.byte;}s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value){ return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);}s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command){ union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data)) return -1; else return data.byte;}s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value){ union i2c_smbus_data data; data.byte = value; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA,&data);}s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command){ union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data)) return -1; else return data.word;}s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value){ union i2c_smbus_data data; data.word = value; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_WORD_DATA,&data);}s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values){ union i2c_smbus_data data; if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX; data.block[0] = length; memcpy(&data.block[1], values, length); return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_BLOCK_DATA,&data);}/* Returns the number of read bytes */s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values){ union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_I2C_BLOCK_DATA,&data)) return -1; memcpy(values, &data.block[1], data.block[0]); return data.block[0];}s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values){ union i2c_smbus_data data; if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX; data.block[0] = length; memcpy(data.block + 1, values, length); return i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &data);}/* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data){ /* So we need to generate a series of msgs. In the case of writing, we need to use only one message; when reading, we need two. We initialize most things with sane defaults, to keep the code below somewhat simpler. */ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ?2:1; struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; int i; u8 partial_pec = 0; msgbuf0[0] = command; switch(size) { case I2C_SMBUS_QUICK: msg[0].len = 0; /* Special case: The read/write field is used as data */ msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0; num = 1; break; case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { /* Special case: only a read! */ msg[0].flags = I2C_M_RD | flags; num = 1; } break; case I2C_SMBUS_BYTE_DATA: if (read_write == I2C_SMBUS_READ) msg[1].len = 1; else { msg[0].len = 2; msgbuf0[1] = data->byte; } break; case I2C_SMBUS_WORD_DATA: if (read_write == I2C_SMBUS_READ) msg[1].len = 2; else { msg[0].len=3; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = data->word >> 8; } break; case I2C_SMBUS_PROC_CALL: num = 2; /* Special case */ read_write = I2C_SMBUS_READ; msg[0].len = 3; msg[1].len = 2; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = data->word >> 8; break; case I2C_SMBUS_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { dev_err(&adapter->dev, "Block read not supported " "under I2C emulation!\n"); return -1; } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { dev_err(&adapter->dev, "smbus_access called with " "invalid block write size (%d)\n", data->block[0]); return -1; } for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; case I2C_SMBUS_BLOCK_PROC_CALL: dev_dbg(&adapter->dev, "Block process call not supported " "under I2C emulation!\n"); return -1; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].len = I2C_SMBUS_BLOCK_MAX; } else { msg[0].len = data->block[0] + 1; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with " "invalid block write size (%d)\n", data->block[0]); return -1; } for (i = 1; i <= data->block[0]; i++) msgbuf0[i] = data->block[i]; } break; default: dev_err(&adapter->dev, "smbus_access called with invalid size (%d)\n", size); return -1; } i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA); if (i) { /* Compute PEC if first message is a write */ if (!(msg[0].flags & I2C_M_RD)) { if (num == 1) /* Write only */ i2c_smbus_add_pec(&msg[0]); else /* Write followed by read */ partial_pec = i2c_smbus_msg_pec(0, &msg[0]); } /* Ask for PEC if last message is a read */ if (msg[num-1].flags & I2C_M_RD) msg[num-1].len++; } if (i2c_transfer(adapter, msg, num) < 0) return -1; /* Check PEC if last message is a read */ if (i && (msg[num-1].flags & I2C_M_RD)) { if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0) return -1; } if (read_write == I2C_SMBUS_READ) switch(size) { case I2C_SMBUS_BYTE: data->byte = msgbuf0[0]; break; case I2C_SMBUS_BYTE_DATA: data->byte = msgbuf1[0]; break; case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_PROC_CALL: data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; case I2C_SMBUS_I2C_BLOCK_DATA: /* fixed at 32 for now */ data->block[0] = I2C_SMBUS_BLOCK_MAX; for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) data->block[i+1] = msgbuf1[i]; break; } return 0;}s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data){ s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { mutex_lock(&adapter->bus_lock); res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, command,size,data); mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); return res;}/* Next four are needed by i2c-isa */EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);EXPORT_SYMBOL_GPL(i2c_adapter_driver);EXPORT_SYMBOL_GPL(i2c_adapter_class);EXPORT_SYMBOL_GPL(i2c_bus_type);EXPORT_SYMBOL(i2c_add_adapter);EXPORT_SYMBOL(i2c_del_adapter);EXPORT_SYMBOL(i2c_del_driver);EXPORT_SYMBOL(i2c_attach_client);EXPORT_SYMBOL(i2c_detach_client);EXPORT_SYMBOL(i2c_use_client);EXPORT_SYMBOL(i2c_release_client);EXPORT_SYMBOL(i2c_clients_command);EXPORT_SYMBOL(i2c_check_addr);EXPORT_SYMBOL(i2c_master_send);EXPORT_SYMBOL(i2c_master_recv);EXPORT_SYMBOL(i2c_control);EXPORT_SYMBOL(i2c_transfer);EXPORT_SYMBOL(i2c_get_adapter);EXPORT_SYMBOL(i2c_put_adapter);EXPORT_SYMBOL(i2c_probe);EXPORT_SYMBOL(i2c_smbus_xfer);EXPORT_SYMBOL(i2c_smbus_write_quick);EXPORT_SYMBOL(i2c_smbus_read_byte);EXPORT_SYMBOL(i2c_smbus_write_byte);EXPORT_SYMBOL(i2c_smbus_read_byte_data);EXPORT_SYMBOL(i2c_smbus_write_byte_data);EXPORT_SYMBOL(i2c_smbus_read_word_data);EXPORT_SYMBOL(i2c_smbus_write_word_data);EXPORT_SYMBOL(i2c_smbus_write_block_data);EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");MODULE_DESCRIPTION("I2C-Bus main module");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -