I2C子系統架構,i2c子系統

來源:互聯網
上載者:User

I2C子系統架構,i2c子系統

1  I2C子系統架構

Linux I2C子系統分成三部分:I2C核心層、I2C匯流排驅動和I2C裝置驅動。

 

(1)I2C核心層

I2C核心提供了I2C匯流排驅動和裝置驅動的註冊、登出方法,I2C通訊方法(即algorithm)上層的與具體適配器無關的代碼以及探測裝置、檢測裝置地址的上層代碼等。核心層的代碼在drivers/i2c/i2c-core.c中實現。

(2)I2C匯流排驅動

I2C匯流排驅動是對I2C硬體適配器端的實現,適配器可由CPU控制。I2C匯流排驅動主要包含了I2C適配器資料結構i2c_adapter、I2C適配器的Algorithm資料結構i2c_algorithm和控制I2C適配器產生通訊訊號的函數。

經由I2C匯流排驅動的代碼,我們可以控制I2C適配器以主控產生開始位、停止位、讀寫周期,以及以從裝置方式被讀寫、產生ACK等。

Linux在drivers/i2c/下建立了busses目錄用於存放各種已實現的I2C匯流排驅動,其中包括samsung S3C系列晶片的I2C匯流排驅動實現i2c-s3c2410.c。

(3)I2C裝置驅動

I2C裝置驅動是對I2C硬體裝置端的實現,裝置一般掛接在受CPU控制的I2C控制器上,通過I2C適配器與CPU交換資料。I2C裝置驅動主要包含資料結構i2c_driver和i2c_client,我們需要根據具體裝置實現其中的成員函數。

【溫馨提示】i2c-dev.c實現了I2C適配器裝置檔案的功能,每一個I2C適配器都被分配一個裝置。通過適配器訪問裝置時的主裝置號都為89,次裝置號為0~255。i2c-dev.c並不是針對特定的裝置而設計的,只是提供了通用的read()、write()和ioctl()等介面,應用程式層可以借用這些介面訪問掛接在適配器上的I2C裝置的儲存空間或者寄存器,並控制I2C裝置的工作方式。

2  I2C子系統資料結構

(1)i2c_adapter結構

I2C子系統用struct i2c_adapter來描述一個物理的適配器,適配器的具體通訊方法由struct i2c_adapter的一個類型為struct i2c_algorithm的成員來描述。定義在include/linux/i2c.h。

 1 struct i2c_adapter { 2     struct module *owner; 3     unsigned int id;    // 適配器ID,這個在適配器驅動中不常用 4     unsigned int class;    // 適配器的類類型 5     const struct i2c_algorithm *algo;    // 指向通訊方法資料的指標 6     void *algo_data; 7  8     /* data fields that are valid for all devices   */ 9     u8 level;           /* nesting level for lockdep */10     struct mutex bus_lock;11 12     int timeout;    // 傳輸逾時時間13     int retries;    // 重試次數14     struct device dev;    // 內嵌的device結構15 16     int nr;    // 匯流排編號(也是適配器編號),同時對應裝置節點/dev/i2c-x(x=0,1,2...)來訪問17     char name[48];    // 適配器名稱,這個名稱可以通過/sys/bus/i2c/devices/i2c-x/name(x=0,1,2...)來訪問18     struct completion dev_released;19 };

(2)i2c_algorithm結構

struct i2c_adapter中用於描述通訊方法的成員i2c_algorithm定義如下,該成員及其核心方法的實現是開發I2C匯流排驅動的核心任務。此結構體定義在include/linux/i2c.h。

 1 struct i2c_algorithm { 2     /* 指向具體的I2C傳輸函數的指標,對應的傳輸一般會通過直接操作適配器硬體來發起。這個 3        函數的傳入參數分別是使用該傳輸方法的適配器adap,待傳輸的訊息msgs和訊息數量num。 */ 4     int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, 5                int num); 6     /* 指向具體的SMBus傳輸函數的指標。SMBus協議大部分基於I2C匯流排規範,並在基礎上做了擴充,在訪問 7        時序上由一些差異。如果這個指標置NULL,基於SMBus協議的通訊將通過I2C傳輸來類比 */ 8     int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, 9                unsigned short flags, char read_write,10                u8 command, int size, union i2c_smbus_data *data);11 12     /* 指向返回適配器支援功能的函數的指標,這些功能定義在incude/linux/i2c.h中以I2C_FUNC開頭13        的宏表示,常用的有I2C_FUNC_I2C、I2C_FUNC_SMBUS_EMUL、I2C_FUNC_PROTOCOL_MANGLING */14     u32 (*functionality) (struct i2c_adapter *);15 };

(3)i2c_msg結構

i2c_msg結構用來描述一個用於傳輸I2C的訊息。此結構體定義在include/linux/i2c.h。

 1 struct i2c_msg { 2     __u16 addr;    // 從機地址 3     __u16 flags;    // 反映訊息特定的標誌,當I2C_M_RD位被設定時,表示訊息方向是主機從從機去讀,如果 4                     // 不設定該位(0),則訊息方向是主機向從機寫入。I2C_M_RD可以被所有適配器處理。I2C_M_NOSTART等 5                     // 幾個訊息則需要適配器支援I2C_FUNC_PROTOCOL_MANGLING功能。 6 #define I2C_M_TEN       0x0010  /* this is a ten bit chip address */ 7 #define I2C_M_RD        0x0001  /* read data, from slave to master */ 8 #define I2C_M_NOSTART       0x4000  /* if I2C_FUNC_NOSTART */ 9 #define I2C_M_REV_DIR_ADDR  0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */10 #define I2C_M_IGNORE_NAK    0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */11 #define I2C_M_NO_RD_ACK     0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */12 #define I2C_M_RECV_LEN      0x0400  /* length will be first received byte */13     __u16 len;    // 訊息資料長度,單位是位元組14     __u8 *buf;    // 指向存放訊息資料緩衝區15 };

一個i2c_msg對象代表一個底層I2C傳輸單元。在驅動程式中,i2c_msg對象通過函數i2c_transfer()進行處理,而i2c_transfer()則調用適配器通訊方法的master_xfer()來傳輸訊息資料。

(4)i2c_driver結構

i2c_driver結構定義在include/linux/i2c.h中。它對應於一套驅動方法,其主要成員函數是probe()、remove()、suspend()、resume()等,另外,struct i2c_device_id形式的id_table是該驅動所支援的I2C裝置的ID表。

 1 struct i2c_driver { 2     unsigned int class; 3  4     /* 分別是依附和脫離i2c_adapter的函數指標,驅動註冊函數會遍曆適配器裝置類i2c_adapter_class中的所有裝置 5        並調用該驅動的attach_adapter方法進行依附。相應的,在添加i2c_adapter時,適配器註冊函數會遍曆匯流排i2c_bus_type 6        上所有的驅動,如果驅動定義了attach_adapter方法,他也將得到調用 */ 7     int (*attach_adapter)(struct i2c_adapter *) __deprecated; 8     int (*detach_adapter)(struct i2c_adapter *) __deprecated; 9 10     /* 在裝置驅動中,當匯流排i2c_bus_type上的裝置與裝置驅動匹配後被調用。 */11     int (*probe)(struct i2c_client *, const struct i2c_device_id *);12     int (*remove)(struct i2c_client *);13 14     /* driver model interfaces that don't relate to enumeration  */15     void (*shutdown)(struct i2c_client *);16     int (*suspend)(struct i2c_client *, pm_message_t mesg);17     int (*resume)(struct i2c_client *);18 19     void (*alert)(struct i2c_client *, unsigned int data);20 21     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);22 23     /* 內嵌的driver結構。在註冊i2c_driver對象時,i2c_driver->driver的匯流排類型被指定為i2c_bus_type */24     struct device_driver driver;25     /* 存放該驅動支援的裝置列表。i2c_device id結構在include/linux/mod_devicetable.h26        中定義。包括一個char name[I2C_NAME_SIZE]和一個kernel_ulong_t driver_data的成員。27        name用於匹配裝置和驅動,i2c_bus_type的match()方法會遍曆驅動id_table中的每一項,通過28        比較裝置名稱和這個name成員,找到與裝置匹配的驅動。*/29     const struct i2c_device_id *id_table;30 31     int (*detect)(struct i2c_client *, struct i2c_board_info *);32     const unsigned short *address_list;33     struct list_head clients;34 };

(5)i2c_client結構

i2c_client結構定義在inlcude/linux/i2c.h中。i2c_client對應於真實的物理裝置,每個I2C裝置都需要一個i2c_client描述。i2c_client的資訊通常在BSP的板級檔案中通過i2c_board_info填充或者裝置樹填充。

 1 struct i2c_client { 2     unsigned short flags;    // 兩個主要的標識是:I2C_CLIENT_TEN表示裝置使用10-bit地址; 3                              // I2C_CLIENT_PEC表示裝置使用SMBus包錯誤檢查 4     unsigned short addr;    // 裝置地址,7-bit地址格式下,地址存放該成員的低7位 5     char name[I2C_NAME_SIZE];    // 裝置名稱 6     struct i2c_adapter *adapter;    // 依附的適配器 7     struct i2c_driver *driver;    // 裝置綁定的驅動 8     struct device dev;    // 內嵌device結構。 9     int irq;    10     struct list_head detected;11 };

(1)BSP板級檔案的i2c_board_info填充:

I2C裝置ID為“ad7142_joystick”、地址為0x2C、中斷號為IRQ_PF5。

1 static struct i2c_board_info __initdata xxx_i2c_board_info[] = {2     {3         I2C_BOARD_INFO("ad7142_joystick", 0x2C);4         .irq = IRQ_PF5.5     },6     ...7 }

(2)裝置樹填充:

I2C裝置ID為“invensense,mpu6050”、地址為0x68、中斷號為3。

i2c@138B0000 {    samsung,i2c-sda-delay = <100>;    samsung,i2c-max-bus-freq = <20000>;    pinctrl-0 = <&i2c5_bus>;    pinctrl-names = "default";    status = "okay";        mpu6050-3-axis@68 {        compatible = "invensense,mpu6050";        reg = <0x68>;        interrupt-parent = <&gpx3>;        interrupts = <3 2>;    };};

在I2C匯流排驅動i2c_bus_type的match()函數i2c_device_match()中,會調用i2c_match_id()函數匹配板級檔案中定義的ID和i2c_driver所支援的ID表。

3  I2C子系統介面

(1)i2c_add_adapter()

i2c_add_adapter()向系統註冊一個i2c_adapter對象,不必指定其nr成員,匯流排編號自動在i2c_add_adapter中分配並賦值給nr。

函數原形

int i2c_add_adapter(struct i2c_adapter *adapter);

函數參數

adaper:i2c_adapter結構指標

(2)i2c_del_adaper()

i2c_del_adapter()向系統登出一個i2c_adapter對象。

函數原形

int i2c_del_adapter(struct i2c_adapter *adapter);

函數參數

adaper:i2c_adapter結構指標

(3)i2c_add_numbered_adapter()

i2c_add_numbered_adapter()向系統註冊一個i2c_adapter結構。此函數必須靜態指定一個匯流排編號給nr成員。

函數原形

int i2c_add_numbered_adapter(struct i2c_adapter *adapter);

函數參數

adaper:i2c_adapter結構指標

(4)i2c_add_driver()

i2c_add_driver()向系統添加一個i2c_driver對象。

函數原形

int i2c_add_driver(struct i2c_driver *driver);

函數參數

driver:i2c_driver結構指標

(5)i2c_del_driver()

i2c_del_driver()向系統登出一個i2c_driver對象。

函數原形

int i2c_del_driver(struct i2c_driver *driver);

函數參數

driver:i2c_driver結構指標

(6)i2c_master_send()

i2c_master_send()函數用來主機向i2c_client裝置對象發送資料。在使用它們收發資料時,必須先設定裝置地址。

函數原形

int i2c_master_send(const struct i2c_client *client, const char *buf, int count);

函數參數

client:i2c_client結構指標

buf:存放發送資料的緩衝區

count:發送資料的大小

(7)i2c_master_recv()

i2c_master_recv()函數用來主機擷取從機的資料。在它們收發資料時,必須先設定裝置節點。

函數原形

int i2c_master_recv(const struct i2c_client *client, const char *buf, int count);

函數參數

client:i2c_client結構指標

buf:存放接收資料的緩衝區

count:接收資料的大小

(8)i2c_transfer()

i2c_transfer()函數用於執行單個或組合的MSG訊息。

函數原形

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

函數參數

adapter:I2C適配器的結構指標

msgs:i2c_msg結構,存放發送和接收的資料

num:msg的數量

【溫馨提示】i2c_transfer()一次可以傳輸多個i2c_msg(考慮到很多外設的讀寫波形比較複雜)。而對於時序比較簡單的外設,i2c_master_send()函數和i2c_master_recv()函數內部調用i2c_transfer()函數分別完成一條寫訊息和一條讀訊息。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.