+static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ const struct mtk_desc_pin *pin;
+ struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ int irq;
+
+ pin = pctl->devdata->pins + offset;
+ if (pin->eint.eintnum == NO_EINT_SUPPORT)
+ return -EINVAL;
+
+ irq = irq_find_mapping(pctl->domain, pin->eint.eintnum);
+ if (!irq)
+ return -EINVAL;
+
+ return irq;
+}
+
+static int mtk_pinctrl_irq_request_resources(struct irq_data *d)
+{
+ struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+ const struct mtk_desc_pin *pin;
+ int ret;
+
+ pin = mtk_find_pin_by_eint_num(pctl, d->hwirq);
+
+ if (!pin) {
+ dev_err(pctl->dev, "Can not find pin\n");
+ return -EINVAL;
+ }
+
+ ret = gpiochip_lock_as_irq(pctl->chip, pin->pin.number);
+ if (ret) {
+ dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
+ irqd_to_hwirq(d));
+ return ret;
+ }
+
+ /* set mux to INT mode */
+ mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux);
+
+ return 0;
+}
+
+static void mtk_pinctrl_irq_release_resources(struct irq_data *d)
+{
+ struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+ const struct mtk_desc_pin *pin;
+
+ pin = mtk_find_pin_by_eint_num(pctl, d->hwirq);
+
+ if (!pin) {
+ dev_err(pctl->dev, "Can not find pin\n");
+ return;
+ }
+
+ gpiochip_unlock_as_irq(pctl->chip, pin->pin.number);
+}
+
+static void __iomem *mtk_eint_get_offset(struct mtk_pinctrl *pctl,
+ unsigned int eint_num, unsigned int offset)
+{
+ unsigned int eint_base = 0;
+ void __iomem *reg;
+
+ if (eint_num >= pctl->devdata->ap_num)
+ eint_base = pctl->devdata->ap_num;
+
+ reg = pctl->eint_reg_base + offset + ((eint_num - eint_base) / 32) * 4;
+
+ return reg;
+}
+
+/*
+ * mtk_can_en_debounce: Check the EINT number is able to enable debounce or not
+ * @eint_num: the EINT number to setmtk_pinctrl
+ */
+static unsigned int mtk_eint_can_en_debounce(struct mtk_pinctrl *pctl,
+ unsigned int eint_num)
+{
+ unsigned int sens;
+ unsigned int bit = BIT(eint_num % 32);
+ const struct mtk_eint_offsets *eint_offsets =
+ &pctl->devdata->eint_offsets;
+
+ void __iomem *reg = mtk_eint_get_offset(pctl, eint_num,
+ eint_offsets->sens);
+
+ if (readl(reg) & bit)
+ sens = MT_LEVEL_SENSITIVE;
+ else
+ sens = MT_EDGE_SENSITIVE;
+
+ if ((eint_num < pctl->devdata->db_cnt) && (sens != MT_EDGE_SENSITIVE))
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * mtk_eint_get_mask: To get the eint mask
+ * @eint_num: the EINT number to get
+ */
+static unsigned int mtk_eint_get_mask(struct mtk_pinctrl *pctl,
+ unsigned int eint_num)
+{
+ unsigned int bit = BIT(eint_num % 32);
+ const struct mtk_eint_offsets *eint_offsets =
+ &pctl->devdata->eint_offsets;
+
+ void __iomem *reg = mtk_eint_get_offset(pctl, eint_num,
+ eint_offsets->mask);
+
+ return !!(readl(reg) & bit);
+}
+
+static void mtk_eint_mask(struct irq_data *d)
+{
+ struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+ const struct mtk_eint_offsets *eint_offsets =
+ &pctl->devdata->eint_offsets;
+ u32 mask = BIT(d->hwirq & 0x1f);
+ void __iomem *reg = mtk_eint_get_offset(pctl, d->hwirq,
+ eint_offsets->mask_set);
+
+ writel(mask, reg);
+}
+
+static void mtk_eint_unmask(struct irq_data *d)
+{
+ struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+ const struct mtk_eint_offsets *eint_offsets =
+ &pctl->devdata->eint_offsets;
+ u32 mask = BIT(d->hwirq & 0x1f);
+ void __iomem *reg = mtk_eint_get_offset(pctl, d->hwirq,
+ eint_offsets->mask_clr);
+
+ writel(mask, reg);
+}
+
+static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
+ unsigned debounce)
+{
+ struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ int eint_num, virq, eint_offset;
+ unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc;
+ static const unsigned int dbnc_arr[] = {0 , 1, 16, 32, 64, 128, 256};
+ const struct mtk_desc_pin *pin;
+ struct irq_data *d;
+
+ pin = pctl->devdata->pins + offset;
+ if (pin->eint.eintnum == NO_EINT_SUPPORT)
+ return -EINVAL;
+
+ eint_num = pin->eint.eintnum;
+ virq = irq_find_mapping(pctl->domain, eint_num);
+ eint_offset = (eint_num % 4) * 8;
+ d = irq_get_irq_data(virq);
+
+ set_offset = (eint_num / 4) * 4 + pctl->devdata->eint_offsets.dbnc_set;
+ clr_offset = (eint_num / 4) * 4 + pctl->devdata->eint_offsets.dbnc_clr;
+ if (!mtk_eint_can_en_debounce(pctl, eint_num))
+ return -ENOSYS;
+
+ dbnc = ARRAY_SIZE(dbnc_arr);
+ for (i = 0; i < ARRAY_SIZE(dbnc_arr); i++) {
+ if (debounce <= dbnc_arr[i]) {
+ dbnc = i;
+ break;
+ }
+ }
+
+ if (!mtk_eint_get_mask(pctl, eint_num)) {
+ mtk_eint_mask(d);
+ unmask = 1;
+ }
+
+ clr_bit = 0xff << eint_offset;
+ writel(clr_bit, pctl->eint_reg_base + clr_offset);
+
+ bit = ((dbnc << EINT_DBNC_SET_DBNC_BITS) | EINT_DBNC_SET_EN) <<
+ eint_offset;
+ rst = EINT_DBNC_RST_BIT << eint_offset;
+ writel(rst | bit, pctl->eint_reg_base + set_offset);
+
+ /* Delay a while (more than 2T) to wait for hw debounce counter reset
+ work correctly */
+ udelay(1);
+ if (unmask == 1)
+ mtk_eint_unmask(d);
+
+ return 0;
+}
+