Skip to content

Commit bc998a7

Browse files
brglbroonie
authored andcommitted
regmap: irq: handle HW using separate rising/falling edge interrupts
Some interrupt controllers use separate bits for controlling rising and falling edge interrupts in the mask register i.e. they have one interrupt for rising edge and one for falling. We already handle the case where we have a single interrupt in the mask register and a separate type configuration register. Add a new switch to regmap_irq_chip which tells the framework to use the mask_base address for configuring the edge of the interrupts that define type_falling/rising_mask values. For such interrupts we never update the type_base bits. For interrupts that don't define type masks or their regmap irq chip doesn't set the type_in_mask to true everything stays the same. Signed-off-by: Bartosz Golaszewski <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent 43fac32 commit bc998a7

File tree

2 files changed

+48
-20
lines changed

2 files changed

+48
-20
lines changed

drivers/base/regmap/regmap-irq.c

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -157,20 +157,23 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
157157
}
158158
}
159159

160-
for (i = 0; i < d->chip->num_type_reg; i++) {
161-
if (!d->type_buf_def[i])
162-
continue;
163-
reg = d->chip->type_base +
164-
(i * map->reg_stride * d->type_reg_stride);
165-
if (d->chip->type_invert)
166-
ret = regmap_irq_update_bits(d, reg,
167-
d->type_buf_def[i], ~d->type_buf[i]);
168-
else
169-
ret = regmap_irq_update_bits(d, reg,
170-
d->type_buf_def[i], d->type_buf[i]);
171-
if (ret != 0)
172-
dev_err(d->map->dev, "Failed to sync type in %x\n",
173-
reg);
160+
/* Don't update the type bits if we're using mask bits for irq type. */
161+
if (!d->chip->type_in_mask) {
162+
for (i = 0; i < d->chip->num_type_reg; i++) {
163+
if (!d->type_buf_def[i])
164+
continue;
165+
reg = d->chip->type_base +
166+
(i * map->reg_stride * d->type_reg_stride);
167+
if (d->chip->type_invert)
168+
ret = regmap_irq_update_bits(d, reg,
169+
d->type_buf_def[i], ~d->type_buf[i]);
170+
else
171+
ret = regmap_irq_update_bits(d, reg,
172+
d->type_buf_def[i], d->type_buf[i]);
173+
if (ret != 0)
174+
dev_err(d->map->dev, "Failed to sync type in %x\n",
175+
reg);
176+
}
174177
}
175178

176179
if (d->chip->runtime_pm)
@@ -194,8 +197,27 @@ static void regmap_irq_enable(struct irq_data *data)
194197
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
195198
struct regmap *map = d->map;
196199
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
200+
unsigned int mask, type;
201+
202+
type = irq_data->type_falling_mask | irq_data->type_rising_mask;
203+
204+
/*
205+
* The type_in_mask flag means that the underlying hardware uses
206+
* separate mask bits for rising and falling edge interrupts, but
207+
* we want to make them into a single virtual interrupt with
208+
* configurable edge.
209+
*
210+
* If the interrupt we're enabling defines the falling or rising
211+
* masks then instead of using the regular mask bits for this
212+
* interrupt, use the value previously written to the type buffer
213+
* at the corresponding offset in regmap_irq_set_type().
214+
*/
215+
if (d->chip->type_in_mask && type)
216+
mask = d->type_buf[irq_data->reg_offset / map->reg_stride];
217+
else
218+
mask = irq_data->mask;
197219

198-
d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
220+
d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~mask;
199221
}
200222

201223
static void regmap_irq_disable(struct irq_data *data)
@@ -430,6 +452,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
430452
struct regmap_irq_chip_data *d;
431453
int i;
432454
int ret = -ENOMEM;
455+
int num_type_reg;
433456
u32 reg;
434457
u32 unmask_offset;
435458

@@ -479,13 +502,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
479502
goto err_alloc;
480503
}
481504

482-
if (chip->num_type_reg) {
483-
d->type_buf_def = kcalloc(chip->num_type_reg,
484-
sizeof(unsigned int), GFP_KERNEL);
505+
num_type_reg = chip->type_in_mask ? chip->num_regs : chip->num_type_reg;
506+
if (num_type_reg) {
507+
d->type_buf_def = kcalloc(num_type_reg,
508+
sizeof(unsigned int), GFP_KERNEL);
485509
if (!d->type_buf_def)
486510
goto err_alloc;
487511

488-
d->type_buf = kcalloc(chip->num_type_reg, sizeof(unsigned int),
512+
d->type_buf = kcalloc(num_type_reg, sizeof(unsigned int),
489513
GFP_KERNEL);
490514
if (!d->type_buf)
491515
goto err_alloc;
@@ -600,7 +624,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
600624
}
601625
}
602626

603-
if (chip->num_type_reg) {
627+
if (chip->num_type_reg && !chip->type_in_mask) {
604628
for (i = 0; i < chip->num_irqs; i++) {
605629
reg = chip->irqs[i].type_reg_offset / map->reg_stride;
606630
d->type_buf_def[reg] |= chip->irqs[i].type_rising_mask |

include/linux/regmap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,9 @@ struct regmap_irq {
11371137
* @ack_invert: Inverted ack register: cleared bits for ack.
11381138
* @wake_invert: Inverted wake register: cleared bits are wake enabled.
11391139
* @type_invert: Invert the type flags.
1140+
* @type_in_mask: Use the mask registers for controlling irq type. For
1141+
* interrupts defining type_rising/falling_mask use mask_base
1142+
* for edge configuration and never update bits in type_base.
11401143
* @runtime_pm: Hold a runtime PM lock on the device when accessing it.
11411144
*
11421145
* @num_regs: Number of registers in each control bank.
@@ -1175,6 +1178,7 @@ struct regmap_irq_chip {
11751178
bool wake_invert:1;
11761179
bool runtime_pm:1;
11771180
bool type_invert:1;
1181+
bool type_in_mask:1;
11781182

11791183
int num_regs;
11801184

0 commit comments

Comments
 (0)