📄 i2c-core.c
字号:
int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, union i2c_smbus_data *data){ u8 buf[3], rpec, cpec; buf[1] = command; switch(size) { case I2C_SMBUS_BYTE_DATA: buf[0] = (addr << 1) | 1; cpec = i2c_smbus_pec(2, buf, NULL); rpec = data->byte; break; case I2C_SMBUS_WORD_DATA: buf[0] = (addr << 1) | 1; buf[2] = data->word & 0xff; cpec = i2c_smbus_pec(3, buf, NULL); rpec = data->word >> 8; break; case I2C_SMBUS_WORD_DATA_PEC: /* unsupported */ cpec = rpec = 0; break; case I2C_SMBUS_PROC_CALL_PEC: /* unsupported */ cpec = rpec = 0; break; case I2C_SMBUS_BLOCK_DATA_PEC: buf[0] = (addr << 1); buf[2] = (addr << 1) | 1; cpec = i2c_smbus_pec(3, buf, data->block); rpec = data->block[data->block[0] + 1]; break; case I2C_SMBUS_BLOCK_PROC_CALL_PEC: buf[0] = (addr << 1) | 1; rpec = i2c_smbus_partial_pec(partial, 1, buf, data->block); cpec = data->block[data->block[0] + 1]; break; default: cpec = rpec = 0; break; } 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 0x0FF & data.byte;}s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value){ union i2c_smbus_data data; /* only for PEC */ return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data);}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 0x0FF & 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 0x0FFFF & 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_process_call(struct i2c_client *client, u8 command, u16 value){ union i2c_smbus_data data; data.word = value; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_PROC_CALL, &data)) return -1; else return 0x0FFFF & data.word;}/* Returns the number of read bytes */s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values){ union i2c_smbus_data data; int i; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_BLOCK_DATA,&data)) return -1; else { for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; return data.block[0]; }}s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values){ union i2c_smbus_data data; int i; if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = 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_block_process_call(struct i2c_client *client, u8 command, u8 length, u8 *values){ union i2c_smbus_data data; int i; if (length > I2C_SMBUS_BLOCK_MAX - 1) return -1; data.block[0] = length; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; if(i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_BLOCK_PROC_CALL, &data)) return -1; for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; return data.block[0];}/* 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; int i; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_I2C_BLOCK_DATA,&data)) return -1; else { for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; return data.block[0]; }}s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values){ union i2c_smbus_data data; int i; if (length > I2C_SMBUS_I2C_BLOCK_MAX) length = I2C_SMBUS_I2C_BLOCK_MAX; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = 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[34]; unsigned char msgbuf1[34]; 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; 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) & 0xff; } 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) & 0xff; break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_DATA_PEC: 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; } if(size == I2C_SMBUS_BLOCK_DATA_PEC) (msg[0].len)++; for (i = 1; i <= msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; case I2C_SMBUS_BLOCK_PROC_CALL: case I2C_SMBUS_BLOCK_PROC_CALL_PEC: 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_I2C_BLOCK_MAX; } else { msg[0].len = data->block[0] + 1; if (msg[0].len > I2C_SMBUS_I2C_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; } if (i2c_transfer(adapter, msg, num) < 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_I2C_BLOCK_MAX; for (i = 0; i < I2C_SMBUS_I2C_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; int swpec = 0; u8 partial = 0; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if((flags & I2C_CLIENT_PEC) && !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { swpec = 1; if(read_write == I2C_SMBUS_READ && size == I2C_SMBUS_BLOCK_DATA) size = I2C_SMBUS_BLOCK_DATA_PEC; else if(size == I2C_SMBUS_PROC_CALL) size = I2C_SMBUS_PROC_CALL_PEC; else if(size == I2C_SMBUS_BLOCK_PROC_CALL) { i2c_smbus_add_pec(addr, command, I2C_SMBUS_BLOCK_DATA, data); partial = data->block[data->block[0] + 1]; size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; } else if(read_write == I2C_SMBUS_WRITE && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA) size = i2c_smbus_add_pec(addr, command, size, data); } if (adapter->algo->smbus_xfer) { down(&adapter->bus_lock); res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, command,size,data); up(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); if(res >= 0 && swpec && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC || size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { if(i2c_smbus_check_pec(addr, command, size, partial, data)) return -1; } return res;}/* You should always define `functionality'; the 'else' is just for backward compatibility. */ u32 i2c_get_functionality (struct i2c_adapter *adap){ if (adap->algo->functionality) return adap->algo->functionality(adap); else return 0xffffffff;}int i2c_check_functionality (struct i2c_adapter *adap, u32 func){ u32 adap_func = i2c_get_functionality (adap); return (func & adap_func) == func;}EXPORT_SYMBOL(i2c_add_adapter);EXPORT_SYMBOL(i2c_del_adapter);EXPORT_SYMBOL(i2c_add_driver);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_adapter_id);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_process_call);EXPORT_SYMBOL(i2c_smbus_read_block_data);EXPORT_SYMBOL(i2c_smbus_write_block_data);EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);EXPORT_SYMBOL(i2c_get_functionality);EXPORT_SYMBOL(i2c_check_functionality);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 + -