内核regmap机制

内核regmap机制

2018年01月15日 14:11:49 板砖先生 阅读数:726

版权声明:本文为博主原创文章,转载请附上链接。 https://blog.csdn.net/heabby2010/article/details/79063949

内核版本:3.10.92

内核3.1引入了一套新的API机制:regmap,主要为I2C,SPI,IRQ等操作提供统一接口,提高代码可重用性,减少重复逻辑。

以I2C为例:

要让设备跟I2C通信,以前的办法是调用i2c_transfer接口,其实regmap最终还是调用到i2c_transfer,只不过中间加了一层缓冲,这样统一了接口,减少了底层I/O的操作次数。

在初始化之前,要先填充regmap_config结构体。

先看看定义:

 

 
  1. struct regmap_config {

  2. const char *name;

  3.  
  4. int reg_bits;//寄存器地址位数,必须配置

  5. int reg_stride;

  6. int pad_bits;//寄存器和值之间的填充位数

  7. int val_bits;//寄存器值的位数,必须配置

  8.  
  9. bool (*writeable_reg)(struct device *dev, unsigned int reg);

  10. bool (*readable_reg)(struct device *dev, unsigned int reg);

  11. bool (*volatile_reg)(struct device *dev, unsigned int reg);

  12. bool (*precious_reg)(struct device *dev, unsigned int reg);

  13. regmap_lock lock;

  14. regmap_unlock unlock;

  15. void *lock_arg;

  16.  
  17. int (*reg_read)(void *context, unsigned int reg, unsigned int *val);

  18. int (*reg_write)(void *context, unsigned int reg, unsigned int val);

  19.  
  20. bool fast_io;

  21.  
  22. unsigned int max_register;

  23. const struct regmap_access_table *wr_table;

  24. const struct regmap_access_table *rd_table;

  25. const struct regmap_access_table *volatile_table;

  26. const struct regmap_access_table *precious_table;

  27. const struct reg_default *reg_defaults;

  28. unsigned int num_reg_defaults;

  29. enum regcache_type cache_type;

  30. const void *reg_defaults_raw;

  31. unsigned int num_reg_defaults_raw;

  32.  
  33. u8 read_flag_mask;

  34. u8 write_flag_mask;

  35.  
  36. bool use_single_rw;

  37.  
  38. enum regmap_endian reg_format_endian;

  39. enum regmap_endian val_format_endian;

  40.  
  41. const struct regmap_range_cfg *ranges;

  42. unsigned int num_ranges;

  43. };

注册:

 

 

 
  1. struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,

  2. const struct regmap_config *config)

读写I2C:

 

 

 
  1. int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);//读取reg中的值,保存在val中

  2. int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,

  3. size_t val_len); //从reg中读取val_len长度的数据,保存在val中

  4. int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);//将val写入到reg中

  5. int regmap_raw_write(struct regmap *map, unsigned int reg,

  6. const void *val, size_t val_len);//将val写入到reg中,val长度为val_len

  7. int regmap_update_bits(struct regmap *map, unsigned int reg,

  8. 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吧

 

 
  1. static int regmap_i2c_write(void *context, const void *data, size_t count)

  2. {

  3. struct device *dev = context;

  4. struct i2c_client *i2c = to_i2c_client(dev);

  5. int ret;

  6.  
  7. ret = i2c_master_send(i2c, data, count);

  8. if (ret == count)

  9. return 0;

  10. else if (ret < 0)

  11. return ret;

  12. else

  13. return -EIO;

  14. }

  15. static int regmap_i2c_read(void *context,

  16. const void *reg, size_t reg_size,

  17. void *val, size_t val_size)

  18. {

  19. struct device *dev = context;

  20. struct i2c_client *i2c = to_i2c_client(dev);

  21. struct i2c_msg xfer[2];

  22. int ret;

  23.  
  24. xfer[0].addr = i2c->addr;

  25. xfer[0].flags = 0;

  26. xfer[0].len = reg_size;

  27. xfer[0].buf = (void *)reg;

  28. #ifdef CONFIG_I2C_ROCKCHIP_COMPAT

  29. xfer[0].scl_rate = 100*1000;

  30. #endif

  31.  
  32. xfer[1].addr = i2c->addr;

  33. xfer[1].flags = I2C_M_RD;

  34. xfer[1].len = val_size;

  35. xfer[1].buf = val;

  36. #ifdef CONFIG_I2C_ROCKCHIP_COMPAT

  37. xfer[1].scl_rate = 100*1000;

  38. #endif

  39.  
  40. ret = i2c_transfer(i2c->adapter, xfer, 2);

  41. if (ret == 2)

  42. return 0;

  43. else if (ret < 0)

  44. return ret;

  45. else

  46. return -EIO;

  47. }

熟悉吧,跟我们之前调用I2C的方法是一样的。

你可能感兴趣的:(linux,驱动)