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

Commit e48b044e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull regmap updates from Mark Brown:
 "There are only two changes here:

   - fix for conflicting attributes on the rbtree node structure

   - implementation of main status register support in the interrupt
     code which supports chips that have a register to cut down on the
     number of per-interrupt status registers that need to be checked
     when handling interrupts"

* tag 'regmap-v5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: Remove attribute packed from struct 'regcache_rbtree_node'
  regmap: regmap-irq: Add main status register support
parents 42eaf185 66fb181d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ struct regcache_rbtree_node {
	unsigned int blklen;
	/* the actual rbtree node holding this block */
	struct rb_node node;
} __attribute__ ((packed));
};

struct regcache_rbtree_ctx {
	struct rb_root root;
+95 −4
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ struct regmap_irq_chip_data {
	int wake_count;

	void *status_reg_buf;
	unsigned int *main_status_buf;
	unsigned int *status_buf;
	unsigned int *mask_buf;
	unsigned int *mask_buf_def;
@@ -329,6 +330,33 @@ static const struct irq_chip regmap_irq_chip = {
	.irq_set_wake		= regmap_irq_set_wake,
};

static inline int read_sub_irq_data(struct regmap_irq_chip_data *data,
					   unsigned int b)
{
	const struct regmap_irq_chip *chip = data->chip;
	struct regmap *map = data->map;
	struct regmap_irq_sub_irq_map *subreg;
	int i, ret = 0;

	if (!chip->sub_reg_offsets) {
		/* Assume linear mapping */
		ret = regmap_read(map, chip->status_base +
				  (b * map->reg_stride * data->irq_reg_stride),
				   &data->status_buf[b]);
	} else {
		subreg = &chip->sub_reg_offsets[b];
		for (i = 0; i < subreg->num_regs; i++) {
			unsigned int offset = subreg->offset[i];

			ret = regmap_read(map, chip->status_base + offset,
					  &data->status_buf[offset]);
			if (ret)
				break;
		}
	}
	return ret;
}

static irqreturn_t regmap_irq_thread(int irq, void *d)
{
	struct regmap_irq_chip_data *data = d;
@@ -352,11 +380,65 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
	}

	/*
	 * Read in the statuses, using a single bulk read if possible
	 * in order to reduce the I/O overheads.
	 * Read only registers with active IRQs if the chip has 'main status
	 * register'. Else read in the statuses, using a single bulk read if
	 * possible in order to reduce the I/O overheads.
	 */
	if (!map->use_single_read && map->reg_stride == 1 &&

	if (chip->num_main_regs) {
		unsigned int max_main_bits;
		unsigned long size;

		size = chip->num_regs * sizeof(unsigned int);

		max_main_bits = (chip->num_main_status_bits) ?
				 chip->num_main_status_bits : chip->num_regs;
		/* Clear the status buf as we don't read all status regs */
		memset(data->status_buf, 0, size);

		/* We could support bulk read for main status registers
		 * but I don't expect to see devices with really many main
		 * status registers so let's only support single reads for the
		 * sake of simplicity. and add bulk reads only if needed
		 */
		for (i = 0; i < chip->num_main_regs; i++) {
			ret = regmap_read(map, chip->main_status +
				  (i * map->reg_stride
				   * data->irq_reg_stride),
				  &data->main_status_buf[i]);
			if (ret) {
				dev_err(map->dev,
					"Failed to read IRQ status %d\n",
					ret);
				goto exit;
			}
		}

		/* Read sub registers with active IRQs */
		for (i = 0; i < chip->num_main_regs; i++) {
			unsigned int b;
			const unsigned long mreg = data->main_status_buf[i];

			for_each_set_bit(b, &mreg, map->format.val_bytes * 8) {
				if (i * map->format.val_bytes * 8 + b >
				    max_main_bits)
					break;
				ret = read_sub_irq_data(data, b);

				if (ret != 0) {
					dev_err(map->dev,
						"Failed to read IRQ status %d\n",
						ret);
					if (chip->runtime_pm)
						pm_runtime_put(map->dev);
					goto exit;
				}
			}

		}
	} else if (!map->use_single_read && map->reg_stride == 1 &&
		   data->irq_reg_stride == 1) {

		u8 *buf8 = data->status_reg_buf;
		u16 *buf16 = data->status_reg_buf;
		u32 *buf32 = data->status_reg_buf;
@@ -521,6 +603,15 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
	if (!d)
		return -ENOMEM;

	if (chip->num_main_regs) {
		d->main_status_buf = kcalloc(chip->num_main_regs,
					     sizeof(unsigned int),
					     GFP_KERNEL);

		if (!d->main_status_buf)
			goto err_alloc;
	}

	d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
				GFP_KERNEL);
	if (!d->status_buf)
+31 −0
Original line number Diff line number Diff line
@@ -1131,11 +1131,37 @@ struct regmap_irq {
		.reg_offset = (_id) / (_reg_bits),	\
	}

#define REGMAP_IRQ_MAIN_REG_OFFSET(arr)				\
	{ .num_regs = ARRAY_SIZE((arr)), .offset = &(arr)[0] }

struct regmap_irq_sub_irq_map {
	unsigned int num_regs;
	unsigned int *offset;
};

/**
 * struct regmap_irq_chip - Description of a generic regmap irq_chip.
 *
 * @name:        Descriptive name for IRQ controller.
 *
 * @main_status: Base main status register address. For chips which have
 *		 interrupts arranged in separate sub-irq blocks with own IRQ
 *		 registers and which have a main IRQ registers indicating
 *		 sub-irq blocks with unhandled interrupts. For such chips fill
 *		 sub-irq register information in status_base, mask_base and
 *		 ack_base.
 * @num_main_status_bits: Should be given to chips where number of meaningfull
 *			  main status bits differs from num_regs.
 * @sub_reg_offsets: arrays of mappings from main register bits to sub irq
 *		     registers. First item in array describes the registers
 *		     for first main status bit. Second array for second bit etc.
 *		     Offset is given as sub register status offset to
 *		     status_base. Should contain num_regs arrays.
 *		     Can be provided for chips with more complex mapping than
 *		     1.st bit to 1.st sub-reg, 2.nd bit to 2.nd sub-reg, ...
 * @num_main_regs: Number of 'main status' irq registers for chips which have
 *		   main_status set.
 *
 * @status_base: Base status register address.
 * @mask_base:   Base mask register address.
 * @mask_writeonly: Base mask register is write only.
@@ -1181,6 +1207,11 @@ struct regmap_irq {
struct regmap_irq_chip {
	const char *name;

	unsigned int main_status;
	unsigned int num_main_status_bits;
	struct regmap_irq_sub_irq_map *sub_reg_offsets;
	int num_main_regs;

	unsigned int status_base;
	unsigned int mask_base;
	unsigned int unmask_base;