Merge branches 'regmap-core', 'regmap-mmio' and 'regmap-naming' into regmap-stride

This commit is contained in:
Mark Brown 2012-04-10 11:01:07 +01:00
commit c0cc6fe1d0
11 changed files with 394 additions and 69 deletions

View File

@ -14,5 +14,8 @@ config REGMAP_I2C
config REGMAP_SPI
tristate
config REGMAP_MMIO
tristate
config REGMAP_IRQ
bool

View File

@ -3,4 +3,5 @@ obj-$(CONFIG_REGMAP) += 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
obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o

View File

@ -26,21 +26,29 @@ struct regmap_format {
size_t val_bytes;
void (*format_write)(struct regmap *map,
unsigned int reg, unsigned int val);
void (*format_reg)(void *buf, unsigned int reg);
void (*format_val)(void *buf, unsigned int val);
void (*format_reg)(void *buf, unsigned int reg, unsigned int shift);
void (*format_val)(void *buf, unsigned int val, unsigned int shift);
unsigned int (*parse_val)(void *buf);
};
typedef void (*regmap_lock)(struct regmap *map);
typedef void (*regmap_unlock)(struct regmap *map);
struct regmap {
struct mutex lock;
struct mutex mutex;
spinlock_t spinlock;
regmap_lock lock;
regmap_unlock unlock;
struct device *dev; /* Device we do I/O on */
void *work_buf; /* Scratch buffer used to format I/O */
struct regmap_format format; /* Buffer format */
const struct regmap_bus *bus;
void *bus_context;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
const char *debugfs_name;
#endif
unsigned int max_register;
@ -52,6 +60,9 @@ struct regmap {
u8 read_flag_mask;
u8 write_flag_mask;
/* number of bits to (left) shift the reg value when formatting*/
int reg_shift;
/* regcache specific members */
const struct regcache_ops *cache_ops;
enum regcache_type cache_type;
@ -101,11 +112,11 @@ int _regmap_write(struct regmap *map, unsigned int reg,
#ifdef CONFIG_DEBUG_FS
extern void regmap_debugfs_initcall(void);
extern void regmap_debugfs_init(struct regmap *map);
extern void regmap_debugfs_init(struct regmap *map, const char *name);
extern void regmap_debugfs_exit(struct regmap *map);
#else
static inline void regmap_debugfs_initcall(void) { }
static inline void regmap_debugfs_init(struct regmap *map) { }
static inline void regmap_debugfs_init(struct regmap *map, const char *name) { }
static inline void regmap_debugfs_exit(struct regmap *map) { }
#endif

View File

@ -140,7 +140,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
int registers = 0;
int average;
mutex_lock(&map->lock);
map->lock(map);
for (node = rb_first(&rbtree_ctx->root); node != NULL;
node = rb_next(node)) {
@ -161,7 +161,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
seq_printf(s, "%d nodes, %d registers, average %d registers\n",
nodes, registers, average);
mutex_unlock(&map->lock);
map->unlock(map);
return 0;
}

View File

@ -264,7 +264,7 @@ int regcache_sync(struct regmap *map)
BUG_ON(!map->cache_ops || !map->cache_ops->sync);
mutex_lock(&map->lock);
map->lock(map);
/* Remember the initial bypass state */
bypass = map->cache_bypass;
dev_dbg(map->dev, "Syncing %s cache\n",
@ -296,7 +296,7 @@ out:
trace_regcache_sync(map->dev, name, "stop");
/* Restore the bypass state */
map->cache_bypass = bypass;
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
@ -323,7 +323,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
BUG_ON(!map->cache_ops || !map->cache_ops->sync);
mutex_lock(&map->lock);
map->lock(map);
/* Remember the initial bypass state */
bypass = map->cache_bypass;
@ -342,7 +342,7 @@ out:
trace_regcache_sync(map->dev, name, "stop region");
/* Restore the bypass state */
map->cache_bypass = bypass;
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
@ -362,11 +362,11 @@ EXPORT_SYMBOL_GPL(regcache_sync_region);
*/
void regcache_cache_only(struct regmap *map, bool enable)
{
mutex_lock(&map->lock);
map->lock(map);
WARN_ON(map->cache_bypass && enable);
map->cache_only = enable;
trace_regmap_cache_only(map->dev, enable);
mutex_unlock(&map->lock);
map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_cache_only);
@ -381,9 +381,9 @@ EXPORT_SYMBOL_GPL(regcache_cache_only);
*/
void regcache_mark_dirty(struct regmap *map)
{
mutex_lock(&map->lock);
map->lock(map);
map->cache_dirty = true;
mutex_unlock(&map->lock);
map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);
@ -400,11 +400,11 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty);
*/
void regcache_cache_bypass(struct regmap *map, bool enable)
{
mutex_lock(&map->lock);
map->lock(map);
WARN_ON(map->cache_only && enable);
map->cache_bypass = enable;
trace_regmap_cache_bypass(map->dev, enable);
mutex_unlock(&map->lock);
map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);

View File

@ -242,10 +242,17 @@ static const struct file_operations regmap_access_fops = {
.llseek = default_llseek,
};
void regmap_debugfs_init(struct regmap *map)
void regmap_debugfs_init(struct regmap *map, const char *name)
{
map->debugfs = debugfs_create_dir(dev_name(map->dev),
regmap_debugfs_root);
if (name) {
map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
dev_name(map->dev), name);
name = map->debugfs_name;
} else {
name = dev_name(map->dev);
}
map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
if (!map->debugfs) {
dev_warn(map->dev, "Failed to create debugfs directory\n");
return;
@ -274,6 +281,7 @@ void regmap_debugfs_init(struct regmap *map)
void regmap_debugfs_exit(struct regmap *map)
{
debugfs_remove_recursive(map->debugfs);
kfree(map->debugfs_name);
}
void regmap_debugfs_initcall(void)

View File

@ -15,8 +15,9 @@
#include <linux/module.h>
#include <linux/init.h>
static int regmap_i2c_write(struct device *dev, const void *data, size_t count)
static int regmap_i2c_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
int ret;
@ -29,10 +30,11 @@ static int regmap_i2c_write(struct device *dev, const void *data, size_t count)
return -EIO;
}
static int regmap_i2c_gather_write(struct device *dev,
static int regmap_i2c_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2];
int ret;
@ -62,10 +64,11 @@ static int regmap_i2c_gather_write(struct device *dev,
return -EIO;
}
static int regmap_i2c_read(struct device *dev,
static int regmap_i2c_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2];
int ret;
@ -107,7 +110,7 @@ static struct regmap_bus regmap_i2c = {
struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
return regmap_init(&i2c->dev, &regmap_i2c, config);
return regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
}
EXPORT_SYMBOL_GPL(regmap_init_i2c);
@ -124,7 +127,7 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c);
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
return devm_regmap_init(&i2c->dev, &regmap_i2c, config);
return devm_regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);

View File

@ -0,0 +1,211 @@
/*
* Register map access API - MMIO support
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
struct regmap_mmio_context {
void __iomem *regs;
unsigned val_bytes;
};
static int regmap_mmio_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
struct regmap_mmio_context *ctx = context;
u32 offset;
BUG_ON(reg_size != 4);
offset = be32_to_cpup(reg);
while (val_size) {
switch (ctx->val_bytes) {
case 1:
writeb(*(u8 *)val, ctx->regs + offset);
break;
case 2:
writew(be16_to_cpup(val), ctx->regs + offset);
break;
case 4:
writel(be32_to_cpup(val), ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
writeq(be64_to_cpup(val), ctx->regs + offset);
break;
#endif
default:
/* Should be caught by regmap_mmio_check_config */
BUG();
}
val_size -= ctx->val_bytes;
val += ctx->val_bytes;
offset += ctx->val_bytes;
}
return 0;
}
static int regmap_mmio_write(void *context, const void *data, size_t count)
{
BUG_ON(count < 4);
return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
}
static int regmap_mmio_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
struct regmap_mmio_context *ctx = context;
u32 offset;
BUG_ON(reg_size != 4);
offset = be32_to_cpup(reg);
while (val_size) {
switch (ctx->val_bytes) {
case 1:
*(u8 *)val = readb(ctx->regs + offset);
break;
case 2:
*(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
break;
case 4:
*(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
break;
#ifdef CONFIG_64BIT
case 8:
*(u64 *)val = cpu_to_be32(readq(ctx->regs + offset));
break;
#endif
default:
/* Should be caught by regmap_mmio_check_config */
BUG();
}
val_size -= ctx->val_bytes;
val += ctx->val_bytes;
offset += ctx->val_bytes;
}
return 0;
}
static void regmap_mmio_free_context(void *context)
{
kfree(context);
}
static struct regmap_bus regmap_mmio = {
.fast_io = true,
.write = regmap_mmio_write,
.gather_write = regmap_mmio_gather_write,
.read = regmap_mmio_read,
.free_context = regmap_mmio_free_context,
};
struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
if (config->reg_bits != 32)
return ERR_PTR(-EINVAL);
if (config->pad_bits)
return ERR_PTR(-EINVAL);
switch (config->val_bits) {
case 8:
case 16:
case 32:
#ifdef CONFIG_64BIT
case 64:
#endif
break;
default:
return ERR_PTR(-EINVAL);
}
ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
if (!ctx)
return ERR_PTR(-ENOMEM);
ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8;
return ctx;
}
/**
* regmap_init_mmio(): Initialise register map
*
* @dev: Device that will be interacted with
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_mmio(struct device *dev,
void __iomem *regs,
const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
ctx = regmap_mmio_gen_context(regs, config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
return regmap_init(dev, &regmap_mmio, ctx, config);
}
EXPORT_SYMBOL_GPL(regmap_init_mmio);
/**
* devm_regmap_init_mmio(): Initialise managed register map
*
* @dev: Device that will be interacted with
* @regs: Pointer to memory-mapped IO region
* @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_mmio(struct device *dev,
void __iomem *regs,
const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
ctx = regmap_mmio_gen_context(regs, config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
return devm_regmap_init(dev, &regmap_mmio, ctx, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
MODULE_LICENSE("GPL v2");

View File

@ -15,17 +15,19 @@
#include <linux/init.h>
#include <linux/module.h>
static int regmap_spi_write(struct device *dev, const void *data, size_t count)
static int regmap_spi_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
return spi_write(spi, data, count);
}
static int regmap_spi_gather_write(struct device *dev,
static int regmap_spi_gather_write(void *context,
const void *reg, size_t reg_len,
const void *val, size_t val_len)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
struct spi_message m;
struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, },
@ -38,10 +40,11 @@ static int regmap_spi_gather_write(struct device *dev,
return spi_sync(spi, &m);
}
static int regmap_spi_read(struct device *dev,
static int regmap_spi_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
return spi_write_then_read(spi, reg, reg_size, val, val_size);
@ -66,7 +69,7 @@ static struct regmap_bus regmap_spi = {
struct regmap *regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{
return regmap_init(&spi->dev, &regmap_spi, config);
return regmap_init(&spi->dev, &regmap_spi, &spi->dev, config);
}
EXPORT_SYMBOL_GPL(regmap_init_spi);
@ -83,7 +86,7 @@ EXPORT_SYMBOL_GPL(regmap_init_spi);
struct regmap *devm_regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{
return devm_regmap_init(&spi->dev, &regmap_spi, config);
return devm_regmap_init(&spi->dev, &regmap_spi, &spi->dev, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_spi);

View File

@ -112,25 +112,36 @@ static void regmap_format_10_14_write(struct regmap *map,
out[0] = reg >> 2;
}
static void regmap_format_8(void *buf, unsigned int val)
static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
{
u8 *b = buf;
b[0] = val;
b[0] = val << shift;
}
static void regmap_format_16(void *buf, unsigned int val)
static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
{
__be16 *b = buf;
b[0] = cpu_to_be16(val);
b[0] = cpu_to_be16(val << shift);
}
static void regmap_format_32(void *buf, unsigned int val)
static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
{
u8 *b = buf;
val <<= shift;
b[0] = val >> 16;
b[1] = val >> 8;
b[2] = val;
}
static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
{
__be32 *b = buf;
b[0] = cpu_to_be32(val);
b[0] = cpu_to_be32(val << shift);
}
static unsigned int regmap_parse_8(void *buf)
@ -149,6 +160,16 @@ static unsigned int regmap_parse_16(void *buf)
return b[0];
}
static unsigned int regmap_parse_24(void *buf)
{
u8 *b = buf;
unsigned int ret = b[2];
ret |= ((unsigned int)b[1]) << 8;
ret |= ((unsigned int)b[0]) << 16;
return ret;
}
static unsigned int regmap_parse_32(void *buf)
{
__be32 *b = buf;
@ -158,11 +179,32 @@ static unsigned int regmap_parse_32(void *buf)
return b[0];
}
static void regmap_lock_mutex(struct regmap *map)
{
mutex_lock(&map->mutex);
}
static void regmap_unlock_mutex(struct regmap *map)
{
mutex_unlock(&map->mutex);
}
static void regmap_lock_spinlock(struct regmap *map)
{
spin_lock(&map->spinlock);
}
static void regmap_unlock_spinlock(struct regmap *map)
{
spin_unlock(&map->spinlock);
}
/**
* regmap_init(): Initialise register map
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
* @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
@ -171,6 +213,7 @@ static unsigned int regmap_parse_32(void *buf)
*/
struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config)
{
struct regmap *map;
@ -185,14 +228,24 @@ struct regmap *regmap_init(struct device *dev,
goto err;
}
mutex_init(&map->lock);
if (bus->fast_io) {
spin_lock_init(&map->spinlock);
map->lock = regmap_lock_spinlock;
map->unlock = regmap_unlock_spinlock;
} else {
mutex_init(&map->mutex);
map->lock = regmap_lock_mutex;
map->unlock = regmap_unlock_mutex;
}
map->format.buf_size = (config->reg_bits + 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->reg_shift = config->pad_bits % 8;
map->dev = dev;
map->bus = bus;
map->bus_context = bus_context;
map->max_register = config->max_register;
map->writeable_reg = config->writeable_reg;
map->readable_reg = config->readable_reg;
@ -207,7 +260,7 @@ struct regmap *regmap_init(struct device *dev,
map->read_flag_mask = bus->read_flag_mask;
}
switch (config->reg_bits) {
switch (config->reg_bits + map->reg_shift) {
case 2:
switch (config->val_bits) {
case 6:
@ -273,6 +326,10 @@ struct regmap *regmap_init(struct device *dev,
map->format.format_val = regmap_format_16;
map->format.parse_val = regmap_parse_16;
break;
case 24:
map->format.format_val = regmap_format_24;
map->format.parse_val = regmap_parse_24;
break;
case 32:
map->format.format_val = regmap_format_32;
map->format.parse_val = regmap_parse_32;
@ -289,7 +346,7 @@ struct regmap *regmap_init(struct device *dev,
goto err_map;
}
regmap_debugfs_init(map);
regmap_debugfs_init(map, config->name);
ret = regcache_init(map, config);
if (ret < 0)
@ -316,6 +373,7 @@ static void devm_regmap_release(struct device *dev, void *res)
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
* @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
@ -325,6 +383,7 @@ static void devm_regmap_release(struct device *dev, void *res)
*/
struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config)
{
struct regmap **ptr, *regmap;
@ -333,7 +392,7 @@ struct regmap *devm_regmap_init(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
regmap = regmap_init(dev, bus, config);
regmap = regmap_init(dev, bus, bus_context, config);
if (!IS_ERR(regmap)) {
*ptr = regmap;
devres_add(dev, ptr);
@ -360,7 +419,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
{
int ret;
mutex_lock(&map->lock);
map->lock(map);
regcache_exit(map);
regmap_debugfs_exit(map);
@ -372,14 +431,14 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
map->precious_reg = config->precious_reg;
map->cache_type = config->cache_type;
regmap_debugfs_init(map);
regmap_debugfs_init(map, config->name);
map->cache_bypass = false;
map->cache_only = false;
ret = regcache_init(map, config);
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
@ -391,6 +450,8 @@ void regmap_exit(struct regmap *map)
{
regcache_exit(map);
regmap_debugfs_exit(map);
if (map->bus->free_context)
map->bus->free_context(map->bus_context);
kfree(map->work_buf);
kfree(map);
}
@ -431,7 +492,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
}
}
map->format.format_reg(map->work_buf, reg);
map->format.format_reg(map->work_buf, reg, map->reg_shift);
u8[0] |= map->write_flag_mask;
@ -444,12 +505,12 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
*/
if (val == (map->work_buf + map->format.pad_bytes +
map->format.reg_bytes))
ret = map->bus->write(map->dev, map->work_buf,
ret = map->bus->write(map->bus_context, map->work_buf,
map->format.reg_bytes +
map->format.pad_bytes +
val_len);
else if (map->bus->gather_write)
ret = map->bus->gather_write(map->dev, map->work_buf,
ret = map->bus->gather_write(map->bus_context, map->work_buf,
map->format.reg_bytes +
map->format.pad_bytes,
val, val_len);
@ -464,7 +525,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
memcpy(buf, map->work_buf, map->format.reg_bytes);
memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
val, val_len);
ret = map->bus->write(map->dev, buf, len);
ret = map->bus->write(map->bus_context, buf, len);
kfree(buf);
}
@ -498,7 +559,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
trace_regmap_hw_write_start(map->dev, reg, 1);
ret = map->bus->write(map->dev, map->work_buf,
ret = map->bus->write(map->bus_context, map->work_buf,
map->format.buf_size);
trace_regmap_hw_write_done(map->dev, reg, 1);
@ -506,7 +567,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
return ret;
} else {
map->format.format_val(map->work_buf + map->format.reg_bytes
+ map->format.pad_bytes, val);
+ map->format.pad_bytes, val, 0);
return _regmap_raw_write(map, reg,
map->work_buf +
map->format.reg_bytes +
@ -529,11 +590,11 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{
int ret;
mutex_lock(&map->lock);
map->lock(map);
ret = _regmap_write(map, reg, val);
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
@ -560,11 +621,14 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
{
int ret;
mutex_lock(&map->lock);
if (val_len % map->format.val_bytes)
return -EINVAL;
map->lock(map);
ret = _regmap_raw_write(map, reg, val, val_len);
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
@ -594,7 +658,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (!map->format.parse_val)
return -EINVAL;
mutex_lock(&map->lock);
map->lock(map);
/* No formatting is require if val_byte is 1 */
if (val_bytes == 1) {
@ -615,7 +679,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
kfree(wval);
out:
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);
@ -626,7 +690,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
u8 *u8 = map->work_buf;
int ret;
map->format.format_reg(map->work_buf, reg);
map->format.format_reg(map->work_buf, reg, map->reg_shift);
/*
* Some buses or devices flag reads by setting the high bits in the
@ -639,7 +703,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
trace_regmap_hw_read_start(map->dev, reg,
val_len / map->format.val_bytes);
ret = map->bus->read(map->dev, map->work_buf,
ret = map->bus->read(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.pad_bytes,
val, val_len);
@ -689,11 +753,11 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{
int ret;
mutex_lock(&map->lock);
map->lock(map);
ret = _regmap_read(map, reg, val);
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
@ -718,7 +782,10 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
unsigned int v;
int ret, i;
mutex_lock(&map->lock);
if (val_len % map->format.val_bytes)
return -EINVAL;
map->lock(map);
if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
map->cache_type == REGCACHE_NONE) {
@ -734,12 +801,12 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
if (ret != 0)
goto out;
map->format.format_val(val + (i * val_bytes), v);
map->format.format_val(val + (i * val_bytes), v, 0);
}
}
out:
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
@ -792,7 +859,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
int ret;
unsigned int tmp, orig;
mutex_lock(&map->lock);
map->lock(map);
ret = _regmap_read(map, reg, &orig);
if (ret != 0)
@ -809,7 +876,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
}
out:
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}
@ -876,7 +943,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
if (map->patch)
return -EBUSY;
mutex_lock(&map->lock);
map->lock(map);
bypass = map->cache_bypass;
@ -904,7 +971,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
out:
map->cache_bypass = bypass;
mutex_unlock(&map->lock);
map->unlock(map);
return ret;
}

View File

@ -46,6 +46,9 @@ struct reg_default {
/**
* Configuration for the register map of a device.
*
* @name: Optional name of the regmap. Useful when a device has multiple
* register regions.
*
* @reg_bits: Number of bits in a register address, mandatory.
* @pad_bits: Number of bits of padding between register and value.
* @val_bits: Number of bits in a register value, mandatory.
@ -77,6 +80,8 @@ struct reg_default {
* @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
*/
struct regmap_config {
const char *name;
int reg_bits;
int pad_bits;
int val_bits;
@ -97,18 +102,21 @@ struct regmap_config {
u8 write_flag_mask;
};
typedef int (*regmap_hw_write)(struct device *dev, const void *data,
typedef int (*regmap_hw_write)(void *context, const void *data,
size_t count);
typedef int (*regmap_hw_gather_write)(struct device *dev,
typedef int (*regmap_hw_gather_write)(void *context,
const void *reg, size_t reg_len,
const void *val, size_t val_len);
typedef int (*regmap_hw_read)(struct device *dev,
typedef int (*regmap_hw_read)(void *context,
const void *reg_buf, size_t reg_size,
void *val_buf, size_t val_size);
typedef void (*regmap_hw_free_context)(void *context);
/**
* Description of a hardware bus for the register map infrastructure.
*
* @fast_io: Register IO is fast. Use a spinlock instead of a mutex
* to perform locking.
* @write: Write operation.
* @gather_write: Write operation with split register/value, return -ENOTSUPP
* if not implemented on a given device.
@ -118,27 +126,37 @@ typedef int (*regmap_hw_read)(struct device *dev,
* a read.
*/
struct regmap_bus {
bool fast_io;
regmap_hw_write write;
regmap_hw_gather_write gather_write;
regmap_hw_read read;
regmap_hw_free_context free_context;
u8 read_flag_mask;
};
struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config);
struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config);
struct regmap *regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config);
struct regmap *regmap_init_mmio(struct device *dev,
void __iomem *regs,
const struct regmap_config *config);
struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config);
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config);
struct regmap *devm_regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config);
struct regmap *devm_regmap_init_mmio(struct device *dev,
void __iomem *regs,
const struct regmap_config *config);
void regmap_exit(struct regmap *map);
int regmap_reinit_cache(struct regmap *map,