162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2016 MediaTek Inc.
462306a36Sopenharmony_ci * Author: Youlin.Pei <youlin.pei@mediatek.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/interrupt.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/irq.h>
1062306a36Sopenharmony_ci#include <linux/irqchip.h>
1162306a36Sopenharmony_ci#include <linux/irqdomain.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/of_irq.h>
1462306a36Sopenharmony_ci#include <linux/of_address.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/syscore_ops.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cienum mtk_cirq_regoffs_index {
1962306a36Sopenharmony_ci	CIRQ_STA,
2062306a36Sopenharmony_ci	CIRQ_ACK,
2162306a36Sopenharmony_ci	CIRQ_MASK_SET,
2262306a36Sopenharmony_ci	CIRQ_MASK_CLR,
2362306a36Sopenharmony_ci	CIRQ_SENS_SET,
2462306a36Sopenharmony_ci	CIRQ_SENS_CLR,
2562306a36Sopenharmony_ci	CIRQ_POL_SET,
2662306a36Sopenharmony_ci	CIRQ_POL_CLR,
2762306a36Sopenharmony_ci	CIRQ_CONTROL
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic const u32 mtk_cirq_regoffs_v1[] = {
3162306a36Sopenharmony_ci	[CIRQ_STA]	= 0x0,
3262306a36Sopenharmony_ci	[CIRQ_ACK]	= 0x40,
3362306a36Sopenharmony_ci	[CIRQ_MASK_SET]	= 0xc0,
3462306a36Sopenharmony_ci	[CIRQ_MASK_CLR]	= 0x100,
3562306a36Sopenharmony_ci	[CIRQ_SENS_SET]	= 0x180,
3662306a36Sopenharmony_ci	[CIRQ_SENS_CLR]	= 0x1c0,
3762306a36Sopenharmony_ci	[CIRQ_POL_SET]	= 0x240,
3862306a36Sopenharmony_ci	[CIRQ_POL_CLR]	= 0x280,
3962306a36Sopenharmony_ci	[CIRQ_CONTROL]	= 0x300,
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const u32 mtk_cirq_regoffs_v2[] = {
4362306a36Sopenharmony_ci	[CIRQ_STA]	= 0x0,
4462306a36Sopenharmony_ci	[CIRQ_ACK]	= 0x80,
4562306a36Sopenharmony_ci	[CIRQ_MASK_SET]	= 0x180,
4662306a36Sopenharmony_ci	[CIRQ_MASK_CLR]	= 0x200,
4762306a36Sopenharmony_ci	[CIRQ_SENS_SET]	= 0x300,
4862306a36Sopenharmony_ci	[CIRQ_SENS_CLR]	= 0x380,
4962306a36Sopenharmony_ci	[CIRQ_POL_SET]	= 0x480,
5062306a36Sopenharmony_ci	[CIRQ_POL_CLR]	= 0x500,
5162306a36Sopenharmony_ci	[CIRQ_CONTROL]	= 0x600,
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define CIRQ_EN	0x1
5562306a36Sopenharmony_ci#define CIRQ_EDGE	0x2
5662306a36Sopenharmony_ci#define CIRQ_FLUSH	0x4
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct mtk_cirq_chip_data {
5962306a36Sopenharmony_ci	void __iomem *base;
6062306a36Sopenharmony_ci	unsigned int ext_irq_start;
6162306a36Sopenharmony_ci	unsigned int ext_irq_end;
6262306a36Sopenharmony_ci	const u32 *offsets;
6362306a36Sopenharmony_ci	struct irq_domain *domain;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic struct mtk_cirq_chip_data *cirq_data;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic void __iomem *mtk_cirq_reg(struct mtk_cirq_chip_data *chip_data,
6962306a36Sopenharmony_ci				  enum mtk_cirq_regoffs_index idx)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	return chip_data->base + chip_data->offsets[idx];
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void __iomem *mtk_cirq_irq_reg(struct mtk_cirq_chip_data *chip_data,
7562306a36Sopenharmony_ci				      enum mtk_cirq_regoffs_index idx,
7662306a36Sopenharmony_ci				      unsigned int cirq_num)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	return mtk_cirq_reg(chip_data, idx) + (cirq_num / 32) * 4;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic void mtk_cirq_write_mask(struct irq_data *data, enum mtk_cirq_regoffs_index idx)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct mtk_cirq_chip_data *chip_data = data->chip_data;
8462306a36Sopenharmony_ci	unsigned int cirq_num = data->hwirq;
8562306a36Sopenharmony_ci	u32 mask = 1 << (cirq_num % 32);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	writel_relaxed(mask, mtk_cirq_irq_reg(chip_data, idx, cirq_num));
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic void mtk_cirq_mask(struct irq_data *data)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	mtk_cirq_write_mask(data, CIRQ_MASK_SET);
9362306a36Sopenharmony_ci	irq_chip_mask_parent(data);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void mtk_cirq_unmask(struct irq_data *data)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	mtk_cirq_write_mask(data, CIRQ_MASK_CLR);
9962306a36Sopenharmony_ci	irq_chip_unmask_parent(data);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int mtk_cirq_set_type(struct irq_data *data, unsigned int type)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	int ret;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	switch (type & IRQ_TYPE_SENSE_MASK) {
10762306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
10862306a36Sopenharmony_ci		mtk_cirq_write_mask(data, CIRQ_POL_CLR);
10962306a36Sopenharmony_ci		mtk_cirq_write_mask(data, CIRQ_SENS_CLR);
11062306a36Sopenharmony_ci		break;
11162306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
11262306a36Sopenharmony_ci		mtk_cirq_write_mask(data, CIRQ_POL_SET);
11362306a36Sopenharmony_ci		mtk_cirq_write_mask(data, CIRQ_SENS_CLR);
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
11662306a36Sopenharmony_ci		mtk_cirq_write_mask(data, CIRQ_POL_CLR);
11762306a36Sopenharmony_ci		mtk_cirq_write_mask(data, CIRQ_SENS_SET);
11862306a36Sopenharmony_ci		break;
11962306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_HIGH:
12062306a36Sopenharmony_ci		mtk_cirq_write_mask(data, CIRQ_POL_SET);
12162306a36Sopenharmony_ci		mtk_cirq_write_mask(data, CIRQ_SENS_SET);
12262306a36Sopenharmony_ci		break;
12362306a36Sopenharmony_ci	default:
12462306a36Sopenharmony_ci		break;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	data = data->parent_data;
12862306a36Sopenharmony_ci	ret = data->chip->irq_set_type(data, type);
12962306a36Sopenharmony_ci	return ret;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic struct irq_chip mtk_cirq_chip = {
13362306a36Sopenharmony_ci	.name			= "MT_CIRQ",
13462306a36Sopenharmony_ci	.irq_mask		= mtk_cirq_mask,
13562306a36Sopenharmony_ci	.irq_unmask		= mtk_cirq_unmask,
13662306a36Sopenharmony_ci	.irq_eoi		= irq_chip_eoi_parent,
13762306a36Sopenharmony_ci	.irq_set_type		= mtk_cirq_set_type,
13862306a36Sopenharmony_ci	.irq_retrigger		= irq_chip_retrigger_hierarchy,
13962306a36Sopenharmony_ci#ifdef CONFIG_SMP
14062306a36Sopenharmony_ci	.irq_set_affinity	= irq_chip_set_affinity_parent,
14162306a36Sopenharmony_ci#endif
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int mtk_cirq_domain_translate(struct irq_domain *d,
14562306a36Sopenharmony_ci				     struct irq_fwspec *fwspec,
14662306a36Sopenharmony_ci				     unsigned long *hwirq,
14762306a36Sopenharmony_ci				     unsigned int *type)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	if (is_of_node(fwspec->fwnode)) {
15062306a36Sopenharmony_ci		if (fwspec->param_count != 3)
15162306a36Sopenharmony_ci			return -EINVAL;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		/* No PPI should point to this domain */
15462306a36Sopenharmony_ci		if (fwspec->param[0] != 0)
15562306a36Sopenharmony_ci			return -EINVAL;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		/* cirq support irq number check */
15862306a36Sopenharmony_ci		if (fwspec->param[1] < cirq_data->ext_irq_start ||
15962306a36Sopenharmony_ci		    fwspec->param[1] > cirq_data->ext_irq_end)
16062306a36Sopenharmony_ci			return -EINVAL;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		*hwirq = fwspec->param[1] - cirq_data->ext_irq_start;
16362306a36Sopenharmony_ci		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
16462306a36Sopenharmony_ci		return 0;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return -EINVAL;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int mtk_cirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
17162306a36Sopenharmony_ci				 unsigned int nr_irqs, void *arg)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int ret;
17462306a36Sopenharmony_ci	irq_hw_number_t hwirq;
17562306a36Sopenharmony_ci	unsigned int type;
17662306a36Sopenharmony_ci	struct irq_fwspec *fwspec = arg;
17762306a36Sopenharmony_ci	struct irq_fwspec parent_fwspec = *fwspec;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	ret = mtk_cirq_domain_translate(domain, fwspec, &hwirq, &type);
18062306a36Sopenharmony_ci	if (ret)
18162306a36Sopenharmony_ci		return ret;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (WARN_ON(nr_irqs != 1))
18462306a36Sopenharmony_ci		return -EINVAL;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
18762306a36Sopenharmony_ci				      &mtk_cirq_chip,
18862306a36Sopenharmony_ci				      domain->host_data);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	parent_fwspec.fwnode = domain->parent->fwnode;
19162306a36Sopenharmony_ci	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
19262306a36Sopenharmony_ci					    &parent_fwspec);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic const struct irq_domain_ops cirq_domain_ops = {
19662306a36Sopenharmony_ci	.translate	= mtk_cirq_domain_translate,
19762306a36Sopenharmony_ci	.alloc		= mtk_cirq_domain_alloc,
19862306a36Sopenharmony_ci	.free		= irq_domain_free_irqs_common,
19962306a36Sopenharmony_ci};
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
20262306a36Sopenharmony_cistatic int mtk_cirq_suspend(void)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	void __iomem *reg;
20562306a36Sopenharmony_ci	u32 value, mask;
20662306a36Sopenharmony_ci	unsigned int irq, hwirq_num;
20762306a36Sopenharmony_ci	bool pending, masked;
20862306a36Sopenharmony_ci	int i, pendret, maskret;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/*
21162306a36Sopenharmony_ci	 * When external interrupts happened, CIRQ will record the status
21262306a36Sopenharmony_ci	 * even CIRQ is not enabled. When execute flush command, CIRQ will
21362306a36Sopenharmony_ci	 * resend the signals according to the status. So if don't clear the
21462306a36Sopenharmony_ci	 * status, CIRQ will resend the wrong signals.
21562306a36Sopenharmony_ci	 *
21662306a36Sopenharmony_ci	 * arch_suspend_disable_irqs() will be called before CIRQ suspend
21762306a36Sopenharmony_ci	 * callback. If clear all the status simply, the external interrupts
21862306a36Sopenharmony_ci	 * which happened between arch_suspend_disable_irqs and CIRQ suspend
21962306a36Sopenharmony_ci	 * callback will be lost. Using following steps to avoid this issue;
22062306a36Sopenharmony_ci	 *
22162306a36Sopenharmony_ci	 * - Iterate over all the CIRQ supported interrupts;
22262306a36Sopenharmony_ci	 * - For each interrupt, inspect its pending and masked status at GIC
22362306a36Sopenharmony_ci	 *   level;
22462306a36Sopenharmony_ci	 * - If pending and unmasked, it happened between
22562306a36Sopenharmony_ci	 *   arch_suspend_disable_irqs and CIRQ suspend callback, don't ACK
22662306a36Sopenharmony_ci	 *   it. Otherwise, ACK it.
22762306a36Sopenharmony_ci	 */
22862306a36Sopenharmony_ci	hwirq_num = cirq_data->ext_irq_end - cirq_data->ext_irq_start + 1;
22962306a36Sopenharmony_ci	for (i = 0; i < hwirq_num; i++) {
23062306a36Sopenharmony_ci		irq = irq_find_mapping(cirq_data->domain, i);
23162306a36Sopenharmony_ci		if (irq) {
23262306a36Sopenharmony_ci			pendret = irq_get_irqchip_state(irq,
23362306a36Sopenharmony_ci							IRQCHIP_STATE_PENDING,
23462306a36Sopenharmony_ci							&pending);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci			maskret = irq_get_irqchip_state(irq,
23762306a36Sopenharmony_ci							IRQCHIP_STATE_MASKED,
23862306a36Sopenharmony_ci							&masked);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci			if (pendret == 0 && maskret == 0 &&
24162306a36Sopenharmony_ci			    (pending && !masked))
24262306a36Sopenharmony_ci				continue;
24362306a36Sopenharmony_ci		}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		reg = mtk_cirq_irq_reg(cirq_data, CIRQ_ACK, i);
24662306a36Sopenharmony_ci		mask = 1 << (i % 32);
24762306a36Sopenharmony_ci		writel_relaxed(mask, reg);
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* set edge_only mode, record edge-triggerd interrupts */
25162306a36Sopenharmony_ci	/* enable cirq */
25262306a36Sopenharmony_ci	reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
25362306a36Sopenharmony_ci	value = readl_relaxed(reg);
25462306a36Sopenharmony_ci	value |= (CIRQ_EDGE | CIRQ_EN);
25562306a36Sopenharmony_ci	writel_relaxed(value, reg);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return 0;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic void mtk_cirq_resume(void)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	void __iomem *reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
26362306a36Sopenharmony_ci	u32 value;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* flush recorded interrupts, will send signals to parent controller */
26662306a36Sopenharmony_ci	value = readl_relaxed(reg);
26762306a36Sopenharmony_ci	writel_relaxed(value | CIRQ_FLUSH, reg);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* disable cirq */
27062306a36Sopenharmony_ci	value = readl_relaxed(reg);
27162306a36Sopenharmony_ci	value &= ~(CIRQ_EDGE | CIRQ_EN);
27262306a36Sopenharmony_ci	writel_relaxed(value, reg);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic struct syscore_ops mtk_cirq_syscore_ops = {
27662306a36Sopenharmony_ci	.suspend	= mtk_cirq_suspend,
27762306a36Sopenharmony_ci	.resume		= mtk_cirq_resume,
27862306a36Sopenharmony_ci};
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void mtk_cirq_syscore_init(void)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	register_syscore_ops(&mtk_cirq_syscore_ops);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci#else
28562306a36Sopenharmony_cistatic inline void mtk_cirq_syscore_init(void) {}
28662306a36Sopenharmony_ci#endif
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic const struct of_device_id mtk_cirq_of_match[] = {
28962306a36Sopenharmony_ci	{ .compatible = "mediatek,mt2701-cirq", .data = &mtk_cirq_regoffs_v1 },
29062306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8135-cirq", .data = &mtk_cirq_regoffs_v1 },
29162306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8173-cirq", .data = &mtk_cirq_regoffs_v1 },
29262306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8192-cirq", .data = &mtk_cirq_regoffs_v2 },
29362306a36Sopenharmony_ci	{ /* sentinel */ }
29462306a36Sopenharmony_ci};
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int __init mtk_cirq_of_init(struct device_node *node,
29762306a36Sopenharmony_ci				   struct device_node *parent)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct irq_domain *domain, *domain_parent;
30062306a36Sopenharmony_ci	const struct of_device_id *match;
30162306a36Sopenharmony_ci	unsigned int irq_num;
30262306a36Sopenharmony_ci	int ret;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	domain_parent = irq_find_host(parent);
30562306a36Sopenharmony_ci	if (!domain_parent) {
30662306a36Sopenharmony_ci		pr_err("mtk_cirq: interrupt-parent not found\n");
30762306a36Sopenharmony_ci		return -EINVAL;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	cirq_data = kzalloc(sizeof(*cirq_data), GFP_KERNEL);
31162306a36Sopenharmony_ci	if (!cirq_data)
31262306a36Sopenharmony_ci		return -ENOMEM;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	cirq_data->base = of_iomap(node, 0);
31562306a36Sopenharmony_ci	if (!cirq_data->base) {
31662306a36Sopenharmony_ci		pr_err("mtk_cirq: unable to map cirq register\n");
31762306a36Sopenharmony_ci		ret = -ENXIO;
31862306a36Sopenharmony_ci		goto out_free;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	ret = of_property_read_u32_index(node, "mediatek,ext-irq-range", 0,
32262306a36Sopenharmony_ci					 &cirq_data->ext_irq_start);
32362306a36Sopenharmony_ci	if (ret)
32462306a36Sopenharmony_ci		goto out_unmap;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	ret = of_property_read_u32_index(node, "mediatek,ext-irq-range", 1,
32762306a36Sopenharmony_ci					 &cirq_data->ext_irq_end);
32862306a36Sopenharmony_ci	if (ret)
32962306a36Sopenharmony_ci		goto out_unmap;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	match = of_match_node(mtk_cirq_of_match, node);
33262306a36Sopenharmony_ci	if (!match) {
33362306a36Sopenharmony_ci		ret = -ENODEV;
33462306a36Sopenharmony_ci		goto out_unmap;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci	cirq_data->offsets = match->data;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	irq_num = cirq_data->ext_irq_end - cirq_data->ext_irq_start + 1;
33962306a36Sopenharmony_ci	domain = irq_domain_add_hierarchy(domain_parent, 0,
34062306a36Sopenharmony_ci					  irq_num, node,
34162306a36Sopenharmony_ci					  &cirq_domain_ops, cirq_data);
34262306a36Sopenharmony_ci	if (!domain) {
34362306a36Sopenharmony_ci		ret = -ENOMEM;
34462306a36Sopenharmony_ci		goto out_unmap;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci	cirq_data->domain = domain;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	mtk_cirq_syscore_init();
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ciout_unmap:
35362306a36Sopenharmony_ci	iounmap(cirq_data->base);
35462306a36Sopenharmony_ciout_free:
35562306a36Sopenharmony_ci	kfree(cirq_data);
35662306a36Sopenharmony_ci	return ret;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ciIRQCHIP_DECLARE(mtk_cirq, "mediatek,mtk-cirq", mtk_cirq_of_init);
360