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

Commit 5062ecdb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull regmap updates from Mark Brown:
 "Quite a few new features for regmap this time, mostly expanding things
  around the edges of the existing functionality to cover more devices
  rather than thinsg with wide applicability:

   - Support for offload of the update_bits() operation to hardware
     where devices implement bit level access.
   - Support for a few extra operations that need scratch buffers on
     fast_io devices where we can't sleep.
   - Expanded the feature set of regmap_irq to cope with some extra
     register layouts.
   - Cleanups to the debugfs code"

* tag 'regmap-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: Allow installing custom reg_update_bits function
  regmap: debugfs: simplify regmap_reg_ranges_read_file() slightly
  regmap: debugfs: use memcpy instead of snprintf
  regmap: debugfs: use snprintf return value in regmap_reg_ranges_read_file()
  regmap: Add generic macro to define regmap_irq
  regmap: debugfs: Remove scratch buffer for register length calculation
  regmap: irq: add ack_invert flag for chips using cleared bits as ack
  regmap: irq: add support for chips who have separate unmask registers
  regmap: Allocate buffers with GFP_ATOMIC when fast_io == true
parents e86328c4 d4a1a317
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ struct regmap {
	regmap_lock lock;
	regmap_unlock unlock;
	void *lock_arg; /* This is passed to lock/unlock functions */
	gfp_t alloc_flags;

	struct device *dev; /* Device we do I/O on */
	void *work_buf;     /* Scratch buffer used to format I/O */
@@ -98,6 +99,8 @@ struct regmap {

	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
	int (*reg_update_bits)(void *context, unsigned int reg,
			       unsigned int mask, unsigned int val);

	bool defer_caching;

+10 −13
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ static LIST_HEAD(regmap_debugfs_early_list);
static DEFINE_MUTEX(regmap_debugfs_early_lock);

/* Calculate the length of a fixed format  */
static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
static size_t regmap_calc_reg_len(int max_val)
{
	return snprintf(NULL, 0, "%x", max_val);
}
@@ -173,8 +173,7 @@ static inline void regmap_calc_tot_len(struct regmap *map,
{
	/* Calculate the length of a fixed format  */
	if (!map->debugfs_tot_len) {
		map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
							   buf, count);
		map->debugfs_reg_len = regmap_calc_reg_len(map->max_register),
		map->debugfs_val_len = 2 * map->format.val_bytes;
		map->debugfs_tot_len = map->debugfs_reg_len +
			map->debugfs_val_len + 3;      /* : \n */
@@ -338,6 +337,7 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file,
	char *buf;
	char *entry;
	int ret;
	unsigned entry_len;

	if (*ppos < 0 || !count)
		return -EINVAL;
@@ -365,18 +365,15 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file,
	p = 0;
	mutex_lock(&map->cache_lock);
	list_for_each_entry(c, &map->debugfs_off_cache, list) {
		snprintf(entry, PAGE_SIZE, "%x-%x",
		entry_len = snprintf(entry, PAGE_SIZE, "%x-%x\n",
				     c->base_reg, c->max_reg);
		if (p >= *ppos) {
			if (buf_pos + 1 + strlen(entry) > count)
			if (buf_pos + entry_len > count)
				break;
			snprintf(buf + buf_pos, count - buf_pos,
				 "%s", entry);
			buf_pos += strlen(entry);
			buf[buf_pos] = '\n';
			buf_pos++;
			memcpy(buf + buf_pos, entry, entry_len);
			buf_pos += entry_len;
		}
		p += strlen(entry) + 1;
		p += entry_len;
	}
	mutex_unlock(&map->cache_lock);

@@ -420,7 +417,7 @@ static ssize_t regmap_access_read_file(struct file *file,
		return -ENOMEM;

	/* Calculate the length of a fixed format  */
	reg_len = regmap_calc_reg_len(map->max_register, buf, count);
	reg_len = regmap_calc_reg_len(map->max_register);
	tot_len = reg_len + 10; /* ': R W V P\n' */

	for (i = 0; i <= map->max_register; i += map->reg_stride) {
+38 −5
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
	struct regmap *map = d->map;
	int i, ret;
	u32 reg;
	u32 unmask_offset;

	if (d->chip->runtime_pm) {
		ret = pm_runtime_get_sync(map->dev);
@@ -79,12 +80,28 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
	for (i = 0; i < d->chip->num_regs; i++) {
		reg = d->chip->mask_base +
			(i * map->reg_stride * d->irq_reg_stride);
		if (d->chip->mask_invert)
		if (d->chip->mask_invert) {
			ret = regmap_update_bits(d->map, reg,
					 d->mask_buf_def[i], ~d->mask_buf[i]);
		else
		} else if (d->chip->unmask_base) {
			/* set mask with mask_base register */
			ret = regmap_update_bits(d->map, reg,
					d->mask_buf_def[i], ~d->mask_buf[i]);
			if (ret < 0)
				dev_err(d->map->dev,
					"Failed to sync unmasks in %x\n",
					reg);
			unmask_offset = d->chip->unmask_base -
							d->chip->mask_base;
			/* clear mask with unmask_base register */
			ret = regmap_update_bits(d->map,
					reg + unmask_offset,
					d->mask_buf_def[i],
					d->mask_buf[i]);
		} else {
			ret = regmap_update_bits(d->map, reg,
					 d->mask_buf_def[i], d->mask_buf[i]);
		}
		if (ret != 0)
			dev_err(d->map->dev, "Failed to sync masks in %x\n",
				reg);
@@ -116,6 +133,10 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
		if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) {
			reg = d->chip->ack_base +
				(i * map->reg_stride * d->irq_reg_stride);
			/* some chips ack by write 0 */
			if (d->chip->ack_invert)
				ret = regmap_write(map, reg, ~d->mask_buf[i]);
			else
				ret = regmap_write(map, reg, d->mask_buf[i]);
			if (ret != 0)
				dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
@@ -339,6 +360,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
	int i;
	int ret = -ENOMEM;
	u32 reg;
	u32 unmask_offset;

	if (chip->num_regs <= 0)
		return -EINVAL;
@@ -420,7 +442,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
		if (chip->mask_invert)
			ret = regmap_update_bits(map, reg,
					 d->mask_buf[i], ~d->mask_buf[i]);
		else
		else if (d->chip->unmask_base) {
			unmask_offset = d->chip->unmask_base -
					d->chip->mask_base;
			ret = regmap_update_bits(d->map,
					reg + unmask_offset,
					d->mask_buf[i],
					d->mask_buf[i]);
		} else
			ret = regmap_update_bits(map, reg,
					 d->mask_buf[i], d->mask_buf[i]);
		if (ret != 0) {
@@ -445,6 +474,10 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
		if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
			reg = chip->ack_base +
				(i * map->reg_stride * d->irq_reg_stride);
			if (chip->ack_invert)
				ret = regmap_write(map, reg,
					~(d->status_buf[i] & d->mask_buf[i]));
			else
				ret = regmap_write(map, reg,
					d->status_buf[i] & d->mask_buf[i]);
			if (ret != 0) {
+29 −12
Original line number Diff line number Diff line
@@ -561,6 +561,16 @@ struct regmap *__regmap_init(struct device *dev,
		}
		map->lock_arg = map;
	}

	/*
	 * When we write in fast-paths with regmap_bulk_write() don't allocate
	 * scratch buffers with sleeping allocations.
	 */
	if ((bus && bus->fast_io) || config->fast_io)
		map->alloc_flags = GFP_ATOMIC;
	else
		map->alloc_flags = GFP_KERNEL;

	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);
@@ -619,6 +629,7 @@ struct regmap *__regmap_init(struct device *dev,
		goto skip_format_initialization;
	} else {
		map->reg_read  = _regmap_bus_read;
		map->reg_update_bits = bus->reg_update_bits;
	}

	reg_endian = regmap_get_reg_endian(bus, config);
@@ -1786,7 +1797,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
		if (!val_count)
			return -EINVAL;

		wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
		wval = kmemdup(val, val_count * val_bytes, map->alloc_flags);
		if (!wval) {
			dev_err(map->dev, "Error in memory allocation\n");
			return -ENOMEM;
@@ -2509,6 +2520,14 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
	int ret;
	unsigned int tmp, orig;

	if (change)
		*change = false;

	if (regmap_volatile(map, reg) && map->reg_update_bits) {
		ret = map->reg_update_bits(map->bus_context, reg, mask, val);
		if (ret == 0 && change)
			*change = true;
	} else {
		ret = _regmap_read(map, reg, &orig);
		if (ret != 0)
			return ret;
@@ -2518,11 +2537,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,

		if (force_write || (tmp != orig)) {
			ret = _regmap_write(map, reg, tmp);
		if (change)
			if (ret == 0 && change)
				*change = true;
	} else {
		if (change)
			*change = false;
		}
	}

	return ret;
+11 −0
Original line number Diff line number Diff line
@@ -296,6 +296,8 @@ typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg,
				  unsigned int *val);
typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg,
				   unsigned int val);
typedef int (*regmap_hw_reg_update_bits)(void *context, unsigned int reg,
					 unsigned int mask, unsigned int val);
typedef struct regmap_async *(*regmap_hw_async_alloc)(void);
typedef void (*regmap_hw_free_context)(void *context);

@@ -335,6 +337,7 @@ struct regmap_bus {
	regmap_hw_gather_write gather_write;
	regmap_hw_async_write async_write;
	regmap_hw_reg_write reg_write;
	regmap_hw_reg_update_bits reg_update_bits;
	regmap_hw_read read;
	regmap_hw_reg_read reg_read;
	regmap_hw_free_context free_context;
@@ -791,6 +794,9 @@ struct regmap_irq {
	unsigned int mask;
};

#define REGMAP_IRQ_REG(_irq, _off, _mask)		\
	[_irq] = { .reg_offset = (_off), .mask = (_mask) }

/**
 * Description of a generic regmap irq_chip.  This is not intended to
 * handle every possible interrupt controller, but it should handle a
@@ -800,6 +806,8 @@ struct regmap_irq {
 *
 * @status_base: Base status register address.
 * @mask_base:   Base mask register address.
 * @unmask_base:  Base unmask register address. for chips who have
 *                separate mask and unmask registers
 * @ack_base:    Base ack address. If zero then the chip is clear on read.
 *               Using zero value is possible with @use_ack bit.
 * @wake_base:   Base address for wake enables.  If zero unsupported.
@@ -807,6 +815,7 @@ struct regmap_irq {
 * @init_ack_masked: Ack all masked interrupts once during initalization.
 * @mask_invert: Inverted mask register: cleared bits are masked out.
 * @use_ack:     Use @ack register even if it is zero.
 * @ack_invert:  Inverted ack register: cleared bits for ack.
 * @wake_invert: Inverted wake register: cleared bits are wake enabled.
 * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
 *
@@ -820,12 +829,14 @@ struct regmap_irq_chip {

	unsigned int status_base;
	unsigned int mask_base;
	unsigned int unmask_base;
	unsigned int ack_base;
	unsigned int wake_base;
	unsigned int irq_reg_stride;
	bool init_ack_masked:1;
	bool mask_invert:1;
	bool use_ack:1;
	bool ack_invert:1;
	bool wake_invert:1;
	bool runtime_pm:1;