在 Linux 內核中,struct regmap_config
是 ?Regmap 子系統的核心配置結構體,用于定義如何與底層硬件寄存器進行交互。Regmap(Register Map)子系統通過抽象不同總線(如 I2C、SPI、MMIO 等)的寄存器訪問細節,為驅動開發者提供統一的寄存器讀寫接口,顯著簡化了設備驅動的開發。
以下是對 struct regmap_config
結構體的詳細解析,涵蓋其核心成員、功能及典型配置場景:
一、結構體定義概覽(以 Linux 5.10+ 內核為例)
struct regmap_config {/* 基礎標識與總線類型 */const char *name; // Regmap 實例名稱(調試用)enum regmap_bus_type bus_type; // 總線類型(如 REGMAP_BUS_I2C、REGMAP_BUS_SPI、REGMAP_BUS_MMIO 等)/* 寄存器與值的位寬配置 */int reg_bits; // 寄存器地址的位寬(如 8/16/32 位)int val_bits; // 寄存器值的位寬(如 8/16/32 位)int pad_bits; // 地址/值與實際總線傳輸間的填充位(通常為 0)/* 字節序與對齊方式 */enum regmap_endian reg_format_endian; // 寄存器地址的字節序(大端/小端/不轉換)enum regmap_endian val_format_endian; // 寄存器值的字節序(同上)bool reg_stride; // 地址自動遞增步長(默認 1,若硬件地址不連續需手動設置)/* 訪問約束與超時 */unsigned int max_register; // 設備支持的最大寄存器地址(0 表示無限制)unsigned int fast_io; // 是否啟用快速 IO(1 啟用,依賴硬件特性)unsigned long read_flag_mask; // 讀操作的標志掩碼(如 I2C 的 RD 位)unsigned long write_flag_mask; // 寫操作的標志掩碼(如 I2C 的 WR 位)/* 緩存策略 */enum regmap_cache_type cache_type; // 緩存類型(無緩存/讀緩存/寫緩存/讀寫緩存)unsigned int cache_size; // 緩存大小(字節數,0 表示自動計算)bool use_single_read; // 強制單次讀(即使支持批量讀)bool use_single_write; // 強制單次寫(即使支持批量寫)/* 中斷與事件處理 */int irq; // 設備關聯的中斷號(若需要)unsigned long irq_flags; // 中斷觸發標志(如 IRQF_SHARED)/* 自定義回調函數 */int (*reg_read)(struct regmap *map, unsigned int reg, unsigned int *val); // 自定義讀回調int (*reg_write)(struct regmap *map, unsigned int reg, unsigned int val); // 自定義寫回調void (*lock)(struct regmap *map); // 自定義鎖函數void (*unlock)(struct regmap *map); // 自定義解鎖函數/* 調試與日志 */bool verbose; // 是否啟用詳細日志(調試用)struct dentry *debugfs; // DebugFS 掛載點(用于調試)
};
二、核心成員詳解
1. 基礎標識與總線類型
- ?**
name
**?:Regmap 實例的名稱(如"my_spi_device_regmap"
),主要用于調試日志和 DebugFS 展示。 - ?**
bus_type
**?:指定底層總線類型,決定 Regmap 如何與總線驅動交互。常見值包括:REGMAP_BUS_I2C
:I2C 總線(需配合struct i2c_client
使用)。REGMAP_BUS_SPI
:SPI 總線(需配合struct spi_device
使用)。REGMAP_BUS_MMIO
:內存映射 IO(MMIO,直接訪問物理內存地址)。REGMAP_BUS_HOST
:主機側總線(如用于連接外部芯片的專用總線)。
2. 寄存器與值的位寬配置
- ?**
reg_bits
**?:寄存器地址的二進制位數(如 8 位地址對應reg_bits=8
)。
示例:若設備寄存器地址范圍是0x00 ~ 0xFF
,則reg_bits=8
。 - ?**
val_bits
**?:寄存器值的二進制位數(如 16 位值對應val_bits=16
)。
示例:若寄存器是 8 位寬(每次讀寫 1 字節),則val_bits=8
;若是 16 位寬(大端存儲),則val_bits=16
。 - ?**
pad_bits
**?:地址或值與實際總線傳輸字節的填充位數(通常為 0)。
示例:某些 SPI 設備需要在地址后填充 4 位校驗位,則pad_bits=4
。
3. 字節序與對齊方式
- ?**
reg_format_endian
**?:寄存器地址的字節序(僅當reg_bits > 8
時有效)。
可選值:REGMAP_ENDIAN_BIG
(大端)、REGMAP_ENDIAN_LITTLE
(小端)、REGMAP_ENDIAN_NATIVE
(與 CPU 一致)。 - ?**
val_format_endian
**?:寄存器值的字節序(僅當val_bits > 8
時有效)。
示例:SPI 設備寄存器值為 16 位大端格式,則val_format_endian=REGMAP_ENDIAN_BIG
。 - ?**
reg_stride
**?:地址自動遞增的步長(默認 1)。
場景:若硬件寄存器地址不連續(如跳過保留地址),可手動設置步長(如reg_stride=2
表示每次地址+2)。
4. 訪問約束與超時
- ?**
max_register
**?:設備支持的最大寄存器地址(0 表示無限制)。
作用:Regmap 會檢查讀寫操作的地址是否超過此值,避免越界訪問。 - ?**
fast_io
**?:啟用快速 IO 優化(默認 0)。
條件:僅當底層總線支持原子讀寫(如 MMIO 或高速 SPI)時設置為 1,可減少函數調用開銷。 - ?**
read_flag_mask
/write_flag_mask
**?:總線操作的標志位掩碼。
示例:I2C 設備寫操作需要在地址后置位0
(寫標志),則write_flag_mask=0x00
;讀操作置位1
(讀標志),則read_flag_mask=0x01
(具體取決于總線協議)。
5. 緩存策略
Regmap 支持緩存寄存器值以減少總線訪問次數(尤其適用于頻繁讀寫的只讀/半靜態寄存器)。
- ?**
cache_type
**?:緩存類型,可選值:REGMAP_CACHE_NONE
:無緩存(每次讀寫直接訪問硬件)。REGMAP_CACHE_R
:只讀緩存(僅緩存讀操作結果,寫操作后失效)。REGMAP_CACHE_W
:寫緩存(寫操作先更新緩存,讀操作從緩存讀取,需配合regmap_write
自動同步)。REGMAP_CACHE_RW
:讀寫緩存(讀寫均通過緩存,需手動調用regmap_sync()
同步到硬件)。
- ?**
cache_size
**?:緩存大小(字節數)。若為 0,Regmap 會根據max_register
和val_bits
自動計算。 - ?**
use_single_read
/use_single_write
**?:強制單次讀寫(即使總線支持批量操作)。
場景:某些老舊設備不支持批量傳輸,需強制每次讀寫一個寄存器。
6. 中斷與事件處理
- ?**
irq
**?:設備關聯的中斷號(若需要 Regmap 處理中斷)。
配合:需結合regmap_irq_chip
定義中斷映射,實現中斷的統一管理。 - ?**
irq_flags
**?:中斷觸發標志(如IRQF_SHARED
共享中斷、IRQF_ONESHOT
單次觸發)。
7. 自定義回調函數
Regmap 允許通過自定義回調覆蓋默認的讀寫邏輯(如硬件有特殊時序要求)。
- ?**
reg_read
/reg_write
**?:自定義讀寫函數,原型為:int (*reg_read)(struct regmap *map, unsigned int reg, unsigned int *val); int (*reg_write)(struct regmap *map, unsigned int reg, unsigned int val);
- ?**
lock
/unlock
**?:自定義鎖函數(默認使用自旋鎖或互斥鎖)。
場景:多線程/中斷上下文共享 Regmap 時,需自定義鎖機制保證線程安全。
8. 調試與日志
- ?**
verbose
**?:啟用詳細日志(默認 0)。設置為 1 時,Regmap 會在讀寫操作時打印調試信息(如地址、值)。 - ?**
debugfs
**?:DebugFS 掛載點路徑(如"/sys/kernel/debug/regmap/my_regmap"
),可通過regmap-dump
工具查看寄存器狀態。
三、典型配置示例
示例 1:SPI 設備(16 位地址,8 位值,大端)
假設一個 SPI 設備的寄存器地址為 16 位(范圍 0x0000 ~ 0xFFFF
),每個寄存器值是 8 位,且地址采用大端格式:
static const struct regmap_config my_spi_regmap_config = {.name = "my_spi_device",.bus_type = REGMAP_BUS_SPI,.reg_bits = 16, // 16 位寄存器地址.val_bits = 8, // 8 位寄存器值.reg_format_endian = REGMAP_ENDIAN_BIG, // 地址大端格式.max_register = 0xFFFF, // 最大地址.fast_io = 1, // 啟用快速 IO.cache_type = REGMAP_CACHE_RW, // 讀寫緩存
};
示例 2:I2C 設備(8 位地址,16 位值,小端)
假設一個 I2C 設備的寄存器地址為 8 位(范圍 0x00 ~ 0x7F
),每個寄存器值是 16 位小端格式:
static const struct regmap_config my_i2c_regmap_config = {.name = "my_i2c_device",.bus_type = REGMAP_BUS_I2C,.reg_bits = 8, // 8 位寄存器地址.val_bits = 16, // 16 位寄存器值.val_format_endian = REGMAP_ENDIAN_LITTLE, // 值小端格式.max_register = 0x7F, // 最大地址.read_flag_mask = 0x01, // I2C 讀操作標志位(假設設備要求地址后第 0 位為 1).cache_type = REGMAP_CACHE_NONE, // 無緩存(實時性要求高)
};
四、關鍵注意事項
- ?總線適配器依賴?:
bus_type
需與實際使用的總線驅動匹配(如 SPI 需先注冊spi_device
,I2C 需先注冊i2c_client
)。 - ?位寬對齊?:
reg_bits
和val_bits
需與硬件寄存器的實際位寬嚴格一致,否則會導致讀寫錯誤。 - ?緩存一致性?:啟用緩存(
cache_type != REGMAP_CACHE_NONE
)時,需在寄存器值變更后調用regmap_write()
或regmap_update_bits()
觸發緩存同步;若硬件狀態可能被外部修改(如其他主設備),需手動調用regmap_sync()
刷新緩存。 - ?字節序處理?:
reg_format_endian
和val_format_endian
需根據硬件的寄存器定義設置(如網絡設備常用大端,傳感器常用小端)。 - ?中斷處理?:若設備需要中斷支持,需額外定義
struct regmap_irq_chip
并關聯到 Regmap 實例(通過regmap_add_irq_chip()
)。
五、總結
struct regmap_config
是 Linux Regmap 子系統的核心配置結構體,通過靈活設置其成員,開發者可以適配各種總線和寄存器特性的硬件設備。關鍵是根據硬件的實際需求(總線類型、位寬、字節序、緩存需求等)配置相應字段,并合理利用 Regmap 提供的統一接口簡化寄存器操作。