linux下的i2c驅動以及與時鐘芯片pcf8563通信過程
爲更深入的瞭解linux下的i2c總線驅動以及通信原理,可以用一個用戶程序模擬,
這個程序,可以使用一個addr, 一個offset,對i2c的從設備地址爲addr,寄存器地址爲offset的寄存器讀寫操作。
在我們的版卡上時鐘芯片pcf8563的i2c地址爲0x51 , pcf8563有00—0f個寄存器,通過讀寫秒,分鐘,小時等的寄存器,可以驗證我們的程序是否執行成功。
一,這個測試程序怎麼寫?
思路是: hwclock -w /hwclock -s 這些命令都是對始終芯片pcf8563執行了讀寫的操作命令,那麼我們的程序,就模仿hwclock -w 的執行過程,最後實現通過cpu(octeon) 與i2c從設備的數據通信。 這樣就看到了i2c總線在處理器octeon的控制下的通信過程。
二,怎麼觀察hwclock -w 的執行過程?
hwclock -w 讀寫了時鐘芯片pcf8563,那麼從pcf8563的驅動程序入手,在pcf8563中的read,write 函數中進入i2c層。再有i2c層進入octeon。
即從rtc層進入i2c層, 再進入cpu層。 在這之間的執行函數分別加printk,在版卡上觀察dmesg, 這樣就可以找到執行的層層路徑。
知道了數據的發送路徑,再觀察出hwclock -w 實現了哪些數據的包裝和發送,那麼我們的程序就可以在以用戶層模仿這些操作。
注意:
我們版卡的cpu是CaviumNetworks OCTEON CN52XX
****************************************************************************** *************************
by 韓大衛@吉林師範大學 [email protected] 轉載務必表明出處!
********************************************** *******************************
hwclock -w 命令需要使用到的rtc芯片pcf8563中的讀寫函數如下:
在driver/rtc/rtc-pcf8563.c 中
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
int i, err;
unsigned char buf[9];
printk(KERN_DEBUG "%s: secs=%d, mins=%d, hours=%d,ecs=%d, mins=%d, hours=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
/* hours, minutes and seconds */
buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);
buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);
buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);
buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
/* month, 1 - 12 */
buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);
/* year and century */
buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
/* write register's data */
for (i = 0; i < 7; i++) {
unsigned char data[2] = { PCF8563_REG_SC + i,
buf[PCF8563_REG_SC + i] };
err = i2c_master_send(client, data, sizeof(data));
if (err != sizeof(data)) {
dev_err(&client->dev,
"%s: err=%d addr=%02x, data=%02x\n",
__func__, err, data[0], data[1]);
return -EIO;
}
在 driver/i2c/i2c-core.c 中:
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
{
int ret;
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
//added by handwei.2012.7.5
printk(KERN_DEBUG "%s: msg.addr = %x,msg.flags = %x,msg.len = %d,msg.buf[0] = %x,msg.buf[1] = %x\n",__func__,msg.addr,msg.flags,msg.len,msg.buf[0],msg.buf[1]);
ret = i2c_transfer(adap, &msg, 1);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
注意: i2c_transfer(adap, &msg, 1);
中的 1 決定了 進入 octeon_i2c_xfer ()後,要進入 if(num==1)中。
下面是 octeon_i2c_xfer的代碼:
static int octeon_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int num)
{
printk(KERN_DEBUG "here is octeon_i2c_xfer,num = %d\n",num);
struct i2c_msg *pmsg;
int i;
int ret = 0;
struct octeon_i2c *i2c = i2c_get_adapdata(adap);
if (num == 1) {
if (msgs[0].len > 0 && msgs[0].len <= 8) {
if (msgs[0].flags & I2C_M_RD)
ret = octeon_i2c_simple_read(i2c, msgs);
else
ret = octeon_i2c_simple_write(i2c, msgs);
goto out;
}
} else if (num == 2) {
if ((msgs[0].flags & I2C_M_RD) == 0 &&
msgs[0].len > 0 && msgs[0].len <= 2 &&
msgs[1].len > 0 && msgs[1].len <= 8 &&
msgs[0].addr == msgs[1].addr) {
if (msgs[1].flags & I2C_M_RD)
ret = octeon_i2c_ia_read(i2c, msgs);
else
ret = octeon_i2c_ia_write(i2c, msgs);
goto out;
}
}
for (i = 0; ret == 0 && i < num; i++) {
pmsg = &msgs[i];
dev_dbg(i2c->dev,
"Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
pmsg->flags & I2C_M_RD ? "read" : "write",
pmsg->len, pmsg->addr, i + 1, num);
if (pmsg->flags & I2C_M_RD)
ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
pmsg->len, i);
else
ret = octeon_i2c_ia_write(i2c, msgs);
}
octeon_i2c_stop(i2c);
out:
return (ret != 0) ? ret : num;
}
通過在 i2c-core.c: i2c_master_send()中添加printk,
printk(KERN_DEBUG "%s: msg.addr = %x,msg.flags = %x,msg.len = %d,msg.buf(data) = %s\n",__func__,msg.addr,msg.flags,msg.len,msg.buf);
運行後可以看到 msg.flags 一直等於0 ,那麼 在 octeon_i2c_xfer ()中
if (num == 1) {
if (msgs[0].len > 0 && msgs[0].len <= 8) {
if (msgs[0].flags & I2C_M_RD)
ret = octeon_i2c_simple_read(i2c, msgs);
else
ret = octeon_i2c_simple_write(i2c, msgs);
goto out;
會一直進入octeon_i2c_simple_write()執行寫操作。 下面是octeon_i2c_simple_write()的代碼:
static int octeon_i2c_simple_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
{
u64 cmd;
int i, j;
int ret = 0;
octeon_i2c_enable_hlc(i2c);
printk(KERN_DEBUG "%s:\n",__func__);
retry:
cmd = SW_TWSI_V | SW_TWSI_SOVR;
/* SIZE */
cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_A_SHIFT;
if (msgs[0].flags & I2C_M_TEN)
cmd |= SW_TWSI_OP_10;
else
cmd |= SW_TWSI_OP_7;
printk(KERN_DEBUG "%s:cmd = %llx\n",__func__,cmd);
for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--){
cmd |= (u64)msgs[0].buf[j] << (8 * i);
printk(KERN_DEBUG "%s:msgs[0].buf[%d] = %x,cmd = %llx\n",__func__,j,msgs[0].buf[j],cmd);
}
if (msgs[0].len >= 4) {
u64 ext = 0;
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
ext |= (u64)msgs[0].buf[j] << (8 * i);
printk(KERN_DEBUG "%s:ext = %llx\n",__func__,ext);
__raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
}
octeon_i2c_hlc_int_clear(i2c);
__raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
goto err;
cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
if ((cmd & SW_TWSI_R) == 0) {
if (octeon_i2c_lost_arb(cmd))
goto retry;
ret = -EIO;
goto err;
}
err:
return ret;
}
下面是版卡執行 hwclock -w 後的dmesg 中的一部分:
[ 38.989069] pcf8563_get_datetime: secs=4, mins=41, hours=18,ecs=5, mins=6, hours=112
[ 40.292306] pcf8563_set_datetime: secs=5, mins=41, hours=18,ecs=5, mins=6, hours=112
[ 40.292321] pcf8563_set_datetime:data[0] = 2,data[1] = 5
[ 40.292333] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 2,msg.buf[1] = 5
[ 40.292346] here is octeon_i2c_xfer, num = 1
[ 40.292355] octeon_i2c_simple_write:
[ 40.292363] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.292374] octeon_i2c_simple_write:msgs[0].buf[1] = 5,cmd = 8090510000000005
[ 40.292386] octeon_i2c_simple_write:msgs[0].buf[0] = 2,cmd = 8090510000000205
[ 40.292687] pcf8563_set_datetime:data[0] = 3,data[1] = 41
[ 40.292699] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 3,msg.buf[1] = 41
[ 40.292712] here is octeon_i2c_xfer, num = 1
[ 40.292719] octeon_i2c_simple_write:
[ 40.292727] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.292738] octeon_i2c_simple_write:msgs[0].buf[1] = 41,cmd = 8090510000000041
[ 40.292750] octeon_i2c_simple_write:msgs[0].buf[0] = 3,cmd = 8090510000000341
[ 40.293049] pcf8563_set_datetime:data[0] = 4,data[1] = 18
[ 40.293061] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 4,msg.buf[1] = 18
[ 40.293074] here is octeon_i2c_xfer, num = 1
[ 40.293082] octeon_i2c_simple_write:
[ 40.293089] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.293100] octeon_i2c_simple_write:msgs[0].buf[1] = 18,cmd = 8090510000000018
[ 40.293112] octeon_i2c_simple_write:msgs[0].buf[0] = 4,cmd = 8090510000000418
[ 40.293411] pcf8563_set_datetime:data[0] = 5,data[1] = 5
[ 40.293423] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 5,msg.buf[1] = 5
[ 40.293435] here is octeon_i2c_xfer, num = 1
[ 40.293443] octeon_i2c_simple_write:
[ 40.293451] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.293462] octeon_i2c_simple_write:msgs[0].buf[1] = 5,cmd = 8090510000000005
[ 40.293474] octeon_i2c_simple_write:msgs[0].buf[0] = 5,cmd = 8090510000000505
[ 40.293772] pcf8563_set_datetime:data[0] = 6,data[1] = 4
[ 40.293784] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 6,msg.buf[1] = 4
[ 40.293796] here is octeon_i2c_xfer, num = 1
[ 40.293804] octeon_i2c_simple_write:
[ 40.293812] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.293822] octeon_i2c_simple_write:msgs[0].buf[1] = 4,cmd = 8090510000000004
[ 40.293835] octeon_i2c_simple_write:msgs[0].buf[0] = 6,cmd = 8090510000000604
[ 40.294133] pcf8563_set_datetime:data[0] = 7,data[1] = 7
[ 40.294145] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 7,msg.buf[1] = 7
[ 40.294157] here is octeon_i2c_xfer, num = 1
[ 40.294165] octeon_i2c_simple_write:
[ 40.294173] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.294184] octeon_i2c_simple_write:msgs[0].buf[1] = 7,cmd = 8090510000000007
[ 40.294196] octeon_i2c_simple_write:msgs[0].buf[0] = 7,cmd = 8090510000000707
[ 40.294494] pcf8563_set_datetime:data[0] = 8,data[1] = 12
[ 40.294506] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 8,msg.buf[1] = 12
[ 40.294519] here is octeon_i2c_xfer, num = 1
[ 40.294526] octeon_i2c_simple_write:
[ 40.294534] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.294545] octeon_i2c_simple_write:msgs[0].buf[1] = 12,cmd = 8090510000000012
[ 40.294557] octeon_i2c_simple_write:msgs[0].buf[0] = 8,cmd = 8090510000000812
pcf8563_get_datetime: 是讀到的時間
pcf8563_set_datetime: 是要寫的時間
在pcf8563_set_datetime 中需要執行7次循環:
/* write register's data */
for (i = 0; i < 7; i++) {
unsigned char data[2] = { PCF8563_REG_SC + i,
buf[PCF8563_REG_SC + i] };
err = i2c_master_send(client, data, sizeof(data));
第一個循環部分dmesg:
[ 40.292321] pcf8563_set_datetime:data[0] = 2,data[1] = 5
[ 40.292333] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 2,msg.buf[1] = 5
[ 40.292346] here is octeon_i2c_xfer, num = 1
[ 40.292355] octeon_i2c_simple_write:
[ 40.292363] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.292374] octeon_i2c_simple_write:msgs[0].buf[1] = 5,cmd = 8090510000000005
[ 40.292386] octeon_i2c_simple_write:msgs[0].buf[0] = 2,cmd = 8090510000000205
在pcf8563_set_datetime ()中:
for (i = 0; i < 7; i++) {
unsigned char data[2] = { PCF8563_REG_SC + i,
//注意: #define PCF8563_REG_SC 0x02
err = i2c_master_send(client, data, sizeof(data));
if (err != sizeof(data)) {
dev_err(&client->dev,
"%s: err=%d addr=%02x, data=%02x\n",
__func__, err, data[0], data[1]);
}
通過i2c_master_send()進入octeon_i2c_xfer(),再進入 octeon_i2c_simple_write,
在這個函數中:
{
cmd = SW_TWSI_V | SW_TWSI_SOVR;
cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
// Address field.:<49:40>
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_A_SHIFT;
if (msgs[0].flags & I2C_M_TEN)
cmd |= SW_TWSI_OP_10;
for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--){
cmd |= (u64)msgs[0].buf[j] << (8 * i);
...
}
根據msgs中的len,addr,flags, buf[]中的內容填充cmd,執行cmd 並 返回執行結果
同樣的, 在進入第二次循環時, 這時操作的是pcf8563 的第三個寄存器,03h: minutes 分鐘寄存器。
[ 40.292687] pcf8563_set_datetime:data[0] = 3,data[1] = 41
[ 40.292699] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 3,msg.buf[1] = 41
[ 40.292712] here is octeon_i2c_xfer, num = 1
[ 40.292719] octeon_i2c_simple_write:
[ 40.292727] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.292738] octeon_i2c_simple_write:msgs[0].buf[1] = 41,cmd = 8090510000000041
[ 40.292750] octeon_i2c_simple_write:msgs[0].buf[0] = 3,cmd = 8090510000000341
第三次,操作pcf8563的第四個寄存器:04h hours
[ 40.293049] pcf8563_set_datetime:data[0] = 4,data[1] = 18
[ 40.293061] i2c_master_send: msg.addr = 51,msg.flags = 0,msg.len = 2,msg.buf[0] = 4,msg.buf[1] = 18
[ 40.293074] here is octeon_i2c_xfer, num = 1
[ 40.293082] octeon_i2c_simple_write:
[ 40.293089] octeon_i2c_simple_write:cmd = 8090510000000000
[ 40.293100] octeon_i2c_simple_write:msgs[0].buf[1] = 18,cmd = 8090510000000018
[ 40.293112] octeon_i2c_simple_write:msgs[0].buf[0] = 4,cmd = 8090510000000418
我們看到:
hwclock -w 通過 octeon_i2c_simple_write 來寫pcf8563時鐘芯片,
其中:msg.addr = 0x51 , msg.len = 2 ,msg.flags = 0,
msg.buf[0] = 相應地址偏移
msg.buf[1] = 給相應寄存器的值
cmd 中最後8bit爲數據域: 0418 ,04 代表offset, 18代表data。
那麼我們的i2c-test, 也這樣操作試試:
包裝一個msg, 傳入octeon_i2c_xfer(),再傳入 octeon_i2c_simple_write,看看能不能得到期望的執行結果。
另外 , 還要通過hwclock 來觀察 ,爲什麼沒有使用octeon_i2c_simple_read 來讀寄存器的現象。
注意到:
在關於寫的操作中: pcf8563_set_datetime()
i2c_master_send()
{
..
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
ret = i2c_transfer(adap, &msg, 1);
..}
i2c_transfer 最後一個參數是 1, 就是寫的時候每次只寫一個msg
這個msg中的成員buf,在pcf8563_set_datetime()中做了相應的填充:
for (i = 0; i < 7; i++) {
unsigned char data[2] = { PCF8563_REG_SC + i,
buf[PCF8563_REG_SC + i] };
err = i2c_master_send(client, data, sizeof(data));
}
最後,這一個msg中buf 內容包括了全部的寫的信息。
而在pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = {
{ client->addr, 0, 1, buf }, /* setup read ptr */
{ client->addr, I2C_M_RD, 13, buf }, /* read status + date */
};
if ((i2c_transfer(client->adapter, msgs, 2)) != 2)
...
}
i2c_transfer 第三個參數是2,即每次讀操作時,每次操作2個msg。 兩個msg,addr相同,flags不同, len不同,buf內容也不同。
正是由於pcf8563_get_datetime與pcf8563_set_datetime 每次操作msg的個數不同,
所以進入octeon_i2c_xfer()後 執行的函數不同,這就是爲什麼每次pcf8563_get_datetime操作了octeon_i2c_xfer的 octeon_i2c_write() 與 octeon_i2c_read()
而pcf8563_set_datetime 每次操作了octeon_i2c_xfer的 octeon_i2c_simple_write()
這就是爲什麼使用hwclock -w 後觀察不到octeon_i2c_xfer()進入octeon_i2c_simple_read()的原因。
Hwclock -w 後:
here is pcf8563_get_datetime ,next func is i2c_transfer!
[ 1102.616179] octeon_i2c_xfer: num = 2
[ 1102.616188] octeon_i2c_xfer:msgs[0].addr = 51, msgs[0].flags = 0, msgs[0].len = 1
[ 1102.616200] octeon_i2c_xfer:msgs[0].buf[0] = 0
[ 1102.616211] octeon_i2c_xfer:msgs[1].addr = 51, msgs[1].flags = 1, msgs[1].len = 13
[ 1102.616223] octeon_i2c_xfer:msgs[1].buf[1] = 0
[ 1102.616233] octeon_i2c_write:data[0](msgs->buf[]) = 0, target(addr) = 51, length = 1, phase = 0
[ 1102.616360] octeon_i2c_write: data[0] = 0
[ 1102.616468] octeon_i2c_read:data[0](msgs->buf[0]) = 0,target(addr) = 51, length = 13,phase = 1
[ 1102.616697] octeon_i2c_read: data[0] = 8
[ 1102.616804] octeon_i2c_read: data[1] = 0
[ 1102.616911] octeon_i2c_read: data[2] = 28
[ 1102.617019] octeon_i2c_read: data[3] = 35
[ 1102.617127] octeon_i2c_read: data[4] = 14
[ 1102.617235] octeon_i2c_read: data[5] = 6
[ 1102.617342] octeon_i2c_read: data[6] = 2d
[ 1102.617450] octeon_i2c_read: data[7] = 27
[ 1102.617557] octeon_i2c_read: data[8] = 12
[ 1102.617665] octeon_i2c_read: data[9] = a0
[ 1102.617773] octeon_i2c_read: data[10] = 84
[ 1102.617881] octeon_i2c_read: data[11] = b2
[ 1102.617989] octeon_i2c_read: data[12] = b5
[ 1102.618003] here come back pcf8563_get_datetime ,the received data : secs=28, mins=35, hours=14,mday=6, mon=6, year=112,wday=5
由於num = 2,
進入octeon_i2c_xfer後 先要判斷:
else if (num == 2) {
if ((msgs[0].flags & I2C_M_RD) == 0 &&
msgs[0].len > 0 && msgs[0].len <= 2 &&
msgs[1].len > 0 && msgs[1].len <= 8 &&
msgs[0].addr == msgs[1].addr) {
if (msgs[1].flags & I2C_M_RD)
ret = octeon_i2c_ia_read(i2c, msgs);
else
ret = octeon_i2c_ia_write(i2c, msgs);
goto out;
for (i = 0; ret == 0 && i < num; i++) {
pmsg = &msgs[i];
dev_dbg(i2c->dev,
"Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
pmsg->flags & I2C_M_RD ? "read" : "write",
pmsg->len, pmsg->addr, i + 1, num);
if (pmsg->flags & I2C_M_RD)
ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
pmsg->len, i);
else
ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
pmsg->len, i);
}
由於 msgs[1].len = 13,不滿足條件,因此即使num=2,pcf8563_get_datetime永遠不會進入octeon_i2c_ia_read/write ,不會進入內部地址的讀寫操作。
之後程序進入for循環,這樣,經過判斷,第一次要進入octeon_i2c_write()函數,第二次循環進入 octeon_i2c_read(),
在 Octeon_i2c_write()中:
static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
const u8 *data, int length, int phase)
{
int i, result;
u8 tmp;
restart:
result = octeon_i2c_start(i2c);
if (result)
return result;
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1);
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
result = octeon_i2c_wait(i2c);
if (result)
return result;
for (i = 0; i < length; i++) {
tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
if (phase == 0 && octeon_i2c_lost_arb(tmp))
goto restart;
if ((tmp != STAT_TXADDR_ACK) && (tmp != STAT_TXDATA_ACK)) {
dev_err(i2c->dev,
"%s: bad status before write (0x%x)\n",
__func__, tmp);
return -EIO;
}
printk(KERN_DEBUG "%s: data[%d] = %x\n",__func__,i,data[i]);
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]);
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
result = octeon_i2c_wait(i2c);
if (result)
return result;
}
return 0;
}
其中:
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]);
作用就是將data[i] 數據寫進入octeon 的數據寄存器,即實現了寫的操作。
static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
u8 *data, int length, int phase)
{
//added by handawei.2012.7.2
printk(KERN_DEBUG "%s:data[0](msgs->buf[0]) = %xtarget(addr) = %x, length = %d,phase = %d\n",
__func__,data[0],target,length,phase);
int i, result;
u8 tmp;
if (length < 1)
return -EINVAL;
restart:
result = octeon_i2c_start(i2c);
if (result)
return result;
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, (target<<1) | 1);
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
result = octeon_i2c_wait(i2c);
if (result)
return result;
for (i = 0; i < length; i++) {
tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
if (phase == 0 && octeon_i2c_lost_arb(tmp))
goto restart;
if ((tmp != STAT_RXDATA_ACK) && (tmp != STAT_RXADDR_ACK)) {
dev_err(i2c->dev,
"%s: bad status before read (0x%x)\n",
__func__, tmp);
return -EIO;
}
if (i+1 < length)
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
TWSI_CTL_ENAB | TWSI_CTL_AAK);
else
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
TWSI_CTL_ENAB);
result = octeon_i2c_wait(i2c);
if (result)
return result;
data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
printk(KERN_DEBUG "%s: data[%d] = %x\n",__func__,i,data[i]);
}
return 0;
}
data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
data[i] 就保存了cpu 讀數據寄存器後的返回結果,即保存了讀的操作。
here is pcf8563_get_datetime ,next func is i2c_transfer!
[ 1102.616179] octeon_i2c_xfer: num = 2
[ 1102.616188] octeon_i2c_xfer:msgs[0].addr = 51, msgs[0].flags = 0, msgs[0].len = 1
[ 1102.616200] octeon_i2c_xfer:msgs[0].buf[0] = 0
[ 1102.616211] octeon_i2c_xfer:msgs[1].addr = 51, msgs[1].flags = 1, msgs[1].len = 13
[ 1102.616223] octeon_i2c_xfer:msgs[1].buf[1] = 0
[ 1102.616233] octeon_i2c_write:data[0](msgs->buf[]) = 0, target(addr) = 51, length = 1, phase = 0
[ 1102.616360] octeon_i2c_write: data[0] = 0
[ 1102.616468] octeon_i2c_read:data[0](msgs->buf[0]) = 0,target(addr) = 51, length = 13,phase = 1
[ 1102.616697] octeon_i2c_read: data[0] = 8
[ 1102.616804] octeon_i2c_read: data[1] = 0
[ 1102.616911] octeon_i2c_read: data[2] = 28
[ 1102.617773] octeon_i2c_read: data[10] = 84
[ 1102.618003] here come back pcf8563_get_datetime ,the received data : secs=28, mins=35, hours=14,mday=6, mon=6, year=112,wday=5
可以看到,len = 13,經過了13次循環後,通過讀pcf8563的00-0c號寄存器,buf[]得到了填充。
而返回後Buf[] 的值賦給了 struct rtc_time *tm 的相應成員。
在pcf8563_get_datatime()中,完成了對struct rtc_time *tm 的填充,完成了讀了操作。
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = {
{ client->addr, 0, 1, buf }, /* setup read ptr */
{ client->addr, I2C_M_RD, 13, buf }, /* read status + date */
};
printk(KERN_DEBUG "here is %s ,next func is i2c_transfer!\n",__func__);
/* read registers */
if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)
dev_info(&client->dev,
"low voltage detected, date/time is not reliable.\n");
// the orginal data is dev_dbg . modified by handawei.2012.6.4
dev_dbg(&client->dev,
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
__func__,
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7],
buf[8]);
tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ /* -1 :tm_mon: [0-11] */
tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
(tm->tm_year >= 100) : (tm->tm_year < 100);
/* detect the polarity heuristically. see note above. */
if (rtc_valid_tm(tm) < 0)
dev_err(&client->dev, "retrieved date/time is not valid.\n");
return 0;
}
執行 hwclock -r 後 也可以看到:
[ 2821.618046] here is pcf8563_get_datetime ,next func is i2c_transfer!
[ 2821.618058] octeon_i2c_xfer: num = 2
[ 2821.618067] octeon_i2c_xfer:msgs[0].addr = 51, msgs[0].flags = 0, msgs[0].len = 1
[ 2821.618079] octeon_i2c_xfer:msgs[0].buf[0] = 0
[ 2821.618090] octeon_i2c_xfer:msgs[1].addr = 51, msgs[1].flags = 1, msgs[1].len = 13
[ 2821.618102] octeon_i2c_xfer:msgs[1].buf[1] = 0
[ 2821.618112] octeon_i2c_write:data[0](msgs->buf[]) = 0, target(addr) = 51, length = 1, phase = 0
[ 2821.618240] octeon_i2c_write: data[0] = 0
[ 2821.618348] octeon_i2c_read:data[0](msgs->buf[0]) = 0,target(addr) = 51, length = 13,phase = 1
[ 2821.618578] octeon_i2c_read: data[0] = 8
[ 2821.618685] octeon_i2c_read: data[1] = 0
[ 2821.618792] octeon_i2c_read: data[2] = 8
[ 2821.619329] octeon_i2c_read: data[7] = 7
[ 2821.619440] octeon_i2c_read: data[8] = 12
[ 2821.619547] octeon_i2c_read: data[9] = a0
[ 2821.619655] octeon_i2c_read: data[10] = 84
[ 2821.619763] octeon_i2c_read: data[11] = b2
[ 2821.619871] octeon_i2c_read: data[12] = b5
[ 2821.619885] here come back pcf8563_get_datetime ,the received data : secs=8, mins=4, hours=15,mday=6, mon=6, year=112,wday=5
宗上,可以定下結論:
在執行關於時間的讀操作時 ,使用了 pcf8563_get_datetime --> octeon_i2c_read
執行關於時間啊的寫操作是,使用了pcf8563_set_datetime ---> octeon_i2c_simple_write
在octeon_i2c_xfer() 中 進入不同讀寫函數的條件是就利用 msg中的 flags,len.
我們仿照pcf8563_get_datetime()中的代碼:
struct i2c_msg msgs[] = {
{ client->addr, 0, 1, buf }, /* setup read ptr */
{ client->addr, I2C_M_RD, 13, buf }, /* read status + date */
};
寫設計一個我們自定義的數據結構,這個數據結構爲struct i2c_rdwr_ioctl_data, 代碼如下:
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
struct i2c_msg代碼如下:
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
我們定義一個i2c_read_data(),參考pcf8563_get_datetime,核心內容如下:
{
struct i2c_rdwr_ioctl_data *data;
data->nmsgs = 2;
data->msgs[0].addr = addr;
data->msgs[0].flags = 0;
data->msgs[0].len = 1;
data->msgs[0].buf[0] = offset;
data->msgs[1].addr = addr;
data->msgs[1].flags = I2C_M_RD;
data->msgs[1].len = 13;
data->msgs[1].buf[0] = 0;
ioctl(fd, I2C_RDWR, (unsigned long)data) ;
}
pcf8563_set_datetime中使用的i2c_master_send(){
..
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
ret = i2c_transfer(adap, &msg, 1);
..
}
參考以上,我們定義一個i2c_write_data(),核心代碼如下:
{
struct i2c_rdwr_ioctl_data *data;
data->nmsgs = 1;
data->msgs[0].addr = addr;
data->msgs[0].flags = 0;
data->msgs[0].len = 2;
data->msgs[0].buf[0] = offset;
data->msgs[0].buf[1] = val;
ioctl(fd, I2C_RDWR, (unsigned long)data) ;
}
通過i2cctl函數將我們包裝好的數據結構發送出去。
******************************************************************************************
運行結果如下:
root@(none):/han# ./i2c-test /dev/i2c-20
Hello i2c-test![ 5536.661954] i2c-mux.c: msgs = 51 , num = 2
enter i2c_open OK!
i2c.c: i2c_open: fd = 3
enter __i2c_set [ 5536.669209] i2c-mux.c: msgs = 51 , num = 1
OK!
__i2c_set done!
here is i2c_read_data function in main.c
[ 5536.677154] i2c-mux.c: msgs = 51 , num = 2
__i2c_send: data->msgs[0].addr = 51,data->msgs[0].buf[0] = 4
i2c_read_data success, val = 15
here is i2c_write_data function in main.c
the data to write val = 8
__i2c_send: data->msgs[0].addr = 51,data->msgs[0].buf[0] = 4
i2c_write_data success,val1 = 8
here is i2c_read_data function in main.c
__i2c_send: data->msgs[0].addr = 51,data->msgs[0].buf[0] = 4
i2c_read_data success, val = 8
root@(none):/han# date
Fri Jul 6 15:49:25 UTC 2012
root@(none):/han# hwclock -r
Fri Jul 6 08:49:28 2012 -0.628861 seconds
成功了!!!
i2c-test 成功地讀寫到了地址爲0x51, 偏移地址爲0x04的 寄存器內容!!!