Skip to content

Commit

Permalink
regmap: add support for non contiguous status to regmap-irq
Browse files Browse the repository at this point in the history
In some chips the IRQ status registers are not contiguous in the register
map but spaced at even spaces. This is an easy case to handle with minor
changes. It is assume for this purpose that the stride for status is
equal to the stride for mask/ack registers as well.

Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
  • Loading branch information
Graeme Gregory authored and Mark Brown committed May 14, 2012
1 parent 4af8be6 commit 022f926
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 33 deletions.
54 changes: 21 additions & 33 deletions drivers/base/regmap/regmap-irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ struct regmap_irq_chip_data {
int irq_base;
struct irq_domain *domain;

void *status_reg_buf;
unsigned int *status_buf;
unsigned int *mask_buf;
unsigned int *mask_buf_def;

unsigned int irq_reg_stride;
};

static inline const
Expand Down Expand Up @@ -62,7 +63,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
*/
for (i = 0; i < d->chip->num_regs; i++) {
ret = regmap_update_bits(d->map, d->chip->mask_base +
(i * map->reg_stride),
(i * map->reg_stride *
d->irq_reg_stride),
d->mask_buf_def[i], d->mask_buf[i]);
if (ret != 0)
dev_err(d->map->dev, "Failed to sync masks in %x\n",
Expand Down Expand Up @@ -104,18 +106,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
struct regmap_irq_chip *chip = data->chip;
struct regmap *map = data->map;
int ret, i;
u8 *buf8 = data->status_reg_buf;
u16 *buf16 = data->status_reg_buf;
u32 *buf32 = data->status_reg_buf;
bool handled = false;

ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf,
chip->num_regs);
if (ret != 0) {
dev_err(map->dev, "Failed to read IRQ status: %d\n", ret);
return IRQ_NONE;
}

/*
* Ignore masked IRQs and ack if we need to; we ack early so
* there is no race between handling and acknowleding the
Expand All @@ -124,26 +116,22 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
* doing a write per register.
*/
for (i = 0; i < data->chip->num_regs; i++) {
switch (map->format.val_bytes) {
case 1:
data->status_buf[i] = buf8[i];
break;
case 2:
data->status_buf[i] = buf16[i];
break;
case 4:
data->status_buf[i] = buf32[i];
break;
default:
BUG();
ret = regmap_read(map, chip->mask_base + (i * map->reg_stride
* data->irq_reg_stride),
&data->status_buf[i]);

if (ret != 0) {
dev_err(map->dev, "Failed to read IRQ status: %d\n",
ret);
return IRQ_NONE;
}

data->status_buf[i] &= ~data->mask_buf[i];

if (data->status_buf[i] && chip->ack_base) {
ret = regmap_write(map, chip->ack_base +
(i * map->reg_stride),
(i * map->reg_stride *
data->irq_reg_stride),
data->status_buf[i]);
if (ret != 0)
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
Expand Down Expand Up @@ -242,11 +230,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d->status_buf)
goto err_alloc;

d->status_reg_buf = kzalloc(map->format.val_bytes * chip->num_regs,
GFP_KERNEL);
if (!d->status_reg_buf)
goto err_alloc;

d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL);
if (!d->mask_buf)
Expand All @@ -260,6 +243,12 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
d->map = map;
d->chip = chip;
d->irq_base = irq_base;

if (chip->irq_reg_stride)
d->irq_reg_stride = chip->irq_reg_stride;
else
d->irq_reg_stride = 1;

mutex_init(&d->lock);

for (i = 0; i < chip->num_irqs; i++)
Expand All @@ -269,7 +258,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
/* Mask all the interrupts by default */
for (i = 0; i < chip->num_regs; i++) {
d->mask_buf[i] = d->mask_buf_def[i];
ret = regmap_write(map, chip->mask_base + (i * map->reg_stride),
ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
* d->irq_reg_stride),
d->mask_buf[i]);
if (ret != 0) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
Expand Down Expand Up @@ -306,7 +296,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
err_alloc:
kfree(d->mask_buf_def);
kfree(d->mask_buf);
kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
return ret;
Expand All @@ -328,7 +317,6 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
/* We should unmap the domain but... */
kfree(d->mask_buf_def);
kfree(d->mask_buf);
kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
}
Expand Down
2 changes: 2 additions & 0 deletions include/linux/regmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ struct regmap_irq {
* @status_base: Base status register address.
* @mask_base: Base mask register address.
* @ack_base: Base ack address. If zero then the chip is clear on read.
* @irq_reg_stride: Stride to use for chips where registers are not contiguous.
*
* @num_regs: Number of registers in each control bank.
* @irqs: Descriptors for individual IRQs. Interrupt numbers are
Expand All @@ -231,6 +232,7 @@ struct regmap_irq_chip {
unsigned int status_base;
unsigned int mask_base;
unsigned int ack_base;
unsigned int irq_reg_stride;

int num_regs;

Expand Down

0 comments on commit 022f926

Please sign in to comment.