From 614e0110234a7540bacb183c0d2eb84f17fd1042 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 28 Nov 2011 18:50:39 +0000 Subject: [PATCH] --- yaml --- r: 280554 b: refs/heads/master c: d23511f9590870effa5ace575b59aac18c47175f h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/base/regmap/Makefile | 3 +- trunk/drivers/base/regmap/internal.h | 6 +- trunk/drivers/base/regmap/regcache-indexed.c | 64 ++++++++++++++ trunk/drivers/base/regmap/regcache-lzo.c | 21 ++--- trunk/drivers/base/regmap/regcache-rbtree.c | 61 +------------ trunk/drivers/base/regmap/regcache.c | 77 ++++++---------- trunk/drivers/base/regmap/regmap-irq.c | 7 +- trunk/drivers/base/regmap/regmap.c | 92 ++++++++------------ trunk/include/linux/regmap.h | 6 +- 10 files changed, 151 insertions(+), 188 deletions(-) create mode 100644 trunk/drivers/base/regmap/regcache-indexed.c diff --git a/[refs] b/[refs] index 3ea70d1ffd25..a09ab9a3447d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: cce585ce1ebd5307c9709e24758d5eb8a1e087a7 +refs/heads/master: d23511f9590870effa5ace575b59aac18c47175f diff --git a/trunk/drivers/base/regmap/Makefile b/trunk/drivers/base/regmap/Makefile index defd57963c84..ce2d18a6465b 100644 --- a/trunk/drivers/base/regmap/Makefile +++ b/trunk/drivers/base/regmap/Makefile @@ -1,5 +1,4 @@ -obj-$(CONFIG_REGMAP) += regmap.o regcache.o -obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o +obj-$(CONFIG_REGMAP) += regmap.o regcache.o regcache-indexed.o regcache-rbtree.o regcache-lzo.o obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o diff --git a/trunk/drivers/base/regmap/internal.h b/trunk/drivers/base/regmap/internal.h index 1a02b7537c8b..348ff02eb93e 100644 --- a/trunk/drivers/base/regmap/internal.h +++ b/trunk/drivers/base/regmap/internal.h @@ -74,7 +74,6 @@ struct regmap { struct reg_default *reg_defaults; const void *reg_defaults_raw; void *cache; - bool cache_dirty; }; struct regcache_ops { @@ -106,7 +105,7 @@ static inline void regmap_debugfs_exit(struct regmap *map) { } #endif /* regcache core declarations */ -int regcache_init(struct regmap *map, const struct regmap_config *config); +int regcache_init(struct regmap *map); void regcache_exit(struct regmap *map); int regcache_read(struct regmap *map, unsigned int reg, unsigned int *value); @@ -119,7 +118,10 @@ unsigned int regcache_get_val(const void *base, unsigned int idx, bool regcache_set_val(void *base, unsigned int idx, unsigned int val, unsigned int word_size); int regcache_lookup_reg(struct regmap *map, unsigned int reg); +int regcache_insert_reg(struct regmap *map, unsigned int reg, + unsigned int val); +extern struct regcache_ops regcache_indexed_ops; extern struct regcache_ops regcache_rbtree_ops; extern struct regcache_ops regcache_lzo_ops; diff --git a/trunk/drivers/base/regmap/regcache-indexed.c b/trunk/drivers/base/regmap/regcache-indexed.c new file mode 100644 index 000000000000..507731ad8ec1 --- /dev/null +++ b/trunk/drivers/base/regmap/regcache-indexed.c @@ -0,0 +1,64 @@ +/* + * Register cache access API - indexed caching support + * + * Copyright 2011 Wolfson Microelectronics plc + * + * Author: Dimitris Papastamos + * + * 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 + +#include "internal.h" + +static int regcache_indexed_read(struct regmap *map, unsigned int reg, + unsigned int *value) +{ + int ret; + + ret = regcache_lookup_reg(map, reg); + if (ret >= 0) + *value = map->reg_defaults[ret].def; + + return ret; +} + +static int regcache_indexed_write(struct regmap *map, unsigned int reg, + unsigned int value) +{ + int ret; + + ret = regcache_lookup_reg(map, reg); + if (ret < 0) + return regcache_insert_reg(map, reg, value); + map->reg_defaults[ret].def = value; + return 0; +} + +static int regcache_indexed_sync(struct regmap *map) +{ + unsigned int i; + int ret; + + for (i = 0; i < map->num_reg_defaults; i++) { + ret = _regmap_write(map, map->reg_defaults[i].reg, + map->reg_defaults[i].def); + if (ret < 0) + return ret; + dev_dbg(map->dev, "Synced register %#x, value %#x\n", + map->reg_defaults[i].reg, + map->reg_defaults[i].def); + } + return 0; +} + +struct regcache_ops regcache_indexed_ops = { + .type = REGCACHE_INDEXED, + .name = "indexed", + .read = regcache_indexed_read, + .write = regcache_indexed_write, + .sync = regcache_indexed_sync +}; diff --git a/trunk/drivers/base/regmap/regcache-lzo.c b/trunk/drivers/base/regmap/regcache-lzo.c index b7d16143edeb..066aeece3626 100644 --- a/trunk/drivers/base/regmap/regcache-lzo.c +++ b/trunk/drivers/base/regmap/regcache-lzo.c @@ -15,8 +15,6 @@ #include "internal.h" -static int regcache_lzo_exit(struct regmap *map); - struct regcache_lzo_ctx { void *wmem; void *dst; @@ -29,7 +27,7 @@ struct regcache_lzo_ctx { }; #define LZO_BLOCK_NUM 8 -static int regcache_lzo_block_count(struct regmap *map) +static int regcache_lzo_block_count(void) { return LZO_BLOCK_NUM; } @@ -108,22 +106,19 @@ static inline int regcache_lzo_get_blkindex(struct regmap *map, unsigned int reg) { return (reg * map->cache_word_size) / - DIV_ROUND_UP(map->cache_size_raw, - regcache_lzo_block_count(map)); + DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()); } static inline int regcache_lzo_get_blkpos(struct regmap *map, unsigned int reg) { - return reg % (DIV_ROUND_UP(map->cache_size_raw, - regcache_lzo_block_count(map)) / + return reg % (DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()) / map->cache_word_size); } static inline int regcache_lzo_get_blksize(struct regmap *map) { - return DIV_ROUND_UP(map->cache_size_raw, - regcache_lzo_block_count(map)); + return DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()); } static int regcache_lzo_init(struct regmap *map) @@ -136,7 +131,7 @@ static int regcache_lzo_init(struct regmap *map) ret = 0; - blkcount = regcache_lzo_block_count(map); + blkcount = regcache_lzo_block_count(); map->cache = kzalloc(blkcount * sizeof *lzo_blocks, GFP_KERNEL); if (!map->cache) @@ -195,7 +190,7 @@ static int regcache_lzo_init(struct regmap *map) return 0; err: - regcache_lzo_exit(map); + regcache_exit(map); return ret; } @@ -208,7 +203,7 @@ static int regcache_lzo_exit(struct regmap *map) if (!lzo_blocks) return 0; - blkcount = regcache_lzo_block_count(map); + blkcount = regcache_lzo_block_count(); /* * the pointer to the bitmap used for syncing the cache * is shared amongst all lzo_blocks. Ensure it is freed @@ -356,7 +351,7 @@ static int regcache_lzo_sync(struct regmap *map) } struct regcache_ops regcache_lzo_ops = { - .type = REGCACHE_COMPRESSED, + .type = REGCACHE_LZO, .name = "lzo", .init = regcache_lzo_init, .exit = regcache_lzo_exit, diff --git a/trunk/drivers/base/regmap/regcache-rbtree.c b/trunk/drivers/base/regmap/regcache-rbtree.c index 32620c4f1683..e31498499b0f 100644 --- a/trunk/drivers/base/regmap/regcache-rbtree.c +++ b/trunk/drivers/base/regmap/regcache-rbtree.c @@ -11,15 +11,12 @@ */ #include -#include #include -#include #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 */ @@ -127,60 +124,6 @@ static int regcache_rbtree_insert(struct rb_root *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; - - 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; - } - - seq_printf(s, "%d nodes, %d registers, average %d registers\n", - nodes, registers, registers / nodes); - - 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; @@ -203,12 +146,10 @@ static int regcache_rbtree_init(struct regmap *map) goto err; } - rbtree_debugfs_init(map); - return 0; err: - regcache_rbtree_exit(map); + regcache_exit(map); return ret; } diff --git a/trunk/drivers/base/regmap/regcache.c b/trunk/drivers/base/regmap/regcache.c index 1ca2d7a1051f..666f6f5011dc 100644 --- a/trunk/drivers/base/regmap/regcache.c +++ b/trunk/drivers/base/regmap/regcache.c @@ -19,6 +19,7 @@ #include "internal.h" static const struct regcache_ops *cache_types[] = { + ®cache_indexed_ops, ®cache_rbtree_ops, ®cache_lzo_ops, }; @@ -60,10 +61,8 @@ static int regcache_hw_init(struct regmap *map) map->reg_defaults = kmalloc(count * sizeof(struct reg_default), GFP_KERNEL); - if (!map->reg_defaults) { - ret = -ENOMEM; - goto err_free; - } + if (!map->reg_defaults) + return -ENOMEM; /* fill the reg_defaults */ map->num_reg_defaults = count; @@ -78,15 +77,9 @@ static int regcache_hw_init(struct regmap *map) } return 0; - -err_free: - if (map->cache_free) - kfree(map->reg_defaults_raw); - - return ret; } -int regcache_init(struct regmap *map, const struct regmap_config *config) +int regcache_init(struct regmap *map) { int ret; int i; @@ -107,12 +100,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) return -EINVAL; } - map->num_reg_defaults = config->num_reg_defaults; - map->num_reg_defaults_raw = config->num_reg_defaults_raw; - map->reg_defaults_raw = config->reg_defaults_raw; - map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8); - map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw; - map->cache = NULL; map->cache_ops = cache_types[i]; @@ -125,10 +112,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) * won't vanish from under us. We'll need to make * a copy of it. */ - if (config->reg_defaults) { + if (map->reg_defaults) { if (!map->num_reg_defaults) return -EINVAL; - tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults * + tmp_buf = kmemdup(map->reg_defaults, map->num_reg_defaults * sizeof(struct reg_default), GFP_KERNEL); if (!tmp_buf) return -ENOMEM; @@ -149,18 +136,9 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) if (map->cache_ops->init) { dev_dbg(map->dev, "Initializing %s cache\n", map->cache_ops->name); - ret = map->cache_ops->init(map); - if (ret) - goto err_free; + return map->cache_ops->init(map); } return 0; - -err_free: - kfree(map->reg_defaults); - if (map->cache_free) - kfree(map->reg_defaults_raw); - - return ret; } void regcache_exit(struct regmap *map) @@ -198,6 +176,9 @@ int regcache_read(struct regmap *map, BUG_ON(!map->cache_ops); + if (!regmap_readable(map, reg)) + return -EIO; + if (!regmap_volatile(map, reg)) return map->cache_ops->read(map, reg, value); @@ -260,8 +241,6 @@ int regcache_sync(struct regmap *map) map->cache_ops->name); name = map->cache_ops->name; trace_regcache_sync(map->dev, name, "start"); - if (!map->cache_dirty) - goto out; if (map->cache_ops->sync) { ret = map->cache_ops->sync(map); } else { @@ -311,23 +290,6 @@ void regcache_cache_only(struct regmap *map, bool enable) } EXPORT_SYMBOL_GPL(regcache_cache_only); -/** - * regcache_mark_dirty: Mark the register cache as dirty - * - * @map: map to mark - * - * Mark the register cache as dirty, for example due to the device - * having been powered down for suspend. If the cache is not marked - * as dirty then the cache sync will be suppressed. - */ -void regcache_mark_dirty(struct regmap *map) -{ - mutex_lock(&map->lock); - map->cache_dirty = true; - mutex_unlock(&map->lock); -} -EXPORT_SYMBOL_GPL(regcache_mark_dirty); - /** * regcache_cache_bypass: Put a register map into cache bypass mode * @@ -419,3 +381,22 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg) else return -ENOENT; } + +int regcache_insert_reg(struct regmap *map, unsigned int reg, + unsigned int val) +{ + void *tmp; + + tmp = krealloc(map->reg_defaults, + (map->num_reg_defaults + 1) * sizeof(struct reg_default), + GFP_KERNEL); + if (!tmp) + return -ENOMEM; + map->reg_defaults = tmp; + map->num_reg_defaults++; + map->reg_defaults[map->num_reg_defaults - 1].reg = reg; + map->reg_defaults[map->num_reg_defaults - 1].def = val; + sort(map->reg_defaults, map->num_reg_defaults, + sizeof(struct reg_default), regcache_default_cmp, NULL); + return 0; +} diff --git a/trunk/drivers/base/regmap/regmap-irq.c b/trunk/drivers/base/regmap/regmap-irq.c index bd54f63be9ed..6b8a74c3ed18 100644 --- a/trunk/drivers/base/regmap/regmap-irq.c +++ b/trunk/drivers/base/regmap/regmap-irq.c @@ -100,6 +100,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) u8 *buf8 = data->status_reg_buf; u16 *buf16 = data->status_reg_buf; u32 *buf32 = data->status_reg_buf; + bool handled = false; ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf, chip->num_regs); @@ -146,10 +147,14 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (data->status_buf[chip->irqs[i].reg_offset] & chip->irqs[i].mask) { handle_nested_irq(data->irq_base + i); + handled = true; } } - return IRQ_HANDLED; + if (handled) + return IRQ_HANDLED; + else + return IRQ_NONE; } /** diff --git a/trunk/drivers/base/regmap/regmap.c b/trunk/drivers/base/regmap/regmap.c index a8620900abc4..bf441db1ee90 100644 --- a/trunk/drivers/base/regmap/regmap.c +++ b/trunk/drivers/base/regmap/regmap.c @@ -64,18 +64,6 @@ bool regmap_precious(struct regmap *map, unsigned int reg) return false; } -static bool regmap_volatile_range(struct regmap *map, unsigned int reg, - unsigned int num) -{ - unsigned int i; - - for (i = 0; i < num; i++) - if (!regmap_volatile(map, reg + i)) - return false; - - return true; -} - static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val) { @@ -90,16 +78,6 @@ static void regmap_format_7_9_write(struct regmap *map, *out = cpu_to_be16((reg << 9) | val); } -static void regmap_format_10_14_write(struct regmap *map, - unsigned int reg, unsigned int val) -{ - u8 *out = map->work_buf; - - out[2] = val; - out[1] = (val >> 8) | (reg << 6); - out[0] = reg >> 2; -} - static void regmap_format_8(void *buf, unsigned int val) { u8 *b = buf; @@ -149,7 +127,7 @@ struct regmap *regmap_init(struct device *dev, int ret = -EINVAL; if (!bus || !config) - goto err; + return NULL; map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) { @@ -169,6 +147,12 @@ struct regmap *regmap_init(struct device *dev, map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; map->cache_type = config->cache_type; + map->reg_defaults = config->reg_defaults; + map->num_reg_defaults = config->num_reg_defaults; + map->num_reg_defaults_raw = config->num_reg_defaults_raw; + map->reg_defaults_raw = config->reg_defaults_raw; + map->cache_size_raw = (config->val_bits / 8) * config->num_reg_defaults_raw; + map->cache_word_size = config->val_bits / 8; if (config->read_flag_mask || config->write_flag_mask) { map->read_flag_mask = config->read_flag_mask; @@ -198,16 +182,6 @@ struct regmap *regmap_init(struct device *dev, } break; - case 10: - switch (config->val_bits) { - case 14: - map->format.format_write = regmap_format_10_14_write; - break; - default: - goto err_map; - } - break; - case 8: map->format.format_reg = regmap_format_8; break; @@ -241,16 +215,14 @@ struct regmap *regmap_init(struct device *dev, goto err_map; } - regmap_debugfs_init(map); - - ret = regcache_init(map, config); + ret = regcache_init(map); if (ret < 0) - goto err_free_workbuf; + goto err_map; + + regmap_debugfs_init(map); return map; -err_free_workbuf: - kfree(map->work_buf); err_map: kfree(map); err: @@ -334,10 +306,8 @@ int _regmap_write(struct regmap *map, unsigned int reg, ret = regcache_write(map, reg, val); if (ret != 0) return ret; - if (map->cache_only) { - map->cache_dirty = true; + if (map->cache_only) return 0; - } } trace_regmap_reg_write(map->dev, reg, val); @@ -405,11 +375,9 @@ EXPORT_SYMBOL_GPL(regmap_write); int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len) { - size_t val_count = val_len / map->format.val_bytes; int ret; - WARN_ON(!regmap_volatile_range(map, reg, val_count) && - map->cache_type != REGCACHE_NONE); + WARN_ON(map->cache_type != REGCACHE_NONE); mutex_lock(&map->lock); @@ -454,15 +422,15 @@ static int _regmap_read(struct regmap *map, unsigned int reg, { int ret; + if (!map->format.parse_val) + return -EINVAL; + if (!map->cache_bypass) { ret = regcache_read(map, reg, val); if (ret == 0) return 0; } - if (!map->format.parse_val) - return -EINVAL; - if (map->cache_only) return -EBUSY; @@ -513,11 +481,15 @@ EXPORT_SYMBOL_GPL(regmap_read); int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, size_t val_len) { - size_t val_count = val_len / map->format.val_bytes; int ret; + int i; + bool vol = true; - WARN_ON(!regmap_volatile_range(map, reg, val_count) && - map->cache_type != REGCACHE_NONE); + for (i = 0; i < val_len / map->format.val_bytes; i++) + if (!regmap_volatile(map, reg + i)) + vol = false; + + WARN_ON(!vol && map->cache_type != REGCACHE_NONE); mutex_lock(&map->lock); @@ -545,11 +517,16 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, { int ret, i; size_t val_bytes = map->format.val_bytes; - bool vol = regmap_volatile_range(map, reg, val_count); + bool vol = true; if (!map->format.parse_val) return -EINVAL; + /* Is this a block of volatile registers? */ + for (i = 0; i < val_count; i++) + if (!regmap_volatile(map, reg + i)) + vol = false; + if (vol || map->cache_type == REGCACHE_NONE) { ret = regmap_raw_read(map, reg, val, val_bytes * val_count); if (ret != 0) @@ -570,7 +547,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, EXPORT_SYMBOL_GPL(regmap_bulk_read); /** - * regmap_update_bits: Perform a read/modify/write cycle on the register map + * remap_update_bits: Perform a read/modify/write cycle on the register map * * @map: Register map to update * @reg: Register to update @@ -583,19 +560,18 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val) { int ret; - unsigned int tmp, orig; + unsigned int tmp; mutex_lock(&map->lock); - ret = _regmap_read(map, reg, &orig); + ret = _regmap_read(map, reg, &tmp); if (ret != 0) goto out; - tmp = orig & ~mask; + tmp &= ~mask; tmp |= val & mask; - if (tmp != orig) - ret = _regmap_write(map, reg, tmp); + ret = _regmap_write(map, reg, tmp); out: mutex_unlock(&map->lock); diff --git a/trunk/include/linux/regmap.h b/trunk/include/linux/regmap.h index 81dfe0acb20c..bd54cecdfdf8 100644 --- a/trunk/include/linux/regmap.h +++ b/trunk/include/linux/regmap.h @@ -23,8 +23,9 @@ struct spi_device; /* An enum of all the supported cache types */ enum regcache_type { REGCACHE_NONE, + REGCACHE_INDEXED, REGCACHE_RBTREE, - REGCACHE_COMPRESSED + REGCACHE_LZO }; /** @@ -82,7 +83,7 @@ struct regmap_config { bool (*precious_reg)(struct device *dev, unsigned int reg); unsigned int max_register; - const struct reg_default *reg_defaults; + struct reg_default *reg_defaults; unsigned int num_reg_defaults; enum regcache_type cache_type; const void *reg_defaults_raw; @@ -142,7 +143,6 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, int regcache_sync(struct regmap *map); void regcache_cache_only(struct regmap *map, bool enable); void regcache_cache_bypass(struct regmap *map, bool enable); -void regcache_mark_dirty(struct regmap *map); /** * Description of an IRQ for the generic regmap irq_chip.