I2C總線僅僅使用SCL、SDA兩根信號線就實現了設備之間的數據交互,極大地簡化對硬件資源和PCB板布線空間的占用。因此,I2C總線被非常廣泛地應用在EEPROM、實時鐘、小型LCD等設備與CPU的接口中。
Linux定義了系統的I2C驅動體系結構,在Linux系統中,I2C驅動由3部分組成,即I2C核心、I2C總線驅動和I2C設備驅動。這3部分相互協作,形成了非常通用、可適應性很強的I2C框架。
本章第1節將對Linux I2C體系結構進行分析,講明3個組成部分各自的功能及相互聯系。
第2節將對Linux I2C核心進行分析,解釋i2c-core.c文件的功能和主要函數的實現。
第3、4節將分別詳細介紹I2C總線驅動和I2C設備驅動的編寫方法,給出可供參考的設計模板。
第5、6節將以第3、4節給出的設計模板為基礎,講解S3C2410 ARM處理器I2C總線驅動及掛接在上的SAA7113H視頻模擬/數字轉換芯片設備驅動的編寫方法。
15.1 Linux I2C體系結構
Linux的I2C體系結構分為3個組成部分:
? I2C核心
I2C核心提供了I2C總線驅動和設備驅動的注冊、注銷方法,I2C通信方法(即“algorithm”,筆者認為直譯為“運算方法”並不合適,為免引起誤解,下文將直接使用“algorithm”)上層的、與具體適配器無關的代碼以及探測設備、檢測設備地址的上層代碼等。
? I2C總線驅動
I2C總線驅動是對I2C硬件體系結構中適配器端的實現,適配器可由CPU控制,甚至直接集成在CPU內部。
I2C總線驅動主要包含了I2C適配器數據結構i2c_adapter、I2C適配器的algorithm數據結構i2c_algorithm和控制I2C適配器產生通信信號的函數。
經由I2C總線驅動的代碼,我們可以控制I2C適配器以主控方式產生開始位、停止位、讀寫周期,以及以從設備方式被讀寫、產生ACK等。
? I2C設備驅動
I2C設備驅動是對I2C硬件體系結構中設備端的實現,設備一般掛接在受CPU控制的I2C適配器上,通過I2C適配器與CPU交換數據。
I2C設備驅動主要包含了數據結構i2c_driver和i2c_client,我們需要根據具體設備實現其中的成員函數。
圖15.1 Linux I2C體系結構
在Linux 2.6內核中,所有的I2C設備都被在sysfs文件系統中顯示,存在於/sys/bus/i2c/目錄,以適配器地址和芯片地址的形式列出,如:
$ tree /sys/bus/i2c/
/sys/bus/i2c/
|-- devices
| |-- 0-0048 -> ../../../devices/legacy/i2c-0/0-0048
| |-- 0-0049 -> ../../../devices/legacy/i2c-0/0-0049
| |-- 0-004a -> ../../../devices/legacy/i2c-0/0-004a
| |-- 0-004b -> ../../../devices/legacy/i2c-0/0-004b
| |-- 0-004c -> ../../../devices/legacy/i2c-0/0-004c
| |-- 0-004d -> ../../../devices/legacy/i2c-0/0-004d
| |-- 0-004e -> ../../../devices/legacy/i2c-0/0-004e
| `-- 0-004f -> ../../../devices/legacy/i2c-0/0-004f
`-- drivers
|-- i2c_adapter
`-- lm75
|-- 0-0048 -> ../../../../devices/legacy/i2c-0/0-0048
|-- 0-0049 -> ../../../../devices/legacy/i2c-0/0-0049
|-- 0-004a -> ../../../../devices/legacy/i2c-0/0-004a
|-- 0-004b -> ../../../../devices/legacy/i2c-0/0-004b
|-- 0-004c -> ../../../../devices/legacy/i2c-0/0-004c
|-- 0-004d -> ../../../../devices/legacy/i2c-0/0-004d
|-- 0-004e -> ../../../../devices/legacy/i2c-0/0-004e
`-- 0-004f -> ../../../../devices/legacy/i2c-0/0-004f
在Linux內核源代碼中的drivers目錄下包含一個i2c目錄,而在i2c目錄下又包含如下文件和文件夾:
? i2c-core.c
這個文件實現了I2C核心的功能以及/proc/bus/i2c*接口。
? i2c-dev.c
實現了I2C適配器設備文件的功能,每一個I2C適配器都被分配一個設備。通過適配器訪問設備時的主設備號都為89,次設備號為0~255。應用程序通過“i2c-%d” (i2c-0, i2c-1, ..., i2c-10, ...)文件名並使用文件操作接口open()、write()、read()、ioctl()和close()等來訪問這個設備。
i2c-dev.c並沒有針對特定的設備而設計,只是提供了通用的read()、write()和ioctl()等接口,應用層可以借用這些接口訪問掛接在適配器上的I2C設備的存儲空間或寄存器並控制I2C設備的工作方式。
? chips文件夾
這個目錄中包含了一些特定的I2C設備驅動,如Dallas公司的DS1337實時鐘芯片、EPSON公司的RTC8564實時鐘芯片和I2C接口的EEPROM驅動等。
? busses文件夾
這個文件中包含了一些I2C總線的驅動,如S3C2410的I2C控制器驅動為i2c-s3c2410.c。
? algos文件夾
實現了一些I2C總線適配器的algorithm。
此外,內核中的i2c.h這個頭文件對i2c_driver、i2c_client、i2c_adapter和i2c_algorithm這4個數據結構進行了定義。理解這4個結構體的作用十分關鍵,代碼清單15.1、15.2、15.3、15.4分別給出了它們的定義。
代碼清單15.1 i2c_adapter結構體
1 struct i2c_adapter {
2 struct module *owner;/*所屬模塊*/
3 unsigned int id; /*algorithm的類型,定義於i2c-id.h,以I2C_ALGO_開始*/
4 unsigned int class;
5 struct i2c_algorithm *algo;/*總線通信方法結構體指針 */
6 void *algo_data; /* algorithm數據 */
7 int (*client_register)(struct i2c_client *); /*client注冊時調用*/
8 int (*client_unregister)(struct i2c_client *); /*client注銷時調用*/
9 struct semaphore bus_lock; /*控制並發訪問的自旋鎖*/
10 struct semaphore clist_lock;
11 int timeout;
12 int retries; /*重試次數*/
13 struct device dev; /* 適配器設備 */
14 struct class_device class_dev; /* 類設備 */
15 int nr;
16 struct list_head clients; /* client鏈表頭*/
17 struct list_head list;