最近调试模块,用到了regmap,事后了解了一下,觉得还是有点意思的东西
以下是最新的linux源码对于regmap_config的结构,可以看到函数指针以及一些变量
源码中直接搜索"struct regmap_config"是可以搜到其他模块是如何使用这个变量的
也就能看到初始化的时候,初始化了哪些变量.(能看到这里的应该不用一个个解释了吧)
struct regmap_config {
const char *name;
int reg_bits;
int reg_stride;
int reg_shift;
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);
/* Bulk read/write */
int (*read)(void *context, const void *reg_buf, size_t reg_size,
void *val_buf, size_t val_size);
int (*write)(void *context, const void *data, size_t count);
size_t max_raw_read;
size_t max_raw_write;
bool fast_io;
bool io_port;
unsigned int max_register;
bool max_register_is_0;
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;
};
上面的结构是一个基础模块
//可以直接使用下面这个宏初始化ragmap
#define devm_regmap_init(dev, bus, bus_context, config) \
__regmap_lockdep_wrapper(__devm_regmap_init, #config, \
dev, bus, bus_context, config)
//实际的源码中还提供了一些二次封装的实现
#define devm_regmap_init_i2c(i2c, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_i2c, #config, \
i2c, config)
#define devm_regmap_init_mdio(mdio_dev, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_mdio, #config, \
mdio_dev, config)
#define devm_regmap_init_spi(dev, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_spi, #config, \
dev, config)
/*等等等, 可以配合其他模块使用*/
以下是一个demo
/*
这个demo中,我没有注册设备,而是以模块的形式,创建了一个device的结构体用来初始化regmap
目的是为了简单尝试一下regmap的功能,可能不太规范(我还记得我第一任师傅说...我野路子太多了,哈哈)
简单理解一下功能,不深挖细节哈
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/regmap.h>
#define TEST_MEM_SIZE 256
static void *test_regmap_ptr;
static struct device test_device;
/* void *context is init param test_regmap_ptr */
static int test_reg_read(void *context, unsigned int reg, unsigned int *val)
{
uint32_t *base = (uint32_t *)(context);
*val = *(base + (reg/4));
return 0;
}
static int test_reg_write(void *context, unsigned int reg, unsigned int val)
{
uint32_t *base = (uint32_t *)(context);
*(base + (reg/4)) = val;
return 0;
}
static const struct regmap_config config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0xFC,
.reg_read = test_reg_read,
.reg_write = test_reg_write,
.fast_io = true,
};
/*
* This demo just init a memory as rw
* no other function, more sample need to check linux source code
*/
static int __init test_regmap_init(void)
{
int val;
test_regmap_ptr = kmalloc(TEST_MEM_SIZE, GFP_KERNEL);
printk("%s: my_test\n", __func__);
device_initialize(&test_device);
dev_set_name(&test_device, "test_device");
dev_info(&test_device, "This is info\n");
dev_dbg(&test_device, "This is debug\n");
dev_notice(&test_device, "This is notice\n");
dev_warn(&test_device, "This is warn\n");
// val = device_add(&test_device);
// if (val) {
// dev_err(&test_device,
// "device add failed: %d", val);
// }
/*create test_regmap_ptr, as context to init regmap */
struct regmap *map = devm_regmap_init(&test_device, NULL, test_regmap_ptr, &config);
regmap_read(map, 0x00, &val);
printk("0x00:val=%x\n",val);
regmap_read(map, 0x04, &val);
printk("0x04:val=%x\n",val);
regmap_write(map, 0x00, 0x11);
regmap_write(map, 0x04, 0x22);
regmap_read(map, 0x00, &val);
printk("0x00:val=%x\n",val);
regmap_read(map, 0x04, &val);
printk("0x04:val=%x\n",val);
return 0;
}
static void __exit test_regmap_exit(void)
{
}
module_init(test_regmap_init);
module_exit(test_regmap_exit);