162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (c) 2014-2018 MediaTek Inc. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* 562306a36Sopenharmony_ci * Library for MediaTek External Interrupt Support 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Maoguang Meng <maoguang.meng@mediatek.com> 862306a36Sopenharmony_ci * Sean Wang <sean.wang@mediatek.com> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 1762306a36Sopenharmony_ci#include <linux/irqdomain.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/of_irq.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "mtk-eint.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define MTK_EINT_EDGE_SENSITIVE 0 2562306a36Sopenharmony_ci#define MTK_EINT_LEVEL_SENSITIVE 1 2662306a36Sopenharmony_ci#define MTK_EINT_DBNC_SET_DBNC_BITS 4 2762306a36Sopenharmony_ci#define MTK_EINT_DBNC_MAX 16 2862306a36Sopenharmony_ci#define MTK_EINT_DBNC_RST_BIT (0x1 << 1) 2962306a36Sopenharmony_ci#define MTK_EINT_DBNC_SET_EN (0x1 << 0) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const struct mtk_eint_regs mtk_generic_eint_regs = { 3262306a36Sopenharmony_ci .stat = 0x000, 3362306a36Sopenharmony_ci .ack = 0x040, 3462306a36Sopenharmony_ci .mask = 0x080, 3562306a36Sopenharmony_ci .mask_set = 0x0c0, 3662306a36Sopenharmony_ci .mask_clr = 0x100, 3762306a36Sopenharmony_ci .sens = 0x140, 3862306a36Sopenharmony_ci .sens_set = 0x180, 3962306a36Sopenharmony_ci .sens_clr = 0x1c0, 4062306a36Sopenharmony_ci .soft = 0x200, 4162306a36Sopenharmony_ci .soft_set = 0x240, 4262306a36Sopenharmony_ci .soft_clr = 0x280, 4362306a36Sopenharmony_ci .pol = 0x300, 4462306a36Sopenharmony_ci .pol_set = 0x340, 4562306a36Sopenharmony_ci .pol_clr = 0x380, 4662306a36Sopenharmony_ci .dom_en = 0x400, 4762306a36Sopenharmony_ci .dbnc_ctrl = 0x500, 4862306a36Sopenharmony_ci .dbnc_set = 0x600, 4962306a36Sopenharmony_ci .dbnc_clr = 0x700, 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciconst unsigned int debounce_time_mt2701[] = { 5362306a36Sopenharmony_ci 500, 1000, 16000, 32000, 64000, 128000, 256000, 0 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debounce_time_mt2701); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciconst unsigned int debounce_time_mt6765[] = { 5862306a36Sopenharmony_ci 125, 250, 500, 1000, 16000, 32000, 64000, 128000, 256000, 512000, 0 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debounce_time_mt6765); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciconst unsigned int debounce_time_mt6795[] = { 6362306a36Sopenharmony_ci 500, 1000, 16000, 32000, 64000, 128000, 256000, 512000, 0 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debounce_time_mt6795); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void __iomem *mtk_eint_get_offset(struct mtk_eint *eint, 6862306a36Sopenharmony_ci unsigned int eint_num, 6962306a36Sopenharmony_ci unsigned int offset) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci unsigned int eint_base = 0; 7262306a36Sopenharmony_ci void __iomem *reg; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (eint_num >= eint->hw->ap_num) 7562306a36Sopenharmony_ci eint_base = eint->hw->ap_num; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return reg; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint, 8362306a36Sopenharmony_ci unsigned int eint_num) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci unsigned int sens; 8662306a36Sopenharmony_ci unsigned int bit = BIT(eint_num % 32); 8762306a36Sopenharmony_ci void __iomem *reg = mtk_eint_get_offset(eint, eint_num, 8862306a36Sopenharmony_ci eint->regs->sens); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (readl(reg) & bit) 9162306a36Sopenharmony_ci sens = MTK_EINT_LEVEL_SENSITIVE; 9262306a36Sopenharmony_ci else 9362306a36Sopenharmony_ci sens = MTK_EINT_EDGE_SENSITIVE; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (eint_num < eint->hw->db_cnt && sens != MTK_EINT_EDGE_SENSITIVE) 9662306a36Sopenharmony_ci return 1; 9762306a36Sopenharmony_ci else 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int start_level, curr_level; 10462306a36Sopenharmony_ci unsigned int reg_offset; 10562306a36Sopenharmony_ci u32 mask = BIT(hwirq & 0x1f); 10662306a36Sopenharmony_ci u32 port = (hwirq >> 5) & eint->hw->port_mask; 10762306a36Sopenharmony_ci void __iomem *reg = eint->base + (port << 2); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci do { 11262306a36Sopenharmony_ci start_level = curr_level; 11362306a36Sopenharmony_ci if (start_level) 11462306a36Sopenharmony_ci reg_offset = eint->regs->pol_clr; 11562306a36Sopenharmony_ci else 11662306a36Sopenharmony_ci reg_offset = eint->regs->pol_set; 11762306a36Sopenharmony_ci writel(mask, reg + reg_offset); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, 12062306a36Sopenharmony_ci hwirq); 12162306a36Sopenharmony_ci } while (start_level != curr_level); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return start_level; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void mtk_eint_mask(struct irq_data *d) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct mtk_eint *eint = irq_data_get_irq_chip_data(d); 12962306a36Sopenharmony_ci u32 mask = BIT(d->hwirq & 0x1f); 13062306a36Sopenharmony_ci void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, 13162306a36Sopenharmony_ci eint->regs->mask_set); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci eint->cur_mask[d->hwirq >> 5] &= ~mask; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci writel(mask, reg); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void mtk_eint_unmask(struct irq_data *d) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct mtk_eint *eint = irq_data_get_irq_chip_data(d); 14162306a36Sopenharmony_ci u32 mask = BIT(d->hwirq & 0x1f); 14262306a36Sopenharmony_ci void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, 14362306a36Sopenharmony_ci eint->regs->mask_clr); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci eint->cur_mask[d->hwirq >> 5] |= mask; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci writel(mask, reg); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (eint->dual_edge[d->hwirq]) 15062306a36Sopenharmony_ci mtk_eint_flip_edge(eint, d->hwirq); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic unsigned int mtk_eint_get_mask(struct mtk_eint *eint, 15462306a36Sopenharmony_ci unsigned int eint_num) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci unsigned int bit = BIT(eint_num % 32); 15762306a36Sopenharmony_ci void __iomem *reg = mtk_eint_get_offset(eint, eint_num, 15862306a36Sopenharmony_ci eint->regs->mask); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return !!(readl(reg) & bit); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic void mtk_eint_ack(struct irq_data *d) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct mtk_eint *eint = irq_data_get_irq_chip_data(d); 16662306a36Sopenharmony_ci u32 mask = BIT(d->hwirq & 0x1f); 16762306a36Sopenharmony_ci void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, 16862306a36Sopenharmony_ci eint->regs->ack); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci writel(mask, reg); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int mtk_eint_set_type(struct irq_data *d, unsigned int type) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct mtk_eint *eint = irq_data_get_irq_chip_data(d); 17662306a36Sopenharmony_ci bool masked; 17762306a36Sopenharmony_ci u32 mask = BIT(d->hwirq & 0x1f); 17862306a36Sopenharmony_ci void __iomem *reg; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) || 18162306a36Sopenharmony_ci ((type & IRQ_TYPE_LEVEL_MASK) == IRQ_TYPE_LEVEL_MASK)) { 18262306a36Sopenharmony_ci dev_err(eint->dev, 18362306a36Sopenharmony_ci "Can't configure IRQ%d (EINT%lu) for type 0x%X\n", 18462306a36Sopenharmony_ci d->irq, d->hwirq, type); 18562306a36Sopenharmony_ci return -EINVAL; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) 18962306a36Sopenharmony_ci eint->dual_edge[d->hwirq] = 1; 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci eint->dual_edge[d->hwirq] = 0; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (!mtk_eint_get_mask(eint, d->hwirq)) { 19462306a36Sopenharmony_ci mtk_eint_mask(d); 19562306a36Sopenharmony_ci masked = false; 19662306a36Sopenharmony_ci } else { 19762306a36Sopenharmony_ci masked = true; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) { 20162306a36Sopenharmony_ci reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_clr); 20262306a36Sopenharmony_ci writel(mask, reg); 20362306a36Sopenharmony_ci } else { 20462306a36Sopenharmony_ci reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_set); 20562306a36Sopenharmony_ci writel(mask, reg); 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { 20962306a36Sopenharmony_ci reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_clr); 21062306a36Sopenharmony_ci writel(mask, reg); 21162306a36Sopenharmony_ci } else { 21262306a36Sopenharmony_ci reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_set); 21362306a36Sopenharmony_ci writel(mask, reg); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci mtk_eint_ack(d); 21762306a36Sopenharmony_ci if (!masked) 21862306a36Sopenharmony_ci mtk_eint_unmask(d); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct mtk_eint *eint = irq_data_get_irq_chip_data(d); 22662306a36Sopenharmony_ci int shift = d->hwirq & 0x1f; 22762306a36Sopenharmony_ci int reg = d->hwirq >> 5; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (on) 23062306a36Sopenharmony_ci eint->wake_mask[reg] |= BIT(shift); 23162306a36Sopenharmony_ci else 23262306a36Sopenharmony_ci eint->wake_mask[reg] &= ~BIT(shift); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void mtk_eint_chip_write_mask(const struct mtk_eint *eint, 23862306a36Sopenharmony_ci void __iomem *base, u32 *buf) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int port; 24162306a36Sopenharmony_ci void __iomem *reg; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci for (port = 0; port < eint->hw->ports; port++) { 24462306a36Sopenharmony_ci reg = base + (port << 2); 24562306a36Sopenharmony_ci writel_relaxed(~buf[port], reg + eint->regs->mask_set); 24662306a36Sopenharmony_ci writel_relaxed(buf[port], reg + eint->regs->mask_clr); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int mtk_eint_irq_request_resources(struct irq_data *d) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct mtk_eint *eint = irq_data_get_irq_chip_data(d); 25362306a36Sopenharmony_ci struct gpio_chip *gpio_c; 25462306a36Sopenharmony_ci unsigned int gpio_n; 25562306a36Sopenharmony_ci int err; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci err = eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq, 25862306a36Sopenharmony_ci &gpio_n, &gpio_c); 25962306a36Sopenharmony_ci if (err < 0) { 26062306a36Sopenharmony_ci dev_err(eint->dev, "Can not find pin\n"); 26162306a36Sopenharmony_ci return err; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci err = gpiochip_lock_as_irq(gpio_c, gpio_n); 26562306a36Sopenharmony_ci if (err < 0) { 26662306a36Sopenharmony_ci dev_err(eint->dev, "unable to lock HW IRQ %lu for IRQ\n", 26762306a36Sopenharmony_ci irqd_to_hwirq(d)); 26862306a36Sopenharmony_ci return err; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci err = eint->gpio_xlate->set_gpio_as_eint(eint->pctl, d->hwirq); 27262306a36Sopenharmony_ci if (err < 0) { 27362306a36Sopenharmony_ci dev_err(eint->dev, "Can not eint mode\n"); 27462306a36Sopenharmony_ci return err; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void mtk_eint_irq_release_resources(struct irq_data *d) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct mtk_eint *eint = irq_data_get_irq_chip_data(d); 28362306a36Sopenharmony_ci struct gpio_chip *gpio_c; 28462306a36Sopenharmony_ci unsigned int gpio_n; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq, &gpio_n, 28762306a36Sopenharmony_ci &gpio_c); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci gpiochip_unlock_as_irq(gpio_c, gpio_n); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic struct irq_chip mtk_eint_irq_chip = { 29362306a36Sopenharmony_ci .name = "mt-eint", 29462306a36Sopenharmony_ci .irq_disable = mtk_eint_mask, 29562306a36Sopenharmony_ci .irq_mask = mtk_eint_mask, 29662306a36Sopenharmony_ci .irq_unmask = mtk_eint_unmask, 29762306a36Sopenharmony_ci .irq_ack = mtk_eint_ack, 29862306a36Sopenharmony_ci .irq_set_type = mtk_eint_set_type, 29962306a36Sopenharmony_ci .irq_set_wake = mtk_eint_irq_set_wake, 30062306a36Sopenharmony_ci .irq_request_resources = mtk_eint_irq_request_resources, 30162306a36Sopenharmony_ci .irq_release_resources = mtk_eint_irq_release_resources, 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic unsigned int mtk_eint_hw_init(struct mtk_eint *eint) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci void __iomem *dom_en = eint->base + eint->regs->dom_en; 30762306a36Sopenharmony_ci void __iomem *mask_set = eint->base + eint->regs->mask_set; 30862306a36Sopenharmony_ci unsigned int i; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci for (i = 0; i < eint->hw->ap_num; i += 32) { 31162306a36Sopenharmony_ci writel(0xffffffff, dom_en); 31262306a36Sopenharmony_ci writel(0xffffffff, mask_set); 31362306a36Sopenharmony_ci dom_en += 4; 31462306a36Sopenharmony_ci mask_set += 4; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic inline void 32162306a36Sopenharmony_cimtk_eint_debounce_process(struct mtk_eint *eint, int index) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci unsigned int rst, ctrl_offset; 32462306a36Sopenharmony_ci unsigned int bit, dbnc; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl; 32762306a36Sopenharmony_ci dbnc = readl(eint->base + ctrl_offset); 32862306a36Sopenharmony_ci bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8); 32962306a36Sopenharmony_ci if ((bit & dbnc) > 0) { 33062306a36Sopenharmony_ci ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_set; 33162306a36Sopenharmony_ci rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8); 33262306a36Sopenharmony_ci writel(rst, eint->base + ctrl_offset); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void mtk_eint_irq_handler(struct irq_desc *desc) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 33962306a36Sopenharmony_ci struct mtk_eint *eint = irq_desc_get_handler_data(desc); 34062306a36Sopenharmony_ci unsigned int status, eint_num; 34162306a36Sopenharmony_ci int offset, mask_offset, index; 34262306a36Sopenharmony_ci void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat); 34362306a36Sopenharmony_ci int dual_edge, start_level, curr_level; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci chained_irq_enter(chip, desc); 34662306a36Sopenharmony_ci for (eint_num = 0; eint_num < eint->hw->ap_num; eint_num += 32, 34762306a36Sopenharmony_ci reg += 4) { 34862306a36Sopenharmony_ci status = readl(reg); 34962306a36Sopenharmony_ci while (status) { 35062306a36Sopenharmony_ci offset = __ffs(status); 35162306a36Sopenharmony_ci mask_offset = eint_num >> 5; 35262306a36Sopenharmony_ci index = eint_num + offset; 35362306a36Sopenharmony_ci status &= ~BIT(offset); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* 35662306a36Sopenharmony_ci * If we get an interrupt on pin that was only required 35762306a36Sopenharmony_ci * for wake (but no real interrupt requested), mask the 35862306a36Sopenharmony_ci * interrupt (as would mtk_eint_resume do anyway later 35962306a36Sopenharmony_ci * in the resume sequence). 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci if (eint->wake_mask[mask_offset] & BIT(offset) && 36262306a36Sopenharmony_ci !(eint->cur_mask[mask_offset] & BIT(offset))) { 36362306a36Sopenharmony_ci writel_relaxed(BIT(offset), reg - 36462306a36Sopenharmony_ci eint->regs->stat + 36562306a36Sopenharmony_ci eint->regs->mask_set); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci dual_edge = eint->dual_edge[index]; 36962306a36Sopenharmony_ci if (dual_edge) { 37062306a36Sopenharmony_ci /* 37162306a36Sopenharmony_ci * Clear soft-irq in case we raised it last 37262306a36Sopenharmony_ci * time. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci writel(BIT(offset), reg - eint->regs->stat + 37562306a36Sopenharmony_ci eint->regs->soft_clr); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci start_level = 37862306a36Sopenharmony_ci eint->gpio_xlate->get_gpio_state(eint->pctl, 37962306a36Sopenharmony_ci index); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci generic_handle_domain_irq(eint->domain, index); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (dual_edge) { 38562306a36Sopenharmony_ci curr_level = mtk_eint_flip_edge(eint, index); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* 38862306a36Sopenharmony_ci * If level changed, we might lost one edge 38962306a36Sopenharmony_ci * interrupt, raised it through soft-irq. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci if (start_level != curr_level) 39262306a36Sopenharmony_ci writel(BIT(offset), reg - 39362306a36Sopenharmony_ci eint->regs->stat + 39462306a36Sopenharmony_ci eint->regs->soft_set); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (index < eint->hw->db_cnt) 39862306a36Sopenharmony_ci mtk_eint_debounce_process(eint, index); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci chained_irq_exit(chip, desc); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ciint mtk_eint_do_suspend(struct mtk_eint *eint) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_do_suspend); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ciint mtk_eint_do_resume(struct mtk_eint *eint) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_do_resume); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ciint mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, 42162306a36Sopenharmony_ci unsigned int debounce) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci int virq, eint_offset; 42462306a36Sopenharmony_ci unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, 42562306a36Sopenharmony_ci dbnc; 42662306a36Sopenharmony_ci struct irq_data *d; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (!eint->hw->db_time) 42962306a36Sopenharmony_ci return -EOPNOTSUPP; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci virq = irq_find_mapping(eint->domain, eint_num); 43262306a36Sopenharmony_ci eint_offset = (eint_num % 4) * 8; 43362306a36Sopenharmony_ci d = irq_get_irq_data(virq); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci set_offset = (eint_num / 4) * 4 + eint->regs->dbnc_set; 43662306a36Sopenharmony_ci clr_offset = (eint_num / 4) * 4 + eint->regs->dbnc_clr; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (!mtk_eint_can_en_debounce(eint, eint_num)) 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci dbnc = eint->num_db_time; 44262306a36Sopenharmony_ci for (i = 0; i < eint->num_db_time; i++) { 44362306a36Sopenharmony_ci if (debounce <= eint->hw->db_time[i]) { 44462306a36Sopenharmony_ci dbnc = i; 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (!mtk_eint_get_mask(eint, eint_num)) { 45062306a36Sopenharmony_ci mtk_eint_mask(d); 45162306a36Sopenharmony_ci unmask = 1; 45262306a36Sopenharmony_ci } else { 45362306a36Sopenharmony_ci unmask = 0; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci clr_bit = 0xff << eint_offset; 45762306a36Sopenharmony_ci writel(clr_bit, eint->base + clr_offset); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) << 46062306a36Sopenharmony_ci eint_offset; 46162306a36Sopenharmony_ci rst = MTK_EINT_DBNC_RST_BIT << eint_offset; 46262306a36Sopenharmony_ci writel(rst | bit, eint->base + set_offset); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* 46562306a36Sopenharmony_ci * Delay a while (more than 2T) to wait for hw debounce counter reset 46662306a36Sopenharmony_ci * work correctly. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci udelay(1); 46962306a36Sopenharmony_ci if (unmask == 1) 47062306a36Sopenharmony_ci mtk_eint_unmask(d); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_set_debounce); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ciint mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci int irq; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci irq = irq_find_mapping(eint->domain, eint_n); 48162306a36Sopenharmony_ci if (!irq) 48262306a36Sopenharmony_ci return -EINVAL; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return irq; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_find_irq); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ciint mtk_eint_do_init(struct mtk_eint *eint) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci int i; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* If clients don't assign a specific regs, let's use generic one */ 49362306a36Sopenharmony_ci if (!eint->regs) 49462306a36Sopenharmony_ci eint->regs = &mtk_generic_eint_regs; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports, 49762306a36Sopenharmony_ci sizeof(*eint->wake_mask), GFP_KERNEL); 49862306a36Sopenharmony_ci if (!eint->wake_mask) 49962306a36Sopenharmony_ci return -ENOMEM; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports, 50262306a36Sopenharmony_ci sizeof(*eint->cur_mask), GFP_KERNEL); 50362306a36Sopenharmony_ci if (!eint->cur_mask) 50462306a36Sopenharmony_ci return -ENOMEM; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num, 50762306a36Sopenharmony_ci sizeof(int), GFP_KERNEL); 50862306a36Sopenharmony_ci if (!eint->dual_edge) 50962306a36Sopenharmony_ci return -ENOMEM; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci eint->domain = irq_domain_add_linear(eint->dev->of_node, 51262306a36Sopenharmony_ci eint->hw->ap_num, 51362306a36Sopenharmony_ci &irq_domain_simple_ops, NULL); 51462306a36Sopenharmony_ci if (!eint->domain) 51562306a36Sopenharmony_ci return -ENOMEM; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (eint->hw->db_time) { 51862306a36Sopenharmony_ci for (i = 0; i < MTK_EINT_DBNC_MAX; i++) 51962306a36Sopenharmony_ci if (eint->hw->db_time[i] == 0) 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci eint->num_db_time = i; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci mtk_eint_hw_init(eint); 52562306a36Sopenharmony_ci for (i = 0; i < eint->hw->ap_num; i++) { 52662306a36Sopenharmony_ci int virq = irq_create_mapping(eint->domain, i); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci irq_set_chip_and_handler(virq, &mtk_eint_irq_chip, 52962306a36Sopenharmony_ci handle_level_irq); 53062306a36Sopenharmony_ci irq_set_chip_data(virq, eint); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler, 53462306a36Sopenharmony_ci eint); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_eint_do_init); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 54162306a36Sopenharmony_ciMODULE_DESCRIPTION("MediaTek EINT Driver"); 542