From 3324a7c1a2273e502a4f3c02a021e1d15ce2c458 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 7 Feb 2019 21:16:24 -0500 Subject: mfd: pm8xxx: convert to v2 irq interfaces to support hierarchical IRQ chips Convert the PM8XXX IRQ code to use the version 2 IRQ interface in order to support hierarchical IRQ chips. This is necessary so that ssbi-gpio can be setup as a hierarchical IRQ chip with PM8xxx as the parent. IRQ chips in device tree should be usable from the start without having to make an additional call to gpio[d]_to_irq() to get the proper IRQ on the parent. pm8821_irq_domain_ops and pm8821_irq_domain_map are removed by this patch since the irq_chip is now contained in the pm_irq_data struct, and that allows us to use a common IRQ mapping function. This change was tested on an APQ8060 DragonBoard. Signed-off-by: Brian Masney Tested-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/qcom-pm8xxx.c | 75 ++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index e6e8d81c15fd..8eb2528793f9 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c @@ -70,22 +70,23 @@ #define PM8XXX_NR_IRQS 256 #define PM8821_NR_IRQS 112 +struct pm_irq_data { + int num_irqs; + struct irq_chip *irq_chip; + void (*irq_handler)(struct irq_desc *desc); +}; + struct pm_irq_chip { struct regmap *regmap; spinlock_t pm_irq_lock; struct irq_domain *irqdomain; - unsigned int num_irqs; unsigned int num_blocks; unsigned int num_masters; + const struct pm_irq_data *pm_irq_data; + /* MUST BE AT THE END OF THIS STRUCT */ u8 config[0]; }; -struct pm_irq_data { - int num_irqs; - const struct irq_domain_ops *irq_domain_ops; - void (*irq_handler)(struct irq_desc *desc); -}; - static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, unsigned int *ip) { @@ -375,21 +376,38 @@ static struct irq_chip pm8xxx_irq_chip = { .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, }; -static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) +static void pm8xxx_irq_domain_map(struct pm_irq_chip *chip, + struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq, unsigned int type) { - struct pm_irq_chip *chip = d->host_data; - - irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq); - irq_set_chip_data(irq, chip); + irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip, + chip, handle_level_irq, NULL, NULL); irq_set_noprobe(irq); +} + +static int pm8xxx_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *data) +{ + struct pm_irq_chip *chip = domain->host_data; + struct irq_fwspec *fwspec = data; + irq_hw_number_t hwirq; + unsigned int type; + int ret, i; + + ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + for (i = 0; i < nr_irqs; i++) + pm8xxx_irq_domain_map(chip, domain, virq + i, hwirq + i, type); return 0; } static const struct irq_domain_ops pm8xxx_irq_domain_ops = { - .xlate = irq_domain_xlate_twocell, - .map = pm8xxx_irq_domain_map, + .alloc = pm8xxx_irq_domain_alloc, + .free = irq_domain_free_irqs_common, + .translate = irq_domain_translate_twocell, }; static void pm8821_irq_mask_ack(struct irq_data *d) @@ -473,23 +491,6 @@ static struct irq_chip pm8821_irq_chip = { .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, }; -static int pm8821_irq_domain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct pm_irq_chip *chip = d->host_data; - - irq_set_chip_and_handler(irq, &pm8821_irq_chip, handle_level_irq); - irq_set_chip_data(irq, chip); - irq_set_noprobe(irq); - - return 0; -} - -static const struct irq_domain_ops pm8821_irq_domain_ops = { - .xlate = irq_domain_xlate_twocell, - .map = pm8821_irq_domain_map, -}; - static const struct regmap_config ssbi_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -501,13 +502,13 @@ static const struct regmap_config ssbi_regmap_config = { static const struct pm_irq_data pm8xxx_data = { .num_irqs = PM8XXX_NR_IRQS, - .irq_domain_ops = &pm8xxx_irq_domain_ops, + .irq_chip = &pm8xxx_irq_chip, .irq_handler = pm8xxx_irq_handler, }; static const struct pm_irq_data pm8821_data = { .num_irqs = PM8821_NR_IRQS, - .irq_domain_ops = &pm8821_irq_domain_ops, + .irq_chip = &pm8821_irq_chip, .irq_handler = pm8821_irq_handler, }; @@ -571,14 +572,14 @@ static int pm8xxx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, chip); chip->regmap = regmap; - chip->num_irqs = data->num_irqs; - chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8); + chip->num_blocks = DIV_ROUND_UP(data->num_irqs, 8); chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); + chip->pm_irq_data = data; spin_lock_init(&chip->pm_irq_lock); chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, data->num_irqs, - data->irq_domain_ops, + &pm8xxx_irq_domain_ops, chip); if (!chip->irqdomain) return -ENODEV; -- cgit v1.2.3 From ee08e24c2e761e6aa3ef2c03cc2004e11fe111b3 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 7 Feb 2019 21:16:25 -0500 Subject: mfd: pm8xxx: disassociate old virq if hwirq mapping already exists Check to see if the hwirq is already associated with another virq on this IRQ domain. If so, then disassociate it before associating the hwirq with the new virq. This is a temporary hack that is needed in order to not break git bisect for existing boards. The next patch in this series converts ssbi-gpio to be a hierarchical IRQ chip, then there are several patches to update all of the device tree files, and finally this patch will be reverted within the same patch series. IRQs for ssbi-gpio are all initially setup without an IRQ hierarchy this driver is probed due to the interrupts property in device tree. Once ssbi-gpio is converted to be a hierarchical IRQ chip in the next patch, existing users of gpio[d]_to_irq() will call pmic_gpio_to_irq(), and that will use the new IRQ chip code in ssbi-gpio that sets up the IRQ in an IRQ hierarchy. The hwirq is now associated with two Linux virqs and interrupts will not work as expected. This patch corrects that issue. This change was tested on an APQ8060 DragonBoard. Signed-off-by: Brian Masney Tested-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/qcom-pm8xxx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index 8eb2528793f9..2f99a98ccee5 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c @@ -380,6 +380,12 @@ static void pm8xxx_irq_domain_map(struct pm_irq_chip *chip, struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq, unsigned int type) { + unsigned int old_virq; + + old_virq = irq_find_mapping(domain, hwirq); + if (old_virq) + irq_domain_disassociate(domain, old_virq); + irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip, chip, handle_level_irq, NULL, NULL); irq_set_noprobe(irq); -- cgit v1.2.3 From 1a25d59a55292631a6c601fda5413abc297097b7 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 7 Feb 2019 21:16:31 -0500 Subject: mfd: pm8xxx: revert "disassociate old virq if hwirq mapping already exists" Now that ssbi-gpio is a proper hierarchical IRQ chip, and all in-tree users of device tree have been updated, we can now drop the hack that was introduced to disassociate the old Linux virq if a hwirq mapping already exists. That patch was introduced to not break git bisect for any existing boards. This change was tested on an APQ8060 DragonBoard. Signed-off-by: Brian Masney Tested-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/qcom-pm8xxx.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index 2f99a98ccee5..8eb2528793f9 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c @@ -380,12 +380,6 @@ static void pm8xxx_irq_domain_map(struct pm_irq_chip *chip, struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq, unsigned int type) { - unsigned int old_virq; - - old_virq = irq_find_mapping(domain, hwirq); - if (old_virq) - irq_domain_disassociate(domain, old_virq); - irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip, chip, handle_level_irq, NULL, NULL); irq_set_noprobe(irq); -- cgit v1.2.3 From de744e01aa3af421470eb9725574e3cbce319053 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 13 Feb 2019 20:36:40 -0500 Subject: mfd: pm8xxx: select IRQ_DOMAIN_HIERARCHY in Kconfig Select IRQ_DOMAIN_HIERARCHY for pm8xxx in Kconfig since this driver uses the version 2 IRQ interfaces. IRQ_DOMAIN_HIERARCHY selects IRQ_DOMAIN, so it can be removed from here. Signed-off-by: Brian Masney Acked-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8c5dfdce4326..001a84749852 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -927,7 +927,7 @@ config UCB1400_CORE config MFD_PM8XXX tristate "Qualcomm PM8xxx PMIC chips driver" depends on (ARM || HEXAGON || COMPILE_TEST) - select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY select MFD_CORE select REGMAP help -- cgit v1.2.3