Skip to content

Commit 4af8be6

Browse files
committed
regmap: Convert regmap_irq to use irq_domain
This gets us up to date with the recommended current kernel infrastructure and should transparently give us device tree interrupt bindings for any devices using the framework. If an explicit IRQ mapping is passed in then a legacy interrupt range is created, otherwise a simple linear mapping is used. Previously a mapping was mandatory so existing drivers should not be affected. A function regmap_irq_get_virq() is provided to allow drivers to map individual IRQs which should be used in preference to the existing regmap_irq_chip_get_base() which is only valid if a legacy IRQ range is provided. Signed-off-by: Mark Brown <[email protected]>
1 parent 06e65cb commit 4af8be6

File tree

3 files changed

+74
-27
lines changed

3 files changed

+74
-27
lines changed

drivers/base/regmap/regmap-irq.c

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/regmap.h>
1616
#include <linux/irq.h>
1717
#include <linux/interrupt.h>
18+
#include <linux/irqdomain.h>
1819
#include <linux/slab.h>
1920

2021
#include "internal.h"
@@ -26,6 +27,7 @@ struct regmap_irq_chip_data {
2627
struct regmap_irq_chip *chip;
2728

2829
int irq_base;
30+
struct irq_domain *domain;
2931

3032
void *status_reg_buf;
3133
unsigned int *status_buf;
@@ -37,7 +39,7 @@ static inline const
3739
struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
3840
int irq)
3941
{
40-
return &data->chip->irqs[irq - data->irq_base];
42+
return &data->chip->irqs[irq];
4143
}
4244

4345
static void regmap_irq_lock(struct irq_data *data)
@@ -74,7 +76,7 @@ static void regmap_irq_enable(struct irq_data *data)
7476
{
7577
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
7678
struct regmap *map = d->map;
77-
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
79+
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
7880

7981
d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
8082
}
@@ -83,7 +85,7 @@ static void regmap_irq_disable(struct irq_data *data)
8385
{
8486
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
8587
struct regmap *map = d->map;
86-
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
88+
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
8789

8890
d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
8991
}
@@ -153,7 +155,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
153155
for (i = 0; i < chip->num_irqs; i++) {
154156
if (data->status_buf[chip->irqs[i].reg_offset /
155157
map->reg_stride] & chip->irqs[i].mask) {
156-
handle_nested_irq(data->irq_base + i);
158+
handle_nested_irq(irq_find_mapping(data->domain, i));
157159
handled = true;
158160
}
159161
}
@@ -164,6 +166,31 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
164166
return IRQ_NONE;
165167
}
166168

169+
static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
170+
irq_hw_number_t hw)
171+
{
172+
struct regmap_irq_chip_data *data = h->host_data;
173+
174+
irq_set_chip_data(virq, data);
175+
irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq);
176+
irq_set_nested_thread(virq, 1);
177+
178+
/* ARM needs us to explicitly flag the IRQ as valid
179+
* and will set them noprobe when we do so. */
180+
#ifdef CONFIG_ARM
181+
set_irq_flags(virq, IRQF_VALID);
182+
#else
183+
irq_set_noprobe(virq);
184+
#endif
185+
186+
return 0;
187+
}
188+
189+
static struct irq_domain_ops regmap_domain_ops = {
190+
.map = regmap_irq_map,
191+
.xlate = irq_domain_xlate_twocell,
192+
};
193+
167194
/**
168195
* regmap_add_irq_chip(): Use standard regmap IRQ controller handling
169196
*
@@ -184,7 +211,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
184211
struct regmap_irq_chip_data **data)
185212
{
186213
struct regmap_irq_chip_data *d;
187-
int cur_irq, i;
214+
int i;
188215
int ret = -ENOMEM;
189216

190217
for (i = 0; i < chip->num_irqs; i++) {
@@ -195,11 +222,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
195222
return -EINVAL;
196223
}
197224

198-
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
199-
if (irq_base < 0) {
200-
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
201-
irq_base);
202-
return irq_base;
225+
if (irq_base) {
226+
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
227+
if (irq_base < 0) {
228+
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
229+
irq_base);
230+
return irq_base;
231+
}
203232
}
204233

205234
d = kzalloc(sizeof(*d), GFP_KERNEL);
@@ -249,33 +278,31 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
249278
}
250279
}
251280

252-
/* Register them with genirq */
253-
for (cur_irq = irq_base;
254-
cur_irq < chip->num_irqs + irq_base;
255-
cur_irq++) {
256-
irq_set_chip_data(cur_irq, d);
257-
irq_set_chip_and_handler(cur_irq, &regmap_irq_chip,
258-
handle_edge_irq);
259-
irq_set_nested_thread(cur_irq, 1);
260-
261-
/* ARM needs us to explicitly flag the IRQ as valid
262-
* and will set them noprobe when we do so. */
263-
#ifdef CONFIG_ARM
264-
set_irq_flags(cur_irq, IRQF_VALID);
265-
#else
266-
irq_set_noprobe(cur_irq);
267-
#endif
281+
if (irq_base)
282+
d->domain = irq_domain_add_legacy(map->dev->of_node,
283+
chip->num_irqs, irq_base, 0,
284+
&regmap_domain_ops, d);
285+
else
286+
d->domain = irq_domain_add_linear(map->dev->of_node,
287+
chip->num_irqs,
288+
&regmap_domain_ops, d);
289+
if (!d->domain) {
290+
dev_err(map->dev, "Failed to create IRQ domain\n");
291+
ret = -ENOMEM;
292+
goto err_alloc;
268293
}
269294

270295
ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
271296
chip->name, d);
272297
if (ret != 0) {
273298
dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret);
274-
goto err_alloc;
299+
goto err_domain;
275300
}
276301

277302
return 0;
278303

304+
err_domain:
305+
/* Should really dispose of the domain but... */
279306
err_alloc:
280307
kfree(d->mask_buf_def);
281308
kfree(d->mask_buf);
@@ -298,6 +325,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
298325
return;
299326

300327
free_irq(irq, d);
328+
/* We should unmap the domain but... */
301329
kfree(d->mask_buf_def);
302330
kfree(d->mask_buf);
303331
kfree(d->status_reg_buf);
@@ -315,6 +343,21 @@ EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
315343
*/
316344
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data)
317345
{
346+
WARN_ON(!data->irq_base);
318347
return data->irq_base;
319348
}
320349
EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);
350+
351+
/**
352+
* regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
353+
*
354+
* Useful for drivers to request their own IRQs.
355+
*
356+
* @data: regmap_irq controller to operate on.
357+
* @irq: index of the interrupt requested in the chip IRQs
358+
*/
359+
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
360+
{
361+
return irq_create_mapping(data->domain, irq);
362+
}
363+
EXPORT_SYMBOL_GPL(regmap_irq_get_virq);

drivers/mfd/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ config PMIC_DA9052
376376

377377
config MFD_DA9052_SPI
378378
bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI"
379+
select IRQ_DOMAIN
379380
select REGMAP_SPI
380381
select REGMAP_IRQ
381382
select PMIC_DA9052
@@ -388,6 +389,7 @@ config MFD_DA9052_SPI
388389

389390
config MFD_DA9052_I2C
390391
bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C"
392+
select IRQ_DOMAIN
391393
select REGMAP_I2C
392394
select REGMAP_IRQ
393395
select PMIC_DA9052
@@ -558,6 +560,7 @@ config MFD_WM8994
558560
bool "Support Wolfson Microelectronics WM8994"
559561
select MFD_CORE
560562
select REGMAP_I2C
563+
select IRQ_DOMAIN
561564
select REGMAP_IRQ
562565
depends on I2C=y && GENERIC_HARDIRQS
563566
help

include/linux/regmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
245245
struct regmap_irq_chip_data **data);
246246
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
247247
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
248+
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);
248249

249250
#else
250251

0 commit comments

Comments
 (0)