Skip to content

Commit

Permalink
Merge tag 'regmap-3.4' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/broonie/regmap

Pull regmap updates from Mark Brown:
 "Things are really quieting down with the regmap API, while we're still
  seeing a trickle of new features coming in they're getting much
  smaller than they were.  It's also nice to have some features which
  support other subsystems building infrastructure on top of regmap.
  Highlights include:

  - Support for padding between the register and the value when
    interacting with the device, sometimes needed for fast interfaces.
  - Support for applying register updates to the device when restoring
    the register state.  This is intended to be used to apply updates
    supplied by manufacturers for tuning the performance of the device
    (many of which are to undocumented registers which aren't otherwise
    covered).
  - Support for multi-register operations on cached registers.
  - Support for syncing only part of the register cache.
  - Stubs and parameter query functions intended to make it easier for
    other subsystems to build infrastructure on top of the regmap API.

  plus a few driver updates making use of the new features which it was
  easier to merge via this tree."

* tag 'regmap-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (41 commits)
  regmap: Fix future missing prototype of devres_alloc() and friends
  regmap: Rejig struct declarations for stubbed API
  regmap: Fix rbtree block base in sync
  regcache: Make sure we sync register 0 in an rbtree cache
  regmap: delete unused module.h from drivers/base/regmap files
  regmap: Add stub for regcache_sync_region()
  mfd: Improve performance of later WM1811 revisions
  regmap: Fix x86_64 breakage
  regmap: Allow drivers to sync only part of the register cache
  regmap: Supply ranges to the sync operations
  regmap: Add tracepoints for cache only and cache bypass
  regmap: Mark the cache as clean after a successful sync
  regmap: Remove default cache sync implementation
  regmap: Skip hardware defaults for LZO caches
  regmap: Expose the driver name in debugfs
  mfd: wm8400: Convert to devm_regmap_init_i2c()
  mfd: wm831x: Convert to devm_regmap_init()
  mfd: wm8994: Convert to devm_regmap_init()
  mfd/ASoC: Convert WM8994 driver to use regmap patches
  mfd: Add __devinit and __devexit annotations in wm8994
  ...
  • Loading branch information
torvalds committed Mar 23, 2012
2 parents 3469940 + addfd8a commit 9586c95
Show file tree
Hide file tree
Showing 16 changed files with 695 additions and 122 deletions.
11 changes: 6 additions & 5 deletions drivers/base/regmap/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct regcache_ops;
struct regmap_format {
size_t buf_size;
size_t reg_bytes;
size_t pad_bytes;
size_t val_bytes;
void (*format_write)(struct regmap *map,
unsigned int reg, unsigned int val);
Expand Down Expand Up @@ -65,16 +66,16 @@ struct regmap {
unsigned int num_reg_defaults_raw;

/* if set, only the cache is modified not the HW */
unsigned int cache_only:1;
u32 cache_only;
/* if set, only the HW is modified not the cache */
unsigned int cache_bypass:1;
u32 cache_bypass;
/* if set, remember to free reg_defaults_raw */
unsigned int cache_free:1;
bool cache_free;

struct reg_default *reg_defaults;
const void *reg_defaults_raw;
void *cache;
bool cache_dirty;
u32 cache_dirty;

struct reg_default *patch;
int patch_regs;
Expand All @@ -87,7 +88,7 @@ struct regcache_ops {
int (*exit)(struct regmap *map);
int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
int (*sync)(struct regmap *map);
int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
};

bool regmap_writeable(struct regmap *map, unsigned int reg);
Expand Down
16 changes: 14 additions & 2 deletions drivers/base/regmap/regcache-lzo.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,18 +331,30 @@ static int regcache_lzo_write(struct regmap *map,
return ret;
}

static int regcache_lzo_sync(struct regmap *map)
static int regcache_lzo_sync(struct regmap *map, unsigned int min,
unsigned int max)
{
struct regcache_lzo_ctx **lzo_blocks;
unsigned int val;
int i;
int ret;

lzo_blocks = map->cache;
for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
i = min;
for_each_set_bit_cont(i, lzo_blocks[0]->sync_bmp,
lzo_blocks[0]->sync_bmp_nbits) {
if (i > max)
continue;

ret = regcache_read(map, i, &val);
if (ret)
return ret;

/* Is this the hardware default? If so skip. */
ret = regcache_lookup_reg(map, i);
if (ret > 0 && val == map->reg_defaults[ret].def)
continue;

map->cache_bypass = 1;
ret = _regmap_write(map, i, val);
map->cache_bypass = 0;
Expand Down
27 changes: 23 additions & 4 deletions drivers/base/regmap/regcache-rbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,27 +357,46 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
return 0;
}

static int regcache_rbtree_sync(struct regmap *map)
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;
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);
for (i = 0; i < rbnode->blklen; i++) {

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, i);
if (ret > 0 && val == map->reg_defaults[ret].def)
if (ret >= 0 && val == map->reg_defaults[ret].def)
continue;

map->cache_bypass = 1;
Expand Down
97 changes: 73 additions & 24 deletions drivers/base/regmap/regcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ static int regcache_hw_init(struct regmap *map)
return -EINVAL;

if (!map->reg_defaults_raw) {
u32 cache_bypass = map->cache_bypass;
dev_warn(map->dev, "No cache defaults, reading back from HW\n");

/* Bypass the cache access till data read from HW*/
map->cache_bypass = 1;
tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
if (!tmp_buf)
return -EINVAL;
ret = regmap_bulk_read(map, 0, tmp_buf,
map->num_reg_defaults_raw);
map->cache_bypass = cache_bypass;
if (ret < 0) {
kfree(tmp_buf);
return ret;
Expand Down Expand Up @@ -211,7 +216,6 @@ int regcache_read(struct regmap *map,

return -EINVAL;
}
EXPORT_SYMBOL_GPL(regcache_read);

/**
* regcache_write: Set the value of a given register in the cache.
Expand All @@ -238,7 +242,6 @@ int regcache_write(struct regmap *map,

return 0;
}
EXPORT_SYMBOL_GPL(regcache_write);

/**
* regcache_sync: Sync the register cache with the hardware.
Expand All @@ -254,12 +257,11 @@ EXPORT_SYMBOL_GPL(regcache_write);
int regcache_sync(struct regmap *map)
{
int ret = 0;
unsigned int val;
unsigned int i;
const char *name;
unsigned int bypass;

BUG_ON(!map->cache_ops);
BUG_ON(!map->cache_ops || !map->cache_ops->sync);

mutex_lock(&map->lock);
/* Remember the initial bypass state */
Expand All @@ -269,7 +271,11 @@ int regcache_sync(struct regmap *map)
name = map->cache_ops->name;
trace_regcache_sync(map->dev, name, "start");

if (!map->cache_dirty)
goto out;

/* Apply any patch first */
map->cache_bypass = 1;
for (i = 0; i < map->patch_regs; i++) {
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
if (ret != 0) {
Expand All @@ -278,27 +284,13 @@ int regcache_sync(struct regmap *map)
goto out;
}
}
map->cache_bypass = 0;

if (!map->cache_dirty)
goto out;
if (map->cache_ops->sync) {
ret = map->cache_ops->sync(map);
} else {
for (i = 0; i < map->num_reg_defaults; i++) {
ret = regcache_read(map, i, &val);
if (ret < 0)
goto out;
map->cache_bypass = 1;
ret = _regmap_write(map, i, val);
map->cache_bypass = 0;
if (ret < 0)
goto out;
dev_dbg(map->dev, "Synced register %#x, value %#x\n",
map->reg_defaults[i].reg,
map->reg_defaults[i].def);
}
ret = map->cache_ops->sync(map, 0, map->max_register);

if (ret == 0)
map->cache_dirty = false;

}
out:
trace_regcache_sync(map->dev, name, "stop");
/* Restore the bypass state */
Expand All @@ -309,6 +301,51 @@ int regcache_sync(struct regmap *map)
}
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, unsigned int min,
unsigned int max)
{
int ret = 0;
const char *name;
unsigned int bypass;

BUG_ON(!map->cache_ops || !map->cache_ops->sync);

mutex_lock(&map->lock);

/* 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->dev, name, "start region");

if (!map->cache_dirty)
goto out;

ret = map->cache_ops->sync(map, min, max);

out:
trace_regcache_sync(map->dev, name, "stop region");
/* Restore the bypass state */
map->cache_bypass = bypass;
mutex_unlock(&map->lock);

return ret;
}

/**
* regcache_cache_only: Put a register map into cache only mode
*
Expand All @@ -326,6 +363,7 @@ void regcache_cache_only(struct regmap *map, bool enable)
mutex_lock(&map->lock);
WARN_ON(map->cache_bypass && enable);
map->cache_only = enable;
trace_regmap_cache_only(map->dev, enable);
mutex_unlock(&map->lock);
}
EXPORT_SYMBOL_GPL(regcache_cache_only);
Expand Down Expand Up @@ -363,6 +401,7 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
mutex_lock(&map->lock);
WARN_ON(map->cache_only && enable);
map->cache_bypass = enable;
trace_regmap_cache_bypass(map->dev, enable);
mutex_unlock(&map->lock);
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
Expand All @@ -385,10 +424,16 @@ bool regcache_set_val(void *base, unsigned int idx,
cache[idx] = val;
break;
}
case 4: {
u32 *cache = base;
if (cache[idx] == val)
return true;
cache[idx] = val;
break;
}
default:
BUG();
}
/* unreachable */
return false;
}

Expand All @@ -407,6 +452,10 @@ unsigned int regcache_get_val(const void *base, unsigned int idx,
const u16 *cache = base;
return cache[idx];
}
case 4: {
const u32 *cache = base;
return cache[idx];
}
default:
BUG();
}
Expand Down
Loading

0 comments on commit 9586c95

Please sign in to comment.