[ 導(dǎo)讀] 本文通過閱讀內(nèi)核代碼,來梳理一下I2C子系統(tǒng)的整體視圖。在開發(fā)I2C設(shè)備驅(qū)動(dòng)程序時(shí),往往缺乏對(duì)于系統(tǒng)整體的認(rèn)識(shí),沒有一個(gè)清晰的思路。所以從高層級(jí)來分析一下I2C系統(tǒng)的設(shè)計(jì)思路,將有助于設(shè)計(jì)調(diào)試具體的驅(qū)動(dòng)程序。
I2C/SMBUS基礎(chǔ)
I2C是一種芯片間通訊總線技術(shù),最早由Philips設(shè)計(jì)制定。下面內(nèi)容參考I2C 2.1 規(guī)格書
半雙工通信方式,通信采用主/從結(jié)構(gòu)
支持多主模式,下圖來源于I2C 2.1規(guī)格書
其內(nèi)部電氣實(shí)現(xiàn)采用集電極開路(Open-collector)/漏極開路(open-drain)結(jié)構(gòu)以實(shí)現(xiàn)線與功能,這是總線的實(shí)現(xiàn)基礎(chǔ),多芯片通過查詢總線狀態(tài)實(shí)現(xiàn)介質(zhì)仲裁以實(shí)現(xiàn)總線控制。 ?
總線信號(hào)由兩線實(shí)現(xiàn),串行時(shí)鐘線SCL(Serial Clock Line)/串行數(shù)據(jù)線SDA(serial Data Line)。
具有三種通訊速率模式:
standard mode:0-100 kbps ?(bps: bit/s)
Fast mode:0-400 kbps
High-speed mode : 0-3.4Mbps
可支持混速模式
不同的速率在硬件設(shè)計(jì)時(shí)需要注意信號(hào)的完整性,I2C總線等效電容Cx,主要需要考慮PCB布線,以及上拉電阻選取。
支持7bit/10bit 兩種芯片地址模式
I2C總線電氣特性,這個(gè)非常重要,須嚴(yán)格遵守標(biāo)準(zhǔn)的電氣特性
SMBUS(system management bus) 。大多數(shù)SMBus系統(tǒng)也符合I2C,電氣約束對(duì)于SMBus更為嚴(yán)格,并且它標(biāo)準(zhǔn)化了特定的協(xié)議消息和習(xí)慣用語。支持I2C的控制器也可以支持大多數(shù)SMBus操作,但是SMBus控制器并不支持I2C控制器將支持的所有協(xié)議選項(xiàng)。通過使用I2C原語或通過向不支持這些I2C操作的i2c_adapter設(shè)備發(fā)出SMBus命令,可以執(zhí)行各種SMBus協(xié)議操作。
I2C bus(Inter-Integrated Circuit bus) https://www.i2c-bus.org/
I2C 在Linux設(shè)備中的拓?fù)浣Y(jié)構(gòu)
在PC體系中,大體如下拓?fù)洌?/p>
PC體系中通過橋接芯片,擴(kuò)展出PCI,在由PCI擴(kuò)展出I2C適配器,進(jìn)而得到I2C總線,或者橋接芯片直接擴(kuò)展出SMBUS/I2C總線。
在嵌入式應(yīng)用中,則可能為:
嵌入式應(yīng)用中,則可能更多的情況是處理器內(nèi)置了I2C/SMBUS總線控制器,直接可得到I2C/SMBUS總線。嵌入式系統(tǒng)中常常會(huì)設(shè)計(jì)很多傳感器掛載在I2C總線上,比如溫度檢測,壓力檢測等等,又或者諸如電容觸摸屏、電源管理IC等等。
代碼實(shí)現(xiàn)
I2C 的core實(shí)現(xiàn)位于./drivers/i2c/下,實(shí)現(xiàn)了I2C總線設(shè)備以及驅(qū)動(dòng)(適配器)和設(shè)備驅(qū)動(dòng)的注冊(cè)、注銷方法,I2C通信方法algorithm抽象,以及與具體硬件無關(guān)的代碼
I2C主控制器驅(qū)動(dòng)位于 ./drivers/i2c/busses/,這里主要實(shí)現(xiàn)總線控制器,具體體現(xiàn)為i2c_adapter的實(shí)現(xiàn)。負(fù)責(zé)I2C適配器與從設(shè)備通信。I2C總線驅(qū)動(dòng)由i2c_adapter和i2c_algorithm來抽象描述。
設(shè)備驅(qū)動(dòng)則分散在./driver/下,這取決于具體的實(shí)現(xiàn),種類繁多。
i2c-dev,大多位于drivers/i2c/i2c-dev.c,這種方法只是封裝了主機(jī)(I2Cmaster,一般是SoC中內(nèi)置的I2C控制器)的I2C基本操作,并且向應(yīng)用層提供相應(yīng)的操作接口,應(yīng)用層代碼需要自己去實(shí)現(xiàn)對(duì)slave的控制和操作,所以這種I2C驅(qū)動(dòng)相當(dāng)于提供給應(yīng)用層可以訪問slave硬件設(shè)備的接口,本身并未對(duì)硬件做任何操作,應(yīng)用需要實(shí)現(xiàn)對(duì)硬件的操作。這種模式也稱為應(yīng)用驅(qū)動(dòng)程序。
另一種I2C驅(qū)動(dòng)是將所有的代碼都放在驅(qū)動(dòng)層實(shí)現(xiàn),直接向應(yīng)用層提供最終結(jié)果。應(yīng)用層甚至不需要知道這里面有I2C存在,譬如電容式觸摸屏驅(qū)動(dòng),直接向應(yīng)用層提供/dev/input/event1的操作接口,應(yīng)用層編程的人根本不知道event1中涉及到了I2C。
?
I2C子系統(tǒng)的主要目的是,對(duì)I2C總線以及設(shè)備利用面向?qū)ο缶幊趟枷雽?shí)現(xiàn)統(tǒng)一建模,以高內(nèi)聚-低耦合的軟件工程思想,實(shí)現(xiàn)一個(gè)分層體系結(jié)構(gòu),以便于內(nèi)核統(tǒng)一管理I2C設(shè)備,從而可以更容易的在linux下實(shí)現(xiàn)I2C設(shè)備以及高可移植。
主要數(shù)據(jù)結(jié)構(gòu)
其內(nèi)部有幾個(gè)關(guān)鍵數(shù)據(jù)結(jié)構(gòu),來梳理一下:
i2c_client, 用于抽象掛載在I2C總線上的從設(shè)備
i2c_driver,用于驅(qū)動(dòng)掛載在I2C總線的從設(shè)備,也即從設(shè)備的設(shè)備驅(qū)動(dòng)程序
i2c_adapter,用于抽象I2C的主設(shè)備
i2c_algorithm,抽象I2C總線操作接口
i2c_devinfo
該結(jié)構(gòu)體主要用于板級(jí)I2C信息管理
i2c_msg
該結(jié)構(gòu)體主要用于抽象I2C報(bào)文,其內(nèi)容如下:
i2c_timings
主要用于抽象I2C電氣特性,對(duì)于支持設(shè)備樹的系統(tǒng)構(gòu)建而言,主要通過以下內(nèi)核接口函數(shù),從設(shè)備樹解析電氣特性參數(shù)。
?
void?i2c_parse_fw_timings(struct?device?*dev,?struct?i2c_timings?*t,?bool?use_defaults) { ?int?ret; ?memset(t,?0,?sizeof(*t)); ?ret?=?device_property_read_u32(dev,?"clock-frequency",?&t->bus_freq_hz); ?if?(ret?&&?use_defaults) ??t->bus_freq_hz?=?100000; ?ret?=?device_property_read_u32(dev,?"i2c-scl-rising-time-ns",?&t->scl_rise_ns); ?if?(ret?&&?use_defaults)?{ ??if?(t->bus_freq_hz?<=?100000) ???t->scl_rise_ns?=?1000; ??else?if?(t->bus_freq_hz?<=?400000) ???t->scl_rise_ns?=?300; ??else ???t->scl_rise_ns?=?120; ?} ?ret?=?device_property_read_u32(dev,?"i2c-scl-falling-time-ns",?&t->scl_fall_ns); ?if?(ret?&&?use_defaults)?{ ??if?(t->bus_freq_hz?<=?400000) ???t->scl_fall_ns?=?300; ??else ???t->scl_fall_ns?=?120; ?} ?device_property_read_u32(dev,?"i2c-scl-internal-delay-ns",?&t->scl_int_delay_ns); ?ret?=?device_property_read_u32(dev,?"i2c-sda-falling-time-ns",?&t->sda_fall_ns); ?if?(ret?&&?use_defaults) ??t->sda_fall_ns?=?t->scl_fall_ns; ?device_property_read_u32(dev,?"i2c-sda-hold-time-ns",?&t->sda_hold_ns); } EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
?
i2c_device_identity
該結(jié)構(gòu)體主要用于抽象I2C 設(shè)備的ID屬性,通過內(nèi)核接口函數(shù)i2c_get_device_id以獲取設(shè)備ID屬性。
總體框架
概述
Linux I2C編程接口支持總線交互的主端和從端。從高層級(jí)看由兩種驅(qū)動(dòng)程序和兩種設(shè)備構(gòu)成:
適配器設(shè)備與適配器設(shè)備驅(qū)動(dòng)對(duì):I2C 適配器驅(qū)動(dòng)程序用于抽象控制器硬件;它綁定到一個(gè)物理設(shè)備(可能是一個(gè)PCI設(shè)備(PC體系多一些)或platform_device(嵌入式應(yīng)用居多)),并構(gòu)建i2c_adapter實(shí)體以呈現(xiàn)所管理的1個(gè)I2C總線段。
?
?
/*?ALI1535?device?address?register?bits?*/ #define?ALI1535_RD_ADDR??0x01?/*?Read/Write?Bit?in?Device?*/ ?????/*??Address?field??*/ ?????/*??->?Write?=?0??*/ ?????/*??->?Read??=?1??*/ #define?ALI1535_SMBIO_EN?0x04?/*?SMB?I/O?Space?enable??*/ /*PCI?設(shè)備驅(qū)動(dòng)*/ static?struct?pci_driver?ali1535_driver; static?unsigned?long?ali1535_smba; static?unsigned?short?ali1535_offset;
pci-I2C 適配器設(shè)備。如在i2c-ali1535.c中:
platform_device。比如:i2c-s3c2410,如下:
?
????????static?const?struct?platform_device_id?s3c24xx_driver_ids[]?=?{ ?{ ??.name??=?"s3c2410-i2c", ??.driver_data?=?0, ?},?{ ??.name??=?"s3c2440-i2c", ??.driver_data?=?QUIRK_S3C2440, ?},?{ ??.name??=?"s3c2440-hdmiphy-i2c", ??.driver_data?=?QUIRK_S3C2440?|?QUIRK_HDMIPHY?|?QUIRK_NO_GPIO, ?},?{?}, }; MODULE_DEVICE_TABLE(platform,?s3c24xx_driver_ids);
?
I2C從設(shè)備及設(shè)備驅(qū)動(dòng):每個(gè)I2C總線段上將有一個(gè)由結(jié)構(gòu)i2c_client表示的I2C設(shè)備。這些設(shè)備將被綁定到一個(gè)struct i2c_driver,遵循標(biāo)準(zhǔn)的Linux驅(qū)動(dòng)程序模型。
架構(gòu)
圖片來源//www.kernel.org/doc/html/latest/i2c/slave-interface.html
主端總線驅(qū)動(dòng)職責(zé):
適配器和算法驅(qū)動(dòng)程序,見下面i2c_algorithm結(jié)構(gòu)體詳細(xì)描述
管理I2C總線交互
從端設(shè)備驅(qū)動(dòng)職責(zé):
i2c_client結(jié)構(gòu)體具有設(shè)備的I2C總線地址以及適配器的驅(qū)動(dòng)程序指針
當(dāng)用戶程序發(fā)出文件操作申請(qǐng)I2C事務(wù)時(shí):
i2C_transfer (i2C-core.c) 調(diào)用 adap_algo_master_xfer,數(shù)據(jù)或消息以i2c_msg結(jié)構(gòu)體傳入。
適配器對(duì)硬件I / O地址進(jìn)行讀/寫操作,實(shí)現(xiàn)底層的I2C讀寫設(shè)備操作。
從應(yīng)用程序直到底層的大致交互流程如下:
總結(jié)一下
I2C總線子系統(tǒng)在Linux內(nèi)核中總線模型分為主/從兩端,主端主要有適配器以及適配器驅(qū)動(dòng)負(fù)責(zé)管理總線,從端主要有從設(shè)備抽象以及設(shè)備驅(qū)動(dòng),實(shí)現(xiàn)具體的從設(shè)備應(yīng)用。主端適配器以兩種形式存在于內(nèi)核代碼中,分為PCI橋接適配器或者platform_device形式。從總體理解I2C子系統(tǒng)的驅(qū)動(dòng)模型,以及相應(yīng)主要數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系,將有助于開發(fā)調(diào)試驅(qū)動(dòng)程序,快速定位問題。
審核編輯:湯梓紅
評(píng)論
查看更多