目錄:
一、regmap子系統(tǒng)的引入
二绣檬、regmap子系統(tǒng)的內(nèi)部實(shí)現(xiàn)
一足陨、regmap子系統(tǒng)的引入
沒(méi)有regmap子系統(tǒng)之前
在內(nèi)核代碼里,有成千上萬(wàn)的以I2C / SPI為通訊接口的設(shè)備驅(qū)動(dòng)娇未。
以I2C設(shè)備為例
各種I2C接口的設(shè)備驅(qū)動(dòng)都需要通過(guò)I2C子系統(tǒng)的API(i2c_transfer())來(lái)進(jìn)行讀寫寄存器的操作墨缘。在對(duì)應(yīng)的設(shè)備驅(qū)動(dòng)中,I2C讀寫寄存器的操作通常會(huì)被封裝成2個(gè)靜態(tài)函數(shù)忘蟹。
xxx_i2c_read_reg()/xxx_i2c_write_reg():
在沒(méi)有regmap抽象層之前飒房,內(nèi)核里充斥著大量類似的代碼,這些代碼都是多余的媚值,使用I2C總線來(lái)讀寫寄存器的操作是有共性的,應(yīng)該被抽象出來(lái)护糖,形成一份統(tǒng)一的代碼褥芒。驅(qū)動(dòng)開(kāi)發(fā)人員應(yīng)使用該抽象層的API來(lái)讀寫I2C設(shè)備的寄存器,然后把更多的精力放在驅(qū)動(dòng)的邏輯設(shè)計(jì)上嫡良。
同樣的锰扶,沒(méi)有regmap子系統(tǒng)時(shí),spi設(shè)備的寄存器讀寫操作也是散落在各個(gè)spi設(shè)備驅(qū)動(dòng)寝受。
i2c/spi drvier坷牛、i2c/spi device、i2c/spi subsystem之間的關(guān)系如下:
有了regmap子系統(tǒng)后
1. 同樣以I2C設(shè)備為例很澄,先定義struct regmap_config:
struct regmap_config里包含了讀寫芯片寄存器所需所有信息京闰,例如寄存器數(shù)據(jù)位寬、地址位寬等甩苛。
2. 將struct regmap_config注冊(cè)給regmap子系統(tǒng):
得到一個(gè)struct regmap對(duì)象蹂楣,有了這個(gè)對(duì)象,就可以調(diào)用regmap子系統(tǒng)提供的用于讀寫寄存器的API了讯蒲。
3. 使用regmap API讀寫寄存器:
int regmap_read(struct regmap *map, unsigned int reg,
? ? ? ? ? ? ? ? unsigned int *val);
int regmap_write(struct regmap *map, unsigned int reg,
? ? ? ? ? ? ? ? unsigned int val);
int regmap_update_bits(struct regmap *map, unsigned int reg,
? ? ? ? ? ? ? ? unsigned int mask, unsigned int val);
讀寫寄存器的操作已經(jīng)抽象到regmap子系統(tǒng)里了痊土,完整的API位于include/linux/regmap.h。
有了regmap后墨林,i2c/spi drvier赁酝、i2c/spi device、i2c/spi subsystem之間的關(guān)系如下:
我在Linux-4.14內(nèi)核里搜索了一下旭等,目前大約有491個(gè)地方使用了regmap子系統(tǒng)酌呆,將來(lái)可能會(huì)更多。
二辆雾、regmap子系統(tǒng)的內(nèi)部實(shí)現(xiàn)
regmap的拓?fù)浣Y(jié)構(gòu)
在Linux-4.14內(nèi)核中肪笋,regmap分為3層:
源碼文件:
regmap的緩存功能
在regmap子系統(tǒng)里,可以選擇是否使用緩存功能:
regmap內(nèi)支持3 種緩存類型:數(shù)組(flat)、LZO 壓縮和紅黑樹(rbtree)
1) 數(shù)組是最簡(jiǎn)單的緩存類型藤乙,當(dāng)設(shè)備寄存器很少時(shí)猜揪,可以用這種類型來(lái)緩存寄存器值。
2) LZO(Lempel–Ziv–Oberhumer) 是 Linux 中經(jīng)常用到的一種壓縮算法坛梁,Linux 編譯后就會(huì)用這個(gè)算法來(lái)壓縮而姐。這個(gè)算法有 3 個(gè)特性:壓縮快,解壓不需要額外內(nèi)存划咐,壓縮比可以自動(dòng)調(diào)節(jié)拴念。在這里,你可以理解為一個(gè)數(shù)組緩存褐缠,套了一層壓縮政鼠,來(lái)節(jié)約內(nèi)存。當(dāng)設(shè)備寄存器數(shù)量中等時(shí)队魏,可以考慮這種緩存類型公般。
3) 紅黑樹特性就是索引快,所以當(dāng)設(shè)備寄存器數(shù)量比較大胡桨,或者對(duì)寄存器操作延時(shí)要求低時(shí)官帘,就可以用這種緩存類型。
相關(guān)結(jié)構(gòu)體:
struct regmap_config
struct regmap_config里包含了讀寫芯片寄存器所需的所有信息昧谊,它是regmap API里最核心的結(jié)構(gòu)體刽虹。使用regmap子系統(tǒng)的第一步就是填充該結(jié)構(gòu)體。這個(gè)結(jié)構(gòu)體看著龐大呢诬,但是大多數(shù)情況下只要初始化幾個(gè)成員變量就足夠了涌哲,最簡(jiǎn)單和常見(jiàn)的情況類似這樣:
struct regmap_config重要成員變量的含義如下:
struct regmap_bus
該結(jié)構(gòu)體用于描述一種硬件總線的寄存器讀寫操作(a hardware bus for the register map infrastructure)。
regmap_bus并不是面向用戶的API馅巷,也就是說(shuō)使用regmap子系統(tǒng)并不要求一定要了解該結(jié)構(gòu)體膛虫,但是理解該結(jié)構(gòu)體有助于我們了解regmap是如何抽象寄存器讀寫操作的。無(wú)論是i2c還是spi钓猬,在調(diào)用devm_regmap_init_[i2c|spi|...]將struct regmap_config注冊(cè)給regmap子系統(tǒng)后稍刀,在子系統(tǒng)內(nèi)部都會(huì)根據(jù)remap_config里的配置信息找到對(duì)應(yīng)的struct regmap_bus。
比如:
static struct regmap_bus regmap_i2c
[...]
static struct regmap_bus regmap_i2c_smbus_i2c_block
static struct regmap_bus regmap_spi
static struct regmap_bus regmap_spmi_base
[...]
有了適配芯片的 regmap_config 和 regmap_bus敞曹,regmap子系統(tǒng)就有了讀寫該芯片寄存器的能力账月,然后就會(huì)返回一個(gè)struct regmap供設(shè)備驅(qū)動(dòng)來(lái)使用了,struct regmap類似一個(gè)大管家澳迫,包含了所有信息局齿,負(fù)責(zé)統(tǒng)籌一切。
struct regmap_bus重要成員變量的含義如下:
定義一個(gè)regmap_bus結(jié)構(gòu)體時(shí)不需要初始化其所有成員變量橄登,例如某些 i2c 芯片的寄存器是16bit(2Byte)的抓歼,其使用的regmap_bus如下:
常用的regmap API
regmap提供出來(lái)的讀寫寄存器的API非常多讥此,最常用的3個(gè)API如下:
可以猜測(cè)上述API會(huì)利用struct regmap_config + struct regmap_bus完成寄存器的讀寫操作。
簡(jiǎn)單看下regmap_read()的實(shí)現(xiàn):
regmap_read
? ? struct regmap *map
? ? map->reg_read(context, reg, val);
? ? ? ? _regmap_bus_reg_read
? ? ? ? ? ? map->bus->reg_read
總結(jié)
regmap 是在 Linux 3.1 加入進(jìn)來(lái)的特性谣妻,其最初的目的是減少i2c/spi等設(shè)備驅(qū)動(dòng)里的重復(fù)邏輯萄喳,提供一種通用的接口來(lái)操作芯片內(nèi)寄存器,隨著版本的更迭蹋半,regmap 支持的bus越來(lái)越多他巨,并且除了能做到統(tǒng)一的 寄存器I/O 接口,還可以在驅(qū)動(dòng)和硬件 IC 之間做一層緩存减江,從而能減少底層 I/O 的操作次數(shù)染突。給我的感覺(jué)是:內(nèi)核越來(lái)越強(qiáng)大了,但是學(xué)習(xí)的難度也越來(lái)越大辈灼,前路漫漫啊份企,求老司機(jī)帶路...
你和我各有一個(gè)蘋果,如果我們交換蘋果的話茵休,我們還是只有一個(gè)蘋果薪棒。但當(dāng)你和我各有一個(gè)想法,我們交換想法的話榕莺,我們就都有兩個(gè)想法了。如果你也對(duì)嵌入式系統(tǒng)開(kāi)發(fā)有興趣棵介,并且想和更多人互相交流學(xué)習(xí)的話钉鸯,請(qǐng)關(guān)注我的公眾號(hào):ESexpert,一起來(lái)學(xué)習(xí)吧邮辽,歡迎各種收藏/轉(zhuǎn)發(fā)/批評(píng)唠雕。
?