*参照元 [#o1cfe50a] #backlinks *説明 [#zc9e359e] -パス: [[linux-4.4.1/drivers/base/regmap/regmap.c]] -FIXME: これは何? --説明 **引数 [#g88475c7] -struct device *dev -- --[[linux-4.4.1/device]] -const struct regmap_bus *bus -- --[[linux-4.4.1/regmap_bus]] -void *bus_context -- -const struct regmap_config *config -- --[[linux-4.4.1/regmap_config]] -struct lock_class_key *lock_key -- --[[linux-4.4.1/lock_class_key]] -const char *lock_name -- **返り値 [#ub55c3aa] -struct regmap * -- --[[linux-4.4.1/regmap]] **参考 [#m26fa42e] *実装 [#o61988bc] struct regmap *__regmap_init(struct device *dev, const struct regmap_bus *bus, void *bus_context, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name) { struct regmap *map; int ret = -EINVAL; enum regmap_endian reg_endian, val_endian; int i, j; - --[[linux-4.4.1/regmap]] --[[linux-4.4.1/regmap_endian]] if (!config) goto err; map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) { ret = -ENOMEM; goto err; } - --[[linux-4.4.1/kzalloc()]] if (config->lock && config->unlock) { map->lock = config->lock; map->unlock = config->unlock; map->lock_arg = config->lock_arg; } else { if ((bus && bus->fast_io) || config->fast_io) { spin_lock_init(&map->spinlock); map->lock = regmap_lock_spinlock; map->unlock = regmap_unlock_spinlock; lockdep_set_class_and_name(&map->spinlock, lock_key, lock_name); } else { mutex_init(&map->mutex); map->lock = regmap_lock_mutex; map->unlock = regmap_unlock_mutex; lockdep_set_class_and_name(&map->mutex, lock_key, lock_name); } map->lock_arg = map; } - --[[linux-4.4.1/spin_lock_init()]] --[[linux-4.4.1/regmap_lock_spinlock()]] --[[linux-4.4.1/regmap_unlock_spinlock()]] --[[linux-4.4.1/regmap_lock_mutex()]] --[[linux-4.4.1/regmap_unlock_mutex()]] --[[linux-4.4.1/lockdep_set_class_and_name()]] /* * When we write in fast-paths with regmap_bulk_write() don't allocate * scratch buffers with sleeping allocations. */ if ((bus && bus->fast_io) || config->fast_io) map->alloc_flags = GFP_ATOMIC; else map->alloc_flags = GFP_KERNEL; map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); map->format.pad_bytes = config->pad_bits / 8; map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); map->format.buf_size = DIV_ROUND_UP(config->reg_bits + config->val_bits + config->pad_bits, 8); map->reg_shift = config->pad_bits % 8; - --map->format は struct regmap_format 型 --[[linux-4.4.1/regmap_format]] --[[linux-4.4.1/DIV_ROUND_UP()]] if (config->reg_stride) map->reg_stride = config->reg_stride; else map->reg_stride = 1; map->use_single_read = config->use_single_rw || !bus || !bus->read; map->use_single_write = config->use_single_rw || !bus || !bus->write; map->can_multi_write = config->can_multi_write && bus && bus->write; if (bus) { map->max_raw_read = bus->max_raw_read; map->max_raw_write = bus->max_raw_write; } map->dev = dev; map->bus = bus; map->bus_context = bus_context; map->max_register = config->max_register; map->wr_table = config->wr_table; map->rd_table = config->rd_table; map->volatile_table = config->volatile_table; map->precious_table = config->precious_table; map->writeable_reg = config->writeable_reg; map->readable_reg = config->readable_reg; map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; map->cache_type = config->cache_type; map->name = config->name; spin_lock_init(&map->async_lock); INIT_LIST_HEAD(&map->async_list); INIT_LIST_HEAD(&map->async_free); init_waitqueue_head(&map->async_waitq); - --[[linux-4.4.1/spin_lock_init()]] --[[linux-4.4.1/INIT_LIST_HEAD()]] --[[linux-4.4.1/init_waitqueue_head()]] if (config->read_flag_mask || config->write_flag_mask) { map->read_flag_mask = config->read_flag_mask; map->write_flag_mask = config->write_flag_mask; } else if (bus) { map->read_flag_mask = bus->read_flag_mask; } if (!bus) { map->reg_read = config->reg_read; map->reg_write = config->reg_write; map->defer_caching = false; goto skip_format_initialization; } else if (!bus->read || !bus->write) { map->reg_read = _regmap_bus_reg_read; map->reg_write = _regmap_bus_reg_write; map->defer_caching = false; goto skip_format_initialization; } else { map->reg_read = _regmap_bus_read; map->reg_update_bits = bus->reg_update_bits; } reg_endian = regmap_get_reg_endian(bus, config); val_endian = regmap_get_val_endian(dev, bus, config); - --[[linux-4.4.1/regmap_get_reg_endian()]] --[[linux-4.4.1/regmap_get_val_endian()]] switch (config->reg_bits + map->reg_shift) { case 2: switch (config->val_bits) { case 6: map->format.format_write = regmap_format_2_6_write; break; default: goto err_map; } break; - --map->format は struct regmap_format 型 --[[linux-4.4.1/regmap_format]] --[[linux-4.4.1/regmap_format_2_6_write()]] case 4: switch (config->val_bits) { case 12: map->format.format_write = regmap_format_4_12_write; break; default: goto err_map; } break; - --[[linux-4.4.1/regmap_format_4_12_write()]] case 7: switch (config->val_bits) { case 9: map->format.format_write = regmap_format_7_9_write; break; default: goto err_map; } break; - --[[linux-4.4.1/regmap_format_7_9_write()]] case 10: switch (config->val_bits) { case 14: map->format.format_write = regmap_format_10_14_write; break; default: goto err_map; } break; - --[[linux-4.4.1/regmap_format_10_14_write()]] case 8: map->format.format_reg = regmap_format_8; break; - --[[linux-4.4.1/regmap_format_8()]] case 16: switch (reg_endian) { case REGMAP_ENDIAN_BIG: map->format.format_reg = regmap_format_16_be; break; case REGMAP_ENDIAN_NATIVE: map->format.format_reg = regmap_format_16_native; break; default: goto err_map; } break; - --[[linux-4.4.1/regmap_format_16_be()]] --[[linux-4.4.1/regmap_format_16_native()]] case 24: if (reg_endian != REGMAP_ENDIAN_BIG) goto err_map; map->format.format_reg = regmap_format_24; break; - --[[linux-4.4.1/regmap_format_24()]] case 32: switch (reg_endian) { case REGMAP_ENDIAN_BIG: map->format.format_reg = regmap_format_32_be; break; case REGMAP_ENDIAN_NATIVE: map->format.format_reg = regmap_format_32_native; break; default: goto err_map; } break; - --[[linux-4.4.1/regmap_format_32_be()]] --[[linux-4.4.1/regmap_format_32_native()]] default: goto err_map; } if (val_endian == REGMAP_ENDIAN_NATIVE) map->format.parse_inplace = regmap_parse_inplace_noop; - --map->format は struct regmap_format 型 --[[linux-4.4.1/regmap_format]] --[[linux-4.4.1/regmap_parse_inplace_noop()]] switch (config->val_bits) { case 8: map->format.format_val = regmap_format_8; map->format.parse_val = regmap_parse_8; map->format.parse_inplace = regmap_parse_inplace_noop; break; - --[[linux-4.4.1/regmap_format_8()]] --[[linux-4.4.1/regmap_parse_8()]] --[[linux-4.4.1/regmap_parse_inplace_noop()]] case 16: switch (val_endian) { case REGMAP_ENDIAN_BIG: map->format.format_val = regmap_format_16_be; map->format.parse_val = regmap_parse_16_be; map->format.parse_inplace = regmap_parse_16_be_inplace; break; - --[[linux-4.4.1/regmap_format_16_be()]] --[[linux-4.4.1/regmap_parse_16_be()]] --[[linux-4.4.1/regmap_parse_16_be_inplace()]] case REGMAP_ENDIAN_LITTLE: map->format.format_val = regmap_format_16_le; map->format.parse_val = regmap_parse_16_le; map->format.parse_inplace = regmap_parse_16_le_inplace; break; - --[[linux-4.4.1/regmap_format_16_le()]] --[[linux-4.4.1/regmap_parse_16_le()]] --[[linux-4.4.1/regmap_parse_16_le_inplace()]] case REGMAP_ENDIAN_NATIVE: map->format.format_val = regmap_format_16_native; map->format.parse_val = regmap_parse_16_native; break; - --[[linux-4.4.1/regmap_format_16_native()]] --[[linux-4.4.1/regmap_parse_16_native()]] default: goto err_map; } break; case 24: if (val_endian != REGMAP_ENDIAN_BIG) goto err_map; map->format.format_val = regmap_format_24; map->format.parse_val = regmap_parse_24; break; - --[[linux-4.4.1/regmap_format_16_le()]] --[[linux-4.4.1/regmap_parse_16_le()]] --[[linux-4.4.1/regmap_parse_16_le_inplace()]] case 32: switch (val_endian) { case REGMAP_ENDIAN_BIG: map->format.format_val = regmap_format_32_be; map->format.parse_val = regmap_parse_32_be; map->format.parse_inplace = regmap_parse_32_be_inplace; - --[[linux-4.4.1/regmap_format_32_be()]] --[[linux-4.4.1/regmap_parse_32_be()]] --[[linux-4.4.1/regmap_parse_32_be_inplace()]] break; case REGMAP_ENDIAN_LITTLE: map->format.format_val = regmap_format_32_le; map->format.parse_val = regmap_parse_32_le; map->format.parse_inplace = regmap_parse_32_le_inplace; break; - --[[linux-4.4.1/regmap_format_32_le()]] --[[linux-4.4.1/regmap_parse_32_le()]] --[[linux-4.4.1/regmap_parse_32_le_inplace()]] case REGMAP_ENDIAN_NATIVE: map->format.format_val = regmap_format_32_native; map->format.parse_val = regmap_parse_32_native; break; - --[[linux-4.4.1/regmap_format_32_native()]] --[[linux-4.4.1/regmap_parse_32_native()]] default: goto err_map; } break; } if (map->format.format_write) { if ((reg_endian != REGMAP_ENDIAN_BIG) || (val_endian != REGMAP_ENDIAN_BIG)) goto err_map; map->use_single_write = true; } if (!map->format.format_write && !(map->format.format_reg && map->format.format_val)) goto err_map; map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); if (map->work_buf == NULL) { ret = -ENOMEM; goto err_map; } - --[[linux-4.4.1/kzalloc()]] if (map->format.format_write) { map->defer_caching = false; map->reg_write = _regmap_bus_formatted_write; } else if (map->format.format_val) { map->defer_caching = true; map->reg_write = _regmap_bus_raw_write; } - --[[linux-4.4.1/_regmap_bus_formatted_write()]] --[[linux-4.4.1/_regmap_bus_raw_write()]] skip_format_initialization: map->range_tree = RB_ROOT; for (i = 0; i < config->num_ranges; i++) { const struct regmap_range_cfg *range_cfg = &config->ranges[i]; struct regmap_range_node *new; - --[[linux-4.4.1/regmap_range_cfg]] --[[linux-4.4.1/regmap_range_node]] /* Sanity check */ if (range_cfg->range_max < range_cfg->range_min) { dev_err(map->dev, "Invalid range %d: %d < %d\n", i, range_cfg->range_max, range_cfg->range_min); goto err_range; } - --[[linux-4.4.1/dev_err()]] if (range_cfg->range_max > map->max_register) { dev_err(map->dev, "Invalid range %d: %d > %d\n", i, range_cfg->range_max, map->max_register); goto err_range; } if (range_cfg->selector_reg > map->max_register) { dev_err(map->dev, "Invalid range %d: selector out of map\n", i); goto err_range; } if (range_cfg->window_len == 0) { dev_err(map->dev, "Invalid range %d: window_len 0\n", i); goto err_range; } /* Make sure, that this register range has no selector or data window within its boundary */ for (j = 0; j < config->num_ranges; j++) { unsigned sel_reg = config->ranges[j].selector_reg; unsigned win_min = config->ranges[j].window_start; unsigned win_max = win_min + config->ranges[j].window_len - 1; /* Allow data window inside its own virtual range */ if (j == i) continue; if (range_cfg->range_min <= sel_reg && sel_reg <= range_cfg->range_max) { dev_err(map->dev, "Range %d: selector for %d in window\n", i, j); goto err_range; } if (!(win_max < range_cfg->range_min || win_min > range_cfg->range_max)) { dev_err(map->dev, "Range %d: window for %d in window\n", i, j); goto err_range; } } new = kzalloc(sizeof(*new), GFP_KERNEL); if (new == NULL) { ret = -ENOMEM; goto err_range; } new->map = map; new->name = range_cfg->name; new->range_min = range_cfg->range_min; new->range_max = range_cfg->range_max; new->selector_reg = range_cfg->selector_reg; new->selector_mask = range_cfg->selector_mask; new->selector_shift = range_cfg->selector_shift; new->window_start = range_cfg->window_start; new->window_len = range_cfg->window_len; if (!_regmap_range_add(map, new)) { dev_err(map->dev, "Failed to add range %d\n", i); kfree(new); goto err_range; } - --[[linux-4.4.1/_remap_range_add()]] --[[linux-4.4.1/kfree()]] if (map->selector_work_buf == NULL) { map->selector_work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); if (map->selector_work_buf == NULL) { ret = -ENOMEM; goto err_range; } } } ret = regcache_init(map, config); if (ret != 0) goto err_range; - --[[linux-4.4.1/regcache_init()]] if (dev) { ret = regmap_attach_dev(dev, map, config); if (ret != 0) goto err_regcache; } - --[[linux-4.4.1/regmap_attach_dev()]] return map; err_regcache: regcache_exit(map); - --[[linux-4.4.1/regcache_exit()]] err_range: regmap_range_exit(map); kfree(map->work_buf); - --[[linux-4.4.1/regmap_range_exit()]] err_map: kfree(map); err: return ERR_PTR(ret); - --[[linux-4.4.1/ERR_PTR()]] } EXPORT_SYMBOL_GPL(__regmap_init); - --[[linux-4.4.1/EXPORT_SYMBOL_GPL()]] *コメント [#a5052838]