aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartosz Golaszewski <bgolaszewski@baylibre.com>2018-12-19 06:18:05 -0500
committerMark Brown <broonie@kernel.org>2018-12-19 13:38:13 -0500
commitc82ea33ead18801605b236523f21e5c893c7c253 (patch)
treeb4b523aac45485555343e4ff9133c529a6ecd38e
parent1c2928e3e3212252b505b746ec10951027a95813 (diff)
regmap: irq: add an option to clear status registers on unmask
Some interrupt controllers whose interrupts are acked on read will set the status bits for masked interrupts without changing the state of the IRQ line. Some chips have an additional "feature" where if those set bits are not cleared before unmasking their respective interrupts, the IRQ line will change the state and we'll interpret this as an interrupt although it actually fired when it was masked. Add a new field to the irq chip struct that tells the regmap irq chip code to always clear the status registers before actually changing the irq mask values. Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/base/regmap/regmap-irq.c23
-rw-r--r--include/linux/regmap.h4
2 files changed, 27 insertions, 0 deletions
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 31d23c9a5ae7..1bd1145ad8b5 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -44,6 +44,8 @@ struct regmap_irq_chip_data {
44 44
45 unsigned int irq_reg_stride; 45 unsigned int irq_reg_stride;
46 unsigned int type_reg_stride; 46 unsigned int type_reg_stride;
47
48 bool clear_status:1;
47}; 49};
48 50
49static inline const 51static inline const
@@ -77,6 +79,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
77 int i, ret; 79 int i, ret;
78 u32 reg; 80 u32 reg;
79 u32 unmask_offset; 81 u32 unmask_offset;
82 u32 val;
80 83
81 if (d->chip->runtime_pm) { 84 if (d->chip->runtime_pm) {
82 ret = pm_runtime_get_sync(map->dev); 85 ret = pm_runtime_get_sync(map->dev);
@@ -85,6 +88,20 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
85 ret); 88 ret);
86 } 89 }
87 90
91 if (d->clear_status) {
92 for (i = 0; i < d->chip->num_regs; i++) {
93 reg = d->chip->status_base +
94 (i * map->reg_stride * d->irq_reg_stride);
95
96 ret = regmap_read(map, reg, &val);
97 if (ret)
98 dev_err(d->map->dev,
99 "Failed to clear the interrupt status bits\n");
100 }
101
102 d->clear_status = false;
103 }
104
88 /* 105 /*
89 * If there's been a change in the mask write it back to the 106 * If there's been a change in the mask write it back to the
90 * hardware. We rely on the use of the regmap core cache to 107 * hardware. We rely on the use of the regmap core cache to
@@ -217,6 +234,9 @@ static void regmap_irq_enable(struct irq_data *data)
217 else 234 else
218 mask = irq_data->mask; 235 mask = irq_data->mask;
219 236
237 if (d->chip->clear_on_unmask)
238 d->clear_status = true;
239
220 d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~mask; 240 d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~mask;
221} 241}
222 242
@@ -474,6 +494,9 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
474 if (chip->num_regs <= 0) 494 if (chip->num_regs <= 0)
475 return -EINVAL; 495 return -EINVAL;
476 496
497 if (chip->clear_on_unmask && (chip->ack_base || chip->use_ack))
498 return -EINVAL;
499
477 for (i = 0; i < chip->num_irqs; i++) { 500 for (i = 0; i < chip->num_irqs; i++) {
478 if (chip->irqs[i].reg_offset % map->reg_stride) 501 if (chip->irqs[i].reg_offset % map->reg_stride)
479 return -EINVAL; 502 return -EINVAL;
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 0f1832e4c2c8..1781b6cb793c 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -1155,6 +1155,9 @@ struct regmap_irq {
1155 * @type_in_mask: Use the mask registers for controlling irq type. For 1155 * @type_in_mask: Use the mask registers for controlling irq type. For
1156 * interrupts defining type_rising/falling_mask use mask_base 1156 * interrupts defining type_rising/falling_mask use mask_base
1157 * for edge configuration and never update bits in type_base. 1157 * for edge configuration and never update bits in type_base.
1158 * @clear_on_unmask: For chips with interrupts cleared on read: read the status
1159 * registers before unmasking interrupts to clear any bits
1160 * set when they were masked.
1158 * @runtime_pm: Hold a runtime PM lock on the device when accessing it. 1161 * @runtime_pm: Hold a runtime PM lock on the device when accessing it.
1159 * 1162 *
1160 * @num_regs: Number of registers in each control bank. 1163 * @num_regs: Number of registers in each control bank.
@@ -1194,6 +1197,7 @@ struct regmap_irq_chip {
1194 bool runtime_pm:1; 1197 bool runtime_pm:1;
1195 bool type_invert:1; 1198 bool type_invert:1;
1196 bool type_in_mask:1; 1199 bool type_in_mask:1;
1200 bool clear_on_unmask:1;
1197 1201
1198 int num_regs; 1202 int num_regs;
1199 1203