staticint regcache_hw_init(struct regmap *map)
{ int i, j; int ret; int count; unsignedint reg, val; void *tmp_buf;
if (!map->num_reg_defaults_raw) return -EINVAL;
/* calculate the size of reg_defaults */ for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) if (regmap_readable(map, i * map->reg_stride) &&
!regmap_volatile(map, i * map->reg_stride))
count++;
/* all registers are unreadable or volatile, so just bypass */ if (!count) {
map->cache_bypass = true; return 0;
}
int regcache_init(struct regmap *map, conststruct regmap_config *config)
{ int ret; int i; void *tmp_buf;
if (map->cache_type == REGCACHE_NONE) { if (config->reg_defaults || config->num_reg_defaults_raw)
dev_warn(map->dev, "No cache used with register defaults set!\n");
map->cache_bypass = true; return 0;
}
if (config->reg_defaults && !config->num_reg_defaults) {
dev_err(map->dev, "Register defaults are set without the number!\n"); return -EINVAL;
}
if (config->num_reg_defaults && !config->reg_defaults) {
dev_err(map->dev, "Register defaults number are set without the reg!\n"); return -EINVAL;
}
for (i = 0; i < config->num_reg_defaults; i++) if (config->reg_defaults[i].reg % map->reg_stride) return -EINVAL;
for (i = 0; i < ARRAY_SIZE(cache_types); i++) if (cache_types[i]->type == map->cache_type) break;
if (i == ARRAY_SIZE(cache_types)) {
dev_err(map->dev, "Could not match cache type: %d\n",
map->cache_type); return -EINVAL;
}
if (!map->cache_ops->read ||
!map->cache_ops->write ||
!map->cache_ops->name) return -EINVAL;
/* We still need to ensure that the reg_defaults * won't vanish from under us. We'll need to make * a copy of it.
*/ if (config->reg_defaults) {
tmp_buf = kmemdup_array(config->reg_defaults, map->num_reg_defaults, sizeof(*map->reg_defaults), GFP_KERNEL); if (!tmp_buf) return -ENOMEM;
map->reg_defaults = tmp_buf;
} elseif (map->num_reg_defaults_raw) { /* Some devices such as PMICs don't have cache defaults, * we cope with this by reading back the HW registers and * crafting the cache defaults by hand.
*/
ret = regcache_hw_init(map); if (ret < 0) return ret; if (map->cache_bypass) return 0;
}
/** * regcache_read - Fetch the value of a given register from the cache. * * @map: map to configure. * @reg: The register index. * @value: The value to be returned. * * Return a negative value on failure, 0 on success.
*/ int regcache_read(struct regmap *map, unsignedint reg, unsignedint *value)
{ int ret;
if (map->cache_type == REGCACHE_NONE) return -EINVAL;
BUG_ON(!map->cache_ops);
if (!regmap_volatile(map, reg)) {
ret = map->cache_ops->read(map, reg, value);
if (ret == 0)
trace_regmap_reg_read_cache(map, reg, *value);
return ret;
}
return -EINVAL;
}
/** * regcache_write - Set the value of a given register in the cache. * * @map: map to configure. * @reg: The register index. * @value: The new register value. * * Return a negative value on failure, 0 on success.
*/ int regcache_write(struct regmap *map, unsignedint reg, unsignedint value)
{ if (map->cache_type == REGCACHE_NONE) return 0;
BUG_ON(!map->cache_ops);
if (!regmap_volatile(map, reg)) return map->cache_ops->write(map, reg, value);
/* If we don't know the chip just got reset, then sync everything. */ if (!map->no_sync_defaults) returntrue;
/* Is this the hardware default? If so skip. */
ret = regcache_lookup_reg(map, reg); if (ret >= 0 && val == map->reg_defaults[ret].def) returnfalse; returntrue;
}
/** * regcache_sync - Sync the register cache with the hardware. * * @map: map to configure. * * Any registers that should not be synced should be marked as * volatile. In general drivers can choose not to use the provided * syncing functionality if they so require. * * Return a negative value on failure, 0 on success.
*/ int regcache_sync(struct regmap *map)
{ int ret = 0; unsignedint i; constchar *name; bool bypass; struct rb_node *node;
if (WARN_ON(map->cache_type == REGCACHE_NONE)) return -EINVAL;
BUG_ON(!map->cache_ops);
map->lock(map->lock_arg); /* Remember the initial bypass state */
bypass = map->cache_bypass;
dev_dbg(map->dev, "Syncing %s cache\n",
map->cache_ops->name);
name = map->cache_ops->name;
trace_regcache_sync(map, name, "start");
if (!map->cache_dirty) goto out;
/* Apply any patch first */
map->cache_bypass = true; for (i = 0; i < map->patch_regs; i++) {
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n",
map->patch[i].reg, map->patch[i].def, ret); goto out;
}
}
map->cache_bypass = false;
if (map->cache_ops->sync)
ret = map->cache_ops->sync(map, 0, map->max_register); else
ret = regcache_default_sync(map, 0, map->max_register);
if (ret == 0)
map->cache_dirty = false;
out: /* Restore the bypass state */
map->cache_bypass = bypass;
map->no_sync_defaults = false;
/* * If we did any paging with cache bypassed and a cached * paging register then the register and cache state might * have gone out of sync, force writes of all the paging * registers.
*/
rb_for_each(node, NULL, &map->range_tree, rbtree_all) { struct regmap_range_node *this =
rb_entry(node, struct regmap_range_node, node);
/* If there's nothing in the cache there's nothing to sync */ if (regcache_read(map, this->selector_reg, &i) != 0) continue;
ret = _regmap_write(map, this->selector_reg, i); if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n",
this->selector_reg, i, ret); break;
}
}
map->unlock(map->lock_arg);
regmap_async_complete(map);
trace_regcache_sync(map, name, "stop");
return ret;
}
EXPORT_SYMBOL_GPL(regcache_sync);
/** * regcache_sync_region - Sync part of the register cache with the hardware. * * @map: map to sync. * @min: first register to sync * @max: last register to sync * * Write all non-default register values in the specified region to * the hardware. * * Return a negative value on failure, 0 on success.
*/ int regcache_sync_region(struct regmap *map, unsignedint min, unsignedint max)
{ int ret = 0; constchar *name; bool bypass;
if (WARN_ON(map->cache_type == REGCACHE_NONE)) return -EINVAL;
BUG_ON(!map->cache_ops);
map->lock(map->lock_arg);
/* Remember the initial bypass state */
bypass = map->cache_bypass;
name = map->cache_ops->name;
dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
trace_regcache_sync(map, name, "start region");
if (!map->cache_dirty) goto out;
map->async = true;
if (map->cache_ops->sync)
ret = map->cache_ops->sync(map, min, max); else
ret = regcache_default_sync(map, min, max);
out: /* Restore the bypass state */
map->cache_bypass = bypass;
map->async = false;
map->no_sync_defaults = false;
map->unlock(map->lock_arg);
/** * regcache_drop_region - Discard part of the register cache * * @map: map to operate on * @min: first register to discard * @max: last register to discard * * Discard part of the register cache. * * Return a negative value on failure, 0 on success.
*/ int regcache_drop_region(struct regmap *map, unsignedint min, unsignedint max)
{ int ret = 0;
if (!map->cache_ops || !map->cache_ops->drop) return -EINVAL;
/** * regcache_cache_only - Put a register map into cache only mode * * @map: map to configure * @enable: flag if changes should be written to the hardware * * When a register map is marked as cache only writes to the register * map API will only update the register cache, they will not cause * any hardware changes. This is useful for allowing portions of * drivers to act as though the device were functioning as normal when * it is disabled for power saving reasons.
*/ void regcache_cache_only(struct regmap *map, bool enable)
{
map->lock(map->lock_arg);
WARN_ON(map->cache_type != REGCACHE_NONE &&
map->cache_bypass && enable);
map->cache_only = enable;
trace_regmap_cache_only(map, enable);
map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_cache_only);
/** * regcache_mark_dirty - Indicate that HW registers were reset to default values * * @map: map to mark * * Inform regcache that the device has been powered down or reset, so that * on resume, regcache_sync() knows to write out all non-default values * stored in the cache. * * If this function is not called, regcache_sync() will assume that * the hardware state still matches the cache state, modulo any writes that * happened when cache_only was true.
*/ void regcache_mark_dirty(struct regmap *map)
{
map->lock(map->lock_arg);
map->cache_dirty = true;
map->no_sync_defaults = true;
map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);
/** * regcache_cache_bypass - Put a register map into cache bypass mode * * @map: map to configure * @enable: flag if changes should not be written to the cache * * When a register map is marked with the cache bypass option, writes * to the register map API will only update the hardware and not * the cache directly. This is useful when syncing the cache back to * the hardware.
*/ void regcache_cache_bypass(struct regmap *map, bool enable)
{
map->lock(map->lock_arg);
WARN_ON(map->cache_only && enable);
map->cache_bypass = enable;
trace_regmap_cache_bypass(map, enable);
map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
/** * regcache_reg_cached - Check if a register is cached * * @map: map to check * @reg: register to check * * Reports if a register is cached.
*/ bool regcache_reg_cached(struct regmap *map, unsignedint reg)
{ unsignedint val; int ret;
map->lock(map->lock_arg);
ret = regcache_read(map, reg, &val);
map->unlock(map->lock_arg);
return ret == 0;
}
EXPORT_SYMBOL_GPL(regcache_reg_cached);
void regcache_set_val(struct regmap *map, void *base, unsignedint idx, unsignedint val)
{ /* Use device native format if possible */ if (map->format.format_val) {
map->format.format_val(base + (map->cache_word_size * idx),
val, 0); return;
}
switch (map->cache_word_size) { case 1: {
u8 *cache = base;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.