Merge tag 'regmap-v5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
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
This commit is contained in:
@@ -33,7 +33,7 @@ struct regcache_rbtree_node {
|
|||||||
unsigned int blklen;
|
unsigned int blklen;
|
||||||
/* the actual rbtree node holding this block */
|
/* the actual rbtree node holding this block */
|
||||||
struct rb_node node;
|
struct rb_node node;
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
struct regcache_rbtree_ctx {
|
struct regcache_rbtree_ctx {
|
||||||
struct rb_root root;
|
struct rb_root root;
|
||||||
|
@@ -35,6 +35,7 @@ struct regmap_irq_chip_data {
|
|||||||
int wake_count;
|
int wake_count;
|
||||||
|
|
||||||
void *status_reg_buf;
|
void *status_reg_buf;
|
||||||
|
unsigned int *main_status_buf;
|
||||||
unsigned int *status_buf;
|
unsigned int *status_buf;
|
||||||
unsigned int *mask_buf;
|
unsigned int *mask_buf;
|
||||||
unsigned int *mask_buf_def;
|
unsigned int *mask_buf_def;
|
||||||
@@ -329,6 +330,33 @@ static const struct irq_chip regmap_irq_chip = {
|
|||||||
.irq_set_wake = regmap_irq_set_wake,
|
.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)
|
static irqreturn_t regmap_irq_thread(int irq, void *d)
|
||||||
{
|
{
|
||||||
struct regmap_irq_chip_data *data = 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
|
* Read only registers with active IRQs if the chip has 'main status
|
||||||
* in order to reduce the I/O overheads.
|
* 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 &&
|
|
||||||
data->irq_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;
|
u8 *buf8 = data->status_reg_buf;
|
||||||
u16 *buf16 = data->status_reg_buf;
|
u16 *buf16 = data->status_reg_buf;
|
||||||
u32 *buf32 = 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)
|
if (!d)
|
||||||
return -ENOMEM;
|
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),
|
d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!d->status_buf)
|
if (!d->status_buf)
|
||||||
|
@@ -1131,11 +1131,37 @@ struct regmap_irq {
|
|||||||
.reg_offset = (_id) / (_reg_bits), \
|
.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.
|
* struct regmap_irq_chip - Description of a generic regmap irq_chip.
|
||||||
*
|
*
|
||||||
* @name: Descriptive name for IRQ controller.
|
* @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.
|
* @status_base: Base status register address.
|
||||||
* @mask_base: Base mask register address.
|
* @mask_base: Base mask register address.
|
||||||
* @mask_writeonly: Base mask register is write only.
|
* @mask_writeonly: Base mask register is write only.
|
||||||
@@ -1181,6 +1207,11 @@ struct regmap_irq {
|
|||||||
struct regmap_irq_chip {
|
struct regmap_irq_chip {
|
||||||
const char *name;
|
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 status_base;
|
||||||
unsigned int mask_base;
|
unsigned int mask_base;
|
||||||
unsigned int unmask_base;
|
unsigned int unmask_base;
|
||||||
|
Reference in New Issue
Block a user