2018-05-20 17:07:23

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 0/7] add external interrupt support to MT7622 pinctrl

From: Sean Wang <[email protected]>

The series is to add external interrupt support to MT7622 pinctrl.

Before we can freely do that in pinctrl-mt7622.c with patch 3, a refactor
work has to be done with patch 2 to split EINT-related code from a
specific driver and then allows pintrl-mt7622.c to reuse it.

patch 1, 3, 7: add EINT support to MT7622 pinctrl.
patch 2, 6: make EINT-related become a generic way for all MediaTek
pinctrl.
patch 4, 5: eliminate unnecessary code in existent EINT-related ones after
refactor work was done.

Sean Wang (7):
dt-bindings: pinctrl: add external interrupt support to MT7622 pinctrl
pinctrl: mediatek: refactor EINT related code for all MediaTek pinctrl
can fit
pinctrl: mediatek: add EINT support to MT7622 SoC
pinctrl: mediatek: use generic EINT register maps for each SoC
pinctrl: mediatek: remove unused fields in struct mtk_eint_hw
MAINTAINERS: update entry for PIN CONTROLLER - MEDIATEK
arm64: dts: mt7622: add EINT support to pinctrl

.../devicetree/bindings/pinctrl/pinctrl-mt7622.txt | 10 +
MAINTAINERS | 1 +
arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 2 +-
arch/arm64/boot/dts/mediatek/mt7622.dtsi | 8 +-
drivers/pinctrl/mediatek/Kconfig | 6 +
drivers/pinctrl/mediatek/Makefile | 1 +
drivers/pinctrl/mediatek/mtk-eint.c | 492 +++++++++++++++++
drivers/pinctrl/mediatek/mtk-eint.h | 106 ++++
drivers/pinctrl/mediatek/pinctrl-mt2701.c | 25 +-
drivers/pinctrl/mediatek/pinctrl-mt2712.c | 25 +-
drivers/pinctrl/mediatek/pinctrl-mt7622.c | 143 +++++
drivers/pinctrl/mediatek/pinctrl-mt8127.c | 25 +-
drivers/pinctrl/mediatek/pinctrl-mt8135.c | 25 +-
drivers/pinctrl/mediatek/pinctrl-mt8173.c | 25 +-
drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 608 ++++-----------------
drivers/pinctrl/mediatek/pinctrl-mtk-common.h | 13 +-
16 files changed, 901 insertions(+), 614 deletions(-)
create mode 100644 drivers/pinctrl/mediatek/mtk-eint.c
create mode 100644 drivers/pinctrl/mediatek/mtk-eint.h

--
2.7.4



2018-05-20 17:03:42

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 6/7] MAINTAINERS: update entry for PIN CONTROLLER - MEDIATEK

From: Sean Wang <[email protected]>

Add new files for the entry

Signed-off-by: Sean Wang <[email protected]>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9051a9c..7f3cced 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11193,6 +11193,7 @@ L: [email protected] (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
F: Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt
+F: drivers/pinctrl/mediatek/mtk-eint.*
F: drivers/pinctrl/mediatek/pinctrl-mtk-common.*
F: drivers/pinctrl/mediatek/pinctrl-mt2701.c
F: drivers/pinctrl/mediatek/pinctrl-mt7622.c
--
2.7.4


2018-05-20 17:03:42

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 4/7] pinctrl: mediatek: use generic EINT register maps for each SoC

From: Sean Wang <[email protected]>

So far, EINT on each SoC all used exactly identical register map and thus
it's better that we apply generic register map already supported in EINT
library and stop copy-n-pasting the same data block and filling into its
platform data.

Signed-off-by: Sean Wang <[email protected]>
---
drivers/pinctrl/mediatek/pinctrl-mt2701.c | 20 --------------------
drivers/pinctrl/mediatek/pinctrl-mt2712.c | 20 --------------------
drivers/pinctrl/mediatek/pinctrl-mt8127.c | 20 --------------------
drivers/pinctrl/mediatek/pinctrl-mt8135.c | 20 --------------------
drivers/pinctrl/mediatek/pinctrl-mt8173.c | 20 --------------------
drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 6 +++++-
drivers/pinctrl/mediatek/pinctrl-mtk-common.h | 2 +-
7 files changed, 6 insertions(+), 102 deletions(-)

diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
index e0963c6..db22250 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -538,26 +538,6 @@ static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
.ap_num = 169,
.db_cnt = 16,
},
- .eint_regs = {
- .stat = 0x000,
- .ack = 0x040,
- .mask = 0x080,
- .mask_set = 0x0c0,
- .mask_clr = 0x100,
- .sens = 0x140,
- .sens_set = 0x180,
- .sens_clr = 0x1c0,
- .soft = 0x200,
- .soft_set = 0x240,
- .soft_clr = 0x280,
- .pol = 0x300,
- .pol_set = 0x340,
- .pol_clr = 0x380,
- .dom_en = 0x400,
- .dbnc_ctrl = 0x500,
- .dbnc_set = 0x600,
- .dbnc_clr = 0x700,
- },
};

static int mt2701_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2712.c b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
index 02aff28..6e2acef 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2712.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
@@ -583,26 +583,6 @@ static const struct mtk_pinctrl_devdata mt2712_pinctrl_data = {
.ap_num = 229,
.db_cnt = 40,
},
- .eint_regs = {
- .stat = 0x000,
- .ack = 0x040,
- .mask = 0x080,
- .mask_set = 0x0c0,
- .mask_clr = 0x100,
- .sens = 0x140,
- .sens_set = 0x180,
- .sens_clr = 0x1c0,
- .soft = 0x200,
- .soft_set = 0x240,
- .soft_clr = 0x280,
- .pol = 0x300,
- .pol_set = 0x340,
- .pol_clr = 0x380,
- .dom_en = 0x400,
- .dbnc_ctrl = 0x500,
- .dbnc_set = 0x600,
- .dbnc_clr = 0x700,
- },
};

static int mt2712_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8127.c b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
index 71f6258..949a235 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8127.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
@@ -307,26 +307,6 @@ static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
.ap_num = 143,
.db_cnt = 16,
},
- .eint_regs = {
- .stat = 0x000,
- .ack = 0x040,
- .mask = 0x080,
- .mask_set = 0x0c0,
- .mask_clr = 0x100,
- .sens = 0x140,
- .sens_set = 0x180,
- .sens_clr = 0x1c0,
- .soft = 0x200,
- .soft_set = 0x240,
- .soft_clr = 0x280,
- .pol = 0x300,
- .pol_set = 0x340,
- .pol_clr = 0x380,
- .dom_en = 0x400,
- .dbnc_ctrl = 0x500,
- .dbnc_set = 0x600,
- .dbnc_clr = 0x700,
- },
};

static int mt8127_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8135.c b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
index fdfa357..974a1f43 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8135.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
@@ -320,26 +320,6 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.ap_num = 192,
.db_cnt = 16,
},
- .eint_regs = {
- .stat = 0x000,
- .ack = 0x040,
- .mask = 0x080,
- .mask_set = 0x0c0,
- .mask_clr = 0x100,
- .sens = 0x140,
- .sens_set = 0x180,
- .sens_clr = 0x1c0,
- .soft = 0x200,
- .soft_set = 0x240,
- .soft_clr = 0x280,
- .pol = 0x300,
- .pol_set = 0x340,
- .pol_clr = 0x380,
- .dom_en = 0x400,
- .dbnc_ctrl = 0x500,
- .dbnc_set = 0x600,
- .dbnc_clr = 0x700,
- },
};

static int mt8135_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index 1466c95..a836cee3 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -347,26 +347,6 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
.ap_num = 224,
.db_cnt = 16,
},
- .eint_regs = {
- .stat = 0x000,
- .ack = 0x040,
- .mask = 0x080,
- .mask_set = 0x0c0,
- .mask_clr = 0x100,
- .sens = 0x140,
- .sens_set = 0x180,
- .sens_clr = 0x1c0,
- .soft = 0x200,
- .soft_set = 0x240,
- .soft_clr = 0x280,
- .pol = 0x300,
- .pol_set = 0x340,
- .pol_clr = 0x380,
- .dom_en = 0x400,
- .dbnc_ctrl = 0x500,
- .dbnc_set = 0x600,
- .dbnc_clr = 0x700,
- },
};

static int mt8173_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 11e0d0f..b379969 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -1014,7 +1014,11 @@ static int mtk_eint_init(struct mtk_pinctrl *pctl, struct platform_device *pdev)
return -EINVAL;

pctl->eint->dev = &pdev->dev;
- pctl->eint->regs = &pctl->devdata->eint_regs;
+ /*
+ * If pctl->eint->regs == NULL, it would fall back into using a generic
+ * register map in mtk_eint_do_init calls.
+ */
+ pctl->eint->regs = pctl->devdata->eint_regs;
pctl->eint->hw = &pctl->devdata->eint_hw;
pctl->eint->pctl = pctl;
pctl->eint->gpio_xlate = &mtk_eint_xt;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
index 346e3db..bf13eb0 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -261,7 +261,7 @@ struct mtk_pinctrl_devdata {
unsigned char port_mask;
unsigned char port_align;
struct mtk_eint_hw eint_hw;
- struct mtk_eint_regs eint_regs;
+ struct mtk_eint_regs *eint_regs;
};

struct mtk_pinctrl {
--
2.7.4


2018-05-20 17:03:42

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 2/7] pinctrl: mediatek: refactor EINT related code for all MediaTek pinctrl can fit

From: Sean Wang <[email protected]>

This patch is in preparation for adding EINT support to MT7622 pinctrl,
and the refactoring doesn't alter any existent logic.

A reason we have to refactor EINT code pieces into a generic way is that
currently, they're tightly coupled with a certain type of MediaTek pinctrl
would cause a grown in a very bad way as there is different types of
pinctrl devices getting to join.

Therefore, it is an essential or urgent thing that EINT code pieces are
refactored to eliminate any dependencies across GPIO and EINT as possible.

Additional structure mtk_eint_[xt, hw, regs] are being introduced for
indicating how maps being designed between GPIO and EINT hw number, how to
set and get GPIO state for a certain EINT pin, what characteristic on a
EINT device is present on various SoCs.

Signed-off-by: Sean Wang <[email protected]>
---
drivers/pinctrl/mediatek/Kconfig | 6 +
drivers/pinctrl/mediatek/Makefile | 1 +
drivers/pinctrl/mediatek/mtk-eint.c | 492 +++++++++++++++++++++
drivers/pinctrl/mediatek/mtk-eint.h | 107 +++++
drivers/pinctrl/mediatek/pinctrl-mt2701.c | 12 +-
drivers/pinctrl/mediatek/pinctrl-mt2712.c | 12 +-
drivers/pinctrl/mediatek/pinctrl-mt8127.c | 12 +-
drivers/pinctrl/mediatek/pinctrl-mt8135.c | 12 +-
drivers/pinctrl/mediatek/pinctrl-mt8173.c | 12 +-
drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 604 +++++---------------------
drivers/pinctrl/mediatek/pinctrl-mtk-common.h | 13 +-
11 files changed, 756 insertions(+), 527 deletions(-)
create mode 100644 drivers/pinctrl/mediatek/mtk-eint.c
create mode 100644 drivers/pinctrl/mediatek/mtk-eint.h

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 862c5db..310db42 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -1,12 +1,18 @@
menu "MediaTek pinctrl drivers"
depends on ARCH_MEDIATEK || COMPILE_TEST

+config EINT_MTK
+ bool "MediaTek External Interrupt Support"
+ depends on PINCTRL_MTK || COMPILE_TEST
+ select IRQ_DOMAIN
+
config PINCTRL_MTK
bool
depends on OF
select PINMUX
select GENERIC_PINCONF
select GPIOLIB
+ select EINT_MTK
select OF_GPIO

# For ARMv7 SoCs
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index 7959e77..3de7156 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# Core
+obj-$(CONFIG_EINT_MTK) += mtk-eint.o
obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o

# SoC Drivers
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
new file mode 100644
index 0000000..30f3316
--- /dev/null
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2014-2018 MediaTek Inc.
+
+/*
+ * Library for MediaTek External Interrupt Support
+ *
+ * Author: Maoguang Meng <[email protected]>
+ * Sean Wang <[email protected]>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#include "mtk-eint.h"
+
+#define MTK_EINT_EDGE_SENSITIVE 0
+#define MTK_EINT_LEVEL_SENSITIVE 1
+#define MTK_EINT_DBNC_SET_DBNC_BITS 4
+#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
+#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
+
+static const struct mtk_eint_regs mtk_generic_eint_regs = {
+ .stat = 0x000,
+ .ack = 0x040,
+ .mask = 0x080,
+ .mask_set = 0x0c0,
+ .mask_clr = 0x100,
+ .sens = 0x140,
+ .sens_set = 0x180,
+ .sens_clr = 0x1c0,
+ .soft = 0x200,
+ .soft_set = 0x240,
+ .soft_clr = 0x280,
+ .pol = 0x300,
+ .pol_set = 0x340,
+ .pol_clr = 0x380,
+ .dom_en = 0x400,
+ .dbnc_ctrl = 0x500,
+ .dbnc_set = 0x600,
+ .dbnc_clr = 0x700,
+};
+
+static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
+ unsigned int eint_num,
+ unsigned int offset)
+{
+ unsigned int eint_base = 0;
+ void __iomem *reg;
+
+ if (eint_num >= eint->hw->ap_num)
+ eint_base = eint->hw->ap_num;
+
+ reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+
+ return reg;
+}
+
+static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int sens;
+ unsigned int bit = BIT(eint_num % 32);
+ void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
+ eint->regs->sens);
+
+ if (readl(reg) & bit)
+ sens = MTK_EINT_LEVEL_SENSITIVE;
+ else
+ sens = MTK_EINT_EDGE_SENSITIVE;
+
+ if (eint_num < eint->hw->db_cnt && sens != MTK_EINT_EDGE_SENSITIVE)
+ return 1;
+ else
+ return 0;
+}
+
+static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
+{
+ int start_level, curr_level;
+ unsigned int reg_offset;
+ u32 mask = BIT(hwirq & 0x1f);
+ u32 port = (hwirq >> 5) & eint->hw->port_mask;
+ void __iomem *reg = eint->base + (port << 2);
+
+ curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
+
+ do {
+ start_level = curr_level;
+ if (start_level)
+ reg_offset = eint->regs->pol_clr;
+ else
+ reg_offset = eint->regs->pol_set;
+ writel(mask, reg + reg_offset);
+
+ curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
+ hwirq);
+ } while (start_level != curr_level);
+
+ return start_level;
+}
+
+static void mtk_eint_mask(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ u32 mask = BIT(d->hwirq & 0x1f);
+ void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->regs->mask_set);
+
+ writel(mask, reg);
+}
+
+static void mtk_eint_unmask(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ u32 mask = BIT(d->hwirq & 0x1f);
+ void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->regs->mask_clr);
+
+ writel(mask, reg);
+
+ if (eint->dual_edge[d->hwirq])
+ mtk_eint_flip_edge(eint, d->hwirq);
+}
+
+static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
+ unsigned int eint_num)
+{
+ unsigned int bit = BIT(eint_num % 32);
+ void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
+ eint->regs->mask);
+
+ return !!(readl(reg) & bit);
+}
+
+static void mtk_eint_ack(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ u32 mask = BIT(d->hwirq & 0x1f);
+ void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
+ eint->regs->ack);
+
+ writel(mask, reg);
+}
+
+static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ u32 mask = BIT(d->hwirq & 0x1f);
+ void __iomem *reg;
+
+ if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
+ ((type & IRQ_TYPE_LEVEL_MASK) == IRQ_TYPE_LEVEL_MASK)) {
+ dev_err(eint->dev,
+ "Can't configure IRQ%d (EINT%lu) for type 0x%X\n",
+ d->irq, d->hwirq, type);
+ return -EINVAL;
+ }
+
+ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+ eint->dual_edge[d->hwirq] = 1;
+ else
+ eint->dual_edge[d->hwirq] = 0;
+
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
+ reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_clr);
+ writel(mask, reg);
+ } else {
+ reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_set);
+ writel(mask, reg);
+ }
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+ reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_clr);
+ writel(mask, reg);
+ } else {
+ reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_set);
+ writel(mask, reg);
+ }
+
+ if (eint->dual_edge[d->hwirq])
+ mtk_eint_flip_edge(eint, d->hwirq);
+
+ return 0;
+}
+
+static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ int shift = d->hwirq & 0x1f;
+ int reg = d->hwirq >> 5;
+
+ if (on)
+ eint->wake_mask[reg] |= BIT(shift);
+ else
+ eint->wake_mask[reg] &= ~BIT(shift);
+
+ return 0;
+}
+
+static void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
+ void __iomem *base, u32 *buf)
+{
+ int port;
+ void __iomem *reg;
+
+ for (port = 0; port < eint->hw->ports; port++) {
+ reg = base + (port << 2);
+ writel_relaxed(~buf[port], reg + eint->regs->mask_set);
+ writel_relaxed(buf[port], reg + eint->regs->mask_clr);
+ }
+}
+
+static void mtk_eint_chip_read_mask(const struct mtk_eint *eint,
+ void __iomem *base, u32 *buf)
+{
+ int port;
+ void __iomem *reg;
+
+ for (port = 0; port < eint->hw->ports; port++) {
+ reg = base + eint->regs->mask + (port << 2);
+ buf[port] = ~readl_relaxed(reg);
+ /* Mask is 0 when irq is enabled, and 1 when disabled. */
+ }
+}
+
+static int mtk_eint_irq_request_resources(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gpio_c;
+ unsigned int gpio_n;
+ int err;
+
+ err = eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq,
+ &gpio_n, &gpio_c);
+ if (err < 0) {
+ dev_err(eint->dev, "Can not find pin\n");
+ return err;
+ }
+
+ err = gpiochip_lock_as_irq(gpio_c, gpio_n);
+ if (err < 0) {
+ dev_err(eint->dev, "unable to lock HW IRQ %lu for IRQ\n",
+ irqd_to_hwirq(d));
+ return err;
+ }
+
+ err = eint->gpio_xlate->set_gpio_as_eint(eint->pctl, d->hwirq);
+ if (err < 0) {
+ dev_err(eint->dev, "Can not eint mode\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static void mtk_eint_irq_release_resources(struct irq_data *d)
+{
+ struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gpio_c;
+ unsigned int gpio_n;
+
+ eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq, &gpio_n,
+ &gpio_c);
+
+ gpiochip_unlock_as_irq(gpio_c, gpio_n);
+}
+
+static struct irq_chip mtk_eint_irq_chip = {
+ .name = "mt-eint",
+ .irq_disable = mtk_eint_mask,
+ .irq_mask = mtk_eint_mask,
+ .irq_unmask = mtk_eint_unmask,
+ .irq_ack = mtk_eint_ack,
+ .irq_set_type = mtk_eint_set_type,
+ .irq_set_wake = mtk_eint_irq_set_wake,
+ .irq_request_resources = mtk_eint_irq_request_resources,
+ .irq_release_resources = mtk_eint_irq_release_resources,
+};
+
+static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
+{
+ void __iomem *reg = eint->base + eint->regs->dom_en;
+ unsigned int i;
+
+ for (i = 0; i < eint->hw->ap_num; i += 32) {
+ writel(0xffffffff, reg);
+ reg += 4;
+ }
+
+ return 0;
+}
+
+static inline void
+mtk_eint_debounce_process(struct mtk_eint *eint, int index)
+{
+ unsigned int rst, ctrl_offset;
+ unsigned int bit, dbnc;
+
+ ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl;
+ dbnc = readl(eint->base + ctrl_offset);
+ bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8);
+ if ((bit & dbnc) > 0) {
+ ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_set;
+ rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8);
+ writel(rst, eint->base + ctrl_offset);
+ }
+}
+
+static void mtk_eint_irq_handler(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct mtk_eint *eint = irq_desc_get_handler_data(desc);
+ unsigned int status, eint_num;
+ int offset, index, virq;
+ void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
+ int dual_edge, start_level, curr_level;
+
+ chained_irq_enter(chip, desc);
+ for (eint_num = 0; eint_num < eint->hw->ap_num; eint_num += 32,
+ reg += 4) {
+ status = readl(reg);
+ while (status) {
+ offset = __ffs(status);
+ index = eint_num + offset;
+ virq = irq_find_mapping(eint->domain, index);
+ status &= ~BIT(offset);
+
+ dual_edge = eint->dual_edge[index];
+ if (dual_edge) {
+ /*
+ * Clear soft-irq in case we raised it last
+ * time.
+ */
+ writel(BIT(offset), reg - eint->regs->stat +
+ eint->regs->soft_clr);
+
+ start_level =
+ eint->gpio_xlate->get_gpio_state(eint->pctl,
+ index);
+ }
+
+ generic_handle_irq(virq);
+
+ if (dual_edge) {
+ curr_level = mtk_eint_flip_edge(eint, index);
+
+ /*
+ * If level changed, we might lost one edge
+ * interrupt, raised it through soft-irq.
+ */
+ if (start_level != curr_level)
+ writel(BIT(offset), reg -
+ eint->regs->stat +
+ eint->regs->soft_set);
+ }
+
+ if (index < eint->hw->db_cnt)
+ mtk_eint_debounce_process(eint, index);
+ }
+ }
+ chained_irq_exit(chip, desc);
+}
+
+int mtk_eint_do_suspend(struct mtk_eint *eint)
+{
+ mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask);
+ mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
+
+ return 0;
+}
+
+int mtk_eint_do_resume(struct mtk_eint *eint)
+{
+ mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
+
+ return 0;
+}
+
+int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
+ unsigned int debounce)
+{
+ int virq, eint_offset;
+ unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
+ dbnc;
+ static const unsigned int debounce_time[] = {500, 1000, 16000, 32000,
+ 64000, 128000, 256000};
+ struct irq_data *d;
+
+ virq = irq_find_mapping(eint->domain, eint_num);
+ eint_offset = (eint_num % 4) * 8;
+ d = irq_get_irq_data(virq);
+
+ set_offset = (eint_num / 4) * 4 + eint->regs->dbnc_set;
+ clr_offset = (eint_num / 4) * 4 + eint->regs->dbnc_clr;
+
+ if (!mtk_eint_can_en_debounce(eint, eint_num))
+ return -EINVAL;
+
+ dbnc = ARRAY_SIZE(debounce_time);
+ for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+ if (debounce <= debounce_time[i]) {
+ dbnc = i;
+ break;
+ }
+ }
+
+ if (!mtk_eint_get_mask(eint, eint_num)) {
+ mtk_eint_mask(d);
+ unmask = 1;
+ } else {
+ unmask = 0;
+ }
+
+ clr_bit = 0xff << eint_offset;
+ writel(clr_bit, eint->base + clr_offset);
+
+ bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) <<
+ eint_offset;
+ rst = MTK_EINT_DBNC_RST_BIT << eint_offset;
+ writel(rst | bit, eint->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;
+}
+
+int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
+{
+ int irq;
+
+ irq = irq_find_mapping(eint->domain, eint_n);
+ if (!irq)
+ return -EINVAL;
+
+ return irq;
+}
+
+int mtk_eint_do_init(struct mtk_eint *eint)
+{
+ int i;
+
+ /* If clients don't assign a specific regs, let's use generic one */
+ if (!eint->regs)
+ eint->regs = &mtk_generic_eint_regs;
+
+ eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
+ sizeof(*eint->wake_mask), GFP_KERNEL);
+ if (!eint->wake_mask)
+ return -ENOMEM;
+
+ eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
+ sizeof(*eint->cur_mask), GFP_KERNEL);
+ if (!eint->cur_mask)
+ return -ENOMEM;
+
+ eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
+ sizeof(int), GFP_KERNEL);
+ if (!eint->dual_edge)
+ return -ENOMEM;
+
+ eint->domain = irq_domain_add_linear(eint->dev->of_node,
+ eint->hw->ap_num,
+ &irq_domain_simple_ops, NULL);
+ if (!eint->domain)
+ return -ENOMEM;
+
+ mtk_eint_hw_init(eint);
+ for (i = 0; i < eint->hw->ap_num; i++) {
+ int virq = irq_create_mapping(eint->domain, i);
+
+ irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
+ handle_level_irq);
+ irq_set_chip_data(virq, eint);
+ }
+
+ irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
+ eint);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
new file mode 100644
index 0000000..55b4d5f
--- /dev/null
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2014-2018 MediaTek Inc.
+ *
+ * Author: Maoguang Meng <[email protected]>
+ * Sean Wang <[email protected]>
+ *
+ */
+#ifndef __MTK_EINT_H
+#define __MTK_EINT_H
+
+#include <linux/irqdomain.h>
+
+struct mtk_eint_regs {
+ unsigned int stat;
+ unsigned int ack;
+ unsigned int mask;
+ unsigned int mask_set;
+ unsigned int mask_clr;
+ unsigned int sens;
+ unsigned int sens_set;
+ unsigned int sens_clr;
+ unsigned int soft;
+ unsigned int soft_set;
+ unsigned int soft_clr;
+ unsigned int pol;
+ unsigned int pol_set;
+ unsigned int pol_clr;
+ unsigned int dom_en;
+ unsigned int dbnc_ctrl;
+ unsigned int dbnc_set;
+ unsigned int dbnc_clr;
+};
+
+struct mtk_eint_hw {
+ const char *name;
+ u8 port_mask;
+ u8 ports;
+ unsigned int ap_num;
+ unsigned int db_cnt;
+};
+
+struct mtk_eint;
+
+struct mtk_eint_xt {
+ int (*get_gpio_n)(void *data, unsigned long eint_n,
+ unsigned int *gpio_n,
+ struct gpio_chip **gpio_chip);
+ int (*get_gpio_state)(void *data, unsigned long eint_n);
+ int (*set_gpio_as_eint)(void *data, unsigned long eint_n);
+};
+
+struct mtk_eint {
+ struct device *dev;
+ void __iomem *base;
+ struct irq_domain *domain;
+ int irq;
+
+ int *dual_edge;
+ u32 *wake_mask;
+ u32 *cur_mask;
+
+ /* Used to fit into various EINT device */
+ const struct mtk_eint_hw *hw;
+ const struct mtk_eint_regs *regs;
+
+ /* Used to fit into various pinctrl device */
+ void *pctl;
+ const struct mtk_eint_xt *gpio_xlate;
+};
+
+#if IS_ENABLED(CONFIG_EINT_MTK)
+int mtk_eint_do_init(struct mtk_eint *eint);
+int mtk_eint_do_suspend(struct mtk_eint *eint);
+int mtk_eint_do_resume(struct mtk_eint *eint);
+int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
+ unsigned int debounce);
+int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n);
+
+#else
+static inline int mtk_eint_do_init(struct mtk_eint *eint)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int mtk_eint_do_resume(struct mtk_eint *eint)
+{
+ return -EOPNOTSUPP;
+}
+
+int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
+ unsigned int debounce)
+{
+ return -EOPNOTSUPP;
+}
+
+int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+#endif /* __MTK_EINT_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
index f86f3b3..e0963c6 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -531,8 +531,14 @@ static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
.port_shf = 4,
.port_mask = 0x1f,
.port_align = 4,
- .eint_offsets = {
+ .eint_hw = {
.name = "mt2701_eint",
+ .port_mask = 6,
+ .ports = 6,
+ .ap_num = 169,
+ .db_cnt = 16,
+ },
+ .eint_regs = {
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
@@ -551,11 +557,7 @@ static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
- .port_mask = 6,
- .ports = 6,
},
- .ap_num = 169,
- .db_cnt = 16,
};

static int mt2701_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2712.c b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
index 81e11f9..02aff28 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2712.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
@@ -576,8 +576,14 @@ static const struct mtk_pinctrl_devdata mt2712_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
- .eint_offsets = {
+ .eint_hw = {
.name = "mt2712_eint",
+ .port_mask = 0xf,
+ .ports = 8,
+ .ap_num = 229,
+ .db_cnt = 40,
+ },
+ .eint_regs = {
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
@@ -596,11 +602,7 @@ static const struct mtk_pinctrl_devdata mt2712_pinctrl_data = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
- .port_mask = 0xf,
- .ports = 8,
},
- .ap_num = 229,
- .db_cnt = 40,
};

static int mt2712_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8127.c b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
index d764915..71f6258 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8127.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
@@ -300,8 +300,14 @@ static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
- .eint_offsets = {
+ .eint_hw = {
.name = "mt8127_eint",
+ .port_mask = 7,
+ .ports = 6,
+ .ap_num = 143,
+ .db_cnt = 16,
+ },
+ .eint_regs = {
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
@@ -320,11 +326,7 @@ static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
- .port_mask = 7,
- .ports = 6,
},
- .ap_num = 143,
- .db_cnt = 16,
};

static int mt8127_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8135.c b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
index d8c645f..fdfa357 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8135.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
@@ -313,8 +313,14 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
- .eint_offsets = {
+ .eint_hw = {
.name = "mt8135_eint",
+ .port_mask = 7,
+ .ports = 6,
+ .ap_num = 192,
+ .db_cnt = 16,
+ },
+ .eint_regs = {
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
@@ -333,11 +339,7 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
- .port_mask = 7,
- .ports = 6,
},
- .ap_num = 192,
- .db_cnt = 16,
};

static int mt8135_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index 8bfd427..1466c95 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -340,8 +340,14 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
- .eint_offsets = {
+ .eint_hw = {
.name = "mt8173_eint",
+ .port_mask = 7,
+ .ports = 6,
+ .ap_num = 224,
+ .db_cnt = 16,
+ },
+ .eint_regs = {
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
@@ -360,11 +366,7 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
- .port_mask = 7,
- .ports = 6,
},
- .ap_num = 224,
- .db_cnt = 16,
};

static int mt8173_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index c3975a0..11e0d0f 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -38,6 +38,7 @@
#include "../core.h"
#include "../pinconf.h"
#include "../pinctrl-utils.h"
+#include "mtk-eint.h"
#include "pinctrl-mtk-common.h"

#define MAX_GPIO_MODE_PER_REG 5
@@ -831,243 +832,38 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)

static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- const struct mtk_desc_pin *pin;
struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- 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);
- /* set gpio direction to input */
- mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number, true);
- /* set input-enable */
- mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1, PIN_CONFIG_INPUT_ENABLE);
-
- 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 int mtk_eint_flip_edge(struct mtk_pinctrl *pctl, int hwirq)
-{
- int start_level, curr_level;
- unsigned int reg_offset;
- const struct mtk_eint_offsets *eint_offsets = &(pctl->devdata->eint_offsets);
- u32 mask = BIT(hwirq & 0x1f);
- u32 port = (hwirq >> 5) & eint_offsets->port_mask;
- void __iomem *reg = pctl->eint_reg_base + (port << 2);
- const struct mtk_desc_pin *pin;
-
- pin = mtk_find_pin_by_eint_num(pctl, hwirq);
- curr_level = mtk_gpio_get(pctl->chip, pin->pin.number);
- do {
- start_level = curr_level;
- if (start_level)
- reg_offset = eint_offsets->pol_clr;
- else
- reg_offset = eint_offsets->pol_set;
- writel(mask, reg + reg_offset);
-
- curr_level = mtk_gpio_get(pctl->chip, pin->pin.number);
- } while (start_level != curr_level);
-
- return start_level;
-}
-
-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);
-
- if (pctl->eint_dual_edges[d->hwirq])
- mtk_eint_flip_edge(pctl, d->hwirq);
-}
-
-static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
- unsigned debounce)
-{
- struct mtk_pinctrl *pctl = dev_get_drvdata(chip->parent);
- int eint_num, virq, eint_offset;
- unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc;
- static const unsigned int debounce_time[] = {500, 1000, 16000, 32000, 64000,
- 128000, 256000};
const struct mtk_desc_pin *pin;
- struct irq_data *d;
+ unsigned long eint_n;

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(debounce_time);
- for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
- if (debounce <= debounce_time[i]) {
- dbnc = i;
- break;
- }
- }
+ eint_n = pin->eint.eintnum;

- if (!mtk_eint_get_mask(pctl, eint_num)) {
- mtk_eint_mask(d);
- unmask = 1;
- } else {
- unmask = 0;
- }
-
- 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;
+ return mtk_eint_find_irq(pctl->eint, eint_n);
}

static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned offset,
unsigned long config)
{
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
+ const struct mtk_desc_pin *pin;
+ unsigned long eint_n;
u32 debounce;

if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
return -ENOTSUPP;

+ pin = pctl->devdata->pins + offset;
+ if (pin->eint.eintnum == NO_EINT_SUPPORT)
+ return -EINVAL;
+
debounce = pinconf_to_config_argument(config);
- return mtk_gpio_set_debounce(chip, offset, debounce);
+ eint_n = pin->eint.eintnum;
+
+ return mtk_eint_set_debounce(pctl->eint, eint_n, debounce);
}

static const struct gpio_chip mtk_gpio_chip = {
@@ -1084,117 +880,18 @@ static const struct gpio_chip mtk_gpio_chip = {
.of_gpio_n_cells = 2,
};

-static int mtk_eint_set_type(struct irq_data *d,
- unsigned int type)
-{
- 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;
-
- if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
- ((type & IRQ_TYPE_LEVEL_MASK) == IRQ_TYPE_LEVEL_MASK)) {
- dev_err(pctl->dev, "Can't configure IRQ%d (EINT%lu) for type 0x%X\n",
- d->irq, d->hwirq, type);
- return -EINVAL;
- }
-
- if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- pctl->eint_dual_edges[d->hwirq] = 1;
- else
- pctl->eint_dual_edges[d->hwirq] = 0;
-
- if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
- reg = mtk_eint_get_offset(pctl, d->hwirq,
- eint_offsets->pol_clr);
- writel(mask, reg);
- } else {
- reg = mtk_eint_get_offset(pctl, d->hwirq,
- eint_offsets->pol_set);
- writel(mask, reg);
- }
-
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- reg = mtk_eint_get_offset(pctl, d->hwirq,
- eint_offsets->sens_clr);
- writel(mask, reg);
- } else {
- reg = mtk_eint_get_offset(pctl, d->hwirq,
- eint_offsets->sens_set);
- writel(mask, reg);
- }
-
- if (pctl->eint_dual_edges[d->hwirq])
- mtk_eint_flip_edge(pctl, d->hwirq);
-
- return 0;
-}
-
-static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
-{
- struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
- int shift = d->hwirq & 0x1f;
- int reg = d->hwirq >> 5;
-
- if (on)
- pctl->wake_mask[reg] |= BIT(shift);
- else
- pctl->wake_mask[reg] &= ~BIT(shift);
-
- return 0;
-}
-
-static void mtk_eint_chip_write_mask(const struct mtk_eint_offsets *chip,
- void __iomem *eint_reg_base, u32 *buf)
-{
- int port;
- void __iomem *reg;
-
- for (port = 0; port < chip->ports; port++) {
- reg = eint_reg_base + (port << 2);
- writel_relaxed(~buf[port], reg + chip->mask_set);
- writel_relaxed(buf[port], reg + chip->mask_clr);
- }
-}
-
-static void mtk_eint_chip_read_mask(const struct mtk_eint_offsets *chip,
- void __iomem *eint_reg_base, u32 *buf)
-{
- int port;
- void __iomem *reg;
-
- for (port = 0; port < chip->ports; port++) {
- reg = eint_reg_base + chip->mask + (port << 2);
- buf[port] = ~readl_relaxed(reg);
- /* Mask is 0 when irq is enabled, and 1 when disabled. */
- }
-}
-
static int mtk_eint_suspend(struct device *device)
{
- void __iomem *reg;
struct mtk_pinctrl *pctl = dev_get_drvdata(device);
- const struct mtk_eint_offsets *eint_offsets =
- &pctl->devdata->eint_offsets;

- reg = pctl->eint_reg_base;
- mtk_eint_chip_read_mask(eint_offsets, reg, pctl->cur_mask);
- mtk_eint_chip_write_mask(eint_offsets, reg, pctl->wake_mask);
-
- return 0;
+ return mtk_eint_do_suspend(pctl->eint);
}

static int mtk_eint_resume(struct device *device)
{
struct mtk_pinctrl *pctl = dev_get_drvdata(device);
- const struct mtk_eint_offsets *eint_offsets =
- &pctl->devdata->eint_offsets;

- mtk_eint_chip_write_mask(eint_offsets,
- pctl->eint_reg_base, pctl->cur_mask);
-
- return 0;
+ return mtk_eint_do_resume(pctl->eint);
}

const struct dev_pm_ops mtk_eint_pm_ops = {
@@ -1202,117 +899,6 @@ const struct dev_pm_ops mtk_eint_pm_ops = {
.resume_noirq = mtk_eint_resume,
};

-static void mtk_eint_ack(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->ack);
-
- writel(mask, reg);
-}
-
-static struct irq_chip mtk_pinctrl_irq_chip = {
- .name = "mt-eint",
- .irq_disable = mtk_eint_mask,
- .irq_mask = mtk_eint_mask,
- .irq_unmask = mtk_eint_unmask,
- .irq_ack = mtk_eint_ack,
- .irq_set_type = mtk_eint_set_type,
- .irq_set_wake = mtk_eint_irq_set_wake,
- .irq_request_resources = mtk_pinctrl_irq_request_resources,
- .irq_release_resources = mtk_pinctrl_irq_release_resources,
-};
-
-static unsigned int mtk_eint_init(struct mtk_pinctrl *pctl)
-{
- const struct mtk_eint_offsets *eint_offsets =
- &pctl->devdata->eint_offsets;
- void __iomem *reg = pctl->eint_reg_base + eint_offsets->dom_en;
- unsigned int i;
-
- for (i = 0; i < pctl->devdata->ap_num; i += 32) {
- writel(0xffffffff, reg);
- reg += 4;
- }
- return 0;
-}
-
-static inline void
-mtk_eint_debounce_process(struct mtk_pinctrl *pctl, int index)
-{
- unsigned int rst, ctrl_offset;
- unsigned int bit, dbnc;
- const struct mtk_eint_offsets *eint_offsets =
- &pctl->devdata->eint_offsets;
-
- ctrl_offset = (index / 4) * 4 + eint_offsets->dbnc_ctrl;
- dbnc = readl(pctl->eint_reg_base + ctrl_offset);
- bit = EINT_DBNC_SET_EN << ((index % 4) * 8);
- if ((bit & dbnc) > 0) {
- ctrl_offset = (index / 4) * 4 + eint_offsets->dbnc_set;
- rst = EINT_DBNC_RST_BIT << ((index % 4) * 8);
- writel(rst, pctl->eint_reg_base + ctrl_offset);
- }
-}
-
-static void mtk_eint_irq_handler(struct irq_desc *desc)
-{
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct mtk_pinctrl *pctl = irq_desc_get_handler_data(desc);
- unsigned int status, eint_num;
- int offset, index, virq;
- const struct mtk_eint_offsets *eint_offsets =
- &pctl->devdata->eint_offsets;
- void __iomem *reg = mtk_eint_get_offset(pctl, 0, eint_offsets->stat);
- int dual_edges, start_level, curr_level;
- const struct mtk_desc_pin *pin;
-
- chained_irq_enter(chip, desc);
- for (eint_num = 0;
- eint_num < pctl->devdata->ap_num;
- eint_num += 32, reg += 4) {
- status = readl(reg);
- while (status) {
- offset = __ffs(status);
- index = eint_num + offset;
- virq = irq_find_mapping(pctl->domain, index);
- status &= ~BIT(offset);
-
- dual_edges = pctl->eint_dual_edges[index];
- if (dual_edges) {
- /* Clear soft-irq in case we raised it
- last time */
- writel(BIT(offset), reg - eint_offsets->stat +
- eint_offsets->soft_clr);
-
- pin = mtk_find_pin_by_eint_num(pctl, index);
- start_level = mtk_gpio_get(pctl->chip,
- pin->pin.number);
- }
-
- generic_handle_irq(virq);
-
- if (dual_edges) {
- curr_level = mtk_eint_flip_edge(pctl, index);
-
- /* If level changed, we might lost one edge
- interrupt, raised it through soft-irq */
- if (start_level != curr_level)
- writel(BIT(offset), reg -
- eint_offsets->stat +
- eint_offsets->soft_set);
- }
-
- if (index < pctl->devdata->db_cnt)
- mtk_eint_debounce_process(pctl , index);
- }
- }
- chained_irq_exit(chip, desc);
-}
-
static int mtk_pctrl_build_state(struct platform_device *pdev)
{
struct mtk_pinctrl *pctl = platform_get_drvdata(pdev);
@@ -1345,6 +931,97 @@ static int mtk_pctrl_build_state(struct platform_device *pdev)
return 0;
}

+static int
+mtk_xt_get_gpio_n(void *data, unsigned long eint_n, unsigned int *gpio_n,
+ struct gpio_chip **gpio_chip)
+{
+ struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
+ const struct mtk_desc_pin *pin;
+
+ pin = mtk_find_pin_by_eint_num(pctl, eint_n);
+ if (!pin)
+ return -EINVAL;
+
+ *gpio_chip = pctl->chip;
+ *gpio_n = pin->pin.number;
+
+ return 0;
+}
+
+static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
+{
+ struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
+ const struct mtk_desc_pin *pin;
+
+ pin = mtk_find_pin_by_eint_num(pctl, eint_n);
+ if (!pin)
+ return -EINVAL;
+
+ return mtk_gpio_get(pctl->chip, pin->pin.number);
+}
+
+static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
+{
+ struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
+ const struct mtk_desc_pin *pin;
+
+ pin = mtk_find_pin_by_eint_num(pctl, eint_n);
+ if (!pin)
+ return -EINVAL;
+
+ /* set mux to INT mode */
+ mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux);
+ /* set gpio direction to input */
+ mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number,
+ true);
+ /* set input-enable */
+ mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1,
+ PIN_CONFIG_INPUT_ENABLE);
+
+ return 0;
+}
+
+static const struct mtk_eint_xt mtk_eint_xt = {
+ .get_gpio_n = mtk_xt_get_gpio_n,
+ .get_gpio_state = mtk_xt_get_gpio_state,
+ .set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
+};
+
+static int mtk_eint_init(struct mtk_pinctrl *pctl, struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+
+ if (!of_property_read_bool(np, "interrupt-controller"))
+ return -ENODEV;
+
+ pctl->eint = devm_kzalloc(pctl->dev, sizeof(*pctl->eint), GFP_KERNEL);
+ if (!pctl->eint)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get eint resource\n");
+ return -ENODEV;
+ }
+
+ pctl->eint->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctl->eint->base))
+ return PTR_ERR(pctl->eint->base);
+
+ pctl->eint->irq = irq_of_parse_and_map(np, 0);
+ if (!pctl->eint->irq)
+ return -EINVAL;
+
+ pctl->eint->dev = &pdev->dev;
+ pctl->eint->regs = &pctl->devdata->eint_regs;
+ pctl->eint->hw = &pctl->devdata->eint_hw;
+ pctl->eint->pctl = pctl;
+ pctl->eint->gpio_xlate = &mtk_eint_xt;
+
+ return mtk_eint_do_init(pctl->eint);
+}
+
int mtk_pctrl_init(struct platform_device *pdev,
const struct mtk_pinctrl_devdata *data,
struct regmap *regmap)
@@ -1353,8 +1030,7 @@ int mtk_pctrl_init(struct platform_device *pdev,
struct mtk_pinctrl *pctl;
struct device_node *np = pdev->dev.of_node, *node;
struct property *prop;
- struct resource *res;
- int i, ret, irq, ports_buf;
+ int ret, i;

pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
if (!pctl)
@@ -1441,70 +1117,10 @@ int mtk_pctrl_init(struct platform_device *pdev,
goto chip_error;
}

- if (!of_property_read_bool(np, "interrupt-controller"))
- return 0;
-
- /* Get EINT register base from dts. */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get Pinctrl resource\n");
- ret = -EINVAL;
- goto chip_error;
- }
-
- pctl->eint_reg_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(pctl->eint_reg_base)) {
- ret = -EINVAL;
- goto chip_error;
- }
-
- ports_buf = pctl->devdata->eint_offsets.ports;
- pctl->wake_mask = devm_kcalloc(&pdev->dev, ports_buf,
- sizeof(*pctl->wake_mask), GFP_KERNEL);
- if (!pctl->wake_mask) {
- ret = -ENOMEM;
- goto chip_error;
- }
-
- pctl->cur_mask = devm_kcalloc(&pdev->dev, ports_buf,
- sizeof(*pctl->cur_mask), GFP_KERNEL);
- if (!pctl->cur_mask) {
- ret = -ENOMEM;
- goto chip_error;
- }
-
- pctl->eint_dual_edges = devm_kcalloc(&pdev->dev, pctl->devdata->ap_num,
- sizeof(int), GFP_KERNEL);
- if (!pctl->eint_dual_edges) {
- ret = -ENOMEM;
- goto chip_error;
- }
-
- irq = irq_of_parse_and_map(np, 0);
- if (!irq) {
- dev_err(&pdev->dev, "couldn't parse and map irq\n");
- ret = -EINVAL;
- goto chip_error;
- }
-
- pctl->domain = irq_domain_add_linear(np,
- pctl->devdata->ap_num, &irq_domain_simple_ops, NULL);
- if (!pctl->domain) {
- dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
- ret = -ENOMEM;
+ ret = mtk_eint_init(pctl, pdev);
+ if (ret)
goto chip_error;
- }
-
- mtk_eint_init(pctl);
- for (i = 0; i < pctl->devdata->ap_num; i++) {
- int virq = irq_create_mapping(pctl->domain, i);
-
- irq_set_chip_and_handler(virq, &mtk_pinctrl_irq_chip,
- handle_level_irq);
- irq_set_chip_data(virq, pctl);
- }

- irq_set_chained_handler_and_data(irq, mtk_eint_irq_handler, pctl);
return 0;

chip_error:
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
index 8543bc4..346e3db 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -19,6 +19,8 @@
#include <linux/regmap.h>
#include <linux/pinctrl/pinconf-generic.h>

+#include "mtk-eint.h"
+
#define NO_EINT_SUPPORT 255
#define MT_EDGE_SENSITIVE 0
#define MT_LEVEL_SENSITIVE 1
@@ -258,9 +260,8 @@ struct mtk_pinctrl_devdata {
unsigned char port_shf;
unsigned char port_mask;
unsigned char port_align;
- struct mtk_eint_offsets eint_offsets;
- unsigned int ap_num;
- unsigned int db_cnt;
+ struct mtk_eint_hw eint_hw;
+ struct mtk_eint_regs eint_regs;
};

struct mtk_pinctrl {
@@ -274,11 +275,7 @@ struct mtk_pinctrl {
const char **grp_names;
struct pinctrl_dev *pctl_dev;
const struct mtk_pinctrl_devdata *devdata;
- void __iomem *eint_reg_base;
- struct irq_domain *domain;
- int *eint_dual_edges;
- u32 *wake_mask;
- u32 *cur_mask;
+ struct mtk_eint *eint;
};

int mtk_pctrl_init(struct platform_device *pdev,
--
2.7.4


2018-05-20 17:03:57

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 3/7] pinctrl: mediatek: add EINT support to MT7622 SoC

From: Sean Wang <[email protected]>

Add EINT support to MT7622 SoC and the support is made as just an option
to MT7622 pinctrl.

Signed-off-by: Sean Wang <[email protected]>
---
drivers/pinctrl/mediatek/Kconfig | 2 +-
drivers/pinctrl/mediatek/pinctrl-mt7622.c | 143 ++++++++++++++++++++++++++++++
2 files changed, 144 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 310db42..9905dc6 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -3,7 +3,7 @@ menu "MediaTek pinctrl drivers"

config EINT_MTK
bool "MediaTek External Interrupt Support"
- depends on PINCTRL_MTK || COMPILE_TEST
+ depends on PINCTRL_MTK || PINCTRL_MT7622 || COMPILE_TEST
select IRQ_DOMAIN

config PINCTRL_MTK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c
index 06e8406..ad6da11 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
@@ -30,6 +31,7 @@
#include "../core.h"
#include "../pinconf.h"
#include "../pinmux.h"
+#include "mtk-eint.h"

#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME
#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
@@ -123,6 +125,8 @@ struct mtk_pin_soc {
unsigned int ngrps;
const struct function_desc *funcs;
unsigned int nfuncs;
+ const struct mtk_eint_regs *eint_regs;
+ const struct mtk_eint_hw *eint_hw;
};

struct mtk_pinctrl {
@@ -131,6 +135,7 @@ struct mtk_pinctrl {
struct device *dev;
struct gpio_chip chip;
const struct mtk_pin_soc *soc;
+ struct mtk_eint *eint;
};

static const struct mtk_pin_field_calc mt7622_pin_mode_range[] = {
@@ -913,6 +918,13 @@ static const struct pin_config_item mtk_conf_items[] = {
};
#endif

+static const struct mtk_eint_hw mt7622_eint_hw = {
+ .port_mask = 7,
+ .ports = 7,
+ .ap_num = ARRAY_SIZE(mt7622_pins),
+ .db_cnt = 20,
+};
+
static const struct mtk_pin_soc mt7622_data = {
.reg_cal = mt7622_reg_cals,
.pins = mt7622_pins,
@@ -921,6 +933,7 @@ static const struct mtk_pin_soc mt7622_data = {
.ngrps = ARRAY_SIZE(mt7622_groups),
.funcs = mt7622_functions,
.nfuncs = ARRAY_SIZE(mt7622_functions),
+ .eint_hw = &mt7622_eint_hw,
};

static void mtk_w32(struct mtk_pinctrl *pctl, u32 reg, u32 val)
@@ -1441,6 +1454,32 @@ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
return pinctrl_gpio_direction_output(chip->base + gpio);
}

+static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ unsigned long eint_n;
+
+ eint_n = offset;
+
+ return mtk_eint_find_irq(hw->eint, eint_n);
+}
+
+static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ unsigned long eint_n;
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+ eint_n = offset;
+
+ return mtk_eint_set_debounce(hw->eint, eint_n, debounce);
+}
+
static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
{
struct gpio_chip *chip = &hw->chip;
@@ -1454,6 +1493,8 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
chip->direction_output = mtk_gpio_direction_output;
chip->get = mtk_gpio_get;
chip->set = mtk_gpio_set;
+ chip->to_irq = mtk_gpio_to_irq,
+ chip->set_config = mtk_gpio_set_config,
chip->base = -1;
chip->ngpio = hw->soc->npins;
chip->of_node = np;
@@ -1514,6 +1555,103 @@ static int mtk_build_functions(struct mtk_pinctrl *hw)
return 0;
}

+static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
+ unsigned int *gpio_n,
+ struct gpio_chip **gpio_chip)
+{
+ struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+
+ *gpio_chip = &hw->chip;
+ *gpio_n = eint_n;
+
+ return 0;
+}
+
+static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
+{
+ struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+ struct gpio_chip *gpio_chip;
+ unsigned int gpio_n;
+ int err;
+
+ err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
+ if (err)
+ return err;
+
+ return mtk_gpio_get(gpio_chip, gpio_n);
+}
+
+static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
+{
+ struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+ struct gpio_chip *gpio_chip;
+ unsigned int gpio_n;
+ int err;
+
+ err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_MODE,
+ MTK_GPIO_MODE);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_DIR, MTK_INPUT);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_SMT, MTK_ENABLE);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static const struct mtk_eint_xt mtk_eint_xt = {
+ .get_gpio_n = mtk_xt_get_gpio_n,
+ .get_gpio_state = mtk_xt_get_gpio_state,
+ .set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
+};
+
+static int
+mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+
+ if (!IS_ENABLED(CONFIG_EINT_MTK))
+ return 0;
+
+ if (!of_property_read_bool(np, "interrupt-controller"))
+ return -ENODEV;
+
+ hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
+ if (!hw->eint)
+ return -ENOMEM;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint");
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get eint resource\n");
+ return -ENODEV;
+ }
+
+ hw->eint->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->eint->base))
+ return PTR_ERR(hw->eint->base);
+
+ hw->eint->irq = irq_of_parse_and_map(np, 0);
+ if (!hw->eint->irq)
+ return -EINVAL;
+
+ hw->eint->dev = &pdev->dev;
+ hw->eint->hw = hw->soc->eint_hw;
+ hw->eint->pctl = hw;
+ hw->eint->gpio_xlate = &mtk_eint_xt;
+
+ return mtk_eint_do_init(hw->eint);
+}
+
static const struct of_device_id mtk_pinctrl_of_match[] = {
{ .compatible = "mediatek,mt7622-pinctrl", .data = &mt7622_data},
{ }
@@ -1577,6 +1715,11 @@ static int mtk_pinctrl_probe(struct platform_device *pdev)
return err;
}

+ err = mtk_build_eint(hw, pdev);
+ if (err)
+ dev_warn(&pdev->dev,
+ "Failed to add EINT, but pinctrl still can work\n");
+
platform_set_drvdata(pdev, hw);

return 0;
--
2.7.4


2018-05-20 17:04:14

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 1/7] dt-bindings: pinctrl: add external interrupt support to MT7622 pinctrl

From: Sean Wang <[email protected]>

Extend the capability of MT7622 pinctrl with adding EINT so that each
GPIO can be used to notify CPU when a signal state is changing on the
line as an external interrupt.

Signed-off-by: Sean Wang <[email protected]>
---
Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt
index f18ed99..743b32d 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt
@@ -9,6 +9,16 @@ Required properties for the root node:
- #gpio-cells: Should be two. The first cell is the pin number and the
second is the GPIO flags.

+Optional properties:
+- interrupt-controller : Marks the device node as an interrupt controller
+
+If the property interrupt-controller is defined, following property is required
+- reg-names: A string describing the "reg" entries. Must contain "eint".
+- interrupts : The interrupt output from the controller.
+- #interrupt-cells: Should be two.
+- interrupt-parent: Phandle of the interrupt parent to which the external
+ GPIO interrupts are forwarded to.
+
Please refer to pinctrl-bindings.txt in this directory for details of the
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
--
2.7.4


2018-05-20 17:04:38

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 7/7] arm64: dts: mt7622: add EINT support to pinctrl

From: Sean Wang <[email protected]>

Add EINT support to pinctrl and set those GPIO keys as interrupt-driven
keys.

Signed-off-by: Sean Wang <[email protected]>
---
arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 2 +-
arch/arm64/boot/dts/mediatek/mt7622.dtsi | 8 +++++++-
2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
index b783764..1ff003e 100644
--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
@@ -34,7 +34,7 @@
};

gpio-keys {
- compatible = "gpio-keys-polled";
+ compatible = "gpio-keys";
poll-interval = <100>;

factory {
diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
index 9213c96..e2c5450 100644
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
@@ -286,9 +286,15 @@

pio: pinctrl@10211000 {
compatible = "mediatek,mt7622-pinctrl";
- reg = <0 0x10211000 0 0x1000>;
+ reg = <0 0x10211000 0 0x1000>,
+ <0 0x10005000 0 0x1000>;
+ reg-names = "base", "eint";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ #interrupt-cells = <2>;
};

watchdog: watchdog@10212000 {
--
2.7.4


2018-05-20 17:07:18

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 5/7] pinctrl: mediatek: remove unused fields in struct mtk_eint_hw

From: Sean Wang <[email protected]>

The .name field has been not being used in existent code logic, so
it's better that we remove them all.

Signed-off-by: Sean Wang <[email protected]>
---
drivers/pinctrl/mediatek/mtk-eint.h | 1 -
drivers/pinctrl/mediatek/pinctrl-mt2701.c | 1 -
drivers/pinctrl/mediatek/pinctrl-mt2712.c | 1 -
drivers/pinctrl/mediatek/pinctrl-mt8127.c | 1 -
drivers/pinctrl/mediatek/pinctrl-mt8135.c | 1 -
drivers/pinctrl/mediatek/pinctrl-mt8173.c | 1 -
6 files changed, 6 deletions(-)

diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 55b4d5f..c286a9b 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -33,7 +33,6 @@ struct mtk_eint_regs {
};

struct mtk_eint_hw {
- const char *name;
u8 port_mask;
u8 ports;
unsigned int ap_num;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
index db22250..e91c314 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -532,7 +532,6 @@ static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
.port_mask = 0x1f,
.port_align = 4,
.eint_hw = {
- .name = "mt2701_eint",
.port_mask = 6,
.ports = 6,
.ap_num = 169,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2712.c b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
index 6e2acef..8398d55 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2712.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
@@ -577,7 +577,6 @@ static const struct mtk_pinctrl_devdata mt2712_pinctrl_data = {
.port_mask = 0xf,
.port_align = 4,
.eint_hw = {
- .name = "mt2712_eint",
.port_mask = 0xf,
.ports = 8,
.ap_num = 229,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8127.c b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
index 949a235..2e4cc92 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8127.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
@@ -301,7 +301,6 @@ static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
.port_mask = 0xf,
.port_align = 4,
.eint_hw = {
- .name = "mt8127_eint",
.port_mask = 7,
.ports = 6,
.ap_num = 143,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8135.c b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
index 974a1f43..7f5edfa 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8135.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
@@ -314,7 +314,6 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.port_mask = 0xf,
.port_align = 4,
.eint_hw = {
- .name = "mt8135_eint",
.port_mask = 7,
.ports = 6,
.ap_num = 192,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index a836cee3..c449c9a 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -341,7 +341,6 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
.port_mask = 0xf,
.port_align = 4,
.eint_hw = {
- .name = "mt8173_eint",
.port_mask = 7,
.ports = 6,
.ap_num = 224,
--
2.7.4


2018-05-22 20:03:45

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v1 1/7] dt-bindings: pinctrl: add external interrupt support to MT7622 pinctrl

On Mon, May 21, 2018 at 01:01:47AM +0800, [email protected] wrote:
> From: Sean Wang <[email protected]>
>
> Extend the capability of MT7622 pinctrl with adding EINT so that each
> GPIO can be used to notify CPU when a signal state is changing on the
> line as an external interrupt.
>
> Signed-off-by: Sean Wang <[email protected]>
> ---
> Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt | 10 ++++++++++
> 1 file changed, 10 insertions(+)

Reviewed-by: Rob Herring <[email protected]>

2018-05-24 07:41:35

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v1 1/7] dt-bindings: pinctrl: add external interrupt support to MT7622 pinctrl

On Sun, May 20, 2018 at 7:01 PM, <[email protected]> wrote:

> From: Sean Wang <[email protected]>
>
> Extend the capability of MT7622 pinctrl with adding EINT so that each
> GPIO can be used to notify CPU when a signal state is changing on the
> line as an external interrupt.
>
> Signed-off-by: Sean Wang <[email protected]>

Patch applied with Rob's review tag.

Yours,
Linus Walleij

2018-05-24 07:42:04

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v1 2/7] pinctrl: mediatek: refactor EINT related code for all MediaTek pinctrl can fit

On Sun, May 20, 2018 at 7:01 PM, <[email protected]> wrote:

> From: Sean Wang <[email protected]>
>
> This patch is in preparation for adding EINT support to MT7622 pinctrl,
> and the refactoring doesn't alter any existent logic.
>
> A reason we have to refactor EINT code pieces into a generic way is that
> currently, they're tightly coupled with a certain type of MediaTek pinctrl
> would cause a grown in a very bad way as there is different types of
> pinctrl devices getting to join.
>
> Therefore, it is an essential or urgent thing that EINT code pieces are
> refactored to eliminate any dependencies across GPIO and EINT as possible.
>
> Additional structure mtk_eint_[xt, hw, regs] are being introduced for
> indicating how maps being designed between GPIO and EINT hw number, how to
> set and get GPIO state for a certain EINT pin, what characteristic on a
> EINT device is present on various SoCs.
>
> Signed-off-by: Sean Wang <[email protected]>

Patch applied.

Yours,
Linus Walleij

2018-05-24 07:44:43

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v1 3/7] pinctrl: mediatek: add EINT support to MT7622 SoC

On Sun, May 20, 2018 at 7:01 PM, <[email protected]> wrote:

> From: Sean Wang <[email protected]>
>
> Add EINT support to MT7622 SoC and the support is made as just an option
> to MT7622 pinctrl.
>
> Signed-off-by: Sean Wang <[email protected]>

Patch applied.

Yours,
Linus Walleij

2018-05-24 07:46:00

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v1 4/7] pinctrl: mediatek: use generic EINT register maps for each SoC

On Sun, May 20, 2018 at 7:01 PM, <[email protected]> wrote:

> From: Sean Wang <[email protected]>
>
> So far, EINT on each SoC all used exactly identical register map and thus
> it's better that we apply generic register map already supported in EINT
> library and stop copy-n-pasting the same data block and filling into its
> platform data.
>
> Signed-off-by: Sean Wang <[email protected]>

Patch applied.

Yours,
Linus Walleij

2018-05-24 07:46:30

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v1 5/7] pinctrl: mediatek: remove unused fields in struct mtk_eint_hw

On Sun, May 20, 2018 at 7:01 PM, <[email protected]> wrote:

> From: Sean Wang <[email protected]>
>
> The .name field has been not being used in existent code logic, so
> it's better that we remove them all.
>
> Signed-off-by: Sean Wang <[email protected]>

Patch applied.

Yours,
Linus Walleij

2018-05-24 07:57:46

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v1 6/7] MAINTAINERS: update entry for PIN CONTROLLER - MEDIATEK

On Sun, May 20, 2018 at 7:01 PM, <[email protected]> wrote:

> From: Sean Wang <[email protected]>
>
> Add new files for the entry
>
> Signed-off-by: Sean Wang <[email protected]>

Patch applied.

Yours,
Linus Walleij

2018-05-24 07:59:24

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v1 7/7] arm64: dts: mt7622: add EINT support to pinctrl

On Sun, May 20, 2018 at 7:01 PM, <[email protected]> wrote:

> From: Sean Wang <[email protected]>
>
> Add EINT support to pinctrl and set those GPIO keys as interrupt-driven
> keys.
>
> Signed-off-by: Sean Wang <[email protected]>

Acked-by: Linus Walleij <[email protected]>

Please merge this through the ARM SoC tree.

Yours,
Linus Walleij

2018-06-25 15:04:05

by Matthias Brugger

[permalink] [raw]
Subject: Re: [PATCH v1 7/7] arm64: dts: mt7622: add EINT support to pinctrl



On 20/05/18 19:01, [email protected] wrote:
> From: Sean Wang <[email protected]>
>
> Add EINT support to pinctrl and set those GPIO keys as interrupt-driven
> keys.
>
> Signed-off-by: Sean Wang <[email protected]>
> ---

Merged,

Thanks!

> arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 2 +-
> arch/arm64/boot/dts/mediatek/mt7622.dtsi | 8 +++++++-
> 2 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
> index b783764..1ff003e 100644
> --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
> +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
> @@ -34,7 +34,7 @@
> };
>
> gpio-keys {
> - compatible = "gpio-keys-polled";
> + compatible = "gpio-keys";
> poll-interval = <100>;
>
> factory {
> diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
> index 9213c96..e2c5450 100644
> --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
> @@ -286,9 +286,15 @@
>
> pio: pinctrl@10211000 {
> compatible = "mediatek,mt7622-pinctrl";
> - reg = <0 0x10211000 0 0x1000>;
> + reg = <0 0x10211000 0 0x1000>,
> + <0 0x10005000 0 0x1000>;
> + reg-names = "base", "eint";
> gpio-controller;
> #gpio-cells = <2>;
> + interrupt-controller;
> + interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-parent = <&gic>;
> + #interrupt-cells = <2>;
> };
>
> watchdog: watchdog@10212000 {
>