📄 i2c-core.c
字号:
/* Normal entries are done last, unless shadowed by an ignore entry */ for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { int j, ignore; ignore = 0; for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; j += 2) { if ((address_data->ignore[j] == adap_id || address_data->ignore[j] == ANY_I2C_BUS) && address_data->ignore[j + 1] == address_data->normal_i2c[i]) { dev_dbg(&adapter->dev, "found ignore " "parameter for adapter %d, " "addr 0x%02x\n", adap_id, address_data->ignore[j + 1]); ignore = 1; break; } } if (ignore) continue; dev_dbg(&adapter->dev, "found normal entry for adapter %d, " "addr 0x%02x\n", adap_id, address_data->normal_i2c[i]); err = i2c_probe_address(adapter, address_data->normal_i2c[i], -1, found_proc); if (err) return err; } return 0;}EXPORT_SYMBOL(i2c_probe);struct i2c_client *i2c_new_probed_device(struct i2c_adapter *adap, struct i2c_board_info *info, unsigned short const *addr_list){ int i; /* Stop here if the bus doesn't support probing */ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) { dev_err(&adap->dev, "Probing not supported\n"); return NULL; } mutex_lock(&adap->clist_lock); for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { dev_warn(&adap->dev, "Invalid 7-bit address " "0x%02x\n", addr_list[i]); continue; } /* Check address availability */ if (__i2c_check_addr(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); continue; } /* Test address responsiveness The default probe method is a quick write, but it is known to corrupt the 24RF08 EEPROMs due to a state machine bug, and could also irreversibly write-protect some EEPROMs, so for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte read instead. Also, some bus drivers don't implement quick write, so we fallback to a byte read it that case too. */ if ((addr_list[i] & ~0x07) == 0x30 || (addr_list[i] & ~0x0f) == 0x50 || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) { if (i2c_smbus_xfer(adap, addr_list[i], 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, NULL) >= 0) break; } else { if (i2c_smbus_xfer(adap, addr_list[i], 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_QUICK, NULL) >= 0) break; } } mutex_unlock(&adap->clist_lock); if (addr_list[i] == I2C_CLIENT_END) { dev_dbg(&adap->dev, "Probing failed, no device found\n"); return NULL; } info->addr = addr_list[i]; return i2c_new_device(adap, info);}EXPORT_SYMBOL_GPL(i2c_new_probed_device);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;}EXPORT_SYMBOL(i2c_get_adapter);void i2c_put_adapter(struct i2c_adapter *adap){ module_put(adap->owner);}EXPORT_SYMBOL(i2c_put_adapter);/* 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);}EXPORT_SYMBOL(i2c_smbus_write_quick);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;}EXPORT_SYMBOL(i2c_smbus_read_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);}EXPORT_SYMBOL(i2c_smbus_write_byte);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;}EXPORT_SYMBOL(i2c_smbus_read_byte_data);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);}EXPORT_SYMBOL(i2c_smbus_write_byte_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;}EXPORT_SYMBOL(i2c_smbus_read_word_data);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);}EXPORT_SYMBOL(i2c_smbus_write_word_data);/** * i2c_smbus_read_block_data - SMBus block read request * @client: Handle to slave device * @command: Command byte issued to let the slave know what data should * be returned * @values: Byte array into which data will be read; big enough to hold * the data returned by the slave. SMBus allows at most 32 bytes. * * Returns the number of bytes read in the slave's response, else a * negative number to indicate some kind of error. * * Note that using this function requires that the client's adapter support * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality. Not all adapter drivers * support this; its emulation through I2C messaging relies on a specific * mechanism (I2C_M_RECV_LEN) which may not be implemented. */s32 i2c_smbus_read_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_BLOCK_DATA, &data)) return -1; memcpy(values, &data.block[1], data.block[0]); return data.block[0];}EXPORT_SYMBOL(i2c_smbus_read_block_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);}EXPORT_SYMBOL(i2c_smbus_write_block_data);/* Returns the number of read bytes */s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values){ union i2c_smbus_data data; if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX; data.block[0] = length; 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];}EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);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);}EXPORT_SYMBOL(i2c_smbus_write_i2c_block_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) { msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ } 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: num = 2; /* Another special case */ read_write = I2C_SMBUS_READ; if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { dev_err(&adapter->dev, "%s called with invalid " "block proc call size (%d)\n", __FUNCTION__, data->block[0]); return -1; } msg[0].len = data->block[0] + 2; for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ break; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].len = data->block[0]; } 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: for (i = 0; i < data->block[0]; i++) data->block[i+1] = msgbuf1[i]; break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: for (i = 0; i < msgbuf1[0] + 1; i++) data->block[i] = 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;}EXPORT_SYMBOL(i2c_smbus_xfer);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 + -