1 regmap的架构 regmap
是为了方便操作寄存器而设计的,它将所有模块的寄存器(包括soc上模块的寄存器和外围设备的寄存器等) 抽象出来,用一套统一接口来操作寄存器,统一操作 i2c、i3c、spi、mmio、sccb、sdw、slimbus、irq
等。
regmap
框架分为三层:
①、底层物理总线: regmap
支持的物理总线有 i2c、i3c、spi、mmio、sccb、sdw、slimbus、irq、spmi 和 w1
。
②、regmap
核心层:用于实现 regmap
核心。
③、regmapAPI
抽象层,regmap
向驱动编写人员提供的 API 接口。
2 数据结构 2.1 regmap 结构体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 struct regmap { union { struct mutex mutex ; struct { spinlock_t spinlock; unsigned long spinlock_flags; }; }; regmap_lock lock; regmap_unlock unlock; void *lock_arg; struct device *dev ; void *work_buf; struct regmap_format format ; const struct regmap_bus *bus ; void *bus_context; const char *name; bool async; spinlock_t async_lock; wait_queue_head_t async_waitq; struct list_head async_list ; struct list_head async_free ; int async_ret; ... unsigned int max_register; bool (*writeable_reg)(struct device *dev, unsigned int reg); bool (*readable_reg)(struct device *dev, unsigned int reg); bool (*volatile_reg)(struct device *dev, unsigned int reg); bool (*precious_reg)(struct device *dev, unsigned int reg); const struct regmap_access_table *wr_table ; const struct regmap_access_table *rd_table ; const struct regmap_access_table *volatile_table ; const struct regmap_access_table *precious_table ; int (*reg_read)(void *context, unsigned int reg, unsigned int *val); int (*reg_write)(void *context, unsigned int reg, unsigned int val); ...... struct rb_root range_tree ; void *selector_work_buf; };
regmap
的初始化通过结构体 regmap_config
来完成。
2.2 regmap_config 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 struct regmap_config { const char *name; int reg_bits; int reg_stride; int pad_bits; int val_bits; bool (*writeable_reg)(struct device *dev, unsigned int reg); bool (*readable_reg)(struct device *dev, unsigned int reg); bool (*volatile_reg)(struct device *dev, unsigned int reg); bool (*precious_reg)(struct device *dev, unsigned int reg); regmap_lock lock; regmap_unlock unlock; void *lock_arg; int (*reg_read)(void *context, unsigned int reg, unsigned int *val); int (*reg_write)(void *context, unsigned int reg, unsigned int val); bool fast_io; unsigned int max_register; const struct regmap_access_table *wr_table ; const struct regmap_access_table *rd_table ; const struct regmap_access_table *volatile_table ; const struct regmap_access_table *precious_table ; const struct reg_default *reg_defaults ; unsigned int num_reg_defaults; enum regcache_type cache_type ; const void *reg_defaults_raw; unsigned int num_reg_defaults_raw; u8 read_flag_mask; u8 write_flag_mask; bool use_single_rw; bool can_multi_write; enum regmap_endian reg_format_endian ; enum regmap_endian val_format_endian ; const struct regmap_range_cfg *ranges ; unsigned int num_ranges; };
3 API 3.1 Regmap 申请与初始化 regmap
支持多种物理总线,比如 I2C 和 SPI,我们需要根据所使用的接口来选 择合适的 regmap
初始化函数。
1 2 3 struct regmap * regmap_init_spi (struct spi_device *spi, const struct regmap_config *config) ;struct regmap * regmap_init_i2c (struct i2c_client *i2c, const struct regmap_config *config) ;void regmap_exit (struct regmap *map ) ;
3.2 regmap 设备访问 1 2 int regmap_read (struct regmap *map , unsigned int reg, unsigned int *val) ;int regmap_write (struct regmap *map , unsigned int reg, unsigned int val) ;
在 regmap_read
和 regmap_write
的基础上还衍生出了其他一些 regmap
的 API 函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int regmap_update_bits (struct regmap *map , unsigned int reg, unsigned int mask, unsigned int val) ;int regmap_bulk_read (struct regmap *map , unsigned int reg, void *val, size_t val_count) ;int regmap_bulk_write (struct regmap *map , unsigned int reg, const void *val, size_t val_count)
3.3 regmap_config 掩码设置 结构体regmap_config
里面有三个关于掩码的成员变量:read_flag_mask
和 write_flag_mask
.
Linux下SPI子系统驱动 字符设备驱动-SPI子系统 | Hexo (fuzidage.github.io)
其中读操作要将寄存器的地址 bit7
置 1,表示这是 一个读操作。当我们使用regmap
的时候就不需要手动将寄存器地址的 bit7 置 1,在初始化 regmap_config
的时候直接将read_flag_mask
设置为 0X80
即可,这样通过regmap
读取 SPI 内部寄存器的时候就会将寄存器地址与read_flag_mask
进行或运算,结果就是将 bit7
置 1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static struct regmap_bus regmap_spi = { .write = regmap_spi_write, .gather_write = regmap_spi_gather_write, .async_write = regmap_spi_async_write, .async_alloc = regmap_spi_async_alloc, .read = regmap_spi_read, .read_flag_mask = 0x80 , .reg_format_endian_default = REGMAP_ENDIAN_BIG, .val_format_endian_default = REGMAP_ENDIAN_BIG, }; ... struct regmap *regmap_init_spi (struct spi_device *spi, const struct regmap_config *config) { return regmap_init(&spi->dev, ®map_spi, &spi->dev, config); }
在 regmap_init
函数中找到如下所示内容:
1 2 3 4 5 6 if (config->read_flag_mask || config->write_flag_mask) { map ->read_flag_mask = config->read_flag_mask; map ->write_flag_mask = config->write_flag_mask; } else if (bus) { map ->read_flag_mask = bus->read_flag_mask; }
可以看到初始化时用regmap_config
中的读写掩码来初始化regmap_bus
中的掩码。由于 regmap_spi
默认将 read_flag_mask
设置为 0X80,假如你所使用的 SPI 设备不需要读掩码,在初始 化regmap_config
的时候一定要将 read_flag_mask
设置为 0X00。
4 Regmap操作SPI-ICM20608实验 Linux下SPI子系统驱动 字符设备驱动-SPI子系统 | Hexo (fuzidage.github.io)
之前构造了icm20608_dev
利用spi子系统框架
通信。框架还是保持不变,添加regmap和regmap_config
参数。
4.1 初始化 regmap
4.2 regmap 访问icm20608 以前的读写寄存器操作要构造spi_message,spi_transfer
:
现在直接套用reg_map
函数,无需要调用spi数据传输相关api:
读多组寄存器也是一样,调用regmap_bulk_read
。
5 Regmap操作I2C-ap3216c实验
Linux I2C子系统驱动 字符设备驱动-I2C子系统 | Hexo (fuzidage.github.io)
5.1 初始化 regmap
5.2 regmap 访问ap3216c
这里初始化open fd
时,要用到regmap_write
进行i2c从设备的寄存器写入初始化。然后调用read,调用regmap_read
进行读操作,这里每次都只读取一个byte,不需要用到regmap_bulk_read
.