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

Commit 0b74f06f authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'regmap/topic/devm-irq', 'regmap/topic/doc',...

Merge remote-tracking branches 'regmap/topic/devm-irq', 'regmap/topic/doc', 'regmap/topic/irq' and 'regmap/topic/stride' into regmap-next
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ struct regmap {
	/* number of bits to (left) shift the reg value when formatting*/
	int reg_shift;
	int reg_stride;
	int reg_stride_order;

	/* regcache specific members */
	const struct regcache_ops *cache_ops;
@@ -263,4 +264,19 @@ static inline const char *regmap_name(const struct regmap *map)
	return map->name;
}

static inline unsigned int regmap_get_offset(const struct regmap *map,
					     unsigned int index)
{
	if (map->reg_stride_order >= 0)
		return index << map->reg_stride_order;
	else
		return index * map->reg_stride;
}

static inline unsigned int regcache_get_index_by_order(const struct regmap *map,
						       unsigned int reg)
{
	return reg >> map->reg_stride_order;
}

#endif
+15 −5
Original line number Diff line number Diff line
@@ -16,20 +16,30 @@

#include "internal.h"

static inline unsigned int regcache_flat_get_index(const struct regmap *map,
						   unsigned int reg)
{
	return regcache_get_index_by_order(map, reg);
}

static int regcache_flat_init(struct regmap *map)
{
	int i;
	unsigned int *cache;

	map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int),
			     GFP_KERNEL);
	if (!map || map->reg_stride_order < 0)
		return -EINVAL;

	map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
			     + 1, sizeof(unsigned int), GFP_KERNEL);
	if (!map->cache)
		return -ENOMEM;

	cache = map->cache;

	for (i = 0; i < map->num_reg_defaults; i++)
		cache[map->reg_defaults[i].reg] = map->reg_defaults[i].def;
		cache[regcache_flat_get_index(map, map->reg_defaults[i].reg)] =
				map->reg_defaults[i].def;

	return 0;
}
@@ -47,7 +57,7 @@ static int regcache_flat_read(struct regmap *map,
{
	unsigned int *cache = map->cache;

	*value = cache[reg];
	*value = cache[regcache_flat_get_index(map, reg)];

	return 0;
}
@@ -57,7 +67,7 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg,
{
	unsigned int *cache = map->cache;

	cache[reg] = value;
	cache[regcache_flat_get_index(map, reg)] = value;

	return 0;
}
+104 −0
Original line number Diff line number Diff line
@@ -379,6 +379,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
	irq_set_chip_data(virq, data);
	irq_set_chip(virq, &data->irq_chip);
	irq_set_nested_thread(virq, 1);
	irq_set_parent(virq, data->irq);
	irq_set_noprobe(virq);

	return 0;
@@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
 *
 * @irq: Primary IRQ for the device
 * @d:   regmap_irq_chip_data allocated by regmap_add_irq_chip()
 *
 * This function also dispose all mapped irq on chip.
 */
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
{
	unsigned int virq;
	int hwirq;

	if (!d)
		return;

	free_irq(irq, d);

	/* Dispose all virtual irq from irq domain before removing it */
	for (hwirq = 0; hwirq < d->chip->num_irqs; hwirq++) {
		/* Ignore hwirq if holes in the IRQ list */
		if (!d->chip->irqs[hwirq].mask)
			continue;

		/*
		 * Find the virtual irq of hwirq on chip and if it is
		 * there then dispose it
		 */
		virq = irq_find_mapping(d->domain, hwirq);
		if (virq)
			irq_dispose_mapping(virq);
	}

	irq_domain_remove(d->domain);
	kfree(d->type_buf);
	kfree(d->type_buf_def);
@@ -674,6 +696,88 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
}
EXPORT_SYMBOL_GPL(regmap_del_irq_chip);

static void devm_regmap_irq_chip_release(struct device *dev, void *res)
{
	struct regmap_irq_chip_data *d = *(struct regmap_irq_chip_data **)res;

	regmap_del_irq_chip(d->irq, d);
}

static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data)

{
	struct regmap_irq_chip_data **r = res;

	if (!r || !*r) {
		WARN_ON(!r || !*r);
		return 0;
	}
	return *r == data;
}

/**
 * devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip()
 *
 * @dev:       The device pointer on which irq_chip belongs to.
 * @map:       The regmap for the device.
 * @irq:       The IRQ the device uses to signal interrupts
 * @irq_flags: The IRQF_ flags to use for the primary interrupt.
 * @chip:      Configuration for the interrupt controller.
 * @data:      Runtime data structure for the controller, allocated on success
 *
 * Returns 0 on success or an errno on failure.
 *
 * The regmap_irq_chip data automatically be released when the device is
 * unbound.
 */
int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
			     int irq_flags, int irq_base,
			     const struct regmap_irq_chip *chip,
			     struct regmap_irq_chip_data **data)
{
	struct regmap_irq_chip_data **ptr, *d;
	int ret;

	ptr = devres_alloc(devm_regmap_irq_chip_release, sizeof(*ptr),
			   GFP_KERNEL);
	if (!ptr)
		return -ENOMEM;

	ret = regmap_add_irq_chip(map, irq, irq_flags, irq_base,
				  chip, &d);
	if (ret < 0) {
		devres_free(ptr);
		return ret;
	}

	*ptr = d;
	devres_add(dev, ptr);
	*data = d;
	return 0;
}
EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip);

/**
 * devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip()
 *
 * @dev: Device for which which resource was allocated.
 * @irq: Primary IRQ for the device
 * @d:   regmap_irq_chip_data allocated by regmap_add_irq_chip()
 */
void devm_regmap_del_irq_chip(struct device *dev, int irq,
			      struct regmap_irq_chip_data *data)
{
	int rc;

	WARN_ON(irq != data->irq);
	rc = devres_release(dev, devm_regmap_irq_chip_release,
			    devm_regmap_irq_chip_match, data);

	if (rc != 0)
		WARN_ON(rc);
}
EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip);

/**
 * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip
 *
+13 −6
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/rbtree.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/log2.h>

#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -640,6 +641,10 @@ struct regmap *__regmap_init(struct device *dev,
		map->reg_stride = config->reg_stride;
	else
		map->reg_stride = 1;
	if (is_power_of_2(map->reg_stride))
		map->reg_stride_order = ilog2(map->reg_stride);
	else
		map->reg_stride_order = -1;
	map->use_single_read = config->use_single_rw || !bus || !bus->read;
	map->use_single_write = config->use_single_rw || !bus || !bus->write;
	map->can_multi_write = config->can_multi_write && bus && bus->write;
@@ -1310,7 +1315,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
	if (map->writeable_reg)
		for (i = 0; i < val_len / map->format.val_bytes; i++)
			if (!map->writeable_reg(map->dev,
						reg + (i * map->reg_stride)))
					       reg + regmap_get_offset(map, i)))
				return -EINVAL;

	if (!map->cache_bypass && map->format.parse_val) {
@@ -1318,7 +1323,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
		int val_bytes = map->format.val_bytes;
		for (i = 0; i < val_len / val_bytes; i++) {
			ival = map->format.parse_val(val + (i * val_bytes));
			ret = regcache_write(map, reg + (i * map->reg_stride),
			ret = regcache_write(map,
					     reg + regmap_get_offset(map, i),
					     ival);
			if (ret) {
				dev_err(map->dev,
@@ -1848,7 +1854,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
				goto out;
			}

			ret = _regmap_write(map, reg + (i * map->reg_stride),
			ret = _regmap_write(map,
					    reg + regmap_get_offset(map, i),
					    ival);
			if (ret != 0)
				goto out;
@@ -2421,7 +2428,7 @@ 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 * map->reg_stride),
			ret = _regmap_read(map, reg + regmap_get_offset(map, i),
					   &v);
			if (ret != 0)
				goto out;
@@ -2573,7 +2580,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
	} else {
		for (i = 0; i < val_count; i++) {
			unsigned int ival;
			ret = regmap_read(map, reg + (i * map->reg_stride),
			ret = regmap_read(map, reg + regmap_get_offset(map, i),
					  &ival);
			if (ret != 0)
				return ret;
+9 −1
Original line number Diff line number Diff line
@@ -162,7 +162,7 @@ typedef void (*regmap_unlock)(void *);
 *		  This field is a duplicate of a similar file in
 *		  'struct regmap_bus' and serves exact same purpose.
 *		   Use it only for "no-bus" cases.
 * @max_register: Optional, specifies the maximum valid register index.
 * @max_register: Optional, specifies the maximum valid register address.
 * @wr_table:     Optional, points to a struct regmap_access_table specifying
 *                valid ranges for write access.
 * @rd_table:     As above, for read access.
@@ -868,6 +868,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
			int irq_base, const struct regmap_irq_chip *chip,
			struct regmap_irq_chip_data **data);
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);

int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
			     int irq_flags, int irq_base,
			     const struct regmap_irq_chip *chip,
			     struct regmap_irq_chip_data **data);
void devm_regmap_del_irq_chip(struct device *dev, int irq,
			      struct regmap_irq_chip_data *data);

int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);
struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data);