lkml.org 
[lkml]   [2012]   [Aug]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH] mfd: arizona: simplify use of shared IRQ
    Date
    From: Stephen Warren <swarren@nvidia.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@nvidia.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


    \
     
     \ /
      Last update: 2012-08-01 23:22    [W:0.033 / U:61.904 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site