diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-05 04:11:58 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-05 04:11:58 +0300 |
commit | f8b036a7fc231fe6e8297daddee5dffdbbf2581f (patch) | |
tree | 5d2dc734524b19f6dd8c638da4fb2d8cf4330dac /drivers/irqchip/irq-imx-intmux.c | |
parent | 2ed90dbbf7be3b7cd2790fc6fa946c478ab496b8 (diff) | |
parent | 3d5128c1deb5d27993fb11ba5e517798f8021046 (diff) | |
download | linux-f8b036a7fc231fe6e8297daddee5dffdbbf2581f.tar.xz |
Merge tag 'irq-core-2020-08-04' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner:
"The usual boring updates from the interrupt subsystem:
- Infrastructure to allow building irqchip drivers as modules
- Consolidation of irqchip ACPI probing
- Removal of the EOI-preflow interrupt handler which was required for
SPARC support and became obsolete after SPARC was converted to use
sparse interrupts.
- Cleanups, fixes and improvements all over the place"
* tag 'irq-core-2020-08-04' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (51 commits)
irqchip/loongson-pch-pic: Fix the misused irq flow handler
irqchip/loongson-htvec: Support 8 groups of HT vectors
irqchip/loongson-liointc: Fix misuse of gc->mask_cache
dt-bindings: interrupt-controller: Update Loongson HTVEC description
irqchip/imx-intmux: Fix irqdata regs save in imx_intmux_runtime_suspend()
irqchip/imx-intmux: Implement intmux runtime power management
irqchip/gic-v4.1: Use GFP_ATOMIC flag in allocate_vpe_l1_table()
irqchip: Fix IRQCHIP_PLATFORM_DRIVER_* compilation by including module.h
irqchip/stm32-exti: Map direct event to irq parent
irqchip/mtk-cirq: Convert to a platform driver
irqchip/mtk-sysirq: Convert to a platform driver
irqchip/qcom-pdc: Switch to using IRQCHIP_PLATFORM_DRIVER helper macros
irqchip: Add IRQCHIP_PLATFORM_DRIVER_BEGIN/END and IRQCHIP_MATCH helper macros
irqchip: irq-bcm2836.h: drop a duplicated word
irqchip/gic-v4.1: Ensure accessing the correct RD when writing INVALLR
irqchip/irq-bcm7038-l1: Guard uses of cpu_logical_map
irqchip/gic-v3: Remove unused register definition
irqchip/qcom-pdc: Allow QCOM_PDC to be loadable as a permanent module
genirq: Export irq_chip_retrigger_hierarchy and irq_chip_set_vcpu_affinity_parent
irqdomain: Export irq_domain_update_bus_token
...
Diffstat (limited to 'drivers/irqchip/irq-imx-intmux.c')
-rw-r--r-- | drivers/irqchip/irq-imx-intmux.c | 70 |
1 files changed, 66 insertions, 4 deletions
diff --git a/drivers/irqchip/irq-imx-intmux.c b/drivers/irqchip/irq-imx-intmux.c index c27577c81126..e35b7b09c3ab 100644 --- a/drivers/irqchip/irq-imx-intmux.c +++ b/drivers/irqchip/irq-imx-intmux.c @@ -53,6 +53,7 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/spinlock.h> +#include <linux/pm_runtime.h> #define CHANIER(n) (0x10 + (0x40 * n)) #define CHANIPR(n) (0x20 + (0x40 * n)) @@ -60,6 +61,8 @@ #define CHAN_MAX_NUM 0x8 struct intmux_irqchip_data { + struct irq_chip chip; + u32 saved_reg; int chanidx; int irq; struct irq_domain *domain; @@ -120,8 +123,10 @@ static struct irq_chip imx_intmux_irq_chip = { static int imx_intmux_irq_map(struct irq_domain *h, unsigned int irq, irq_hw_number_t hwirq) { - irq_set_chip_data(irq, h->host_data); - irq_set_chip_and_handler(irq, &imx_intmux_irq_chip, handle_level_irq); + struct intmux_irqchip_data *data = h->host_data; + + irq_set_chip_data(irq, data); + irq_set_chip_and_handler(irq, &data->chip, handle_level_irq); return 0; } @@ -210,8 +215,7 @@ static int imx_intmux_probe(struct platform_device *pdev) return -EINVAL; } - data = devm_kzalloc(&pdev->dev, sizeof(*data) + - channum * sizeof(data->irqchip_data[0]), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, struct_size(data, irqchip_data, channum), GFP_KERNEL); if (!data) return -ENOMEM; @@ -232,6 +236,10 @@ static int imx_intmux_probe(struct platform_device *pdev) data->channum = channum; raw_spin_lock_init(&data->lock); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ret = clk_prepare_enable(data->ipg_clk); if (ret) { dev_err(&pdev->dev, "failed to enable ipg clk: %d\n", ret); @@ -239,6 +247,8 @@ static int imx_intmux_probe(struct platform_device *pdev) } for (i = 0; i < channum; i++) { + data->irqchip_data[i].chip = imx_intmux_irq_chip; + data->irqchip_data[i].chip.parent_device = &pdev->dev; data->irqchip_data[i].chanidx = i; data->irqchip_data[i].irq = irq_of_parse_and_map(np, i); @@ -267,6 +277,12 @@ static int imx_intmux_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); + /* + * Let pm_runtime_put() disable clock. + * If CONFIG_PM is not enabled, the clock will stay powered. + */ + pm_runtime_put(&pdev->dev); + return 0; out: clk_disable_unprepare(data->ipg_clk); @@ -288,11 +304,56 @@ static int imx_intmux_remove(struct platform_device *pdev) irq_domain_remove(data->irqchip_data[i].domain); } + pm_runtime_disable(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int imx_intmux_runtime_suspend(struct device *dev) +{ + struct intmux_data *data = dev_get_drvdata(dev); + struct intmux_irqchip_data *irqchip_data; + int i; + + for (i = 0; i < data->channum; i++) { + irqchip_data = &data->irqchip_data[i]; + irqchip_data->saved_reg = readl_relaxed(data->regs + CHANIER(i)); + } + clk_disable_unprepare(data->ipg_clk); return 0; } +static int imx_intmux_runtime_resume(struct device *dev) +{ + struct intmux_data *data = dev_get_drvdata(dev); + struct intmux_irqchip_data *irqchip_data; + int ret, i; + + ret = clk_prepare_enable(data->ipg_clk); + if (ret) { + dev_err(dev, "failed to enable ipg clk: %d\n", ret); + return ret; + } + + for (i = 0; i < data->channum; i++) { + irqchip_data = &data->irqchip_data[i]; + writel_relaxed(irqchip_data->saved_reg, data->regs + CHANIER(i)); + } + + return 0; +} +#endif + +static const struct dev_pm_ops imx_intmux_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(imx_intmux_runtime_suspend, + imx_intmux_runtime_resume, NULL) +}; + static const struct of_device_id imx_intmux_id[] = { { .compatible = "fsl,imx-intmux", }, { /* sentinel */ }, @@ -302,6 +363,7 @@ static struct platform_driver imx_intmux_driver = { .driver = { .name = "imx-intmux", .of_match_table = imx_intmux_id, + .pm = &imx_intmux_pm_ops, }, .probe = imx_intmux_probe, .remove = imx_intmux_remove, |