Merge branches 'regmap-core', 'regmap-stride', 'regmap-mmio' and 'regmap-irq' into regmap-next
This commit is contained in:
@@ -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
|
||||
|
@@ -31,16 +31,25 @@ struct regmap_format {
|
||||
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;
|
||||
const char *name;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs;
|
||||
const char *debugfs_name;
|
||||
#endif
|
||||
|
||||
unsigned int max_register;
|
||||
@@ -54,6 +63,7 @@ struct regmap {
|
||||
|
||||
/* number of bits to (left) shift the reg value when formatting*/
|
||||
int reg_shift;
|
||||
int reg_stride;
|
||||
|
||||
/* regcache specific members */
|
||||
const struct regcache_ops *cache_ops;
|
||||
@@ -82,6 +92,9 @@ struct regmap {
|
||||
|
||||
struct reg_default *patch;
|
||||
int patch_regs;
|
||||
|
||||
/* if set, converts bulk rw to single rw */
|
||||
bool use_single_rw;
|
||||
};
|
||||
|
||||
struct regcache_ops {
|
||||
@@ -104,11 +117,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
|
||||
|
||||
|
@@ -108,7 +108,7 @@ static int regcache_lzo_decompress_cache_block(struct regmap *map,
|
||||
static inline int regcache_lzo_get_blkindex(struct regmap *map,
|
||||
unsigned int reg)
|
||||
{
|
||||
return (reg * map->cache_word_size) /
|
||||
return ((reg / map->reg_stride) * map->cache_word_size) /
|
||||
DIV_ROUND_UP(map->cache_size_raw,
|
||||
regcache_lzo_block_count(map));
|
||||
}
|
||||
@@ -116,9 +116,10 @@ static inline int regcache_lzo_get_blkindex(struct regmap *map,
|
||||
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)) /
|
||||
map->cache_word_size);
|
||||
return (reg / map->reg_stride) %
|
||||
(DIV_ROUND_UP(map->cache_size_raw,
|
||||
regcache_lzo_block_count(map)) /
|
||||
map->cache_word_size);
|
||||
}
|
||||
|
||||
static inline int regcache_lzo_get_blksize(struct regmap *map)
|
||||
@@ -322,7 +323,7 @@ static int regcache_lzo_write(struct regmap *map,
|
||||
}
|
||||
|
||||
/* set the bit so we know we have to sync this register */
|
||||
set_bit(reg, lzo_block->sync_bmp);
|
||||
set_bit(reg / map->reg_stride, lzo_block->sync_bmp);
|
||||
kfree(tmp_dst);
|
||||
kfree(lzo_block->src);
|
||||
return 0;
|
||||
|
@@ -39,11 +39,12 @@ struct regcache_rbtree_ctx {
|
||||
};
|
||||
|
||||
static inline void regcache_rbtree_get_base_top_reg(
|
||||
struct regmap *map,
|
||||
struct regcache_rbtree_node *rbnode,
|
||||
unsigned int *base, unsigned int *top)
|
||||
{
|
||||
*base = rbnode->base_reg;
|
||||
*top = rbnode->base_reg + rbnode->blklen - 1;
|
||||
*top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
|
||||
}
|
||||
|
||||
static unsigned int regcache_rbtree_get_register(
|
||||
@@ -70,7 +71,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
|
||||
|
||||
rbnode = rbtree_ctx->cached_rbnode;
|
||||
if (rbnode) {
|
||||
regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
|
||||
regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
|
||||
&top_reg);
|
||||
if (reg >= base_reg && reg <= top_reg)
|
||||
return rbnode;
|
||||
}
|
||||
@@ -78,7 +80,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
|
||||
node = rbtree_ctx->root.rb_node;
|
||||
while (node) {
|
||||
rbnode = container_of(node, struct regcache_rbtree_node, node);
|
||||
regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
|
||||
regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
|
||||
&top_reg);
|
||||
if (reg >= base_reg && reg <= top_reg) {
|
||||
rbtree_ctx->cached_rbnode = rbnode;
|
||||
return rbnode;
|
||||
@@ -92,7 +95,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int regcache_rbtree_insert(struct rb_root *root,
|
||||
static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root,
|
||||
struct regcache_rbtree_node *rbnode)
|
||||
{
|
||||
struct rb_node **new, *parent;
|
||||
@@ -106,7 +109,7 @@ static int regcache_rbtree_insert(struct rb_root *root,
|
||||
rbnode_tmp = container_of(*new, struct regcache_rbtree_node,
|
||||
node);
|
||||
/* base and top registers of the current rbnode */
|
||||
regcache_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
|
||||
regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp,
|
||||
&top_reg_tmp);
|
||||
/* base register of the rbnode to be added */
|
||||
base_reg = rbnode->base_reg;
|
||||
@@ -138,24 +141,31 @@ static int rbtree_show(struct seq_file *s, void *ignored)
|
||||
unsigned int base, top;
|
||||
int nodes = 0;
|
||||
int registers = 0;
|
||||
int this_registers, average;
|
||||
|
||||
mutex_lock(&map->lock);
|
||||
map->lock(map);
|
||||
|
||||
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);
|
||||
regcache_rbtree_get_base_top_reg(map, n, &base, &top);
|
||||
this_registers = ((top - base) / map->reg_stride) + 1;
|
||||
seq_printf(s, "%x-%x (%d)\n", base, top, this_registers);
|
||||
|
||||
nodes++;
|
||||
registers += top - base + 1;
|
||||
registers += this_registers;
|
||||
}
|
||||
|
||||
seq_printf(s, "%d nodes, %d registers, average %d registers\n",
|
||||
nodes, registers, registers / nodes);
|
||||
if (nodes)
|
||||
average = registers / nodes;
|
||||
else
|
||||
average = 0;
|
||||
|
||||
mutex_unlock(&map->lock);
|
||||
seq_printf(s, "%d nodes, %d registers, average %d registers\n",
|
||||
nodes, registers, average);
|
||||
|
||||
map->unlock(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -249,7 +259,7 @@ static int regcache_rbtree_read(struct regmap *map,
|
||||
|
||||
rbnode = regcache_rbtree_lookup(map, reg);
|
||||
if (rbnode) {
|
||||
reg_tmp = reg - rbnode->base_reg;
|
||||
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
|
||||
*value = regcache_rbtree_get_register(rbnode, reg_tmp,
|
||||
map->cache_word_size);
|
||||
} else {
|
||||
@@ -304,7 +314,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
||||
*/
|
||||
rbnode = regcache_rbtree_lookup(map, reg);
|
||||
if (rbnode) {
|
||||
reg_tmp = reg - rbnode->base_reg;
|
||||
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
|
||||
val = regcache_rbtree_get_register(rbnode, reg_tmp,
|
||||
map->cache_word_size);
|
||||
if (val == value)
|
||||
@@ -315,13 +325,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
||||
/* look for an adjacent register to the one we are about to add */
|
||||
for (node = rb_first(&rbtree_ctx->root); node;
|
||||
node = rb_next(node)) {
|
||||
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node);
|
||||
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
|
||||
node);
|
||||
for (i = 0; i < rbnode_tmp->blklen; i++) {
|
||||
reg_tmp = rbnode_tmp->base_reg + i;
|
||||
if (abs(reg_tmp - reg) != 1)
|
||||
reg_tmp = rbnode_tmp->base_reg +
|
||||
(i * map->reg_stride);
|
||||
if (abs(reg_tmp - reg) != map->reg_stride)
|
||||
continue;
|
||||
/* decide where in the block to place our register */
|
||||
if (reg_tmp + 1 == reg)
|
||||
if (reg_tmp + map->reg_stride == reg)
|
||||
pos = i + 1;
|
||||
else
|
||||
pos = i;
|
||||
@@ -351,7 +363,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
||||
return -ENOMEM;
|
||||
}
|
||||
regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
|
||||
regcache_rbtree_insert(&rbtree_ctx->root, rbnode);
|
||||
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
|
||||
rbtree_ctx->cached_rbnode = rbnode;
|
||||
}
|
||||
|
||||
@@ -391,12 +403,12 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
|
||||
end = rbnode->blklen;
|
||||
|
||||
for (i = base; i < end; i++) {
|
||||
regtmp = rbnode->base_reg + i;
|
||||
regtmp = rbnode->base_reg + (i * map->reg_stride);
|
||||
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);
|
||||
ret = regcache_lookup_reg(map, regtmp);
|
||||
if (ret >= 0 && val == map->reg_defaults[ret].def)
|
||||
continue;
|
||||
|
||||
|
@@ -59,7 +59,7 @@ static int regcache_hw_init(struct regmap *map)
|
||||
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
|
||||
val = regcache_get_val(map->reg_defaults_raw,
|
||||
i, map->cache_word_size);
|
||||
if (regmap_volatile(map, i))
|
||||
if (regmap_volatile(map, i * map->reg_stride))
|
||||
continue;
|
||||
count++;
|
||||
}
|
||||
@@ -76,9 +76,9 @@ static int regcache_hw_init(struct regmap *map)
|
||||
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
|
||||
val = regcache_get_val(map->reg_defaults_raw,
|
||||
i, map->cache_word_size);
|
||||
if (regmap_volatile(map, i))
|
||||
if (regmap_volatile(map, i * map->reg_stride))
|
||||
continue;
|
||||
map->reg_defaults[j].reg = i;
|
||||
map->reg_defaults[j].reg = i * map->reg_stride;
|
||||
map->reg_defaults[j].def = val;
|
||||
j++;
|
||||
}
|
||||
@@ -98,6 +98,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
|
||||
int i;
|
||||
void *tmp_buf;
|
||||
|
||||
for (i = 0; i < config->num_reg_defaults; i++)
|
||||
if (config->reg_defaults[i].reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
if (map->cache_type == REGCACHE_NONE) {
|
||||
map->cache_bypass = true;
|
||||
return 0;
|
||||
@@ -264,7 +268,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",
|
||||
@@ -278,6 +282,10 @@ int regcache_sync(struct regmap *map)
|
||||
/* Apply any patch first */
|
||||
map->cache_bypass = 1;
|
||||
for (i = 0; i < map->patch_regs; i++) {
|
||||
if (map->patch[i].reg % map->reg_stride) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
|
||||
if (ret != 0) {
|
||||
dev_err(map->dev, "Failed to write %x = %x: %d\n",
|
||||
@@ -296,7 +304,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 +331,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,10 +350,11 @@ 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;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regcache_sync_region);
|
||||
|
||||
/**
|
||||
* regcache_cache_only: Put a register map into cache only mode
|
||||
@@ -361,11 +370,11 @@ out:
|
||||
*/
|
||||
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);
|
||||
|
||||
@@ -380,9 +389,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);
|
||||
|
||||
@@ -399,11 +408,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);
|
||||
|
||||
|
@@ -27,12 +27,6 @@ static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static int regmap_open_file(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t regmap_name_read_file(struct file *file,
|
||||
char __user *user_buf, size_t count,
|
||||
loff_t *ppos)
|
||||
@@ -57,7 +51,7 @@ static ssize_t regmap_name_read_file(struct file *file,
|
||||
}
|
||||
|
||||
static const struct file_operations regmap_name_fops = {
|
||||
.open = regmap_open_file,
|
||||
.open = simple_open,
|
||||
.read = regmap_name_read_file,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
@@ -86,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
|
||||
val_len = 2 * map->format.val_bytes;
|
||||
tot_len = reg_len + val_len + 3; /* : \n */
|
||||
|
||||
for (i = 0; i < map->max_register + 1; i++) {
|
||||
for (i = 0; i <= map->max_register; i += map->reg_stride) {
|
||||
if (!regmap_readable(map, i))
|
||||
continue;
|
||||
|
||||
@@ -174,7 +168,7 @@ static ssize_t regmap_map_write_file(struct file *file,
|
||||
#endif
|
||||
|
||||
static const struct file_operations regmap_map_fops = {
|
||||
.open = regmap_open_file,
|
||||
.open = simple_open,
|
||||
.read = regmap_map_read_file,
|
||||
.write = regmap_map_write_file,
|
||||
.llseek = default_llseek,
|
||||
@@ -203,7 +197,7 @@ static ssize_t regmap_access_read_file(struct file *file,
|
||||
reg_len = regmap_calc_reg_len(map->max_register, buf, count);
|
||||
tot_len = reg_len + 10; /* ': R W V P\n' */
|
||||
|
||||
for (i = 0; i < map->max_register + 1; i++) {
|
||||
for (i = 0; i <= map->max_register; i += map->reg_stride) {
|
||||
/* Ignore registers which are neither readable nor writable */
|
||||
if (!regmap_readable(map, i) && !regmap_writeable(map, i))
|
||||
continue;
|
||||
@@ -243,15 +237,22 @@ out:
|
||||
}
|
||||
|
||||
static const struct file_operations regmap_access_fops = {
|
||||
.open = regmap_open_file,
|
||||
.open = simple_open,
|
||||
.read = regmap_access_read_file,
|
||||
.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;
|
||||
@@ -280,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);
|
||||
|
||||
|
@@ -50,6 +50,7 @@ static void regmap_irq_lock(struct irq_data *data)
|
||||
static void regmap_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
|
||||
struct regmap *map = d->map;
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
@@ -58,11 +59,12 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
|
||||
* suppress pointless writes.
|
||||
*/
|
||||
for (i = 0; i < d->chip->num_regs; i++) {
|
||||
ret = regmap_update_bits(d->map, d->chip->mask_base + i,
|
||||
ret = regmap_update_bits(d->map, d->chip->mask_base +
|
||||
(i * map->reg_stride),
|
||||
d->mask_buf_def[i], d->mask_buf[i]);
|
||||
if (ret != 0)
|
||||
dev_err(d->map->dev, "Failed to sync masks in %x\n",
|
||||
d->chip->mask_base + i);
|
||||
d->chip->mask_base + (i * map->reg_stride));
|
||||
}
|
||||
|
||||
mutex_unlock(&d->lock);
|
||||
@@ -71,17 +73,19 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
|
||||
static void regmap_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
|
||||
struct regmap *map = d->map;
|
||||
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
|
||||
|
||||
d->mask_buf[irq_data->reg_offset] &= ~irq_data->mask;
|
||||
d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void regmap_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
|
||||
struct regmap *map = d->map;
|
||||
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
|
||||
|
||||
d->mask_buf[irq_data->reg_offset] |= irq_data->mask;
|
||||
d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
|
||||
}
|
||||
|
||||
static struct irq_chip regmap_irq_chip = {
|
||||
@@ -136,17 +140,19 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
|
||||
data->status_buf[i] &= ~data->mask_buf[i];
|
||||
|
||||
if (data->status_buf[i] && chip->ack_base) {
|
||||
ret = regmap_write(map, chip->ack_base + i,
|
||||
ret = regmap_write(map, chip->ack_base +
|
||||
(i * map->reg_stride),
|
||||
data->status_buf[i]);
|
||||
if (ret != 0)
|
||||
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
|
||||
chip->ack_base + i, ret);
|
||||
chip->ack_base + (i * map->reg_stride),
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < chip->num_irqs; i++) {
|
||||
if (data->status_buf[chip->irqs[i].reg_offset] &
|
||||
chip->irqs[i].mask) {
|
||||
if (data->status_buf[chip->irqs[i].reg_offset /
|
||||
map->reg_stride] & chip->irqs[i].mask) {
|
||||
handle_nested_irq(data->irq_base + i);
|
||||
handled = true;
|
||||
}
|
||||
@@ -181,6 +187,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
||||
int cur_irq, i;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
for (i = 0; i < chip->num_irqs; i++) {
|
||||
if (chip->irqs[i].reg_offset % map->reg_stride)
|
||||
return -EINVAL;
|
||||
if (chip->irqs[i].reg_offset / map->reg_stride >=
|
||||
chip->num_regs)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
|
||||
@@ -192,6 +206,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
*data = d;
|
||||
|
||||
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
|
||||
GFP_KERNEL);
|
||||
if (!d->status_buf)
|
||||
@@ -218,16 +234,17 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
||||
mutex_init(&d->lock);
|
||||
|
||||
for (i = 0; i < chip->num_irqs; i++)
|
||||
d->mask_buf_def[chip->irqs[i].reg_offset]
|
||||
d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride]
|
||||
|= chip->irqs[i].mask;
|
||||
|
||||
/* Mask all the interrupts by default */
|
||||
for (i = 0; i < chip->num_regs; i++) {
|
||||
d->mask_buf[i] = d->mask_buf_def[i];
|
||||
ret = regmap_write(map, chip->mask_base + i, d->mask_buf[i]);
|
||||
ret = regmap_write(map, chip->mask_base + (i * map->reg_stride),
|
||||
d->mask_buf[i]);
|
||||
if (ret != 0) {
|
||||
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
|
||||
chip->mask_base + i, ret);
|
||||
chip->mask_base + (i * map->reg_stride), ret);
|
||||
goto err_alloc;
|
||||
}
|
||||
}
|
||||
|
224
drivers/base/regmap/regmap-mmio.c
Normal file
224
drivers/base/regmap/regmap-mmio.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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;
|
||||
int min_stride;
|
||||
|
||||
if (config->reg_bits != 32)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (config->pad_bits)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
switch (config->val_bits) {
|
||||
case 8:
|
||||
/* The core treats 0 as 1 */
|
||||
min_stride = 0;
|
||||
break;
|
||||
case 16:
|
||||
min_stride = 2;
|
||||
break;
|
||||
case 32:
|
||||
min_stride = 4;
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 64:
|
||||
min_stride = 8;
|
||||
break;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (config->reg_stride < min_stride)
|
||||
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);
|
||||
|
||||
|
@@ -179,11 +179,41 @@ 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);
|
||||
}
|
||||
|
||||
static void dev_get_regmap_release(struct device *dev, void *res)
|
||||
{
|
||||
/*
|
||||
* We don't actually have anything to do here; the goal here
|
||||
* is not to manage the regmap but to provide a simple way to
|
||||
* get the regmap back given a struct device.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -192,9 +222,10 @@ 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;
|
||||
struct regmap *map, **m;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!bus || !config)
|
||||
@@ -206,21 +237,36 @@ 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;
|
||||
if (config->reg_stride)
|
||||
map->reg_stride = config->reg_stride;
|
||||
else
|
||||
map->reg_stride = 1;
|
||||
map->use_single_rw = config->use_single_rw;
|
||||
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;
|
||||
map->volatile_reg = config->volatile_reg;
|
||||
map->precious_reg = config->precious_reg;
|
||||
map->cache_type = config->cache_type;
|
||||
map->name = config->name;
|
||||
|
||||
if (config->read_flag_mask || config->write_flag_mask) {
|
||||
map->read_flag_mask = config->read_flag_mask;
|
||||
@@ -305,6 +351,9 @@ struct regmap *regmap_init(struct device *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
if (map->format.format_write)
|
||||
map->use_single_rw = true;
|
||||
|
||||
if (!map->format.format_write &&
|
||||
!(map->format.format_reg && map->format.format_val))
|
||||
goto err_map;
|
||||
@@ -315,14 +364,25 @@ 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)
|
||||
goto err_free_workbuf;
|
||||
|
||||
/* Add a devres resource for dev_get_regmap() */
|
||||
m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
|
||||
if (!m) {
|
||||
ret = -ENOMEM;
|
||||
goto err_cache;
|
||||
}
|
||||
*m = map;
|
||||
devres_add(dev, m);
|
||||
|
||||
return map;
|
||||
|
||||
err_cache:
|
||||
regcache_exit(map);
|
||||
err_free_workbuf:
|
||||
kfree(map->work_buf);
|
||||
err_map:
|
||||
@@ -342,6 +402,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
|
||||
@@ -351,6 +412,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;
|
||||
@@ -359,7 +421,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);
|
||||
@@ -386,7 +448,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);
|
||||
@@ -398,14 +460,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;
|
||||
}
|
||||
@@ -417,11 +479,51 @@ 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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_exit);
|
||||
|
||||
static int dev_get_regmap_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct regmap **r = res;
|
||||
if (!r || !*r) {
|
||||
WARN_ON(!r || !*r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the user didn't specify a name match any */
|
||||
if (data)
|
||||
return (*r)->name == data;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_get_regmap(): Obtain the regmap (if any) for a device
|
||||
*
|
||||
* @dev: Device to retrieve the map for
|
||||
* @name: Optional name for the register map, usually NULL.
|
||||
*
|
||||
* Returns the regmap for the device if one is present, or NULL. If
|
||||
* name is specified then it must match the name specified when
|
||||
* registering the device, if it is NULL then the first regmap found
|
||||
* will be used. Devices with multiple register maps are very rare,
|
||||
* generic code should normally not need to specify a name.
|
||||
*/
|
||||
struct regmap *dev_get_regmap(struct device *dev, const char *name)
|
||||
{
|
||||
struct regmap **r = devres_find(dev, dev_get_regmap_release,
|
||||
dev_get_regmap_match, (void *)name);
|
||||
|
||||
if (!r)
|
||||
return NULL;
|
||||
return *r;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_get_regmap);
|
||||
|
||||
static int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
const void *val, size_t val_len)
|
||||
{
|
||||
@@ -434,7 +536,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
/* Check for unwritable registers before we start */
|
||||
if (map->writeable_reg)
|
||||
for (i = 0; i < val_len / map->format.val_bytes; i++)
|
||||
if (!map->writeable_reg(map->dev, reg + i))
|
||||
if (!map->writeable_reg(map->dev,
|
||||
reg + (i * map->reg_stride)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!map->cache_bypass && map->format.parse_val) {
|
||||
@@ -443,7 +546,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
for (i = 0; i < val_len / val_bytes; i++) {
|
||||
memcpy(map->work_buf, val + (i * val_bytes), val_bytes);
|
||||
ival = map->format.parse_val(map->work_buf);
|
||||
ret = regcache_write(map, reg + i, ival);
|
||||
ret = regcache_write(map, reg + (i * map->reg_stride),
|
||||
ival);
|
||||
if (ret) {
|
||||
dev_err(map->dev,
|
||||
"Error in caching of register: %u ret: %d\n",
|
||||
@@ -470,12 +574,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);
|
||||
@@ -490,7 +594,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);
|
||||
}
|
||||
@@ -524,7 +628,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);
|
||||
@@ -555,11 +659,14 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&map->lock);
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map);
|
||||
|
||||
ret = _regmap_write(map, reg, val);
|
||||
|
||||
mutex_unlock(&map->lock);
|
||||
map->unlock(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -586,11 +693,16 @@ 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;
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map);
|
||||
|
||||
ret = _regmap_raw_write(map, reg, val, val_len);
|
||||
|
||||
mutex_unlock(&map->lock);
|
||||
map->unlock(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -619,8 +731,10 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
||||
|
||||
if (!map->format.parse_val)
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&map->lock);
|
||||
map->lock(map);
|
||||
|
||||
/* No formatting is require if val_byte is 1 */
|
||||
if (val_bytes == 1) {
|
||||
@@ -635,13 +749,28 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
||||
for (i = 0; i < val_count * val_bytes; i += val_bytes)
|
||||
map->format.parse_val(wval + i);
|
||||
}
|
||||
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
|
||||
/*
|
||||
* Some devices does not support bulk write, for
|
||||
* them we have a series of single write operations.
|
||||
*/
|
||||
if (map->use_single_rw) {
|
||||
for (i = 0; i < val_count; i++) {
|
||||
ret = regmap_raw_write(map,
|
||||
reg + (i * map->reg_stride),
|
||||
val + (i * val_bytes),
|
||||
val_bytes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
|
||||
}
|
||||
|
||||
if (val_bytes != 1)
|
||||
kfree(wval);
|
||||
|
||||
out:
|
||||
mutex_unlock(&map->lock);
|
||||
map->unlock(map);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_bulk_write);
|
||||
@@ -665,7 +794,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);
|
||||
|
||||
@@ -718,11 +847,14 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&map->lock);
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map);
|
||||
|
||||
ret = _regmap_read(map, reg, val);
|
||||
|
||||
mutex_unlock(&map->lock);
|
||||
map->unlock(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -747,7 +879,12 @@ 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;
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map);
|
||||
|
||||
if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
|
||||
map->cache_type == REGCACHE_NONE) {
|
||||
@@ -759,7 +896,8 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
|
||||
* cost as we expect to hit the cache.
|
||||
*/
|
||||
for (i = 0; i < val_count; i++) {
|
||||
ret = _regmap_read(map, reg + i, &v);
|
||||
ret = _regmap_read(map, reg + (i * map->reg_stride),
|
||||
&v);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
||||
@@ -768,7 +906,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&map->lock);
|
||||
map->unlock(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -794,19 +932,40 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
|
||||
|
||||
if (!map->format.parse_val)
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
if (vol || map->cache_type == REGCACHE_NONE) {
|
||||
ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
/*
|
||||
* Some devices does not support bulk read, for
|
||||
* them we have a series of single read operations.
|
||||
*/
|
||||
if (map->use_single_rw) {
|
||||
for (i = 0; i < val_count; i++) {
|
||||
ret = regmap_raw_read(map,
|
||||
reg + (i * map->reg_stride),
|
||||
val + (i * val_bytes),
|
||||
val_bytes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = regmap_raw_read(map, reg, val,
|
||||
val_bytes * val_count);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < val_count * val_bytes; i += val_bytes)
|
||||
map->format.parse_val(val + i);
|
||||
} else {
|
||||
for (i = 0; i < val_count; i++) {
|
||||
ret = regmap_read(map, reg + i, val + (i * val_bytes));
|
||||
unsigned int ival;
|
||||
ret = regmap_read(map, reg + (i * map->reg_stride),
|
||||
&ival);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
memcpy(val + (i * val_bytes), &ival, val_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,7 +980,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)
|
||||
@@ -838,7 +997,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&map->lock);
|
||||
map->unlock(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -905,7 +1064,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;
|
||||
|
||||
@@ -933,7 +1092,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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user