linux i2c驅動筆記

來源:互聯網
上載者:User

1. i2c-dev interface

 

I2C dev-interface

通常,i2c裝置由某個核心驅動控制。但是在使用者空間,也可以訪問某個I2C裝置:你需要

載入i2c-dev模組。

每個被註冊的i2c適配器(控制器)會獲得一個數字型大小,從0開始。你可以檢查

/sys/class/i2c-dev,來查看適配器對應哪個數字型大小。你也可以通過命令"i2cdetect -l"獲

取你的當前系統的所有I2c適配器的列表。i2cdetct是i2c-tool包中的一個工具。

i2c裝置檔案是字元裝置,主裝置號是89,次裝置號的分配如上所述。裝置檔案名稱通常被

規定為"i2c-%d"(i2c-0, i2c-1, ...,i2c-10, ...)i2c裝置檔案是字元裝置,主裝置號是

89,次裝置號的分配如上所述。裝置檔案名稱通常被規定為"i2c-%d"(i2c-0, i2c-1,

...,i2c-10, ...).所有256個次裝置號都保留給i2c使用。

C example

=========

假定你要在你的C應用程式中訪問i2c適配器。第一件事情就是包含標頭檔"#include

<linux/i2c-dev.h>"。注意,存在兩個"i2c-dev.h"檔案: 一個屬於Linux kernel,用於

核心驅動中;一個由i2c-tools發布,用於使用者程式。顯然,這裡需要使用第二個

i2c-dev.h檔案。

現在,你需要確定訪問哪個適配器。你需要通過查看/sys/class/i2c-dev/或者運行

"i2cdetect -l"確定。適配器號時常是動態分配的,你無法預先假定某個值。因為它們甚

至會在系統重啟後變為不同的值。

下一步,開啟裝置檔案,如下:

    int file;

    int adapter_nr = 2; /*probably dynamically determined */

    char filename[20];

    snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);

    file = open(filename, O_RDWR);

    if (file < 0) {

        /* ERROR HANDLING; you can check errno to see what went wrong */

        exit(1);

    }

當你開啟裝置後,你必須明確說明你相與哪個裝置地址進行通訊:

    int addr = 0x40;

    if (ioctl(file, I2C_SLAVE, addr) < 0) {

        /* ERROR HANDLING; you can check errno to see what went wrong */

        exit(1);

    }

Well, 你現在準備好與I2C裝置通訊了。你現在可以使用SMBus命令集或者無格式I2C

(plain I2C)與你的裝置進行通訊。如果裝置支援SMB協議,則SMBus命令集優先選擇。

代碼如下:

    __u8 register = 0x10; /* Device register to access */

    __s32 res;

    char buf[10];

    /* Using SMBus commands */

    res = i2c_smbus_read_word_data(file, register);

    if (res < 0) {

        /* ERROR HANDLING; you can check errno to see what went wrong */

    } else {

        /* res contains the read word */

    }

    /* Using I2C Write, equivalent of

       i2c_smbus_write_word_data(file, register, 0x6543) */

    buf[0] = reister;

    buf[1] = 0x43;

    buf[2] = 0x65;

    if (write(file ,buf, 3) != 3) {

        /* ERROR HANDLING: i2c transaction failed */

    }

    /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */

    if (read(file, buf, 1) != 1) {

        /* ERROR HANDLING: i2c transaction failed */

    } else {

        /* buf[0] contains the read byte */

    }

注意,僅有I2C和SMBus協議的一部分子集功能可以通過read()和write()的調用完成。尤

其,對於組合型的傳輸(mixing read and write messages in the same transaction)不

被read()/write()支援。基於這個原因,read()和write()這兩個介面幾乎不被使用者空間

程式使用。

IMPORTANT: because of the use of inline functions, you *have* to use '-O" or

some variation when you compile your program!

Full interface description

==========================

IOCTLs定義如下:

ioctl(file ,I2C_SLAVE, long addr)

Change slave address. The address is passed in the 7 lower bits of the

argument (except for 10 bit addresses, passed in the 10 lower bits in this

case)

ioctl(file, I2C_TENBIT, long select)

Selects ten bit addressed if select not equals 0, selects normal 7 bit

addresses if select equals 0. Default 0. This request is only valid if the

adapter has I2C_FUNC_10BIT_ADDR.

ioctl(file, I2C_PEC, long select)

Selects SMBus PEC (packet error checking) generation and verification if

select not equals 0, disables if select equals 0. Default 0.

Used only for SMBus transactions. This request only has an effect if the

adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just doesn't have

any effect.

ioctl(file, I2C_FUNCS, unsigned long *funcs)

Gets the adapter functionality and puts it in *funcs.

ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)

Do combined read/write transaction without stop in between. Only valid if the

adatpter has I2C_FUNC_I2C. The argument is a pointer to a

struct i2c_rdwr_ioctl_data {

    struct i2c_msg *msgs;    /* ptr to array of simple messages */

    int nmsgs;        /* number of messages to exchanges */

}

msgs[]包含指向data buffer的指標。此函數調用會根據每個message中的I2C_M_RD flag

的設定向buffer寫或者讀資料。在每個message裡,slave address和是否使用

ten-bit-address必須設定。

ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)

Not meant to be called directly; instead, use the access functions below.

你可以通過使用read(2)和write(2)調用來進行無格式i2c傳輸。在訪問裝置前通過ioctl

I2C_SLAVE來設定地址。

你可以使用SMBus級傳輸(see documentation file smbus-protocol for details),通過

如下函數調用:

    __s32 i2c_smbus_write_quick(int file, __u8 value);

    __s32 i2c_smbus_read_byte(int file);

    __s32 i2c_smbus_write_byte(int file, __u8 value);

    __s32 i2c_smbus_read_byte_data(int file, __u8 command);

    __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);

    __s32 i2c_smbus_read_word_data(int file, __u8 command);

    __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);

    __s32 i2c_smbus_process_call(int file, __u8 comand, __u16 value);

    __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);

    __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,

                                    __u8 *values);

 

所有上述傳輸失敗時返回-1;你可以讀取errno來檢查具體錯誤資訊。'write'傳輸成功後

返回0;'read'傳輸成功後返回讀取的值。但是read_block例外,他返回讀取的位元組數,

block buffer長度不超過32位元組。

The above functions are all inline functions, that resolve to calls to the

i2c_smbus_access function, that on its turn calls a specific ioctl with the

data in a specific format. Read the source code if you want to know what

happenss behind the screens.

Implementation details

======================

下面是當你使用i2c的/dev介面時核心的內部處理:

1* 你的程式開啟/dev/i2c-N並調用了ioctl()

2* open()和ioctl()調用會被i2c-dev核心驅動處理:參考i2c-dev.c的相關函數

(i2cdev_ioctl(), i2cdev_open() ...)。你可以認為i2c-dev是由使用者程式訪問的通用

i2c chip driver。

3* 一些ioctl的命令是針對管理工作的,可以被i2c-dev直接處理。例如I2C_SLAVE(設定你

想訪問的裝置地址)和I2C_PEC(使能或禁止SMBus錯誤檢查)。

4* 其他ioctl的命令會被i2c-dev轉化為核心驅動裡的函數調用。例如I2C_FUNCS,通過調

用i2c.h:2c_get_functionality()來請求I2C適配器所支援的功能(functionality);

I2C_SMBUS,通過調用i2c-core.c:i2c_smbus_xfer()來執行SMBus傳輸。

i2c-dev driver負責檢查來自使用者空間的參數的有效性。除了這一點,使用者程式訪問

i2c和核心訪問i2c的函數調用沒什麼區別。這意味著在i2c bus driver裡不必實現任何支

持使用者訪問的代碼。

5* i2c-core.c/i2c-.h中的函數是你的實際i2c bus driver所需要實現的封裝調用常式。每個

適配器都必須聲明一些回呼函數來實現這些標準調用。

i2c.h:i2c_get_functionality()調用i2c_adapter.algo->functionality(),

i2c-core.c:i2c_smbus_xfer()調用i2c_adapter.algo->smbus_xfer() (如果實現了

smbus_xfer()回呼函數),否則

i2c-core.c:i2c_smbus_xfer_emulated()會調用i2c_adapter.algo->master_xfer()。

(註:smbus_xfer()和master_xfer()回呼函數必須至少實現一個)

After your I2C bus driver has processed these request, execution runs up the

call chain, with almost no processing done, except by i2c-dev to package the

returned data, if any, in suitable format for the ioctl.

 

 

 



2. i2c functionality

 

INTRODUCTION
------------

不是所有的I2C或者SMBus適配器實現了I2C規範上的所有功能,因此當訪問I2C適配器時,
並不能完全假定適配器提供了你所需的功能。the client需要有一種檢測適配器是否提供
了所需功能的方法。

FUNCTIONALILTY CONSTANTS
-----------------------

對於不斷更新的I2C適配器功能常量列表,參考<linux/i2c.h>

I2C_FUNC_I2C            無格式i2c-level命令(Pure SMBus適配器不能用這些
                命令)
I2C_FUNC_10BIT_ADDR        處理10-bit地址的擴充
I2C_FUNC_PROTOCOL_MANGLING    熟知的有I2C_M_IGNORE_NAK, I2C_M_REV_DIR_ADDR,
                I2C_M_NOSTART, I2C_MNO_RD_ACK等flags (which modify the I2C protocol)
I2C_FUNC_SMBUS_QUICK        處理SMBus write_quick命令
I2C_FUNC_SMBUS_READ_BYTE    處理SMBus read_byte命令
I2C_FUNC_SMBUS_WRITE_BYTE    處理SMBus write_byte命令
I2C_FUNC_SMBUS_READ_BYTE_DATA    處理SMBus read_byte_data命令
I2C_FUNC_SMBUS_WRITE_BYTE_DATA    處理SMBus write_byte_data命令
I2C_FUNC_SMBUS_READ_WORD_DATA    處理SMBus read_word_data命令
I2C_FUNC_SMBUS_WRITE_WORD_DATA    處理SMBus write_word_data命令
I2C_FUNC_SMBUS_PROC_CALL    處理SMBus process_call命令
I2C_FUNC_SMBUS_READ_BLOCK_DATA    處理SMBus read_block_data命令
I2C_FUNC_SMBUS_WIRTE_BLOCK_DATA    處理SMBus wrtie_block_data命令
I2C_FUNC_SMBUS_READ_I2C_BLOCK    處理SMBus read_i2c_block_data命令
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK    處理SMBus write_i2c_block_data命令

還有一些flags的組合定義如下(為了你的方便):

I2C_FUNC_SMBUS_BYTE        處理SMBus read_byte & write_byte命令
I2C_FUNC_SMBUS_BYTE_DATA    處理SMBus read_byte_data & write_byte_data命令
I2C_FUNC_SMBUS_WORD_DATA    處理SMBus read_word_data & write_word_data命令
I2C_FUNC_SMBUS_BLOCK_DATA    處理SMBus read_block_data & write_block_data命令
I2C_FU7NC_SMBUS_I2C_BLOCK    處理SMBus read_i2c_block_data &
                write_i2c_block_data命令
I2C_FUNC_SMBUS_EMUL        處理所有的能夠被I2C adapter模擬的SMBus命令
                (using transparent emulation layer)

ADAPTER IMPLEMENTATION
----------------------

當你寫一個新的adapter driver時,你必須實現回呼函數'functionality'。典型的實現
如下所示。

一個典型的SMBus-only adapter需要列出它能夠支援的所有SMBus transactions。下面的
例子來自i2c-piix4 driver:

static u32 piix4_func(struct i2c_adapter *adapter)
{
    return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
               I2C_FUNC_SMBUS_BLOCK_DATA;
}

一個典型的full-I2C adapter需要使用如下的functionality函數(來自i2c-pxa driver):

srtatic u32 i2c_pxa_functionality(struct i2c_adapter *adap)
{
    return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}

I2C_FUNC_SMBUS_EMUL包含了所有的SMBus transactions (包括I2C block
transactions), i2c-core可以使用I2C_FUNC_I2C來模擬SMBus所有命令。這個構思是希望
client drivers僅檢查i2c子系統是否支援SMBus命令集,而不用關心是硬體支援還是軟體
模擬。

CLIENT CHECKING
---------------

在一個client嘗試訪問I2C適配器之前,或者在測試配接器是否支援某一裝置之前,應當
首先檢測所需的functionality是否支援。典型的做法如下(from Im75 driver):

static int Im75_detect(...)
{
    (...)
    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                    I2C_FUNC_SMBUS_WORD_DATA))
        goto exit;
    (...)
}

Im75 driver檢測了adapter是否支援SMBus byte data & SMBus word data
transactions。如果不支援,driver將不再在這個adapter上工作,不再繼續執行。如果
檢測成功,則driver知道它可以調用下面的函數:
i2c_smbus_read_byte_data(), i2c_smbus_write_byte_data(),
i2c_smbus_read_word_data(), i2c_smbus_write_word_data().
因此,你使用i2c_check_functionality()檢測的functionality常量,應當與你的
驅動希望調用的函數介面相匹配。

注意上述的檢測並不關心functionalities是否由硬體實現或者軟體模擬。client
drivers不需要關心這個,i2c-core會在i2c adapter driver之上透明地實現SMBus
transactions.

CHECKING THROUGH /DEV
---------------------

如果你需要在使用者空間訪問i2c適配器的話,你需要使用/dev interface。你仍然需要檢
測你需要的functionality是否被支援。這通過I2C_FUNCS ioctl來完成。樣本如下:

int file;
if (file = open("/dev/i2c-0", O_RDWR) < 0) {
    /* Some kind of error handling */
    exit(1);
}
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
    /* Some kind of error handling */
    exit(1);
}
if (!(funcs & I2C_FUNC_SMBUS_QUICK)) {
    /* Oops, the needed functionality (SMBus write_quick function) is not
       available! */
    exit(1);
}
/*Now it is safe to use the SMBus write_quick command */

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.