Linux I2C Driver - 使用str8131(5)static int str8131_xfer(struct i2c_adapter *adapter, struct i2c_msg msgs[], int num){    struct i2c_msg *i2c;    u8  i;     if (num != 1 && num != 2) // 我們預期的動作,其數目只會是 1 或 2個 i2c_msg    {        TRACE("An unexpected situation, num=%d\n", num);        return -EIO;    }   if(clock != current_clock) str8131_i2c_init();    for (i=0; i    {        if (msgs[i].flags & I2C_M_TEN) // 我們這裡並不支援 10 bit chip address        {            TRACE("Presently the driver does not handle extended addressing\n");           return -EIO;        }        if (msgs[i].len == 0) return 0; // 長度為0就不用做了    }    i2c = &msgs[0]; // 至少要有一個 i2c_msg    if (num == 2) // 通常 2的話,就是指 W_R(Write_Read)    {        // In general, the num=2 send W_R sequence message        if (i2c->flags != 0) // 0:write ,W_R第一個i2c_msg的flag必須要為0來表示為 土地買賣write        {            TRACE("An unexpected situation, i2c[0]->flags != write\n");            return -EIO;        }        i2c = &msgs[1]; // ,W_R第二個i2c_msg的flag必須要為I2C_M_RD來表示為 read        if ((i2c->flags & I2C_M_RD) == 0) // The msg[1] should be read        {            TRACE("An unexpected situation, i2c[1]->flags != read\n");            return -EIO;        }        if (i2c_write_read(msgs) != 0) // 做 write and read的動作        {            TRACE("i2c_write_read failed\n");            return -EIO;        }    }    else // 1的話,可能是讀或寫    {        if (i2c->flags & I2C_M_RD) // read        {            if (i2c_read(msgs) != 0)    房地產        {                TRACE("i2c_read failed\n");                return -EIO;            }        }        else // write        {            if (i2c_write(msgs) != 0)            {                TRACE("i2c_write failed\n");                return -EIO;            }        }    }    // Return the number of messages processed, or the error code.    return num;接下來我們看i2c_read 、 i2c_write、i2c_write_read三個函式,這裡要先注意的是,儘量不要改變傳進來的 i2c_msg的內容,可能因為它是指標,和kernel實做時會用到,這裡修改它可能會造成一些非預期的結果。把它當作 const,只讀取就好了。當初手賤的去改變傳進來的 msgs的len來當做迴圈的計數,就發現怎麼出現一些奇怪的結果><我們在傳輸時都會呼叫 I2C_Command來做傳輸,這時會把 i2c 的 slave address 左移1位元(i2c->addr << 1),這是因為 i2c的規定,最右邊設計裝潢的那個bit 是用來表示讀或寫。所以當 user-space 傳進來的 slave addr為0x50時,這裡會變成 0xa0static int i2c_read(struct i2c_msg msgs[]){    u32 read_data = 0;    u16 i, read_len, read_i2c_len;    struct i2c_msg *i2c;    i = 0;    i2c = &msgs[0];    read_i2c_len = i2c->len;    TRACE("read_i2c_len=%d\n", read_i2c_len);    while (read_i2c_len)    {        // To count maximum length of read at a time        if (read_i2c_len > I2C_MAX_DATA_LEN)        {            read_len = I2C_MAX_DATA_LEN;            read_i2c_len -= I2C_MAX_DATA_LEN;        }        else        {            read_len = read_i2c_len;            read_i2c_len = 0;        }        if (I2C_Command(                I2C_READ_ONLY_CMD, (i2c->addr<<1), 0, 0, read_len-1, &read_data) != 0)        禮服{            TRACE("read_only_command failed\n");            return -EIO;        }        TRACE("i=%d, read_len=%d, read_data=0x%x\n", i, read_len, read_data);        memcpy(i2c->buf+i, &read_data, read_len);        i += I2C_MAX_DATA_LEN;    }    return 0;}i2c_read 就是依傳進來的 i2c->len,來判斷要讀取多少位元,這裡的I2C_MAX_DATA_LEN為4,這是cpu暫存器上的限制,所以假設傳進來的 len 為10,那我們就讀 4、4、2, 把資料拷貝到msgs->buf裡。我們呼叫I2C_Command來傳輸資料。static int i2c_write(struct i2c_msg msgs[]){    const u8 addr_len = 2;    u8 first_addr, second_addr;    u16 i, index, write_len, write_i2c_data_len;    u32 write_data=0;    struct i2c_msg *i2c;    i = 1;    i2c = &msgs[0];    index = i2c->buf[0];    write_i2c_data_len = i2c->len - 1; // Subtract legnth of index from i2c->len    if (write_i2c_data_len == 0)    // only write index    {        first_addr  = (index>>8&0xff);    買屋    second_addr = (index>>0&0xff);        write_data |= (first_addr<<0) | (second_addr<<8);        if(I2C_Command(                I2C_WRITE_ONLY_CMD , (i2c->addr<<1), I2C_DATA_LEN_2_BYTE, write_data, 0 , NULL) != 0)        {            TRACE("write_only_command failed\n");            return -EIO;        }        TRACE("Write index only, index=%d\n", index);    }    else    {        while (write_i2c_data_len)        {            write_data = 0;            first_addr  = (index>>8&0xff);            second_addr = (index>>0&0xff);            write_data |= (first_addr<<0) | (second_addr<<8);            // To count maximum length of write data at a time        21世紀房屋仲介    if (write_i2c_data_len > I2C_MAX_WRITE_DATA_LEN)            {                write_len = I2C_MAX_WRITE_DATA_LEN;                write_i2c_data_len -= I2C_MAX_WRITE_DATA_LEN;            }            else            {                write_len = write_i2c_data_len;                write_i2c_data_len = 0;            }            write_data |= ((u32)i2c->buf[i] << 16);            if (write_len > 1) write_data |= ((u32)i2c->buf[i+1] << 24);            write_len += addr_len;            TRACE("write:: i=%d, write_data=0x%x, write_len=%d, index=%d, i2c->addr=0x%x, i2c->len=%d\n"                    , i, write_data, write_len, index, i2c->addr, 有巢氏房屋i2c->len);            if(I2C_Command(                    I2C_WRITE_ONLY_CMD , (i2c->addr<<1)                        , write_len-1, write_data                        , 0, NULL) != 0)            {                TRACE("write_only_command failed\n");                return -EIO;            }            i += I2C_MAX_WRITE_DATA_LEN;            index += I2C_MAX_WRITE_DATA_LEN; // Move index to next address        }    }    return 0;}i2c_write 和 i2c_read類似,只是 write時要寫入 index和資料,i2c_read時並沒有寫入 index。先判斷傳進來的 len 的大小,如果是 1 的話,那就代表只有傳 index,因為如果沒有含index,是寫不進去的。所以第一個byte都把它認為 index。如果不是1的話,我們就使用 loop來寫入資料,每次寫入都會帶 1 個 byte 的 index,因為要移到新的位置,而最大的寫入為4 東森房屋bytes,但寫入時的index要轉換為 2 bytes(實際上index 的最大可為2 bytes,但那是支援I2C_M_TEN時才會是 2 bytes,我們這裡不支援,只支援 7 bit模式,所以為1 byte),可算出 (4) - (2 bytes的index) = (2 bytes的資料)。一次最大可帶 2 bytes 的資料。自已有試過先寫入一次 index,然後寫入不帶 index(4 bytes)的資料,可惜沒有成功,index不會自已移動。如果可以的話這樣的方法會比較有效率。因為除了第一次要 2 bytes的資料,之後每次可以寫入 4 bytes的資料。static int i2c_write_read(struct i2c_msg msgs[]){    u32 read_data=0, write_data=0;    u16 i, index, read_len, read_i2c_len;    u8 first_addr, second_addr;    struct i2c_msg *i2c;    i = 0;    index = msgs[0].buf[0];    i2c = &msgs[1];    read_i2c_len = i2c->len;    while (read_i2c_len)    {        first_addr  = (index>>8 & 0xff);        second_addr = (index>>0 & 0xff);        write_data |= (first_addr<<0) | (second_addr<<8);        // To count maximum length of read at a time        if (read_i2c_len > I2C_MAX_DATA_LEN)        {            read_len = I2C_MAX_DATA_LEN;    保濕面膜        read_i2c_len -= I2C_MAX_DATA_LEN;        }        else        {            read_len = read_i2c_len;            read_i2c_len = 0;        }        if(I2C_Command(                I2C_WRITE_READ_CMD , (i2c->addr<<1)                , I2C_DATA_LEN_2_BYTE, write_data                , read_len-1, &read_data) != 0)        {            TRACE("write_read_command failed\n");            return -EIO;        }        memcpy(i2c->buf+i, &read_data, read_len);        i += I2C_MAX_DATA_LEN;        index += I2C_MAX_DATA_LEN; // Move index to next address    }    return 0;}前面 wirte 和 read 的合體,先寫入 index ,再做讀取的動作,因為光做讀取,是讀不到資料的。


.msgcontent .wsharing ul li { 信用卡代償text-indent: 0; }



分享

Facebook
Plurk
YAHOO!

arrow
arrow
    全站熱搜

    ob50obilsr 發表在 痞客邦 留言(0) 人氣()