I2C匯流排架構 之 裝置驅動

2021-10-09 02:48:48 字數 4365 閱讀 7450

i2c裝置驅動是i2c框架中最接近應用層的,其上接應用層,下接i2c核心。也是驅動開發人員需要實現的**,在此驅動中我們只需負責以下步驟(以ap3216c為例):

a. 新增硬體資訊(裝置樹)

b. 搭建驅動框架

c. 構建i2c_driver,並註冊到linux

d. 註冊字元裝置

e. 向應用層提供i2c裝置操作介面

f. 登出i2c裝置

本篇文章會按照以上六個階段展開解析。

a. 新增硬體資訊裝置樹(裝置樹)

首先觀察硬體i2c裝置掛載到哪個i2c匯流排上,然後在裝置樹檔案找到該匯流排的裝置節點,在節點下建立子節點描述i2c裝置硬體資訊即可。

&i2c1 ;

};

b. 搭建驅動框架所謂搭建驅動框架,無非就是字元驅動將驅動入口、出口、以及對應用層的介面實現。與其他字元驅動的搭建是一樣的。

c. 構建i2c_driver,並註冊到linux i2c中

首先先看需要構建的i2c_driver結構體原型:

struct i2c_driver 

;

注:i2c_driver類似於platform_driver,在i2c_driver註冊到核心且名稱與裝置樹匹配一致就會進入probe中,在要解除安裝該驅動時會進入remove中。因此要填充i2c_driver的入口函式probe、出口函式(remove)和用於匹配的硬體資訊driver。

static

struct i2c_driver ap3216c_device_driver =

,.id_table = ap3216c_id,

};

d. 註冊i2c裝置

static

int __init ap3216c_init

(void

)

注:註冊i2c裝置很簡單,只需要在初始化中呼叫linux提供的巨集i2c_add_driver 即可。但是i2c_add_driver具體如何實現,有必要了解一下:

首先,這個巨集呼叫了i2c_register_driver:

#define i2c_add_driver(driver) \

i2c_register_driver(this_module, driver)

再大致了解i2c_register_driver函式流程:

--

- drivers --

- i2c_core.c --

-i2c_register_driver(--

- driver->driver.bus =

&i2c_bus_type

|struct module *owner,|-

init_list_head

(&driver->clients)

|struct i2c_driver *driver)|-

driver_register

(&driver->driver)||

-i2c_for_each_dev

(driver, __process_new_driver)|-

i2c_for_each_dev(--

-bus_for_each_dev

(&i2c_bus_type,

null

, data, fn)

|void

*data,

|int

(*fn)

(struct device *

,void*)

)|-__process_new_driver(--

-if(dev->type !=

&i2c_adapter_type)

struct device *dev,

|return0;

void

*data)|-

i2c_do_add_adapter

(data,

to_i2c_adapter

(dev)

);

小結:從上圖流程來看,在將i2c結構體註冊進核心時,呼叫了屬於i2c核心的i2c_register_driver。進入i2c核心中,會將i2c結構體新增到i2c鍊錶中,並實現i2c_client與i2c_driver的匹配,匹配成功會進入i2c_driver 結構體的probe函式中。(具體實現放在i2c核心文章分析)

e. 向應用層提供i2c裝置操作介面

成功進入probe函式後,就說明i2c驅動配置基本成功。接下來在probe中需要實現字元驅動的註冊,以及實現對外的讀寫介面。字元驅動的註冊**,與其他字元驅動是一致的,瀏覽**實現即可。主要分析對外介面的讀寫i2c裝置操作:

在微控制器的程式中,實現對i2c裝置的讀寫,需要手動實現讀寫i2c暫存器,或者通過gpio模擬i2c時序與i2c裝置通訊。而在linux中,如何與i2c裝置的具體通訊已經被封裝成固定的api,在程式中填充這些api的資料引數呼叫即可,列舉讀寫單個位元組的實現:

static

intap3216c_read_regs

(struct sap3216c_dev *dev,

unsigned

char reg,

void

*val,

int len)

else

return ret;

}static

intap3216c_write_regs

(struct sap3216c_dev *dev,

unsigned

char reg,

unsigned

char

*buf,

unsigned

char len)

小結:由以上**發現,在與i2c裝置的讀寫通訊中,都是通過呼叫i2c_transfer實現。

i2c_transfer的三個引數意義 :

(1) client->adapter: 該i2c裝置連線的i2c匯流排介面卡;

(2) msg:需要傳送的資料;

(3) 1:需要傳送的msg個數。

(1) 寫操作只需要乙個msg結構體:

起始位 + 寫操作(msg[0]) + 停止位。

(2) 讀操作需要兩個msg結構體 :

起始位+ 寫操作(寫入位址 msg[0])+ 起始位 + 讀操作(存入msg[1]) + 停止位。

f. 登出i2c裝置

登出操作:在字元驅動出口函式中,解除安裝掉註冊的i2c裝置。這裡呼叫i2c_del_driver即可實現,與i2c_add_driver是對應的。

static

void __exit ap3216c_exit

(void

)

到這裡本篇文章對i2c裝置驅動的具體分析基本完成。本篇以ap3216c光敏感測器**為例,從入口到出口**走向展開分析。通讀文章大致了解,會發現本篇i2c裝置驅動是與虛擬匯流排platform架構類似。不同的是platform是軟體實現的虛擬匯流排,在soc上並不存在;而i2c匯流排,在soc上是實際存在的。相同的是兩者實現將驅動分層為硬體引數和驅動抽象,在註冊時遍歷匹配,然後進入正文probe中!

由於linux內部的實現較為複雜,本篇主要以裝置驅動的角度來分析整個驅動的**走向,涉及到內部api的實現,本篇只大概介紹其功能,剩餘部分會放在i2c核心繼續分析。

參考:

《linux裝置驅動開發詳解》

《【正點原子】i.mx6u嵌入式linux驅動開發指南v1.4》

推薦閱讀:

i2c匯流排架構 之 i2c協議

i2c匯流排架構 之 i2c匯流排驅動

i2c匯流排架構 之 i2c核心

i2c裝置驅動例項除錯

如有技術交流需要,歡迎關注「開源519」

開源519.jpg

i2c裝置驅動

1,i2c 裝置註冊 static struct i2c board info i2c2 devices i2c裝置一般在板級 中註冊 static void msm8916 add i2c deivces void 2,i2c驅動註冊 include static const struct i2c...

Linux驅動之I2C裝置驅動

核心 4.20 晶元 hym8563 rtc 下面的 分析主要都在注釋中,會按照驅動中函式的執行順序分析。static const struct i2c device id hym8563 id module device table i2c,hym8563 id static const stru...

Linux驅動 I2C匯流排

這裡以rk3288為例子,使用的是linux4.14,根據裝置樹節點i2c 與rk3x i2c driver,match之後,就會呼叫對應的probe rk3x i2c probe 這裡主要就是註冊乙個adapt i2c add adapter 也就是i2c控制器,或者說是i2c主裝置,既然是主裝置...