Commit 9586c959 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'regmap-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/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
  ...
parents 34699403 addfd8a0
......@@ -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);
......@@ -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;
......@@ -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);
......
......@@ -331,7 +331,8 @@ 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;
......@@ -339,10 +340,21 @@ static int regcache_lzo_sync(struct regmap *map)
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;
......
......@@ -357,7 +357,8 @@ 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;
......@@ -365,19 +366,37 @@ static int regcache_rbtree_sync(struct regmap *map)
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;
......
......@@ -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;
......@@ -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.
......@@ -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.
......@@ -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 */
......@@ -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) {
......@@ -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 */
......@@ -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
*
......@@ -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);
......@@ -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);
......@@ -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;
}
......@@ -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();
}
......
......@@ -11,7 +11,6 @@
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
......@@ -33,6 +32,35 @@ static int regmap_open_file(struct inode *inode, struct file *file)
return 0;
}
static ssize_t regmap_name_read_file(struct file *file,
char __user *user_buf, size_t count,
loff_t *ppos)
{
struct regmap *map = file->private_data;
int ret;
char *buf;
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
if (ret < 0) {
kfree(buf);
return ret;
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
return ret;
}
static const struct file_operations regmap_name_fops = {
.open = regmap_open_file,
.read = regmap_name_read_file,
.llseek = default_llseek,
};
static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
......@@ -103,9 +131,51 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
return ret;
}
#undef REGMAP_ALLOW_WRITE_DEBUGFS
#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
/*
* This can be dangerous especially when we have clients such as
* PMICs, therefore don't provide any real compile time configuration option
* for this feature, people who want to use this will need to modify
* the source code directly.
*/
static ssize_t regmap_map_write_file(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
char buf[32];
size_t buf_size;
char *start = buf;
unsigned long reg, value;
struct regmap *map = file->private_data;
buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = 0;
while (*start == ' ')
start++;
reg = simple_strtoul(start, &start, 16);
while (*start == ' ')
start++;
if (strict_strtoul(start, 16, &value))
return -EINVAL;
/* Userspace has been fiddling around behind the kernel's back */
add_taint(TAINT_USER);
regmap_write(map, reg, value);
return buf_size;
}
#else
#define regmap_map_write_file NULL
#endif
static const struct file_operations regmap_map_fops = {
.open = regmap_open_file,
.read = regmap_map_read_file,
.write = regmap_map_write_file,
.llseek = default_llseek,
};
......@@ -186,12 +256,24 @@ void regmap_debugfs_init(struct regmap *map)
return;
}
debugfs_create_file("name", 0400, map->debugfs,
map, &regmap_name_fops);
if (map->max_register) {
debugfs_create_file("registers", 0400, map->debugfs,
map, &regmap_map_fops);
debugfs_create_file("access", 0400, map->debugfs,
map, &regmap_access_fops);
}
if (map->cache_type) {
debugfs_create_bool("cache_only", 0400, map->debugfs,
&map->cache_only);
debugfs_create_bool("cache_dirty", 0400, map->debugfs,
&map->cache_dirty);
debugfs_create_bool("cache_bypass", 0400, map->debugfs,
&map->cache_bypass);
}
}
void regmap_debugfs_exit(struct regmap *map)
......
......@@ -111,4 +111,21 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c,
}
EXPORT_SYMBOL_GPL(regmap_init_i2c);
/**
* devm_regmap_init_i2c(): Initialise managed register map
*
* @i2c: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
return devm_regmap_init(&i2c->dev, &regmap_i2c, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);
MODULE_LICENSE("GPL");
......@@ -70,4 +70,21 @@ struct regmap *regmap_init_spi(struct spi_device *spi,
}
EXPORT_SYMBOL_GPL(regmap_init_spi);
/**
* devm_regmap_init_spi(): Initialise register map
*
* @spi: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The map will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{
return devm_regmap_init(&spi->dev, &regmap_spi, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_spi);
MODULE_LICENSE("GPL");
......@@ -10,8 +10,9 @@
* published by the Free Software Foundation.
*/
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/err.h>
......@@ -36,6 +37,9 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
if (map->max_register && reg > map->max_register)
return false;
if (map->format.format_write)
return false;
if (map->readable_reg)
return map->readable_reg(map->dev, reg);
......@@ -44,7 +48,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
bool regmap_volatile(struct regmap *map, unsigned int reg)
{
if (map->max_register && reg > map->max_register)
if (!regmap_readable(map, reg))
return false;
if (map->volatile_reg)
......@@ -55,7 +59,7 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
bool regmap_precious(struct regmap *map, unsigned int reg)
{
if (map->max_register && reg > map->max_register)
if (!regmap_readable(map, reg))
return false;
if (map->precious_reg)
......@@ -76,6 +80,14 @@ static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
return true;
}
static void regmap_format_2_6_write(struct regmap *map,
unsigned int reg, unsigned int val)
{
u8 *out = map->work_buf;
*out = (reg << 6) | val;
}
static void regmap_format_4_12_write(struct regmap *map,
unsigned int reg, unsigned int val)
{
......@@ -114,6 +126,13 @@ static void regmap_format_16(void *buf, unsigned int val)
b[0] = cpu_to_be16(val);
}
static void regmap_format_32(void *buf, unsigned int val)
{
__be32 *b = buf;
b[0] = cpu_to_be32(val);
}
static unsigned int regmap_parse_8(void *buf)
{
u8 *b = buf;
......@@ -130,6 +149,15 @@ static unsigned int regmap_parse_16(void *buf)
return b[0];
}
static unsigned int regmap_parse_32(void *buf)
{
__be32 *b = buf;
b[0] = be32_to_cpu(b[0]);
return b[0];
}
/**
* regmap_init(): Initialise register map
*
......@@ -159,8 +187,10 @@ struct regmap *regmap_init(struct device *dev,
mutex_init(&map->lock);
map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
map->format.reg_bytes = config->reg_bits / 8;
map->format.val_bytes = config->val_bits / 8;
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 += map->format.pad_bytes;
map->dev = dev;
map->bus = bus;
map->max_register = config->max_register;
......@@ -178,6 +208,16 @@ struct regmap *regmap_init(struct device *dev,
}
switch (config->reg_bits) {
case 2:
switch (config->val_bits) {
case 6:
map->format.format_write = regmap_format_2_6_write;
break;
default:
goto err_map;
}
break;
case 4:
switch (config->val_bits) {
case 12:
......@@ -216,6 +256,10 @@ struct regmap *regmap_init(struct device *dev,
map->format.format_reg = regmap_format_16;
break;
case 32:
map->format.format_reg = regmap_format_32;
break;
default:
goto err_map;
}
......@@ -229,13 +273,17 @@ struct regmap *regmap_init(struct device *dev,
map->format.format_val = regmap_format_16;
map->format.parse_val = regmap_parse_16;
break;
case 32:
map->format.format_val = regmap_format_32;
map->format.parse_val = regmap_parse_32;
break;
}
if (!map->format.format_write &&
!(map->format.format_reg && map->format.format_val))
goto err_map;
map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL);
map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL);
if (map->work_buf == NULL) {
ret = -ENOMEM;
goto err_map;
......@@ -258,6 +306,45 @@ struct regmap *regmap_init(struct device *dev,
}
EXPORT_SYMBOL_GPL(regmap_init);
static void devm_regmap_release(