Linux内核之 regmap 子系统


前言

在 Linux 驱动中很多涉及设备寄存器等的操作都是通过 I2C / SPI 等常用接口,针对i2c设备我们通过接口 i2c_transferi2c_master_send 等接口进行读写操作,而针对spi 设备我们则通过接口 spi_writespi_syncspi_async 等接口实现读写操作。虽然直接调用 i2c 或 spi 设备的操作接口也很方便,但这些子系统中的读写接口中充斥着大量的 i2c、spi 操作,因此引入了 Regmap 子系统来方便内核开发人员统一操作 I2C/SPI 设备。


一、regmap 子系统介绍

Linux 内核提供了 regmap 子系统来针对 spi、i2c 等设备的操作提供了一次抽象,对外提供对 spi、i2c 等设备相关寄存器的统一访问接口( regmap_write、regmap_read )等,而在 regmap 子系统内部再通过调用 i2c、spi 等设备的寄存器读写接口,实现对具体设备寄存器的读写操作。我们常常会在一些驱动中使用到 regmap 子系统接口 regmap_write/read 等来操作设备寄存器,同时 regmap 子系统提供缓存机制,也可以减小对设备的访问次数。

1.什么情况下会使用 regmap

  • 硬件寄存器操作,比如选用通过 I2C/SPI 接口来读写设备的内部寄存器,或者需要读写 SOC 内部的硬件寄存器。
  • 提高代码复用性和驱动一致性,简化驱动开发过程。
  • 减少底层 I/O 操作次数,提高访问效率。

二、regmap 子系统框架

regmap 子系统主要包含 regmapregmap_bus 两大部分,其中 regmap 表示一个慢速 i/o 设备的 reg 操作的映射,reg_bus 则表示一类慢速 i/o 设备的 reg 操作(如i2c设备可定义对应的regmap_bus,提供寄存器的读写操作接口、spi设备也定义对应的remap_bus,提供寄存器的读写接口)。

针对regmap子系统而言,regmap_bus的实现由内核层完成、属于regmap子系统的一部分(目前实现了regmap_i2c、regmap_spi、regmap_mmio等regmap_bus),内核层通过实现remap_i2c、regmap_spi,只需要使用i2c、spi的regmap创建接口,然后就可使用regmap提供的操作接口,实现对这两类设备的访问操作。

regmap 驱动框架如下:
在这里插入图片描述
通过regmap子系统的抽象,具体的设备驱动模块只需要调用regmap_write、regmap_read等通用接 口,即可实现对i2c/spi设备的访问。

三、regmap 子系统重要数据结构

regmap 子系统主要包含 3 个重要的数据结构, struct regmap、struct regmap_config、struct regmap_bus,其中,

  • regmap数据结构即为具体设备的 map (如一个 i2c 设备、spi 设备均需要一个 regmap),而 regmap 里面则包含 regcache 相关的支持、该 regmap 关联的 regmap、寄存器是否可读写等接口;
  • regmap_config - Configuration for the register map of a device,实现对 regmap 的初始化;
  • regmap_bus 数据结构即对具体总线控制器 map 的抽象(i2s、spi 模块均完成了 regmap_bus 的定义,其中定义了对 i2c 设备、spi 设备的统一读写接口)。

regmap子系统的数据结构间的定义相对来说并不复杂,并且regmap子系统的设计相对来说也不算复杂(比如并没有提供remap_bus的注册接口,也不需要关注系统中已经定义了多少个regmap_bus以及系统中已经创建了多少个regmap等等),相比于设备驱动模型、pinctrl子系统、input子系统而言,算是较简单的子系统设计。针对regmap子系统,只要我们理解了regmap、regmap_bus的定义,基本上也可以大概了解regmap子系统的实现了。下面我们详细说明下。

1. struct regmap

regmap 数据结构定义在 drivers/base/regmap/internal.h

struct regmap {
    
    
	...
	struct device *dev; /* Device we do I/O on */
	void *work_buf;     /* Scratch buffer used to format I/O */
	/* 针对有些设备而言,其寄存器的位数、寄存器值的位数可能有所不同
	 *(有的设备寄存器为8位、寄存器值也是8位;有的设备寄存器为16位、
	 * 寄存器值也是16位等等),而且存在字节序的问题,因此提供struct 
	 * regmap_format类型的变量,实现寄存器、寄存器值位数设定、寄存
	 * 器及其值的格式化操作接口等。
	 */
	struct regmap_format format;  /* Buffer format */
	const struct regmap_bus *bus;
	
	/* 相关的异步写链表以及异步写相关的等待队列 */
	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);
	bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
	bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);

	/* 该regmap相关的寄存器读写权限(提供寄存器是否可写接口、是否可
	 * 读接口、是否为volatile等),并提供可写寄存器table、可读寄存
	 * 器table、volatile_table等等,regmap子系统实现了寄存器的访问
	 * 权限控制,这个设计还是很好的。 
	 */
	const struct regmap_access_table *wr_table;
	const struct regmap_access_table *rd_table;
	const struct regmap_access_table *volatile_table;

	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
	int (*reg_update_bits)(void *context, unsigned int reg,
			       unsigned int mask, unsigned int val);

	/* 该regmap相关的cache操作接口、是否支持cache操作等 */
	/* regcache specific members */
	const struct regcache_ops *cache_ops;
	enum regcache_type cache_type;

	/* number of bytes in reg_defaults_raw */
	unsigned int cache_size_raw;
	/* number of bytes per word in reg_defaults_raw */
	unsigned int cache_word_size;
	/* number of entries in reg_defaults */
	unsigned int num_reg_defaults;
	/* number of entries in reg_defaults_raw */
	unsigned int num_reg_defaults_raw;

	/* if set, only the cache is modified not the HW */
	bool cache_only;
	/* if set, only the HW is modified not the cache */
	bool cache_bypass;
	/* if set, remember to free reg_defaults_raw */
	bool cache_free;

	struct reg_default *reg_defaults;
	const void *reg_defaults_raw;
	void *cache;
	/* if set, the cache contains newer data than the HW */
	bool cache_dirty;
	/* if set, the HW registers are known to match map->reg_defaults */
	bool no_sync_defaults;

	/* if set, raw reads/writes are limited to this size */
	size_t max_raw_read;
	size_t max_raw_write;
	
	/* 该regmap是否支持按页访问操作(针对某类设备而言,如phy寄存器,
	 * 协议上规则只支持32个寄存器,但有些phy设备提供的功能比较复杂,
	 * 对外提供的寄存器个数超过了32个,那它就提供按页访问操作,比如
	 * 定义向寄存器27写入值进行页的选择,这样的话支持的寄存器就好超
	 * 过32个(如marvell的88exxxx系统的芯片,基本上都是支持按页访问
	 * 的)),若该设备支持按页访问,则需要设定page 访问的范围、page 
	 * 选择寄存器号及其偏移等等,并会将对应的信息存放在红黑树
	 * range_tree中。
	 */
	struct rb_root range_tree;
	void *selector_work_buf;	/* Scratch buffer used for selector */

	/* if set, the regmap core can sleep */
	bool can_sleep;
};

regmap 基本上则为数据结构中描述的功能,围绕这 regmap 又定义了 regmap_formatregmap_access_table 等数据结构。

扫描二维码关注公众号,回复: 14857375 查看本文章

1.1 struct regmap_format

regmap_format 数据结构定义在 drivers/base/regmap/internal.h,该数据结构主要实现寄存器及其值的位数、格式化操作等接口。

针对寄存器值不是 8 bit 整数倍的情形,则需要实现 format_write 接口(如 reg 占用 4 bit、value 占用 12 bit 情况);而针对寄存器值是 8 bit 整数倍的情况,则只需要实现 format_regformat_valparse_valparse_inplace 接口。

struct regmap_format {
    
    
	size_t buf_size;
	size_t reg_bytes;
	size_t pad_bytes;
	size_t reg_downshift;
	size_t val_bytes;
	void (*format_write)(struct regmap *map,
			     unsigned int reg, unsigned int val);
	void (*format_reg)(void *buf, unsigned int reg, unsigned int shift);
	void (*format_val)(void *buf, unsigned int val, unsigned int shift);
	unsigned int (*parse_val)(const void *buf);
	void (*parse_inplace)(void *buf);
};

1.2 struct regmap_access_table

该数据结构主要用于描述regmap的寄存器读写权限控制的,该数据结构内部包含struct regmap_ranage类型的变量。

  • 支持访问的寄存器的范围;
  • 不支持访问的寄存器的范围等。
/**
 * struct regmap_access_table - A table of register ranges for access checks
 *
 * @yes_ranges : pointer to an array of regmap ranges used as "yes ranges"
 * @n_yes_ranges: size of the above array
 * @no_ranges: pointer to an array of regmap ranges used as "no ranges"
 * @n_no_ranges: size of the above array
 *
 * A table of ranges including some yes ranges and some no ranges.
 * If a register belongs to a no_range, the corresponding check function
 * will return false. If a register belongs to a yes range, the corresponding
 * check function will return true. "no_ranges" are searched first.
 */
struct regmap_access_table {
    
    
	const struct regmap_range *yes_ranges;
	unsigned int n_yes_ranges;
	const struct regmap_range *no_ranges;
	unsigned int n_no_ranges;
};

2. struct regmap_config

该数据结构主要在创建一个 regmap 时,实现对 regmap 的初始化,主要信息如下:

  1. 寄存器的位数、寄存器值的位数;
  2. 寄存器读写权限判断的回调函数、读写范围的定义;
  3. 加锁、解锁函数;
  4. 读写flag;
  5. 字节序相关的配置;
  6. 是否支持page读写方式,若需要定义regmap_range_cfg类型的变量,说明page select reg、page reg范围等内容;
/**
 1. struct regmap_config - Configuration for the register map of a device.
 2.  3. @name: Optional name of the regmap. Useful when a device has multiple
 4.        register regions.
 5.  6. @reg_bits: Number of bits in a register address, mandatory.
 7. @reg_stride: The register address stride. Valid register addresses are a
 8.              multiple of this value. If set to 0, a value of 1 will be
 9.              used.
 10. @reg_downshift: The number of bits to downshift the register before
 11. 	   performing any operations.
 12. @reg_base: Value to be added to every register address before performing any
 13.       operation.
 14. @pad_bits: Number of bits of padding between register and value.
 15. @val_bits: Number of bits in a register value, mandatory.
 16.  17. @writeable_reg: Optional callback returning true if the register
 18. 	   can be written to. If this field is NULL but wr_table
 19. 	   (see below) is not, the check is performed on such table
 20.                 (a register is writeable if it belongs to one of the ranges
 21.                  specified by wr_table).
 22. @readable_reg: Optional callback returning true if the register
 23. 	  can be read from. If this field is NULL but rd_table
 24. 	   (see below) is not, the check is performed on such table
 25.                 (a register is readable if it belongs to one of the ranges
 26.                  specified by rd_table).
 27. @volatile_reg: Optional callback returning true if the register
 28. 	  value can't be cached. If this field is NULL but
 29. 	  volatile_table (see below) is not, the check is performed on
 30.                such table (a register is volatile if it belongs to one of
 31.                the ranges specified by volatile_table).
 32. @precious_reg: Optional callback returning true if the register
 33. 	  should not be read outside of a call from the driver
 34. 	  (e.g., a clear on read interrupt status register). If this
 35.                field is NULL but precious_table (see below) is not, the
 36.                check is performed on such table (a register is precious if
 37.                it belongs to one of the ranges specified by precious_table).
 38. @writeable_noinc_reg: Optional callback returning true if the register
 39. 		supports multiple write operations without incrementing
 40. 		the register number. If this field is NULL but
 41. 		wr_noinc_table (see below) is not, the check is
 42. 		performed on such table (a register is no increment
 43. 		writeable if it belongs to one of the ranges specified
 44. 		by wr_noinc_table).
 45. @readable_noinc_reg: Optional callback returning true if the register
 46. 		supports multiple read operations without incrementing
 47. 		the register number. If this field is NULL but
 48. 		rd_noinc_table (see below) is not, the check is
 49. 		performed on such table (a register is no increment
 50. 		readable if it belongs to one of the ranges specified
 51. 		by rd_noinc_table).
 52. @disable_locking: This regmap is either protected by external means or
 53.                   is guaranteed not to be accessed from multiple threads.
 54.                   Don't use any locking mechanisms.
 55. @lock:	  Optional lock callback (overrides regmap's default lock
 56. 	  function, based on spinlock or mutex).
 57. @unlock:	  As above for unlocking.
 58. @lock_arg:	  this field is passed as the only argument of lock/unlock
 59. 	  functions (ignored in case regular lock/unlock functions
 60. 	  are not overridden).
 61. @reg_read:	  Optional callback that if filled will be used to perform
 62.           	  all the reads from the registers. Should only be provided for
 63. 	  devices whose read operation cannot be represented as a simple
 64. 	  read operation on a bus such as SPI, I2C, etc. Most of the
 65. 	  devices do not need this.
 66. @reg_write:	  Same as above for writing.
 67. @reg_update_bits: Optional callback that if filled will be used to perform
 68. 	     all the update_bits(rmw) operation. Should only be provided
 69. 	     if the function require special handling with lock and reg
 70. 	     handling and the operation cannot be represented as a simple
 71. 	     update_bits operation on a bus such as SPI, I2C, etc.
 72. @fast_io:	  Register IO is fast. Use a spinlock instead of a mutex
 73.      	  to perform locking. This field is ignored if custom lock/unlock
 74.      	  functions are used (see fields lock/unlock of struct regmap_config).
 75. 	  This field is a duplicate of a similar file in
 76. 	  'struct regmap_bus' and serves exact same purpose.
 77. 	   Use it only for "no-bus" cases.
 78. @max_register: Optional, specifies the maximum valid register address.
 79. @wr_table:     Optional, points to a struct regmap_access_table specifying
 80.                valid ranges for write access.
 81. @rd_table:     As above, for read access.
 82. @volatile_table: As above, for volatile registers.
 83. @precious_table: As above, for precious registers.
 84. @wr_noinc_table: As above, for no increment writeable registers.
 85. @rd_noinc_table: As above, for no increment readable registers.
 86. @reg_defaults: Power on reset values for registers (for use with
 87.                register cache support).
 88. @num_reg_defaults: Number of elements in reg_defaults.
 89.  90. @read_flag_mask: Mask to be set in the top bytes of the register when doing
 91.                  a read.
 92. @write_flag_mask: Mask to be set in the top bytes of the register when doing
 93.                   a write. If both read_flag_mask and write_flag_mask are
 94.                   empty and zero_flag_mask is not set the regmap_bus default
 95.                   masks are used.
 96. @zero_flag_mask: If set, read_flag_mask and write_flag_mask are used even
 97.                   if they are both empty.
 98. @use_relaxed_mmio: If set, MMIO R/W operations will not use memory barriers.
 99.                    This can avoid load on devices which don't require strict
 100.                    orderings, but drivers should carefully add any explicit
 101.                    memory barriers when they may require them.
 102. @use_single_read: If set, converts the bulk read operation into a series of
 103.                   single read operations. This is useful for a device that
 104.                   does not support  bulk read.
 105. @use_single_write: If set, converts the bulk write operation into a series of
 106.                    single write operations. This is useful for a device that
 107.                    does not support bulk write.
 108. @can_multi_write: If set, the device supports the multi write mode of bulk
 109.                   write operations, if clear multi write requests will be
 110.                   split into individual write operations
 111.  112. @cache_type: The actual cache type.
 113. @reg_defaults_raw: Power on reset values for registers (for use with
 114.                    register cache support).
 115. @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
 116. @reg_format_endian: Endianness for formatted register addresses. If this is
 117.                     DEFAULT, the @reg_format_endian_default value from the
 118.                     regmap bus is used.
 119. @val_format_endian: Endianness for formatted register values. If this is
 120.                     DEFAULT, the @reg_format_endian_default value from the
 121.                     regmap bus is used.
 122.  123. @ranges: Array of configuration entries for virtual address ranges.
 124. @num_ranges: Number of range configuration entries.
 125. @use_hwlock: Indicate if a hardware spinlock should be used.
 126. @use_raw_spinlock: Indicate if a raw spinlock should be used.
 127. @hwlock_id: Specify the hardware spinlock id.
 128. @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE,
 129. 	 HWLOCK_IRQ or 0.
 130. @can_sleep: Optional, specifies whether regmap operations can sleep.
 */
struct regmap_config {
    
    
	const char *name;

	int reg_bits;
	int reg_stride;
	int reg_downshift;
	unsigned int reg_base;
	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);
	bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
	bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);

	bool disable_locking;
	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);
	int (*reg_update_bits)(void *context, unsigned int reg,
			       unsigned int mask, 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 regmap_access_table *wr_noinc_table;
	const struct regmap_access_table *rd_noinc_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;

	unsigned long read_flag_mask;
	unsigned long write_flag_mask;
	bool zero_flag_mask;

	bool use_single_read;
	bool use_single_write;
	bool use_relaxed_mmio;
	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;

	bool use_hwlock;
	bool use_raw_spinlock;
	unsigned int hwlock_id;
	unsigned int hwlock_mode;

	bool can_sleep;
};

3. struct regmap_bus

如下即为regmap_bus的定义,其主要提供如下几个方面的内容:

  1. Regmap bus的同步写接口;
  2. Regmap bus的异步写接口;
  3. Regmap bus的读接口;
  4. Regmap bus的读写flag;
  5. Regmap bus的寄存器、寄存器值的格式(大端、小端);
  6. Regmap bus异步写相关的缓存申请接口等。

regmap_bus的定义也是比较简单,只需提供regmap_bus对应总线控制器的访问方法即可。

/**
 * struct regmap_bus - Description of a hardware bus for the register map
 *                     infrastructure.
 *
 * @fast_io: Register IO is fast. Use a spinlock instead of a mutex
 *	     to perform locking. This field is ignored if custom lock/unlock
 *	     functions are used (see fields lock/unlock of
 *	     struct regmap_config).
 * @write: Write operation.
 * @gather_write: Write operation with split register/value, return -ENOTSUPP
 *                if not implemented  on a given device.
 * @async_write: Write operation which completes asynchronously, optional and
 *               must serialise with respect to non-async I/O.
 * @reg_write: Write a single register value to the given register address. This
 *             write operation has to complete when returning from the function.
 * @reg_update_bits: Update bits operation to be used against volatile
 *                   registers, intended for devices supporting some mechanism
 *                   for setting clearing bits without having to
 *                   read/modify/write.
 * @read: Read operation.  Data is returned in the buffer used to transmit
 *         data.
 * @reg_read: Read a single register value from a given register address.
 * @free_context: Free context.
 * @async_alloc: Allocate a regmap_async() structure.
 * @read_flag_mask: Mask to be set in the top byte of the register when doing
 *                  a read.
 * @reg_format_endian_default: Default endianness for formatted register
 *     addresses. Used when the regmap_config specifies DEFAULT. If this is
 *     DEFAULT, BIG is assumed.
 * @val_format_endian_default: Default endianness for formatted register
 *     values. Used when the regmap_config specifies DEFAULT. If this is
 *     DEFAULT, BIG is assumed.
 * @max_raw_read: Max raw read size that can be used on the bus.
 * @max_raw_write: Max raw write size that can be used on the bus.
 * @free_on_exit: kfree this on exit of regmap
 */
struct regmap_bus {
    
    
	bool fast_io;
	regmap_hw_write write;
	regmap_hw_gather_write gather_write;
	regmap_hw_async_write async_write;
	regmap_hw_reg_write reg_write;
	regmap_hw_reg_update_bits reg_update_bits;
	regmap_hw_read read;
	regmap_hw_reg_read reg_read;
	regmap_hw_free_context free_context;
	regmap_hw_async_alloc async_alloc;
	u8 read_flag_mask;
	enum regmap_endian reg_format_endian_default;
	enum regmap_endian val_format_endian_default;
	size_t max_raw_read;
	size_t max_raw_write;
	bool free_on_exit;
};

参考链接如下:
Linux regmap子系统分析之一 系统概述
Linux regmap子系统分析之二 从数据结构分析系统实现
其中关于 regmap 相关结构体之间调用关系参考如下:
Linux regmap子系统分析之三 regmap bus实例分析

四、regmap 使用

1. regmap 初始化与释放

目前 regmap 支持的物理总线有 i2c、i3c、spi、mmio、sccb、sdw、slimbus、irq、spmi 和 w1 等,在 /include/linux/regmap.h 中提供了对各种总线 regmap 初始化的 api,以 I2C 与 SPI 两个常用接口为例,

/**
 * devm_regmap_init_i2c() - Initialise managed register map
 *
 * @i2c: Device that will be interacted with
 * @config: Configuration for register map
 *
 * The return value will be an ERR_PTR() on error or a valid pointer
 * to a struct regmap.  The regmap will be automatically freed by the
 * device management code.
 */
#define devm_regmap_init_i2c(i2c, config)				\
	__regmap_lockdep_wrapper(__devm_regmap_init_i2c, #config,	\
				i2c, config)

/**
 * devm_regmap_init_spi() - Initialise register map
 *
 * @dev: Device that will be interacted with
 * @config: Configuration for register map
 *
 * The return value will be an ERR_PTR() on error or a valid pointer
 * to a struct regmap.  The map will be automatically freed by the
 * device management code.
 */
#define devm_regmap_init_spi(dev, config)				\
	__regmap_lockdep_wrapper(__devm_regmap_init_spi, #config,	\
				dev, config)

其中 i2c 为 i2c_client 对象指针,dev 为 spi_device 对象指针;
config 为 regmap_config 结构体对象,是 regmap 注册时的重要结构体;
返回值为 struct regmap 指针。

void regmap_exit(struct regmap *map);

2. regmap 读写接口

regmap 读写接口屏蔽了 i2c 和 spi 读写的具体细节,提供统一接口,

/**
 * regmap_write() - Write a value to a single register
 *
 * @map: Register map to write to
 * @reg: Register to write to
 * @val: Value to be written
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);

/**
 * regmap_read() - Read a value from a single register
 *
 * @map: Register map to read from
 * @reg: Register to be read from
 * @val: Pointer to store read value
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);

3. wm8960 驱动中 regmap 的使用

/sound/soc/codec/wm8960.c 中使用 regmap 如下:

struct wm8960_priv {
    
    
    ...
	struct regmap *regmap;
};

/*
 * wm8960 register cache
 * We can't read the WM8960 register space when we are
 * using 2 wire for device control, so we cache them instead.
 */
static const struct reg_default wm8960_reg_defaults[] = {
    
    
	/* reg addr - reg default val */
	{
    
      0x0, 0x00a7 },
	{
    
      0x1, 0x00a7 },
	...
};

static bool wm8960_volatile(struct device *dev, unsigned int reg)
{
    
    
	switch (reg) {
    
    
	case WM8960_RESET:
		return true;
	default:
		return false;
	}
}

static const struct regmap_config wm8960_regmap = {
    
    
	.reg_bits = 7,	//寄存器地址位数
	.val_bits = 9,	//寄存器 val 位数
	.max_register = WM8960_PLL4,	//寄存器最大地址

	.reg_defaults = wm8960_reg_defaults, //上电时寄存器默认值,使用cache会使用
	.num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults), //reg_defaults的元素个数
	.cache_type = REGCACHE_RBTREE,	//cache方式,使用红黑树

	.volatile_reg = wm8960_volatile,
};

static int wm8960_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
    
    
	struct wm8960_priv *wm8960;
	...
	wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
	if (IS_ERR(wm8960->regmap))
		return PTR_ERR(wm8960->regmap);
	...

	/* Latch the update bits */
	regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100);
	regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100);
	...
}

4.ragmap中的cache使用

/* An enum of all the supported cache types */
enum regcache_type {
    
    
	REGCACHE_NONE,	//不使用缓存
	REGCACHE_RBTREE, //使用红黑树
	REGCACHE_COMPRESSED, //使用LZO 压缩
	REGCACHE_FLAT, //本质上是数组
};
  • 经过 regmap cache,提高访问效率,对于写操作,待cache存在一定数据量或者超出时间后写入物理寄存器,但降低实时性。
  • 不经过 regmap cache,对于写操作,立即写入物理寄存器,实时性好。

cache同步

/**
 * regcache_sync - Sync the register cache with the hardware.
 *
 * @map: map to configure.
 *
 * Any registers that should not be synced should be marked as
 * volatile.  In general drivers can choose not to use the provided
 * syncing functionality if they so require.
 *
 * Return a negative value on failure, 0 on success.
 */
int regcache_sync(struct regmap *map);

/**
 * regcache_sync_region - Sync part  of the register cache with the hardware.
 *
 * @map: map to sync.
 * @min: first register to sync
 * @max: last register to sync
 *
 * Write all non-default register values in the specified region to
 * the hardware.
 *
 * Return a negative value on failure, 0 on success.
 */
int regcache_sync_region(struct regmap *map, unsigned int min,
			 unsigned int max);

参考链接:regmap 使用

猜你喜欢

转载自blog.csdn.net/weixin_45437140/article/details/124417193