18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (c) 2014-2018 MediaTek Inc.
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci/*
58c2ecf20Sopenharmony_ci * Library for MediaTek External Interrupt Support
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Maoguang Meng <maoguang.meng@mediatek.com>
88c2ecf20Sopenharmony_ci *	   Sean Wang <sean.wang@mediatek.com>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/err.h>
148c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
158c2ecf20Sopenharmony_ci#include <linux/io.h>
168c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h>
178c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
208c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "mtk-eint.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define MTK_EINT_EDGE_SENSITIVE           0
258c2ecf20Sopenharmony_ci#define MTK_EINT_LEVEL_SENSITIVE          1
268c2ecf20Sopenharmony_ci#define MTK_EINT_DBNC_SET_DBNC_BITS	  4
278c2ecf20Sopenharmony_ci#define MTK_EINT_DBNC_RST_BIT		  (0x1 << 1)
288c2ecf20Sopenharmony_ci#define MTK_EINT_DBNC_SET_EN		  (0x1 << 0)
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic const struct mtk_eint_regs mtk_generic_eint_regs = {
318c2ecf20Sopenharmony_ci	.stat      = 0x000,
328c2ecf20Sopenharmony_ci	.ack       = 0x040,
338c2ecf20Sopenharmony_ci	.mask      = 0x080,
348c2ecf20Sopenharmony_ci	.mask_set  = 0x0c0,
358c2ecf20Sopenharmony_ci	.mask_clr  = 0x100,
368c2ecf20Sopenharmony_ci	.sens      = 0x140,
378c2ecf20Sopenharmony_ci	.sens_set  = 0x180,
388c2ecf20Sopenharmony_ci	.sens_clr  = 0x1c0,
398c2ecf20Sopenharmony_ci	.soft      = 0x200,
408c2ecf20Sopenharmony_ci	.soft_set  = 0x240,
418c2ecf20Sopenharmony_ci	.soft_clr  = 0x280,
428c2ecf20Sopenharmony_ci	.pol       = 0x300,
438c2ecf20Sopenharmony_ci	.pol_set   = 0x340,
448c2ecf20Sopenharmony_ci	.pol_clr   = 0x380,
458c2ecf20Sopenharmony_ci	.dom_en    = 0x400,
468c2ecf20Sopenharmony_ci	.dbnc_ctrl = 0x500,
478c2ecf20Sopenharmony_ci	.dbnc_set  = 0x600,
488c2ecf20Sopenharmony_ci	.dbnc_clr  = 0x700,
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
528c2ecf20Sopenharmony_ci					 unsigned int eint_num,
538c2ecf20Sopenharmony_ci					 unsigned int offset)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	unsigned int eint_base = 0;
568c2ecf20Sopenharmony_ci	void __iomem *reg;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (eint_num >= eint->hw->ap_num)
598c2ecf20Sopenharmony_ci		eint_base = eint->hw->ap_num;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return reg;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint,
678c2ecf20Sopenharmony_ci					     unsigned int eint_num)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	unsigned int sens;
708c2ecf20Sopenharmony_ci	unsigned int bit = BIT(eint_num % 32);
718c2ecf20Sopenharmony_ci	void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
728c2ecf20Sopenharmony_ci						eint->regs->sens);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (readl(reg) & bit)
758c2ecf20Sopenharmony_ci		sens = MTK_EINT_LEVEL_SENSITIVE;
768c2ecf20Sopenharmony_ci	else
778c2ecf20Sopenharmony_ci		sens = MTK_EINT_EDGE_SENSITIVE;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (eint_num < eint->hw->db_cnt && sens != MTK_EINT_EDGE_SENSITIVE)
808c2ecf20Sopenharmony_ci		return 1;
818c2ecf20Sopenharmony_ci	else
828c2ecf20Sopenharmony_ci		return 0;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	int start_level, curr_level;
888c2ecf20Sopenharmony_ci	unsigned int reg_offset;
898c2ecf20Sopenharmony_ci	u32 mask = BIT(hwirq & 0x1f);
908c2ecf20Sopenharmony_ci	u32 port = (hwirq >> 5) & eint->hw->port_mask;
918c2ecf20Sopenharmony_ci	void __iomem *reg = eint->base + (port << 2);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	do {
968c2ecf20Sopenharmony_ci		start_level = curr_level;
978c2ecf20Sopenharmony_ci		if (start_level)
988c2ecf20Sopenharmony_ci			reg_offset = eint->regs->pol_clr;
998c2ecf20Sopenharmony_ci		else
1008c2ecf20Sopenharmony_ci			reg_offset = eint->regs->pol_set;
1018c2ecf20Sopenharmony_ci		writel(mask, reg + reg_offset);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
1048c2ecf20Sopenharmony_ci							      hwirq);
1058c2ecf20Sopenharmony_ci	} while (start_level != curr_level);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return start_level;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic void mtk_eint_mask(struct irq_data *d)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
1138c2ecf20Sopenharmony_ci	u32 mask = BIT(d->hwirq & 0x1f);
1148c2ecf20Sopenharmony_ci	void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
1158c2ecf20Sopenharmony_ci						eint->regs->mask_set);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	eint->cur_mask[d->hwirq >> 5] &= ~mask;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	writel(mask, reg);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic void mtk_eint_unmask(struct irq_data *d)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
1258c2ecf20Sopenharmony_ci	u32 mask = BIT(d->hwirq & 0x1f);
1268c2ecf20Sopenharmony_ci	void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
1278c2ecf20Sopenharmony_ci						eint->regs->mask_clr);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	eint->cur_mask[d->hwirq >> 5] |= mask;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	writel(mask, reg);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (eint->dual_edge[d->hwirq])
1348c2ecf20Sopenharmony_ci		mtk_eint_flip_edge(eint, d->hwirq);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
1388c2ecf20Sopenharmony_ci				      unsigned int eint_num)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	unsigned int bit = BIT(eint_num % 32);
1418c2ecf20Sopenharmony_ci	void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
1428c2ecf20Sopenharmony_ci						eint->regs->mask);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return !!(readl(reg) & bit);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic void mtk_eint_ack(struct irq_data *d)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
1508c2ecf20Sopenharmony_ci	u32 mask = BIT(d->hwirq & 0x1f);
1518c2ecf20Sopenharmony_ci	void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
1528c2ecf20Sopenharmony_ci						eint->regs->ack);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	writel(mask, reg);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic int mtk_eint_set_type(struct irq_data *d, unsigned int type)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
1608c2ecf20Sopenharmony_ci	u32 mask = BIT(d->hwirq & 0x1f);
1618c2ecf20Sopenharmony_ci	void __iomem *reg;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
1648c2ecf20Sopenharmony_ci	    ((type & IRQ_TYPE_LEVEL_MASK) == IRQ_TYPE_LEVEL_MASK)) {
1658c2ecf20Sopenharmony_ci		dev_err(eint->dev,
1668c2ecf20Sopenharmony_ci			"Can't configure IRQ%d (EINT%lu) for type 0x%X\n",
1678c2ecf20Sopenharmony_ci			d->irq, d->hwirq, type);
1688c2ecf20Sopenharmony_ci		return -EINVAL;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
1728c2ecf20Sopenharmony_ci		eint->dual_edge[d->hwirq] = 1;
1738c2ecf20Sopenharmony_ci	else
1748c2ecf20Sopenharmony_ci		eint->dual_edge[d->hwirq] = 0;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
1778c2ecf20Sopenharmony_ci		reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_clr);
1788c2ecf20Sopenharmony_ci		writel(mask, reg);
1798c2ecf20Sopenharmony_ci	} else {
1808c2ecf20Sopenharmony_ci		reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_set);
1818c2ecf20Sopenharmony_ci		writel(mask, reg);
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
1858c2ecf20Sopenharmony_ci		reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_clr);
1868c2ecf20Sopenharmony_ci		writel(mask, reg);
1878c2ecf20Sopenharmony_ci	} else {
1888c2ecf20Sopenharmony_ci		reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_set);
1898c2ecf20Sopenharmony_ci		writel(mask, reg);
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (eint->dual_edge[d->hwirq])
1938c2ecf20Sopenharmony_ci		mtk_eint_flip_edge(eint, d->hwirq);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return 0;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
2018c2ecf20Sopenharmony_ci	int shift = d->hwirq & 0x1f;
2028c2ecf20Sopenharmony_ci	int reg = d->hwirq >> 5;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (on)
2058c2ecf20Sopenharmony_ci		eint->wake_mask[reg] |= BIT(shift);
2068c2ecf20Sopenharmony_ci	else
2078c2ecf20Sopenharmony_ci		eint->wake_mask[reg] &= ~BIT(shift);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	return 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
2138c2ecf20Sopenharmony_ci				     void __iomem *base, u32 *buf)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int port;
2168c2ecf20Sopenharmony_ci	void __iomem *reg;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	for (port = 0; port < eint->hw->ports; port++) {
2198c2ecf20Sopenharmony_ci		reg = base + (port << 2);
2208c2ecf20Sopenharmony_ci		writel_relaxed(~buf[port], reg + eint->regs->mask_set);
2218c2ecf20Sopenharmony_ci		writel_relaxed(buf[port], reg + eint->regs->mask_clr);
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int mtk_eint_irq_request_resources(struct irq_data *d)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
2288c2ecf20Sopenharmony_ci	struct gpio_chip *gpio_c;
2298c2ecf20Sopenharmony_ci	unsigned int gpio_n;
2308c2ecf20Sopenharmony_ci	int err;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	err = eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq,
2338c2ecf20Sopenharmony_ci					   &gpio_n, &gpio_c);
2348c2ecf20Sopenharmony_ci	if (err < 0) {
2358c2ecf20Sopenharmony_ci		dev_err(eint->dev, "Can not find pin\n");
2368c2ecf20Sopenharmony_ci		return err;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	err = gpiochip_lock_as_irq(gpio_c, gpio_n);
2408c2ecf20Sopenharmony_ci	if (err < 0) {
2418c2ecf20Sopenharmony_ci		dev_err(eint->dev, "unable to lock HW IRQ %lu for IRQ\n",
2428c2ecf20Sopenharmony_ci			irqd_to_hwirq(d));
2438c2ecf20Sopenharmony_ci		return err;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	err = eint->gpio_xlate->set_gpio_as_eint(eint->pctl, d->hwirq);
2478c2ecf20Sopenharmony_ci	if (err < 0) {
2488c2ecf20Sopenharmony_ci		dev_err(eint->dev, "Can not eint mode\n");
2498c2ecf20Sopenharmony_ci		return err;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic void mtk_eint_irq_release_resources(struct irq_data *d)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
2588c2ecf20Sopenharmony_ci	struct gpio_chip *gpio_c;
2598c2ecf20Sopenharmony_ci	unsigned int gpio_n;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq, &gpio_n,
2628c2ecf20Sopenharmony_ci				     &gpio_c);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	gpiochip_unlock_as_irq(gpio_c, gpio_n);
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic struct irq_chip mtk_eint_irq_chip = {
2688c2ecf20Sopenharmony_ci	.name = "mt-eint",
2698c2ecf20Sopenharmony_ci	.irq_disable = mtk_eint_mask,
2708c2ecf20Sopenharmony_ci	.irq_mask = mtk_eint_mask,
2718c2ecf20Sopenharmony_ci	.irq_unmask = mtk_eint_unmask,
2728c2ecf20Sopenharmony_ci	.irq_ack = mtk_eint_ack,
2738c2ecf20Sopenharmony_ci	.irq_set_type = mtk_eint_set_type,
2748c2ecf20Sopenharmony_ci	.irq_set_wake = mtk_eint_irq_set_wake,
2758c2ecf20Sopenharmony_ci	.irq_request_resources = mtk_eint_irq_request_resources,
2768c2ecf20Sopenharmony_ci	.irq_release_resources = mtk_eint_irq_release_resources,
2778c2ecf20Sopenharmony_ci};
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	void __iomem *dom_en = eint->base + eint->regs->dom_en;
2828c2ecf20Sopenharmony_ci	void __iomem *mask_set = eint->base + eint->regs->mask_set;
2838c2ecf20Sopenharmony_ci	unsigned int i;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	for (i = 0; i < eint->hw->ap_num; i += 32) {
2868c2ecf20Sopenharmony_ci		writel(0xffffffff, dom_en);
2878c2ecf20Sopenharmony_ci		writel(0xffffffff, mask_set);
2888c2ecf20Sopenharmony_ci		dom_en += 4;
2898c2ecf20Sopenharmony_ci		mask_set += 4;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	return 0;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic inline void
2968c2ecf20Sopenharmony_cimtk_eint_debounce_process(struct mtk_eint *eint, int index)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	unsigned int rst, ctrl_offset;
2998c2ecf20Sopenharmony_ci	unsigned int bit, dbnc;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl;
3028c2ecf20Sopenharmony_ci	dbnc = readl(eint->base + ctrl_offset);
3038c2ecf20Sopenharmony_ci	bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8);
3048c2ecf20Sopenharmony_ci	if ((bit & dbnc) > 0) {
3058c2ecf20Sopenharmony_ci		ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_set;
3068c2ecf20Sopenharmony_ci		rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8);
3078c2ecf20Sopenharmony_ci		writel(rst, eint->base + ctrl_offset);
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic void mtk_eint_irq_handler(struct irq_desc *desc)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	struct irq_chip *chip = irq_desc_get_chip(desc);
3148c2ecf20Sopenharmony_ci	struct mtk_eint *eint = irq_desc_get_handler_data(desc);
3158c2ecf20Sopenharmony_ci	unsigned int status, eint_num;
3168c2ecf20Sopenharmony_ci	int offset, mask_offset, index, virq;
3178c2ecf20Sopenharmony_ci	void __iomem *reg =  mtk_eint_get_offset(eint, 0, eint->regs->stat);
3188c2ecf20Sopenharmony_ci	int dual_edge, start_level, curr_level;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	chained_irq_enter(chip, desc);
3218c2ecf20Sopenharmony_ci	for (eint_num = 0; eint_num < eint->hw->ap_num; eint_num += 32,
3228c2ecf20Sopenharmony_ci	     reg += 4) {
3238c2ecf20Sopenharmony_ci		status = readl(reg);
3248c2ecf20Sopenharmony_ci		while (status) {
3258c2ecf20Sopenharmony_ci			offset = __ffs(status);
3268c2ecf20Sopenharmony_ci			mask_offset = eint_num >> 5;
3278c2ecf20Sopenharmony_ci			index = eint_num + offset;
3288c2ecf20Sopenharmony_ci			virq = irq_find_mapping(eint->domain, index);
3298c2ecf20Sopenharmony_ci			status &= ~BIT(offset);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci			/*
3328c2ecf20Sopenharmony_ci			 * If we get an interrupt on pin that was only required
3338c2ecf20Sopenharmony_ci			 * for wake (but no real interrupt requested), mask the
3348c2ecf20Sopenharmony_ci			 * interrupt (as would mtk_eint_resume do anyway later
3358c2ecf20Sopenharmony_ci			 * in the resume sequence).
3368c2ecf20Sopenharmony_ci			 */
3378c2ecf20Sopenharmony_ci			if (eint->wake_mask[mask_offset] & BIT(offset) &&
3388c2ecf20Sopenharmony_ci			    !(eint->cur_mask[mask_offset] & BIT(offset))) {
3398c2ecf20Sopenharmony_ci				writel_relaxed(BIT(offset), reg -
3408c2ecf20Sopenharmony_ci					eint->regs->stat +
3418c2ecf20Sopenharmony_ci					eint->regs->mask_set);
3428c2ecf20Sopenharmony_ci			}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci			dual_edge = eint->dual_edge[index];
3458c2ecf20Sopenharmony_ci			if (dual_edge) {
3468c2ecf20Sopenharmony_ci				/*
3478c2ecf20Sopenharmony_ci				 * Clear soft-irq in case we raised it last
3488c2ecf20Sopenharmony_ci				 * time.
3498c2ecf20Sopenharmony_ci				 */
3508c2ecf20Sopenharmony_ci				writel(BIT(offset), reg - eint->regs->stat +
3518c2ecf20Sopenharmony_ci				       eint->regs->soft_clr);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci				start_level =
3548c2ecf20Sopenharmony_ci				eint->gpio_xlate->get_gpio_state(eint->pctl,
3558c2ecf20Sopenharmony_ci								 index);
3568c2ecf20Sopenharmony_ci			}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci			generic_handle_irq(virq);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci			if (dual_edge) {
3618c2ecf20Sopenharmony_ci				curr_level = mtk_eint_flip_edge(eint, index);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci				/*
3648c2ecf20Sopenharmony_ci				 * If level changed, we might lost one edge
3658c2ecf20Sopenharmony_ci				 * interrupt, raised it through soft-irq.
3668c2ecf20Sopenharmony_ci				 */
3678c2ecf20Sopenharmony_ci				if (start_level != curr_level)
3688c2ecf20Sopenharmony_ci					writel(BIT(offset), reg -
3698c2ecf20Sopenharmony_ci					       eint->regs->stat +
3708c2ecf20Sopenharmony_ci					       eint->regs->soft_set);
3718c2ecf20Sopenharmony_ci			}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci			if (index < eint->hw->db_cnt)
3748c2ecf20Sopenharmony_ci				mtk_eint_debounce_process(eint, index);
3758c2ecf20Sopenharmony_ci		}
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci	chained_irq_exit(chip, desc);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ciint mtk_eint_do_suspend(struct mtk_eint *eint)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return 0;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ciint mtk_eint_do_resume(struct mtk_eint *eint)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_do_resume);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ciint mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
3978c2ecf20Sopenharmony_ci			  unsigned int debounce)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	int virq, eint_offset;
4008c2ecf20Sopenharmony_ci	unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
4018c2ecf20Sopenharmony_ci		     dbnc;
4028c2ecf20Sopenharmony_ci	static const unsigned int debounce_time[] = {500, 1000, 16000, 32000,
4038c2ecf20Sopenharmony_ci						     64000, 128000, 256000};
4048c2ecf20Sopenharmony_ci	struct irq_data *d;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	virq = irq_find_mapping(eint->domain, eint_num);
4078c2ecf20Sopenharmony_ci	eint_offset = (eint_num % 4) * 8;
4088c2ecf20Sopenharmony_ci	d = irq_get_irq_data(virq);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	set_offset = (eint_num / 4) * 4 + eint->regs->dbnc_set;
4118c2ecf20Sopenharmony_ci	clr_offset = (eint_num / 4) * 4 + eint->regs->dbnc_clr;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (!mtk_eint_can_en_debounce(eint, eint_num))
4148c2ecf20Sopenharmony_ci		return -EINVAL;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	dbnc = ARRAY_SIZE(debounce_time);
4178c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
4188c2ecf20Sopenharmony_ci		if (debounce <= debounce_time[i]) {
4198c2ecf20Sopenharmony_ci			dbnc = i;
4208c2ecf20Sopenharmony_ci			break;
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (!mtk_eint_get_mask(eint, eint_num)) {
4258c2ecf20Sopenharmony_ci		mtk_eint_mask(d);
4268c2ecf20Sopenharmony_ci		unmask = 1;
4278c2ecf20Sopenharmony_ci	} else {
4288c2ecf20Sopenharmony_ci		unmask = 0;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	clr_bit = 0xff << eint_offset;
4328c2ecf20Sopenharmony_ci	writel(clr_bit, eint->base + clr_offset);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) <<
4358c2ecf20Sopenharmony_ci		eint_offset;
4368c2ecf20Sopenharmony_ci	rst = MTK_EINT_DBNC_RST_BIT << eint_offset;
4378c2ecf20Sopenharmony_ci	writel(rst | bit, eint->base + set_offset);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/*
4408c2ecf20Sopenharmony_ci	 * Delay a while (more than 2T) to wait for hw debounce counter reset
4418c2ecf20Sopenharmony_ci	 * work correctly.
4428c2ecf20Sopenharmony_ci	 */
4438c2ecf20Sopenharmony_ci	udelay(1);
4448c2ecf20Sopenharmony_ci	if (unmask == 1)
4458c2ecf20Sopenharmony_ci		mtk_eint_unmask(d);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return 0;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_set_debounce);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ciint mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	int irq;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	irq = irq_find_mapping(eint->domain, eint_n);
4568c2ecf20Sopenharmony_ci	if (!irq)
4578c2ecf20Sopenharmony_ci		return -EINVAL;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	return irq;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_find_irq);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ciint mtk_eint_do_init(struct mtk_eint *eint)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	int i;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	/* If clients don't assign a specific regs, let's use generic one */
4688c2ecf20Sopenharmony_ci	if (!eint->regs)
4698c2ecf20Sopenharmony_ci		eint->regs = &mtk_generic_eint_regs;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
4728c2ecf20Sopenharmony_ci				       sizeof(*eint->wake_mask), GFP_KERNEL);
4738c2ecf20Sopenharmony_ci	if (!eint->wake_mask)
4748c2ecf20Sopenharmony_ci		return -ENOMEM;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
4778c2ecf20Sopenharmony_ci				      sizeof(*eint->cur_mask), GFP_KERNEL);
4788c2ecf20Sopenharmony_ci	if (!eint->cur_mask)
4798c2ecf20Sopenharmony_ci		return -ENOMEM;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
4828c2ecf20Sopenharmony_ci				       sizeof(int), GFP_KERNEL);
4838c2ecf20Sopenharmony_ci	if (!eint->dual_edge)
4848c2ecf20Sopenharmony_ci		return -ENOMEM;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	eint->domain = irq_domain_add_linear(eint->dev->of_node,
4878c2ecf20Sopenharmony_ci					     eint->hw->ap_num,
4888c2ecf20Sopenharmony_ci					     &irq_domain_simple_ops, NULL);
4898c2ecf20Sopenharmony_ci	if (!eint->domain)
4908c2ecf20Sopenharmony_ci		return -ENOMEM;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	mtk_eint_hw_init(eint);
4938c2ecf20Sopenharmony_ci	for (i = 0; i < eint->hw->ap_num; i++) {
4948c2ecf20Sopenharmony_ci		int virq = irq_create_mapping(eint->domain, i);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
4978c2ecf20Sopenharmony_ci					 handle_level_irq);
4988c2ecf20Sopenharmony_ci		irq_set_chip_data(virq, eint);
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
5028c2ecf20Sopenharmony_ci					 eint);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	return 0;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_do_init);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
5098c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MediaTek EINT Driver");
510