regcache_hw_init有些i2c设备的寄存器是volatile的,是不能cache的.1,先计算不是volatile类型的寄存器个数轮询0到map->num_reg_defaults_raw,并用regmap_volatile判断当前的寄存器是否是volatile的.记录下不是volatile的寄存器的个数.如果全部寄存器都是volatile的,那直接返回没必要在往下走.2,调用kmalloc_array分配count个reg_default寄存器所占的空间.3, reg_defaults_raw描述的寄存器默认的原始值为空时.需要分配出来并调用regmap_raw_read拿到该raw数据.4,填充寄存器值.调用regcache_get_val从raw数据中拿到对应寄存器的值并写到对应的def中.regmap_raw_readregmap_raw_read1,如果目标寄存器index是volatile范围的,或者i2c设备配置是bypass的,或者i2c设备的cache类型是REGCACHE_NONE,这些含义是没有cache的.直接调用_regmap_raw_read从硬件读取2,否则的话语_regmap_read从cache中读取.并调用map->format.format_val取出格式化的val值._regmap_raw_read1,从红黑树中找到当前reg的node.2,如果拿到了node,调用_regmap_select_page修正reg的值,该reg和window相操作.3,调用map->format.format_reg描述的格式化的寄存器.比如地址+值 是 6+74,调用map->bus->read描述的read操作.regcache_get_valregcache_get_val_regmap_select_page_regmap_select_pageReg是当前寄存器的index,Range_min是当前i2c范围的开始地址,window_len是”窗”的长度.1,计算偏移 win_offset = (*reg - range->range_min) % range->window_len; win_page = (*reg - range->range_min) / range->window_len;2,如果目标寄存器跨越1个寄存器(超过4个字节了)调用_regmap_update_bits来拿到新的数据._regmap_update_bits调用_regmap_read先从i2c中目标寄存器中读出值orig,然后把该值orig掩码掉mask,然后或上val,将得到的结果调用_regmap_write写入到目标寄存器. _regmap_write写有两种方式,一种通过cache,一种不过cache.这里的cache并不是cpu中的那种,是一种缓冲的机制.1,调用_regmap_map_get_context拿到上下文.这个context是为了在没有cache情况下,或者cache_only为false情况下,通过reg_write来写时,会用到这个context._regmap_map_get_contextreturn (map->bus) ? map : map->bus_context; // 如果bus存在返回map,不存在,返回bus_context2,调用regmap_writeable判断是否可写,不可写就返回EIO错误.regmap_writeable可写满足条件:map->max_register存在且reg<=map->max_register如果map->writeable_reg存在,返回map->writeable_reg()针对reg这个index的结果如果map->writeable_reg不存在,但是map->wr_table存在,调用regmap_check_range_table返回reg这个index在table中的结果.如果都不存在,默认是true.regmap_check_range_table1,针对yes_range和no_range做基本的判断2,调用regmap_reg_in_ranges来判断reg描述的index是否在range内.其中regmap_reg_in_ranges比较reg这个index是否处于(ange->range_min ,range->range_max)间.3,针对cache写情况,调用regcache_write来写.regcache_write调用map->cache_ops->write()函数.4,不经cachemap->reg_write(context, reg, val);在regmap_init中根据不同的情况Reg_write会被赋予:reg_writemap->format.format_write 存在时, _regmap_bus_formatted_write map->format.format_val存在时, _regmap_bus_raw_write(!bus->read || !bus->write)时, _regmap_bus_reg_write // 这个bus代表前边的regmap_i2c描述的i2c的bus(!bus)时, map->reg_write = config->reg_write;_regmap_bus_formatted_write直接调用regmap_i2c的map->bus->write描述的regmap_i2c_write._regmap_bus_raw_write_regmap_bus_raw_write 调用_regmap_raw_write.在_regmap_raw_write中,一个比较关键的数据结构是void *work_val = map->work_buf + map->format.reg_bytes + map->format.pad_bytes; // 拿到要写入值的容器的地址这个pad_bytes来源于configmap->format.pad_bytes = config->pad_bits / 8;1,如果不是cache_bypass,并且format_parse_val存在.调用map->format.parse_val()先带写入的val格式化成一个ival.然后调用regcache_write向目标reg写入这个格式化后的ival.如果cache_only为true,直接返回.2,其他情况,从regmap中的红黑树中拿到reg对应的node.找到其对应的win_offset win_residue,如果目标reg所含有的值的长度超过了一个”窗”的长度,需要递归调用_regmap_raw_write写入目标值.如果没有超过”窗长度”,调用_regmap_select_page来修正描述寄存器index的reg为相对于当前window的偏移.3,调用format.format_reg把reg描述的寄存器地址偏移格式化(如果在红黑树中,reg描述的是据当前窗体的偏移,如果不在红黑树中,reg描述的是寄存器的index偏移地址.)4,如果只对一个寄存器”写”操作,就直接调用i2c的write操作,否则调用i2c的gather_write操作.(核心的写操作)if (val == work_val) ret = map->bus->write(map->bus_context, map->work_buf, map->format.reg_bytes + map->format.pad_bytes + val_len); else if (map->bus->gather_write) ret = map->bus->gather_write(map->bus_context, map->work_buf, map->format.reg_bytes + map->format.pad_bytes, val, val_len);_regmap_bus_reg_write调用map->bus->reg_write函数但是regmap_i2c没有此函数总结,regmap的write操作:1,先尝试向缓冲cache中write.2,如果bypass了,或者volatile,或者cache none情况,调用对应的底层协议的写( I2C、SPI、AC97、MMIO 和 SPMI 等),这里是i2c_regmap_read_regmap_read1,先拿到context,在以后的map->reg_read会用到2,如果不是bypass的,调用regcache_read从cache中读3,如果不能从cache中read到,调用map->reg_readmap->reg_read的来源有三种: if (!bus) { map->reg_read = config->reg_read; // bus不存在时从config中… } else if (!bus->read || !bus->write) { map->reg_read = _regmap_bus_reg_read; // bus存在,依据bus的read,(i2c的read)… } else { map->reg_read = _regmap_bus_read; // 默认 }_regmap_bus_reg_read调用map->bus->reg_read_regmap_bus_read调用_regmap_raw_read调用map->bus->readMacroDIV_ROUND_UP#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))devm_regmap_init_i2cdevm_regmap_init_i2c1,调用regmap_get_i2c_bus从i2c中拿到regmap_bus.struct regmap_bus { // 描述的regmap的write read的底层机制 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_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;};2,调用devm_regmap_init对regmap进行初始化.主要是把config和描述i2c设备的bus设置到regmap中.
描述driver/led设备的led_classdev结构体.struct led_classdev { const char *name; enum led_brightness brightness; // 亮度的刻度,不同刻度的亮度 enum led_brightness max_brightness; int flags; /* Lower 16 bits reflect status */#define LED_SUSPENDED (1 << 0) /* Upper 16 bits reflect control information */#define LED_CORE_SUSPENDRESUME (1 << 16)#define LED_BLINK_ONESHOT (1 << 17)#define LED_BLINK_ONESHOT_STOP (1 << 18)#define LED_BLINK_INVERT (1 << 19)#define LED_SYSFS_DISABLE (1 << 20)#define SET_BRIGHTNESS_ASYNC (1 << 21)#define SET_BRIGHTNESS_SYNC (1 << 22)#define LED_DEV_CAP_FLASH (1 << 23) /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ void (*brightness_set)(struct led_classdev *led_cdev, enum led_brightness brightness); // 设置亮度的函数 /* * Set LED brightness level immediately - it can block the caller for * the time required for accessing a LED device register. */ int (*brightness_set_sync)(struct led_classdev *led_cdev, enum led_brightness brightness); // 同步设置亮度函数 /* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); // 获得当前亮度等级 /* * Activate hardware accelerated blink, delays are in milliseconds * and if both are zero then a sensible default should be chosen. * The call should adjust the timings in that case and if it can't * match the values specified exactly. * Deactivate blinking again when the brightness is set to a fixed * value via the brightness_set() callback. */ int (*blink_set)(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off); // 设置闪烁的延迟ms. struct device *dev; const struct attribute_group **groups; struct list_head node; /* LED Device list */ const char *default_trigger; /* Trigger to use */ unsigned long blink_delay_on, blink_delay_off; struct timer_list blink_timer; int blink_brightness; void (*flash_resume)(struct led_classdev *led_cdev); struct work_struct set_brightness_work; int delayed_set_value;#ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */ struct rw_semaphore trigger_lock; struct led_trigger *trigger; // 激活 熄灭led等操作的结构体 struct list_head trig_list; void *trigger_data; /* true if activated - deactivate routine uses it to do cleanup */ bool activated;#endif /* Ensures consistent access to the LED Flash Class device */ struct mutex led_access;};struct led_trigger { /* Trigger Properties */ const char *name; void (*activate)(struct led_classdev *led_cdev); // 激活led void (*deactivate)(struct led_classdev *led_cdev); // 熄灭led /* LEDs under control by this trigger (for simple triggers) */ rwlock_t leddev_list_lock; struct list_head led_cdevs; /* Link to next registered trigger */ struct list_head next_trig;};i2c_set_clientdatastatic inline void i2c_set_clientdata(struct i2c_client *dev, void *data){ dev_set_drvdata(&dev->dev, data);}static inline void dev_set_drvdata(struct device *dev, void *data){ dev->driver_data = data;}devm_led_classdev_registerdevm_led_classdev_register1,调用devres_alloc分配led_classdev结构体.并把devm_led_classdev_release设置成led_classdev的devres_node成员结构体的release方法.当device_ktype的device_release -> devres_release_all -> release_nodes -> 该release方法.2,调用led_classdev_register注册led_cdev描述的led字符设备.led_classdev_register1,调用led_classdev_next_name设置name2,调用device_create_with_groups创建device3,把当前led字符设备描述的node加到leds_list描述的led设备链中. list_add_tail(&led_cdev->node, &leds_list);4,更新led的亮度,调用led_update_brightness5,调用setup_timer创建led的timer, led_timer_function,而timer是led_cdev->blink_timer.#define __setup_timer(_timer, _fn, _data, _flags) \ do { \ __init_timer((_timer), (_flags)); \ (_timer)->function = (_fn); \ 设置function (_timer)->data = (_data); \ 设置data } while (0)__init_timer -> init_timer_key -> do_init_timerdo_init_timerstatic DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases;#define raw_cpu_read(pcp) __pcpu_size_call_return(raw_cpu_read_, pcp)每cpu变量是raw_cpu_read_4_ tvec_bases,用这个值和flags与,然后初始化timer的base字段.struct tvec_base { spinlock_t lock; struct timer_list *running_timer; unsigned long timer_jiffies; unsigned long next_timer; unsigned long active_timers; unsigned long all_timers; int cpu; struct tvec_root tv1; struct tvec tv2; struct tvec tv3; struct tvec tv4; struct tvec tv5;} ____cacheline_aligned;