[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1343853455-29131-1-git-send-email-swarren@wwwdotorg.org>
Date: Wed, 1 Aug 2012 14:37:35 -0600
From: Stephen Warren <swarren@...dotorg.org>
To: Mark Brown <broonie@...nsource.wolfsonmicro.com>,
Samuel Ortiz <sameo@...ux.intel.com>
Cc: linux-kernel@...r.kernel.org, Stephen Warren <swarren@...dia.com>
Subject: [PATCH] mfd: arizona: simplify use of shared IRQ
From: Stephen Warren <swarren@...dia.com>
The Arizona core contains a shared IRQ line driven by multiple blocks,
each represented as a separate regmap_irq_chip in the kernel.
The existing code avoids calling request_threaded_irq() with no handler
multiple times on this shared interrupt line (which apparently wasn't
supported or didn't work in the past) by using a handler that manually
distributes the shared interrupt to each regmap_irq_chip. Since the IRQ
core appears to support this now, simplify the code by removing the
open-coded handler.
This also removes the top-level IRQ domain for the Arizona core. In
theory, such a change would prevent this driver acting as an interrupt
controller when instantiated from device tree. However, I don't believe
that worked before, since the IRQ domain only contained the two virtual
interrupts needed to invoke the regmap_irq_chip handlers, and hence did
not allow the child interrupts to be translated anyway. Hence, this is
unlikely to be a regression.
Signed-off-by: Stephen Warren <swarren@...dia.com>
---
One outstanding issue with this change is that it removes the pm_runtime
calls from the interrupt handler thread. Equivalent code should presumably
be added to regmap_irq_thread(). However, I haven't attempted this yet
since I understand some pm_runtime support has already been added to
regmap, so don't want to duplicate anything, although I haven't seen
those changes yet to be sure.
Note: I have only compile-tested this particular change. However, I have
runtime tested the same shared-interrupt logic in the MAX8907 driver which
has a similar HW setup.
---
drivers/mfd/arizona-irq.c | 101 ++++----------------------------------
include/linux/mfd/arizona/core.h | 1 -
2 files changed, 10 insertions(+), 92 deletions(-)
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
index 98ac345..6b97876 100644
--- a/drivers/mfd/arizona-irq.c
+++ b/drivers/mfd/arizona-irq.c
@@ -91,66 +91,6 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data)
return IRQ_HANDLED;
}
-static irqreturn_t arizona_irq_thread(int irq, void *data)
-{
- struct arizona *arizona = data;
- int i, ret;
-
- ret = pm_runtime_get_sync(arizona->dev);
- if (ret < 0) {
- dev_err(arizona->dev, "Failed to resume device: %d\n", ret);
- return IRQ_NONE;
- }
-
- /* Check both domains */
- for (i = 0; i < 2; i++)
- handle_nested_irq(irq_find_mapping(arizona->virq, i));
-
- pm_runtime_mark_last_busy(arizona->dev);
- pm_runtime_put_autosuspend(arizona->dev);
-
- return IRQ_HANDLED;
-}
-
-static void arizona_irq_enable(struct irq_data *data)
-{
-}
-
-static void arizona_irq_disable(struct irq_data *data)
-{
-}
-
-static struct irq_chip arizona_irq_chip = {
- .name = "arizona",
- .irq_disable = arizona_irq_disable,
- .irq_enable = arizona_irq_enable,
-};
-
-static int arizona_irq_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- struct regmap_irq_chip_data *data = h->host_data;
-
- irq_set_chip_data(virq, data);
- irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_edge_irq);
- irq_set_nested_thread(virq, 1);
-
- /* ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
- set_irq_flags(virq, IRQF_VALID);
-#else
- irq_set_noprobe(virq);
-#endif
-
- return 0;
-}
-
-static struct irq_domain_ops arizona_domain_ops = {
- .map = arizona_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
int arizona_irq_init(struct arizona *arizona)
{
int flags = IRQF_ONESHOT;
@@ -189,26 +129,18 @@ int arizona_irq_init(struct arizona *arizona)
flags |= IRQF_TRIGGER_LOW;
}
- /* Allocate a virtual IRQ domain to distribute to the regmap domains */
- arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops,
- arizona);
- if (!arizona->virq) {
- ret = -EINVAL;
- goto err;
- }
+ irq_set_status_flags(arizona->irq, IRQ_NOAUTOEN);
- ret = regmap_add_irq_chip(arizona->regmap,
- irq_create_mapping(arizona->virq, 0),
- IRQF_ONESHOT, -1, aod,
+ ret = regmap_add_irq_chip(arizona->regmap, arizona->irq,
+ IRQF_ONESHOT | IRQF_SHARED, -1, aod,
&arizona->aod_irq_chip);
if (ret != 0) {
dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret);
goto err_domain;
}
- ret = regmap_add_irq_chip(arizona->regmap,
- irq_create_mapping(arizona->virq, 1),
- IRQF_ONESHOT, -1, irq,
+ ret = regmap_add_irq_chip(arizona->regmap, arizona->irq,
+ IRQF_ONESHOT | IRQF_SHARED, -1, irq,
&arizona->irq_chip);
if (ret != 0) {
dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret);
@@ -235,27 +167,16 @@ int arizona_irq_init(struct arizona *arizona)
goto err_ctrlif;
}
- ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread,
- flags, "arizona", arizona);
-
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to request IRQ %d: %d\n",
- arizona->irq, ret);
- goto err_main_irq;
- }
+ enable_irq(arizona->irq);
return 0;
-err_main_irq:
- free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR), arizona);
err_ctrlif:
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
err_boot_done:
- regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
- arizona->irq_chip);
+ regmap_del_irq_chip(arizona->irq, arizona->irq_chip);
err_aod:
- regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
- arizona->aod_irq_chip);
+ regmap_del_irq_chip(arizona->irq, arizona->aod_irq_chip);
err_domain:
err:
return ret;
@@ -265,10 +186,8 @@ int arizona_irq_exit(struct arizona *arizona)
{
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR), arizona);
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
- regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
- arizona->irq_chip);
- regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
- arizona->aod_irq_chip);
+ regmap_del_irq_chip(arizona->irq, arizona->irq_chip);
+ regmap_del_irq_chip(arizona->irq, arizona->aod_irq_chip);
free_irq(arizona->irq, arizona);
return 0;
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h
index dd231ac..b9e758b 100644
--- a/include/linux/mfd/arizona/core.h
+++ b/include/linux/mfd/arizona/core.h
@@ -92,7 +92,6 @@ struct arizona {
struct arizona_pdata pdata;
int irq;
- struct irq_domain *virq;
struct regmap_irq_chip_data *aod_irq_chip;
struct regmap_irq_chip_data *irq_chip;
--
1.7.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists