[RK3288][Android6.0] I2C預設傳輸速率及修改
阿新 • • 發佈:2018-12-22
Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92
RK對應的i2c controller驅動在
kernel/drivers/i2c/busses/i2c-rockchip.c對應的傳輸函式是rockchip_i2c_xfer():
static const struct i2c_algorithm rockchip_i2c_algorithm = {
.master_xfer = rockchip_i2c_xfer,
.functionality = rockchip_i2c_func,
};
程式碼上一般會直接呼叫i2c_master_send或者i2c_master_recvi2c_master_send|i2c_master_recv -> i2c_transfer -> adap->algo->master_xfer -> rockchip_i2c_xfer
這種情況下預設是i2c的傳輸速率設的是100kHz.而有些地方會直接呼叫i2c_transfer(), 比如at24.c中int i2c_master_send(const struct i2c_client *client, const char *buf, int count) { ...... #ifdef CONFIG_I2C_ROCKCHIP_COMPAT msg.scl_rate = 100 * 1000; #endif ret = i2c_transfer(adap, &msg, 1); ...... } int i2c_master_recv(const struct i2c_client *client, char *buf, int count) { ...... #ifdef CONFIG_I2C_ROCKCHIP_COMPAT msg.scl_rate = 100 * 1000; #endif ret = i2c_transfer(adap, &msg, 1); ...... } EXPORT_SYMBOL(i2c_master_recv);
這種情況,最終也是呼叫rockchip_i2c_xfer().static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, unsigned offset, size_t count) { ...... default: i = 0; if (at24->chip.flags & AT24_FLAG_ADDR16) msgbuf[i++] = offset >> 8; msgbuf[i++] = offset; msg[0].addr = client->addr; msg[0].buf = msgbuf; msg[0].len = i; msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].buf = buf; msg[1].len = count; } ...... default: status = i2c_transfer(client->adapter, msg, 2); if (status == 2) status = count; } ...... return -ETIMEDOUT; }
但是這時驅動設定scl rate,雖然預設也是100kHz,但會有類似如下警告:static int rockchip_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { ...... #ifdef CONFIG_I2C_ROCKCHIP_COMPAT if (msgs[0].scl_rate <= 400000 && msgs[0].scl_rate >= 10000) scl_rate = msgs[0].scl_rate; else if (msgs[0].scl_rate > 400000) { dev_warn_ratelimited(i2c->dev, "Warning: addr[0x%04x] msg[0].scl_rate( = %dKhz) is too high!", msgs[0].addr, msgs[0].scl_rate/1000); scl_rate = 400000; } else { dev_warn_ratelimited(i2c->dev, "Warning: addr[0x%04x] msg[0].scl_rate( = %dKhz) is too low!", msgs[0].addr, msgs[0].scl_rate/1000); scl_rate = 100000; } rockchip_i2c_set_clk(i2c, scl_rate); #endif i2c_dbg(i2c->dev, "i2c transfer start: addr: 0x%04x, scl_reate: %ldKhz, len: %d\n", msgs[0].addr, scl_rate/1000, num); ret = rockchip_i2c_doxfer(i2c, msgs, num); i2c_dbg(i2c->dev, "i2c transfer stop: addr: 0x%04x, state: %d, ret: %d\n", msgs[0].addr, ret, i2c->state); ...... }
rockchip_i2c ff170000.i2c: Warning: addr[0x0050] msg[0].scl_rate( = 0Khz) is too low!
修改:
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 2baeec5..bf090b4 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -213,11 +213,14 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
msg[0].addr = client->addr;
msg[0].buf = msgbuf;
msg[0].len = i;
+ msg[0].scl_rate = 100*1000;
+
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].buf = buf;
msg[1].len = count;
+ msg[1].scl_rate = 100*1000;
}