Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae82a828 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull regmap updates from Mark Brown:
 "A surprisingly large series of updates for regmap this time, mostly
  due to all the work Stephen Warren has done to add support for MMIO
  buses.  This wasn't really the target for the framework but it turns
  out that there's a reasonable number of cases where it's very helpful
  to use the register cache support to allow the register map to remain
  available while the device is suspended.

  - A MMIO bus implementation, contributed by Stephen Warren.  Currently
    this is limited to 32 bit systems and native endian registers.
  - Support for naming register maps, mainly intended for MMIO devices
    with multiple register banks.  This was also contributed by Stephen
    Warren.
  - Support for register striding, again contributed by Stephen Warren
    and mainly intended for use with MMIO as typically the registers
    will be a fixed size but byte addressed.
  - irqdomain support for the generic regmap irq_chip, including support
    for dynamically allocate interrupt numbers.
  - A function dev_get_regmap() which allows frameworks using regmap to
    obtain the regmap for a device from the struct device, making life a
    little simpler for them.
  - Updates to regmap-irq to support more chips (contributed by Graeme
    Gregory) and to use irqdomains.
  - Support for devices with 24 bit register addresses.

  The striding support collided with all the topic branches so the
  branches look a bit messy and eventually I just gave up.  There's also
  the TI Palmas driver and a couple of other isolated MFD patches that
  all depend on new regmap features so are being merged here."

* tag 'regmap-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (24 commits)
  mfd: palmas PMIC device support Kconfig
  mfd: palmas PMIC device support
  regmap: Fix typo in IRQ register striding
  mfd: wm8994: Update to fully use irq_domain
  regmap: add support for non contiguous status to regmap-irq
  regmap: Convert regmap_irq to use irq_domain
  regmap: Pass back the allocated regmap IRQ controller data
  mfd: da9052: Fix genirq abuse
  regmap: Implement dev_get_regmap()
  regmap: Devices using format_write don't support bulk operations
  regmap: Converts group operation into single read write operations
  regmap: Cache single values read from the chip
  regmap: fix compile errors in regmap-irq.c due to stride changes
  regmap: implement register striding
  regmap: fix compilation when !CONFIG_DEBUG_FS
  regmap: allow regmap instances to be named
  regmap: validate regmap_raw_read/write val_len
  regmap: mmio: remove some error checks now in the core
  regmap: mmio: convert some error returns to BUG()
  regmap: add MMIO bus support
  ...
parents 3bb07f1b c948ef3a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -14,5 +14,8 @@ config REGMAP_I2C
config REGMAP_SPI
	tristate

config REGMAP_MMIO
	tristate

config REGMAP_IRQ
	bool
+1 −0
Original line number Diff line number Diff line
@@ -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
+21 −5
Original line number Diff line number Diff line
@@ -26,21 +26,30 @@ 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;
	const char *name;

#ifdef CONFIG_DEBUG_FS
	struct dentry *debugfs;
	const char *debugfs_name;
#endif

	unsigned int max_register;
@@ -52,6 +61,10 @@ struct regmap {
	u8 read_flag_mask;
	u8 write_flag_mask;

	/* 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;
	enum regcache_type cache_type;
@@ -79,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 {
@@ -101,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

+6 −5
Original line number Diff line number Diff line
@@ -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,7 +116,8 @@ 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,
	return (reg / map->reg_stride) %
		    (DIV_ROUND_UP(map->cache_size_raw,
				  regcache_lzo_block_count(map)) /
		     map->cache_word_size);
}
@@ -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;
+25 −19
Original line number Diff line number Diff line
@@ -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,19 +141,20 @@ static int rbtree_show(struct seq_file *s, void *ignored)
	unsigned int base, top;
	int nodes = 0;
	int registers = 0;
	int average;
	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;
	}

	if (nodes)
@@ -161,7 +165,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;
}
@@ -255,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 {
@@ -310,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)
@@ -321,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;
@@ -357,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;
	}

@@ -397,7 +403,7 @@ 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);

Loading