Merge branches 'regmap-core', 'regmap-mmio' and 'regmap-naming' into regmap-stride
This commit is contained in:
Коммит
c0cc6fe1d0
|
@ -14,5 +14,8 @@ config REGMAP_I2C
|
|||
config REGMAP_SPI
|
||||
tristate
|
||||
|
||||
config REGMAP_MMIO
|
||||
tristate
|
||||
|
||||
config REGMAP_IRQ
|
||||
bool
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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, ®map_i2c, config);
|
||||
return regmap_init(&i2c->dev, ®map_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, ®map_i2c, config);
|
||||
return devm_regmap_init(&i2c->dev, ®map_i2c, &i2c->dev, config);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);
|
||||
|
||||
|
|
|
@ -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, ®map_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, ®map_mmio, ctx, config);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -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, ®map_spi, config);
|
||||
return regmap_init(&spi->dev, ®map_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, ®map_spi, config);
|
||||
return devm_regmap_init(&spi->dev, ®map_spi, &spi->dev, config);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_regmap_init_spi);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче