1. 程式人生 > >[RK3288][Android6.0] I2C預設傳輸速率及修改

[RK3288][Android6.0] I2C預設傳輸速率及修改

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_recv
i2c_master_send|i2c_master_recv ->    i2c_transfer -> adap->algo->master_xfer -> rockchip_i2c_xfer
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);
這種情況下預設是i2c的傳輸速率設的是100kHz.而有些地方會直接呼叫i2c_transfer(), 比如at24.c中
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;
}
這種情況,最終也是呼叫rockchip_i2c_xfer().
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);
......
}
但是這時驅動設定scl rate,雖然預設也是100kHz,但會有類似如下警告:
rockchip_i2c ff170000.i2c: Warning: addr[0x0050] msg[0].scl_rate( = 0Khz) is too low!

修改:

dts也沒有提供相對應的property來修改scl rate,因此只能在程式碼中修改了,例如:
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;
        }