diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/base/regmap/regcache-rbtree.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/base/regmap/regcache-rbtree.c | 430 |
1 files changed, 0 insertions, 430 deletions
diff --git a/ANDROID_3.4.5/drivers/base/regmap/regcache-rbtree.c b/ANDROID_3.4.5/drivers/base/regmap/regcache-rbtree.c deleted file mode 100644 index 92b779ee..00000000 --- a/ANDROID_3.4.5/drivers/base/regmap/regcache-rbtree.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Register cache access API - rbtree caching support - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/slab.h> -#include <linux/device.h> -#include <linux/debugfs.h> -#include <linux/rbtree.h> -#include <linux/seq_file.h> - -#include "internal.h" - -static int regcache_rbtree_write(struct regmap *map, unsigned int reg, - unsigned int value); -static int regcache_rbtree_exit(struct regmap *map); - -struct regcache_rbtree_node { - /* the actual rbtree node holding this block */ - struct rb_node node; - /* base register handled by this block */ - unsigned int base_reg; - /* block of adjacent registers */ - void *block; - /* number of registers available in the block */ - unsigned int blklen; -} __attribute__ ((packed)); - -struct regcache_rbtree_ctx { - struct rb_root root; - struct regcache_rbtree_node *cached_rbnode; -}; - -static inline void regcache_rbtree_get_base_top_reg( - struct regcache_rbtree_node *rbnode, - unsigned int *base, unsigned int *top) -{ - *base = rbnode->base_reg; - *top = rbnode->base_reg + rbnode->blklen - 1; -} - -static unsigned int regcache_rbtree_get_register( - struct regcache_rbtree_node *rbnode, unsigned int idx, - unsigned int word_size) -{ - return regcache_get_val(rbnode->block, idx, word_size); -} - -static void regcache_rbtree_set_register(struct regcache_rbtree_node *rbnode, - unsigned int idx, unsigned int val, - unsigned int word_size) -{ - regcache_set_val(rbnode->block, idx, val, word_size); -} - -static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, - unsigned int reg) -{ - struct regcache_rbtree_ctx *rbtree_ctx = map->cache; - struct rb_node *node; - struct regcache_rbtree_node *rbnode; - unsigned int base_reg, top_reg; - - rbnode = rbtree_ctx->cached_rbnode; - if (rbnode) { - regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); - if (reg >= base_reg && reg <= top_reg) - return rbnode; - } - - node = rbtree_ctx->root.rb_node; - while (node) { - rbnode = container_of(node, struct regcache_rbtree_node, node); - regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); - if (reg >= base_reg && reg <= top_reg) { - rbtree_ctx->cached_rbnode = rbnode; - return rbnode; - } else if (reg > top_reg) { - node = node->rb_right; - } else if (reg < base_reg) { - node = node->rb_left; - } - } - - return NULL; -} - -static int regcache_rbtree_insert(struct rb_root *root, - struct regcache_rbtree_node *rbnode) -{ - struct rb_node **new, *parent; - struct regcache_rbtree_node *rbnode_tmp; - unsigned int base_reg_tmp, top_reg_tmp; - unsigned int base_reg; - - parent = NULL; - new = &root->rb_node; - while (*new) { - rbnode_tmp = container_of(*new, struct regcache_rbtree_node, - node); - /* base and top registers of the current rbnode */ - regcache_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp, - &top_reg_tmp); - /* base register of the rbnode to be added */ - base_reg = rbnode->base_reg; - parent = *new; - /* if this register has already been inserted, just return */ - if (base_reg >= base_reg_tmp && - base_reg <= top_reg_tmp) - return 0; - else if (base_reg > top_reg_tmp) - new = &((*new)->rb_right); - else if (base_reg < base_reg_tmp) - new = &((*new)->rb_left); - } - - /* insert the node into the rbtree */ - rb_link_node(&rbnode->node, parent, new); - rb_insert_color(&rbnode->node, root); - - return 1; -} - -#ifdef CONFIG_DEBUG_FS -static int rbtree_show(struct seq_file *s, void *ignored) -{ - struct regmap *map = s->private; - struct regcache_rbtree_ctx *rbtree_ctx = map->cache; - struct regcache_rbtree_node *n; - struct rb_node *node; - unsigned int base, top; - int nodes = 0; - int registers = 0; - int average; - - mutex_lock(&map->lock); - - for (node = rb_first(&rbtree_ctx->root); node != NULL; - node = rb_next(node)) { - n = container_of(node, struct regcache_rbtree_node, node); - - regcache_rbtree_get_base_top_reg(n, &base, &top); - seq_printf(s, "%x-%x (%d)\n", base, top, top - base + 1); - - nodes++; - registers += top - base + 1; - } - - if (nodes) - average = registers / nodes; - else - average = 0; - - seq_printf(s, "%d nodes, %d registers, average %d registers\n", - nodes, registers, average); - - mutex_unlock(&map->lock); - - return 0; -} - -static int rbtree_open(struct inode *inode, struct file *file) -{ - return single_open(file, rbtree_show, inode->i_private); -} - -static const struct file_operations rbtree_fops = { - .open = rbtree_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void rbtree_debugfs_init(struct regmap *map) -{ - debugfs_create_file("rbtree", 0400, map->debugfs, map, &rbtree_fops); -} -#else -static void rbtree_debugfs_init(struct regmap *map) -{ -} -#endif - -static int regcache_rbtree_init(struct regmap *map) -{ - struct regcache_rbtree_ctx *rbtree_ctx; - int i; - int ret; - - map->cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL); - if (!map->cache) - return -ENOMEM; - - rbtree_ctx = map->cache; - rbtree_ctx->root = RB_ROOT; - rbtree_ctx->cached_rbnode = NULL; - - for (i = 0; i < map->num_reg_defaults; i++) { - ret = regcache_rbtree_write(map, - map->reg_defaults[i].reg, - map->reg_defaults[i].def); - if (ret) - goto err; - } - - rbtree_debugfs_init(map); - - return 0; - -err: - regcache_rbtree_exit(map); - return ret; -} - -static int regcache_rbtree_exit(struct regmap *map) -{ - struct rb_node *next; - struct regcache_rbtree_ctx *rbtree_ctx; - struct regcache_rbtree_node *rbtree_node; - - /* if we've already been called then just return */ - rbtree_ctx = map->cache; - if (!rbtree_ctx) - return 0; - - /* free up the rbtree */ - next = rb_first(&rbtree_ctx->root); - while (next) { - rbtree_node = rb_entry(next, struct regcache_rbtree_node, node); - next = rb_next(&rbtree_node->node); - rb_erase(&rbtree_node->node, &rbtree_ctx->root); - kfree(rbtree_node->block); - kfree(rbtree_node); - } - - /* release the resources */ - kfree(map->cache); - map->cache = NULL; - - return 0; -} - -static int regcache_rbtree_read(struct regmap *map, - unsigned int reg, unsigned int *value) -{ - struct regcache_rbtree_node *rbnode; - unsigned int reg_tmp; - - rbnode = regcache_rbtree_lookup(map, reg); - if (rbnode) { - reg_tmp = reg - rbnode->base_reg; - *value = regcache_rbtree_get_register(rbnode, reg_tmp, - map->cache_word_size); - } else { - return -ENOENT; - } - - return 0; -} - - -static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode, - unsigned int pos, unsigned int reg, - unsigned int value, unsigned int word_size) -{ - u8 *blk; - - blk = krealloc(rbnode->block, - (rbnode->blklen + 1) * word_size, GFP_KERNEL); - if (!blk) - return -ENOMEM; - - /* insert the register value in the correct place in the rbnode block */ - memmove(blk + (pos + 1) * word_size, - blk + pos * word_size, - (rbnode->blklen - pos) * word_size); - - /* update the rbnode block, its size and the base register */ - rbnode->block = blk; - rbnode->blklen++; - if (!pos) - rbnode->base_reg = reg; - - regcache_rbtree_set_register(rbnode, pos, value, word_size); - return 0; -} - -static int regcache_rbtree_write(struct regmap *map, unsigned int reg, - unsigned int value) -{ - struct regcache_rbtree_ctx *rbtree_ctx; - struct regcache_rbtree_node *rbnode, *rbnode_tmp; - struct rb_node *node; - unsigned int val; - unsigned int reg_tmp; - unsigned int pos; - int i; - int ret; - - rbtree_ctx = map->cache; - /* if we can't locate it in the cached rbnode we'll have - * to traverse the rbtree looking for it. - */ - rbnode = regcache_rbtree_lookup(map, reg); - if (rbnode) { - reg_tmp = reg - rbnode->base_reg; - val = regcache_rbtree_get_register(rbnode, reg_tmp, - map->cache_word_size); - if (val == value) - return 0; - regcache_rbtree_set_register(rbnode, reg_tmp, value, - map->cache_word_size); - } else { - /* look for an adjacent register to the one we are about to add */ - for (node = rb_first(&rbtree_ctx->root); node; - node = rb_next(node)) { - rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node); - for (i = 0; i < rbnode_tmp->blklen; i++) { - reg_tmp = rbnode_tmp->base_reg + i; - if (abs(reg_tmp - reg) != 1) - continue; - /* decide where in the block to place our register */ - if (reg_tmp + 1 == reg) - pos = i + 1; - else - pos = i; - ret = regcache_rbtree_insert_to_block(rbnode_tmp, pos, - reg, value, - map->cache_word_size); - if (ret) - return ret; - rbtree_ctx->cached_rbnode = rbnode_tmp; - return 0; - } - } - /* we did not manage to find a place to insert it in an existing - * block so create a new rbnode with a single register in its block. - * This block will get populated further if any other adjacent - * registers get modified in the future. - */ - rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); - if (!rbnode) - return -ENOMEM; - rbnode->blklen = 1; - rbnode->base_reg = reg; - rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size, - GFP_KERNEL); - if (!rbnode->block) { - kfree(rbnode); - return -ENOMEM; - } - regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size); - regcache_rbtree_insert(&rbtree_ctx->root, rbnode); - rbtree_ctx->cached_rbnode = rbnode; - } - - return 0; -} - -static int regcache_rbtree_sync(struct regmap *map, unsigned int min, - unsigned int max) -{ - struct regcache_rbtree_ctx *rbtree_ctx; - struct rb_node *node; - struct regcache_rbtree_node *rbnode; - unsigned int regtmp; - unsigned int val; - int ret; - int i, base, end; - - rbtree_ctx = map->cache; - for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { - rbnode = rb_entry(node, struct regcache_rbtree_node, node); - - if (rbnode->base_reg < min) - continue; - if (rbnode->base_reg > max) - break; - if (rbnode->base_reg + rbnode->blklen < min) - continue; - - if (min > rbnode->base_reg) - base = min - rbnode->base_reg; - else - base = 0; - - if (max < rbnode->base_reg + rbnode->blklen) - end = rbnode->base_reg + rbnode->blklen - max; - else - end = rbnode->blklen; - - for (i = base; i < end; i++) { - regtmp = rbnode->base_reg + i; - val = regcache_rbtree_get_register(rbnode, i, - map->cache_word_size); - - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret >= 0 && val == map->reg_defaults[ret].def) - continue; - - map->cache_bypass = 1; - ret = _regmap_write(map, regtmp, val); - map->cache_bypass = 0; - if (ret) - return ret; - dev_dbg(map->dev, "Synced register %#x, value %#x\n", - regtmp, val); - } - } - - return 0; -} - -struct regcache_ops regcache_rbtree_ops = { - .type = REGCACHE_RBTREE, - .name = "rbtree", - .init = regcache_rbtree_init, - .exit = regcache_rbtree_exit, - .read = regcache_rbtree_read, - .write = regcache_rbtree_write, - .sync = regcache_rbtree_sync -}; |