I2C子系統框架

来源:https://www.cnblogs.com/laoyaodada/archive/2018/02/01/8399537.html
-Advertisement-
Play Games

1 I2C子系統框架 Linux I2C子系統分成三部分:I2C核心層、I2C匯流排驅動和I2C設備驅動。 (1)I2C核心層 I2C核心提供了I2C匯流排驅動和設備驅動的註冊、註銷方法,I2C通信方法(即algorithm)上層的與具體適配器無關的代碼以及探測設備、檢測設備地址的上層代碼等。核心層的代 ...


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.h
26        中定義。包括一個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 };

1BSP板級文件的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_typematch()函數i2c_device_match()中,會調用i2c_match_id()函數匹配板級文件中定義的IDi2c_driver所支持的ID表。

3  I2C子系統介面

1i2c_add_adapter()

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

函數原形

int i2c_add_adapter(struct i2c_adapter *adapter);

函數參數

adaperi2c_adapter結構指針

2i2c_del_adaper()

i2c_del_adapter()向系統註銷一個i2c_adapter對象。

函數原形

int i2c_del_adapter(struct i2c_adapter *adapter);

函數參數

adaperi2c_adapter結構指針

3i2c_add_numbered_adapter()

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

函數原形

int i2c_add_numbered_adapter(struct i2c_adapter *adapter);

函數參數

adaperi2c_adapter結構指針

4i2c_add_driver()

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

函數原形

int i2c_add_driver(struct i2c_driver *driver);

函數參數

driveri2c_driver結構指針

5i2c_del_driver()

i2c_del_driver()向系統註銷一個i2c_driver對象。

函數原形

int i2c_del_driver(struct i2c_driver *driver);

函數參數

driveri2c_driver結構指針

6i2c_master_send()

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

函數原形

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

函數參數

clienti2c_client結構指針

buf:存放發送數據的緩衝區

count:發送數據的大小

7i2c_master_recv()

i2c_master_recv()函數用來主機獲取從機的數據。在它們收發數據時,必須先設置設備節點。

函數原形

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

函數參數

clienti2c_client結構指針

buf:存放接收數據的緩衝區

count:接收數據的大小

8i2c_transfer()

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

函數原形

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

函數參數

adapterI2C適配器的結構指針

msgsi2c_msg結構,存放發送和接收的數據

nummsg的數量

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 英文原文: https://www.linuxatemyram.com/ 作者: "Vidar Holen" 譯者: "thinkam" 發生了什麼? Linux正借用你未使用的記憶體來做磁碟緩存。這使你的電腦看起來可用記憶體很少,但事實不是這樣!一切都很正常! 為什麼這麼做? 磁碟緩存使你的系統運行 ...
  • centos7與之前的版本都不一樣,修改主機名在/ect/hostname 和/ect/hosts 這兩個文件控制 首先修改/ect/hostname vi /ect/hostname 打開之後的內容是: localhost.localdomain 把它修改成你想要的名字就可以,比如: niukou ...
  • 1.echo 輸出字元,或者輸出變數的值。 2.date %Y:年; %m:月; %d:日; %H:小時,24小時制; %I:小時,12小時制; %M:分鐘; %S:秒; %F:年-月-日; %T:時-分-秒; -s:設置日期和時間; 3.reboot 重啟電腦。 4.poweroff 關機。 5 ...
  • 1. Oracle官網下載JDK linux安裝包,這裡使用的是【jdk-8u11-linux-i586.tar.gz】 註:下載前先用命令查看系統位數再下載對應位數的JDK【[root@localhost /]# getconf LONG_BIT】 2. 在 usr 文件夾下新增 java 文件夾 ...
  • 這裡介紹Linux下兩種安裝mysql的方式:yum安裝和源碼編譯安裝。 1. yum安裝 (1)首先查看centos自帶的mysql是否被安裝: (2)下載MySQL官網的yum倉庫:https://dev.mysql.com/downloads/repo/yum/, (3)使用mysql yum ...
  • shell 什麼是shell bash shell bash的配置文件 shell 登錄兩種方式 bash中的退出時的任務 ...
  • 編譯安裝 程式包編譯 編譯安裝 ...
  • I2C設備驅動要使用i2c_driver和i2c_client數據結構並填充i2c_driver中的成員函數。i2c_client一般被包含在設備的私有信息結構體xxx_data中,而i2c_driver則適合被定義為全局變數並初始化。下麵提供i2c_driver的初始化模版: 1 Linux I2 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...