博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
lwn拾遗:[sn3218 led drivers]-api解释-1
阅读量:7117 次
发布时间:2019-06-28

本文共 6856 字,大约阅读时间需要 22 分钟。

hot3.png

前言

针对sn3218涉及到的dts、i2c、regmap等api函数做一些解释。


1,dts

of_get_child_count

拿到子节点的个数,方法是从根节点"\"轮训每个node,记录node个数。

for_each_child_of_node(np, child)

                   num++;

其他的dts api函数以后专门介绍。


2,regmap的api

使用regmap时需要的几个重要的数据结构:

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;  //  如果是fast的io,用spinlock替代mutex          unsigned int max_register;  //  最大的寄存器的index值         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;};

led driver中调用regmap_init_i2c来依据config构建拿到一个regmap结构体。

struct regmap *regmap_init_i2c(struct i2c_client *i2c,                                   const struct regmap_config *config){         const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);          if (IS_ERR(bus))                   return ERR_CAST(bus);          return regmap_init(&i2c->dev, bus, &i2c->dev, config);  //  用regmap_config往regmap结构体中填充}
1,regmap_get_i2c_bus1-1,一般的i2c返回regmap_i2c结构体.1-2,满足val_bits == 16并且寄存器地址是reg_bits == 8,并且I2C_FUNC_SMBUS_WORD_DATA描述的以字为传输单位.此时根据i2c设备的endian来返回不同的regmap结构体:小端: regmap_smbus_word大端: regmap_smbus_word_swapped1-3,如果寄存器值val_bits是8,寄存器地址reg_bits是8,并且是I2C_FUNC_SMBUS_BYTE_DATA描述的字节传输单位.返回regmap_smbus_byte的regmap结构体.static struct   regmap_bus   regmap_i2c = {    //  代表regmap的i2c的bus         .write = regmap_i2c_write,  //  写,regmap最底层的写调用i2c bus的写         .gather_write = regmap_i2c_gather_write,   //  分散写         .read = regmap_i2c_read,         .reg_format_endian_default = REGMAP_ENDIAN_BIG,   //  reg 地址默认大端         .val_format_endian_default = REGMAP_ENDIAN_BIG,   //  reg 的值默认大端};2, regmap_init1,根据config内容来填充regmap结构体.1)锁的选择Config中有lock和unlock函数时,regmap选择config中的lock和unlock函数否则,如果bus中有fast_io,含义是spinlock.则regmap用regmap_lock_spinlock和regmap_unlock_spinlock否则,默认regmap用regmap_lock_mutex和regmap_unlock_mutex2)reg_read和reg_write的选择Bus不存在(这里是i2c 的bus),用config中的reg_read reg_write方法否则,bus存在,用_regmap_bus_reg_read 和_regmap_bus_reg_write 函数,这些函数最终本质上调用bus里的reg_read和reg_write方法,这里是用i2c bus里的.否则,默认只读,调用_regmap_bus_read函数.3)根据config的reg_bits  reg_shift  val_bits来选择regmap的map->format.format_write描述的格式化写操作的函数, map->format.format_reg描述的格式化reg地址的函数, map->format.format_val描述的格式化val值的方法函数,map->format.parse_val描述的解析val值的方法函数, map->format.parse_inplace描述的解析替换的方法函数.2,建立struct regmap_range_node *new描述的红黑树的节点.先调用kzalloc分配空间,然后调用_regmap_range_add在合适的位置插入node.
/* Return 1 if adapter supports everything we need, 0 if not. */static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func){         return (func & i2c_get_functionality(adap)) == func;}
/* Return the functionality mask */static inline u32 i2c_get_functionality(struct i2c_adapter *adap){         return adap->algo->functionality(adap);  //  调用针对i2s总线驱动的functionality函数来判断其返回结果.}//一般的functionality函数,就是直接return一个结果,返回的结果是一个32位的整数,应该每一位表示一种功能,默认的每一位表示功能的含义如下:#define I2C_FUNC_I2C                      0x00000001#define I2C_FUNC_10BIT_ADDR             0x00000002#define I2C_FUNC_PROTOCOL_MANGLING  0x00000004 /* I2C_M_IGNORE_NAK etc. */….默认情况下,是i2s总线就会支持I2C_FUNC_I2C,其他的比较高端的还会有不同功能的组合.
regmap_get_val_endian1,从config中拿到2,从dev的dtb node中拿到3,从bus的default endian中拿到默认是返回big endian
init_waitqueue_head#define init_waitqueue_head(q)                                 \         do {                                                 \                   static struct lock_class_key __key;          \                                                                 \                   __init_waitqueue_head((q), #q, &__key);       \         } while (0)  struct lockdep_subclass_key {         char __one_byte;}; struct lock_class_key {         struct lockdep_subclass_key    subkeys[MAX_LOCKDEP_SUBCLASSES];   //   8};  void __init  _waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key){         spin_lock_init(&q->lock);         lockdep_set_class_and_name(&q->lock, key, name);         INIT_LIST_HEAD(&q->task_list);}
_regmap_range_add利用新建的节点的描述的范围点与regmap结构体中的range_tree描述的红黑树的每个成员节点的描述的范围点来比较,找到合适插入新节点的节点.data->range_max < this->range_mindata->range_min > this->range_max利用rb_link_node插入,利用rb_insert_color使红黑树自平衡struct regmap_range_node {         struct rb_node node;         const char *name;         struct regmap *map;          unsigned int range_min;         unsigned int range_max;          unsigned int selector_reg;         unsigned int selector_mask;         int selector_shift;          unsigned int window_start;         unsigned int window_len;};
regcache_init1,错误检查,如果map->cache_type是REGCACHE_NONE,则肯定是出错的.2, 从cache_types[]描述的缓冲类型数组中找到和map->cache_type匹配的缓冲类型.重要数据结构:static const struct regcache_ops *cache_types[] = {	&regcache_rbtree_ops,    //  红黑树的cache策略,有点查找很快	&regcache_lzo_ops,       //  LZO 是 Lempel-Ziv-Oberhumer 的缩写。这个算法是无损算法.优点:压缩快,解压不需要额外内存。	&regcache_flat_ops,       //  数组};3,用config和找到的cache_type[i]来完善regmap结构体.特别的完善其regcache_ops成员map->cache_ops = cache_types[i];struct regcache_ops {    //   来自于各自cache方法的结构体	const char *name;	enum regcache_type type;	int (*init)(struct regmap *map);	int (*exit)(struct regmap *map);#ifdef CONFIG_DEBUG_FS	void (*debugfs_init)(struct regmap *map);#endif	int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);	int (*write)(struct regmap *map, unsigned int reg, unsigned int value);	int (*sync)(struct regmap *map, unsigned int min, unsigned int max);	int (*drop)(struct regmap *map, unsigned int min, unsigned int max);};4,记录(暂存)当前的设备(i2c,spi等)的寄存器当前值(默认值)kmemdup(config->reg_defaults, map->num_reg_defaults *sizeof(struct reg_default), GFP_KERNEL);对于没有default值的设备,调用regcache_hw_init获取.

转载于:https://my.oschina.net/hainanren/blog/617319

你可能感兴趣的文章
shell命令:sed命令
查看>>
Mysql相关函数使用和总结(cast、convert)
查看>>
Ruby设计模式-观察者模式学习笔记
查看>>
您需要售后返修管理软件的N个理由
查看>>
git 提交项目代码到码云步骤 以及出现错误解决办法
查看>>
线性表
查看>>
ceph
查看>>
如果Google面试让你用python写一个树的遍历程序
查看>>
Java第四次实验
查看>>
为discuz x2.5添加播放附件(mp4)的方法
查看>>
SpringMVC深度探险(一) —— SpringMVC前传
查看>>
面试 框架部分
查看>>
display: flex属性介绍
查看>>
mysql复制表的方法
查看>>
镜像复制+copy命令+镜像复制案例
查看>>
Android APP 中英文切换
查看>>
RabbitMQ学习总结(7)——Spring整合RabbitMQ实例
查看>>
模糊查询,多条件查询
查看>>
java JNI 实现原理 (二) Linux 下如何 load JNILibrary
查看>>
内联函数和函数重载
查看>>