內核regmap機制【轉】


轉自:https://blog.csdn.net/heabby2010/article/details/79063949?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

內核版本:3.10.92

內核3.1引入了一套新的API機制:regmap,主要為I2C,SPI,IRQ等操作提供統一接口,提高代碼可重用性,減少重復邏輯。

以I2C為例:

要讓設備跟I2C通信,以前的辦法是調用i2c_transfer接口,其實regmap最終還是調用到i2c_transfer,只不過中間加了一層緩沖,這樣統一了接口,減少了底層I/O的操作次數。

在初始化之前,要先填充regmap_config結構體。

先看看定義:


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;

enum regmap_endian reg_format_endian;
enum regmap_endian val_format_endian;

const struct regmap_range_cfg *ranges;
unsigned int num_ranges;
};
注冊:

struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
讀寫I2C:

int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);//讀取reg中的值,保存在val中
int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
size_t val_len); //從reg中讀取val_len長度的數據,保存在val中
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);//將val寫入到reg中
int regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len);//將val寫入到reg中,val長度為val_len
int regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)//更新reg中指定的位


看下注冊過程:

regmap_init_i2c -> //regmap-i2c.c

regmap_init-> //多了兩個參數,最重要是第二個regmap_bus regmap_i2c,實現了I2C的讀寫,SPI同理

map->reg_read  = _regmap_bus_read; //綁定讀函數

map->reg_write = _regmap_bus_raw_write; //綁定寫函數

 

看下讀寫過程:
讀:

regmap_read ->

_regmap_read ->

map->reg_read -> //初始化時已經綁定_regmap_bus_read

_regmap_bus_read->

_regmap_raw_read ->

map->bus->read    //調用regmap-i2c.c中實現的regmap_i2c.read

 

寫:

regmap_write->
_regmap_write ->

map->reg_write  -> //初始化時已經綁定_regmap_bus_raw_write

_regmap_bus_raw_write->

_regmap_raw_write->

map->bus->write //調用regmap-i2c.c中實現的regmap_i2c.write


最后看看regmap-i2c.c吧


static int regmap_i2c_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
int ret;

ret = i2c_master_send(i2c, data, count);
if (ret == count)
return 0;
else if (ret < 0)
return ret;
else
return -EIO;
}
static int regmap_i2c_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2];
int ret;

xfer[0].addr = i2c->addr;
xfer[0].flags = 0;
xfer[0].len = reg_size;
xfer[0].buf = (void *)reg;
#ifdef CONFIG_I2C_ROCKCHIP_COMPAT
xfer[0].scl_rate = 100*1000;
#endif

xfer[1].addr = i2c->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = val_size;
xfer[1].buf = val;
#ifdef CONFIG_I2C_ROCKCHIP_COMPAT
xfer[1].scl_rate = 100*1000;
#endif

ret = i2c_transfer(i2c->adapter, xfer, 2);
if (ret == 2)
return 0;
else if (ret < 0)
return ret;
else
return -EIO;
}
熟悉吧,跟我們之前調用I2C的方法是一樣的。
————————————————
版權聲明:本文為CSDN博主「板磚先生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/heabby2010/article/details/79063949


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM