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

Commit 8e24a6e6 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'regmap/topic/table' into regmap-next

parents db760fbe 76aad392
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -69,6 +69,10 @@ struct regmap {
	bool (*readable_reg)(struct device *dev, unsigned int reg);
	bool (*volatile_reg)(struct device *dev, unsigned int reg);
	bool (*precious_reg)(struct device *dev, unsigned int reg);
	const struct regmap_access_table *wr_table;
	const struct regmap_access_table *rd_table;
	const struct regmap_access_table *volatile_table;
	const struct regmap_access_table *precious_table;

	u8 read_flag_mask;
	u8 write_flag_mask;
+46 −0
Original line number Diff line number Diff line
@@ -34,6 +34,36 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
			       unsigned int mask, unsigned int val,
			       bool *change);

bool regmap_reg_in_ranges(unsigned int reg,
			  const struct regmap_range *ranges,
			  unsigned int nranges)
{
	const struct regmap_range *r;
	int i;

	for (i = 0, r = ranges; i < nranges; i++, r++)
		if (regmap_reg_in_range(reg, r))
			return true;
	return false;
}
EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);

static bool _regmap_check_range_table(struct regmap *map,
				      unsigned int reg,
				      const struct regmap_access_table *table)
{
	/* Check "no ranges" first */
	if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges))
		return false;

	/* In case zero "yes ranges" are supplied, any reg is OK */
	if (!table->n_yes_ranges)
		return true;

	return regmap_reg_in_ranges(reg, table->yes_ranges,
				    table->n_yes_ranges);
}

bool regmap_writeable(struct regmap *map, unsigned int reg)
{
	if (map->max_register && reg > map->max_register)
@@ -42,6 +72,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
	if (map->writeable_reg)
		return map->writeable_reg(map->dev, reg);

	if (map->wr_table)
		return _regmap_check_range_table(map, reg, map->wr_table);

	return true;
}

@@ -56,6 +89,9 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
	if (map->readable_reg)
		return map->readable_reg(map->dev, reg);

	if (map->rd_table)
		return _regmap_check_range_table(map, reg, map->rd_table);

	return true;
}

@@ -67,6 +103,9 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
	if (map->volatile_reg)
		return map->volatile_reg(map->dev, reg);

	if (map->volatile_table)
		return _regmap_check_range_table(map, reg, map->volatile_table);

	return true;
}

@@ -78,6 +117,9 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
	if (map->precious_reg)
		return map->precious_reg(map->dev, reg);

	if (map->precious_table)
		return _regmap_check_range_table(map, reg, map->precious_table);

	return false;
}

@@ -370,6 +412,10 @@ struct regmap *regmap_init(struct device *dev,
	map->bus = bus;
	map->bus_context = bus_context;
	map->max_register = config->max_register;
	map->wr_table = config->wr_table;
	map->rd_table = config->rd_table;
	map->volatile_table = config->volatile_table;
	map->precious_table = config->precious_table;
	map->writeable_reg = config->writeable_reg;
	map->readable_reg = config->readable_reg;
	map->volatile_reg = config->volatile_reg;
+72 −11
Original line number Diff line number Diff line
@@ -54,6 +54,36 @@ enum regmap_endian {
	REGMAP_ENDIAN_NATIVE,
};

/**
 * A register range, used for access related checks
 * (readable/writeable/volatile/precious checks)
 *
 * @range_min: address of first register
 * @range_max: address of last register
 */
struct regmap_range {
	unsigned int range_min;
	unsigned int range_max;
};

/*
 * A table of ranges including some yes ranges and some no ranges.
 * If a register belongs to a no_range, the corresponding check function
 * will return false. If a register belongs to a yes range, the corresponding
 * check function will return true. "no_ranges" are searched first.
 *
 * @yes_ranges : pointer to an array of regmap ranges used as "yes ranges"
 * @n_yes_ranges: size of the above array
 * @no_ranges: pointer to an array of regmap ranges used as "no ranges"
 * @n_no_ranges: size of the above array
 */
struct regmap_access_table {
	const struct regmap_range *yes_ranges;
	unsigned int n_yes_ranges;
	const struct regmap_range *no_ranges;
	unsigned int n_no_ranges;
};

typedef void (*regmap_lock)(void *);
typedef void (*regmap_unlock)(void *);

@@ -71,14 +101,26 @@ typedef void (*regmap_unlock)(void *);
 * @val_bits: Number of bits in a register value, mandatory.
 *
 * @writeable_reg: Optional callback returning true if the register
 *                 can be written to.
 *		   can be written to. If this field is NULL but wr_table
 *		   (see below) is not, the check is performed on such table
 *                 (a register is writeable if it belongs to one of the ranges
 *                  specified by wr_table).
 * @readable_reg: Optional callback returning true if the register
 *                can be read from.
 *		  can be read from. If this field is NULL but rd_table
 *		   (see below) is not, the check is performed on such table
 *                 (a register is readable if it belongs to one of the ranges
 *                  specified by rd_table).
 * @volatile_reg: Optional callback returning true if the register
 *                value can't be cached.
 *		  value can't be cached. If this field is NULL but
 *		  volatile_table (see below) is not, the check is performed on
 *                such table (a register is volatile if it belongs to one of
 *                the ranges specified by volatile_table).
 * @precious_reg: Optional callback returning true if the rgister
 *		  should not be read outside of a call from the driver
 *                (eg, a clear on read interrupt status register).
 *		  (eg, a clear on read interrupt status register). If this
 *                field is NULL but precious_table (see below) is not, the
 *                check is performed on such table (a register is precious if
 *                it belongs to one of the ranges specified by precious_table).
 * @lock:	  Optional lock callback (overrides regmap's default lock
 *		  function, based on spinlock or mutex).
 * @unlock:	  As above for unlocking.
@@ -87,6 +129,11 @@ typedef void (*regmap_unlock)(void *);
 *		  are not overridden).
 *
 * @max_register: Optional, specifies the maximum valid register index.
 * @wr_table:     Optional, points to a struct regmap_access_table specifying
 *                valid ranges for write access.
 * @rd_table:     As above, for read access.
 * @volatile_table: As above, for volatile registers.
 * @precious_table: As above, for precious registers.
 * @reg_defaults: Power on reset values for registers (for use with
 *                register cache support).
 * @num_reg_defaults: Number of elements in reg_defaults.
@@ -131,6 +178,10 @@ struct regmap_config {
	void *lock_arg;

	unsigned int max_register;
	const struct regmap_access_table *wr_table;
	const struct regmap_access_table *rd_table;
	const struct regmap_access_table *volatile_table;
	const struct regmap_access_table *precious_table;
	const struct reg_default *reg_defaults;
	unsigned int num_reg_defaults;
	enum regcache_type cache_type;
@@ -281,6 +332,16 @@ void regcache_mark_dirty(struct regmap *map);
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
			  int num_regs);

static inline bool regmap_reg_in_range(unsigned int reg,
				       const struct regmap_range *range)
{
	return reg >= range->range_min && reg <= range->range_max;
}

bool regmap_reg_in_ranges(unsigned int reg,
			  const struct regmap_range *ranges,
			  unsigned int nranges);

/**
 * Description of an IRQ for the generic regmap irq_chip.
 *