Merge remote-tracking branches 'regmap/topic/devm-irq', 'regmap/topic/doc', 'regmap/topic/irq' and 'regmap/topic/stride' into regmap-next
This commit is contained in:
commit
0b74f06fcb
@ -110,6 +110,7 @@ struct regmap {
|
|||||||
/* number of bits to (left) shift the reg value when formatting*/
|
/* number of bits to (left) shift the reg value when formatting*/
|
||||||
int reg_shift;
|
int reg_shift;
|
||||||
int reg_stride;
|
int reg_stride;
|
||||||
|
int reg_stride_order;
|
||||||
|
|
||||||
/* regcache specific members */
|
/* regcache specific members */
|
||||||
const struct regcache_ops *cache_ops;
|
const struct regcache_ops *cache_ops;
|
||||||
@ -263,4 +264,19 @@ static inline const char *regmap_name(const struct regmap *map)
|
|||||||
return map->name;
|
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
|
#endif
|
||||||
|
@ -16,20 +16,30 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#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)
|
static int regcache_flat_init(struct regmap *map)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned int *cache;
|
unsigned int *cache;
|
||||||
|
|
||||||
map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int),
|
if (!map || map->reg_stride_order < 0)
|
||||||
GFP_KERNEL);
|
return -EINVAL;
|
||||||
|
|
||||||
|
map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
|
||||||
|
+ 1, sizeof(unsigned int), GFP_KERNEL);
|
||||||
if (!map->cache)
|
if (!map->cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
cache = map->cache;
|
cache = map->cache;
|
||||||
|
|
||||||
for (i = 0; i < map->num_reg_defaults; i++)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -47,7 +57,7 @@ static int regcache_flat_read(struct regmap *map,
|
|||||||
{
|
{
|
||||||
unsigned int *cache = map->cache;
|
unsigned int *cache = map->cache;
|
||||||
|
|
||||||
*value = cache[reg];
|
*value = cache[regcache_flat_get_index(map, reg)];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -57,7 +67,7 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg,
|
|||||||
{
|
{
|
||||||
unsigned int *cache = map->cache;
|
unsigned int *cache = map->cache;
|
||||||
|
|
||||||
cache[reg] = value;
|
cache[regcache_flat_get_index(map, reg)] = value;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -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_data(virq, data);
|
||||||
irq_set_chip(virq, &data->irq_chip);
|
irq_set_chip(virq, &data->irq_chip);
|
||||||
irq_set_nested_thread(virq, 1);
|
irq_set_nested_thread(virq, 1);
|
||||||
|
irq_set_parent(virq, data->irq);
|
||||||
irq_set_noprobe(virq);
|
irq_set_noprobe(virq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
|
|||||||
*
|
*
|
||||||
* @irq: Primary IRQ for the device
|
* @irq: Primary IRQ for the device
|
||||||
* @d: regmap_irq_chip_data allocated by regmap_add_irq_chip()
|
* @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)
|
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
|
||||||
{
|
{
|
||||||
|
unsigned int virq;
|
||||||
|
int hwirq;
|
||||||
|
|
||||||
if (!d)
|
if (!d)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
free_irq(irq, d);
|
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);
|
irq_domain_remove(d->domain);
|
||||||
kfree(d->type_buf);
|
kfree(d->type_buf);
|
||||||
kfree(d->type_buf_def);
|
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);
|
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
|
* regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip
|
||||||
*
|
*
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/log2.h>
|
||||||
|
|
||||||
#define CREATE_TRACE_POINTS
|
#define CREATE_TRACE_POINTS
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
@ -640,6 +641,10 @@ struct regmap *__regmap_init(struct device *dev,
|
|||||||
map->reg_stride = config->reg_stride;
|
map->reg_stride = config->reg_stride;
|
||||||
else
|
else
|
||||||
map->reg_stride = 1;
|
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_read = config->use_single_rw || !bus || !bus->read;
|
||||||
map->use_single_write = config->use_single_rw || !bus || !bus->write;
|
map->use_single_write = config->use_single_rw || !bus || !bus->write;
|
||||||
map->can_multi_write = config->can_multi_write && 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)
|
if (map->writeable_reg)
|
||||||
for (i = 0; i < val_len / map->format.val_bytes; i++)
|
for (i = 0; i < val_len / map->format.val_bytes; i++)
|
||||||
if (!map->writeable_reg(map->dev,
|
if (!map->writeable_reg(map->dev,
|
||||||
reg + (i * map->reg_stride)))
|
reg + regmap_get_offset(map, i)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!map->cache_bypass && map->format.parse_val) {
|
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;
|
int val_bytes = map->format.val_bytes;
|
||||||
for (i = 0; i < val_len / val_bytes; i++) {
|
for (i = 0; i < val_len / val_bytes; i++) {
|
||||||
ival = map->format.parse_val(val + (i * val_bytes));
|
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);
|
ival);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(map->dev,
|
dev_err(map->dev,
|
||||||
@ -1848,7 +1854,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = _regmap_write(map, reg + (i * map->reg_stride),
|
ret = _regmap_write(map,
|
||||||
|
reg + regmap_get_offset(map, i),
|
||||||
ival);
|
ival);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto out;
|
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.
|
* cost as we expect to hit the cache.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < val_count; i++) {
|
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);
|
&v);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto out;
|
goto out;
|
||||||
@ -2573,7 +2580,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
|
|||||||
} else {
|
} else {
|
||||||
for (i = 0; i < val_count; i++) {
|
for (i = 0; i < val_count; i++) {
|
||||||
unsigned int ival;
|
unsigned int ival;
|
||||||
ret = regmap_read(map, reg + (i * map->reg_stride),
|
ret = regmap_read(map, reg + regmap_get_offset(map, i),
|
||||||
&ival);
|
&ival);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -162,7 +162,7 @@ typedef void (*regmap_unlock)(void *);
|
|||||||
* This field is a duplicate of a similar file in
|
* This field is a duplicate of a similar file in
|
||||||
* 'struct regmap_bus' and serves exact same purpose.
|
* 'struct regmap_bus' and serves exact same purpose.
|
||||||
* Use it only for "no-bus" cases.
|
* 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
|
* @wr_table: Optional, points to a struct regmap_access_table specifying
|
||||||
* valid ranges for write access.
|
* valid ranges for write access.
|
||||||
* @rd_table: As above, for read 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,
|
int irq_base, const struct regmap_irq_chip *chip,
|
||||||
struct regmap_irq_chip_data **data);
|
struct regmap_irq_chip_data **data);
|
||||||
void regmap_del_irq_chip(int irq, 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_chip_get_base(struct regmap_irq_chip_data *data);
|
||||||
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);
|
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);
|
struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data);
|
||||||
|
Loading…
Reference in New Issue
Block a user